~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to protocols/meanwhile/meanwhilesession.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    meanwhilesession.cpp - interface to the 'C' meanwhile library
 
3
 
 
4
    Copyright (c) 2003-2004 by Sivaram Gottimukkala  <suppandi@gmail.com>
 
5
    Copyright (c) 2005      by Jeremy Kerr <jk@ozlabs.org>
 
6
 
 
7
    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
 
8
 
 
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
    *************************************************************************
 
17
*/
 
18
 
 
19
#include <string.h>
 
20
#include <stdlib.h>
 
21
#include <kmessagebox.h>
 
22
#include <klocale.h>
 
23
#include <qtcpsocket.h>
 
24
 
 
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"
 
32
 
 
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>
 
44
//Added by qt3to4:
 
45
#include <Q3ValueList>
 
46
 
 
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
 
52
 
 
53
#define get_protocol() (static_cast<MeanwhileProtocol *>(account->protocol()))
 
54
 
 
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", },
 
61
 
 
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", },
 
78
    { 0, NULL },
 
79
};
 
80
 
 
81
 
 
82
MeanwhileSession::MeanwhileSession(MeanwhileAccount *acc)
 
83
    : session(0), state(mwSession_STOPPED), account(acc), socket(0)
 
84
{
 
85
    HERE;
 
86
 
 
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);
 
97
 
 
98
    session = mwSession_new(&sessionHandler);
 
99
    mwSession_setClientData(session, this, 0L);
 
100
 
 
101
    /* set up the aware service */
 
102
    memset(&awareHandler, 0, sizeof(awareHandler));
 
103
    set_aware_handler(on_attrib, Attrib);
 
104
 
 
105
    awareService = mwServiceAware_new(session, &awareHandler);
 
106
    mwSession_addService(session, (struct mwService *)awareService);
 
107
 
 
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);
 
114
 
 
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;
 
122
 
 
123
    imService = mwServiceIm_new(session, &imHandler);
 
124
    mwService_setClientData((struct mwService *)imService, this, 0L);
 
125
    mwSession_addService(session, (struct mwService *) imService);
 
126
 
 
127
    /* add resolve service */
 
128
    resolveService = mwServiceResolve_new(session);
 
129
    mwService_setClientData((struct mwService *)resolveService, this, 0L);
 
130
    mwSession_addService(session, (struct mwService *) resolveService);
 
131
 
 
132
    /* storage service */
 
133
    storageService = mwServiceStorage_new(session);
 
134
    mwService_setClientData((struct mwService *)storageService, this, 0L);
 
135
    mwSession_addService(session, (struct mwService *) storageService);
 
136
 
 
137
#if 0
 
138
    /* conference service setup - just declines invites for now. */
 
139
    memset(&conf_handler, 0, sizeof(conf_handler));
 
140
    conf_handler.on_invited = _conference_invite;
 
141
 
 
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);
 
145
#endif
 
146
 
 
147
    /* add a necessary cipher */
 
148
    mwSession_addCipher(session, mwCipher_new_RC2_40(session));
 
149
    mwSession_addCipher(session, mwCipher_new_RC2_128(session));
 
150
}
 
151
 
 
152
MeanwhileSession::~MeanwhileSession()
 
153
{
 
154
    HERE;
 
155
    if (isConnected() || isConnecting())
 
156
        disconnect();
 
157
 
 
158
    mwSession_removeService(session, mwService_STORAGE);
 
159
    mwSession_removeService(session, mwService_RESOLVE);
 
160
    mwSession_removeService(session, mwService_IM);
 
161
    mwSession_removeService(session, mwService_AWARE);
 
162
 
 
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));
 
170
 
 
171
    mwSession_free(session);
 
172
}
 
173
 
 
174
void MeanwhileSession::getDefaultClientIDParams(int *clientID,
 
175
        int *verMajor, int *verMinor)
 
176
{
 
177
    *clientID = mwLogin_MEANWHILE;
 
178
    *verMajor = MW_PROTOCOL_VERSION_MAJOR;
 
179
    *verMinor = MW_PROTOCOL_VERSION_MINOR;
 
180
}
 
