Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / wlm / wlmchatmanager.cpp
blob18cf4bfd8b1b0e061e283c5837288bc1269cccdd
1 /*
2 wlmchatsession.cpp - MSN Message Manager
4 Copyright (c) 2008 by Tiago Salem Herrmann <tiagosh@gmail.com>
5 Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
7 *************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 *************************************************************************
17 #include "wlmchatmanager.h"
19 #include <QLabel>
20 #include <QImage>
21 #include <QImageReader>
22 #include <QToolTip>
23 #include <QFile>
24 #include <QIcon>
25 #include <QRegExp>
26 #include <QDomDocument>
27 #include <QTextDocument>
29 #include <kconfig.h>
30 #include <kdebug.h>
31 #include <kinputdialog.h>
32 #include <klocale.h>
33 #include <kmessagebox.h>
34 #include <kmenu.h>
35 #include <kmainwindow.h>
36 #include <ktoolbar.h>
37 #include <krun.h>
38 #include <kstandarddirs.h>
39 #include <ktemporaryfile.h>
41 #include "kopetecontactaction.h"
42 #include "kopetemetacontact.h"
43 #include "kopetecontactlist.h"
44 #include "kopetechatsessionmanager.h"
45 #include "kopeteuiglobal.h"
46 #include "kopeteglobal.h"
47 #include "kopeteview.h"
49 #include "wlmcontact.h"
50 #include "wlmprotocol.h"
51 #include "wlmaccount.h"
54 WlmChatManager::WlmChatManager (WlmAccount * account1):
55 m_account (account1)
57 QObject::connect (&account ()->server ()->cb,
58 SIGNAL (messageReceived
59 (MSN::SwitchboardServerConnection *,
60 const QString &, const Kopete::Message &)),
61 this,
62 SLOT (receivedMessage
63 (MSN::SwitchboardServerConnection *,
64 const QString &, const Kopete::Message &)));
66 QObject::connect (&account ()->server ()->cb,
67 SIGNAL (joinedConversation
68 (MSN::SwitchboardServerConnection *,
69 const QString &, const QString &)), this,
70 SLOT (joinedConversation
71 (MSN::SwitchboardServerConnection *,
72 const QString &, const QString &)));
74 QObject::connect (&account ()->server ()->cb,
75 SIGNAL (leftConversation
76 (MSN::SwitchboardServerConnection *,
77 const QString &)), this,
78 SLOT (leftConversation
79 (MSN::SwitchboardServerConnection *,
80 const QString &)));
82 QObject::connect (&account ()->server ()->cb,
83 SIGNAL (gotNewSwitchboard
84 (MSN::SwitchboardServerConnection *,
85 const void *)), this,
86 SLOT (gotNewSwitchboard
87 (MSN::SwitchboardServerConnection *,
88 const void *)));
90 QObject::connect (&account ()->server ()->cb,
91 SIGNAL (SwitchboardServerConnectionTerminated
92 (MSN::SwitchboardServerConnection *)), this,
93 SLOT (SwitchboardServerConnectionTerminated
94 (MSN::SwitchboardServerConnection *)));
96 QObject::connect (&account ()->server ()->cb,
97 SIGNAL (messageSentACK
98 (MSN::SwitchboardServerConnection *,
99 const unsigned int &)), this,
100 SLOT (messageSentACK
101 (MSN::SwitchboardServerConnection *,
102 const unsigned int &)));
104 QObject::connect (&account ()->server ()->cb,
105 SIGNAL (receivedNudge
106 (MSN::SwitchboardServerConnection *,
107 const QString &)), this,
108 SLOT (receivedNudge
109 (MSN::SwitchboardServerConnection *,
110 const QString &)));
112 QObject::connect (&account ()->server ()->cb,
113 SIGNAL (receivedTypingNotification
114 (MSN::SwitchboardServerConnection *,
115 const QString &)), this,
116 SLOT (receivedTypingNotification
117 (MSN::SwitchboardServerConnection *,
118 const QString &)));
120 QObject::connect (&account ()->server ()->cb,
121 SIGNAL (slotGotEmoticonNotification (MSN::SwitchboardServerConnection *,
122 const MSN::Passport &, const QString &,
123 const QString &)), this,
124 SLOT (slotGotEmoticonNotification (MSN::SwitchboardServerConnection *,
125 const MSN::Passport &, const QString &,
126 const QString &)));
128 QObject::connect (&account ()->server ()->cb,
129 SIGNAL (slotGotVoiceClipNotification (MSN::SwitchboardServerConnection *,
130 const MSN::Passport &,
131 const QString &)), this,
132 SLOT(slotGotVoiceClipNotification (MSN::SwitchboardServerConnection *,
133 const MSN::Passport &,
134 const QString &)));
136 QObject::connect (&account ()->server ()->cb,
137 SIGNAL(slotGotWinkNotification (MSN::SwitchboardServerConnection *,
138 const MSN::Passport &,
139 const QString &)), this,
140 SLOT(slotGotWinkNotification (MSN::SwitchboardServerConnection *,
141 const MSN::Passport &,
142 const QString &)));
144 QObject::connect (&account ()->server ()->cb,
145 SIGNAL(slotGotInk (MSN::SwitchboardServerConnection *,
146 const MSN::Passport &,
147 const QString &)), this,
148 SLOT(slotGotInk (MSN::SwitchboardServerConnection *,
149 const MSN::Passport &,
150 const QString &)));
152 QObject::connect (&account ()->server ()->cb,
153 SIGNAL(slotGotVoiceClipFile(MSN::SwitchboardServerConnection *,
154 const unsigned int &,
155 const QString &)), this,
156 SLOT(slotGotVoiceClipFile(MSN::SwitchboardServerConnection *,
157 const unsigned int &,
158 const QString &)));
160 QObject::connect (&account ()->server ()->cb,
161 SIGNAL(slotGotEmoticonFile(MSN::SwitchboardServerConnection *,
162 const unsigned int &,
163 const QString &,
164 const QString &)), this,
165 SLOT(slotGotEmoticonFile(MSN::SwitchboardServerConnection *,
166 const unsigned int &,
167 const QString &,
168 const QString &)));
170 QObject::connect (&account ()->server ()->cb,
171 SIGNAL(slotGotWinkFile(MSN::SwitchboardServerConnection *,
172 const unsigned int &,
173 const QString &)), this,
174 SLOT(slotGotWinkFile(MSN::SwitchboardServerConnection *,
175 const unsigned int &,
176 const QString &)));
179 WlmChatManager::~WlmChatManager ()
181 QMap < MSN::SwitchboardServerConnection *,
182 WlmChatSession * >::Iterator it;
183 for (it = chatSessions.begin (); it != chatSessions.end (); ++it)
185 if (it.value ())
186 it.value ()->setChatService (NULL);
188 chatSessions.clear ();
191 void
192 WlmChatManager::receivedNudge (MSN::SwitchboardServerConnection * conn,
193 const QString & passport)
195 createChat (conn);
197 if(conn)
198 if(chatSessions[conn])
199 chatSessions[conn]->receivedNudge (passport);
203 void
204 WlmChatManager::leftConversation (MSN::SwitchboardServerConnection * conn,
205 const QString & passport)
207 kDebug (14210) << k_funcinfo << " " << conn;
208 WlmChatSession *chat = chatSessions[conn];
210 if (chat)
212 WlmContact * contact = qobject_cast<WlmContact*>(account ()->contacts ()[passport]);
213 if (!contact)
214 return;
215 chat->removeContact (contact);
219 void
220 WlmChatManager::removeChatSession (QObject * obj)
222 QMap <MSN::SwitchboardServerConnection *, WlmChatSession * >::Iterator it;
223 for (it = chatSessions.begin (); it != chatSessions.end (); ++it)
225 if (it.value () == obj)
227 it.value ()->deleteLater();
228 chatSessions.remove (it.key ());
229 return;
234 void
235 WlmChatManager::createChat (MSN::SwitchboardServerConnection * conn)
237 Kopete::ContactPtrList chatmembers;
238 kDebug (14210) << k_funcinfo << " " << conn;
240 if (chatSessions[conn])
241 return;
243 std::list < MSN::Passport >::iterator users = conn->users.begin ();
244 for (; users != conn->users.end (); ++users)
246 Kopete::Contact * contact =
247 account ()->contacts ()[(*users).c_str ()];
248 if (!contact)
250 account ()->addContact ((*users).c_str (), QString(), 0L,
251 Kopete::Account::Temporary);
252 contact = account ()->contacts ()[(*users).c_str ()];
253 contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown);
255 chatmembers.append (contact);
258 Kopete::ChatSession * _manager =
259 Kopete::ChatSessionManager::self ()->findChatSession (account ()->myself (),
260 chatmembers,
261 account ()->protocol ());
262 if (_manager)
263 chatSessions[conn] = qobject_cast < WlmChatSession * >(_manager);
264 else
265 // create a new chat window
266 chatSessions[conn] = new WlmChatSession (account ()->protocol (),
267 account ()->myself (), chatmembers, conn);
268 if(chatSessions[conn])
269 chatSessions[conn]->setChatService (conn);
272 void
273 WlmChatManager::joinedConversation (MSN::SwitchboardServerConnection * conn,
274 const QString & passport,
275 const QString & friendlyname)
277 Q_UNUSED( friendlyname );
279 Kopete::ContactPtrList chatmembers;
280 Kopete::Contact * contact = account ()->contacts ()[passport];
281 if (!contact)
283 account ()->addContact (passport, QString(), 0L,
284 Kopete::Account::Temporary);
285 contact = account ()->contacts ()[passport];
286 contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown);
288 // populate chatmembers from SwitchboardServerConnection
289 std::list < MSN::Passport >::iterator users = conn->users.begin ();
290 for (; users != conn->users.end (); ++users)
292 Kopete::Contact * contact =
293 account ()->contacts ()[(*users).c_str ()];
294 if (!contact)
296 account ()->addContact ((*users).c_str (), QString(), 0L,
297 Kopete::Account::Temporary);
298 contact = account ()->contacts ()[(*users).c_str ()];
299 contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown);
301 chatmembers.append (contact);
304 // check if we already have a similar connection
305 WlmChatSession *_manager =
306 qobject_cast <WlmChatSession *>(Kopete::ChatSessionManager::self ()->
307 findChatSession (account ()->myself (), chatmembers,
308 account ()->protocol ()));
310 if (_manager)
312 // drop the old and replace by the new one
313 MSN::SwitchboardServerConnection * conn_current =
314 chatSessions.key (_manager);
315 if (conn_current && conn_current != conn)
317 chatSessions.remove (conn_current);
318 chatSessions[conn] = _manager;
319 chatSessions[conn]->setChatService(conn);
320 delete conn_current;
321 return;
325 createChat (conn);
326 chatSessions[conn]->addContact (contact);
327 // the session is ready when there are at least 2 contacts, me and somebody
328 if (!chatSessions[conn]->isReady ())
329 chatSessions[conn]->setReady (true);
332 void
333 WlmChatManager::receivedMessage (MSN::SwitchboardServerConnection * conn,
334 const QString & from,
335 const Kopete::Message & message)
337 kDebug (14210) << k_funcinfo << " " << conn;
339 createChat (conn);
341 WlmChatSession *chat = chatSessions[conn];
343 // Pass it on to the contact to process and display via a KMM
344 if (chat)
346 Kopete::Contact * contact = account ()->contacts ()[from];
347 if(!contact)
349 account ()->addContact (from, QString(), 0L,
350 Kopete::Account::Temporary);
351 contact = account ()->contacts ()[from];
353 Kopete::Message * newMessage =
354 new Kopete::Message (contact, chat->members ());
355 newMessage->setPlainBody (message.plainBody ());
356 newMessage->setFont (message.font ());
357 newMessage->setForegroundColor (message.foregroundColor ());
358 newMessage->setDirection (Kopete::Message::Inbound);
360 // stolen from msn plugin
361 QMap<QString,QString>::ConstIterator it = emoticonsList.constBegin();
362 for(;it!=emoticonsList.constEnd(); ++it)
364 QString es=Qt::escape(it.key());
365 QString message1=newMessage->escapedBody();
366 if(message1.contains(es))
368 QFile f(it.value());
369 if(!f.exists())
371 // an emoticon is still missing, so wait for it
372 QLinkedList<Kopete::Message*> msgs = pendingMessages[conn];
373 newMessage->setHtmlBody(message1);
374 msgs.append(newMessage);
375 pendingMessages[conn] = msgs;
376 return;
378 QImage iconImage = QImageReader(it.value()).read();
380 message1.replace( QRegExp(QString::fromLatin1("%1(?![^><]*>)").arg(QRegExp::escape(es))),
381 QString::fromLatin1("<img align=\"center\" width=\"") +
382 QString::number(iconImage.width()) +
383 QString::fromLatin1("\" height=\"") +
384 QString::number(iconImage.height()) +
385 QString::fromLatin1("\" src=\"") + it.value() +
386 QString::fromLatin1("\" title=\"") + es +
387 QString::fromLatin1("\" alt=\"") + es +
388 QString::fromLatin1( "\"/>" ) );
389 newMessage->setHtmlBody(message1);
392 // Add it to the manager
393 chat->appendMessage (*newMessage);
395 delete newMessage;
396 // send keepalive each 50 seconds.
397 chat->startSendKeepAlive();
399 else
401 kWarning (14210) << k_funcinfo <<
402 "unable to look up contact for delivery";
406 void
407 WlmChatManager::SwitchboardServerConnectionTerminated (
408 MSN::SwitchboardServerConnection * conn)
410 if(!conn)
411 return;
413 WlmChatSession *chat = chatSessions[conn];
414 if (chat)
416 chat->setChatService (NULL);
417 chatSessions.remove (conn);
418 /* if(chat->view())
420 if(!chat->view()->isVisible())
421 delete chat;
423 else
424 delete chat;
429 void
430 WlmChatManager::gotNewSwitchboard (MSN::SwitchboardServerConnection * conn,
431 const void *tag)
433 Kopete::ContactPtrList chatmembers;
434 const std::pair < std::string, std::string > *ctx =
435 static_cast < const std::pair < std::string, std::string > *>(tag);
437 if (!ctx)
438 return;
440 conn->inviteUser (ctx->first);
441 delete ctx;
442 conn->auth.tag = NULL;
443 kDebug (14210) << k_funcinfo << " " << conn;
446 void
447 WlmChatManager::messageSentACK (MSN::SwitchboardServerConnection * conn,
448 const unsigned int &trID)
450 WlmChatSession *chat = chatSessions[conn];
451 if (chat)
453 chat->messageSentACK (trID);
457 void
458 WlmChatManager::requestDisplayPicture (QString contactId)
460 Kopete::Contact * contact = account ()->contacts ()[contactId];
462 if (!contact)
463 return;
465 WlmChatSession *session =
466 qobject_cast <WlmChatSession *>(contact->manager (Kopete::Contact::CanCreate));
468 if (session)
469 session->requestDisplayPicture ();
473 void
474 WlmChatManager::receivedTypingNotification (MSN::SwitchboardServerConnection *
475 conn, const QString & contactId)
477 Kopete::Contact * contact = account ()->contacts ()[contactId];
479 if (!contact)
480 return;
482 WlmChatSession *chat = chatSessions[conn];
483 if (chat)
485 chat->receivedTypingMsg (contact, true);
489 void
490 WlmChatManager::slotGotVoiceClipNotification (MSN::SwitchboardServerConnection * conn,
491 const MSN::Passport & from,
492 const QString & msnobject)
494 Q_UNUSED( conn );
495 Q_UNUSED( from );
496 Q_UNUSED( msnobject );
499 void
500 WlmChatManager::slotGotWinkNotification (MSN::SwitchboardServerConnection * conn,
501 const MSN::Passport & from,
502 const QString & msnobject)
504 Q_UNUSED( conn );
505 Q_UNUSED( from );
506 Q_UNUSED( msnobject );
509 void
510 WlmChatManager::slotGotInk (MSN::SwitchboardServerConnection * conn,
511 const MSN::Passport & from,
512 const QString & image)
514 QByteArray ink;
515 WlmChatSession *chat = chatSessions[conn];
516 if (!chat)
518 return;
520 Kopete::Contact * contact = account ()->contacts ()[from.c_str()];
521 if(!contact)
523 account ()->addContact (from.c_str(), QString(), 0L,
524 Kopete::Account::Temporary);
525 contact = account ()->contacts ()[from.c_str()];
527 if(!contact)
528 return;
530 ink = QByteArray::fromBase64(image.toUtf8());
531 KTemporaryFile *inkImage = new KTemporaryFile();
532 inkImage->setPrefix("inkformatgif-");
533 inkImage->setSuffix(".gif");
534 inkImage->open();
535 inkImage->write(ink.data(), ink.size());
536 QString msg=QString ("<img src=\"%1\" />").arg ( inkImage->fileName() );
537 inkImage->close();
539 Kopete::Message kmsg( contact, chat->members() );
540 kmsg.setHtmlBody( msg );
541 kmsg.setDirection( Kopete::Message::Inbound );
542 chat->appendMessage ( kmsg );
544 inkImage = 0l;
548 void
549 WlmChatManager::slotGotVoiceClipFile(MSN::SwitchboardServerConnection * conn,
550 const unsigned int & sessionID,
551 const QString & file)
553 Q_UNUSED( conn );
554 Q_UNUSED( sessionID );
555 Q_UNUSED( file );
558 void WlmChatManager::slotGotEmoticonNotification (MSN::SwitchboardServerConnection * conn,
559 const MSN::Passport & buddy,
560 const QString & alias,
561 const QString & msnobject)
563 Q_UNUSED( buddy );
565 WlmChatSession *chat = chatSessions[conn];
566 if(!chat)
567 return;
569 unsigned int sessionID = chat->generateSessionID();
571 QDomDocument xmlobj;
572 xmlobj.setContent (msnobject);
574 // track display pictures by SHA1D field
575 QString SHA1D = xmlobj.documentElement ().attribute ("SHA1D");
577 if (SHA1D.isEmpty ())
578 return;
580 QString newlocation =
581 KGlobal::dirs ()->locateLocal ("appdata",
582 "wlmpictures/" +
583 QString (SHA1D.replace ('/', '_')));
584 QFile f(newlocation);
585 if (f.exists () && f.size ())
587 emoticonsList[alias] = newlocation;
588 return;
591 // pending emoticon
592 emoticonsList[alias].clear();
594 conn->requestEmoticon(sessionID, newlocation.toAscii().constData(),
595 msnobject.toAscii().constData(), alias.toAscii().constData());
598 void
599 WlmChatManager::slotGotEmoticonFile(MSN::SwitchboardServerConnection * conn,
600 const unsigned int & sessionID,
601 const QString & alias,
602 const QString & file)
604 Q_UNUSED( sessionID );
606 emoticonsList[alias] = file;
608 if(pendingMessages[conn].isEmpty())
609 return;
611 if(!chatSessions[conn])
612 return;
614 // duplicate to avoid crashes when removing items in the next loop
615 QLinkedList<Kopete::Message *> pendingMessages1 = pendingMessages[conn];
617 QLinkedList<Kopete::Message *>::iterator it = pendingMessages1.begin();
618 for(;it!=pendingMessages1.end(); ++it)
620 Kopete::Message *message = (*it);
621 QMap<QString,QString>::iterator it2 = emoticonsList.begin();
622 bool ok = true;
623 // for each emoticon in our list
624 for(;it2!=emoticonsList.end(); ++it2)
626 QString es=Qt::escape(it2.key());
627 QString message1=message->escapedBody();
628 if(message1.contains(es))
630 QFile f(it2.value());
631 if(!f.exists())
633 // an emoticon is still missing, so wait for it
634 QLinkedList<Kopete::Message*> pmsgs = pendingMessages[conn];
635 message->setHtmlBody(message1);
636 pmsgs.removeOne((*it));
637 pmsgs.append((*it));
638 pendingMessages[conn] = pmsgs;
639 ok = false;
640 break;
642 QImage iconImage = QImageReader(it2.value()).read();
644 message1.replace( QRegExp(QString::fromLatin1("%1(?![^><]*>)").arg(QRegExp::escape(es))),
645 QString::fromLatin1("<img align=\"center\" width=\"") +
646 QString::number(iconImage.width()) +
647 QString::fromLatin1("\" height=\"") +
648 QString::number(iconImage.height()) +
649 QString::fromLatin1("\" src=\"") + it2.value() +
650 QString::fromLatin1("\" title=\"") + es +
651 QString::fromLatin1("\" alt=\"") + es +
652 QString::fromLatin1( "\"/>" ) );
653 message->setHtmlBody(message1);
656 if(ok)
658 chatSessions[conn]->appendMessage (*message);
659 pendingMessages[conn].removeOne(message);
660 delete message;
665 void
666 WlmChatManager::slotGotWinkFile(MSN::SwitchboardServerConnection * conn,
667 const unsigned int & sessionID,
668 const QString & file)
670 Q_UNUSED( conn );
671 Q_UNUSED( sessionID );
672 Q_UNUSED( file );
675 #include "wlmchatmanager.moc"