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 <kopetesockettimeoutwatcher.h>
30
#include "meanwhilesession.h"
31
#include "meanwhileprotocol.h"
33
#include <meanwhile/mw_channel.h>
34
#include <meanwhile/mw_message.h>
35
#include <meanwhile/mw_error.h>
36
#include <meanwhile/mw_service.h>
37
#include <meanwhile/mw_session.h>
38
#include <meanwhile/mw_srvc_aware.h>
39
#include <meanwhile/mw_srvc_conf.h>
40
#include <meanwhile/mw_srvc_im.h>
41
#include <meanwhile/mw_srvc_store.h>
42
#include <meanwhile/mw_cipher.h>
43
#include <meanwhile/mw_st_list.h>
45
#include <Q3ValueList>
47
#define set_session_handler(a,b) sessionHandler.a = _handleSession ## b
48
#define set_aware_handler(a,b) awareHandler.a = _handleAware ## b
49
#define set_aware_list_handler(a,b) \
50
awareListHandler.a = _handleAwareList ## b
51
#define set_im_handler(a,b) imHandler.a = _handleIm ## b
53
#define get_protocol() (static_cast<MeanwhileProtocol *>(account->protocol()))
55
static struct MeanwhileClientID ids[] = {
56
{ mwLogin_LIB, "Lotus Binary Library" },
57
{ mwLogin_JAVA_WEB, "Lotus Java Applet", },
58
{ mwLogin_BINARY, "Lotus Binary App", },
59
{ mwLogin_JAVA_APP, "Lotus Java App", },
60
{ mwLogin_LINKS, "Sametime Links", },
62
{ mwLogin_NOTES_6_5, "Notes 6.5", },
63
{ mwLogin_NOTES_6_5_3, "Notes 6.5.3", },
64
{ mwLogin_NOTES_7_0_beta, "Notes 7.0 beta", },
65
{ mwLogin_NOTES_7_0, "Notes 7.0", },
66
{ mwLogin_ICT, "ICT", },
67
{ mwLogin_ICT_1_7_8_2, "ICT 1.7.8.2", },
68
{ mwLogin_ICT_SIP, "ICT SIP", },
69
{ mwLogin_NOTESBUDDY_4_14, "NotesBuddy 4.14", },
70
{ mwLogin_NOTESBUDDY_4_15, "NotesBuddy 4.15" },
71
{ mwLogin_NOTESBUDDY_4_16, "NotesBuddy 4.16" },
72
{ mwLogin_SANITY, "Sanity", },
73
{ mwLogin_ST_PERL, "ST Perl", },
74
{ mwLogin_PMR_ALERT, "PMR Alert", },
75
{ mwLogin_TRILLIAN, "Trillian", },
76
{ mwLogin_TRILLIAN_IBM, "Trillian (IBM)", },
77
{ mwLogin_MEANWHILE, "Meanwhile Library", },
82
MeanwhileSession::MeanwhileSession(MeanwhileAccount *acc)
83
: session(0), state(mwSession_STOPPED), account(acc), socket(0)
87
/* set up main session hander */
88
memset(&sessionHandler, 0, sizeof(sessionHandler));
89
set_session_handler(io_write, IOWrite);
90
set_session_handler(io_close, IOClose);
91
set_session_handler(on_stateChange, StateChange);
92
set_session_handler(on_setPrivacyInfo, SetPrivacyInfo);
93
set_session_handler(on_setUserStatus, SetUserStatus);
94
set_session_handler(on_admin, Admin);
95
set_session_handler(on_announce, Announce);
96
set_session_handler(clear, Clear);
98
session = mwSession_new(&sessionHandler);
99
mwSession_setClientData(session, this, 0L);
101
/* set up the aware service */
102
memset(&awareHandler, 0, sizeof(awareHandler));
103
set_aware_handler(on_attrib, Attrib);
105
awareService = mwServiceAware_new(session, &awareHandler);
106
mwSession_addService(session, (struct mwService *)awareService);
108
/* create an aware list */
109
memset(&awareListHandler, 0, sizeof(awareListHandler));
110
set_aware_list_handler(on_aware, Aware);
111
set_aware_list_handler(on_attrib, Attrib);
112
awareList = mwAwareList_new(awareService, &awareListHandler);
113
mwAwareList_setClientData(awareList, this, 0L);
115
/* set up an im service */
116
memset(&imHandler, 0, sizeof(imHandler));
117
set_im_handler(conversation_opened, ConvOpened);
118
set_im_handler(conversation_closed, ConvClosed);
119
set_im_handler(conversation_recv, ConvReceived);
120
imHandler.place_invite = 0L;
121
imHandler.clear = 0L;
123
imService = mwServiceIm_new(session, &imHandler);
124
mwService_setClientData((struct mwService *)imService, this, 0L);
125
mwSession_addService(session, (struct mwService *) imService);
127
/* add resolve service */
128
resolveService = mwServiceResolve_new(session);
129
mwService_setClientData((struct mwService *)resolveService, this, 0L);
130
mwSession_addService(session, (struct mwService *) resolveService);
132
/* storage service */
133
storageService = mwServiceStorage_new(session);
134
mwService_setClientData((struct mwService *)storageService, this, 0L);
135
mwSession_addService(session, (struct mwService *) storageService);
138
/* conference service setup - just declines invites for now. */
139
memset(&conf_handler, 0, sizeof(conf_handler));
140
conf_handler.on_invited = _conference_invite;
142
srvc_conf = mwServiceConference_new(session, &conf_handler);
143
mwService_setClientData((struct mwService *)srvc_conf, this, 0L);
144
mwSession_addService(session, (struct mwService *) srvc_conf);
147
/* add a necessary cipher */
148
mwSession_addCipher(session, mwCipher_new_RC2_40(session));
149
mwSession_addCipher(session, mwCipher_new_RC2_128(session));
152
MeanwhileSession::~MeanwhileSession()
155
if (isConnected() || isConnecting())
158
mwSession_removeService(session, mwService_STORAGE);
159
mwSession_removeService(session, mwService_RESOLVE);
160
mwSession_removeService(session, mwService_IM);
161
mwSession_removeService(session, mwService_AWARE);
163
mwAwareList_free(awareList);
164
mwService_free(MW_SERVICE(storageService));
165
mwService_free(MW_SERVICE(resolveService));
166
mwService_free(MW_SERVICE(imService));
167
mwService_free(MW_SERVICE(awareService));
168
mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
169
mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
171
mwSession_free(session);
174
void MeanwhileSession::getDefaultClientIDParams(int *clientID,
175
int *verMajor, int *verMinor)
177
*clientID = mwLogin_MEANWHILE;
178
*verMajor = MW_PROTOCOL_VERSION_MAJOR;
179
*verMinor = MW_PROTOCOL_VERSION_MINOR;
182
/* external interface called by meanwhileaccount */
183
void MeanwhileSession::connect(QString password)
187
int port, clientID, versionMajor, versionMinor;
191
host = account->getServerName();
192
port = account->getServerPort();
193
useCustomID = account->getClientIDParams(&clientID,
194
&versionMajor, &versionMinor);
197
QTcpSocket *sock = new QTcpSocket(this);
198
Kopete::SocketTimeoutWatcher* timeoutWatcher = Kopete::SocketTimeoutWatcher::watch(sock);
200
QObject::connect(timeoutWatcher, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketAboutToClose()));
202
sock->connectToHost(host, quint16(port));
204
// TODO - make asynchronous
205
if (!sock->waitForConnected()) {
206
KMessageBox::queuedMessageBox(0, KMessageBox::Error,
207
i18n( "Could not connect to server"), i18n("Meanwhile Plugin"),
208
KMessageBox::Notify);
213
/* we want to receive signals when there is data to read */
214
QObject::connect(sock, SIGNAL(readyRead()), this,
215
SLOT(slotSocketDataAvailable()));
216
QObject::connect(sock, SIGNAL(aboutToClose()), this,
217
SLOT(slotSocketAboutToClose()));
219
/* set login details */
220
mwSession_setProperty(session, mwSession_AUTH_USER_ID,
221
g_strdup(account->meanwhileId().toAscii()), g_free);
222
mwSession_setProperty(session, mwSession_AUTH_PASSWORD,
223
g_strdup(password.toAscii()), g_free);
225
/* set client type parameters */
227
mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID,
228
GUINT_TO_POINTER(clientID), NULL);
229
mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR,
230
GUINT_TO_POINTER(versionMajor), NULL);
231
mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR,
232
GUINT_TO_POINTER(versionMinor), NULL);
237
mwSession_start(session);
240
void MeanwhileSession::disconnect()
243
if (state == mwSession_STOPPED || state == mwSession_STOPPING)
246
mwSession_stop(session, ERR_SUCCESS);
249
bool MeanwhileSession::isConnected()
251
return mwSession_isStarted(session);
254
bool MeanwhileSession::isConnecting()
256
return mwSession_isStarting(session);
259
static void free_id_block(void *data, void *p)
261
if (p != 0 || data == 0)
264
struct mwAwareIdBlock *id = reinterpret_cast<struct mwAwareIdBlock *>(data);
269
void MeanwhileSession::addContacts(const QHash<QString, Kopete::Contact *> &contacts)
273
QHash<QString, Kopete::Contact *>::const_iterator it = contacts.constBegin();
275
/** Convert our QDict of kopete contact to a GList of meanwhile buddies */
276
for( ; it != contacts.constEnd(); ++it) {
277
MeanwhileContact *contact = static_cast<MeanwhileContact *>(it.value());
278
struct mwAwareIdBlock *id = reinterpret_cast<struct mwAwareIdBlock *>(malloc(sizeof(*id)));
281
id->user = qstrdup(contact->meanwhileId().toUtf8().constData());
283
id->type = mwAware_USER;
284
buddies = g_list_append(buddies, id);
287
mwAwareList_addAware(awareList, buddies);
289
g_list_foreach(buddies, free_id_block, 0);
290
g_list_free(buddies);
293
/* private functions used only by the meanwhile session object */
294
void MeanwhileSession::addContact(const Kopete::Contact *contact)
297
struct mwAwareIdBlock id = { mwAware_USER,
298
strdup(static_cast<const MeanwhileContact *>(contact)
299
->meanwhileId().toAscii()),
302
GList *buddies = g_list_prepend(0L, &id);
303
mwAwareList_addAware(awareList, buddies);
304
g_list_free(buddies);
308
int MeanwhileSession::sendMessage(Kopete::Message &message)
311
MeanwhileContact *contact =
312
static_cast<MeanwhileContact *>(message.to().first());
314
mwDebug() << "No target for message!" <<endl;
318
struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
319
struct mwConversation *conv;
321
conv = mwServiceIm_getConversation(imService, &target);
324
mwDebug() << "No target for conversation with '"
325
<< contact->meanwhileId() << "'" << endl;
329
struct ConversationData *convdata = (struct ConversationData *)
330
mwConversation_getClientData(conv);
332
if (convdata == 0L) {
333
convdata = createConversationData(conv, contact, true);
334
if (convdata == 0L) {
335
mwDebug() << "No memory for conversation data!" << endl;
340
/* if there's other messages in the queue, or the conversation isn't open,
341
* then append to the queue instead of sending right away */
342
if ((convdata->queue && !convdata->queue->isEmpty()) ||
343
!mwConversation_isOpen(conv)) {
344
convdata->queue->append(message);
345
mwConversation_open(conv);
347
} else if (!mwConversation_send(conv, mwImSend_PLAIN,
348
message.plainBody().toAscii())) {
349
convdata->chat->appendMessage(message);
350
convdata->chat->messageSucceeded();
355
void MeanwhileSession::sendTyping(MeanwhileContact *contact, bool isTyping)
358
struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
359
struct mwConversation *conv;
361
conv = mwServiceIm_getConversation(imService, &target);
366
if (mwConversation_isOpen(conv))
367
mwConversation_send(conv, mwImSend_TYPING, (void *)isTyping);
370
void MeanwhileSession::setStatus(Kopete::OnlineStatus status,
371
const Kopete::StatusMessage &msg)
374
mwDebug() << "setStatus: " << status.description() << '('
375
<< status.internalStatus() << ')' << endl;
376
if (status.internalStatus() == 0)
379
struct mwUserStatus stat;
380
mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
384
stat.status = (mwStatusType)status.internalStatus();
386
stat.desc = ::strdup(status.description().toUtf8().constData());
388
stat.desc = ::strdup(msg.message().toUtf8().constData());
390
mwSession_setUserStatus(session, &stat);
391
/* will free stat.desc */
392
mwUserStatus_clear(&stat);
395
void MeanwhileSession::syncContactsToServer()
398
struct mwSametimeList *list = mwSametimeList_new();
400
/* set up a fallback group for top-level contacts */
401
struct mwSametimeGroup *topstgroup = mwSametimeGroup_new(list,
402
mwSametimeGroup_DYNAMIC, "People");
403
mwSametimeGroup_setOpen(topstgroup, true);
405
const QHash<QString, Kopete::Contact *> contacts = account->contacts();
406
// Q3DictIterator<Kopete::Contact> it(account->contacts());
407
for(QHash<QString, Kopete::Contact *>::const_iterator it = contacts.constBegin();
408
it != contacts.constEnd(); ++it ) {
409
MeanwhileContact *contact = static_cast<MeanwhileContact *>(it.value());
411
/* Find the group that the metacontact is in */
412
Kopete::MetaContact *mc = contact->metaContact();
416
Kopete::Group *contactgroup = mc->groups().value(0);
420
if (contactgroup->type() == Kopete::Group::Temporary)
423
struct mwSametimeGroup *stgroup;
424
if (contactgroup->type() == Kopete::Group::TopLevel) {
425
stgroup = topstgroup;
427
/* find (or create) a matching sametime list group */
428
stgroup = mwSametimeList_findGroup(list,
429
contactgroup->displayName().toUtf8().constData());
431
stgroup = mwSametimeGroup_new(list, mwSametimeGroup_DYNAMIC,
432
contactgroup->displayName().toUtf8().constData());
434
mwSametimeGroup_setOpen(stgroup, contactgroup->isExpanded());
435
mwSametimeGroup_setAlias(stgroup,
436
contactgroup->pluginData(account->protocol(), "alias").toUtf8().constData());
439
QByteArray tmpMeanwhileId = contact->meanwhileId().toUtf8();
440
/* now add the user (by IDBlock) */
441
struct mwIdBlock id =
442
{ (gchar*)tmpMeanwhileId.constData(), 0 };
443
struct mwSametimeUser *stuser = mwSametimeUser_new(stgroup,
444
mwSametimeUser_NORMAL, &id);
446
mwSametimeUser_setAlias(stuser, contact->nickName().toUtf8().constData());
450
struct mwPutBuffer *buf = mwPutBuffer_new();
451
struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
452
struct mwOpaque *opaque = mwStorageUnit_asOpaque(unit);
454
mwSametimeList_put(buf, list);
455
mwPutBuffer_finalize(opaque, buf);
457
mwServiceStorage_save(storageService, unit, NULL, NULL, NULL);
459
mwSametimeList_free(list);
462
void MeanwhileSession::syncContactsFromServer()
464
struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
465
mwServiceStorage_load(storageService, unit, &_handleStorageLoad, 0L, 0L);
468
#define MEANWHILE_SESSION_BUFSIZ 4096
470
void MeanwhileSession::slotSocketDataAvailable()
479
if (!(buf = (guchar *)malloc(MEANWHILE_SESSION_BUFSIZ))) {
480
mwDebug() << "buffer malloc failed" << endl;
484
while (socket && socket->bytesAvailable() > 0) {
485
bytesRead = socket->read((char *)buf, MEANWHILE_SESSION_BUFSIZ);
488
mwSession_recv(session, buf, (unsigned int)bytesRead);
493
void MeanwhileSession::slotSocketAboutToClose()
497
/* TODO -error handling
498
if (reason & KExtendedSocket::involuntary)
499
emit serverNotification(
500
QString("Lost connection with Meanwhile server"));
503
mwSession_stop(session, 0x00);
507
Kopete::OnlineStatus MeanwhileSession::convertStatus(int mstatus)
509
MeanwhileProtocol *protocol =
510
static_cast<MeanwhileProtocol *>(account->protocol());
513
case mwStatus_ACTIVE:
514
return protocol->statusOnline;
517
return protocol->statusIdle;
520
return protocol->statusAway;
523
return protocol->statusBusy;
526
return protocol->statusOffline;
529
mwDebug() << "unknown status lookup: " << mstatus << endl;
531
return protocol->statusOffline;
534
void MeanwhileSession::resolveContactNickname(MeanwhileContact *contact)
536
/* @todo: FIXME: leak! */
537
char *id = strdup(contact->meanwhileId().toAscii());
538
GList *query = g_list_prepend(NULL, id);
539
mwServiceResolve_resolve(resolveService, query, mwResolveFlag_USERS,
540
_handleResolveLookupResults, contact, NULL);
543
QString MeanwhileSession::getNickName(struct mwLoginInfo *logininfo)
545
if (logininfo == 0L || logininfo->user_name == 0L)
547
return getNickName(logininfo->user_name);
550
QString MeanwhileSession::getNickName(QString name)
553
int index = name.indexOf(QLatin1String(" - "));
555
name.remove(0, index + 3);
556
index = name.indexOf(QLatin1Char('/'));
558
name = name.left(index);
563
MeanwhileContact *MeanwhileSession::conversationContact(
564
struct mwConversation *conv)
566
struct mwIdBlock *target = mwConversation_getTarget(conv);
567
if (target == 0L || target->user == 0L) {
570
QString user(target->user);
572
MeanwhileContact *contact = static_cast<MeanwhileContact *>(account->contacts().value(user));
574
struct mwLoginInfo *logininfo = mwConversation_getTargetInfo(conv);
575
QString name = getNickName(logininfo);
578
account->addContact(user, name, 0L, Kopete::Account::Temporary);
579
contact = static_cast<MeanwhileContact *>(account->contacts().value(user));
581
contact->setNickName(name);
586
void MeanwhileSession::handleRedirect(const char *host)
588
/* if configured manually, force the login */
589
if (account->getForceLogin()) {
590
mwSession_forceLogin(session);
594
/* if we're connecting to the same host, force */
595
if (!host || account->getServerName() == host) {
596
mwSession_forceLogin(session);
600
QTcpSocket *sock = new QTcpSocket(this);
602
Kopete::SocketTimeoutWatcher* timeoutWatcher = Kopete::SocketTimeoutWatcher::watch(sock);
604
QObject::connect(timeoutWatcher, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketAboutToClose()));
606
sock->connectToHost(host, quint16(account->getServerPort()));
608
if (!sock->waitForConnected()) {
609
KMessageBox::queuedMessageBox(0, KMessageBox::Error,
610
i18n( "Could not connect to redirected server"),
611
i18n("Meanwhile Plugin"),
612
KMessageBox::Notify);
614
mwSession_forceLogin(session);
618
/* we've redirected, so swap the sockets */
622
/* we want to receive signals when there is data to read */
623
QObject::connect(sock, SIGNAL(readyRead()), this,
624
SLOT(slotSocketDataAvailable()));
625
QObject::connect(sock, SIGNAL(aboutToClose()), this,
626
SLOT(slotSocketAboutToClose()));
629
/* priave session handling functions, called by libmeanwhile callbacks */
630
void MeanwhileSession::handleSessionStateChange(
631
enum mwSessionState state, gpointer data)
637
case mwSession_STARTING:
638
case mwSession_HANDSHAKE:
639
case mwSession_HANDSHAKE_ACK:
640
case mwSession_LOGIN:
641
case mwSession_LOGIN_CONT:
642
case mwSession_LOGIN_ACK:
645
case mwSession_LOGIN_REDIR:
646
handleRedirect((char *)data);
649
case mwSession_STARTED:
651
struct mwUserStatus stat = { mwStatus_ACTIVE, 0, 0L };
652
mwSession_setUserStatus(session, &stat);
653
struct mwLoginInfo *logininfo = mwSession_getLoginInfo(session);
655
account->myself()->setNickName(getNickName(logininfo));
657
syncContactsFromServer();
661
case mwSession_STOPPING:
663
unsigned int info = GPOINTER_TO_UINT(data);
664
if (info & ERR_FAILURE) {
665
if (info == INCORRECT_LOGIN)
666
account->password().setWrong();
667
char *reason = mwError(info);
668
emit serverNotification(QString(reason));
673
emit sessionStateChange(
674
static_cast<MeanwhileProtocol *>(account->protocol())
678
case mwSession_STOPPED:
681
case mwSession_UNKNOWN:
683
mwDebug() << "Unhandled state change " << state << endl;
687
int MeanwhileSession::handleSessionIOWrite(const guchar *buffer,
695
int remaining, retval = 0;
696
for (remaining = count; remaining > 0; remaining -= retval) {
697
retval = socket->write((char *)buffer, count);
705
void MeanwhileSession::handleSessionAdmin(const char *text)
708
emit serverNotification(QString(text));
711
void MeanwhileSession::handleSessionAnnounce(struct mwLoginInfo *from,
712
gboolean /* may_reply */, const char *text)
716
message.sprintf("Announcement from %s:\n%s", from->user_id, text);
717
emit serverNotification(message);
720
void MeanwhileSession::handleSessionSetUserStatus()
722
struct mwUserStatus *userstatus = mwSession_getUserStatus(session);
723
emit sessionStateChange(convertStatus((unsigned int)userstatus->status));
726
void MeanwhileSession::handleSessionSetPrivacyInfo()
730
void MeanwhileSession::handleSessionIOClose()
744
void MeanwhileSession::handleSessionClear()
748
void MeanwhileSession::handleAwareAttrib(struct mwAwareAttribute * /* attrib */)
753
void MeanwhileSession::handleAwareListAware(struct mwAwareSnapshot *snapshot)
756
MeanwhileContact *contact = static_cast<MeanwhileContact *>
757
(account->contacts().value(snapshot->id.user));
762
/* use the setUserStatus callback for status updates for myself. */
763
if (contact == account->myself())
767
contact->setProperty(get_protocol()->statusMessage, snapshot->status.desc);
768
contact->setProperty(get_protocol()->awayMessage, snapshot->status.desc);
771
Kopete::OnlineStatus onlinestatus;
772
if (snapshot->online) {
773
onlinestatus = convertStatus(snapshot->status.status);
774
resolveContactNickname(contact);
776
onlinestatus = convertStatus(0);
779
contact->setOnlineStatus(onlinestatus);
782
/* Commented out in previous kopete/meanwhile plugin for some reason,
783
* but has still been ported to the new API.
786
if (snapshot->status.status == mwStatus_IDLE) {
787
idletime = (snapshot->status.time == 0xdeadbeef) ?
788
0 : snapshot->status.time;
790
contact->setStatusDescription(statusDesc + '[' +
791
QString::number(idletime/60)+" mins]");
794
contact->setStatusDescription(snapshot->status.desc);
798
void MeanwhileSession::handleAwareListAttrib(struct mwAwareIdBlock * /* id */,
799
struct mwAwareAttribute * /* attrib */)
804
struct MeanwhileSession::ConversationData
805
*MeanwhileSession::createConversationData(
806
struct mwConversation *conv, MeanwhileContact *contact,
809
struct ConversationData *cd = new ConversationData();
814
cd->contact = contact;
815
cd->chat = contact->manager(Kopete::Contact::CanCreate);
818
cd->queue = new Q3ValueList<Kopete::Message>();
820
mwConversation_setClientData(conv, cd, 0L);
825
void MeanwhileSession::handleImConvOpened(struct mwConversation *conv)
829
struct ConversationData *convdata =
830
(struct ConversationData *)mwConversation_getClientData(conv);
832
if (convdata == 0L) {
833
/* a new conversation */
834
convdata = createConversationData(conv, conversationContact(conv));
836
if (convdata == 0L) {
837
mwDebug() << "No memory for conversation data!" << endl;
841
} else if (convdata->queue && !convdata->queue->isEmpty()) {
842
/* send any messages that were waiting for the conversation to open */
843
Q3ValueList<Kopete::Message>::iterator it;
844
for (it = convdata->queue->begin(); it != convdata->queue->end();
846
mwConversation_send(conv, mwImSend_PLAIN,
847
(*it).plainBody().toAscii());
848
convdata->chat->appendMessage(*it);
849
convdata->chat->messageSucceeded();
851
convdata->queue->clear();
852
delete convdata->queue;
853
convdata->queue = 0L;
855
resolveContactNickname(convdata->contact);
858
void MeanwhileSession::handleImConvClosed(struct mwConversation *conv,
863
ConversationData *convdata =
864
(ConversationData *)mwConversation_getClientData(conv);
869
mwConversation_setClientData(conv, 0L, 0L);
871
convdata->chat->removeContact(convdata->contact);
872
convdata->chat->deref();
874
if (convdata->queue != 0L) {
875
convdata->queue->clear();
876
delete convdata->queue;
877
convdata->queue = 0L;
882
void MeanwhileSession::handleImConvReceived(struct mwConversation *conv,
883
enum mwImSendType type, gconstpointer msg)
886
ConversationData *convdata =
887
(ConversationData *)mwConversation_getClientData(conv);
895
Kopete::Message message(convdata->contact, account->myself());
896
message.setPlainBody(QString::fromUtf8((const char *)msg));
897
message.setDirection(Kopete::Message::Inbound);
898
convdata->chat->appendMessage(message);
901
case mwImSend_TYPING:
902
convdata->chat->receivedTypingMsg(convdata->contact);
905
mwDebug() << "Unable to handle message type: " << type << endl;
909
void MeanwhileSession::handleResolveLookupResults(
910
struct mwServiceResolve * /* srvc */, guint32 /* id */,
911
guint32 /* code */, GList *results, gpointer data)
913
struct mwResolveResult *result;
914
struct mwResolveMatch *match;
918
if ((result = (struct mwResolveResult *)results->data) == 0L)
921
if (result->matches == 0L)
923
if ((match = (struct mwResolveMatch *)result->matches->data) == 0L)
926
mwDebug() << "resolve lookup returned '" << match->name << "'" << endl;
928
MeanwhileContact *contact = (MeanwhileContact *)data;
932
contact->setNickName(getNickName(match->name));
935
void MeanwhileSession::handleStorageLoad(struct mwServiceStorage * /* srvc */,
936
guint32 result, struct mwStorageUnit *item, gpointer /* data */)
939
if (result != ERR_SUCCESS) {
940
mwDebug() << "contact list load returned " << result << endl;
944
struct mwGetBuffer *buf = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
945
struct mwSametimeList *list = mwSametimeList_new();
946
mwSametimeList_get(buf, list);
948
GList *gl, *glf, *cl, *clf;
950
Kopete::ContactList *contactlist = Kopete::ContactList::self();
952
for (glf = gl = mwSametimeList_getGroups(list); gl; gl = gl->next) {
953
struct mwSametimeGroup *stgroup = (struct mwSametimeGroup *)gl->data;
955
Kopete::Group *group =
956
contactlist->findGroup(mwSametimeGroup_getName(stgroup));
957
group->setPluginData(account->protocol(), "alias",
958
mwSametimeGroup_getAlias(stgroup));
960
for (clf = cl = mwSametimeGroup_getUsers(stgroup); cl; cl = cl->next) {
961
struct mwSametimeUser *stuser = (struct mwSametimeUser *)cl->data;
963
MeanwhileContact *contact = static_cast<MeanwhileContact *>
964
(account->contacts().value(mwSametimeUser_getUser(stuser)));
969
account->addContact(mwSametimeUser_getUser(stuser),
970
mwSametimeUser_getAlias(stuser), group,
971
Kopete::Account::ChangeKABC);
977
mwSametimeList_free(list);
980
const struct MeanwhileClientID *MeanwhileSession::getClientIDs()
986
MEANWHILE_HOOK_CONFERENCE(conference_invite,
987
(struct mwConference *conf, struct mwLoginInfo *inviter,
989
(conf, inviter, invite))
994
message.sprintf("%s has invited you to a conference called \"%s\"\n"
995
"However, this version of the meanwhile plugin does "
996
"not support conferences, so the invitiation has been declined.",
997
inviter->user_id, invite);
999
mwConference_reject(conf, ERR_SUCCESS,
1000
"Sorry, my client doesn't support conferences!");
1001
KMessageBox::queuedMessageBox(0, KMessageBox::Sorry , message,
1002
i18n("Meanwhile Plugin: Conference invitation"),
1003
KMessageBox::Notify);
1006
#include "meanwhilesession.moc"