181
 
 
182
/* external interface called by meanwhileaccount */
 
183
void MeanwhileSession::connect(QString password)
 
184
{
 
185
    HERE;
 
186
 
 
187
    int port, clientID, versionMajor, versionMinor;
 
188
    bool useCustomID;
 
189
    QString host;
 
190
 
 
191
    host = account->getServerName();
 
192
    port = account->getServerPort();
 
193
    useCustomID = account->getClientIDParams(&clientID,
 
194
                    &versionMajor, &versionMinor);
 
195
 
 
196
 
 
197
    QTcpSocket *sock = new QTcpSocket(this);
 
198
    Kopete::SocketTimeoutWatcher* timeoutWatcher = Kopete::SocketTimeoutWatcher::watch(sock);
 
199
    if (timeoutWatcher)
 
200
        QObject::connect(timeoutWatcher, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketAboutToClose()));
 
201
 
 
202
    sock->connectToHost(host, quint16(port));
 
203
 
 
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);
 
209
        delete sock;
 
210
        return;
 
211
    }
 
212
    socket = sock;
 
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()));
 
218
 
 
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);
 
224
 
 
225
    /* set client type parameters */
 
226
    if (useCustomID) {
 
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);
 
233
    }
 
234
 
 
235
 
 
236
    /* go!! */
 
237
    mwSession_start(session);
 
238
}
 
239
 
 
240
void MeanwhileSession::disconnect()
 
241
{
 
242
    HERE;
 
243
    if (state == mwSession_STOPPED || state == mwSession_STOPPING)
 
244
        return;
 
245
 
 
246
    mwSession_stop(session, ERR_SUCCESS);
 
247
}
 
248
 
 
249
bool MeanwhileSession::isConnected()
 
250
{
 
251
    return mwSession_isStarted(session);
 
252
}
 
253
 
 
254
bool MeanwhileSession::isConnecting()
 
255
{
 
256
    return mwSession_isStarting(session);
 
257
}
 
258
 
 
259
static void free_id_block(void *data, void *p)
 
260
{
 
261
    if (p != 0 || data == 0)
 
262
        return;
 
263
 
 
264
    struct mwAwareIdBlock *id = reinterpret_cast<struct mwAwareIdBlock *>(data);
 
265
    delete [] id->user;
 
266
    free(id);
 
267
}
 
268
 
 
269
void MeanwhileSession::addContacts(const QHash<QString, Kopete::Contact *> &contacts)
 
270
{
 
271
    HERE;
 
272
    GList *buddies = 0;
 
273
    QHash<QString, Kopete::Contact *>::const_iterator it = contacts.constBegin();
 
274
 
 
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)));
 
279
        if (!id)
 
280
            continue;
 
281
        id->user = qstrdup(contact->meanwhileId().toUtf8().constData());
 
282
        id->community = 0;
 
283
        id->type = mwAware_USER;
 
284
        buddies = g_list_append(buddies, id);
 
285
    }
 
286
 
 
287
    mwAwareList_addAware(awareList, buddies);
 
288
 
 
289
    g_list_foreach(buddies, free_id_block, 0);
 
290
    g_list_free(buddies);
 
291
}
 
292
 
 
293
/* private functions used only by the meanwhile session object */
 
294
void MeanwhileSession::addContact(const Kopete::Contact *contact)
 
295
{
 
296
    HERE;
 
297
    struct mwAwareIdBlock id = { mwAware_USER,
 
298
        strdup(static_cast<const MeanwhileContact *>(contact)
 
299
                ->meanwhileId().toAscii()),
 
300
        0L };
 
301
 
 
302
    GList *buddies = g_list_prepend(0L, &id);
 
303
    mwAwareList_addAware(awareList, buddies);
 
304
    g_list_free(buddies);
 
305
    free(id.user);
 
306
}
 
307
 
 
308
int MeanwhileSession::sendMessage(Kopete::Message &message)
 
