Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / gadu / gaduaccount.cpp
blob65a40a9fca7d325676bc63ef9e5d923eccb3275e
1 // vim: set noet ts=4 sts=4 sw=4 :
2 // -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*-
3 //
4 // Copyright (C) 2003-2004 Grzegorz Jaskiewicz <gj at pointblue.com.pl>
5 // Copyright (C) 2003 Zack Rusin <zack@kde.org>
6 //
7 // gaduaccount.cpp
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 // 02110-1301, USA
24 #include "gaduaccount.h"
25 #include "gaducontact.h"
26 #include "gaduprotocol.h"
27 #include "gaduaway.h"
28 #include "gadupubdir.h"
29 #include "gadudcc.h"
30 #include "gadudcctransaction.h"
32 #include "kopetemetacontact.h"
33 #include "kopetecontactlist.h"
34 #include "kopetegroup.h"
35 #include "kopetepassword.h"
36 #include "kopeteuiglobal.h"
37 #include "kopeteglobal.h"
39 #include <kpassworddialog.h>
40 #include <kconfig.h>
41 #include <kdebug.h>
42 #include <kglobal.h>
43 #include <klocale.h>
44 #include <kmenu.h>
45 #include <kmessagebox.h>
46 #include <knotification.h>
47 #include <ktemporaryfile.h>
48 #include <kactionmenu.h>
49 #include <ktoggleaction.h>
50 #include <kio/netaccess.h>
51 #include <kicon.h>
53 #include <qapplication.h>
54 #include <qdialog.h>
55 #include <qtimer.h>
56 #include <qtextcodec.h>
57 #include <qtextstream.h>
58 #include <qhostaddress.h>
59 //Added by qt3to4:
60 #include <QByteArray>
61 #include <QList>
63 #include <netinet/in.h>
64 #include <kconfiggroup.h>
66 class GaduAccountPrivate {
68 public:
69 GaduAccountPrivate() {}
71 GaduSession* session_;
72 GaduDCC* gaduDcc_;
74 QTimer* pingTimer_;
76 QTextCodec* textcodec_;
77 KFileDialog* saveListDialog;
78 KFileDialog* loadListDialog;
80 KAction* searchAction;
81 KAction* listputAction;
82 KAction* listToFileAction;
83 KAction* listFromFileAction;
84 KAction* friendsModeAction;
85 bool connectWithSSL;
87 int currentServer;
88 unsigned int serverIP;
90 QString lastDescription;
91 bool forFriends;
92 bool ignoreAnons;
94 QTimer* exportTimer_;
95 bool exportUserlist;
97 KConfigGroup* config;
98 Kopete::OnlineStatus status;
99 QList<unsigned int> servers;
100 KGaduLoginParams loginInfo;
103 // 10s is enough ;p
104 #define USERLISTEXPORT_TIMEOUT (10*1000)
106 // FIXME: use dynamic cache please, i consider this as broken resolution of this problem
107 static const char* const servers_ip[] = {
108 "217.17.41.88",
109 "217.17.41.85",
110 "217.17.45.143",
111 "217.17.45.144",
112 "217.17.45.145",
113 "217.17.45.146",
114 "217.17.45.147",
115 "217.17.41.82",
116 "217.17.41.83",
117 "217.17.41.84",
118 "217.17.41.86",
119 "217.17.41.87",
120 "217.17.41.92",
121 "217.17.41.93",
122 "217.17.45.133"
125 #define NUM_SERVERS (sizeof(servers_ip)/sizeof(char*))
127 GaduAccount::GaduAccount( Kopete::Protocol* parent, const QString& accountID )
128 : Kopete::PasswordedAccount( parent, accountID, false )
130 QHostAddress ip;
131 p = new GaduAccountPrivate;
133 p->pingTimer_ = NULL;
134 p->saveListDialog = NULL;
135 p->loadListDialog = NULL;
136 p->forFriends = false;
138 p->textcodec_ = QTextCodec::codecForName( "CP1250" );
139 p->session_ = new GaduSession( this );
140 p->session_->setObjectName( QLatin1String("GaduSession") );
142 setMyself( new GaduContact( accountId().toInt(), accountId(), this, Kopete::ContactList::self()->myself() ) );
144 p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
145 p->lastDescription.clear();
147 for ( unsigned int i = 0; i < NUM_SERVERS ; i++ ) {
148 ip.setAddress( QString( servers_ip[i] ) );
149 p->servers.append( htonl( ip.toIPv4Address() ) );
150 kDebug( 14100 ) << "adding IP: " << p->servers[ i ] << " to cache";
152 p->currentServer = -1;
153 p->serverIP = 0;
155 // initialize KGaduLogin structure to default values
156 p->loginInfo.uin = accountId().toInt();
157 p->loginInfo.useTls = false;
158 p->loginInfo.status = GG_STATUS_AVAIL;
159 p->loginInfo.server = 0;
160 p->loginInfo.client_port = 0;
161 p->loginInfo.client_addr = 0;
163 p->pingTimer_ = new QTimer( this );
164 p->exportTimer_ = new QTimer( this );
166 p->exportUserlist = false;
167 p->gaduDcc_ = NULL;
169 p->config = configGroup();
171 p->ignoreAnons = ignoreAnons();
172 p->forFriends = loadFriendsMode();
174 initConnections();
175 initActions();
177 QString nick = p->config->readEntry( QString::fromAscii( "nickName" ), QString() );
178 if ( !nick.isNull() ) {
179 myself()->setProperty( Kopete::Global::Properties::self()->nickName(), nick );
181 else {
182 myself()->setProperty( Kopete::Global::Properties::self()->nickName(), accountId() );
183 p->config->writeEntry( QString::fromAscii( "nickName" ), accountId() );
187 GaduAccount::~GaduAccount()
189 delete p;
192 void
193 GaduAccount::initActions()
195 p->searchAction = new KAction( i18n( "&Search for Friends" ), this );
196 //, "actionSearch" );
197 QObject::connect( p->searchAction, SIGNAL(triggered(bool)), this, SLOT(search()) );
198 p->listputAction = new KAction( i18n( "Export Contacts to Server" ), this );
199 //, "actionListput" );
200 QObject::connect( p->listputAction, SIGNAL(triggered(bool)), this, SLOT(slotExportContactsList()) );
201 p->listToFileAction = new KAction( i18n( "Export Contacts to File..." ), this );
202 //, "actionListputFile" );
203 QObject::connect( p->listToFileAction, SIGNAL(triggered(bool)), this, SLOT(slotExportContactsListToFile()) );
204 p->listFromFileAction = new KAction( i18n( "Import Contacts From File..." ), this );
205 //, "actionListgetFile" );
206 QObject::connect( p->listFromFileAction, SIGNAL(triggered(bool)), this, SLOT(slotImportContactsFromFile()) );
207 p->friendsModeAction = new KToggleAction( i18n( "Only for Friends" ), this );
208 //, "actionFriendsMode" );
209 QObject::connect( p->friendsModeAction, SIGNAL(triggered(bool)), this, SLOT(slotFriendsMode()) );
211 static_cast<KToggleAction*>(p->friendsModeAction)->setChecked( p->forFriends );
214 void
215 GaduAccount::initConnections()
217 QObject::connect( p->session_, SIGNAL( error( const QString&, const QString& ) ),
218 SLOT( error( const QString&, const QString& ) ) );
219 QObject::connect( p->session_, SIGNAL( messageReceived( KGaduMessage* ) ),
220 SLOT( messageReceived( KGaduMessage* ) ) );
221 QObject::connect( p->session_, SIGNAL( contactStatusChanged( KGaduNotify* ) ),
222 SLOT( contactStatusChanged( KGaduNotify* ) ) );
223 QObject::connect( p->session_, SIGNAL( connectionFailed( gg_failure_t )),
224 SLOT( connectionFailed( gg_failure_t ) ) );
225 QObject::connect( p->session_, SIGNAL( connectionSucceed( ) ),
226 SLOT( connectionSucceed( ) ) );
227 QObject::connect( p->session_, SIGNAL( disconnect( Kopete::Account::DisconnectReason ) ),
228 SLOT( slotSessionDisconnect( Kopete::Account::DisconnectReason ) ) );
229 QObject::connect( p->session_, SIGNAL( ackReceived( unsigned int ) ),
230 SLOT( ackReceived( unsigned int ) ) );
231 QObject::connect( p->session_, SIGNAL( pubDirSearchResult( const SearchResult&, unsigned int ) ),
232 SLOT( slotSearchResult( const SearchResult&, unsigned int ) ) );
233 QObject::connect( p->session_, SIGNAL( userListExported() ),
234 SLOT( userListExportDone() ) );
235 QObject::connect( p->session_, SIGNAL( userListRecieved( const QString& ) ),
236 SLOT( userlist( const QString& ) ) );
237 QObject::connect( p->session_, SIGNAL( incomingCtcp( unsigned int ) ),
238 SLOT( slotIncomingDcc( unsigned int ) ) );
240 QObject::connect( p->pingTimer_, SIGNAL( timeout() ),
241 SLOT( pingServer() ) );
243 QObject::connect( p->exportTimer_, SIGNAL( timeout() ),
244 SLOT( slotUserlistSynch() ) );
247 void
248 GaduAccount::setAway( bool isAway, const QString& awayMessage )
250 unsigned int currentStatus;
252 if ( isAway ) {
253 currentStatus = ( awayMessage.isEmpty() ) ? GG_STATUS_BUSY : GG_STATUS_BUSY_DESCR;
255 else{
256 currentStatus = ( awayMessage.isEmpty() ) ? GG_STATUS_AVAIL : GG_STATUS_AVAIL_DESCR;
258 changeStatus( GaduProtocol::protocol()->convertStatus( currentStatus ), awayMessage );
262 void
263 GaduAccount::fillActionMenu( KActionMenu *actionMenu )
265 kDebug(14100);
267 actionMenu->setIcon( myself()->onlineStatus().iconFor( this ) );
268 actionMenu->menu()->addTitle( myself()->onlineStatus().iconFor( myself() ), i18n( "%1 <%2> ",
269 myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString(), accountId() ) );
271 if ( p->session_->isConnected() ) {
272 p->searchAction->setEnabled( true );
273 p->listputAction->setEnabled( true );
274 p->friendsModeAction->setEnabled( true );
276 else {
277 p->searchAction->setEnabled( false );
278 p->listputAction->setEnabled( false );
279 p->friendsModeAction->setEnabled( false );
282 if ( contacts().count() > 1 ) {
283 if ( p->saveListDialog ) {
284 p->listToFileAction->setEnabled( false );
286 else {
287 p->listToFileAction->setEnabled( true );
290 p->listToFileAction->setEnabled( true );
292 else {
293 p->listToFileAction->setEnabled( false );
296 if ( p->loadListDialog ) {
297 p->listFromFileAction->setEnabled( false );
299 else {
300 p->listFromFileAction->setEnabled( true );
303 KAction* action = new KAction(
304 KIcon(QIcon(GaduProtocol::protocol()->convertStatus( GG_STATUS_AVAIL ).iconFor( this ))),
305 i18n("Go O&nline"), this );
306 //, "actionGaduConnect" );
307 QObject::connect( action, SIGNAL(triggered(bool)), this, SLOT(slotGoOnline()));
308 actionMenu->addAction( action );
310 action = new KAction(
311 KIcon(QIcon(GaduProtocol::protocol()->convertStatus( GG_STATUS_BUSY ).iconFor( this ))),
312 i18n( "Set &Busy" ), this );
313 //, "actionGaduConnect" );
314 QObject::connect( action, SIGNAL(triggered(bool)), this, SLOT(slotGoBusy()) );
315 actionMenu->addAction( action );
317 action = new KAction(
318 KIcon(QIcon(GaduProtocol::protocol()->convertStatus( GG_STATUS_INVISIBLE ).iconFor( this ))),
319 i18n( "Set &Invisible" ), this );
320 //, "actionGaduConnect" );
321 QObject::connect( action, SIGNAL(triggered(bool)), this, SLOT(slotGoInvisible()) );
322 actionMenu->addAction( action );
324 action = new KAction(
325 KIcon(QIcon(GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ).iconFor( this ))),
326 i18n( "Go &Offline" ), this );
327 //, "actionGaduConnect" );
328 QObject::connect( action, SIGNAL(triggered(bool)), this, SLOT(slotGoOffline()) );
329 actionMenu->addAction( action );
331 action = new KAction( KIcon("edit-rename"), i18n( "Set &Description..." ), this );
332 //, "actionGaduDescription" );
333 QObject::connect( action, SIGNAL(triggered(bool)), this, SLOT(slotDescription()) );
334 actionMenu->addAction( action );
336 actionMenu->addAction( p->friendsModeAction );
338 actionMenu->addSeparator();
340 actionMenu->addAction( p->searchAction );
342 actionMenu->addSeparator();
344 actionMenu->addAction( p->listputAction );
346 actionMenu->addSeparator();
348 actionMenu->addAction( p->listToFileAction );
349 actionMenu->addAction( p->listFromFileAction );
352 bool
353 GaduAccount::hasCustomStatusMenu() const
355 return true;
358 void
359 GaduAccount::connectWithPassword(const QString& password)
361 if (password.isEmpty()) {
362 return;
364 if (isConnected ())
365 return;
366 // FIXME: add status description to this mechainsm, this is a hack now. libkopete design issue.
367 changeStatus( initialStatus(), p->lastDescription );
370 void
371 GaduAccount::disconnect()
373 disconnect( Manual );
376 void
377 GaduAccount::disconnect( DisconnectReason reason )
379 slotGoOffline();
380 p->connectWithSSL = true;
381 Kopete::Account::disconnected( reason );
384 void
385 GaduAccount::setOnlineStatus( const Kopete::OnlineStatus& status , const Kopete::StatusMessage &reason )
387 kDebug(14100) << "Called";
388 changeStatus( status, reason.message() );
391 void
392 GaduAccount::setStatusMessage( const Kopete::StatusMessage& statusMessage )
394 changeStatus( myself()->onlineStatus(), statusMessage.message() );
397 void
398 GaduAccount::slotUserlistSynch()
400 if ( !p->exportUserlist ) {
401 return;
403 p->exportUserlist = false;
404 kDebug(14100) << "userlist changed, exporting";
405 slotExportContactsList();
408 void
409 GaduAccount::userlistChanged()
411 p->exportUserlist = true;
412 p->exportTimer_->start( USERLISTEXPORT_TIMEOUT );
415 bool
416 GaduAccount::createContact( const QString& contactId, Kopete::MetaContact* parentContact )
418 kDebug(14100) << "createContact " << contactId;
420 uin_t uinNumber = contactId.toUInt();
421 GaduContact* newContact = new GaduContact( uinNumber, parentContact->displayName(),this, parentContact );
422 newContact->setParentIdentity( accountId() );
423 addNotify( uinNumber );
425 userlistChanged();
427 return true;
430 void
431 GaduAccount::changeStatus( const Kopete::OnlineStatus& status, const QString& descr )
433 unsigned int ns;
435 kDebug(14100) << "##### change status #####";
436 kDebug(14100) << "### Status = " << p->session_->isConnected();
437 kDebug(14100) << "### Status description = \"" << descr << "\"";
439 // if change to not available, log off
440 if ( GG_S_NA( status.internalStatus() ) ) {
441 if ( !p->session_->isConnected() ) {
442 return;//already logged off
444 else {
445 if ( status.internalStatus() == GG_STATUS_NOT_AVAIL_DESCR ) {
446 if ( p->session_->changeStatusDescription( status.internalStatus(), descr, p->forFriends ) != 0 ) {
447 return;
451 p->session_->logoff();
452 dccOff();
454 else {
455 // if status is for no desc, but we get some desc, than convert it to status with desc
456 if (!descr.isEmpty() && !GaduProtocol::protocol()->statusWithDescription( status.internalStatus() ) ) {
457 // and rerun us again. This won't cause any recursive call, as both conversions are static
458 ns = GaduProtocol::protocol()->statusToWithDescription( status );
459 changeStatus( GaduProtocol::protocol()->convertStatus( ns ), descr );
460 return;
463 // well, if it's empty but we want to set status with desc, change it too
464 if (descr.isEmpty() && GaduProtocol::protocol()->statusWithDescription( status.internalStatus() ) ) {
465 ns = GaduProtocol::protocol()->statusToWithoutDescription( status );
466 changeStatus( GaduProtocol::protocol()->convertStatus( ns ), descr );
467 return;
470 if ( !p->session_->isConnected() ) {
471 if ( password().cachedValue().isEmpty() ) {
472 // FIXME: when status string added to connect(), use it here
473 p->lastDescription = descr;
474 connect( status/*, descr*/ );
475 return;
478 if ( useTls() != TLS_no ) {
479 p->connectWithSSL = true;
481 else {
482 p->connectWithSSL = false;
484 dccOn();
485 p->serverIP = 0;
486 p->currentServer = -1;
487 p->status = status;
488 kDebug(14100) << "#### Connecting..., tls option "<< (int)useTls() << " ";
489 p->lastDescription = descr;
490 slotLogin( status.internalStatus(), descr );
491 return;
493 else {
494 p->status = status;
495 if ( descr.isEmpty() ) {
496 if ( p->session_->changeStatus( status.internalStatus(), p->forFriends ) != 0 )
497 return;
499 else {
500 if ( p->session_->changeStatusDescription( status.internalStatus(), descr, p->forFriends ) != 0 )
501 return;
506 myself()->setOnlineStatus( status );
507 myself()->setStatusMessage( Kopete::StatusMessage(descr) );
509 if ( status.internalStatus() == GG_STATUS_NOT_AVAIL || status.internalStatus() == GG_STATUS_NOT_AVAIL_DESCR ) {
510 if ( p->pingTimer_ ){
511 p->pingTimer_->stop();
514 p->lastDescription = descr;
517 void
518 GaduAccount::slotLogin( int status, const QString& dscr )
520 p->lastDescription = dscr;
522 myself()->setOnlineStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_CONNECTING ));
523 myself()->setStatusMessage( Kopete::StatusMessage(dscr) );
525 if ( !p->session_->isConnected() ) {
526 if ( password().cachedValue().isEmpty() ) {
527 connectionFailed( GG_FAILURE_PASSWORD );
529 else {
530 p->loginInfo.password = p->textcodec_->fromUnicode(password().cachedValue());
531 p->loginInfo.useTls = p->connectWithSSL;
532 p->loginInfo.status = status;
533 p->loginInfo.statusDescr = dscr;
534 p->loginInfo.forFriends = p->forFriends;
535 p->loginInfo.server = p->serverIP;
536 if ( dccEnabled() ) {
537 p->loginInfo.client_addr = gg_dcc_ip;
538 p->loginInfo.client_port = gg_dcc_port;
540 else {
541 p->loginInfo.client_addr = 0;
542 p->loginInfo.client_port = 0;
544 p->session_->login( &p->loginInfo );
547 else {
548 p->session_->changeStatus( status );
552 void
553 GaduAccount::slotLogoff()
555 if ( p->session_->isConnected() || p->status == GaduProtocol::protocol()->convertStatus( GG_STATUS_CONNECTING )) {
556 p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
557 changeStatus( p->status );
558 p->session_->logoff();
559 dccOff();
563 void
564 GaduAccount::slotGoOnline()
566 changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_AVAIL ) );
568 void
569 GaduAccount::slotGoOffline()
571 slotLogoff();
572 dccOff();
575 void
576 GaduAccount::slotGoInvisible()
578 changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_INVISIBLE ) );
581 void
582 GaduAccount::slotGoBusy()
584 changeStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_BUSY ) );
587 void
588 GaduAccount::removeContact( const GaduContact* c )
590 if ( isConnected() ) {
591 const uin_t u = c->uin();
592 p->session_->removeNotify( u );
593 userlistChanged();
597 void
598 GaduAccount::addNotify( uin_t uin )
600 if ( p->session_->isConnected() ) {
601 p->session_->addNotify( uin );
605 void
606 GaduAccount::notify( uin_t* userlist, int count )
608 if ( p->session_->isConnected() ) {
609 p->session_->notify( userlist, count );
613 void
614 GaduAccount::sendMessage( uin_t recipient, const Kopete::Message& msg, int msgClass )
616 if ( p->session_->isConnected() ) {
617 p->session_->sendMessage( recipient, msg, msgClass );
621 void
622 GaduAccount::error( const QString& title, const QString& message )
624 KMessageBox::error( Kopete::UI::Global::mainWidget(), title, message );
627 void
628 GaduAccount::messageReceived( KGaduMessage* gaduMessage )
630 GaduContact* contact = 0;
631 QList<Kopete::Contact*> contactsListTmp;
633 // FIXME:check for ignored users list
635 if ( gaduMessage->sender_id == 0 ) {
636 //system message, display them or not?
637 kDebug(14100) << "####" << " System Message " << gaduMessage->message;
638 return;
641 contact = static_cast<GaduContact*> ( contacts()[ QString::number( gaduMessage->sender_id ) ] );
643 if ( !contact ) {
644 if ( p->ignoreAnons == true ) {
645 return;
648 Kopete::MetaContact* metaContact = new Kopete::MetaContact ();
649 metaContact->setTemporary ( true );
650 contact = new GaduContact( gaduMessage->sender_id,
651 QString::number( gaduMessage->sender_id ), this, metaContact );
652 Kopete::ContactList::self ()->addMetaContact( metaContact );
653 addNotify( gaduMessage->sender_id );
656 contactsListTmp.append( myself() );
658 Kopete::Message msg( contact, contactsListTmp );
659 msg.setTimestamp( gaduMessage->sendTime );
660 msg.setHtmlBody( gaduMessage->message );
661 msg.setDirection( Kopete::Message::Inbound );
663 contact->messageReceived( msg );
666 void
667 GaduAccount::ackReceived( unsigned int recipient )
669 GaduContact* contact;
671 contact = static_cast<GaduContact*> ( contacts()[ QString::number( recipient ) ] );
672 if ( contact ) {
673 kDebug(14100) << "####" << "Received an ACK from " << contact->uin();
674 contact->messageAck();
676 else {
677 kDebug(14100) << "####" << "Received an ACK from an unknown user : " << recipient;
681 void
682 GaduAccount::contactStatusChanged( KGaduNotify* gaduNotify )
684 kDebug(14100) << "####" << " contact's status changed, uin:" << gaduNotify->contact_id;
686 GaduContact* contact;
688 contact = static_cast<GaduContact*>( contacts()[ QString::number( gaduNotify->contact_id ) ] );
689 if( !contact ) {
690 kDebug(14100) << "Notify not in the list " << gaduNotify->contact_id;
691 return;
694 contact->changedStatus( gaduNotify );
697 void
698 GaduAccount::pong()
700 kDebug(14100) << "####" << " Pong...";
703 void
704 GaduAccount::pingServer()
706 kDebug(14100) << "####" << " Ping...";
707 p->session_->ping();
710 void
711 GaduAccount::connectionFailed( gg_failure_t failure )
713 bool tryReconnect = false;
714 QString pass;
717 switch (failure) {
718 case GG_FAILURE_PASSWORD:
719 password().setWrong();
720 // user pressed CANCEL
721 p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
722 myself()->setOnlineStatus( p->status );
723 disconnected( BadPassword );
724 return;
725 default:
726 if ( p->connectWithSSL ) {
727 if ( useTls() != TLS_only ) {
728 slotCommandDone( QString(), i18n( "connection using SSL was not possible, retrying without." ) );
729 kDebug( 14100 ) << "try without tls now";
730 p->connectWithSSL = false;
731 tryReconnect = true;
732 p->currentServer = -1;
733 p->serverIP = 0;
734 break;
737 else {
738 if ( p->currentServer == NUM_SERVERS - 1 ) {
739 p->serverIP = 0;
740 p->currentServer = -1;
741 kDebug(14100) << "trying : " << "IP from hub ";
743 else {
744 p->serverIP = p->servers[ ++p->currentServer ];
745 kDebug(14100) << "trying : " << p->currentServer << " IP " << p->serverIP;
746 tryReconnect = true;
749 break;
752 if ( tryReconnect ) {
753 slotLogin( p->status.internalStatus() , p->lastDescription );
755 else {
756 error( i18n( "unable to connect to the Gadu-Gadu server(\"%1\").", GaduSession::failureDescription( failure ) ),
757 i18n( "Connection Error" ) );
758 p->status = GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL );
759 myself()->setOnlineStatus( p->status );
760 disconnected( InvalidHost );
764 void
765 GaduAccount::dccOn()
767 if ( dccEnabled() ) {
768 if ( !p->gaduDcc_ ) {
769 p->gaduDcc_ = new GaduDCC( this );
771 kDebug( 14100 ) << " turn DCC on for " << accountId();
772 p->gaduDcc_->registerAccount( this );
773 p->loginInfo.client_port = p->gaduDcc_->listeingPort();
777 void
778 GaduAccount::dccOff()
780 if ( p->gaduDcc_ ) {
781 kDebug( 14100 ) << "destroying dcc in gaduaccount ";
782 delete p->gaduDcc_;
783 p->gaduDcc_ = NULL;
784 p->loginInfo.client_port = 0;
785 p->loginInfo.client_addr = 0;
789 void
790 GaduAccount::slotIncomingDcc( unsigned int uin )
792 GaduContact* contact;
793 GaduDCCTransaction* trans;
795 if ( !uin ) {
796 return;
799 contact = static_cast<GaduContact*>( contacts()[ QString::number( uin ) ] );
801 if ( !contact ) {
802 kDebug(14100) << "attempt to make dcc connection from unknown uin " << uin;
803 return;
806 // if incapabile to transfer files, forget about it.
807 if ( contact->contactPort() < 10 ) {
808 kDebug(14100) << "can't respond to " << uin << " request, his listeing port is too low";
809 return;
812 trans = new GaduDCCTransaction( p->gaduDcc_ );
813 if ( trans->setupIncoming( p->loginInfo.uin, contact ) == false ) {
814 delete trans;
819 void
820 GaduAccount::connectionSucceed( )
822 kDebug(14100) << "#### Gadu-Gadu connected! ";
823 p->status = GaduProtocol::protocol()->convertStatus( p->session_->status() );
824 myself()->setOnlineStatus( p->status );
825 myself()->setStatusMessage( Kopete::StatusMessage(p->lastDescription) );
826 startNotify();
828 p->session_->requestContacts();
829 p->pingTimer_->start( 3*60*1000 );//3 minute timeout
830 pingServer();
832 // check if we need to export userlist every USERLISTEXPORT_TIMEOUT ms
833 p->exportTimer_->start( USERLISTEXPORT_TIMEOUT );
836 void
837 GaduAccount::startNotify()
839 int i = 0;
840 if ( !contacts().count() ) {
841 return;
844 uin_t* userlist = 0;
845 userlist = new uin_t[ contacts().count() ];
847 QHashIterator<QString, Kopete::Contact*> it(contacts());
848 for( i=0 ; it.hasNext() ; ) {
849 it.next();
850 userlist[i++] = static_cast<GaduContact*> (it.value())->uin();
853 p->session_->notify( userlist, contacts().count() );
854 delete [] userlist;
857 void
858 GaduAccount::slotSessionDisconnect( Kopete::Account::DisconnectReason reason )
860 uin_t status;
862 kDebug(14100) << "Disconnecting";
864 if (p->pingTimer_) {
865 p->pingTimer_->stop();
868 setAllContactsStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ) );
870 status = myself()->onlineStatus().internalStatus();
871 if ( status != GG_STATUS_NOT_AVAIL || status != GG_STATUS_NOT_AVAIL_DESCR ) {
872 myself()->setOnlineStatus( GaduProtocol::protocol()->convertStatus( GG_STATUS_NOT_AVAIL ) );
874 GaduAccount::disconnect( reason );
877 void
878 GaduAccount::userlist( const QString& contactsListString )
880 kDebug(14100)<<"### Got userlist - gadu account";
882 GaduContactsList contactsList( contactsListString );
883 QString contactName;
884 QStringList groups;
885 GaduContact* contact;
886 Kopete::MetaContact* metaContact;
887 unsigned int i;
889 // don't export any new changes that were just imported :-)
890 p->exportTimer_->stop();
892 for ( i = 0; i != contactsList.size() ; i++ ) {
893 kDebug(14100) << "uin " << contactsList[i].uin;
895 if ( contactsList[i].uin.isNull() ) {
896 kDebug(14100) << "no Uin, strange.. ";
897 continue;
900 if ( contacts()[ contactsList[i].uin ] ) {
901 kDebug(14100) << "UIN already exists in contacts "<< contactsList[i].uin;
903 else {
904 contactName = GaduContact::findBestContactName( &contactsList[i] );
905 bool s = addContact( contactsList[i].uin, contactName, 0L, Kopete::Account::DontChangeKABC);
906 if ( s == false ) {
907 kDebug(14100) << "There was a problem adding UIN "<< contactsList[i].uin << "to users list";
908 continue;
911 contact = static_cast<GaduContact*>( contacts()[ contactsList[i].uin ] );
912 if ( contact == NULL ) {
913 kDebug(14100) << "oops, no Kopete::Contact in contacts()[] for some reason, for \"" << contactsList[i].uin << "\"";
914 continue;
917 // update/add infor for contact
918 contact->setContactDetails( &contactsList[i] );
920 if ( !( contactsList[i].group.isEmpty() ) ) {
921 // FIXME: libkopete bug i guess, by default contact goes to top level group
922 // if user desrired to see contact somewhere else, remove it from top level one
923 metaContact = contact->metaContact();
924 metaContact->removeFromGroup( Kopete::Group::topLevel() );
925 // put him in all desired groups:
926 groups = contactsList[i].group.split( ",", QString::SkipEmptyParts );
927 for ( QStringList::Iterator groupsIterator = groups.begin(); groupsIterator != groups.end(); ++groupsIterator ) {
928 metaContact->addToGroup( Kopete::ContactList::self ()->findGroup ( *groupsIterator) );
932 // start to check if we need to export userlist
933 p->exportUserlist = false;
934 p->exportTimer_->start( USERLISTEXPORT_TIMEOUT );
937 void
938 GaduAccount::userListExportDone()
940 slotCommandDone( QString(), i18n( "Contacts exported to the server.") );
943 void
944 GaduAccount::slotFriendsMode()
946 p->forFriends = !p->forFriends;
947 kDebug( 14100 ) << "for friends mode: " << p->forFriends << " desc" << p->lastDescription;
948 // now change status, it will changing it with p->forFriends flag
949 changeStatus( p->status, p->lastDescription );
951 saveFriendsMode( p->forFriends );
955 // FIXME: make loading and saving nonblocking (at the moment KFileDialog stops plugin/kopete)
957 void
958 GaduAccount::slotExportContactsListToFile()
960 KTemporaryFile tempFile;
962 if ( p->saveListDialog ) {
963 kDebug( 14100 ) << " save contacts to file: alread waiting for input ";
964 return;
967 p->saveListDialog = new KFileDialog( "::kopete-gadu" + accountId(), QString(),
968 Kopete::UI::Global::mainWidget() );
969 p->saveListDialog->setCaption(
970 i18n("Save Contacts List for Account %1 As",
971 myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString() ) );
973 if ( p->saveListDialog->exec() == QDialog::Accepted ) {
974 QByteArray list = p->textcodec_->fromUnicode( userlist()->asString() );
976 if ( !tempFile.open() ) {
977 // say cheese, can't create file.....
978 error( i18n( "Unable to create temporary file." ), i18n( "Save Contacts List Failed" ) );
980 else {
981 QTextStream tempStream ( &tempFile );
982 tempStream << list.data();
983 tempStream.flush();
985 bool res = KIO::NetAccess::upload(
986 tempFile.fileName() ,
987 p->saveListDialog->selectedUrl() ,
988 Kopete::UI::Global::mainWidget()
990 if ( !res ) {
991 // say it failed
992 error( KIO::NetAccess::lastErrorString(), i18n( "Save Contacts List Failed" ) );
997 delete p->saveListDialog;
998 p->saveListDialog = NULL;
1001 void
1002 GaduAccount::slotImportContactsFromFile()
1004 KUrl url;
1005 QByteArray list;
1006 QString oname;
1008 if ( p->loadListDialog ) {
1009 kDebug( 14100 ) << "load contacts from file: alread waiting for input ";
1010 return;
1013 p->loadListDialog = new KFileDialog( "::kopete-gadu" + accountId(), QString(),
1014 Kopete::UI::Global::mainWidget() );
1015 p->loadListDialog->setCaption(
1016 i18n("Load Contacts List for Account %1 As",
1017 myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString() ) );
1019 if ( p->loadListDialog->exec() == QDialog::Accepted ) {
1020 url = p->loadListDialog->selectedUrl();
1021 kDebug(14100) << "a:" << url << "\nb:" << oname;
1022 if ( KIO::NetAccess::download( url, oname, Kopete::UI::Global::mainWidget() ) ) {
1023 QFile tempFile( oname );
1024 if ( tempFile.open( QIODevice::ReadOnly ) ) {
1025 list = tempFile.readAll();
1026 tempFile.close();
1027 KIO::NetAccess::removeTempFile( oname );
1028 // and store it
1029 kDebug( 14100 ) << "loaded list:";
1030 kDebug( 14100 ) << list;
1031 kDebug( 14100 ) << " --------------- ";
1032 userlist( p->textcodec_->toUnicode( list ) );
1034 else {
1035 error( tempFile.errorString(),
1036 i18n( "Contacts List Load Has Failed" ) );
1039 else {
1040 // say, it failed misourably
1041 error( KIO::NetAccess::lastErrorString(),
1042 i18n( "Contacts List Load Has Failed" ) );
1046 delete p->loadListDialog;
1047 p->loadListDialog = NULL;
1050 unsigned int
1051 GaduAccount::getPersonalInformation()
1053 return p->session_->getPersonalInformation();
1056 bool
1057 GaduAccount::publishPersonalInformation( ResLine& d )
1059 return p->session_->publishPersonalInformation( d );
1062 void
1063 GaduAccount::slotExportContactsList()
1065 p->session_->exportContactsOnServer( userlist() );
1068 GaduContactsList*
1069 GaduAccount::userlist()
1071 GaduContact* contact;
1072 GaduContactsList* contactsList = new GaduContactsList();
1074 if ( !contacts().count() ) {
1075 return contactsList;
1078 QHashIterator<QString, Kopete::Contact*> contactsIterator( contacts() );
1080 for( ; contactsIterator.hasNext() ; ) {
1081 contactsIterator.next();
1082 contact = static_cast<GaduContact*>( contactsIterator.value() );
1083 if ( contact->uin() != static_cast<GaduContact*>( myself() )->uin() ) {
1084 contactsList->addContact( *contact->contactDetails() );
1088 return contactsList;
1091 void
1092 GaduAccount::slotSearch( int uin )
1094 GaduPublicDir* dir = new GaduPublicDir( this, uin );
1095 dir->setObjectName( QLatin1String("GaduPublicDir") );
1098 void
1099 GaduAccount::slotChangePassword()
1103 void
1104 GaduAccount::slotCommandDone( const QString& /*title*/, const QString& what )
1106 //FIXME: any chance to have my own title in event popup ?
1107 KNotification::event( KNotification::Notification, what );
1110 void
1111 GaduAccount::slotCommandError(const QString& title, const QString& what )
1113 error( title, what );
1116 void
1117 GaduAccount::slotDescription()
1119 GaduAway* away = new GaduAway( this );
1121 if( away->exec() == QDialog::Accepted ) {
1122 changeStatus( GaduProtocol::protocol()->convertStatus( away->status() ),
1123 away->awayText() );
1125 delete away;
1128 unsigned int
1129 GaduAccount::pubDirSearch( ResLine& query, int ageFrom, int ageTo, bool onlyAlive )
1131 return p->session_->pubDirSearch( query, ageFrom, ageTo, onlyAlive );
1134 void
1135 GaduAccount::pubDirSearchClose()
1137 p->session_->pubDirSearchClose();
1140 void
1141 GaduAccount::slotSearchResult( const SearchResult& result, unsigned int seq )
1143 emit pubDirSearchResult( result, seq );
1146 void
1147 GaduAccount::sendFile( GaduContact* peer, QString& filePath )
1149 GaduDCCTransaction* gtran = new GaduDCCTransaction( p->gaduDcc_ );
1150 gtran->setupOutgoing( peer, filePath );
1153 void
1154 GaduAccount::dccRequest( GaduContact* peer )
1156 if ( peer && p->session_ ) {
1157 p->session_->dccRequest( peer->uin() );
1161 // dcc settings
1162 bool
1163 GaduAccount::dccEnabled()
1165 QString s = p->config->readEntry( QString::fromAscii( "useDcc" ), QString() );
1166 kDebug( 14100 ) << "dccEnabled: " << s;
1167 if ( s == QString::fromAscii( "enabled" ) ) {
1168 return true;
1170 return false;
1173 bool
1174 GaduAccount::setDcc( bool d )
1176 QString s;
1177 bool f = true;
1179 if ( d == false ) {
1180 dccOff();
1181 s = QString::fromAscii( "disabled" );
1183 else {
1184 s = QString::fromAscii( "enabled" );
1187 p->config->writeEntry( QString::fromAscii( "useDcc" ), s );
1189 if ( p->session_->isConnected() && d ) {
1190 dccOn();
1192 kDebug( 14100 ) << "s: "<<s;
1194 return f;
1197 void
1198 GaduAccount::saveFriendsMode( bool i )
1200 p->config->writeEntry( QString::fromAscii( "forFriends" ),
1201 i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
1204 bool
1205 GaduAccount::loadFriendsMode()
1207 QString s;
1208 bool r;
1209 int n;
1211 s = p->config->readEntry( QString::fromAscii( "forFriends" ), QString() );
1212 n = s.toInt( &r );
1214 if ( n ) {
1215 return true;
1218 return false;
1222 // might be bit inconsistent with what I used in DCC, but hell, it is so much easier to parse :-)
1223 bool
1224 GaduAccount::ignoreAnons()
1226 QString s;
1227 bool r;
1228 int n;
1230 s = p->config->readEntry( QString( "ignoreAnons" ), QString() );
1231 n = s.toInt( &r );
1233 if ( n ) {
1234 return true;
1237 return false;
1241 void
1242 GaduAccount::setIgnoreAnons( bool i )
1244 p->ignoreAnons = i;
1245 p->config->writeEntry( QString::fromAscii( "ignoreAnons" ),
1246 i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
1249 GaduAccount::tlsConnection
1250 GaduAccount::useTls()
1252 QString s;
1253 bool c;
1254 unsigned int oldC;
1255 tlsConnection Tls;
1257 s = p->config->readEntry( QString::fromAscii( "useEncryptedConnection" ), QString() );
1258 oldC = s.toUInt( &c );
1259 // we have old format
1260 if ( c ) {
1261 kDebug( 14100 ) << "old format for param useEncryptedConnection, value " <<
1262 oldC << " will be converted to new string value" << endl;
1263 setUseTls( (tlsConnection) oldC );
1264 // should be string now, unless there was an error reading
1265 s = p->config->readEntry( QString::fromAscii( "useEncryptedConnection" ), QString() );
1266 kDebug( 14100 ) << "new useEncryptedConnection value : " << s;
1269 Tls = TLS_no;
1270 if ( s == "TLS_ifAvaliable" ) {
1271 Tls = TLS_ifAvaliable;
1273 if ( s == "TLS_only" ) {
1274 Tls = TLS_only;
1277 return Tls;
1280 void
1281 GaduAccount::setUseTls( tlsConnection ut )
1283 QString s;
1284 switch( ut ) {
1285 case TLS_ifAvaliable:
1286 s = "TLS_ifAvaliable";
1287 break;
1289 case TLS_only:
1290 s = "TLS_only";
1291 break;
1293 default:
1294 case TLS_no:
1295 s = "TLS_no";
1296 break;
1299 p->config->writeEntry( QString::fromAscii( "useEncryptedConnection" ), s );
1302 #include "gaduaccount.moc"