Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / groupwise / libgroupwise / client.cpp
blobd60cf0a21d2bfd2389071dfb1f8d076e23f74aee
1 /*
2 Kopete Groupwise Protocol
3 client.cpp - The main interface for the Groupwise protocol
5 Copyright (c) 2004 SUSE Linux AG http://www.suse.com
6 (c) 2008 Novell, Inc.
8 Based on Iris, Copyright (C) 2003 Justin Karneges <justin@affinix.com>
10 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
12 *************************************************************************
13 * *
14 * This library is free software; you can redistribute it and/or *
15 * modify it under the terms of the GNU Lesser General Public *
16 * License as published by the Free Software Foundation; either *
17 * version 2 of the License, or (at your option) any later version. *
18 * *
19 *************************************************************************
22 #include <QApplication>
23 #include <QByteArray>
24 #include <QList>
25 #include <QTimer>
27 #include "chatroommanager.h"
28 #include "gwclientstream.h"
29 #include "privacymanager.h"
30 #include "requestfactory.h"
31 #include "task.h"
32 #include "tasks/conferencetask.h"
33 #include "tasks/connectiontask.h"
34 #include "tasks/createconferencetask.h"
35 #include "tasks/getdetailstask.h"
36 #include "tasks/getstatustask.h"
37 #include "tasks/joinconferencetask.h"
38 #include "tasks/keepalivetask.h"
39 #include "tasks/leaveconferencetask.h"
40 #include "tasks/logintask.h"
41 #include "tasks/rejectinvitetask.h"
42 #include "tasks/sendinvitetask.h"
43 #include "tasks/sendmessagetask.h"
44 #include "tasks/setstatustask.h"
45 #include "tasks/statustask.h"
46 #include "tasks/typingtask.h"
47 #include "userdetailsmanager.h"
48 #include "client.h"
50 class Client::ClientPrivate
52 public:
53 ClientPrivate() {}
55 ClientStream *stream;
56 int id_seed;
57 Task *root;
58 QString host, user, userDN, pass;
59 QString osname, tzname, clientName, clientVersion;
60 uint port;
61 /* int tzoffset;*/
62 bool active;
63 RequestFactory * requestFactory;
64 ChatroomManager * chatroomMgr;
65 UserDetailsManager * userDetailsMgr;
66 PrivacyManager * privacyMgr;
67 uint protocolVersion;
68 QList<GroupWise::CustomStatus> customStatuses;
69 QTimer * keepAliveTimer;
72 Client::Client(QObject *par, uint protocolVersion )
73 :QObject(par)
75 setObjectName("groupwiseclient");
76 d = new ClientPrivate;
77 /* d->tzoffset = 0;*/
78 d->active = false;
79 d->osname = "N/A";
80 d->clientName = "N/A";
81 d->clientVersion = "0.0";
82 d->id_seed = 0xaaaa;
83 d->root = new Task(this, true);
84 d->chatroomMgr = 0;
85 d->requestFactory = new RequestFactory;
86 d->userDetailsMgr = new UserDetailsManager( this );
87 d->userDetailsMgr->setObjectName( "userdetailsmgr" );
88 d->privacyMgr = new PrivacyManager( this );
89 d->privacyMgr->setObjectName( "privacymgr" );
90 d->stream = 0;
91 d->protocolVersion = protocolVersion;
92 // Sends regular keepalives so the server knows we are still running
93 d->keepAliveTimer = new QTimer( this );
94 connect( d->keepAliveTimer, SIGNAL( timeout() ), SLOT( sendKeepAlive() ) );
97 Client::~Client()
99 delete d->root;
100 delete d->requestFactory;
101 delete d;
104 void Client::connectToServer( ClientStream *s, const NovellDN &server, bool auth )
106 d->stream = s;
107 //connect(d->stream, SIGNAL(connected()), SLOT(streamConnected()));
108 //connect(d->stream, SIGNAL(handshaken()), SLOT(streamHandshaken()));
109 connect(d->stream, SIGNAL(error(int)), SLOT(streamError(int)));
110 //connect(d->stream, SIGNAL(sslCertificateReady(const QSSLCert &)), SLOT(streamSSLCertificateReady(const QSSLCert &)));
111 connect(d->stream, SIGNAL(readyRead()), SLOT(streamReadyRead()));
112 //connect(d->stream, SIGNAL(closeFinished()), SLOT(streamCloseFinished()));
114 d->stream->connectToServer(server, auth);
117 void Client::setOSName(const QString &name)
119 d->osname = name;
122 void Client::setClientName(const QString &s)
124 d->clientName = s;
127 void Client::setClientVersion(const QString &s)
129 d->clientVersion = s;
132 void Client::start( const QString &host, const uint port, const QString &userId, const QString &pass )
134 d->host = host;
135 d->port = port;
136 d->user = userId;
137 d->pass = pass;
139 initialiseEventTasks();
141 LoginTask * login = new LoginTask( d->root );
143 connect( login, SIGNAL( gotMyself( const GroupWise::ContactDetails & ) ),
144 this, SIGNAL( accountDetailsReceived( const GroupWise::ContactDetails & ) ) );
146 connect( login, SIGNAL( gotFolder( const FolderItem & ) ),
147 this, SIGNAL( folderReceived( const FolderItem & ) ) );
149 connect( login, SIGNAL( gotContact( const ContactItem & ) ),
150 this, SIGNAL( contactReceived( const ContactItem & ) ) );
152 connect( login, SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
153 this, SIGNAL( contactUserDetailsReceived( const GroupWise::ContactDetails & ) ) ) ;
155 connect( login, SIGNAL( gotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ),
156 privacyManager(), SLOT( slotGotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ) );
158 connect( login, SIGNAL( gotCustomStatus( const GroupWise::CustomStatus & ) ),
159 SLOT( lt_gotCustomStatus( const GroupWise::CustomStatus & ) ) );
161 connect( login, SIGNAL( gotKeepalivePeriod( int ) ), SLOT( lt_gotKeepalivePeriod( int ) ) );
163 connect( login, SIGNAL( finished() ), this, SLOT( lt_loginFinished() ) );
165 login->initialise();
166 login->go( true );
168 d->active = true;
171 void Client::close()
173 debug( "Client::close()" );
174 d->keepAliveTimer->stop();
175 if(d->stream) {
176 d->stream->disconnect(this);
177 d->stream->close();
178 d->stream = 0;
182 QString Client::host()
184 return d->host;
187 int Client::port()
189 return d->port;
192 QList<GroupWise::CustomStatus> Client::customStatuses()
194 return d->customStatuses;
197 void Client::initialiseEventTasks()
199 // The StatusTask handles incoming status changes
200 StatusTask * st = new StatusTask( d->root ); // FIXME - add an additional EventRoot?
201 connect( st, SIGNAL( gotStatus( const QString &, quint16, const QString & ) ), SIGNAL( statusReceived( const QString &, quint16, const QString & ) ) );
202 // The ConferenceTask handles incoming conference events, messages, joins, leaves, etc
203 ConferenceTask * ct = new ConferenceTask( d->root );
204 connect( ct, SIGNAL( message( const ConferenceEvent & ) ), SLOT( ct_messageReceived( const ConferenceEvent & ) ) );
205 connect( ct, SIGNAL( typing( const ConferenceEvent & ) ), SIGNAL( contactTyping( const ConferenceEvent & ) ) );
206 connect( ct, SIGNAL( notTyping( const ConferenceEvent & ) ), SIGNAL( contactNotTyping( const ConferenceEvent & ) ) );
207 connect( ct, SIGNAL( joined( const ConferenceEvent & ) ), SIGNAL( conferenceJoinNotifyReceived( const ConferenceEvent & ) ) );
208 connect( ct, SIGNAL( left( const ConferenceEvent & ) ), SIGNAL( conferenceLeft( const ConferenceEvent & ) ) );
209 connect( ct, SIGNAL( invited( const ConferenceEvent & ) ), SIGNAL( invitationReceived( const ConferenceEvent & ) ) );
210 connect( ct, SIGNAL( otherInvited( const ConferenceEvent & ) ), SIGNAL( inviteNotifyReceived( const ConferenceEvent & ) ) );
211 connect( ct, SIGNAL( invitationDeclined( const ConferenceEvent & ) ), SIGNAL( invitationDeclined( const ConferenceEvent & ) ) );
212 connect( ct, SIGNAL( closed( const ConferenceEvent & ) ), SIGNAL( conferenceClosed( const ConferenceEvent & ) ) );
213 connect( ct, SIGNAL( autoReply( const ConferenceEvent & ) ), SIGNAL( autoReplyReceived( const ConferenceEvent & ) ) );
214 connect( ct, SIGNAL( broadcast( const ConferenceEvent & ) ), SIGNAL( broadcastReceived( const ConferenceEvent & ) ) );
215 connect( ct, SIGNAL( systemBroadcast( const ConferenceEvent & ) ), SIGNAL( systemBroadcastReceived( const ConferenceEvent & ) ) );
218 // The ConnectionTask handles incoming connection events
219 ConnectionTask* cont = new ConnectionTask( d->root );
220 connect( cont, SIGNAL( connectedElsewhere() ), SIGNAL( connectedElsewhere() ) );
223 void Client::setStatus( GroupWise::Status status, const QString & reason, const QString & autoReply )
225 debug( QString("Setting status to %1").arg( status ) );;
226 SetStatusTask * sst = new SetStatusTask( d->root );
227 sst->status( status, reason, autoReply );
228 connect( sst, SIGNAL( finished() ), this, SLOT( sst_statusChanged() ) );
229 sst->go( true );
230 // TODO: set status change in progress flag
233 void Client::requestStatus( const QString & userDN )
235 GetStatusTask * gst = new GetStatusTask( d->root );
236 gst->userDN( userDN );
237 connect( gst, SIGNAL( gotStatus( const QString &, quint16, const QString & ) ), SIGNAL( statusReceived( const QString &, quint16, const QString & ) ) );
238 gst->go( true );
241 void Client::sendMessage( const QStringList & addresseeDNs, const OutgoingMessage & message )
243 SendMessageTask * smt = new SendMessageTask( d->root );
244 smt->message( addresseeDNs, message );
245 connect( smt, SIGNAL( finished() ), SLOT( smt_messageSent() ) );
246 smt->go( true );
249 void Client::sendTyping( const GroupWise::ConferenceGuid & conferenceGuid, bool typing )
251 TypingTask * tt = new TypingTask( d->root );
252 tt->typing( conferenceGuid, typing );
253 tt->go( true );
256 void Client::createConference( const int clientId )
258 QStringList dummy;
259 createConference( clientId, dummy );
262 void Client::createConference( const int clientId, const QStringList & participants )
264 CreateConferenceTask * cct = new CreateConferenceTask( d->root );
265 cct->conference( clientId, participants );
266 connect( cct, SIGNAL( finished() ), SLOT( cct_conferenceCreated() ) );
267 cct->go( true );
269 void Client::requestDetails( const QStringList & userDNs )
271 GetDetailsTask * gdt = new GetDetailsTask( d->root );
272 gdt->userDNs( userDNs );
273 connect( gdt, SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
274 this, SIGNAL( contactUserDetailsReceived( const GroupWise::ContactDetails & ) ) );
275 gdt->go( true );
278 void Client::joinConference( const GroupWise::ConferenceGuid & guid )
280 JoinConferenceTask * jct = new JoinConferenceTask( d->root );
281 jct->join( guid );
282 connect( jct, SIGNAL( finished() ), SLOT( jct_joinConfCompleted() ) );
283 jct->go( true );
286 void Client::rejectInvitation( const GroupWise::ConferenceGuid & guid )
288 RejectInviteTask * rit = new RejectInviteTask ( d->root );
289 rit->reject( guid );
290 // we don't do anything with the results of this task
291 rit->go( true );
294 void Client::leaveConference( const GroupWise::ConferenceGuid & guid )
296 LeaveConferenceTask * lct = new LeaveConferenceTask( d->root );
297 lct->leave( guid );
298 //connect( lct, SIGNAL( finished() ), SLOT( lct_leftConference() ) );
299 lct->go( true );
302 void Client::sendInvitation( const GroupWise::ConferenceGuid & guid, const QString & dn, const GroupWise::OutgoingMessage & message )
304 SendInviteTask * sit = new SendInviteTask( d->root );
305 QStringList invitees( dn );
306 sit->invite( guid, invitees, message );
307 sit->go( true );
310 // SLOTS //
311 void Client::streamError( int error )
313 debug( QString( "CLIENT ERROR (Error %1)" ).arg( error ) );
316 void Client::streamReadyRead()
318 debug( "CLIENT STREAM READY READ" );
319 // take the incoming transfer and distribute it to the task tree
320 Transfer * transfer = d->stream->read();
321 distribute( transfer );
324 void Client::lt_loginFinished()
326 debug( "Client::lt_loginFinished()" );
327 const LoginTask * lt = (LoginTask *)sender();
328 if ( lt->success() )
330 debug( "Client::lt_loginFinished() LOGIN SUCCEEDED" );
331 // set our initial status
332 SetStatusTask * sst = new SetStatusTask( d->root );
333 sst->status( GroupWise::Available, QString(), QString() );
334 sst->go( true );
335 emit loggedIn();
336 // fetch details for any privacy list items that aren't in our contact list.
337 // There is a chicken-and-egg case regarding this: We need the privacy before reading the contact list so
338 // blocked contacts are shown as blocked. But we need not fetch user details for the privacy lists
339 // before reading the contact list, as many privacy items' details are already in the contact list
340 privacyManager()->getDetailsForPrivacyLists();
342 else
344 debug( "Client::lt_loginFinished() LOGIN FAILED" );
345 emit loginFailed();
347 // otherwise client should disconnect and signal failure that way??
350 void Client::sst_statusChanged()
352 const SetStatusTask * sst = (SetStatusTask *)sender();
353 if ( sst->success() )
355 emit ourStatusChanged( sst->requestedStatus(), sst->awayMessage(), sst->autoReply() );
359 void Client::ct_messageReceived( const ConferenceEvent & messageEvent )
361 debug( "parsing received message's RTF" );
362 ConferenceEvent transformedEvent = messageEvent;
363 RTF2HTML parser;
364 QString rtf = messageEvent.message;
365 if ( !rtf.isEmpty() )
366 transformedEvent.message = parser.Parse( rtf.toLatin1(), "" );
368 // fixes for RTF to HTML conversion problems
369 // we can drop these once the server reenables the sending of unformatted text
370 // redundant linebreak at the end of the message
371 QRegExp rx(" </span> </span> </span><br>$");
372 transformedEvent.message.replace( rx, "</span></span></span>" );
373 // missing linebreak after first line of an encrypted message
374 QRegExp ry("-----BEGIN PGP MESSAGE----- </span> </span> </span>");
375 transformedEvent.message.replace( ry, "-----BEGIN PGP MESSAGE-----</span></span></span><br/>" );
377 emit messageReceived( transformedEvent );
380 void Client::cct_conferenceCreated()
382 const CreateConferenceTask * cct = ( CreateConferenceTask * )sender();
383 if ( cct->success() )
385 emit conferenceCreated( cct->clientConfId(), cct->conferenceGUID() );
387 else
389 emit conferenceCreationFailed( cct->clientConfId(), cct->statusCode() );
393 void Client::jct_joinConfCompleted()
395 const JoinConferenceTask * jct = ( JoinConferenceTask * )sender();
396 #ifdef LIBGW_DEBUG
397 debug( QString( "Joined conference %1, participants are: " ).arg( jct->guid() ) );
398 QStringList parts = jct->participants();
399 for ( QStringList::Iterator it = parts.begin(); it != parts.end(); ++it )
400 debug( QString( " - %1" ).arg(*it) );
401 debug( "invitees are: " );
402 QStringList invitees = jct->invitees();
403 for ( QStringList::Iterator it = invitees.begin(); it != invitees.end(); ++it )
404 debug( QString( " - %1" ).arg(*it) );
405 #endif
406 emit conferenceJoined( jct->guid(), jct->participants(), jct->invitees() );
409 void Client::lt_gotCustomStatus( const GroupWise::CustomStatus & custom )
411 d->customStatuses.append( custom );
414 // INTERNALS //
416 QString Client::userId()
418 return d->user;
421 void Client::setUserDN( const QString & userDN )
423 d->userDN = userDN;
426 QString Client::userDN()
428 return d->userDN;
431 QString Client::password()
433 return d->pass;
436 QString Client::userAgent()
438 return QString::fromLatin1( "%1/%2 (%3)" ).arg( d->clientName, d->clientVersion, d->osname );
441 QByteArray Client::ipAddress()
443 // TODO: remove hardcoding
444 return "10.10.11.103";
447 void Client::distribute( Transfer * transfer )
449 if( !rootTask()->take( transfer ) )
450 debug( "CLIENT: root task refused transfer" );
451 // at this point the transfer is no longer needed
452 delete transfer;
455 void Client::send( Request * request )
457 debug( "CLIENT::send()" );
458 if( !d->stream )
460 debug( "CLIENT - NO STREAM TO SEND ON!");
461 return;
463 // QString out = request.toString();
464 // debug(QString("Client: outgoing: [\n%1]\n").arg(out));
465 // xmlOutgoing(out);
467 d->stream->write( request );
470 void Client::debug( const QString &str )
472 #ifdef LIBGW_USE_KDEBUG
473 kDebug() << str;
474 #else
475 qDebug() << "CLIENT: " << str.toAscii();
476 #endif
479 QString Client::genUniqueId()
481 QString s;
482 s.sprintf("a%x", d->id_seed);
483 d->id_seed += 0x10;
484 return s;
487 PrivacyManager * Client::privacyManager()
489 return d->privacyMgr;
492 RequestFactory * Client::requestFactory()
494 return d->requestFactory;
497 UserDetailsManager * Client::userDetailsManager()
499 return d->userDetailsMgr;
502 Task * Client::rootTask()
504 return d->root;
507 uint Client::protocolVersion() const
509 return d->protocolVersion;
512 ChatroomManager * Client::chatroomManager()
514 if ( !d->chatroomMgr )
516 d->chatroomMgr = new ChatroomManager( this );
517 d->chatroomMgr->setObjectName( "chatroommgr" );
519 return d->chatroomMgr;
522 void Client::lt_gotKeepalivePeriod( int period )
524 d->keepAliveTimer->start( period * 60 * 1000 );
527 void Client::sendKeepAlive()
529 KeepAliveTask * kat = new KeepAliveTask( d->root );
530 kat->setup();
531 kat->go( true );
534 void Client::smt_messageSent()
536 const SendMessageTask * smt = ( SendMessageTask * )sender();
537 if ( smt->success() )
539 debug( "message sent OK" );
541 else
543 debug( "message sending failed!" );
544 emit messageSendingFailed();
548 #include "client.moc"