309
{
 
310
    HERE;
 
311
    MeanwhileContact *contact =
 
312
        static_cast<MeanwhileContact *>(message.to().first());
 
313
    if (!contact) {
 
314
        mwDebug() << "No target for message!" <<endl;
 
315
        return 0;
 
316
    }
 
317
 
 
318
    struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
 
319
    struct mwConversation *conv;
 
320
 
 
321
    conv = mwServiceIm_getConversation(imService, &target);
 
322
    free(target.user);
 
323
    if (conv == 0L) {
 
324
        mwDebug() << "No target for conversation with '"
 
325
            << contact->meanwhileId() << "'" << endl;
 
326
        return 0;
 
327
    }
 
328
 
 
329
    struct ConversationData *convdata = (struct ConversationData *)
 
330
        mwConversation_getClientData(conv);
 
331
 
 
332
    if (convdata == 0L) {
 
333
        convdata = createConversationData(conv, contact, true);
 
334
        if (convdata == 0L) {
 
335
            mwDebug() << "No memory for conversation data!" << endl;
 
336
            return 0;
 
337
        }
 
338
    }
 
339
 
 
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);
 
346
 
 
347
    } else if (!mwConversation_send(conv, mwImSend_PLAIN,
 
348
                message.plainBody().toAscii())) {
 
349
        convdata->chat->appendMessage(message);
 
350
        convdata->chat->messageSucceeded();
 
351
    }
 
352
    return 1;
 
353
}
 
354
 
 
355
void MeanwhileSession::sendTyping(MeanwhileContact *contact, bool isTyping)
 
356
{
 
357
    HERE;
 
358
    struct mwIdBlock target = { strdup(contact->meanwhileId().toAscii()), 0L };
 
359
    struct mwConversation *conv;
 
360
 
 
361
    conv = mwServiceIm_getConversation(imService, &target);
 
362
    free(target.user);
 
363
    if (conv == 0L)
 
364
        return;
 
365
 
 
366
    if (mwConversation_isOpen(conv))
 
367
        mwConversation_send(conv, mwImSend_TYPING, (void *)isTyping);
 
368
}
 
369
 
 
370
void MeanwhileSession::setStatus(Kopete::OnlineStatus status,
 
371
        const Kopete::StatusMessage &msg)
 
372
{
 
373
    HERE;
 
374
    mwDebug() << "setStatus: " << status.description() << '('
 
375
        << status.internalStatus() << ')' << endl;
 
376
    if (status.internalStatus() == 0)
 
377
        return;
 
378
 
 
379
    struct mwUserStatus stat;
 
380
    mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
 
381
 
 
382
    free(stat.desc);
 
383
 
 
384
    stat.status = (mwStatusType)status.internalStatus();
 
385
    if (msg.isEmpty())
 
386
        stat.desc = ::strdup(status.description().toUtf8().constData());
 
387
    else
 
388
        stat.desc = ::strdup(msg.message().toUtf8().constData());
 
389
 
 
390
    mwSession_setUserStatus(session, &stat);
 
391
    /* will free stat.desc */
 
392
    mwUserStatus_clear(&stat);
 
393
}
 
394
 
 
395
void MeanwhileSession::syncContactsToServer()
 
396
{
 
397
    HERE;
 
398
    struct mwSametimeList *list = mwSametimeList_new();
 
399
 
 
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);
 
404
 
 
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());
 
410
 
 
411
        /* Find the group that the metacontact is in */
 
412
        Kopete::MetaContact *mc = contact->metaContact();
 
413
        if (!mc)
 
414
            continue;
 
415
 
 
416
        Kopete::Group *contactgroup = mc->groups().value(0);
 
417
        if (!contactgroup)
 
418
            continue;
 
419
 
 
420
        if (contactgroup->type() == Kopete::Group::Temporary)
 
421
            continue;
 
422
 
 
423
        struct mwSametimeGroup *stgroup;
 
