Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / meanwhile / meanwhilesession.cpp
blob4fb3cb54c34be3580b3d815e01a5f81f074a57da
1 /*
2 meanwhilesession.cpp - interface to the 'C' meanwhile library
4 Copyright (c) 2003-2004 by Sivaram Gottimukkala <suppandi@gmail.com>
5 Copyright (c) 2005 by Jeremy Kerr <jk@ozlabs.org>
7 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 *************************************************************************
19 #include <string.h>
20 #include <stdlib.h>
21 #include <kmessagebox.h>
22 #include <klocale.h>
23 #include <qtcpsocket.h>
25 #include <kopetepassword.h>
26 #include <kopetechatsession.h>
27 #include <kopetegroup.h>
28 #include <kopetecontactlist.h>
29 #include "meanwhilesession.h"
30 #include "meanwhileprotocol.h"
32 #include <meanwhile/mw_channel.h>
33 #include <meanwhile/mw_message.h>
34 #include <meanwhile/mw_error.h>
35 #include <meanwhile/mw_service.h>
36 #include <meanwhile/mw_session.h>
37 #include <meanwhile/mw_srvc_aware.h>
38 #include <meanwhile/mw_srvc_conf.h>
39 #include <meanwhile/mw_srvc_im.h>
40 #include <meanwhile/mw_srvc_store.h>
41 #include <meanwhile/mw_cipher.h>
42 #include <meanwhile/mw_st_list.h>
43 //Added by qt3to4:
44 #include <Q3ValueList>
46 #define set_session_handler(a,b) sessionHandler.a = _handleSession ## b
47 #define set_aware_handler(a,b) awareHandler.a = _handleAware ## b
48 #define set_aware_list_handler(a,b) \
49 awareListHandler.a = _handleAwareList ## b
50 #define set_im_handler(a,b) imHandler.a = _handleIm ## b
52 #define get_protocol() (static_cast<MeanwhileProtocol *>(account->protocol()))
54 static struct MeanwhileClientID ids[] = {
55 { mwLogin_LIB, "Lotus Binary Library" },
56 { mwLogin_JAVA_WEB, "Lotus Java Applet", },
57 { mwLogin_BINARY, "Lotus Binary App", },
58 { mwLogin_JAVA_APP, "Lotus Java App", },
59 { mwLogin_LINKS, "Sametime Links", },
61 { mwLogin_NOTES_6_5, "Notes 6.5", },
62 { mwLogin_NOTES_6_5_3, "Notes 6.5.3", },
63 { mwLogin_NOTES_7_0_beta, "Notes 7.0 beta", },
64 { mwLogin_NOTES_7_0, "Notes 7.0", },
65 { mwLogin_ICT, "ICT", },
66 { mwLogin_ICT_1_7_8_2, "ICT 1.7.8.2", },
67 { mwLogin_ICT_SIP, "ICT SIP", },
68 { mwLogin_NOTESBUDDY_4_14, "NotesBuddy 4.14", },
69 { mwLogin_NOTESBUDDY_4_15, "NotesBuddy 4.15" },
70 { mwLogin_NOTESBUDDY_4_16, "NotesBuddy 4.16" },
71 { mwLogin_SANITY, "Sanity", },
72 { mwLogin_ST_PERL, "ST Perl", },
73 { mwLogin_PMR_ALERT, "PMR Alert", },
74 { mwLogin_TRILLIAN, "Trillian", },
75 { mwLogin_TRILLIAN_IBM, "Trillian (IBM)", },
76 { mwLogin_MEANWHILE, "Meanwhile Library", },
77 { 0, NULL },
81 MeanwhileSession::MeanwhileSession(MeanwhileAccount *acc)
82 : session(0), state(mwSession_STOPPED), account(acc), socket(0)
84 HERE;
86 /* set up main session hander */
87 memset(&sessionHandler, 0, sizeof(sessionHandler));
88 set_session_handler(io_write, IOWrite);
89 set_session_handler(io_close, IOClose);
90 set_session_handler(on_stateChange, StateChange);
91 set_session_handler(on_setPrivacyInfo, SetPrivacyInfo);
92 set_session_handler(on_setUserStatus, SetUserStatus);
93 set_session_handler(on_admin, Admin);
94 set_session_handler(on_announce, Announce);
95 set_session_handler(clear, Clear);
97 session = mwSession_new(&sessionHandler);
98 mwSession_setClientData(session, this, 0L);
100 /* set up the aware service */
101 memset(&awareHandler, 0, sizeof(awareHandler));
102 set_aware_handler(on_attrib, Attrib);
104 awareService = mwServiceAware_new(session, &awareHandler);
105 mwSession_addService(session, (struct mwService *)awareService);
107 /* create an aware list */
108 memset(&awareListHandler, 0, sizeof(awareListHandler));
109 set_aware_list_handler(on_aware, Aware);
110 set_aware_list_handler(on_attrib, Attrib);
111 awareList = mwAwareList_new(awareService, &awareListHandler);
112 mwAwareList_setClientData(awareList, this, 0L);
114 /* set up an im service */
115 memset(&imHandler, 0, sizeof(imHandler));
116 set_im_handler(conversation_opened, ConvOpened);
117 set_im_handler(conversation_closed, ConvClosed);
118 set_im_handler(conversation_recv, ConvReceived);
119 imHandler.place_invite = 0L;
120 imHandler.clear = 0L;
122 imService = mwServiceIm_new(session, &imHandler);
123 mwService_setClientData((struct mwService *)imService, this, 0L);
124 mwSession_addService(session, (struct mwService *) imService);
126 /* add resolve service */
127 resolveService = mwServiceResolve_new(session);
128 mwService_setClientData((struct mwService *)resolveService, this, 0L);
129 mwSession_addService(session, (struct mwService *) resolveService);
131 /* storage service */
132 storageService = mwServiceStorage_new(session);
133 mwService_setClientData((struct mwService *)storageService, this, 0L);
134 mwSession_addService(session, (struct mwService *) storageService);
136 #if 0
137 /* conference service setup - just declines invites for now. */
138 memset(&conf_handler, 0, sizeof(conf_handler));
139 conf_handler.on_invited = _conference_invite;
141 srvc_conf = mwServiceConference_new(session, &conf_handler);
142 mwService_setClientData((struct mwService *)srvc_conf, this, 0L);
143 mwSession_addService(session, (struct mwService *) srvc_conf);
144 #endif
146 /* add a necessary cipher */
147 mwSession_addCipher(session, mwCipher_new_RC2_40(session));
148 mwSession_addCipher(session, mwCipher_new_RC2_128(session));
151 MeanwhileSession::~MeanwhileSession()
153 HERE;
154 if (isConnected() || isConnecting())
155 disconnect();
157 mwSession_removeService(session, mwService_STORAGE);
158 mwSession_removeService(session, mwService_RESOLVE);
159 mwSession_removeService(session, mwService_IM);
160 mwSession_removeService(session, mwService_AWARE);
162 mwAwareList_free(awareList);
163 mwService_free(MW_SERVICE(storageService));
164 mwService_free(MW_SERVICE(resolveService));
165 mwService_free(MW_SERVICE(imService));
166 mwService_free(MW_SERVICE(awareService));
167 mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
168 mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
170 mwSession_free(session);
173 void MeanwhileSession::getDefaultClientIDParams(int *clientID,
174 int *verMajor, int *verMinor)
176 *clientID = mwLogin_MEANWHILE;
177 *verMajor = MW_PROTOCOL_VERSION_MAJOR;
178 *verMinor = MW_PROTOCOL_VERSION_MINOR;
181 /* external interface called by meanwhileaccount */
182 void MeanwhileSession::connect(QString password)
184 HERE;
186 int port, clientID, versionMajor, versionMinor;
187 bool useCustomID;
188 QString host;
190 host = account->getServerName();
191 port = account->getServerPort();
192 useCustomID = account->getClientIDParams(&clientID,
193 &versionMajor, &versionMinor);
196 QTcpSocket *sock = new QTcpSocket(this);
197 sock->connectToHost(host, quint16(port));
199 // TODO - make asynchronous
200 if (!sock->waitForConnected()) {
201 KMessageBox::queuedMessageBox(0, KMessageBox::Error,
202 i18n( "Could not connect to server"), i18n("Meanwhile Plugin"),
203 KMessageBox::Notify);
204 delete sock;
205 return;
207 socket = sock;
208 /* we want to receive signals when there is data to read */
209 QObject::connect(sock, SIGNAL(readyRead()), this,
210 SLOT(slotSocketDataAvailable()));
211 QObject::connect(sock, SIGNAL(aboutToClose()), this,
212 SLOT(slotSocketAboutToClose()));
214 /* set login details */
215 mwSession_setProperty(session, mwSession_AUTH_USER_ID,
216 g_strdup(account->meanwhileId().toAscii()), g_free);
217 mwSession_setProperty(session, mwSession_AUTH_PASSWORD,
218 g_strdup(password.toAscii()), g_free);
220 /* set client type parameters */
221 if (useCustomID) {
222 mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID,
223 GUINT_TO_POINTER(clientID), NULL);
224 mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR,
225 GUINT_TO_POINTER(versionMajor), NULL);
226 mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR,
227 GUINT_TO_POINTER(versionMinor), NULL);
231 /* go!! */
232 mwSession_start(session);
235 void MeanwhileSession::disconnect()
237 HERE;
238 if (state == mwSession_STOPPED || state == mwSession_STOPPING)
239 return;
241 mwSession_stop(session, ERR_SUCCESS);
244 bool MeanwhileSession::isConnected()
246 return mwSession_isStarted(session);
249 bool MeanwhileSession::isConnecting()
251 return mwSession_isStarting(session);
254 static void free_id_block(void *data, void *p)
256 if (p != 0 || data == 0)
257 return;
259 struct mwAwareIdBlock *id = reinterpret_cast<struct mwAwareIdBlock *>(data);
260 delete [] id->user;
261 free(id);
264 void MeanwhileSession::addContacts(const QHash<QString, Kopete::Contact *> &contacts)
266 HERE;
267 GList *buddies = 0;
268 QHash<QString, Kopete::Contact *>::const_iterator it = contacts.constBegin();
270 /** Convert our QDict of kopete contact to a GList of meanwhile buddies */
271 for( ; it != contacts.constEnd(); ++it) {
272 MeanwhileContact *contact = static_cast<MeanwhileContact *>(it.value());
273 struct mwAwareIdBlock *id = reinterpret_cast<struct mwAwareIdBlock *>(malloc(sizeof(*id)));
274 if (!id)
275 continue;
276 id->user = qstrdup(contact->meanwhileId().toUtf8().constData());
277 id->community = 0;
278 id->type = mwAware_USER;
279 buddies = g_list_append(buddies, id);
282 mwAwareList_addAware(awareList, buddies);
284 g_list_foreach(buddies, free_id_block, 0);
285 g_list_free(buddies);
288 /* private functions used only by the meanwhile session object */
289 void MeanwhileSession::addContact(const Kopete::Contact *contact)
291 HERE;
292 struct mwAwareIdBlock id = { mwAware_USER,
293 strdup(static_cast<const MeanwhileContact *>(contact)
294 ->meanwhileId().toAscii()),
295 0L };
297 GList *buddies = g_list_prepend(0L, &id);
298 mwAwareList_addAware(awareList, buddies);
299 g_list_free(buddies);
300 free(id.user);
303 int MeanwhileSession::sendMessage(Kopete::Message &message)
305 HERE;
306 MeanwhileContact *contact =
307 static_cast<MeanwhileContact *>(message.to().first());
308 if (!contact) {
309 mwDebug() << "No target for message!" <<endl;
310 return 0;
313 struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
314 struct mwConversation *conv;
316 conv = mwServiceIm_getConversation(imService, &target);
317 free(target.user);
318 if (conv == 0L) {
319 mwDebug() << "No target for conversation with '"
320 << contact->meanwhileId() << "'" << endl;
321 return 0;
324 struct ConversationData *convdata = (struct ConversationData *)
325 mwConversation_getClientData(conv);
327 if (convdata == 0L) {
328 convdata = createConversationData(conv, contact, true);
329 if (convdata == 0L) {
330 mwDebug() << "No memory for conversation data!" << endl;
331 return 0;
335 /* if there's other messages in the queue, or the conversation isn't open,
336 * then append to the queue instead of sending right away */
337 if ((convdata->queue && !convdata->queue->isEmpty()) ||
338 !mwConversation_isOpen(conv)) {
339 convdata->queue->append(message);
340 mwConversation_open(conv);
342 } else if (!mwConversation_send(conv, mwImSend_PLAIN,
343 message.plainBody().toAscii())) {
344 convdata->chat->appendMessage(message);
345 convdata->chat->messageSucceeded();
347 return 1;
350 void MeanwhileSession::sendTyping(MeanwhileContact *contact, bool isTyping)
352 HERE;
353 struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
354 struct mwConversation *conv;
356 conv = mwServiceIm_getConversation(imService, &target);
357 free(target.user);
358 if (conv == 0L)
359 return;
361 if (mwConversation_isOpen(conv))
362 mwConversation_send(conv, mwImSend_TYPING, (void *)isTyping);
365 void MeanwhileSession::setStatus(Kopete::OnlineStatus status,
366 const Kopete::StatusMessage &msg)
368 HERE;
369 mwDebug() << "setStatus: " << status.description() << '('
370 << status.internalStatus() << ')' << endl;
371 if (status.internalStatus() == 0)
372 return;
374 struct mwUserStatus stat;
375 mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
377 free(stat.desc);
379 stat.status = (mwStatusType)status.internalStatus();
380 if (msg.isEmpty())
381 stat.desc = ::strdup(status.description().toUtf8().constData());
382 else
383 stat.desc = ::strdup(msg.message().toUtf8().constData());
385 mwSession_setUserStatus(session, &stat);
386 /* will free stat.desc */
387 mwUserStatus_clear(&stat);
390 void MeanwhileSession::syncContactsToServer()
392 HERE;
393 struct mwSametimeList *list = mwSametimeList_new();
395 /* set up a fallback group for top-level contacts */
396 struct mwSametimeGroup *topstgroup = mwSametimeGroup_new(list,
397 mwSametimeGroup_DYNAMIC, "People");
398 mwSametimeGroup_setOpen(topstgroup, true);
400 const QHash<QString, Kopete::Contact *> contacts = account->contacts();
401 // Q3DictIterator<Kopete::Contact> it(account->contacts());
402 for(QHash<QString, Kopete::Contact *>::const_iterator it = contacts.constBegin();
403 it != contacts.constEnd(); ++it ) {
404 MeanwhileContact *contact = static_cast<MeanwhileContact *>(it.value());
406 /* Find the group that the metacontact is in */
407 Kopete::MetaContact *mc = contact->metaContact();
408 /* myself doesn't have a metacontact */
409 if (!mc)
410 continue;
412 Kopete::Group *contactgroup = mc->groups().value(0);
413 if (!contactgroup)
414 continue;
416 if (contactgroup->type() == Kopete::Group::Temporary)
417 continue;
419 struct mwSametimeGroup *stgroup;
420 if (contactgroup->type() == Kopete::Group::TopLevel) {
421 stgroup = topstgroup;
422 } else {
423 /* find (or create) a matching sametime list group */
424 stgroup = mwSametimeList_findGroup(list,
425 contactgroup->displayName().toUtf8().constData());
426 if (!stgroup) {
427 stgroup = mwSametimeGroup_new(list, mwSametimeGroup_DYNAMIC,
428 contactgroup->displayName().toUtf8().constData());
430 mwSametimeGroup_setOpen(stgroup, contactgroup->isExpanded());
431 mwSametimeGroup_setAlias(stgroup,
432 contactgroup->pluginData(account->protocol(), "alias").toUtf8().constData());
435 QByteArray tmpMeanwhileId = contact->meanwhileId().toUtf8();
436 /* now add the user (by IDBlock) */
437 struct mwIdBlock id =
438 { (gchar*)tmpMeanwhileId.constData(), 0 };
439 struct mwSametimeUser *stuser = mwSametimeUser_new(stgroup,
440 mwSametimeUser_NORMAL, &id);
442 mwSametimeUser_setAlias(stuser, contact->nickName().toUtf8().constData());
445 /* store! */
446 struct mwPutBuffer *buf = mwPutBuffer_new();
447 struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
448 struct mwOpaque *opaque = mwStorageUnit_asOpaque(unit);
450 mwSametimeList_put(buf, list);
451 mwPutBuffer_finalize(opaque, buf);
453 mwServiceStorage_save(storageService, unit, NULL, NULL, NULL);
455 mwSametimeList_free(list);
458 void MeanwhileSession::syncContactsFromServer()
460 struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
461 mwServiceStorage_load(storageService, unit, &_handleStorageLoad, 0L, 0L);
464 #define MEANWHILE_SESSION_BUFSIZ 4096
466 void MeanwhileSession::slotSocketDataAvailable()
468 HERE;
469 guchar *buf;
470 qint64 bytesRead;
472 if (!socket)
473 return;
475 if (!(buf = (guchar *)malloc(MEANWHILE_SESSION_BUFSIZ))) {
476 mwDebug() << "buffer malloc failed" << endl;
477 return;
480 while (socket && socket->bytesAvailable() > 0) {
481 bytesRead = socket->read((char *)buf, MEANWHILE_SESSION_BUFSIZ);
482 if (bytesRead < 0)
483 break;
484 mwSession_recv(session, buf, (unsigned int)bytesRead);
486 free(buf);
489 void MeanwhileSession::slotSocketAboutToClose()
491 HERE;
493 /* TODO -error handling
494 if (reason & KExtendedSocket::involuntary)
495 emit serverNotification(
496 QString("Lost connection with Meanwhile server"));
499 mwSession_stop(session, 0x00);
503 Kopete::OnlineStatus MeanwhileSession::convertStatus(int mstatus)
505 MeanwhileProtocol *protocol =
506 static_cast<MeanwhileProtocol *>(account->protocol());
508 switch (mstatus) {
509 case mwStatus_ACTIVE:
510 return protocol->statusOnline;
511 break;
512 case mwStatus_IDLE:
513 return protocol->statusIdle;
514 break;
515 case mwStatus_AWAY:
516 return protocol->statusAway;
517 break;
518 case mwStatus_BUSY:
519 return protocol->statusBusy;
520 break;
521 case 0:
522 return protocol->statusOffline;
523 break;
524 default:
525 mwDebug() << "unknown status lookup: " << mstatus << endl;
527 return protocol->statusOffline;
530 void MeanwhileSession::resolveContactNickname(MeanwhileContact *contact)
532 /* @todo: FIXME: leak! */
533 char *id = strdup(contact->meanwhileId().toAscii());
534 GList *query = g_list_prepend(NULL, id);
535 mwServiceResolve_resolve(resolveService, query, mwResolveFlag_USERS,
536 _handleResolveLookupResults, contact, NULL);
539 QString MeanwhileSession::getNickName(struct mwLoginInfo *logininfo)
541 if (logininfo == 0L || logininfo->user_name == 0L)
542 return QString();
543 return getNickName(logininfo->user_name);
546 QString MeanwhileSession::getNickName(QString name)
549 int index = name.indexOf(QLatin1String(" - "));
550 if (index != -1)
551 name.remove(0, index + 3);
552 index = name.indexOf(QLatin1Char('/'));
553 if (index != -1)
554 name = name.left(index);
556 return name;
559 MeanwhileContact *MeanwhileSession::conversationContact(
560 struct mwConversation *conv)
562 struct mwIdBlock *target = mwConversation_getTarget(conv);
563 if (target == 0L || target->user == 0L) {
564 return 0L;
566 QString user(target->user);
568 MeanwhileContact *contact =
569 static_cast<MeanwhileContact *>(account->contacts()[user]);
571 struct mwLoginInfo *logininfo = mwConversation_getTargetInfo(conv);
572 QString name = getNickName(logininfo);
574 if (!contact) {
575 account->addContact(user, name, 0L, Kopete::Account::Temporary);
576 contact = static_cast<MeanwhileContact *>(account->contacts()[user]);
577 } else
578 contact->setNickName(name);
580 return contact;
583 void MeanwhileSession::handleRedirect(const char *host)
585 /* if configured manually, force the login */
586 if (account->getForceLogin()) {
587 mwSession_forceLogin(session);
588 return;
591 /* if we're connecting to the same host, force */
592 if (!host || account->getServerName() == host) {
593 mwSession_forceLogin(session);
594 return;
597 QTcpSocket *sock = new QTcpSocket(this);
598 sock->connectToHost(host, quint16(account->getServerPort()));
600 if (!sock->waitForConnected()) {
601 KMessageBox::queuedMessageBox(0, KMessageBox::Error,
602 i18n( "Could not connect to redirected server"),
603 i18n("Meanwhile Plugin"),
604 KMessageBox::Notify);
605 delete sock;
606 mwSession_forceLogin(session);
607 return;
610 /* we've redirected, so swap the sockets */
611 delete this->socket;
612 this->socket = sock;
614 /* we want to receive signals when there is data to read */
615 QObject::connect(sock, SIGNAL(readyRead()), this,
616 SLOT(slotSocketDataAvailable()));
617 QObject::connect(sock, SIGNAL(aboutToClose()), this,
618 SLOT(slotSocketAboutToClose()));
621 /* priave session handling functions, called by libmeanwhile callbacks */
622 void MeanwhileSession::handleSessionStateChange(
623 enum mwSessionState state, gpointer data)
625 HERE;
626 this->state = state;
628 switch (state) {
629 case mwSession_STARTING:
630 case mwSession_HANDSHAKE:
631 case mwSession_HANDSHAKE_ACK:
632 case mwSession_LOGIN:
633 case mwSession_LOGIN_CONT:
634 case mwSession_LOGIN_ACK:
635 break;
637 case mwSession_LOGIN_REDIR:
638 handleRedirect((char *)data);
639 break;
641 case mwSession_STARTED:
643 struct mwUserStatus stat = { mwStatus_ACTIVE, 0, 0L };
644 mwSession_setUserStatus(session, &stat);
645 struct mwLoginInfo *logininfo = mwSession_getLoginInfo(session);
646 if (logininfo) {
647 account->myself()->setNickName(getNickName(logininfo));
649 syncContactsFromServer();
651 break;
653 case mwSession_STOPPING:
655 unsigned int info = GPOINTER_TO_UINT(data);
656 if (info & ERR_FAILURE) {
657 if (info == INCORRECT_LOGIN)
658 account->password().setWrong();
659 char *reason = mwError(info);
660 emit serverNotification(QString(reason));
661 free(reason);
665 emit sessionStateChange(
666 static_cast<MeanwhileProtocol *>(account->protocol())
667 ->statusOffline);
668 break;
670 case mwSession_STOPPED:
671 break;
673 case mwSession_UNKNOWN:
674 default:
675 mwDebug() << "Unhandled state change " << state << endl;
679 int MeanwhileSession::handleSessionIOWrite(const guchar *buffer,
680 gsize count)
682 HERE;
684 if (socket == 0L)
685 return 1;
687 int remaining, retval = 0;
688 for (remaining = count; remaining > 0; remaining -= retval) {
689 retval = socket->write((char *)buffer, count);
690 if (retval <= 0)
691 return 1;
693 socket->flush();
694 return 0;
697 void MeanwhileSession::handleSessionAdmin(const char *text)
699 HERE;
700 emit serverNotification(QString(text));
703 void MeanwhileSession::handleSessionAnnounce(struct mwLoginInfo *from,
704 gboolean /* may_reply */, const char *text)
706 HERE;
707 QString message;
708 message.sprintf("Announcement from %s:\n%s", from->user_id, text);
709 emit serverNotification(message);
712 void MeanwhileSession::handleSessionSetUserStatus()
714 struct mwUserStatus *userstatus = mwSession_getUserStatus(session);
715 emit sessionStateChange(convertStatus((unsigned int)userstatus->status));
718 void MeanwhileSession::handleSessionSetPrivacyInfo()
722 void MeanwhileSession::handleSessionIOClose()
724 HERE;
726 if (!socket)
727 return;
729 socket->flush();
730 socket->close();
732 delete socket;
733 socket = 0;
736 void MeanwhileSession::handleSessionClear()
740 void MeanwhileSession::handleAwareAttrib(struct mwAwareAttribute * /* attrib */)
742 HERE;
745 void MeanwhileSession::handleAwareListAware(struct mwAwareSnapshot *snapshot)
747 HERE;
748 MeanwhileContact *contact = static_cast<MeanwhileContact *>
749 (account->contacts()[snapshot->id.user]);
751 if (contact == 0L)
752 return;
754 /* use the setUserStatus callback for status updates for myself. */
755 if (contact == account->myself())
756 return;
758 /* ### TODO!!
759 contact->setProperty(get_protocol()->statusMessage, snapshot->status.desc);
760 contact->setProperty(get_protocol()->awayMessage, snapshot->status.desc);
763 Kopete::OnlineStatus onlinestatus;
764 if (snapshot->online) {
765 onlinestatus = convertStatus(snapshot->status.status);
766 resolveContactNickname(contact);
767 } else {
768 onlinestatus = convertStatus(0);
771 contact->setOnlineStatus(onlinestatus);
773 #if 0
774 /* Commented out in previous kopete/meanwhile plugin for some reason,
775 * but has still been ported to the new API.
777 time_t idletime = 0;
778 if (snapshot->status.status == mwStatus_IDLE) {
779 idletime = (snapshot->status.time == 0xdeadbeef) ?
780 0 : snapshot->status.time;
781 if (idletime != 0) {
782 contact->setStatusDescription(statusDesc + '[' +
783 QString::number(idletime/60)+" mins]");
785 } else
786 contact->setStatusDescription(snapshot->status.desc);
787 #endif
790 void MeanwhileSession::handleAwareListAttrib(struct mwAwareIdBlock * /* id */,
791 struct mwAwareAttribute * /* attrib */)
793 HERE;
796 struct MeanwhileSession::ConversationData
797 *MeanwhileSession::createConversationData(
798 struct mwConversation *conv, MeanwhileContact *contact,
799 bool createQueue)
801 struct ConversationData *cd = new ConversationData();
803 if (cd == 0L)
804 return 0L;
806 cd->contact = contact;
807 cd->chat = contact->manager(Kopete::Contact::CanCreate);
808 cd->chat->ref();
809 if (createQueue)
810 cd->queue = new Q3ValueList<Kopete::Message>();
812 mwConversation_setClientData(conv, cd, 0L);
814 return cd;
817 void MeanwhileSession::handleImConvOpened(struct mwConversation *conv)
819 HERE;
821 struct ConversationData *convdata =
822 (struct ConversationData *)mwConversation_getClientData(conv);
824 if (convdata == 0L) {
825 /* a new conversation */
826 convdata = createConversationData(conv, conversationContact(conv));
828 if (convdata == 0L) {
829 mwDebug() << "No memory for conversation data!" << endl;
830 return;
833 } else if (convdata->queue && !convdata->queue->isEmpty()) {
834 /* send any messages that were waiting for the conversation to open */
835 Q3ValueList<Kopete::Message>::iterator it;
836 for (it = convdata->queue->begin(); it != convdata->queue->end();
837 ++it) {
838 mwConversation_send(conv, mwImSend_PLAIN,
839 (*it).plainBody().toAscii());
840 convdata->chat->appendMessage(*it);
841 convdata->chat->messageSucceeded();
843 convdata->queue->clear();
844 delete convdata->queue;
845 convdata->queue = 0L;
847 resolveContactNickname(convdata->contact);
850 void MeanwhileSession::handleImConvClosed(struct mwConversation *conv,
851 guint32)
853 HERE;
855 ConversationData *convdata =
856 (ConversationData *)mwConversation_getClientData(conv);
858 if (!convdata)
859 return;
861 mwConversation_setClientData(conv, 0L, 0L);
863 convdata->chat->removeContact(convdata->contact);
864 convdata->chat->deref();
865 convdata->chat = 0L;
866 if (convdata->queue != 0L) {
867 convdata->queue->clear();
868 delete convdata->queue;
869 convdata->queue = 0L;
871 free(convdata);
874 void MeanwhileSession::handleImConvReceived(struct mwConversation *conv,
875 enum mwImSendType type, gconstpointer msg)
877 HERE;
878 ConversationData *convdata =
879 (ConversationData *)mwConversation_getClientData(conv);
881 if (!convdata)
882 return;
884 switch (type) {
885 case mwImSend_PLAIN:
887 Kopete::Message message(convdata->contact, account->myself());
888 message.setPlainBody(QString::fromUtf8((const char *)msg));
889 message.setDirection(Kopete::Message::Inbound);
890 convdata->chat->appendMessage(message);
892 break;
893 case mwImSend_TYPING:
894 convdata->chat->receivedTypingMsg(convdata->contact);
895 break;
896 default:
897 mwDebug() << "Unable to handle message type: " << type << endl;
901 void MeanwhileSession::handleResolveLookupResults(
902 struct mwServiceResolve * /* srvc */, guint32 /* id */,
903 guint32 /* code */, GList *results, gpointer data)
905 struct mwResolveResult *result;
906 struct mwResolveMatch *match;
908 if (results == 0L)
909 return;
910 if ((result = (struct mwResolveResult *)results->data) == 0L)
911 return;
913 if (result->matches == 0L)
914 return;
915 if ((match = (struct mwResolveMatch *)result->matches->data) == 0L)
916 return;
918 mwDebug() << "resolve lookup returned '" << match->name << "'" << endl;
920 MeanwhileContact *contact = (MeanwhileContact *)data;
921 if (contact == 0L)
922 return;
924 contact->setNickName(getNickName(match->name));
927 void MeanwhileSession::handleStorageLoad(struct mwServiceStorage * /* srvc */,
928 guint32 result, struct mwStorageUnit *item, gpointer /* data */)
930 HERE;
931 if (result != ERR_SUCCESS) {
932 mwDebug() << "contact list load returned " << result << endl;
933 return;
936 struct mwGetBuffer *buf = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
937 struct mwSametimeList *list = mwSametimeList_new();
938 mwSametimeList_get(buf, list);
940 GList *gl, *glf, *cl, *clf;
942 Kopete::ContactList *contactlist = Kopete::ContactList::self();
944 for (glf = gl = mwSametimeList_getGroups(list); gl; gl = gl->next) {
945 struct mwSametimeGroup *stgroup = (struct mwSametimeGroup *)gl->data;
947 Kopete::Group *group =
948 contactlist->findGroup(mwSametimeGroup_getName(stgroup));
949 group->setPluginData(account->protocol(), "alias",
950 mwSametimeGroup_getAlias(stgroup));
952 for (clf = cl = mwSametimeGroup_getUsers(stgroup); cl; cl = cl->next) {
953 struct mwSametimeUser *stuser = (struct mwSametimeUser *)cl->data;
955 MeanwhileContact *contact = static_cast<MeanwhileContact *>
956 (account->contacts()[mwSametimeUser_getUser(stuser)]);
958 if (contact != 0L)
959 continue;
961 account->addContact(mwSametimeUser_getUser(stuser),
962 mwSametimeUser_getAlias(stuser), group,
963 Kopete::Account::ChangeKABC);
965 g_list_free(clf);
967 g_list_free(glf);
969 mwSametimeList_free(list);
972 const struct MeanwhileClientID *MeanwhileSession::getClientIDs()
974 return ids;
977 #if 0
978 MEANWHILE_HOOK_CONFERENCE(conference_invite,
979 (struct mwConference *conf, struct mwLoginInfo *inviter,
980 const char *invite),
981 (conf, inviter, invite))
983 HERE;
984 QString message;
986 message.sprintf("%s has invited you to a conference called \"%s\"\n"
987 "However, this version of the meanwhile plugin does "
988 "not support conferences, so the invitiation has been declined.",
989 inviter->user_id, invite);
991 mwConference_reject(conf, ERR_SUCCESS,
992 "Sorry, my client doesn't support conferences!");
993 KMessageBox::queuedMessageBox(0, KMessageBox::Sorry , message,
994 i18n("Meanwhile Plugin: Conference invitation"),
995 KMessageBox::Notify);
997 #endif
998 #include "meanwhilesession.moc"