From bcb704366cb5e333a626c18c308c7e0448a8e69f Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kopete/protocols/gadu/gadusession.cpp | 811 ++++++++++++++++++++++++++++++++++ 1 file changed, 811 insertions(+) create mode 100644 kopete/protocols/gadu/gadusession.cpp (limited to 'kopete/protocols/gadu/gadusession.cpp') diff --git a/kopete/protocols/gadu/gadusession.cpp b/kopete/protocols/gadu/gadusession.cpp new file mode 100644 index 00000000..92f9137d --- /dev/null +++ b/kopete/protocols/gadu/gadusession.cpp @@ -0,0 +1,811 @@ +// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*- +// +// Copyright (C) 2003-2004 Grzegorz Jaskiewicz +// Copyright (C) 2002 Zack Rusin +// +// gadusession.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 "ctime" + +#include "gadusession.h" + +#include +#include +#include "kopetemessage.h" + +#include +#include +#include +#include "gadurichtextformat.h" + +#include +#include +#include + +GaduSession::GaduSession( QObject* parent, const char* name ) +: QObject( parent, name ), session_( 0 ), searchSeqNr_( 0 ) +{ + textcodec = QTextCodec::codecForName( "CP1250" ); + rtf = new GaduRichTextFormat; +} + +GaduSession::~GaduSession() +{ + logoff(); +} + +bool +GaduSession::isConnected() const +{ + if ( session_ ) { + return ( session_->state & GG_STATE_CONNECTED ); + } + return false; +} + +int +GaduSession::status() const +{ + kdDebug(14100)<<"Status = " << session_->status <<", initial = "<< session_->initial_status <status & ( ~GG_STATUS_FRIENDS_MASK ); + } + return GG_STATUS_NOT_AVAIL; +} + +void +GaduSession::login( struct gg_login_params* p ) +{ + if ( !isConnected() ) { + +// turn on in case you have any problems, and you want +// to report it better. libgadu needs to be recompiled with debug enabled +// gg_debug_level=GG_DEBUG_MISC|GG_DEBUG_FUNCTION; + + kdDebug(14100) << "Login" << endl; + + if ( !( session_ = gg_login( p ) ) ) { + destroySession(); + kdDebug( 14100 ) << "libgadu internal error " << endl; + emit connectionFailed( GG_FAILURE_CONNECTING ); + return; + } + + createNotifiers( true ); + enableNotifiers( session_->check ); + searchSeqNr_=0; + } +} + +void +GaduSession::destroyNotifiers() +{ + disableNotifiers(); + if ( read_ ) { + delete read_; + read_ = NULL; + } + if ( write_ ) { + delete write_; + write_ = NULL; + } +} + +void +GaduSession::createNotifiers( bool connect ) +{ + if ( !session_ ){ + return; + } + + read_ = new QSocketNotifier( session_->fd, QSocketNotifier::Read, this ); + read_->setEnabled( false ); + + write_ = new QSocketNotifier( session_->fd, QSocketNotifier::Write, this ); + write_->setEnabled( false ); + + if ( connect ) { + QObject::connect( read_, SIGNAL( activated( int ) ), SLOT( checkDescriptor() ) ); + QObject::connect( write_, SIGNAL( activated( int ) ), SLOT( checkDescriptor() ) ); + } +} + +void +GaduSession::enableNotifiers( int checkWhat ) +{ + if( (checkWhat & GG_CHECK_READ) && read_ ) { + read_->setEnabled( true ); + } + if( (checkWhat & GG_CHECK_WRITE) && write_ ) { + write_->setEnabled( true ); + } +} + +void +GaduSession::disableNotifiers() +{ + if ( read_ ) { + read_->setEnabled( false ); + } + if ( write_ ) { + write_->setEnabled( false ); + } +} + +void +GaduSession::dccRequest( const unsigned int uin ) +{ + if ( session_ ) { + gg_dcc_request( session_, uin ); + } +} + +void +GaduSession::login( KGaduLoginParams* loginp ) +{ + QCString desc = textcodec->fromUnicode( loginp->statusDescr ); + + memset( ¶ms_, 0, sizeof(params_) ); + + params_.status_descr = (char*)desc.data(); + + params_.uin = loginp->uin; + params_.password = (char *)( loginp->password.ascii() ); + params_.status = loginp->status | ( loginp->forFriends ? GG_STATUS_FRIENDS_MASK : 0 ); + params_.async = 1; + params_.tls = loginp->useTls; + params_ .server_addr = loginp->server; + params_.client_addr = loginp->client_addr; + params_.client_port = loginp->client_port; + + kdDebug(14100) << "LOGIN IP: " << loginp->client_addr << endl; + + if ( loginp->useTls ) { + params_.server_port = GG_HTTPS_PORT; + } + else { + if ( loginp->server ) { + params_.server_port = GG_DEFAULT_PORT; + } + } + + kdDebug(14100)<<"gadusession::login, server ( " << loginp->server << " ), tls(" << loginp->useTls << ") " <convertToGaduMessage( msg ); + if ( gadumessage ) { + const void* data = (const void*)gadumessage->rtf.data(); + cpMsg = textcodec->fromUnicode( gadumessage->message ); + int o; + o = gg_send_message_richtext( session_, msgClass, recipient, (const unsigned char *)cpMsg.data(), (const unsigned char*) data, gadumessage->rtf.size() ); + gadumessage->rtf.resize(0); + delete gadumessage; + return o; + } + else { + sendMsg = msg.plainBody(); + sendMsg.replace( QString::fromAscii( "\n" ), QString::fromAscii( "\r\n" ) ); + cpMsg = textcodec->fromUnicode( sendMsg ); + + return gg_send_message( session_, msgClass, recipient, (const unsigned char *)cpMsg.data() ); + } + } + else { + emit error( i18n("Not Connected"), i18n("You are not connected to the server.") ); + } + + return 1; +} + +int +GaduSession::changeStatus( int status, bool forFriends ) +{ + kdDebug(14101)<<"## Changing to "<fromUnicode(descr); + + if ( isConnected() ) { + return gg_change_status_descr( session_, + status | ( forFriends ? GG_STATUS_FRIENDS_MASK : 0), ndescr.data() ); + } + else { + emit error( i18n("Not Connected"), i18n("You have to be connected to the server to change your status.") ); + } + + return 1; +} + +int +GaduSession::ping() +{ + if ( isConnected() ) { + return gg_ping( session_ ); + } + + return 1; +} + +void +GaduSession::pubDirSearchClose() +{ + searchSeqNr_=0; +} + +unsigned int +GaduSession::getPersonalInformation() +{ + gg_pubdir50_t searchRequest; + unsigned int seqNr; + + if ( isConnected() == false ) { + return 0; + } + + searchRequest = gg_pubdir50_new( GG_PUBDIR50_READ ); + if ( !searchRequest ) { + return 0; + } + + seqNr = gg_pubdir50( session_, searchRequest ); + gg_pubdir50_free( searchRequest ); + + return seqNr; +} + +bool +GaduSession::publishPersonalInformation( ResLine& d ) +{ + gg_pubdir50_t r; + + if ( !session_ ) { + return 0; + } + + r = gg_pubdir50_new( GG_PUBDIR50_WRITE ); + + if ( d.firstname.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_FIRSTNAME, + (const char *)((const char*)textcodec->fromUnicode( d.firstname ) ) ); + if ( d.surname.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_LASTNAME, + (const char *)((const char*)textcodec->fromUnicode( d.surname ) ) ); + if ( d.nickname.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_NICKNAME, + (const char *)((const char*)textcodec->fromUnicode( d.nickname ) ) ); + if ( d.age.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_BIRTHYEAR, + (const char *)((const char*)textcodec->fromUnicode( d.age ) ) ); + if ( d.city.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_CITY, + (const char *)((const char*)textcodec->fromUnicode( d.city ) ) ); + if ( d.meiden.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_FAMILYNAME, + (const char *)((const char*)textcodec->fromUnicode( d.meiden ) ) ); + if ( d.orgin.length() ) + gg_pubdir50_add( r, GG_PUBDIR50_FAMILYCITY, + (const char *)((const char*)textcodec->fromUnicode( d.orgin ) ) ); + if ( d.gender.length() == 1 ) + gg_pubdir50_add( r, GG_PUBDIR50_GENDER, + (const char *)((const char*)textcodec->fromUnicode( d.gender ) ) ); + + gg_pubdir50( session_, r ); + + gg_pubdir50_free( r ); + + return true; +} + +unsigned int +GaduSession::pubDirSearch( ResLine& query, int ageFrom, int ageTo, bool onlyAlive ) +{ + QString bufYear; + unsigned int reqNr; + gg_pubdir50_t searchRequest; + + if ( !session_ ) { + return 0; + } + + searchRequest = gg_pubdir50_new( GG_PUBDIR50_SEARCH_REQUEST ); + if ( !searchRequest ) { + return 0; + } + + if ( query.uin == 0 ) { + if (query.firstname.length()) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_FIRSTNAME, + (const char*)textcodec->fromUnicode( query.firstname ) ); + } + if ( query.surname.length() ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_LASTNAME, + (const char*)textcodec->fromUnicode( query.surname ) ); + } + if ( query.nickname.length() ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_NICKNAME, + (const char*)textcodec->fromUnicode( query.nickname ) ); + } + if ( query.city.length() ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_CITY, + (const char*)textcodec->fromUnicode( query.city ) ); + } + if ( ageFrom || ageTo ) { + QString yearFrom = QString::number( QDate::currentDate().year() - ageFrom ); + QString yearTo = QString::number( QDate::currentDate().year() - ageTo ); + + if ( ageFrom && ageTo ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_BIRTHYEAR, + (const char*)textcodec->fromUnicode( yearFrom + " " + yearTo ) ); + } + if ( ageFrom ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_BIRTHYEAR, + (const char*)textcodec->fromUnicode( yearFrom ) ); + } + else { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_BIRTHYEAR, + (const char*)textcodec->fromUnicode( yearTo ) ); + } + } + + if ( query.gender.length() == 1 ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_GENDER, + (const char *)((const char*)textcodec->fromUnicode( query.gender ) ) ); + } + + if ( onlyAlive ) { + gg_pubdir50_add( searchRequest, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE ); + } + } + // otherwise we are looking only for one fellow with this nice UIN + else{ + gg_pubdir50_add( searchRequest, GG_PUBDIR50_UIN, QString::number( query.uin ).ascii() ); + } + + gg_pubdir50_add( searchRequest, GG_PUBDIR50_START, QString::number( searchSeqNr_ ).ascii() ); + reqNr = gg_pubdir50( session_, searchRequest ); + gg_pubdir50_free( searchRequest ); + + return reqNr; +} + +void +GaduSession::sendResult( gg_pubdir50_t result ) +{ + int i, count, age; + ResLine resultLine; + SearchResult sres; + + count = gg_pubdir50_count( result ); + + if ( !count ) { + kdDebug(14100) << "there was nothing found in public directory for requested details" << endl; + } + + for ( i = 0; i < count; i++ ) { + resultLine.uin = QString( gg_pubdir50_get( result, i, GG_PUBDIR50_UIN ) ).toInt(); + resultLine.firstname = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_FIRSTNAME ) ); + resultLine.surname = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_LASTNAME ) ); + resultLine.nickname = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_NICKNAME ) ); + resultLine.age = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_BIRTHYEAR ) ); + resultLine.city = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_CITY ) ); + QString stat = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_STATUS ) ); + resultLine.orgin = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_FAMILYCITY ) ); + resultLine.meiden = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_FAMILYNAME ) ); + resultLine.gender = textcodec->toUnicode( gg_pubdir50_get( result, i, GG_PUBDIR50_GENDER ) ); + + resultLine.status = stat.toInt(); + age = resultLine.age.toInt(); + if ( age ) { + resultLine.age = QString::number( QDate::currentDate().year() - age ); + } + else { + resultLine.age.truncate( 0 ); + } + sres.append( resultLine ); + kdDebug(14100) << "found line "<< resultLine.uin << " " << resultLine.firstname << endl; + } + + searchSeqNr_ = gg_pubdir50_next( result ); + emit pubDirSearchResult( sres, gg_pubdir50_seq( result ) ); +} + +void +GaduSession::requestContacts() +{ + if ( !session_ || session_->state != GG_STATE_CONNECTED ) { + kdDebug(14100) <<" you need to be connected to send " << endl; + return; + } + + if ( gg_userlist_request( session_, GG_USERLIST_GET, NULL ) == -1 ) { + kdDebug(14100) <<" userlist export ERROR " << endl; + return; + } + kdDebug( 14100 ) << "Contacts list import..started " << endl; +} + + +void +GaduSession::exportContactsOnServer( GaduContactsList* contactsList ) +{ + QCString plist; + + if ( !session_ || session_->state != GG_STATE_CONNECTED ) { + kdDebug( 14100 ) << "you need to connect to export Contacts list " << endl; + return; + } + + plist = textcodec->fromUnicode( contactsList->asString() ); + kdDebug(14100) <<"--------------------userlists\n" << plist << endl; + kdDebug(14100) << "----------------------------" << endl; + + if ( gg_userlist_request( session_, GG_USERLIST_PUT, plist.data() ) == -1 ) { + kdDebug( 14100 ) << "export contact list failed " << endl; + return; + } + kdDebug( 14100 ) << "Contacts list export..started " << endl; +} + + +void +GaduSession::handleUserlist( gg_event* event ) +{ + QString ul; + switch( event->event.userlist.type ) { + case GG_USERLIST_GET_REPLY: + if ( event->event.userlist.reply ) { + ul = event->event.userlist.reply; + kdDebug( 14100 ) << "Got Contacts list OK " << endl; + } + else { + kdDebug( 14100 ) << "Got Contacts list FAILED/EMPTY " << endl; + // FIXME: send failed? + } + emit userListRecieved( ul ); + break; + + case GG_USERLIST_PUT_REPLY: + kdDebug( 14100 ) << "Contacts list exported OK " << endl; + emit userListExported(); + break; + + } +} + +QString +GaduSession::stateDescription( int state ) +{ + switch( state ) { + case GG_STATE_IDLE: + return i18n( "idle" ); + case GG_STATE_RESOLVING: + return i18n( "resolving host" ); + case GG_STATE_CONNECTING: + return i18n( "connecting" ); + case GG_STATE_READING_DATA: + return i18n( "reading data" ); + case GG_STATE_ERROR: + return i18n( "error" ); + case GG_STATE_CONNECTING_HUB: + return i18n( "connecting to hub" ); + case GG_STATE_CONNECTING_GG: + return i18n( "connecting to server" ); + case GG_STATE_READING_KEY: + return i18n( "retrieving key" ); + case GG_STATE_READING_REPLY: + return i18n( "waiting for reply" ); + case GG_STATE_CONNECTED: + return i18n( "connected" ); + case GG_STATE_SENDING_QUERY: + return i18n( "sending query" ); + case GG_STATE_READING_HEADER: + return i18n( "reading header" ); + case GG_STATE_PARSING: + return i18n( "parse data" ); + case GG_STATE_DONE: + return i18n( "done" ); + case GG_STATE_TLS_NEGOTIATION: + return i18n( "Tls connection negotiation" ); + default: + return i18n( "unknown" ); + } +} +QString +GaduSession::errorDescription( int err ) +{ + switch( err ){ + case GG_ERROR_RESOLVING: + return i18n( "Resolving error." ); + case GG_ERROR_CONNECTING: + return i18n( "Connecting error." ); + case GG_ERROR_READING: + return i18n( "Reading error." ); + case GG_ERROR_WRITING: + return i18n( "Writing error." ); + default: + return i18n( "Unknown error number %1." ).arg( QString::number( (unsigned int)err ) ); + } +} + +QString +GaduSession::failureDescription( gg_failure_t f ) +{ + switch( f ) { + case GG_FAILURE_RESOLVING: + return i18n( "Unable to resolve server address. DNS failure." ); + case GG_FAILURE_CONNECTING: + return i18n( "Unable to connect to server." ); + case GG_FAILURE_INVALID: + return i18n( "Server send incorrect data. Protocol error." ); + case GG_FAILURE_READING: + return i18n( "Problem reading data from server." ); + case GG_FAILURE_WRITING: + return i18n( "Problem sending data to server." ); + case GG_FAILURE_PASSWORD: + return i18n( "Incorrect password." ); + case GG_FAILURE_404: + return QString::fromAscii( "404." ); + case GG_FAILURE_TLS: + return i18n( "Unable to connect over encrypted channel.\nTry to turn off encryption support in Gadu account settings and reconnect." ); + default: + return i18n( "Unknown error number %1." ).arg( QString::number( (unsigned int)f ) ); + } +} + +void +GaduSession::notify60( gg_event* event ) +{ + KGaduNotify* gn = NULL; + unsigned int n; + + if ( event->event.notify60[0].uin ) { + gn = new KGaduNotify; + } + else { + return; + } + + for( n=0 ; event->event.notify60[n].uin ; n++ ) { + gn->contact_id = event->event.notify60[n].uin; + gn->status = event->event.notify60[n].status; + gn->remote_ip.setAddress( ntohl( event->event.notify60[n].remote_ip ) ); + gn->remote_port = event->event.notify60[n].remote_port; + if ( event->event.notify60[n].remote_ip && gn->remote_port > 10 ) { + gn->fileCap = true; + } + else { + gn->fileCap = false; + } + gn->version = event->event.notify60[n].version; + gn->image_size = event->event.notify60[n].image_size; + gn->description = textcodec->toUnicode( event->event.notify60[n].descr ); + emit contactStatusChanged( gn ); + } + delete gn; +} + +void +GaduSession::checkDescriptor() +{ + disableNotifiers(); + + struct gg_event* event; +// struct gg_dcc* dccSock; + KGaduMessage gaduMessage; + KGaduNotify gaduNotify; + + if ( !( event = gg_watch_fd( session_ ) ) ) { + kdDebug(14100)<<"Connection was broken for some reason"<state == GG_STATE_CONNECTING_HUB || session_->state == GG_STATE_CONNECTING_GG ) { + kdDebug(14100)<<"recreating notifiers"<type ) { + case GG_EVENT_MSG: + kdDebug(14100) << "incoming message:class:" << event->event.msg.msgclass << endl; + if ( event->event.msg.msgclass & GG_CLASS_CTCP ) { + kdDebug( 14100 ) << "incomming ctcp " << endl; + // TODO: DCC CONNECTION + emit incomingCtcp( event->event.msg.sender ); + } + + if ( (event->event.msg.msgclass & GG_CLASS_MSG) || (event->event.msg.msgclass & GG_CLASS_CHAT) ) { + gaduMessage.message = + textcodec->toUnicode((const char*)event->event.msg.message); + gaduMessage.sender_id = event->event.msg.sender; + gaduMessage.sendTime.setTime_t( event->event.msg.time, Qt::LocalTime ); + gaduMessage.message = rtf->convertToHtml( gaduMessage.message, event->event.msg.formats_length, event->event.msg.formats ); + emit messageReceived( &gaduMessage ); + } + break; + case GG_EVENT_ACK: + emit ackReceived( event->event.ack.recipient ); + break; + case GG_EVENT_STATUS: + gaduNotify.status = event->event.status.status; + gaduNotify.contact_id = event->event.status.uin; + if ( event->event.status.descr ) { + gaduNotify.description = textcodec->toUnicode( event->event.status.descr ); + } + else { + gaduNotify.description = QString::null; + } + gaduNotify.remote_port = 0; + gaduNotify.version = 0; + gaduNotify.image_size = 0; + gaduNotify.time = 0; + gaduNotify.fileCap = false; + + emit contactStatusChanged( &gaduNotify ); + break; + case GG_EVENT_STATUS60: + gaduNotify.status = event->event.status60.status; + gaduNotify.contact_id = event->event.status60.uin; + if ( event->event.status60.descr ) { + gaduNotify.description = textcodec->toUnicode( event->event.status60.descr ); + } + else { + gaduNotify.description = QString::null; + } + gaduNotify.remote_ip.setAddress( ntohl( event->event.status60.remote_ip ) ); + gaduNotify.remote_port = event->event.status60.remote_port; + gaduNotify.version = event->event.status60.version; + gaduNotify.image_size = event->event.status60.image_size; + gaduNotify.time = event->event.status60.time; + if ( event->event.status60.remote_ip && gaduNotify.remote_port > 10 ) { + gaduNotify.fileCap = true; + } + else { + gaduNotify.fileCap = false; + } + + emit contactStatusChanged( &gaduNotify ); + break; + case GG_EVENT_NOTIFY60: + notify60( event ); + break; + case GG_EVENT_CONN_SUCCESS: + kdDebug(14100) << "success server: " << session_->server_addr << endl; + emit connectionSucceed(); + break; + case GG_EVENT_CONN_FAILED: + kdDebug(14100) << "failed server: " << session_->server_addr << endl; + destroySession(); + kdDebug(14100) << "emit connection failed(" << event->event.failure << ") signal" << endl; + emit connectionFailed( (gg_failure_t)event->event.failure ); + break; + case GG_EVENT_DISCONNECT: + kdDebug(14100)<<"event Disconnected"<event.pubdir50 ); + break; + case GG_EVENT_USERLIST: + handleUserlist( event ); + break; + default: + kdDebug(14100)<<"Unprocessed GaduGadu Event = "<type<check ); + } +} + +#include "gadusession.moc" -- cgit v1.2.1