424
        if (contactgroup->type() == Kopete::Group::TopLevel) {
 
425
            stgroup = topstgroup;
 
426
        } else  {
 
427
            /* find (or create) a matching sametime list group */
 
428
            stgroup = mwSametimeList_findGroup(list,
 
429
                        contactgroup->displayName().toUtf8().constData());
 
430
            if (!stgroup) {
 
431
                stgroup = mwSametimeGroup_new(list, mwSametimeGroup_DYNAMIC,
 
432
                        contactgroup->displayName().toUtf8().constData());
 
433
            }
 
434
            mwSametimeGroup_setOpen(stgroup, contactgroup->isExpanded());
 
435
            mwSametimeGroup_setAlias(stgroup,
 
436
                    contactgroup->pluginData(account->protocol(), "alias").toUtf8().constData());
 
437
        }
 
438
 
 
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);
 
445
 
 
446
        mwSametimeUser_setAlias(stuser, contact->nickName().toUtf8().constData());
 
447
    }
 
448
 
 
449
    /* store! */
 
450
    struct mwPutBuffer *buf = mwPutBuffer_new();
 
451
    struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
 
452
    struct mwOpaque *opaque = mwStorageUnit_asOpaque(unit);
 
453
 
 
454
    mwSametimeList_put(buf, list);
 
455
    mwPutBuffer_finalize(opaque, buf);
 
456
 
 
457
    mwServiceStorage_save(storageService, unit, NULL, NULL, NULL);
 
458
 
 
459
    mwSametimeList_free(list);
 
460
}
 
461
 
 
462
void MeanwhileSession::syncContactsFromServer()
 
463
{
 
464
    struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
 
465
    mwServiceStorage_load(storageService, unit, &_handleStorageLoad, 0L, 0L);
 
466
}
 
467
 
 
468
#define MEANWHILE_SESSION_BUFSIZ 4096
 
469
 
 
470
void MeanwhileSession::slotSocketDataAvailable()
 
471
{
 
472
    HERE;
 
473
    guchar *buf;
 
474
    qint64 bytesRead;
 
475
 
 
476
    if (!socket)
 
477
        return;
 
478
 
 
479
    if (!(buf = (guchar *)malloc(MEANWHILE_SESSION_BUFSIZ))) {
 
480
        mwDebug() << "buffer malloc failed" << endl;
 
481
        return;
 
482
    }
 
483
 
 
484
    while (socket && socket->bytesAvailable() > 0) {
 
485
        bytesRead = socket->read((char *)buf, MEANWHILE_SESSION_BUFSIZ);
 
486
        if (bytesRead < 0)
 
487
            break;
 
488
        mwSession_recv(session, buf, (unsigned int)bytesRead);
 
489
    }
 
490
    free(buf);
 
491
}
 
492
 
 
493
void MeanwhileSession::slotSocketAboutToClose()
 
494
{
 
495
    HERE;
 
496
 
 
497
    /* TODO -error handling
 
498
    if (reason & KExtendedSocket::involuntary)
 
499
        emit serverNotification(
 
500
                QString("Lost connection with Meanwhile server"));
 
501
    */
 
502
 
 
503
    mwSession_stop(session, 0x00);
 
504
}
 
505
 
 
506
 
 
507
Kopete::OnlineStatus MeanwhileSession::convertStatus(int mstatus)
 
508
{
 
509
    MeanwhileProtocol *protocol =
 
510
        static_cast<MeanwhileProtocol *>(account->protocol());
 
511
 
 
512
    switch (mstatus) {
 
513
    case mwStatus_ACTIVE:
 
514
        return protocol->statusOnline;
 
515
        break;
 
516
    case mwStatus_IDLE:
 
517
        return protocol->statusIdle;
 
518
        break;
 
519
    case mwStatus_AWAY:
 
520
        return protocol->statusAway;
 
521
        break;
 
522
    case mwStatus_BUSY:
 
523
        return protocol->statusBusy;
 
524
        break;
 
525
    case 0:
 
526
        return protocol->statusOffline;
 
527
        break;
 
528
    default:
 
529
        mwDebug() << "unknown status lookup: " << mstatus << endl;
 
530
    }
 
531
    return protocol->statusOffline;
 
532
}
 
533
 
 
534
void MeanwhileSession::resolveContactNickname(MeanwhileContact *contact)
 
535
{
 
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);
 
541
}
 
542
 
 
543
QString MeanwhileSession::getNickName(struct mwLoginInfo *logininfo)
 
