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.
tdenetwork/kopete/protocols/gadu/gaduaccount.cpp

1262 lines
33 KiB

// -*- 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 <zack@kde.org>
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301, 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"