You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
542 lines
16 KiB
542 lines
16 KiB
/*
|
|
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 <kopete-devel@kde.org>
|
|
|
|
*************************************************************************
|
|
* *
|
|
* 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 <tqapplication.h>
|
|
#include <tqtimer.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;
|
|
TQString host, user, userDN, pass;
|
|
TQString osname, tzname, clientName, clientVersion;
|
|
uint port;
|
|
/* int tzoffset;*/
|
|
bool active;
|
|
RequestFactory * requestFactory;
|
|
ChatroomManager * chatroomMgr;
|
|
UserDetailsManager * userDetailsMgr;
|
|
PrivacyManager * privacyMgr;
|
|
uint protocolVersion;
|
|
TQValueList<GroupWise::CustomStatus> customStatuses;
|
|
TQTimer * keepAliveTimer;
|
|
};
|
|
|
|
Client::Client(TQObject *par, uint protocolVersion )
|
|
:TQObject(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 TQTimer( this );
|
|
connect( d->keepAliveTimer, TQT_SIGNAL( timeout() ), TQT_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, TQT_SIGNAL(connected()), TQT_SLOT(streamConnected()));
|
|
//connect(d->stream, TQT_SIGNAL(handshaken()), TQT_SLOT(streamHandshaken()));
|
|
connect(d->stream, TQT_SIGNAL(error(int)), TQT_SLOT(streamError(int)));
|
|
//connect(d->stream, TQT_SIGNAL(sslCertificateReady(const QSSLCert &)), TQT_SLOT(streamSSLCertificateReady(const QSSLCert &)));
|
|
connect(d->stream, TQT_SIGNAL(readyRead()), TQT_SLOT(streamReadyRead()));
|
|
//connect(d->stream, TQT_SIGNAL(closeFinished()), TQT_SLOT(streamCloseFinished()));
|
|
|
|
d->stream->connectToServer(server, auth);
|
|
}
|
|
|
|
void Client::setOSName(const TQString &name)
|
|
{
|
|
d->osname = name;
|
|
}
|
|
|
|
void Client::setClientName(const TQString &s)
|
|
{
|
|
d->clientName = s;
|
|
}
|
|
|
|
void Client::setClientVersion(const TQString &s)
|
|
{
|
|
d->clientVersion = s;
|
|
}
|
|
|
|
void Client::start( const TQString &host, const uint port, const TQString &userId, const TQString &pass )
|
|
{
|
|
d->host = host;
|
|
d->port = port;
|
|
d->user = userId;
|
|
d->pass = pass;
|
|
|
|
initialiseEventTasks();
|
|
|
|
LoginTask * login = new LoginTask( d->root );
|
|
|
|
connect( login, TQT_SIGNAL( gotMyself( const GroupWise::ContactDetails & ) ),
|
|
this, TQT_SIGNAL( accountDetailsReceived( const GroupWise::ContactDetails & ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( gotFolder( const FolderItem & ) ),
|
|
this, TQT_SIGNAL( folderReceived( const FolderItem & ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( gotContact( const ContactItem & ) ),
|
|
this, TQT_SIGNAL( contactReceived( const ContactItem & ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
|
|
this, TQT_SIGNAL( contactUserDetailsReceived( const GroupWise::ContactDetails & ) ) ) ;
|
|
|
|
connect( login, TQT_SIGNAL( gotPrivacySettings( bool, bool, const TQStringList &, const TQStringList & ) ),
|
|
privacyManager(), TQT_SLOT( slotGotPrivacySettings( bool, bool, const TQStringList &, const TQStringList & ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( gotCustomStatus( const GroupWise::CustomStatus & ) ),
|
|
TQT_SLOT( lt_gotCustomStatus( const GroupWise::CustomStatus & ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( gotKeepalivePeriod( int ) ), TQT_SLOT( lt_gotKeepalivePeriod( int ) ) );
|
|
|
|
connect( login, TQT_SIGNAL( finished() ), this, TQT_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;
|
|
}
|
|
}
|
|
|
|
TQString Client::host()
|
|
{
|
|
return d->host;
|
|
}
|
|
|
|
int Client::port()
|
|
{
|
|
return d->port;
|
|
}
|
|
|
|
TQValueList<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, TQT_SIGNAL( gotStatus( const TQString &, Q_UINT16, const TQString & ) ), TQT_SIGNAL( statusReceived( const TQString &, Q_UINT16, const TQString & ) ) );
|
|
// The ConferenceTask handles incoming conference events, messages, joins, leaves, etc
|
|
ConferenceTask * ct = new ConferenceTask( d->root );
|
|
connect( ct, TQT_SIGNAL( message( const ConferenceEvent & ) ), TQT_SLOT( ct_messageReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( typing( const ConferenceEvent & ) ), TQT_SIGNAL( contactTyping( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( notTyping( const ConferenceEvent & ) ), TQT_SIGNAL( contactNotTyping( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( joined( const ConferenceEvent & ) ), TQT_SIGNAL( conferenceJoinNotifyReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( left( const ConferenceEvent & ) ), TQT_SIGNAL( conferenceLeft( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( invited( const ConferenceEvent & ) ), TQT_SIGNAL( invitationReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( otherInvited( const ConferenceEvent & ) ), TQT_SIGNAL( inviteNotifyReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( invitationDeclined( const ConferenceEvent & ) ), TQT_SIGNAL( invitationDeclined( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( closed( const ConferenceEvent & ) ), TQT_SIGNAL( conferenceClosed( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( autoReply( const ConferenceEvent & ) ), TQT_SIGNAL( autoReplyReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( broadcast( const ConferenceEvent & ) ), TQT_SIGNAL( broadcastReceived( const ConferenceEvent & ) ) );
|
|
connect( ct, TQT_SIGNAL( systemBroadcast( const ConferenceEvent & ) ), TQT_SIGNAL( systemBroadcastReceived( const ConferenceEvent & ) ) );
|
|
|
|
|
|
// The ConnectionTask handles incoming connection events
|
|
ConnectionTask* cont = new ConnectionTask( d->root );
|
|
connect( cont, TQT_SIGNAL( connectedElsewhere() ), TQT_SIGNAL( connectedElsewhere() ) );
|
|
}
|
|
|
|
void Client::setStatus( GroupWise::Status status, const TQString & reason, const TQString & autoReply )
|
|
{
|
|
debug( TQString("Setting status to %1").arg( status ) );;
|
|
SetStatusTask * sst = new SetStatusTask( d->root );
|
|
sst->status( status, reason, autoReply );
|
|
connect( sst, TQT_SIGNAL( finished() ), this, TQT_SLOT( sst_statusChanged() ) );
|
|
sst->go( true );
|
|
// TODO: set status change in progress flag
|
|
}
|
|
|
|
void Client::requestStatus( const TQString & userDN )
|
|
{
|
|
GetStatusTask * gst = new GetStatusTask( d->root );
|
|
gst->userDN( userDN );
|
|
connect( gst, TQT_SIGNAL( gotStatus( const TQString &, Q_UINT16, const TQString & ) ), TQT_SIGNAL( statusReceived( const TQString &, Q_UINT16, const TQString & ) ) );
|
|
gst->go( true );
|
|
}
|
|
|
|
void Client::sendMessage( const TQStringList & addresseeDNs, const OutgoingMessage & message )
|
|
{
|
|
SendMessageTask * smt = new SendMessageTask( d->root );
|
|
smt->message( addresseeDNs, message );
|
|
connect( smt, TQT_SIGNAL( finished() ), TQT_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 )
|
|
{
|
|
TQStringList dummy;
|
|
createConference( clientId, dummy );
|
|
}
|
|
|
|
void Client::createConference( const int clientId, const TQStringList & participants )
|
|
{
|
|
CreateConferenceTask * cct = new CreateConferenceTask( d->root );
|
|
cct->conference( clientId, participants );
|
|
connect( cct, TQT_SIGNAL( finished() ), TQT_SLOT( cct_conferenceCreated() ) );
|
|
cct->go( true );
|
|
}
|
|
void Client::requestDetails( const TQStringList & userDNs )
|
|
{
|
|
GetDetailsTask * gdt = new GetDetailsTask( d->root );
|
|
gdt->userDNs( userDNs );
|
|
connect( gdt, TQT_SIGNAL( gotContactUserDetails( const GroupWise::ContactDetails & ) ),
|
|
this, TQT_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, TQT_SIGNAL( finished() ), TQT_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, TQT_SIGNAL( finished() ), TQT_SLOT( lct_leftConference() ) );
|
|
lct->go( true );
|
|
}
|
|
|
|
void Client::sendInvitation( const GroupWise::ConferenceGuid & guid, const TQString & dn, const GroupWise::OutgoingMessage & message )
|
|
{
|
|
SendInviteTask * sit = new SendInviteTask( d->root );
|
|
TQStringList invitees( dn );
|
|
sit->invite( guid, dn, message );
|
|
sit->go( true );
|
|
}
|
|
|
|
// SLOTS //
|
|
void Client::streamError( int error )
|
|
{
|
|
debug( TQString( "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, TQString::null, TQString::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;
|
|
TQString 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
|
|
TQRegExp rx(" </span> </span> </span><br>$");
|
|
transformedEvent.message.replace( rx, "</span></span></span>" );
|
|
// missing linebreak after first line of an encrypted message
|
|
TQRegExp 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( TQString( "Joined conference %1, participants are: " ).arg( jct->guid() ) );
|
|
TQStringList parts = jct->participants();
|
|
for ( TQStringList::Iterator it = parts.begin(); it != parts.end(); ++it )
|
|
debug( TQString( " - %1" ).arg(*it) );
|
|
debug( "invitees are: " );
|
|
TQStringList invitees = jct->invitees();
|
|
for ( TQStringList::Iterator it = invitees.begin(); it != invitees.end(); ++it )
|
|
debug( TQString( " - %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 //
|
|
|
|
TQString Client::userId()
|
|
{
|
|
return d->user;
|
|
}
|
|
|
|
void Client::setUserDN( const TQString & userDN )
|
|
{
|
|
d->userDN = userDN;
|
|
}
|
|
|
|
TQString Client::userDN()
|
|
{
|
|
return d->userDN;
|
|
}
|
|
|
|
TQString Client::password()
|
|
{
|
|
return d->pass;
|
|
}
|
|
|
|
TQString Client::userAgent()
|
|
{
|
|
return TQString::fromLatin1( "%1/%2 (%3)" ).arg( d->clientName, d->clientVersion, d->osname );
|
|
}
|
|
|
|
TQCString 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;
|
|
}
|
|
// TQString out = request.toString();
|
|
// debug(TQString("Client: outgoing: [\n%1]\n").arg(out));
|
|
// xmlOutgoing(out);
|
|
|
|
d->stream->write( request );
|
|
}
|
|
|
|
void Client::debug( const TQString &str )
|
|
{
|
|
#ifdef LIBGW_USE_KDEBUG
|
|
kdDebug( GROUPWISE_DEBUG_LIBGW ) << "debug: " << str << endl;
|
|
#else
|
|
qDebug( "CLIENT: %s\n", str.ascii() );
|
|
#endif
|
|
}
|
|
|
|
TQString Client::genUniqueId()
|
|
{
|
|
TQString 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"
|