544
{
 
545
    if (logininfo == 0L || logininfo->user_name == 0L)
 
546
        return QString();
 
547
    return getNickName(logininfo->user_name);
 
548
}
 
549
 
 
550
QString MeanwhileSession::getNickName(QString name)
 
551
{
 
552
 
 
553
    int index = name.indexOf(QLatin1String(" - "));
 
554
    if (index != -1)
 
555
        name.remove(0, index + 3);
 
556
    index = name.indexOf(QLatin1Char('/'));
 
557
    if (index != -1)
 
558
        name = name.left(index);
 
559
 
 
560
    return name;
 
561
}
 
562
 
 
563
MeanwhileContact *MeanwhileSession::conversationContact(
 
564
        struct mwConversation *conv)
 
565
{
 
566
    struct mwIdBlock *target = mwConversation_getTarget(conv);
 
567
    if (target == 0L || target->user == 0L) {
 
568
        return 0L;
 
569
    }
 
570
    QString user(target->user);
 
571
 
 
572
    MeanwhileContact *contact = static_cast<MeanwhileContact *>(account->contacts().value(user));
 
573
 
 
574
    struct mwLoginInfo *logininfo = mwConversation_getTargetInfo(conv);
 
575
    QString name = getNickName(logininfo);
 
576
 
 
577
    if (!contact) {
 
578
        account->addContact(user, name, 0L, Kopete::Account::Temporary);
 
579
            contact = static_cast<MeanwhileContact *>(account->contacts().value(user));
 
580
    } else
 
581
        contact->setNickName(name);
 
582
 
 
583
    return contact;
 
584
}
 
585
 
 
586
void MeanwhileSession::handleRedirect(const char *host)
 
587
{
 
588
    /* if configured manually, force the login */
 
589
    if (account->getForceLogin()) {
 
590
        mwSession_forceLogin(session);
 
591
        return;
 
592
    }
 
593
 
 
594
    /* if we're connecting to the same host, force */
 
595
    if (!host || account->getServerName() == host) {
 
596
        mwSession_forceLogin(session);
 
597
        return;
 
598
    }
 
599
 
 
600
    QTcpSocket *sock = new QTcpSocket(this);
 
601
 
 
602
    Kopete::SocketTimeoutWatcher* timeoutWatcher = Kopete::SocketTimeoutWatcher::watch(sock);
 
603
    if (timeoutWatcher)
 
604
        QObject::connect(timeoutWatcher, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketAboutToClose()));
 
605
 
 
606
    sock->connectToHost(host, quint16(account->getServerPort()));
 
607
 
 
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);
 
613
        delete sock;
 
614
        mwSession_forceLogin(session);
 
615
        return;
 
616
    }
 
617
 
 
618
    /* we've redirected, so swap the sockets */
 
619
    delete this->socket;
 
620
    this->socket = sock;
 
621
 
 
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()));
 
627
}
 
628
 
 
629
/* priave session handling functions, called by libmeanwhile callbacks */
 
630
void MeanwhileSession::handleSessionStateChange(
 
631
        enum mwSessionState state, gpointer data)
 
632
{
 
633
    HERE;
 
634
    this->state = state;
 
635
 
 
636
    switch (state) {
 
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:
 
643
            break;
 
644
 
 
645
        case mwSession_LOGIN_REDIR:
 
646
            handleRedirect((char *)data);
 
647
            break;
 
648
 
 
649
        case mwSession_STARTED:
 
650
            {
 
651
                struct mwUserStatus stat = { mwStatus_ACTIVE, 0, 0L };
 
652
                mwSession_setUserStatus(session, &stat);
 
653
                struct mwLoginInfo *logininfo = mwSession_getLoginInfo(session);
 
654
                if (logininfo) {
 
655
                    account->myself()->setNickName(getNickName(logininfo));
 
656
                }
 
657
                syncContactsFromServer();
 
658
            }
 
659
            break;
 
660
 
 
661
        case mwSession_STOPPING:
 
662
            {
 
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));
 
669
                    free(reason);
 
670
                }
 
