summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/gadu/gaduaccount.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/gadu/gaduaccount.cpp')
-rw-r--r--kopete/protocols/gadu/gaduaccount.cpp1261
1 files changed, 1261 insertions, 0 deletions
diff --git a/kopete/protocols/gadu/gaduaccount.cpp b/kopete/protocols/gadu/gaduaccount.cpp
new file mode 100644
index 00000000..6dd737ce
--- /dev/null
+++ b/kopete/protocols/gadu/gaduaccount.cpp
@@ -0,0 +1,1261 @@
+// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*-
+//
+// Copyright (C) 2003-2004 Grzegorz Jaskiewicz <gj at pointblue.com.pl>
+// Copyright (C) 2003 Zack Rusin <[email protected]>
+//
+// gaduaccount.cpp
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA
+
+#include "gaduaccount.h"
+#include "gaducontact.h"
+#include "gaduprotocol.h"
+#include "gaduawayui.h"
+#include "gaduaway.h"
+#include "gadupubdir.h"
+#include "gadudcc.h"
+#include "gadudcctransaction.h"
+
+#include "kopetemetacontact.h"
+#include "kopetecontactlist.h"
+#include "kopetegroup.h"
+#include "kopetepassword.h"
+#include "kopeteuiglobal.h"
+#include "kopeteglobal.h"
+
+#include <kpassdlg.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+
+#include <qapplication.h>
+#include <qdialog.h>
+#include <qtimer.h>
+#include <qtextcodec.h>
+#include <qptrlist.h>
+#include <qtextstream.h>
+#include <qhostaddress.h>
+
+#include <netinet/in.h>
+
+class GaduAccountPrivate {
+
+public:
+ GaduAccountPrivate() {}
+
+ GaduSession* session_;
+ GaduDCC* gaduDcc_;
+
+ QTimer* pingTimer_;
+
+ QTextCodec* textcodec_;
+ KFileDialog* saveListDialog;
+ KFileDialog* loadListDialog;
+
+ KActionMenu* actionMenu_;
+ KAction* searchAction;
+ KAction* listputAction;
+ KAction* listToFileAction;
+ KAction* listFromFileAction;
+ KAction* friendsModeAction;
+ bool connectWithSSL;
+
+ int currentServer;
+ unsigned int serverIP;
+
+ QString lastDescription;
+ bool forFriends;
+ bool ignoreAnons;
+
+ QTimer* exportTimer_;
+ bool exportUserlist;
+
+ KConfigGroup* config;
+ Kopete::OnlineStatus status;
+ QValueList<unsigned int> servers;
+ KGaduLoginParams loginInfo;
+};
+
+// 10s is enough ;p
+#define USERLISTEXPORT_TIMEOUT (10*1000)
+
+// FIXME: use dynamic cache please, i consider this as broken resolution of this problem
+static const char* const servers_ip[] = {
+ "217.17.41.85",
+ "217.17.41.83",
+ "217.17.41.84",
+ "217.17.41.86",
+ "217.17.41.87",
+ "217.17.41.88",
+ "217.17.41.92",
+ "217.17.41.93",
+ "217.17.45.133",
+ "217.17.45.143",
+ "217.17.45.144"
+};
+
+#define NUM_SERVERS (sizeof(servers_ip)/sizeof(char*))
+
+ GaduAccount::GaduAccount( Kopete::Protocol* parent, const QString& accountID,const char* name )
+: Kopete::PasswordedAccount( parent, accountID, 0, name )
+{
+ QHostAddress ip;
+ p = new GaduAccountPrivate;
+
+ p->pingTimer_ = NULL;
+ p->saveListDialog = NULL;
+ p->loadListDialog = NULL;
+ p->forFriends = false;
+
+ p->textcodec_ = QTextCodec::codecForName( "CP1250" );
+ p->session_ = new GaduSession( this, "GaduSession" );
+
+ KGlobal::config()->setGroup( "Gadu" );
+
+ setMyself( new GaduContact( accountId().toInt(), accountId(), this, Kopete::ContactList::self()->myself() ) );
+
+ p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
+ p->lastDescription = QString::null;
+
+ for ( unsigned int i = 0; i < NUM_SERVERS ; i++ ) {
+ ip.setAddress( QString( servers_ip[i] ) );
+ p->servers.append( htonl( ip.toIPv4Address() ) );
+ kdDebug( 14100 ) << "adding IP: " << p->servers[ i ] << " to cache" << endl;
+ }
+ p->currentServer = -1;
+ p->serverIP = 0;
+
+ // initialize KGaduLogin structure to default values
+ p->loginInfo.uin = accountId().toInt();
+ p->loginInfo.useTls = false;
+ p->loginInfo.status = GG_STATUS_AVAIL;
+ p->loginInfo.server = 0;
+ p->loginInfo.client_port = 0;
+ p->loginInfo.client_addr = 0;
+
+ p->pingTimer_ = new QTimer( this );
+ p->exportTimer_ = new QTimer( this );
+
+ p->exportUserlist = false;
+ p->gaduDcc_ = NULL;
+
+ p->config = configGroup();
+
+ p->ignoreAnons = ignoreAnons();
+ p->forFriends = loadFriendsMode();
+
+ initConnections();
+ initActions();
+
+ QString nick = p->config->readEntry( QString::fromAscii( "nickName" ) );
+ if ( !nick.isNull() ) {
+ myself()->setProperty( Kopete::Global::Properties::self()->nickName(), nick );
+ }
+ else {
+ myself()->setProperty( Kopete::Global::Properties::self()->nickName(), accountId() );
+ p->config->writeEntry( QString::fromAscii( "nickName" ), accountId() );
+ }
+}
+
+GaduAccount::~GaduAccount()
+{
+ delete p;
+}
+
+void
+GaduAccount::initActions()
+{
+ p->searchAction = new KAction( i18n( "&Search for Friends" ), "", 0,
+ this, SLOT( slotSearch() ), this, "actionSearch" );
+ p->listputAction = new KAction( i18n( "Export Contacts to Server" ), "", 0,
+ this, SLOT( slotExportContactsList() ), this, "actionListput" );
+ p->listToFileAction = new KAction( i18n( "Export Contacts to File..." ), "", 0,
+ this, SLOT( slotExportContactsListToFile() ), this, "actionListputFile" );
+ p->listFromFileAction = new KAction( i18n( "Import Contacts From File..." ), "", 0,
+ this, SLOT( slotImportContactsFromFile() ), this, "actionListgetFile" );
+ p->friendsModeAction = new KToggleAction( i18n( "Only for Friends" ), "", 0,
+ this, SLOT( slotFriendsMode() ), this,
+ "actionFriendsMode" );
+
+ static_cast<KToggleAction*>(p->friendsModeAction)->setChecked( p->forFriends );
+}
+
+void
+GaduAccount::initConnections()
+{
+ QObject::connect( p->session_, SIGNAL( error( const QString&, const QString& ) ),
+ SLOT( error( const QString&, const QString& ) ) );
+ QObject::connect( p->session_, SIGNAL( messageReceived( KGaduMessage* ) ),
+ SLOT( messageReceived( KGaduMessage* ) ) );
+ QObject::connect( p->session_, SIGNAL( contactStatusChanged( KGaduNotify* ) ),
+ SLOT( contactStatusChanged( KGaduNotify* ) ) );
+ QObject::connect( p->session_, SIGNAL( connectionFailed( gg_failure_t )),
+ SLOT( connectionFailed( gg_failure_t ) ) );
+ QObject::connect( p->session_, SIGNAL( connectionSucceed( ) ),
+ SLOT( connectionSucceed( ) ) );
+ QObject::connect( p->session_, SIGNAL( disconnect( Kopete::Account::DisconnectReason ) ),
+ SLOT( slotSessionDisconnect( Kopete::Account::DisconnectReason ) ) );
+ QObject::connect( p->session_, SIGNAL( ackReceived( unsigned int ) ),
+ SLOT( ackReceived( unsigned int ) ) );
+ QObject::connect( p->session_, SIGNAL( pubDirSearchResult( const SearchResult&, unsigned int ) ),
+ SLOT( slotSearchResult( const SearchResult&, unsigned int ) ) );
+ QObject::connect( p->session_, SIGNAL( userListExported() ),
+ SLOT( userListExportDone() ) );
+ QObject::connect( p->session_, SIGNAL( userListRecieved( const QString& ) ),
+ SLOT( userlist( const QString& ) ) );
+ QObject::connect( p->session_, SIGNAL( incomingCtcp( unsigned int ) ),
+ SLOT( slotIncomingDcc( unsigned int ) ) );
+
+ QObject::connect( p->pingTimer_, SIGNAL( timeout() ),
+ SLOT( pingServer() ) );
+
+ QObject::connect( p->exportTimer_, SIGNAL( timeout() ),
+ SLOT( slotUserlistSynch() ) );
+}
+
+void
+GaduAccount::setAway( bool isAway, const QString& awayMessage )
+{
+ unsigned int currentStatus;
+
+ if ( isAway ) {
+ currentStatus = ( awayMessage.isEmpty() ) ? GG_STATUS_BUSY : GG_STATUS_BUSY_DESCR;
+ }
+ else{
+ currentStatus = ( awayMessage.isEmpty() ) ? GG_STATUS_AVAIL : GG_STATUS_AVAIL_DESCR;
+ }
+ changeStatus( GaduProtocol::protocol()->convertStatus( currentStatus ), awayMessage );
+}
+
+
+KActionMenu*
+GaduAccount::actionMenu()
+{
+ kdDebug(14100) << "actionMenu() " << endl;
+
+ p->actionMenu_ = new KActionMenu( accountId(), myself()->onlineStatus().iconFor( this ), this );
+ p->actionMenu_->popupMenu()->insertTitle( myself()->onlineStatus().iconFor( myself() ), i18n( "%1 <%2> " ).
+ arg( myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString(), accountId() ) );
+
+ if ( p->session_->isConnected() ) {
+ p->searchAction->setEnabled( TRUE );
+ p->listputAction->setEnabled( TRUE );
+ p->friendsModeAction->setEnabled( TRUE );
+ }
+ else {
+ p->searchAction->setEnabled( FALSE );
+ p->listputAction->setEnabled( FALSE );
+ p->friendsModeAction->setEnabled( FALSE );
+ }
+
+ if ( contacts().count() > 1 ) {
+ if ( p->saveListDialog ) {
+ p->listToFileAction->setEnabled( FALSE );
+ }
+ else {
+ p->listToFileAction->setEnabled( TRUE );
+ }
+
+ p->listToFileAction->setEnabled( TRUE );
+ }
+ else {
+ p->listToFileAction->setEnabled( FALSE );
+ }
+
+ if ( p->loadListDialog ) {
+ p->listFromFileAction->setEnabled( FALSE );
+ }
+ else {
+ p->listFromFileAction->setEnabled( TRUE );
+ }
+ p->actionMenu_->insert( new KAction( i18n( "Go O&nline" ),
+ GaduProtocol::protocol()->convertStatus( GG_STATUS_AVAIL ).iconFor( this ),
+ 0, this, SLOT( slotGoOnline() ), this, "actionGaduConnect" ) );
+
+ p->actionMenu_->insert( new KAction( i18n( "Set &Busy" ),
+ GaduProtocol::protocol()->convertStatus( GG_STATUS_BUSY ).iconFor( this ),
+ 0, this, SLOT( slotGoBusy() ), this, "actionGaduConnect" ) );
+
+ p->actionMenu_->insert( new KAction( i18n( "Set &Invisible" ),
+ GaduProtocol::protocol()->convertStatus( GG_STATUS_INVISIBLE ).iconFor( this ),
+ 0, this, SLOT( slotGoInvisible() ), this, "actionGaduConnect" ) );
+
+ p->actionMenu_->insert( new KAction( i18n( "Go &Offline" ),
+ GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ).iconFor( this ),
+ 0, this, SLOT( slotGoOffline() ), this, "actionGaduConnect" ) );
+
+ p->actionMenu_->insert( new KAction( i18n( "Set &Description..." ), "info",
+ 0, this, SLOT( slotDescription() ), this, "actionGaduDescription" ) );
+
+ p->actionMenu_->insert( p->friendsModeAction );
+
+ p->actionMenu_->popupMenu()->insertSeparator();
+
+ p->actionMenu_->insert( p->searchAction );
+
+ p->actionMenu_->popupMenu()->insertSeparator();
+
+ p->actionMenu_->insert( p->listputAction );
+
+ p->actionMenu_->popupMenu()->insertSeparator();
+
+ p->actionMenu_->insert( p->listToFileAction );
+ p->actionMenu_->insert( p->listFromFileAction );
+
+ return p->actionMenu_;
+}
+
+void
+GaduAccount::connectWithPassword(const QString& password)
+{
+ if (password.isEmpty()) {
+ return;
+ }
+ if (isConnected ())
+ return;
+ // FIXME: add status description to this mechainsm, this is a hack now. libkopete design issue.
+ changeStatus( initialStatus(), p->lastDescription );
+}
+
+void
+GaduAccount::disconnect()
+{
+ disconnect( Manual );
+}
+
+void
+GaduAccount::disconnect( DisconnectReason reason )
+{
+ slotGoOffline();
+ p->connectWithSSL = true;
+ Kopete::Account::disconnected( reason );
+}
+
+void
+GaduAccount::setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason )
+{
+ kdDebug(14100) << k_funcinfo << "Called" << endl;
+ changeStatus( status, reason);
+}
+
+void
+GaduAccount::slotUserlistSynch()
+{
+ if ( !p->exportUserlist ) {
+ return;
+ }
+ p->exportUserlist = false;
+ kdDebug(14100) << "userlist changed, exporting" << endl;
+ slotExportContactsList();
+}
+
+void
+GaduAccount::userlistChanged()
+{
+ p->exportUserlist = true;
+ p->exportTimer_->changeInterval( USERLISTEXPORT_TIMEOUT );
+}
+
+bool
+GaduAccount::createContact( const QString& contactId, Kopete::MetaContact* parentContact )
+{
+ kdDebug(14100) << "createContact " << contactId << endl;
+
+ uin_t uinNumber = contactId.toUInt();
+ GaduContact* newContact = new GaduContact( uinNumber, parentContact->displayName(),this, parentContact );
+ newContact->setParentIdentity( accountId() );
+ addNotify( uinNumber );
+
+ userlistChanged();
+
+ return true;
+}
+
+void
+GaduAccount::changeStatus( const Kopete::OnlineStatus& status, const QString& descr )
+{
+ unsigned int ns;
+
+ kdDebug(14100) << "##### change status #####" << endl;
+ kdDebug(14100) << "### Status = " << p->session_->isConnected() << endl;
+ kdDebug(14100) << "### Status description = \"" << descr << "\"" << endl;
+
+ // if change to not available, log off
+ if ( GG_S_NA( status.internalStatus() ) ) {
+ if ( !p->session_->isConnected() ) {
+ return;//already logged off
+ }
+ else {
+ if ( status.internalStatus() == GG_STATUS_NOT_AVAIL_DESCR ) {
+ if ( p->session_->changeStatusDescription( status.internalStatus(), descr, p->forFriends ) != 0 ) {
+ return;
+ }
+ }
+ }
+ p->session_->logoff();
+ dccOff();
+ }
+ else {
+ // if status is for no desc, but we get some desc, than convert it to status with desc
+ if (!descr.isEmpty() && !GaduProtocol::protocol()->statusWithDescription( status.internalStatus() ) ) {
+ // and rerun us again. This won't cause any recursive call, as both conversions are static
+ ns = GaduProtocol::protocol()->statusToWithDescription( status );
+ changeStatus( GaduProtocol::protocol()->convertStatus( ns ), descr );
+ return;
+ }
+
+ // well, if it's empty but we want to set status with desc, change it too
+ if (descr.isEmpty() && GaduProtocol::protocol()->statusWithDescription( status.internalStatus() ) ) {
+ ns = GaduProtocol::protocol()->statusToWithoutDescription( status );
+ changeStatus( GaduProtocol::protocol()->convertStatus( ns ), descr );
+ return;
+ }
+
+ if ( !p->session_->isConnected() ) {
+ if ( password().cachedValue().isEmpty() ) {
+ // FIXME: when status string added to connect(), use it here
+ p->lastDescription = descr;
+ connect( status/*, descr*/ );
+ return;
+ }
+
+ if ( useTls() != TLS_no ) {
+ p->connectWithSSL = true;
+ }
+ else {
+ p->connectWithSSL = false;
+ }
+ dccOn();
+ p->serverIP = 0;
+ p->currentServer = -1;
+ p->status = status;
+ kdDebug(14100) << "#### Connecting..., tls option "<< (int)useTls() << " " << endl;
+ p->lastDescription = descr;
+ slotLogin( status.internalStatus(), descr );
+ return;
+ }
+ else {
+ p->status = status;
+ if ( descr.isEmpty() ) {
+ if ( p->session_->changeStatus( status.internalStatus(), p->forFriends ) != 0 )
+ return;
+ }
+ else {
+ if ( p->session_->changeStatusDescription( status.internalStatus(), descr, p->forFriends ) != 0 )
+ return;
+ }
+ }
+ }
+
+ myself()->setOnlineStatus( status );
+ myself()->setProperty( GaduProtocol::protocol()->propAwayMessage, descr );
+
+ if ( status.internalStatus() == GG_STATUS_NOT_AVAIL || status.internalStatus() == GG_STATUS_NOT_AVAIL_DESCR ) {
+ if ( p->pingTimer_ ){
+ p->pingTimer_->stop();
+ }
+ }
+ p->lastDescription = descr;
+}
+
+void
+GaduAccount::slotLogin( int status, const QString& dscr )
+{
+ p->lastDescription = dscr;
+
+ myself()->setOnlineStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_CONNECTING ));
+ myself()->setProperty( GaduProtocol::protocol()->propAwayMessage, dscr );
+
+ if ( !p->session_->isConnected() ) {
+ if ( password().cachedValue().isEmpty() ) {
+ connectionFailed( GG_FAILURE_PASSWORD );
+ }
+ else {
+ p->loginInfo.password = password().cachedValue();
+ p->loginInfo.useTls = p->connectWithSSL;
+ p->loginInfo.status = status;
+ p->loginInfo.statusDescr = dscr;
+ p->loginInfo.forFriends = p->forFriends;
+ p->loginInfo.server = p->serverIP;
+ if ( dccEnabled() ) {
+ p->loginInfo.client_addr = gg_dcc_ip;
+ p->loginInfo.client_port = gg_dcc_port;
+ }
+ else {
+ p->loginInfo.client_addr = 0;
+ p->loginInfo.client_port = 0;
+ }
+ p->session_->login( &p->loginInfo );
+ }
+ }
+ else {
+ p->session_->changeStatus( status );
+ }
+}
+
+void
+GaduAccount::slotLogoff()
+{
+ if ( p->session_->isConnected() || p->status == GaduProtocol::protocol()->convertStatus( GG_STATUS_CONNECTING )) {
+ p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
+ changeStatus( p->status );
+ p->session_->logoff();
+ dccOff();
+ }
+}
+
+void
+GaduAccount::slotGoOnline()
+{
+ changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_AVAIL ) );
+}
+void
+GaduAccount::slotGoOffline()
+{
+ slotLogoff();
+ dccOff();
+}
+
+void
+GaduAccount::slotGoInvisible()
+{
+ changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_INVISIBLE ) );
+}
+
+void
+GaduAccount::slotGoBusy()
+{
+ changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_BUSY ) );
+}
+
+void
+GaduAccount::removeContact( const GaduContact* c )
+{
+ if ( isConnected() ) {
+ const uin_t u = c->uin();
+ p->session_->removeNotify( u );
+ userlistChanged();
+ }
+}
+
+void
+GaduAccount::addNotify( uin_t uin )
+{
+ if ( p->session_->isConnected() ) {
+ p->session_->addNotify( uin );
+ }
+}
+
+void
+GaduAccount::notify( uin_t* userlist, int count )
+{
+ if ( p->session_->isConnected() ) {
+ p->session_->notify( userlist, count );
+ }
+}
+
+void
+GaduAccount::sendMessage( uin_t recipient, const Kopete::Message& msg, int msgClass )
+{
+ if ( p->session_->isConnected() ) {
+ p->session_->sendMessage( recipient, msg, msgClass );
+ }
+}
+
+void
+GaduAccount::error( const QString& title, const QString& message )
+{
+ KMessageBox::error( Kopete::UI::Global::mainWidget(), title, message );
+}
+
+void
+GaduAccount::messageReceived( KGaduMessage* gaduMessage )
+{
+ GaduContact* contact = 0;
+ QPtrList<Kopete::Contact> contactsListTmp;
+
+ // FIXME:check for ignored users list
+
+ if ( gaduMessage->sender_id == 0 ) {
+ //system message, display them or not?
+ kdDebug(14100) << "####" << " System Message " << gaduMessage->message << endl;
+ return;
+ }
+
+ contact = static_cast<GaduContact*> ( contacts()[ QString::number( gaduMessage->sender_id ) ] );
+
+ if ( !contact ) {
+ if ( p->ignoreAnons == true ) {
+ return;
+ }
+
+ Kopete::MetaContact* metaContact = new Kopete::MetaContact ();
+ metaContact->setTemporary ( true );
+ contact = new GaduContact( gaduMessage->sender_id,
+ QString::number( gaduMessage->sender_id ), this, metaContact );
+ Kopete::ContactList::self ()->addMetaContact( metaContact );
+ addNotify( gaduMessage->sender_id );
+ }
+
+ contactsListTmp.append( myself() );
+ Kopete::Message msg( gaduMessage->sendTime, contact, contactsListTmp, gaduMessage->message, Kopete::Message::Inbound, Kopete::Message::RichText );
+ contact->messageReceived( msg );
+}
+
+void
+GaduAccount::ackReceived( unsigned int recipient )
+{
+ GaduContact* contact;
+
+ contact = static_cast<GaduContact*> ( contacts()[ QString::number( recipient ) ] );
+ if ( contact ) {
+ kdDebug(14100) << "####" << "Received an ACK from " << contact->uin() << endl;
+ contact->messageAck();
+ }
+ else {
+ kdDebug(14100) << "####" << "Received an ACK from an unknown user : " << recipient << endl;
+ }
+}
+
+void
+GaduAccount::contactStatusChanged( KGaduNotify* gaduNotify )
+{
+ kdDebug(14100) << "####" << " contact's status changed, uin:" << gaduNotify->contact_id <<endl;
+
+ GaduContact* contact;
+
+ contact = static_cast<GaduContact*>( contacts()[ QString::number( gaduNotify->contact_id ) ] );
+ if( !contact ) {
+ kdDebug(14100) << "Notify not in the list " << gaduNotify->contact_id << endl;
+ return;
+ }
+
+ contact->changedStatus( gaduNotify );
+}
+
+void
+GaduAccount::pong()
+{
+ kdDebug(14100) << "####" << " Pong..." << endl;
+}
+
+void
+GaduAccount::pingServer()
+{
+ kdDebug(14100) << "####" << " Ping..." << endl;
+ p->session_->ping();
+}
+
+void
+GaduAccount::connectionFailed( gg_failure_t failure )
+{
+ bool tryReconnect = false;
+ QString pass;
+
+
+ switch (failure) {
+ case GG_FAILURE_PASSWORD:
+ password().setWrong();
+ // user pressed CANCEL
+ p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
+ myself()->setOnlineStatus( p->status );
+ disconnected( BadPassword );
+ return;
+ default:
+ if ( p->connectWithSSL ) {
+ if ( useTls() != TLS_only ) {
+ slotCommandDone( QString::null, i18n( "connection using SSL was not possible, retrying without." ) );
+ kdDebug( 14100 ) << "try without tls now" << endl;
+ p->connectWithSSL = false;
+ tryReconnect = true;
+ p->currentServer = -1;
+ p->serverIP = 0;
+ break;
+ }
+ }
+ else {
+ if ( p->currentServer == NUM_SERVERS - 1 ) {
+ p->serverIP = 0;
+ p->currentServer = -1;
+ kdDebug(14100) << "trying : " << "IP from hub " << endl;
+ }
+ else {
+ p->serverIP = p->servers[ ++p->currentServer ];
+ kdDebug(14100) << "trying : " << p->currentServer << " IP " << p->serverIP << endl;
+ tryReconnect = true;
+ }
+ }
+ break;
+ }
+
+ if ( tryReconnect ) {
+ slotLogin( p->status.internalStatus() , p->lastDescription );
+ }
+ else {
+ error( i18n( "unable to connect to the Gadu-Gadu server(\"%1\")." ).arg( GaduSession::failureDescription( failure ) ),
+ i18n( "Connection Error" ) );
+ p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
+ myself()->setOnlineStatus( p->status );
+ disconnected( InvalidHost );
+ }
+}
+
+void
+GaduAccount::dccOn()
+{
+ if ( dccEnabled() ) {
+ if ( !p->gaduDcc_ ) {
+ p->gaduDcc_ = new GaduDCC( this );
+ }
+ kdDebug( 14100 ) << " turn DCC on for " << accountId() << endl;
+ p->gaduDcc_->registerAccount( this );
+ p->loginInfo.client_port = p->gaduDcc_->listeingPort();
+ }
+}
+
+void
+GaduAccount::dccOff()
+{
+ if ( p->gaduDcc_ ) {
+ kdDebug( 14100 ) << "destroying dcc in gaduaccount " << endl;
+ delete p->gaduDcc_;
+ p->gaduDcc_ = NULL;
+ p->loginInfo.client_port = 0;
+ p->loginInfo.client_addr = 0;
+ }
+}
+
+void
+GaduAccount::slotIncomingDcc( unsigned int uin )
+{
+ GaduContact* contact;
+ GaduDCCTransaction* trans;
+
+ if ( !uin ) {
+ return;
+ }
+
+ contact = static_cast<GaduContact*>( contacts()[ QString::number( uin ) ] );
+
+ if ( !contact ) {
+ kdDebug(14100) << "attempt to make dcc connection from unknown uin " << uin << endl;
+ return;
+ }
+
+ // if incapabile to transfer files, forget about it.
+ if ( contact->contactPort() < 10 ) {
+ kdDebug(14100) << "can't respond to " << uin << " request, his listeing port is too low" << endl;
+ return;
+ }
+
+ trans = new GaduDCCTransaction( p->gaduDcc_ );
+ if ( trans->setupIncoming( p->loginInfo.uin, contact ) == false ) {
+ delete trans;
+ }
+
+}
+
+void
+GaduAccount::connectionSucceed( )
+{
+ kdDebug(14100) << "#### Gadu-Gadu connected! " << endl;
+ p->status = GaduProtocol::protocol()->convertStatus( p->session_->status() );
+ myself()->setOnlineStatus( p->status );
+ myself()->setProperty( GaduProtocol::protocol()->propAwayMessage, p->lastDescription );
+ startNotify();
+
+ p->session_->requestContacts();
+ p->pingTimer_->start( 3*60*1000 );//3 minute timeout
+ pingServer();
+
+ // check if we need to export userlist every USERLISTEXPORT_TIMEOUT ms
+ p->exportTimer_->start( USERLISTEXPORT_TIMEOUT );
+}
+
+void
+GaduAccount::startNotify()
+{
+ int i = 0;
+ if ( !contacts().count() ) {
+ return;
+ }
+
+ QDictIterator<Kopete::Contact> kopeteContactsList( contacts() );
+
+ uin_t* userlist = 0;
+ userlist = new uin_t[ contacts().count() ];
+
+ for( i=0 ; kopeteContactsList.current() ; ++kopeteContactsList ) {
+ userlist[i++] = static_cast<GaduContact*> ((*kopeteContactsList))->uin();
+ }
+
+ p->session_->notify( userlist, contacts().count() );
+ delete [] userlist;
+}
+
+void
+GaduAccount::slotSessionDisconnect( Kopete::Account::DisconnectReason reason )
+{
+ uin_t status;
+
+ kdDebug(14100) << "Disconnecting" << endl;
+
+ if (p->pingTimer_) {
+ p->pingTimer_->stop();
+ }
+
+ setAllContactsStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ) );
+
+ status = myself()->onlineStatus().internalStatus();
+ if ( status != GG_STATUS_NOT_AVAIL || status != GG_STATUS_NOT_AVAIL_DESCR ) {
+ myself()->setOnlineStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ) );
+ }
+ GaduAccount::disconnect( reason );
+}
+
+void
+GaduAccount::userlist( const QString& contactsListString )
+{
+ kdDebug(14100)<<"### Got userlist - gadu account"<<endl;
+
+ GaduContactsList contactsList( contactsListString );
+ QString contactName;
+ QStringList groups;
+ GaduContact* contact;
+ Kopete::MetaContact* metaContact;
+ unsigned int i;
+
+ // don't export any new changes that were just imported :-)
+ p->exportTimer_->stop();
+
+ for ( i = 0; i != contactsList.size() ; i++ ) {
+ kdDebug(14100) << "uin " << contactsList[i].uin << endl;
+
+ if ( contactsList[i].uin.isNull() ) {
+ kdDebug(14100) << "no Uin, strange.. "<<endl;
+ continue;
+ }
+
+ if ( contacts()[ contactsList[i].uin ] ) {
+ kdDebug(14100) << "UIN already exists in contacts "<< contactsList[i].uin << endl;
+ }
+ else {
+ contactName = GaduContact::findBestContactName( &contactsList[i] );
+ bool s = addContact( contactsList[i].uin, contactName, 0L, Kopete::Account::DontChangeKABC);
+ if ( s == false ) {
+ kdDebug(14100) << "There was a problem adding UIN "<< contactsList[i].uin << "to users list" << endl;
+ continue;
+ }
+ }
+ contact = static_cast<GaduContact*>( contacts()[ contactsList[i].uin ] );
+ if ( contact == NULL ) {
+ kdDebug(14100) << "oops, no Kopete::Contact in contacts()[] for some reason, for \"" << contactsList[i].uin << "\"" << endl;
+ continue;
+ }
+
+ // update/add infor for contact
+ contact->setContactDetails( &contactsList[i] );
+
+ if ( !( contactsList[i].group.isEmpty() ) ) {
+ // FIXME: libkopete bug i guess, by default contact goes to top level group
+ // if user desrired to see contact somewhere else, remove it from top level one
+ metaContact = contact->metaContact();
+ metaContact->removeFromGroup( Kopete::Group::topLevel() );
+ // put him in all desired groups:
+ groups = QStringList::split( ",", contactsList[i].group );
+ for ( QStringList::Iterator groupsIterator = groups.begin(); groupsIterator != groups.end(); ++groupsIterator ) {
+ metaContact->addToGroup( Kopete::ContactList::self ()->findGroup ( *groupsIterator) );
+ }
+ }
+ }
+ // start to check if we need to export userlist
+ p->exportUserlist = false;
+ p->exportTimer_->start( USERLISTEXPORT_TIMEOUT );
+}
+
+void
+GaduAccount::userListExportDone()
+{
+ slotCommandDone( QString::null, i18n( "Contacts exported to the server.") );
+}
+
+void
+GaduAccount::slotFriendsMode()
+{
+ p->forFriends = !p->forFriends;
+ kdDebug( 14100 ) << "for friends mode: " << p->forFriends << " desc" << p->lastDescription << endl;
+ // now change status, it will changing it with p->forFriends flag
+ changeStatus( p->status, p->lastDescription );
+
+ saveFriendsMode( p->forFriends );
+
+}
+
+// FIXME: make loading and saving nonblocking (at the moment KFileDialog stops plugin/kopete)
+
+void
+GaduAccount::slotExportContactsListToFile()
+{
+ KTempFile tempFile;
+ tempFile.setAutoDelete( true );
+
+ if ( p->saveListDialog ) {
+ kdDebug( 14100 ) << " save contacts to file: alread waiting for input " << endl ;
+ return;
+ }
+
+ p->saveListDialog = new KFileDialog( "::kopete-gadu" + accountId(), QString::null,
+ Kopete::UI::Global::mainWidget(), "gadu-list-save", false );
+ p->saveListDialog->setCaption(
+ i18n("Save Contacts List for Account %1 As").arg(
+ myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString() ) );
+
+ if ( p->saveListDialog->exec() == QDialog::Accepted ) {
+ QCString list = p->textcodec_->fromUnicode( userlist()->asString() );
+
+ if ( tempFile.status() ) {
+ // say cheese, can't create file.....
+ error( i18n( "Unable to create temporary file." ), i18n( "Save Contacts List Failed" ) );
+ }
+ else {
+ QTextStream* tempStream = tempFile.textStream();
+ (*tempStream) << list.data();
+ tempFile.close();
+
+ bool res = KIO::NetAccess::upload(
+ tempFile.name() ,
+ p->saveListDialog->selectedURL() ,
+ Kopete::UI::Global::mainWidget()
+ );
+ if ( !res ) {
+ // say it failed
+ error( KIO::NetAccess::lastErrorString(), i18n( "Save Contacts List Failed" ) );
+ }
+ }
+
+ }
+ delete p->saveListDialog;
+ p->saveListDialog = NULL;
+}
+
+void
+GaduAccount::slotImportContactsFromFile()
+{
+ KURL url;
+ QCString list;
+ QString oname;
+
+ if ( p->loadListDialog ) {
+ kdDebug( 14100 ) << "load contacts from file: alread waiting for input " << endl ;
+ return;
+ }
+
+ p->loadListDialog = new KFileDialog( "::kopete-gadu" + accountId(), QString::null,
+ Kopete::UI::Global::mainWidget(), "gadu-list-load", true );
+ p->loadListDialog->setCaption(
+ i18n("Load Contacts List for Account %1 As").arg(
+ myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString() ) );
+
+ if ( p->loadListDialog->exec() == QDialog::Accepted ) {
+ url = p->loadListDialog->selectedURL();
+ kdDebug(14100) << "a:" << url << "\nb:" << oname << endl;
+ if ( KIO::NetAccess::download( url, oname, Kopete::UI::Global::mainWidget() ) ) {
+ QFile tempFile( oname );
+ if ( tempFile.open( IO_ReadOnly ) ) {
+ list = tempFile.readAll();
+ tempFile.close();
+ KIO::NetAccess::removeTempFile( oname );
+ // and store it
+ kdDebug( 14100 ) << "loaded list:" << endl;
+ kdDebug( 14100 ) << list << endl;
+ kdDebug( 14100 ) << " --------------- " << endl;
+ userlist( p->textcodec_->toUnicode( list ) );
+ }
+ else {
+ error( tempFile.errorString(),
+ i18n( "Contacts List Load Has Failed" ) );
+ }
+ }
+ else {
+ // say, it failed misourably
+ error( KIO::NetAccess::lastErrorString(),
+ i18n( "Contacts List Load Has Failed" ) );
+ }
+
+ }
+ delete p->loadListDialog;
+ p->loadListDialog = NULL;
+}
+
+unsigned int
+GaduAccount::getPersonalInformation()
+{
+ return p->session_->getPersonalInformation();
+}
+
+bool
+GaduAccount::publishPersonalInformation( ResLine& d )
+{
+ return p->session_->publishPersonalInformation( d );
+}
+
+void
+GaduAccount::slotExportContactsList()
+{
+ p->session_->exportContactsOnServer( userlist() );
+}
+
+GaduContactsList*
+GaduAccount::userlist()
+{
+ GaduContact* contact;
+ GaduContactsList* contactsList = new GaduContactsList();
+ int i;
+
+ if ( !contacts().count() ) {
+ return contactsList;
+ }
+
+ QDictIterator<Kopete::Contact> contactsIterator( contacts() );
+
+ for( i=0 ; contactsIterator.current() ; ++contactsIterator ) {
+ contact = static_cast<GaduContact*>( *contactsIterator );
+ if ( contact->uin() != static_cast<GaduContact*>( myself() )->uin() ) {
+ contactsList->addContact( *contact->contactDetails() );
+ }
+ }
+
+ return contactsList;
+}
+
+void
+GaduAccount::slotSearch( int uin )
+{
+ new GaduPublicDir( this, uin );
+}
+
+void
+GaduAccount::slotChangePassword()
+{
+}
+
+void
+GaduAccount::slotCommandDone( const QString& /*title*/, const QString& what )
+{
+ //FIXME: any chance to have my own title in event popup ?
+ KNotifyClient::userEvent( 0, what,
+ KNotifyClient::PassivePopup, KNotifyClient::Notification );
+}
+
+void
+GaduAccount::slotCommandError(const QString& title, const QString& what )
+{
+ error( title, what );
+}
+
+void
+GaduAccount::slotDescription()
+{
+ GaduAway* away = new GaduAway( this );
+
+ if( away->exec() == QDialog::Accepted ) {
+ changeStatus( GaduProtocol::protocol()->convertStatus( away->status() ),
+ away->awayText() );
+ }
+ delete away;
+}
+
+unsigned int
+GaduAccount::pubDirSearch( ResLine& query, int ageFrom, int ageTo, bool onlyAlive )
+{
+ return p->session_->pubDirSearch( query, ageFrom, ageTo, onlyAlive );
+}
+
+void
+GaduAccount::pubDirSearchClose()
+{
+ p->session_->pubDirSearchClose();
+}
+
+void
+GaduAccount::slotSearchResult( const SearchResult& result, unsigned int seq )
+{
+ emit pubDirSearchResult( result, seq );
+}
+
+void
+GaduAccount::sendFile( GaduContact* peer, QString& filePath )
+{
+ GaduDCCTransaction* gtran = new GaduDCCTransaction( p->gaduDcc_ );
+ gtran->setupOutgoing( peer, filePath );
+}
+
+void
+GaduAccount::dccRequest( GaduContact* peer )
+{
+ if ( peer && p->session_ ) {
+ p->session_->dccRequest( peer->uin() );
+ }
+}
+
+// dcc settings
+bool
+GaduAccount::dccEnabled()
+{
+ QString s = p->config->readEntry( QString::fromAscii( "useDcc" ) );
+ kdDebug( 14100 ) << "dccEnabled: "<< s << endl;
+ if ( s == QString::fromAscii( "enabled" ) ) {
+ return true;
+ }
+ return false;
+}
+
+bool
+GaduAccount::setDcc( bool d )
+{
+ QString s;
+ bool f = true;
+
+ if ( d == false ) {
+ dccOff();
+ s = QString::fromAscii( "disabled" );
+ }
+ else {
+ s = QString::fromAscii( "enabled" );
+ }
+
+ p->config->writeEntry( QString::fromAscii( "useDcc" ), s );
+
+ if ( p->session_->isConnected() && d ) {
+ dccOn();
+ }
+
+ kdDebug( 14100 ) << "s: "<<s<<endl;
+
+ return f;
+}
+
+void
+GaduAccount::saveFriendsMode( bool i )
+{
+ p->config->writeEntry( QString::fromAscii( "forFriends" ),
+ i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
+}
+
+bool
+GaduAccount::loadFriendsMode()
+{
+ QString s;
+ bool r;
+ int n;
+
+ s = p->config->readEntry( QString::fromAscii( "forFriends" ) );
+ n = s.toInt( &r );
+
+ if ( n ) {
+ return true;
+ }
+
+ return false;
+
+}
+
+// might be bit inconsistent with what I used in DCC, but hell, it is so much easier to parse :-)
+bool
+GaduAccount::ignoreAnons()
+{
+ QString s;
+ bool r;
+ int n;
+
+ s = p->config->readEntry( QString::fromAscii( "ignoreAnons" ) );
+ n = s.toInt( &r );
+
+ if ( n ) {
+ return true;
+ }
+
+ return false;
+
+}
+
+void
+GaduAccount::setIgnoreAnons( bool i )
+{
+ p->ignoreAnons = i;
+ p->config->writeEntry( QString::fromAscii( "ignoreAnons" ),
+ i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
+}
+
+GaduAccount::tlsConnection
+GaduAccount::useTls()
+{
+ QString s;
+ bool c;
+ unsigned int oldC;
+ tlsConnection Tls;
+
+ s = p->config->readEntry( QString::fromAscii( "useEncryptedConnection" ) );
+ oldC = s.toUInt( &c );
+ // we have old format
+ if ( c ) {
+ kdDebug( 14100 ) << "old format for param useEncryptedConnection, value " <<
+ oldC << " willl be converted to new string value" << endl;
+ setUseTls( (tlsConnection) oldC );
+ // should be string now, unless there was an error reading
+ s = p->config->readEntry( QString::fromAscii( "useEncryptedConnection" ) );
+ kdDebug( 14100 ) << "new useEncryptedConnection value : " << s << endl;
+ }
+
+ Tls = TLS_no;
+ if ( s == "TLS_ifAvaliable" ) {
+ Tls = TLS_ifAvaliable;
+ }
+ if ( s == "TLS_only" ) {
+ Tls = TLS_only;
+ }
+
+ return Tls;
+}
+
+void
+GaduAccount::setUseTls( tlsConnection ut )
+{
+ QString s;
+ switch( ut ) {
+ case TLS_ifAvaliable:
+ s = "TLS_ifAvaliable";
+ break;
+
+ case TLS_only:
+ s = "TLS_only";
+ break;
+
+ default:
+ case TLS_no:
+ s = "TLS_no";
+ break;
+ }
+
+ p->config->writeEntry( QString::fromAscii( "useEncryptedConnection" ), s );
+}
+
+#include "gaduaccount.moc"