1 /*
2 icqontact.cpp - Oscar Protocol Plugin
3
4 Copyright (c) 2003 by Stefan Gehn <metz@gehn.net>
5 Copyright (c) 2003 by Olivier Goffart <oggoffart@kde.org>
6 Copyright (c) 2006,2007 by Roman Jarosz <kedgedev@centrum.cz>
7
8 Kopete (c) 2003-2007 by the Kopete developers <kopete-devel@kde.org>
9
10 *************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 *************************************************************************
18 */
19
20 #include "icqcontact.h"
21
22 #include <QPointer>
23 #include <qtimer.h>
24 #include <KActionCollection>
25 #include <KLocalizedString>
26 #include <knotification.h>
27 #include <qinputdialog.h>
28 #include <krandom.h>
29 #include <ktoggleaction.h>
30 #include <QIcon>
31
32 #include "kopeteuiglobal.h"
33 #include "kopetemetacontact.h"
34
35 #include "icqprotocol.h"
36 #include "icqaccount.h"
37 #include "icquserinfowidget.h"
38 #include "icqauthreplydialog.h"
39
40 #include "oscarutils.h"
41 #include "contactmanager.h"
42 #include "oscarstatusmanager.h"
43
ICQContact(Kopete::Account * account,const QString & name,Kopete::MetaContact * parent,const QString & icon)44 ICQContact::ICQContact( Kopete::Account* account, const QString &name, Kopete::MetaContact *parent,
45 const QString& icon )
46 : ICQContactBase( account, name, parent, icon )
47 {
48 m_requestingInfo = InfoNone;
49 mProtocol = static_cast<ICQProtocol *>(protocol());
50 m_infoWidget = nullptr;
51
52 setPresenceTarget( Oscar::Presence( Oscar::Presence::Offline ) );
53
54 QObject::connect( mAccount->engine(), SIGNAL(loggedIn()), this, SLOT(loggedIn()) );
55 //QObject::connect( mAccount->engine(), SIGNAL(userIsOnline(QString)), this, SLOT(userOnline(QString,UserDetails)) );
56 QObject::connect( mAccount->engine(), SIGNAL(userIsOffline(QString)), this, SLOT(userOffline(QString)) );
57 QObject::connect( mAccount->engine(), SIGNAL(authReplyReceived(QString,QString,bool)),
58 this, SLOT(slotGotAuthReply(QString,QString,bool)) );
59 QObject::connect( mAccount->engine(), SIGNAL(receivedIcqShortInfo(QString)),
60 this, SLOT(receivedShortInfo(QString)) );
61 QObject::connect( mAccount->engine(), SIGNAL(receivedIcqLongInfo(QString)),
62 this, SLOT(receivedLongInfo(QString)) );
63 QObject::connect( mAccount->engine(), SIGNAL(receivedUserInfo(QString,UserDetails)),
64 this, SLOT(userInfoUpdated(QString,UserDetails)) );
65 QObject::connect( mAccount->engine(), SIGNAL(receivedIcqTlvInfo(QString)),
66 this, SLOT(receivedTlvInfo(QString)) );
67 }
68
~ICQContact()69 ICQContact::~ICQContact()
70 {
71 delete m_infoWidget;
72 }
73
setSSIItem(const OContact & ssiItem)74 void ICQContact::setSSIItem( const OContact& ssiItem )
75 {
76 if ( ssiItem.waitingAuth() )
77 setOnlineStatus( mProtocol->statusManager()->waitingForAuth() );
78
79 if ( ssiItem.type() != 0xFFFF && ssiItem.waitingAuth() == false &&
80 onlineStatus().status() == Kopete::OnlineStatus::Unknown )
81 {
82 //make sure they're offline
83 setPresenceTarget( Oscar::Presence( Oscar::Presence::Offline ) );
84 }
85
86 if ( mAccount->engine()->isActive() && m_ssiItem.metaInfoId() != ssiItem.metaInfoId() )
87 {
88 // User info has changed, check nickname or status description if needed.
89 // If mAccount->isConnected() is false then the metaInfoId has changed while
90 // we were offline and we don't know how many users changed its info, so better
91 // delay the request.
92 if ( mAccount->isConnected() )
93 QTimer::singleShot( 0, this, SLOT(requestMediumTlvInfo()) );
94 else
95 requestMediumTlvInfoDelayed();
96 }
97
98 ICQContactBase::setSSIItem( ssiItem );
99 }
100
setEncoding(int mib)101 void ICQContact::setEncoding( int mib )
102 {
103 ICQContactBase::setEncoding( mib );
104 QTimer::singleShot( 0, this, SLOT(requestShortInfo()) );
105 }
106
userInfoUpdated(const QString & contact,const UserDetails & details)107 void ICQContact::userInfoUpdated( const QString& contact, const UserDetails& details )
108 {
109 if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
110 return;
111
112 // invalidate old away message if user was offline
113 if ( !isOnline() )
114 {
115 removeProperty( mProtocol->statusTitle );
116 removeProperty( mProtocol->statusMessage );
117 }
118
119 kDebug( OSCAR_ICQ_DEBUG ) << "extendedStatus is " << details.extendedStatus();
120 Oscar::Presence presence = mProtocol->statusManager()->presenceOf( details.extendedStatus(), details.userClass() );
121
122 if ( details.dcOutsideSpecified() )
123 setProperty( mProtocol->ipAddress, details.dcExternalIp().toString() );
124
125 if ( details.capabilitiesSpecified() )
126 setProperty( mProtocol->clientFeatures, details.clientName() );
127
128 OscarContact::userInfoUpdated( contact, details );
129
130 refreshStatus( m_details, presence );
131 }
132
refreshStatus(const UserDetails & details,Oscar::Presence presence)133 void ICQContact::refreshStatus( const UserDetails& details, Oscar::Presence presence )
134 {
135 // Filter our XStatus and ExtStatus
136 presence.setFlags( presence.flags() & ~Oscar::Presence::StatusTypeMask );
137
138 if ( details.statusMood() != -1 )
139 {
140 presence.setFlags( presence.flags() | Oscar::Presence::ExtStatus2 );
141 presence.setMood( details.statusMood() );
142
143 Kopete::StatusMessage msg;
144 msg.setTitle( details.personalMessage() );
145 setStatusMessage( msg );
146 }
147 // XStatus don't support offline status so don't show it (xtrazStatusSpecified can be true if contact was online)
148 else if ( details.xtrazStatus() != -1 && presence.type() != Oscar::Presence::Offline )
149 {
150 presence.setFlags( presence.flags() | Oscar::Presence::XStatus );
151 presence.setXtrazStatus( details.xtrazStatus() );
152
153 Kopete::StatusMessage msg;
154 msg.setTitle( details.personalMessage() );
155 setStatusMessage( msg );
156 }
157 else if ( !details.personalMessage().isEmpty() )
158 {
159 presence.setFlags( presence.flags() | Oscar::Presence::ExtStatus );
160
161 Kopete::StatusMessage msg;
162 msg.setTitle( details.personalMessage() );
163 setStatusMessage( msg );
164 }
165 else
166 {
167 Kopete::StatusMessage msg;
168 setStatusMessage( msg ); // set an empty status message
169 }
170
171 setPresenceTarget( presence );
172
173 Oscar::Presence selfPres( mProtocol->statusManager()->presenceOf( account()->myself()->onlineStatus() ) );
174 bool selfVisible = !(selfPres.flags() & Oscar::Presence::Invisible);
175
176 if ( selfVisible && isReachable() && presence.type() != Oscar::Presence::Offline )
177 {
178 Client::ICQStatus contactStatus = Client::ICQOnline;
179 if ( details.xtrazStatus() != -1 )
180 {
181 contactStatus = Client::ICQXStatus;
182 }
183 else
184 {
185 switch ( presence.type() )
186 {
187 case Oscar::Presence::Online:
188 contactStatus = Client::ICQOnline;
189 break;
190 case Oscar::Presence::Away:
191 contactStatus = Client::ICQAway;
192 break;
193 case Oscar::Presence::NotAvailable:
194 contactStatus = Client::ICQNotAvailable;
195 break;
196 case Oscar::Presence::Occupied:
197 contactStatus = Client::ICQOccupied;
198 break;
199 case Oscar::Presence::DoNotDisturb:
200 contactStatus = Client::ICQDoNotDisturb;
201 break;
202 case Oscar::Presence::FreeForChat:
203 contactStatus = Client::ICQFreeForChat;
204 break;
205 default:
206 break;
207 }
208 }
209
210 // FIXME: How can we check if client supports status plugin messages?
211 if ( details.onlineStatusMsgSupport() )
212 contactStatus |= Client::ICQPluginStatus;
213
214 // If contact is online and doesn't support status plugin messages than
215 // this contact can't have online status message.
216 if ( contactStatus == Client::ICQOnline && !details.onlineStatusMsgSupport() )
217 {
218 mAccount->engine()->removeICQAwayMessageRequest( contactId() );
219 removeProperty( mProtocol->statusMessage );
220 }
221 else
222 {
223 mAccount->engine()->addICQAwayMessageRequest( contactId(), contactStatus );
224 }
225 }
226 else
227 {
228 mAccount->engine()->removeICQAwayMessageRequest( contactId() );
229 }
230 }
231
userOnline(const QString & userId)232 void ICQContact::userOnline( const QString& userId )
233 {
234 if ( Oscar::normalize( userId ) != Oscar::normalize( contactId() ) )
235 return;
236
237 kDebug(OSCAR_ICQ_DEBUG) << "Setting " << userId << " online";
238 setPresenceTarget( Oscar::Presence( Oscar::Presence::Online ) );
239 }
240
userOffline(const QString & userId)241 void ICQContact::userOffline( const QString& userId )
242 {
243 if ( Oscar::normalize( userId ) != Oscar::normalize( contactId() ) )
244 return;
245
246 m_details.clear();
247
248 kDebug(OSCAR_ICQ_DEBUG) << "Setting " << userId << " offline";
249 if ( m_ssiItem.waitingAuth() )
250 setOnlineStatus( mProtocol->statusManager()->waitingForAuth() );
251 else
252 refreshStatus( m_details, Oscar::Presence( Oscar::Presence::Offline ) );
253
254 removeProperty( mProtocol->statusTitle );
255 removeProperty( mProtocol->statusMessage );
256 }
257
loggedIn()258 void ICQContact::loggedIn()
259 {
260 if ( metaContact()->isTemporary() )
261 return;
262
263 if ( m_ssiItem.waitingAuth() )
264 setOnlineStatus( mProtocol->statusManager()->waitingForAuth() );
265
266 requestShortInfoDelayed();
267 }
268
slotRequestAuth()269 void ICQContact::slotRequestAuth()
270 {
271 QString reason = QInputDialog::getText( nullptr, i18n("Request Authorization"),
272 i18n("Reason for requesting authorization:"), QLineEdit::Normal,
273 i18n("Please authorize me so I can add you to my contact list") );
274 if ( !reason.isNull() )
275 mAccount->engine()->requestAuth( contactId(), reason );
276 }
277
slotSendAuth()278 void ICQContact::slotSendAuth()
279 {
280 kDebug(OSCAR_ICQ_DEBUG) << "Sending auth reply";
281 QPointer <ICQAuthReplyDialog> replyDialog = new ICQAuthReplyDialog( 0, false );
282
283 replyDialog->setUser( displayName() );
284 if ( replyDialog->exec() && replyDialog )
285 mAccount->engine()->sendAuth( contactId(), replyDialog->reason(), replyDialog->grantAuth() );
286 delete replyDialog;
287 }
288
slotGotAuthReply(const QString & contact,const QString & reason,bool granted)289 void ICQContact::slotGotAuthReply( const QString& contact, const QString& reason, bool granted )
290 {
291 if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
292 return;
293
294 if ( account()->isBusy() )
295 return;
296
297 kDebug(OSCAR_ICQ_DEBUG) ;
298 QString message;
299 if( granted )
300 {
301 message = i18n( "User %1 has granted your authorization request.\nReason: %2" ,
302 displayName() ,
303 reason );
304
305 // remove the unknown status
306 setPresenceTarget( Oscar::Presence( Oscar::Presence::Offline ) );
307 }
308 else
309 {
310 message = i18n( "User %1 has rejected the authorization request.\nReason: %2" ,
311 displayName() ,
312 reason );
313 }
314 KNotification::event( QString::fromLatin1("icq_authorization"), message );
315 }
316
requestShortInfo()317 void ICQContact::requestShortInfo()
318 {
319 kDebug(OSCAR_ICQ_DEBUG) << "requesting short info for " << contactId();
320 if ( mAccount->engine()->isActive() )
321 mAccount->engine()->requestShortInfo( contactId() );
322
323 // Don't clear m_requestingInfo if info with higher contents was requested
324 if ( m_requestingInfo <= InfoShort )
325 m_requestingInfo = InfoNone;
326 }
327
receivedShortInfo(const QString & contact)328 void ICQContact::receivedShortInfo( const QString& contact )
329 {
330 if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
331 return;
332
333 QTextCodec* codec = contactCodec();
334
335 ICQShortInfo shortInfo = mAccount->engine()->getShortInfo( contact );
336
337 setProperty( mProtocol->firstName, codec->toUnicode( shortInfo.firstName ) );
338 setProperty( mProtocol->lastName, codec->toUnicode( shortInfo.lastName ) );
339 setNickName( codec->toUnicode( shortInfo.nickname ) );
340 }
341
receivedLongInfo(const QString & contact)342 void ICQContact::receivedLongInfo( const QString& contact )
343 {
344 if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
345 {
346 if ( m_infoWidget )
347 m_infoWidget->deleteLater();
348 return;
349 }
350
351 QTextCodec* codec = contactCodec();
352
353 kDebug(OSCAR_ICQ_DEBUG) << "received long info from engine";
354
355 ICQGeneralUserInfo genInfo = mAccount->engine()->getGeneralInfo( contact );
356
357 setProperty( mProtocol->firstName, codec->toUnicode( genInfo.firstName.get() ) );
358 setProperty( mProtocol->lastName, codec->toUnicode( genInfo.lastName.get() ) );
359 setNickName( codec->toUnicode( genInfo.nickName.get() ) );
360
361 emit haveBasicInfo( genInfo );
362
363 ICQWorkUserInfo workInfo = mAccount->engine()->getWorkInfo( contact );
364 emit haveWorkInfo( workInfo );
365
366 ICQEmailInfo emailInfo = mAccount->engine()->getEmailInfo( contact );
367 emit haveEmailInfo( emailInfo );
368
369 ICQNotesInfo notesInfo = mAccount->engine()->getNotesInfo( contact );
370 emit haveNotesInfo( notesInfo );
371
372 ICQMoreUserInfo moreInfo = mAccount->engine()->getMoreInfo( contact );
373 emit haveMoreInfo( moreInfo );
374
375 ICQInterestInfo interestInfo = mAccount->engine()->getInterestInfo( contact );
376 emit haveInterestInfo( interestInfo );
377
378 ICQOrgAffInfo orgAffInfo = mAccount->engine()->getOrgAffInfo( contact );
379 emit haveOrgAffInfo( orgAffInfo );
380 }
381
requestMediumTlvInfo()382 void ICQContact::requestMediumTlvInfo()
383 {
384 kDebug(OSCAR_ICQ_DEBUG) << "requesting medium tlv info for " << contactId();
385 if ( mAccount->engine()->isActive() && !m_ssiItem.metaInfoId().isEmpty() )
386 mAccount->engine()->requestMediumTlvInfo( contactId(), m_ssiItem.metaInfoId() );
387
388 // Don't clear m_requestingInfo if info with higher contents was requested
389 if ( m_requestingInfo <= InfoMediumTlv )
390 m_requestingInfo = InfoNone;
391 }
392
receivedTlvInfo(const QString & contact)393 void ICQContact::receivedTlvInfo( const QString& contact )
394 {
395 if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
396 return;
397
398 ICQFullInfo info = mAccount->engine()->getFullInfo( contact );
399
400 setProperty( mProtocol->firstName, QString::fromUtf8( info.firstName.get() ) );
401 setProperty( mProtocol->lastName, QString::fromUtf8( info.lastName.get() ) );
402 setNickName( QString::fromUtf8( info.nickName.get() ) );
403 }
404
requestShortInfoDelayed(int minDelay)405 void ICQContact::requestShortInfoDelayed( int minDelay )
406 {
407 if ( mAccount->engine()->isActive() && m_requestingInfo < InfoShort )
408 {
409 m_requestingInfo = InfoShort;
410 int time = ( KRandom::random() % 20 ) * 1000 + minDelay;
411 kDebug(OSCAR_ICQ_DEBUG) << "requesting info in " << time/1000 << " seconds";
412 QTimer::singleShot( time, this, SLOT(infoDelayTimeout()) );
413 }
414 }
415
requestMediumTlvInfoDelayed(int minDelay)416 void ICQContact::requestMediumTlvInfoDelayed( int minDelay )
417 {
418 if ( mAccount->engine()->isActive() && m_requestingInfo < InfoMediumTlv )
419 {
420 m_requestingInfo = InfoMediumTlv;
421 int time = ( KRandom::random() % 20 ) * 1000 + minDelay;
422 kDebug(OSCAR_ICQ_DEBUG) << "requesting info in " << time/1000 << " seconds";
423 QTimer::singleShot( time, this, SLOT(infoDelayTimeout()) );
424 }
425 }
426
infoDelayTimeout()427 void ICQContact::infoDelayTimeout()
428 {
429 if ( m_requestingInfo == InfoMediumTlv )
430 requestMediumTlvInfo();
431 else if ( m_requestingInfo == InfoShort )
432 requestShortInfo();
433 }
434
435 #if 0
436 void ICQContact::slotContactChanged(const UserInfo &u)
437 {
438 if (u.sn != contactName())
439 return;
440
441 // update mInfo and general stuff from OscarContact
442 slotParseUserInfo(u);
443
444 /*kDebug(14190) << "Called for '"
445 << displayName() << "', contactName()=" << contactName() << endl;*/
446 QStringList capList;
447 // Append client name and version in case we found one
448 if (!mInfo.clientName.isEmpty())
449 {
450 if (!mInfo.clientVersion.isEmpty())
451 {
452 capList << i18nc("Translators: client-name client-version",
453 "%1 %2", mInfo.clientName, mInfo.clientVersion);
454 }
455 else
456 {
457 capList << mInfo.clientName;
458 }
459 }
460 // and now for some general informative capabilities
461 if (hasCap(CAP_UTF8))
462 capList << i18n("UTF-8");
463 if (hasCap(CAP_RTFMSGS))
464 capList << i18n("RTF-Messages");
465 if (hasCap(CAP_IMIMAGE))
466 capList << i18n("DirectIM/IMImage");
467 if (hasCap(CAP_CHAT))
468 capList << i18n("Groupchat");
469
470 if (capList.count() > 0)
471 setProperty(mProtocol->clientFeatures, capList.join(", "));
472 else
473 removeProperty(mProtocol->clientFeatures);
474
475 unsigned int newStatus = 0;
476 mInvisible = (mInfo.icqextstatus & ICQ_STATUS_IS_INVIS);
477
478 if (mInfo.icqextstatus & ICQ_STATUS_IS_FFC)
479 newStatus = OSCAR_FFC;
480 else if (mInfo.icqextstatus & ICQ_STATUS_IS_DND)
481 newStatus = OSCAR_DND;
482 else if (mInfo.icqextstatus & ICQ_STATUS_IS_OCC)
483 newStatus = OSCAR_OCC;
484 else if (mInfo.icqextstatus & ICQ_STATUS_IS_NA)
485 newStatus = OSCAR_NA;
486 else if (mInfo.icqextstatus & ICQ_STATUS_IS_AWAY)
487 newStatus = OSCAR_AWAY;
488 else
489 newStatus = OSCAR_ONLINE;
490
491 if (this != account()->myself())
492 {
493 if(newStatus != onlineStatus().internalStatus())
494 {
495 if(newStatus != OSCAR_ONLINE) // if user changed to some state other than online
496 {
497 mAccount->engine()->requestAwayMessage(this);
498 }
499 else // user changed to "Online" status and has no away message anymore
500 {
501 removeProperty(mProtocol->statusMessage);
502 }
503 }
504 }
505
506 setStatus(newStatus);
507 }
508
509 void ICQContact::slotOffgoingBuddy(QString sender)
510 {
511 if(sender != contactName())
512 return;
513
514 removeProperty(mProtocol->clientFeatures);
515 removeProperty(mProtocol->statusMessage);
516 setOnlineStatus(mProtocol->statusOffline);
517 }
518
519 void ICQContact::gotIM(OscarSocket::OscarMessageType /*type*/, const QString &message)
520 {
521 // Build a Kopete::Message and set the body as Rich Text
522 Kopete::ContactPtrList tmpList;
523 tmpList.append(account()->myself());
524 Kopete::Message msg(this, tmpList, message, Kopete::Message::Inbound,
525 Kopete::Message::RichText);
526 manager(true)->appendMessage(msg);
527 }
528
529 void ICQContact::slotSendMsg(Kopete::Message& message, Kopete::ChatSession *)
530 {
531 if (message.plainBody().isEmpty()) // no text, do nothing
532 return;
533
534 // Check to see if we're even online
535 if(!account()->isConnected())
536 {
537 KMessageBox::sorry(Kopete::UI::Global::mainWidget(),
538 i18n("<qt>You must be logged on to ICQ before you can "
539 "send a message to a user.</qt>"),
540 i18n("Not Signed On"));
541 return;
542 }
543
544 // FIXME: We don't do HTML in ICQ
545 // we might be able to do that in AIM and we might also convert
546 // HTML to RTF for ICQ type-2 messages [mETz]
547 static_cast<OscarAccount*>(account())->engine()->sendIM(
548 message.plainBody(), this, false);
549
550 // Show the message we just sent in the chat window
551 manager(Kopete::Contact::CanCreate)->appendMessage(message);
552 manager(Kopete::Contact::CanCreate)->messageSucceeded();
553 }
554
555 #endif
556
isReachable()557 bool ICQContact::isReachable()
558 {
559 return account()->isConnected();
560 }
561
customContextMenuActions()562 QList<QAction*> *ICQContact::customContextMenuActions()
563 {
564 QList<QAction*> *actions = new QList<QAction*>();
565
566 actionRequestAuth = new QAction( i18n("&Request Authorization"), this );
567 //, "actionRequestAuth");
568 actionRequestAuth->setIcon( QIcon::fromTheme(QStringLiteral("mail-reply-sender")) );
569 QObject::connect(actionRequestAuth, &QAction::triggered, this, &ICQContact::slotRequestAuth);
570
571 actionSendAuth = new QAction( i18n("&Grant Authorization"), this );
572 //, "actionSendAuth");
573 actionSendAuth->setIcon( QIcon::fromTheme(QStringLiteral("mail-forward")) );
574 QObject::connect(actionSendAuth, &QAction::triggered, this, &ICQContact::slotSendAuth);
575
576 m_actionIgnore = new KToggleAction(i18n("&Ignore"), this );
577 //, "actionIgnore");
578 QObject::connect(m_actionIgnore, &KToggleAction::triggered, this, &ICQContact::slotIgnore);
579
580 m_actionVisibleTo = new KToggleAction(i18n("Always &Visible To"), this );
581 //, "actionVisibleTo");
582 QObject::connect(m_actionVisibleTo, &KToggleAction::triggered, this, &ICQContact::slotVisibleTo);
583
584 m_actionInvisibleTo = new KToggleAction(i18n("Always &Invisible To"), this );
585 //, "actionInvisibleTo");
586 QObject::connect(m_actionInvisibleTo, &KToggleAction::triggered, this, &ICQContact::slotInvisibleTo);
587
588 m_selectEncoding = new QAction( i18n( "Select Encoding..." ), this );
589 //, "changeEncoding" );
590 m_selectEncoding->setIcon( QIcon::fromTheme(QStringLiteral("character-set")) );
591 QObject::connect(m_selectEncoding, &QAction::triggered, this, &ICQContact::changeContactEncoding);
592
593 bool on = account()->isConnected();
594 if ( m_ssiItem.waitingAuth() )
595 actionRequestAuth->setEnabled(on);
596 else
597 actionRequestAuth->setEnabled(false);
598
599 actionSendAuth->setEnabled(on);
600 m_actionIgnore->setEnabled(on);
601 m_actionVisibleTo->setEnabled(on);
602 m_actionInvisibleTo->setEnabled(on);
603
604 ContactManager* ssi = account()->engine()->ssiManager();
605 m_actionIgnore->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_IGNORE ));
606 m_actionVisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_VISIBLE ));
607 m_actionInvisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_INVISIBLE ));
608
609 actions->append(actionRequestAuth);
610 actions->append(actionSendAuth);
611 actions->append( m_selectEncoding );
612
613 actions->append(m_actionIgnore);
614 actions->append(m_actionVisibleTo);
615 actions->append(m_actionInvisibleTo);
616
617 // temporary action collection, used to apply Kiosk policy to the actions
618 KActionCollection tempCollection((QObject*)0);
619 tempCollection.addAction(QLatin1String("contactRequestAuth"), actionRequestAuth);
620 tempCollection.addAction(QLatin1String("contactSendAuth"), actionSendAuth);
621 tempCollection.addAction(QLatin1String("contactSelectEncoding"), m_selectEncoding);
622 tempCollection.addAction(QLatin1String("contactIgnore"), m_actionIgnore);
623 tempCollection.addAction(QLatin1String("oscarContactAlwaysVisibleTo"), m_actionVisibleTo);
624 tempCollection.addAction(QLatin1String("oscarContactAlwaysInvisibleTo"), m_actionInvisibleTo);
625 return actions;
626 }
627
slotUserInfo()628 void ICQContact::slotUserInfo()
629 {
630 if ( m_infoWidget )
631 {
632 m_infoWidget->showNormal();
633 m_infoWidget->activateWindow();
634 return;
635 }
636
637 m_infoWidget = new ICQUserInfoWidget( this, Kopete::UI::Global::mainWidget() );
638 QObject::connect(m_infoWidget, &ICQUserInfoWidget::finished, this, &ICQContact::closeUserInfoDialog);
639 // QObject::connect(m_infoWidget, &ICQUserInfoWidget::okClicked, this, &ICQContact::storeUserInfoDialog);
640 m_infoWidget->show();
641 }
642
storeUserInfoDialog()643 void ICQContact::storeUserInfoDialog()
644 {
645 QString alias = m_infoWidget->getAlias();
646 if ( alias.isEmpty() )
647 requestShortInfoDelayed( 5000 );
648 else
649 mAccount->engine()->changeContactAlias( contactId(), alias );
650 }
651
closeUserInfoDialog()652 void ICQContact::closeUserInfoDialog()
653 {
654 QObject::disconnect( this, 0, m_infoWidget, 0 );
655 m_infoWidget->deleteLater();
656 m_infoWidget = nullptr;
657 }
658
slotIgnore()659 void ICQContact::slotIgnore()
660 {
661 account()->engine()->setIgnore( contactId(), m_actionIgnore->isChecked() );
662 }
663
slotVisibleTo()664 void ICQContact::slotVisibleTo()
665 {
666 account()->engine()->setVisibleTo( contactId(), m_actionVisibleTo->isChecked() );
667 }
668
slotInvisibleTo()669 void ICQContact::slotInvisibleTo()
670 {
671 account()->engine()->setInvisibleTo( contactId(), m_actionInvisibleTo->isChecked() );
672 }
673
674 #if 0
675
676 void ICQContact::slotReadAwayMessage()
677 {
678 kDebug(14153) << "account='" << account()->accountId() <<
679 "', contact='" << displayName() << "'" << endl;
680
681 if (!awayMessageDialog)
682 {
683 awayMessageDialog = new ICQReadAway(this, 0L, "awayMessageDialog");
684 if(!awayMessageDialog)
685 return;
686 QObject::connect(awayMessageDialog, &ICQReadAway::closing, this, &ICQContact::slotCloseAwayMessageDialog);
687 awayMessageDialog->show();
688 }
689 else
690 {
691 awayMessageDialog->raise();
692 }
693 }
694
695 void ICQContact::slotCloseAwayMessageDialog()
696 {
697 awayMessageDialog->deleteLater();
698 awayMessageDialog = nullptr;
699 }
700
701 const QString ICQContact::awayMessage()
702 {
703 kDebug(14150) << property(mProtocol->statusMessage).value().toString();
704 return property(mProtocol->statusMessage).value().toString();
705 }
706
707 void ICQContact::setAwayMessage(const QString &message)
708 {
709 /*kDebug(14150) <<
710 "Called for '" << displayName() << "', away msg='" << message << "'" << endl;*/
711 setProperty(mProtocol->statusMessage, message);
712 emit awayMessageChanged();
713 }
714
715 void ICQContact::slotUpdGeneralInfo(const int seq, const ICQGeneralUserInfo &inf)
716 {
717 // compare reply's sequence with the one we sent with our last request
718 if(seq != userinfoRequestSequence)
719 return;
720 generalInfo = inf;
721
722 if(!generalInfo.firstName.isEmpty())
723 setProperty(mProtocol->firstName, generalInfo.firstName);
724 else
725 removeProperty(mProtocol->firstName);
726
727 if(!generalInfo.lastName.isEmpty())
728 setProperty(mProtocol->lastName, generalInfo.lastName);
729 else
730 removeProperty(mProtocol->lastName);
731
732 if(!generalInfo.eMail.isEmpty())
733 setProperty(mProtocol->emailAddress, generalInfo.eMail);
734 else
735 removeProperty(mProtocol->emailAddress);
736 /*
737 if(!generalInfo.phoneNumber.isEmpty())
738 setProperty("privPhoneNum", generalInfo.phoneNumber);
739 else
740 removeProperty("privPhoneNum");
741
742 if(!generalInfo.faxNumber.isEmpty())
743 setProperty("privFaxNum", generalInfo.faxNumber);
744 else
745 removeProperty("privFaxNum");
746
747 if(!generalInfo.cellularNumber.isEmpty())
748 setProperty("privMobileNum", generalInfo.cellularNumber);
749 else
750 removeProperty("privMobileNum");
751 */
752
753 setDisplayName(generalInfo.nickName);
754
755 incUserInfoCounter();
756 }
757
758 void ICQContact::slotSnacFailed(WORD snacID)
759 {
760 if (userinfoRequestSequence != 0)
761 kDebug(14153) << "snacID = " << snacID << " seq = " << userinfoRequestSequence;
762
763 //TODO: ugly interaction between snacID and request sequence, see OscarSocket::sendCLI_TOICQSRV
764 if (snacID == (0x0000 << 16) | userinfoRequestSequence)
765 {
766 userinfoRequestSequence = 0;
767 emit userInfoRequestFailed();
768 }
769 }
770
771 void ICQContact::slotIgnore()
772 {
773 kDebug(14150) <<
774 "Called; ignore = " << actionIgnore->isChecked() << endl;
775 setIgnore(actionIgnore->isChecked(), true);
776 }
777
778 void ICQContact::slotVisibleTo()
779 {
780 kDebug(14150) <<
781 "Called; visible = " << actionVisibleTo->isChecked() << endl;
782 setVisibleTo(actionVisibleTo->isChecked(), true);
783 }
784 #endif
785