671
            }
 
672
 
 
673
            emit sessionStateChange(
 
674
                    static_cast<MeanwhileProtocol *>(account->protocol())
 
675
                    ->statusOffline);
 
676
            break;
 
677
 
 
678
        case mwSession_STOPPED:
 
679
            break;
 
680
 
 
681
        case mwSession_UNKNOWN:
 
682
        default:
 
683
            mwDebug() << "Unhandled state change " << state << endl;
 
684
    }
 
685
}
 
686
 
 
687
int MeanwhileSession::handleSessionIOWrite(const guchar *buffer,
 
688
        gsize count)
 
689
{
 
690
    HERE;
 
691
 
 
692
    if (socket == 0L)
 
693
        return 1;
 
694
 
 
695
    int remaining, retval = 0;
 
696
    for (remaining = count; remaining > 0; remaining -= retval) {
 
697
        retval = socket->write((char *)buffer, count);
 
698
        if (retval <= 0)
 
699
            return 1;
 
700
    }
 
701
    socket->flush();
 
702
    return 0;
 
703
}
 
704
 
 
705
void MeanwhileSession::handleSessionAdmin(const char *text)
 
706
{
 
707
    HERE;
 
708
    emit serverNotification(QString(text));
 
709
}
 
710
 
 
711
void MeanwhileSession::handleSessionAnnounce(struct mwLoginInfo *from,
 
712
        gboolean /* may_reply */, const char *text)
 
713
{
 
714
    HERE;
 
715
    QString message;
 
716
    message.sprintf("Announcement from %s:\n%s", from->user_id, text);
 
717
    emit serverNotification(message);
 
718
}
 
719
 
 
720
void MeanwhileSession::handleSessionSetUserStatus()
 
721
{
 
722
    struct mwUserStatus *userstatus = mwSession_getUserStatus(session);
 
723
    emit sessionStateChange(convertStatus((unsigned int)userstatus->status));
 
724
}
 
725
 
 
726
void MeanwhileSession::handleSessionSetPrivacyInfo()
 
727
{
 
728
}
 
729
 
 
730
void MeanwhileSession::handleSessionIOClose()
 
731
{
 
732
    HERE;
 
733
 
 
734
    if (!socket)
 
735
        return;
 
736
 
 
737
    socket->flush();
 
738
    socket->close();
 
739
 
 
740
    delete socket;
 
741
    socket = 0;
 
742
}
 
743
 
 
744
void MeanwhileSession::handleSessionClear()
 
745
{
 
746
}
 
747
 
 
748
void MeanwhileSession::handleAwareAttrib(struct mwAwareAttribute * /* attrib */)
 
749
{
 
750
    HERE;
 
751
}
 
752
 
 
753
void MeanwhileSession::handleAwareListAware(struct mwAwareSnapshot *snapshot)
 
754
{
 
755
    HERE;
 
756
    MeanwhileContact *contact = static_cast<MeanwhileContact *>
 
757
                (account->contacts().value(snapshot->id.user));
 
758
 
 
759
    if (contact == 0L)
 
760
        return;
 
761
 
 
762
    /* use the setUserStatus callback for status updates for myself. */
 
763
    if (contact == account->myself())
 
764
        return;
 
765
 
 
766
    /* ### TODO!!
 
767
    contact->setProperty(get_protocol()->statusMessage, snapshot->status.desc);
 
768
    contact->setProperty(get_protocol()->awayMessage, snapshot->status.desc);
 
769
    */
 
770
 
 
771
    Kopete::OnlineStatus onlinestatus;
 
772
    if (snapshot->online) {
 
773
        onlinestatus = convertStatus(snapshot->status.status);
 
774
        resolveContactNickname(contact);
 
775
    } else {
 
776
        onlinestatus = convertStatus(0);
 
777
    }
 
778
 
 
779
    contact->setOnlineStatus(onlinestatus);
 
780
 
 
781
#if 0
 
782
    /* Commented out in previous kopete/meanwhile plugin for some reason,
 
783
     * but has still been ported to the new API.
 
784
     */
 
785
    time_t idletime = 0;
 
786
    if (snapshot->status.status == mwStatus_IDLE) {
 
787
        idletime = (snapshot->status.time == 0xdeadbeef) ?
 
788
            0 : snapshot->status.time;
 
789
        if (idletime != 0) {
 
790
        contact->setStatusDescription(statusDesc + '[' +
 
791
                QString::number(idletime/60)+" mins]");
 
792
        }
 
793
    } else
 
794
        contact->setStatusDescription(snapshot->status.desc);
 
795
#endif
 
796
}
 
