1 /*
2 aimaccount.cpp - Oscar Protocol Plugin, AIM part
3
4 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
5
6 *************************************************************************
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 *************************************************************************
14 */
15
16 #include "aimaccount.h"
17
18 #include <QPointer>
19
20 #include <kdebug.h>
21 #include <kconfig.h>
22 #include <kdialog.h>
23 #include <KLocalizedString>
24
25 #include <kactionmenu.h>
26 #include <kmessagebox.h>
27 #include <ktoggleaction.h>
28 #include <kicon.h>
29
30 #include "kopetepassword.h"
31 #include "kopetestdaction.h"
32 #include "kopeteuiglobal.h"
33 #include "kopetecontactlist.h"
34 #include "kopetemetacontact.h"
35 #include "kopeteprotocol.h"
36 #include "kopetechatsessionmanager.h"
37 #include "kopeteview.h"
38
39 #include "aimprotocol.h"
40 #include "aimchatsession.h"
41 #include "aimcontact.h"
42 #include "icqcontact.h"
43 #include "aimuserinfo.h"
44 #include "aimjoinchat.h"
45 #include "oscarmyselfcontact.h"
46
47 #include "oscarutils.h"
48 #include "client.h"
49 #include "contactmanager.h"
50 #include "oscarsettings.h"
51 #include "oscarstatusmanager.h"
52
53 const Oscar::DWORD AIM_ONLINE = 0x0;
54 const Oscar::DWORD AIM_AWAY = 0x1;
55
56 namespace Kopete { class MetaContact; }
57
AIMMyselfContact(AIMAccount * acct)58 AIMMyselfContact::AIMMyselfContact( AIMAccount *acct )
59 : OscarMyselfContact( acct )
60 {
61 m_acct = acct;
62 }
63
userInfoUpdated()64 void AIMMyselfContact::userInfoUpdated()
65 {
66 Oscar::DWORD extendedStatus = details().extendedStatus();
67 kDebug( OSCAR_AIM_DEBUG ) << "extendedStatus is " << QString::number( extendedStatus, 16 );
68
69 AIMProtocol* p = static_cast<AIMProtocol *>(protocol());
70 Oscar::Presence presence = p->statusManager()->presenceOf( extendedStatus, details().userClass() );
71
72 setOnlineStatus( p->statusManager()->onlineStatusOf( presence ) );
73 setStatusMessage( static_cast<AIMAccount*>( account() )->engine()->statusMessage() );
74 }
75
setOwnProfile(const QString & newProfile)76 void AIMMyselfContact::setOwnProfile( const QString& newProfile )
77 {
78 m_profileString = newProfile;
79 if ( m_acct->isConnected() )
80 m_acct->engine()->updateProfile( newProfile );
81 }
82
userProfile()83 QString AIMMyselfContact::userProfile()
84 {
85 return m_profileString;
86 }
87
manager(Kopete::Contact::CanCreateFlags canCreate)88 Kopete::ChatSession* AIMMyselfContact::manager( Kopete::Contact::CanCreateFlags canCreate )
89 {
90 return manager( canCreate, 0, QString() );
91 }
92
manager(Kopete::Contact::CanCreateFlags canCreate,Oscar::WORD exchange,const QString & room)93 Kopete::ChatSession* AIMMyselfContact::manager( Kopete::Contact::CanCreateFlags canCreate,
94 Oscar::WORD exchange, const QString& room )
95 {
96 kDebug(OSCAR_AIM_DEBUG) ;
97 Kopete::ContactPtrList chatMembers;
98 chatMembers.append( this );
99 Kopete::ChatSession* genericManager = nullptr;
100 genericManager = Kopete::ChatSessionManager::self()->findChatSession( account()->myself(), chatMembers, protocol() );
101 AIMChatSession* session = dynamic_cast<AIMChatSession*>( genericManager );
102
103 if ( !session && canCreate == Contact::CanCreate )
104 {
105 session = new AIMChatSession( this, chatMembers, account()->protocol(), exchange, room );
106 session->setEngine( m_acct->engine() );
107
108 connect(session, &AIMChatSession::messageSent, this, &AIMMyselfContact::sendMessage);
109 m_chatRoomSessions.append( session );
110 }
111 return session;
112 }
113
chatSessionDestroyed(Kopete::ChatSession * session)114 void AIMMyselfContact::chatSessionDestroyed( Kopete::ChatSession* session )
115 {
116 m_chatRoomSessions.removeAll( session );
117 }
118
sendMessage(Kopete::Message & message,Kopete::ChatSession * session)119 void AIMMyselfContact::sendMessage( Kopete::Message& message, Kopete::ChatSession* session )
120 {
121 kDebug(OSCAR_AIM_DEBUG) << "sending a message";
122 //TODO: remove duplication - factor into a message utils class or something
123 Oscar::Message msg;
124 QString s;
125
126 if (message.plainBody().isEmpty()) // no text, do nothing
127 return;
128 //okay, now we need to change the message.escapedBody from real HTML to aimhtml.
129 //looking right now for docs on that "format".
130 //looks like everything except for alignment codes comes in the format of spans
131
132 //font-style:italic -> <i>
133 //font-weight:600 -> <b> (anything > 400 should be <b>, 400 is not bold)
134 //text-decoration:underline -> <u>
135 //font-family: -> <font face="">
136 //font-size:xxpt -> <font ptsize=xx>
137
138 s=message.escapedBody();
139 s.replace ( QRegExp( QString::fromLatin1("<span style=\"([^\"]*)\">([^<]*)</span>")),
140 QString::fromLatin1("<style>\\1;\"\\2</style>"));
141
142 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-style:italic;([^\"]*)\"([^<]*)</style>")),
143 QString::fromLatin1("<i><style>\\1\\2\"\\3</style></i>"));
144
145 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-weight:600;([^\"]*)\"([^<]*)</style>")),
146 QString::fromLatin1("<b><style>\\1\\2\"\\3</style></b>"));
147
148 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)text-decoration:underline;([^\"]*)\"([^<]*)</style>")),
149 QString::fromLatin1("<u><style>\\1\\2\"\\3</style></u>"));
150
151 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-family:([^;]*);([^\"]*)\"([^<]*)</style>")),
152 QString::fromLatin1("<font face=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
153
154 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-size:([^p]*)pt;([^\"]*)\"([^<]*)</style>")),
155 QString::fromLatin1("<font ptsize=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
156
157 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)background-color:([^;]*);([^\"]*)\"([^<]*)</style>")),
158 QString::fromLatin1("<font back=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
159
160 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)color:([^;]*);([^\"]*)\"([^<]*)</style>")),
161 QString::fromLatin1("<font color=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
162
163 s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)\"([^<]*)</style>")),
164 QString::fromLatin1("\\2"));
165
166 //okay now change the <font ptsize="xx"> to <font size="xx">
167
168 //0-9 are size 1
169 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"\\d\">")),
170 QString::fromLatin1("<font size=\"1\">"));
171 //10-11 are size 2
172 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[01]\">")),
173 QString::fromLatin1("<font size=\"2\">"));
174 //12-13 are size 3
175 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[23]\">")),
176 QString::fromLatin1("<font size=\"3\">"));
177 //14-16 are size 4
178 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[456]\">")),
179 QString::fromLatin1("<font size=\"4\">"));
180 //17-22 are size 5
181 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"(?:1[789]|2[012])\">")),
182 QString::fromLatin1("<font size=\"5\">"));
183 //23-29 are size 6
184 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"2[3456789]\">")),QString::fromLatin1("<font size=\"6\">"));
185 //30- (and any I missed) are size 7
186 s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"[^\"]*\">")),QString::fromLatin1("<font size=\"7\">"));
187
188 s.replace ( QRegExp ( QString::fromLatin1("<br[ /]*>")), QString::fromLatin1("<br>") );
189
190 kDebug(14190) << "sending "
191 << s << endl;
192
193 msg.setSender( contactId() );
194 msg.setText( Oscar::Message::UserDefined, s, m_acct->defaultCodec() );
195 msg.setTimestamp(message.timestamp());
196 msg.setChannel(0x03);
197 msg.addProperty( Oscar::Message::ChatRoom );
198
199 AIMChatSession* aimSession = dynamic_cast<AIMChatSession*>( session );
200 if ( !aimSession )
201 {
202 kWarning(OSCAR_AIM_DEBUG) << "couldn't convert to AIM chat room session!";
203 session->messageSucceeded();
204 return;
205 }
206 msg.setExchange( aimSession->exchange() );
207 msg.setChatRoom( aimSession->roomName() );
208
209 m_acct->engine()->sendMessage( msg );
210 //session->appendMessage( message );
211 session->messageSucceeded();
212 }
213
AIMAccount(Kopete::Protocol * parent,QString accountID)214 AIMAccount::AIMAccount(Kopete::Protocol *parent, QString accountID)
215 : OscarAccount(parent, accountID, false)
216 {
217 kDebug(14152) << accountID << ": Called.";
218 AIMMyselfContact* mc = new AIMMyselfContact( this );
219 setMyself( mc );
220 mc->setOnlineStatus( protocol()->statusManager()->onlineStatusOf( Oscar::Presence( Oscar::Presence::Offline ) ) );
221
222 QString profile = configGroup()->readEntry( "Profile",
223 i18n( "Visit the Kopete website at <a href=\"http://kopete.kde.org\">http://kopete.kde.org</a>") );
224 mc->setOwnProfile( profile );
225 mInitialStatusMessage.clear();
226
227 m_joinChatDialog = 0;
228 QObject::connect( engine(), SIGNAL(chatRoomConnected(Oscar::WORD,QString)),
229 this, SLOT(connectedToChatRoom(Oscar::WORD,QString)) );
230
231 QObject::connect( engine(), SIGNAL(userJoinedChat(Oscar::WORD,QString,QString)),
232 this, SLOT(userJoinedChat(Oscar::WORD,QString,QString)) );
233
234 QObject::connect( engine(), SIGNAL(userLeftChat(Oscar::WORD,QString,QString)),
235 this, SLOT(userLeftChat(Oscar::WORD,QString,QString)) );
236
237 // Create actions
238 mJoinChatAction = new QAction( i18n( "Join Chat..." ), this );
239 QObject::connect(mJoinChatAction, &QAction::triggered, this, &AIMAccount::slotJoinChat);
240
241 mEditInfoAction = new QAction( QIcon::fromTheme("user-properties"), i18n( "Edit User Info..." ), this );
242 QObject::connect(mEditInfoAction, &QAction::triggered, this, &AIMAccount::slotEditInfo);
243
244 mActionInvisible = new KToggleAction( i18n( "In&visible" ), this );
245 QObject::connect(mActionInvisible, &KToggleAction::triggered, this, &AIMAccount::slotToggleInvisible);
246 }
247
~AIMAccount()248 AIMAccount::~AIMAccount()
249 {
250 }
251
protocol() const252 AIMProtocol* AIMAccount::protocol() const
253 {
254 return static_cast<AIMProtocol*>(OscarAccount::protocol());
255 }
256
presence()257 Oscar::Presence AIMAccount::presence()
258 {
259 return protocol()->statusManager()->presenceOf( myself()->onlineStatus() );
260 }
261
createNewContact(const QString & contactId,Kopete::MetaContact * parentContact,const OContact & ssiItem)262 OscarContact *AIMAccount::createNewContact( const QString &contactId, Kopete::MetaContact *parentContact, const OContact& ssiItem )
263 {
264 if ( QRegExp("[\\d]+").exactMatch( contactId ) )
265 {
266 ICQContact* contact = new ICQContact( this, contactId, parentContact, QString() );
267 contact->setSSIItem( ssiItem );
268
269 if ( engine()->isActive() )
270 contact->loggedIn();
271
272 return contact;
273 }
274 else
275 {
276 AIMContact* contact = new AIMContact( this, contactId, parentContact, QString() );
277 contact->setSSIItem( ssiItem );
278
279 return contact;
280 }
281 }
282
fillActionMenu(KActionMenu * actionMenu)283 void AIMAccount::fillActionMenu( KActionMenu *actionMenu )
284 {
285 Kopete::Account::fillActionMenu( actionMenu );
286
287 actionMenu->addSeparator();
288
289 mJoinChatAction->setEnabled( isConnected() );
290 actionMenu->addAction( mJoinChatAction );
291
292 mEditInfoAction->setEnabled( isConnected() );
293 actionMenu->addAction( mEditInfoAction );
294
295 Oscar::Presence pres( presence().type(), presence().flags() | Oscar::Presence::Invisible );
296 mActionInvisible->setIcon( QIcon( protocol()->statusManager()->onlineStatusOf( pres ).iconFor( this ) ) );
297 mActionInvisible->setChecked( (presence().flags() & Oscar::Presence::Invisible) == Oscar::Presence::Invisible );
298 actionMenu->addAction( mActionInvisible );
299 }
300
setPresenceFlags(Oscar::Presence::Flags flags,const QString & message)301 void AIMAccount::setPresenceFlags( Oscar::Presence::Flags flags, const QString &message )
302 {
303 Oscar::Presence pres = presence();
304 kDebug(OSCAR_AIM_DEBUG) << "new flags=" << (int)flags << ", old type="
305 << (int)pres.flags() << ", new message=" << message << endl;
306 setPresenceTarget( Oscar::Presence( pres.type(), flags ), message );
307 }
308
setPresenceType(Oscar::Presence::Type type,const QString & message)309 void AIMAccount::setPresenceType( Oscar::Presence::Type type, const QString &message )
310 {
311 Oscar::Presence pres = presence();
312 kDebug(OSCAR_AIM_DEBUG) << "new type=" << (int)type << ", old type="
313 << (int)pres.type() << ", new message=" << message << endl;
314 setPresenceTarget( Oscar::Presence( type, pres.flags() ), message );
315 }
316
setPresenceTarget(const Oscar::Presence & newPres,const QString & message)317 void AIMAccount::setPresenceTarget( const Oscar::Presence &newPres, const QString &message )
318 {
319 bool targetIsOffline = (newPres.type() == Oscar::Presence::Offline);
320 bool accountIsOffline = ( presence().type() == Oscar::Presence::Offline ||
321 myself()->onlineStatus() == protocol()->statusManager()->connectingStatus() );
322
323 if ( targetIsOffline )
324 {
325 OscarAccount::disconnect();
326 // allow toggling invisibility when offline
327 myself()->setOnlineStatus( protocol()->statusManager()->onlineStatusOf( newPres ) );
328 }
329 else if ( accountIsOffline )
330 {
331 mInitialStatusMessage = message;
332 OscarAccount::connect( protocol()->statusManager()->onlineStatusOf( newPres ) );
333 }
334 else
335 {
336 engine()->setStatus( protocol()->statusManager()->oscarStatusOf( newPres ), message );
337 }
338 }
339
setOnlineStatus(const Kopete::OnlineStatus & status,const Kopete::StatusMessage & reason,const OnlineStatusOptions & options)340 void AIMAccount::setOnlineStatus( const Kopete::OnlineStatus& status, const Kopete::StatusMessage &reason, const OnlineStatusOptions& options )
341 {
342 if ( status.status() == Kopete::OnlineStatus::Invisible )
343 {
344 // called from outside, i.e. not by our custom action menu entry...
345
346 if ( presence().type() == Oscar::Presence::Offline )
347 {
348 // ...when we are offline go online invisible.
349 setPresenceTarget( Oscar::Presence( Oscar::Presence::Online, Oscar::Presence::Invisible ) );
350 }
351 else
352 {
353 // ...when we are not offline set invisible.
354 setPresenceFlags( Oscar::Presence::Invisible );
355 }
356 }
357 else
358 {
359 Oscar::Presence pres = protocol()->statusManager()->presenceOf( status );
360 if ( options & Kopete::Account::KeepSpecialFlags )
361 pres.setFlags( presence().flags() );
362
363 setPresenceTarget( pres, reason.message() );
364 }
365 }
366
setStatusMessage(const Kopete::StatusMessage & statusMessage)367 void AIMAccount::setStatusMessage( const Kopete::StatusMessage& statusMessage )
368 {
369 setOnlineStatus( myself()->onlineStatus(), statusMessage, Kopete::Account::KeepSpecialFlags );
370 }
371
setUserProfile(const QString & profile)372 void AIMAccount::setUserProfile(const QString &profile)
373 {
374 kDebug(14152) << "called.";
375 AIMMyselfContact* aimmc = dynamic_cast<AIMMyselfContact*>( myself() );
376 if ( aimmc )
377 aimmc->setOwnProfile( profile );
378 configGroup()->writeEntry( QString::fromLatin1( "Profile" ), profile );
379 }
380
slotEditInfo()381 void AIMAccount::slotEditInfo()
382 {
383 if ( !isConnected() )
384 {
385 KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
386 i18n( "Editing your user info is not possible because "
387 "you are not connected." ),
388 i18n( "Unable to edit user info" ) );
389 return;
390 }
391 QPointer <AIMUserInfoDialog> myInfo = new AIMUserInfoDialog(static_cast<AIMContact *>( myself() ), this);
392 myInfo->exec(); // This is a modal dialog
393 delete myInfo;
394 }
395
slotToggleInvisible()396 void AIMAccount::slotToggleInvisible()
397 {
398 using namespace AIM;
399 if ( (presence().flags() & Presence::Invisible) == Presence::Invisible )
400 setPresenceFlags( presence().flags() & ~Presence::Invisible );
401 else
402 setPresenceFlags( presence().flags() | Presence::Invisible );
403 }
404
slotJoinChat()405 void AIMAccount::slotJoinChat()
406 {
407 if ( !isConnected() )
408 {
409 KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
410 i18n( "Joining an AIM chat room is not possible because "
411 "you are not connected." ),
412 i18n( "Unable to Join AIM Chat Room" ) );
413 return;
414 }
415
416 //get the exchange info
417 //create the dialog
418 //join the chat room
419 if ( !m_joinChatDialog )
420 {
421 m_joinChatDialog = new AIMJoinChatUI( this, Kopete::UI::Global::mainWidget() );
422 QObject::connect(m_joinChatDialog, &AIMJoinChatUI::closing, this, &AIMAccount::joinChatDialogClosed);
423 QList<int> list = engine()->chatExchangeList();
424 m_joinChatDialog->setExchangeList( list );
425 m_joinChatDialog->show();
426 }
427 else
428 m_joinChatDialog->raise();
429 }
430
joinChatDialogClosed(int code)431 void AIMAccount::joinChatDialogClosed( int code )
432 {
433 if ( code == QDialog::Accepted )
434 {
435 //join the chat
436 kDebug(14152) << "chat accepted.";
437 engine()->joinChatRoom( m_joinChatDialog->roomName(),
438 m_joinChatDialog->exchange().toInt() );
439 }
440
441 m_joinChatDialog->delayedDestruct();
442 m_joinChatDialog = nullptr;
443 }
444
loginActions()445 void AIMAccount::loginActions()
446 {
447 OscarAccount::loginActions();
448
449 using namespace AIM::PrivacySettings;
450 int privacySetting = this->configGroup()->readEntry( "PrivacySetting", int(AllowAll) );
451 this->setPrivacySettings( privacySetting );
452 }
453
disconnected(DisconnectReason reason)454 void AIMAccount::disconnected( DisconnectReason reason )
455 {
456 kDebug( OSCAR_AIM_DEBUG ) << "Attempting to set status offline";
457 Oscar::Presence pres( Oscar::Presence::Offline, presence().flags() );
458 myself()->setOnlineStatus( protocol()->statusManager()->onlineStatusOf( pres ) );
459
460 QHash<QString, Kopete::Contact*> contactList = contacts();
461 foreach( Kopete::Contact* c, contactList )
462 {
463 OscarContact* oc = dynamic_cast<OscarContact*>( c );
464 if ( oc )
465 oc->userOffline( oc->contactId() );
466 }
467
468 OscarAccount::disconnected( reason );
469 }
470
messageReceived(const Oscar::Message & message)471 void AIMAccount::messageReceived( const Oscar::Message& message )
472 {
473 kDebug(14152) << " Got a message, calling OscarAccount::messageReceived";
474 // Want to call the parent to do everything else
475 if ( message.channel() != 0x0003 )
476 {
477 OscarAccount::messageReceived(message);
478
479 // Check to see if our status is away, and send an away message
480 // Might be duplicate code from the parent class to get some needed information
481 // Perhaps a refactoring is needed.
482 kDebug(14152) << "Checking to see if I'm online..";
483 if( myself()->onlineStatus().status() == Kopete::OnlineStatus::Away ||
484 myself()->onlineStatus().status() == Kopete::OnlineStatus::Busy)
485 {
486 QString sender = Oscar::normalize( message.sender() );
487 AIMContact* aimSender = dynamic_cast<AIMContact *> ( contacts().value( sender ) ); //should exist now
488 if ( !aimSender )
489 {
490 kWarning(OSCAR_RAW_DEBUG) << "For some reason, could not get the contact "
491 << "That this message is from: " << message.sender() << ", Discarding message" << endl;
492 return;
493 }
494 // Create, or get, a chat session with the contact
495 Kopete::ChatSession* chatSession = aimSender->manager( Kopete::Contact::CanCreate );
496 Q_UNUSED(chatSession);
497
498 // get the away message we have set
499 QString msg = engine()->statusMessage();
500 kDebug(14152) << "Got away message: " << msg;
501 // Create the message
502 Kopete::Message chatMessage( myself(), aimSender );
503 chatMessage.setHtmlBody( msg );
504 chatMessage.setDirection( Kopete::Message::Outbound );
505
506 kDebug(14152) << "Sending autoresponse";
507 // Send the message
508 aimSender->sendAutoResponse( chatMessage );
509 }
510 }
511 else
512 {
513 kDebug(OSCAR_AIM_DEBUG) << "have chat message";
514 //handle chat room messages separately
515 QList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
516 QList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
517 for ( it = chats.begin(); it != itEnd; ++it )
518 {
519 Kopete::ChatSession* kcs = ( *it );
520 AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
521 if ( !session )
522 continue;
523
524 if ( session->exchange() == message.exchange() &&
525 Oscar::normalize( session->roomName() ) ==
526 Oscar::normalize( message.chatRoom() ) )
527 {
528 kDebug(OSCAR_AIM_DEBUG) << "found chat session for chat room";
529 OscarContact* ocSender = static_cast<OscarContact*>(contacts().value( Oscar::normalize( message.sender() ) ));
530 //sanitize;
531 QString sanitizedMsg = sanitizedMessage( message.text( defaultCodec() ) );
532
533 Kopete::Message chatMessage( ocSender, myself() );
534 chatMessage.setDirection( Kopete::Message::Inbound );
535 chatMessage.setHtmlBody( sanitizedMsg );
536 chatMessage.setTimestamp( message.timestamp() );
537
538 session->appendMessage( chatMessage );
539 }
540 }
541 }
542 }
543
connectedToChatRoom(Oscar::WORD exchange,const QString & room)544 void AIMAccount::connectedToChatRoom( Oscar::WORD exchange, const QString& room )
545 {
546 kDebug(OSCAR_AIM_DEBUG) << "Creating chat room session";
547 Kopete::ContactPtrList emptyList;
548 AIMMyselfContact* me = static_cast<AIMMyselfContact*>( myself() );
549 AIMChatSession* session = static_cast<AIMChatSession*>( me->manager( Kopete::Contact::CanCreate,
550 exchange, room ) );
551 session->setDisplayName( room );
552 if ( session->view( true ) )
553 session->raiseView();
554 }
555
userJoinedChat(Oscar::WORD exchange,const QString & room,const QString & contact)556 void AIMAccount::userJoinedChat( Oscar::WORD exchange, const QString& room, const QString& contact )
557 {
558 if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
559 return;
560
561 kDebug(OSCAR_AIM_DEBUG) << "user " << contact << " has joined the chat";
562 QList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
563 QList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
564 for ( it = chats.begin(); it != itEnd; ++it )
565 {
566 Kopete::ChatSession* kcs = ( *it );
567 AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
568 if ( !session )
569 continue;
570
571 kDebug(OSCAR_AIM_DEBUG) << session->exchange() << " " << exchange;
572 kDebug(OSCAR_AIM_DEBUG) << session->roomName() << " " << room;
573 if ( session->exchange() == exchange && session->roomName() == room )
574 {
575 kDebug(OSCAR_AIM_DEBUG) << "found correct chat session";
576 Kopete::Contact* c = contacts().value( Oscar::normalize( contact ) );
577 if ( !c )
578 {
579 Kopete::MetaContact* mc = addContact( Oscar::normalize( contact ),
580 contact, 0, Kopete::Account::Temporary );
581 if ( !mc )
582 kWarning(OSCAR_AIM_DEBUG) << "Unable to add contact for chat room";
583
584 c = mc->contacts().first();
585 c->setNickName( contact );
586 }
587
588 kDebug(OSCAR_AIM_DEBUG) << "adding contact";
589 Kopete::OnlineStatus status = protocol()->statusManager()->onlineStatusOf( Oscar::Presence( Oscar::Presence::Online ) );
590 session->addContact( c, status, true /* suppress */ );
591 }
592 }
593 }
594
userLeftChat(Oscar::WORD exchange,const QString & room,const QString & contact)595 void AIMAccount::userLeftChat( Oscar::WORD exchange, const QString& room, const QString& contact )
596 {
597 if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
598 return;
599
600 QList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
601 QList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
602 for ( it = chats.begin(); it != itEnd; ++it )
603 {
604 Kopete::ChatSession* kcs = ( *it );
605 AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
606 if ( !session )
607 continue;
608
609 if ( session->exchange() == exchange && session->roomName() == room )
610 {
611 //delete temp contact
612 Kopete::Contact* c = contacts().value( Oscar::normalize( contact ) );
613 if ( !c )
614 {
615 kWarning(OSCAR_AIM_DEBUG) << "couldn't find the contact that's left the chat!";
616 continue;
617 }
618 session->removeContact( c );
619 Kopete::MetaContact* mc = c->metaContact();
620 if ( mc->isTemporary() )
621 {
622 mc->removeContact( c );
623 delete c;
624 delete mc;
625 }
626 }
627 }
628 }
629
connectWithPassword(const QString & password)630 void AIMAccount::connectWithPassword( const QString &password )
631 {
632 if ( password.isNull() )
633 return;
634
635 kDebug(14152) << "accountId='" << accountId() << "'";
636
637 Kopete::OnlineStatus status = initialStatus();
638 if ( status == Kopete::OnlineStatus() && status.status() == Kopete::OnlineStatus::Unknown )
639 //use default online in case of invalid online status for connecting
640 status = Kopete::OnlineStatus( Kopete::OnlineStatus::Online );
641
642 Oscar::Presence pres = protocol()->statusManager()->presenceOf( status );
643 bool accountIsOffline = ( presence().type() == Oscar::Presence::Offline ||
644 myself()->onlineStatus() == protocol()->statusManager()->connectingStatus() );
645
646 if ( accountIsOffline )
647 {
648 kDebug(14152) << "Logging in as " << accountId();
649 myself()->setOnlineStatus( protocol()->statusManager()->connectingStatus() );
650
651 // Get the screen name for this account
652 QString screenName = accountId();
653 QString server = configGroup()->readEntry( "Server", QString::fromLatin1( "login.oscar.aol.com" ) );
654 uint port = configGroup()->readEntry( "Port", 5190 );
655
656 //set up the settings for the account
657 Oscar::Settings* oscarSettings = engine()->clientSettings();
658 oscarSettings->setFileProxy( configGroup()->readEntry( "FileProxy", true ) );
659 oscarSettings->setFirstPort( configGroup()->readEntry( "FirstPort", 5190 ) );
660 oscarSettings->setLastPort( configGroup()->readEntry( "LastPort", 5199 ) );
661 oscarSettings->setTimeout( configGroup()->readEntry( "Timeout", 10 ) );
662
663 Oscar::DWORD status = protocol()->statusManager()->oscarStatusOf( pres );
664 updateVersionUpdaterStamp();
665
666 engine()->start( server, port, accountId(), password.left(16) );
667 engine()->setStatus( status, mInitialStatusMessage );
668 engine()->connectToServer( server, port, false, QString() );
669
670 mInitialStatusMessage.clear();
671 }
672 }
673
setPrivacySettings(int privacy)674 void AIMAccount::setPrivacySettings( int privacy )
675 {
676 using namespace AIM::PrivacySettings;
677
678 Oscar::BYTE privacyByte = 0x01;
679 Oscar::DWORD userClasses = 0xFFFFFFFF;
680
681 switch ( privacy )
682 {
683 case AllowAll:
684 privacyByte = 0x01;
685 break;
686 case BlockAll:
687 privacyByte = 0x02;
688 break;
689 case AllowPremitList:
690 privacyByte = 0x03;
691 break;
692 case BlockDenyList:
693 privacyByte = 0x04;
694 break;
695 case AllowMyContacts:
696 privacyByte = 0x05;
697 break;
698 case BlockAIM:
699 privacyByte = 0x01;
700 userClasses = 0x00000004;
701 break;
702 }
703
704 engine()->setPrivacyTLVs( privacyByte, userClasses );
705 }
706
707