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 *************************************************************************
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. *
16 *************************************************************************
21 #include <kmessagebox.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>
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", },
81 MeanwhileSession::MeanwhileSession(MeanwhileAccount
*acc
)
82 : session(0), state(mwSession_STOPPED
), account(acc
), socket(0)
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
);
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
);
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()
154 if (isConnected() || isConnecting())
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
)
186 int port
, clientID
, versionMajor
, versionMinor
;
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
);
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 */
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
);
232 mwSession_start(session
);
235 void MeanwhileSession::disconnect()
238 if (state
== mwSession_STOPPED
|| state
== mwSession_STOPPING
)
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)
259 struct mwAwareIdBlock
*id
= reinterpret_cast<struct mwAwareIdBlock
*>(data
);
264 void MeanwhileSession::addContacts(const QHash
<QString
, Kopete::Contact
*> &contacts
)
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
)));
276 id
->user
= qstrdup(contact
->meanwhileId().toUtf8().constData());
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
)
292 struct mwAwareIdBlock id
= { mwAware_USER
,
293 strdup(static_cast<const MeanwhileContact
*>(contact
)
294 ->meanwhileId().toAscii()),
297 GList
*buddies
= g_list_prepend(0L, &id
);
298 mwAwareList_addAware(awareList
, buddies
);
299 g_list_free(buddies
);
303 int MeanwhileSession::sendMessage(Kopete::Message
&message
)
306 MeanwhileContact
*contact
=
307 static_cast<MeanwhileContact
*>(message
.to().first());
309 mwDebug() << "No target for message!" <<endl
;
313 struct mwIdBlock target
= { strdup(contact
->meanwhileId().toAscii()), 0L };
314 struct mwConversation
*conv
;
316 conv
= mwServiceIm_getConversation(imService
, &target
);
319 mwDebug() << "No target for conversation with '"
320 << contact
->meanwhileId() << "'" << endl
;
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
;
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();
350 void MeanwhileSession::sendTyping(MeanwhileContact
*contact
, bool isTyping
)
353 struct mwIdBlock target
= { strdup(contact
->meanwhileId().toAscii()), 0L };
354 struct mwConversation
*conv
;
356 conv
= mwServiceIm_getConversation(imService
, &target
);
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
)
369 mwDebug() << "setStatus: " << status
.description() << '('
370 << status
.internalStatus() << ')' << endl
;
371 if (status
.internalStatus() == 0)
374 struct mwUserStatus stat
;
375 mwUserStatus_clone(&stat
, mwSession_getUserStatus(session
));
379 stat
.status
= (mwStatusType
)status
.internalStatus();
381 stat
.desc
= ::strdup(status
.description().toUtf8().constData());
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()
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 */
412 Kopete::Group
*contactgroup
= mc
->groups().value(0);
416 if (contactgroup
->type() == Kopete::Group::Temporary
)
419 struct mwSametimeGroup
*stgroup
;
420 if (contactgroup
->type() == Kopete::Group::TopLevel
) {
421 stgroup
= topstgroup
;
423 /* find (or create) a matching sametime list group */
424 stgroup
= mwSametimeList_findGroup(list
,
425 contactgroup
->displayName().toUtf8().constData());
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());
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()
475 if (!(buf
= (guchar
*)malloc(MEANWHILE_SESSION_BUFSIZ
))) {
476 mwDebug() << "buffer malloc failed" << endl
;
480 while (socket
&& socket
->bytesAvailable() > 0) {
481 bytesRead
= socket
->read((char *)buf
, MEANWHILE_SESSION_BUFSIZ
);
484 mwSession_recv(session
, buf
, (unsigned int)bytesRead
);
489 void MeanwhileSession::slotSocketAboutToClose()
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());
509 case mwStatus_ACTIVE
:
510 return protocol
->statusOnline
;
513 return protocol
->statusIdle
;
516 return protocol
->statusAway
;
519 return protocol
->statusBusy
;
522 return protocol
->statusOffline
;
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)
543 return getNickName(logininfo
->user_name
);
546 QString
MeanwhileSession::getNickName(QString name
)
549 int index
= name
.indexOf(QLatin1String(" - "));
551 name
.remove(0, index
+ 3);
552 index
= name
.indexOf(QLatin1Char('/'));
554 name
= name
.left(index
);
559 MeanwhileContact
*MeanwhileSession::conversationContact(
560 struct mwConversation
*conv
)
562 struct mwIdBlock
*target
= mwConversation_getTarget(conv
);
563 if (target
== 0L || target
->user
== 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
);
575 account
->addContact(user
, name
, 0L, Kopete::Account::Temporary
);
576 contact
= static_cast<MeanwhileContact
*>(account
->contacts()[user
]);
578 contact
->setNickName(name
);
583 void MeanwhileSession::handleRedirect(const char *host
)
585 /* if configured manually, force the login */
586 if (account
->getForceLogin()) {
587 mwSession_forceLogin(session
);
591 /* if we're connecting to the same host, force */
592 if (!host
|| account
->getServerName() == host
) {
593 mwSession_forceLogin(session
);
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
);
606 mwSession_forceLogin(session
);
610 /* we've redirected, so swap the sockets */
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
)
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
:
637 case mwSession_LOGIN_REDIR
:
638 handleRedirect((char *)data
);
641 case mwSession_STARTED
:
643 struct mwUserStatus stat
= { mwStatus_ACTIVE
, 0, 0L };
644 mwSession_setUserStatus(session
, &stat
);
645 struct mwLoginInfo
*logininfo
= mwSession_getLoginInfo(session
);
647 account
->myself()->setNickName(getNickName(logininfo
));
649 syncContactsFromServer();
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
));
665 emit
sessionStateChange(
666 static_cast<MeanwhileProtocol
*>(account
->protocol())
670 case mwSession_STOPPED
:
673 case mwSession_UNKNOWN
:
675 mwDebug() << "Unhandled state change " << state
<< endl
;
679 int MeanwhileSession::handleSessionIOWrite(const guchar
*buffer
,
687 int remaining
, retval
= 0;
688 for (remaining
= count
; remaining
> 0; remaining
-= retval
) {
689 retval
= socket
->write((char *)buffer
, count
);
697 void MeanwhileSession::handleSessionAdmin(const char *text
)
700 emit
serverNotification(QString(text
));
703 void MeanwhileSession::handleSessionAnnounce(struct mwLoginInfo
*from
,
704 gboolean
/* may_reply */, const char *text
)
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()
736 void MeanwhileSession::handleSessionClear()
740 void MeanwhileSession::handleAwareAttrib(struct mwAwareAttribute
* /* attrib */)
745 void MeanwhileSession::handleAwareListAware(struct mwAwareSnapshot
*snapshot
)
748 MeanwhileContact
*contact
= static_cast<MeanwhileContact
*>
749 (account
->contacts()[snapshot
->id
.user
]);
754 /* use the setUserStatus callback for status updates for myself. */
755 if (contact
== account
->myself())
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
);
768 onlinestatus
= convertStatus(0);
771 contact
->setOnlineStatus(onlinestatus
);
774 /* Commented out in previous kopete/meanwhile plugin for some reason,
775 * but has still been ported to the new API.
778 if (snapshot
->status
.status
== mwStatus_IDLE
) {
779 idletime
= (snapshot
->status
.time
== 0xdeadbeef) ?
780 0 : snapshot
->status
.time
;
782 contact
->setStatusDescription(statusDesc
+ '[' +
783 QString::number(idletime
/60)+" mins]");
786 contact
->setStatusDescription(snapshot
->status
.desc
);
790 void MeanwhileSession::handleAwareListAttrib(struct mwAwareIdBlock
* /* id */,
791 struct mwAwareAttribute
* /* attrib */)
796 struct MeanwhileSession::ConversationData
797 *MeanwhileSession::createConversationData(
798 struct mwConversation
*conv
, MeanwhileContact
*contact
,
801 struct ConversationData
*cd
= new ConversationData();
806 cd
->contact
= contact
;
807 cd
->chat
= contact
->manager(Kopete::Contact::CanCreate
);
810 cd
->queue
= new Q3ValueList
<Kopete::Message
>();
812 mwConversation_setClientData(conv
, cd
, 0L);
817 void MeanwhileSession::handleImConvOpened(struct mwConversation
*conv
)
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
;
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();
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
,
855 ConversationData
*convdata
=
856 (ConversationData
*)mwConversation_getClientData(conv
);
861 mwConversation_setClientData(conv
, 0L, 0L);
863 convdata
->chat
->removeContact(convdata
->contact
);
864 convdata
->chat
->deref();
866 if (convdata
->queue
!= 0L) {
867 convdata
->queue
->clear();
868 delete convdata
->queue
;
869 convdata
->queue
= 0L;
874 void MeanwhileSession::handleImConvReceived(struct mwConversation
*conv
,
875 enum mwImSendType type
, gconstpointer msg
)
878 ConversationData
*convdata
=
879 (ConversationData
*)mwConversation_getClientData(conv
);
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
);
893 case mwImSend_TYPING
:
894 convdata
->chat
->receivedTypingMsg(convdata
->contact
);
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
;
910 if ((result
= (struct mwResolveResult
*)results
->data
) == 0L)
913 if (result
->matches
== 0L)
915 if ((match
= (struct mwResolveMatch
*)result
->matches
->data
) == 0L)
918 mwDebug() << "resolve lookup returned '" << match
->name
<< "'" << endl
;
920 MeanwhileContact
*contact
= (MeanwhileContact
*)data
;
924 contact
->setNickName(getNickName(match
->name
));
927 void MeanwhileSession::handleStorageLoad(struct mwServiceStorage
* /* srvc */,
928 guint32 result
, struct mwStorageUnit
*item
, gpointer
/* data */)
931 if (result
!= ERR_SUCCESS
) {
932 mwDebug() << "contact list load returned " << result
<< endl
;
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
)]);
961 account
->addContact(mwSametimeUser_getUser(stuser
),
962 mwSametimeUser_getAlias(stuser
), group
,
963 Kopete::Account::ChangeKABC
);
969 mwSametimeList_free(list
);
972 const struct MeanwhileClientID
*MeanwhileSession::getClientIDs()
978 MEANWHILE_HOOK_CONFERENCE(conference_invite
,
979 (struct mwConference
*conf
, struct mwLoginInfo
*inviter
,
981 (conf
, inviter
, invite
))
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
);
998 #include "meanwhilesession.moc"