797
 
 
798
void MeanwhileSession::handleAwareListAttrib(struct mwAwareIdBlock * /* id */,
 
799
        struct mwAwareAttribute * /* attrib */)
 
800
{
 
801
    HERE;
 
802
}
 
803
 
 
804
struct MeanwhileSession::ConversationData
 
805
    *MeanwhileSession::createConversationData(
 
806
        struct mwConversation *conv, MeanwhileContact *contact,
 
807
        bool createQueue)
 
808
{
 
809
    struct ConversationData *cd = new ConversationData();
 
810
 
 
811
    if (cd == 0L)
 
812
        return 0L;
 
813
 
 
814
    cd->contact = contact;
 
815
    cd->chat    = contact->manager(Kopete::Contact::CanCreate);
 
816
    cd->chat->ref();
 
817
    if (createQueue)
 
818
        cd->queue = new Q3ValueList<Kopete::Message>();
 
819
 
 
820
    mwConversation_setClientData(conv, cd, 0L);
 
821
 
 
822
    return cd;
 
823
}
 
824
 
 
825
void MeanwhileSession::handleImConvOpened(struct mwConversation *conv)
 
826
{
 
827
    HERE;
 
828
 
 
829
    struct ConversationData *convdata =
 
830
        (struct ConversationData *)mwConversation_getClientData(conv);
 
831
 
 
832
    if (convdata == 0L) {
 
833
        /* a new conversation */
 
834
        convdata = createConversationData(conv, conversationContact(conv));
 
835
 
 
836
        if (convdata == 0L) {
 
837
            mwDebug() << "No memory for conversation data!" << endl;
 
838
            return;
 
839
        }
 
840
 
 
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();
 
845
                ++it) {
 
846
            mwConversation_send(conv, mwImSend_PLAIN,
 
847
                    (*it).plainBody().toAscii());
 
848
            convdata->chat->appendMessage(*it);
 
849
            convdata->chat->messageSucceeded();
 
850
        }
 
851
        convdata->queue->clear();
 
852
        delete convdata->queue;
 
853
        convdata->queue = 0L;
 
854
    }
 
855
    resolveContactNickname(convdata->contact);
 
856
}
 
857
 
 
858
void MeanwhileSession::handleImConvClosed(struct mwConversation *conv,
 
859
        guint32)
 
860
{
 
861
    HERE;
 
862
 
 
863
    ConversationData *convdata =
 
864
        (ConversationData *)mwConversation_getClientData(conv);
 
865
 
 
866
    if (!convdata)
 
867
        return;
 
868
 
 
869
    mwConversation_setClientData(conv, 0L, 0L);
 
870
 
 
871
    convdata->chat->removeContact(convdata->contact);
 
872
    convdata->chat->deref();
 
873
    convdata->chat = 0L;
 
874
    if (convdata->queue != 0L) {
 
875
        convdata->queue->clear();
 
876
        delete convdata->queue;
 
877
        convdata->queue = 0L;
 
878
    }
 
879
    free(convdata);
 
880
}
 
881
 
 
882
void MeanwhileSession::handleImConvReceived(struct mwConversation *conv,
 
883
        enum mwImSendType type, gconstpointer msg)
 
884
{
 
885
    HERE;
 
886
    ConversationData *convdata =
 
887
        (ConversationData *)mwConversation_getClientData(conv);
 
888
 
 
889
    if (!convdata)
 
890
        return;
 
891
 
 
892
    switch (type) {
 
893
    case mwImSend_PLAIN:
 
894
        {
 
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);
 
899
        }
 
900
        break;
 
901
    case mwImSend_TYPING:
 
902
        convdata->chat->receivedTypingMsg(convdata->contact);
 
903
        break;
 
904
    default:
 
905
        mwDebug() << "Unable to handle message type: " << type << endl;
 
906
    }
 
