summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/groupwise/libgroupwise/client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/groupwise/libgroupwise/client.cpp')
-rw-r--r--kopete/protocols/groupwise/libgroupwise/client.cpp541
1 files changed, 541 insertions, 0 deletions
diff --git a/kopete/protocols/groupwise/libgroupwise/client.cpp b/kopete/protocols/groupwise/libgroupwise/client.cpp
new file mode 100644
index 00000000..274a9ea8
--- /dev/null
+++ b/kopete/protocols/groupwise/libgroupwise/client.cpp
@@ -0,0 +1,541 @@
+/*
+ Kopete Groupwise Protocol
+ client.cpp - The main interface for the Groupwise protocol
+
+ Copyright (c) 2004 SUSE Linux AG http://www.suse.com
+ (c) 2008 Novell, Inc.
+
+ Based on Iris, Copyright (C) 2003 Justin Karneges
+
+ Kopete (c) 2002-2004 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qapplication.h>
+#include <qtimer.h>
+
+#include "chatroommanager.h"
+#include "gwclientstream.h"
+#include "privacymanager.h"
+#include "requestfactory.h"
+#include "task.h"
+#include "tasks/conferencetask.h"
+#include "tasks/connectiontask.h"
+#include "tasks/createconferencetask.h"
+#include "tasks/getdetailstask.h"
+#include "tasks/getstatustask.h"
+#include "tasks/joinconferencetask.h"
+#include "tasks/keepalivetask.h"
+#include "tasks/leaveconferencetask.h"
+#include "tasks/logintask.h"
+#include "tasks/rejectinvitetask.h"
+#include "tasks/sendinvitetask.h"
+#include "tasks/sendmessagetask.h"
+#include "tasks/setstatustask.h"
+#include "tasks/statustask.h"
+#include "tasks/typingtask.h"
+#include "userdetailsmanager.h"
+#include "client.h"
+
+class Client::ClientPrivate
+{
+public:
+ ClientPrivate() {}
+
+ ClientStream *stream;
+ int id_seed;
+ Task *root;
+ QString host, user, userDN, pass;
+ QString osname, tzname, clientName, clientVersion;
+ uint port;
+/* int tzoffset;*/
+ bool active;
+ RequestFactory * requestFactory;
+ ChatroomManager * chatroomMgr;
+ UserDetailsManager * userDetailsMgr;
+ PrivacyManager * privacyMgr;
+ uint protocolVersion;
+ QValueList<GroupWise::CustomStatus> customStatuses;
+ QTimer * keepAliveTimer;
+};
+
+Client::Client(QObject *par, uint protocolVersion )
+:QObject(par, "groupwiseclient")
+{
+ d = new ClientPrivate;
+/* d->tzoffset = 0;*/
+ d->active = false;
+ d->osname = "N/A";
+ d->clientName = "N/A";
+ d->clientVersion = "0.0";
+ d->id_seed = 0xaaaa;
+ d->root = new Task(this, true);
+ d->chatroomMgr = 0;
+ d->requestFactory = new RequestFactory;
+ d->userDetailsMgr = new UserDetailsManager( this, "userdetailsmgr" );
+ d->privacyMgr = new PrivacyManager( this, "privacymgr" );
+ d->stream = 0;
+ d->protocolVersion = protocolVersion;
+ // Sends regular keepalives so the server knows we are still running
+ d->keepAliveTimer = new QTimer( this );
+ connect( d->keepAliveTimer, SIGNAL( timeout() ), SLOT( sendKeepAlive() ) );
+}
+
+Client::~Client()
+{
+ delete d->root;
+ delete d->requestFactory;
+ delete d->userDetailsMgr;
+ delete d;
+}
+
+void Client::connectToServer( ClientStream *s, const NovellDN &server, bool auth )
+{
+ d->stream = s;
+ //connect(d->stream, SIGNAL(connected()), SLOT(streamConnected()));
+ //connect(d->stream, SIGNAL(handshaken()), SLOT(streamHandshaken()));
+ connect(d->stream, SIGNAL(error(int)), SLOT(streamError(int)));
+ //connect(d->stream, SIGNAL(sslCertificateReady(const QSSLCert &)), SLOT(streamSSLCertificateReady(const QSSLCert &)));
+ connect(d->stream, SIGNAL(readyRead()), SLOT(streamReadyRead()));
+ //connect(d->stream, SIGNAL(closeFinished()), SLOT(streamCloseFinished()));
+
+ d->stream->connectToServer(server, auth);
+}
+
+void Client::setOSName(const QString &name)
+{
+ d->osname = name;
+}
+
+void Client::setClientName(const QString &s)
+{
+ d->clientName = s;
+}
+
+void Client::setClientVersion(const QString &s)
+{
+ d->clientVersion = s;
+}
+
+void Client::start( const QString &host, const uint port, const QString &userId, const QString &pass )
+{
+ d->host = host;
+ d->port = port;
+ d->user = userId;
+ d->pass = pass;
+
+ initialiseEventTasks();
+
+ LoginTask * login = new LoginTask( d->root );
+
+ connect( login, SIGNAL( gotMyself( const GroupWise::ContactDetails & ) ),
+ this, SIGNAL( accountDetailsReceived( const GroupWise::ContactDetails & ) ) );
+
+ connect( login, SIGNAL( gotFolder( const FolderItem & ) ),
+ this, SIGNAL( folderReceived( const FolderItem & ) ) );
+
+ connect( login, SIGNAL( gotContact( const ContactItem & ) ),
+ this, SIGNAL( contactReceived( const ContactItem & ) ) );
+
+ connect( login, SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
+ this, SIGNAL( contactUserDetailsReceived( const GroupWise::ContactDetails & ) ) ) ;
+
+ connect( login, SIGNAL( gotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ),
+ privacyManager(), SLOT( slotGotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ) );
+
+ connect( login, SIGNAL( gotCustomStatus( const GroupWise::CustomStatus & ) ),
+ SLOT( lt_gotCustomStatus( const GroupWise::CustomStatus & ) ) );
+
+ connect( login, SIGNAL( gotKeepalivePeriod( int ) ), SLOT( lt_gotKeepalivePeriod( int ) ) );
+
+ connect( login, SIGNAL( finished() ), this, SLOT( lt_loginFinished() ) );
+
+ login->initialise();
+ login->go( true );
+
+ d->active = true;
+}
+
+void Client::close()
+{
+ debug( "Client::close()" );
+ d->keepAliveTimer->stop();
+ if(d->stream) {
+ d->stream->disconnect(this);
+ d->stream->close();
+ d->stream = 0;
+ }
+}
+
+QString Client::host()
+{
+ return d->host;
+}
+
+int Client::port()
+{
+ return d->port;
+}
+
+QValueList<GroupWise::CustomStatus> Client::customStatuses()
+{
+ return d->customStatuses;
+}
+
+void Client::initialiseEventTasks()
+{
+ // The StatusTask handles incoming status changes
+ StatusTask * st = new StatusTask( d->root ); // FIXME - add an additional EventRoot?
+ connect( st, SIGNAL( gotStatus( const QString &, Q_UINT16, const QString & ) ), SIGNAL( statusReceived( const QString &, Q_UINT16, const QString & ) ) );
+ // The ConferenceTask handles incoming conference events, messages, joins, leaves, etc
+ ConferenceTask * ct = new ConferenceTask( d->root );
+ connect( ct, SIGNAL( message( const ConferenceEvent & ) ), SLOT( ct_messageReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( typing( const ConferenceEvent & ) ), SIGNAL( contactTyping( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( notTyping( const ConferenceEvent & ) ), SIGNAL( contactNotTyping( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( joined( const ConferenceEvent & ) ), SIGNAL( conferenceJoinNotifyReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( left( const ConferenceEvent & ) ), SIGNAL( conferenceLeft( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( invited( const ConferenceEvent & ) ), SIGNAL( invitationReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( otherInvited( const ConferenceEvent & ) ), SIGNAL( inviteNotifyReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( invitationDeclined( const ConferenceEvent & ) ), SIGNAL( invitationDeclined( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( closed( const ConferenceEvent & ) ), SIGNAL( conferenceClosed( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( autoReply( const ConferenceEvent & ) ), SIGNAL( autoReplyReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( broadcast( const ConferenceEvent & ) ), SIGNAL( broadcastReceived( const ConferenceEvent & ) ) );
+ connect( ct, SIGNAL( systemBroadcast( const ConferenceEvent & ) ), SIGNAL( systemBroadcastReceived( const ConferenceEvent & ) ) );
+
+
+ // The ConnectionTask handles incoming connection events
+ ConnectionTask* cont = new ConnectionTask( d->root );
+ connect( cont, SIGNAL( connectedElsewhere() ), SIGNAL( connectedElsewhere() ) );
+}
+
+void Client::setStatus( GroupWise::Status status, const QString & reason, const QString & autoReply )
+{
+ debug( QString("Setting status to %1").arg( status ) );;
+ SetStatusTask * sst = new SetStatusTask( d->root );
+ sst->status( status, reason, autoReply );
+ connect( sst, SIGNAL( finished() ), this, SLOT( sst_statusChanged() ) );
+ sst->go( true );
+ // TODO: set status change in progress flag
+}
+
+void Client::requestStatus( const QString & userDN )
+{
+ GetStatusTask * gst = new GetStatusTask( d->root );
+ gst->userDN( userDN );
+ connect( gst, SIGNAL( gotStatus( const QString &, Q_UINT16, const QString & ) ), SIGNAL( statusReceived( const QString &, Q_UINT16, const QString & ) ) );
+ gst->go( true );
+}
+
+void Client::sendMessage( const QStringList & addresseeDNs, const OutgoingMessage & message )
+{
+ SendMessageTask * smt = new SendMessageTask( d->root );
+ smt->message( addresseeDNs, message );
+ connect( smt, SIGNAL( finished() ), SLOT( smt_messageSent() ) );
+ smt->go( true );
+}
+
+void Client::sendTyping( const GroupWise::ConferenceGuid & conferenceGuid, bool typing )
+{
+ TypingTask * tt = new TypingTask( d->root );
+ tt->typing( conferenceGuid, typing );
+ tt->go( true );
+}
+
+void Client::createConference( const int clientId )
+{
+ QStringList dummy;
+ createConference( clientId, dummy );
+}
+
+void Client::createConference( const int clientId, const QStringList & participants )
+{
+ CreateConferenceTask * cct = new CreateConferenceTask( d->root );
+ cct->conference( clientId, participants );
+ connect( cct, SIGNAL( finished() ), SLOT( cct_conferenceCreated() ) );
+ cct->go( true );
+}
+void Client::requestDetails( const QStringList & userDNs )
+{
+ GetDetailsTask * gdt = new GetDetailsTask( d->root );
+ gdt->userDNs( userDNs );
+ connect( gdt, SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
+ this, SIGNAL( contactUserDetailsReceived( const GroupWise::ContactDetails & ) ) );
+ gdt->go( true );
+}
+
+void Client::joinConference( const GroupWise::ConferenceGuid & guid )
+{
+ JoinConferenceTask * jct = new JoinConferenceTask( d->root );
+ jct->join( guid );
+ connect( jct, SIGNAL( finished() ), SLOT( jct_joinConfCompleted() ) );
+ jct->go( true );
+}
+
+void Client::rejectInvitation( const GroupWise::ConferenceGuid & guid )
+{
+ RejectInviteTask * rit = new RejectInviteTask ( d->root );
+ rit->reject( guid );
+ // we don't do anything with the results of this task
+ rit->go( true );
+}
+
+void Client::leaveConference( const GroupWise::ConferenceGuid & guid )
+{
+ LeaveConferenceTask * lct = new LeaveConferenceTask( d->root );
+ lct->leave( guid );
+ //connect( lct, SIGNAL( finished() ), SLOT( lct_leftConference() ) );
+ lct->go( true );
+}
+
+void Client::sendInvitation( const GroupWise::ConferenceGuid & guid, const QString & dn, const GroupWise::OutgoingMessage & message )
+{
+ SendInviteTask * sit = new SendInviteTask( d->root );
+ QStringList invitees( dn );
+ sit->invite( guid, dn, message );
+ sit->go( true );
+}
+
+// SLOTS //
+void Client::streamError( int error )
+{
+ debug( QString( "CLIENT ERROR (Error %1)" ).arg( error ) );
+}
+
+void Client::streamReadyRead()
+{
+ debug( "CLIENT STREAM READY READ" );
+ // take the incoming transfer and distribute it to the task tree
+ Transfer * transfer = d->stream->read();
+ distribute( transfer );
+}
+
+void Client::lt_loginFinished()
+{
+ debug( "Client::lt_loginFinished()" );
+ const LoginTask * lt = (LoginTask *)sender();
+ if ( lt->success() )
+ {
+ debug( "Client::lt_loginFinished() LOGIN SUCCEEDED" );
+ // set our initial status
+ SetStatusTask * sst = new SetStatusTask( d->root );
+ sst->status( GroupWise::Available, QString::null, QString::null );
+ sst->go( true );
+ emit loggedIn();
+ // fetch details for any privacy list items that aren't in our contact list.
+ // There is a chicken-and-egg case regarding this: We need the privacy before reading the contact list so
+ // blocked contacts are shown as blocked. But we need not fetch user details for the privacy lists
+ // before reading the contact list, as many privacy items' details are already in the contact list
+ privacyManager()->getDetailsForPrivacyLists();
+ }
+ else
+ {
+ debug( "Client::lt_loginFinished() LOGIN FAILED" );
+ emit loginFailed();
+ }
+ // otherwise client should disconnect and signal failure that way??
+}
+
+void Client::sst_statusChanged()
+{
+ const SetStatusTask * sst = (SetStatusTask *)sender();
+ if ( sst->success() )
+ {
+ emit ourStatusChanged( sst->requestedStatus(), sst->awayMessage(), sst->autoReply() );
+ }
+}
+
+void Client::ct_messageReceived( const ConferenceEvent & messageEvent )
+{
+ debug( "parsing received message's RTF" );
+ ConferenceEvent transformedEvent = messageEvent;
+ RTF2HTML parser;
+ QString rtf = messageEvent.message;
+ if ( !rtf.isEmpty() )
+ transformedEvent.message = parser.Parse( rtf.latin1(), "" );
+
+ // fixes for RTF to HTML conversion problems
+ // we can drop these once the server reenables the sending of unformatted text
+ // redundant linebreak at the end of the message
+ QRegExp rx(" </span> </span> </span><br>$");
+ transformedEvent.message.replace( rx, "</span></span></span>" );
+ // missing linebreak after first line of an encrypted message
+ QRegExp ry("-----BEGIN PGP MESSAGE----- </span> </span> </span>");
+ transformedEvent.message.replace( ry, "-----BEGIN PGP MESSAGE-----</span></span></span><br/>" );
+
+ emit messageReceived( transformedEvent );
+}
+
+void Client::cct_conferenceCreated()
+{
+ const CreateConferenceTask * cct = ( CreateConferenceTask * )sender();
+ if ( cct->success() )
+ {
+ emit conferenceCreated( cct->clientConfId(), cct->conferenceGUID() );
+ }
+ else
+ {
+ emit conferenceCreationFailed( cct->clientConfId(), cct->statusCode() );
+ }
+}
+
+void Client::jct_joinConfCompleted()
+{
+ const JoinConferenceTask * jct = ( JoinConferenceTask * )sender();
+#ifdef LIBGW_DEBUG
+ debug( QString( "Joined conference %1, participants are: " ).arg( jct->guid() ) );
+ QStringList parts = jct->participants();
+ for ( QStringList::Iterator it = parts.begin(); it != parts.end(); ++it )
+ debug( QString( " - %1" ).arg(*it) );
+ debug( "invitees are: " );
+ QStringList invitees = jct->invitees();
+ for ( QStringList::Iterator it = invitees.begin(); it != invitees.end(); ++it )
+ debug( QString( " - %1" ).arg(*it) );
+#endif
+ emit conferenceJoined( jct->guid(), jct->participants(), jct->invitees() );
+}
+
+void Client::lt_gotCustomStatus( const GroupWise::CustomStatus & custom )
+{
+ d->customStatuses.append( custom );
+}
+
+// INTERNALS //
+
+QString Client::userId()
+{
+ return d->user;
+}
+
+void Client::setUserDN( const QString & userDN )
+{
+ d->userDN = userDN;
+}
+
+QString Client::userDN()
+{
+ return d->userDN;
+}
+
+QString Client::password()
+{
+ return d->pass;
+}
+
+QString Client::userAgent()
+{
+ return QString::fromLatin1( "%1/%2 (%3)" ).arg( d->clientName, d->clientVersion, d->osname );
+}
+
+QCString Client::ipAddress()
+{
+ // TODO: remove hardcoding
+ return "10.10.11.103";
+}
+
+void Client::distribute( Transfer * transfer )
+{
+ if( !rootTask()->take( transfer ) )
+ debug( "CLIENT: root task refused transfer" );
+ // at this point the transfer is no longer needed
+ delete transfer;
+}
+
+void Client::send( Request * request )
+{
+ debug( "CLIENT::send()" );
+ if( !d->stream )
+ {
+ debug( "CLIENT - NO STREAM TO SEND ON!");
+ return;
+ }
+// QString out = request.toString();
+// debug(QString("Client: outgoing: [\n%1]\n").arg(out));
+// xmlOutgoing(out);
+
+ d->stream->write( request );
+}
+
+void Client::debug( const QString &str )
+{
+#ifdef LIBGW_USE_KDEBUG
+ kdDebug( GROUPWISE_DEBUG_LIBGW ) << "debug: " << str << endl;
+#else
+ qDebug( "CLIENT: %s\n", str.ascii() );
+#endif
+}
+
+QString Client::genUniqueId()
+{
+ QString s;
+ s.sprintf("a%x", d->id_seed);
+ d->id_seed += 0x10;
+ return s;
+}
+
+PrivacyManager * Client::privacyManager()
+{
+ return d->privacyMgr;
+}
+
+RequestFactory * Client::requestFactory()
+{
+ return d->requestFactory;
+}
+
+UserDetailsManager * Client::userDetailsManager()
+{
+ return d->userDetailsMgr;
+}
+
+Task * Client::rootTask()
+{
+ return d->root;
+}
+
+uint Client::protocolVersion() const
+{
+ return d->protocolVersion;
+}
+
+ChatroomManager * Client::chatroomManager()
+{
+ if ( !d->chatroomMgr )
+ d->chatroomMgr = new ChatroomManager( this, "chatroommgr" );
+ return d->chatroomMgr;
+}
+
+void Client::lt_gotKeepalivePeriod( int period )
+{
+ d->keepAliveTimer->start( period * 60 * 1000 );
+}
+
+void Client::sendKeepAlive()
+{
+ KeepAliveTask * kat = new KeepAliveTask( d->root );
+ kat->setup();
+ kat->go( true );
+}
+
+void Client::smt_messageSent()
+{
+ const SendMessageTask * smt = ( SendMessageTask * )sender();
+ if ( smt->success() )
+ {
+ debug( "message sent OK" );
+ }
+ else
+ {
+ debug( "message sending failed!" );
+ emit messageSendingFailed();
+ }
+}
+
+#include "client.moc"