907
}
 
908
 
 
909
void MeanwhileSession::handleResolveLookupResults(
 
910
        struct mwServiceResolve * /* srvc */, guint32 /* id */,
 
911
        guint32 /* code */, GList *results, gpointer data)
 
912
{
 
913
    struct mwResolveResult *result;
 
914
    struct mwResolveMatch *match;
 
915
 
 
916
    if (results == 0L)
 
917
        return;
 
918
    if ((result = (struct mwResolveResult *)results->data) == 0L)
 
919
        return;
 
920
 
 
921
    if (result->matches == 0L)
 
922
        return;
 
923
    if ((match = (struct mwResolveMatch *)result->matches->data) == 0L)
 
924
        return;
 
925
 
 
926
    mwDebug() << "resolve lookup returned '" << match->name << "'" << endl;
 
927
 
 
928
    MeanwhileContact *contact = (MeanwhileContact *)data;
 
929
    if (contact == 0L)
 
930
        return;
 
931
 
 
932
    contact->setNickName(getNickName(match->name));
 
933
}
 
934
 
 
935
void MeanwhileSession::handleStorageLoad(struct mwServiceStorage * /* srvc */,
 
936
        guint32 result, struct mwStorageUnit *item, gpointer /* data */)
 
937
{
 
938
    HERE;
 
939
    if (result != ERR_SUCCESS) {
 
940
        mwDebug() << "contact list load returned " << result << endl;
 
941
        return;
 
942
    }
 
943
 
 
944
    struct mwGetBuffer *buf = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
 
945
    struct mwSametimeList *list = mwSametimeList_new();
 
946
    mwSametimeList_get(buf, list);
 
947
 
 
948
    GList *gl, *glf, *cl, *clf;
 
949
 
 
950
    Kopete::ContactList *contactlist = Kopete::ContactList::self();
 
951
 
 
952
    for (glf = gl = mwSametimeList_getGroups(list); gl; gl = gl->next) {
 
953
        struct mwSametimeGroup *stgroup = (struct mwSametimeGroup *)gl->data;
 
954
 
 
955
        Kopete::Group *group =
 
956
            contactlist->findGroup(mwSametimeGroup_getName(stgroup));
 
957
        group->setPluginData(account->protocol(), "alias",
 
958
                mwSametimeGroup_getAlias(stgroup));
 
959
 
 
960
        for (clf = cl = mwSametimeGroup_getUsers(stgroup); cl; cl = cl->next) {
 
961
            struct mwSametimeUser *stuser = (struct mwSametimeUser *)cl->data;
 
962
 
 
963
            MeanwhileContact *contact = static_cast<MeanwhileContact *>
 
964
                        (account->contacts().value(mwSametimeUser_getUser(stuser)));
 
965
 
 
966
            if (contact != 0L)
 
967
                continue;
 
968
 
 
969
            account->addContact(mwSametimeUser_getUser(stuser),
 
970
                    mwSametimeUser_getAlias(stuser), group,
 
971
                    Kopete::Account::ChangeKABC);
 
972
        }
 
973
        g_list_free(clf);
 
974
    }
 
975
    g_list_free(glf);
 
976
 
 
977
    mwSametimeList_free(list);
 
978
}
 
979
 
 
980
const struct MeanwhileClientID *MeanwhileSession::getClientIDs()
 
981
{
 
982
    return ids;
 
983
}
 
984
 
 
985
#if 0
 
986
MEANWHILE_HOOK_CONFERENCE(conference_invite,
 
987
        (struct mwConference *conf, struct mwLoginInfo *inviter,
 
988
         const char *invite),
 
989
        (conf, inviter, invite))
 
990
{
 
991
    HERE;
 
992
    QString message;
 
993
 
 
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);
 
998
 
 
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);
 
1004
}
 
1005
#endif
 
1006
#include "meanwhilesession.moc"