File indexing completed on 2024-04-14 04:01:44
0001 /* 0002 * jabbercontact.cpp - Base class for the Kopete Jabber protocol contact 0003 * 0004 * Copyright (c) 2002-2004 by Till Gerken <till@tantalo.net> 0005 * Copyright (c) 2006 by Olivier Goffart <ogoffart at kde.org> 0006 * 0007 * Kopete (c) by the Kopete developers <kopete-devel@kde.org> 0008 * 0009 * ************************************************************************* 0010 * * * 0011 * * This program is free software; you can redistribute it and/or modify * 0012 * * it under the terms of the GNU General Public License as published by * 0013 * * the Free Software Foundation; either either version 2 0014 of the License, or (at your option) any later version.of the License, or * 0015 * * (at your option) any later version. * 0016 * * * 0017 * ************************************************************************* 0018 */ 0019 0020 #include <KLocalizedString> 0021 #include <KStandardDirs> 0022 #include <QTimer> 0023 #include <QImage> 0024 #include <QRegExp> 0025 #include <KMessageBox> 0026 #include <kio/netaccess.h> 0027 0028 0029 #include <kopetegroup.h> 0030 #include <kopetecontactlist.h> 0031 #include <kopeteavatarmanager.h> 0032 0033 #include "jabberbasecontact.h" 0034 0035 #include "xmpp_tasks.h" 0036 0037 #include "jabberprotocol.h" 0038 #include "jabberaccount.h" 0039 #include "jabberresource.h" 0040 #include "jabberresourcepool.h" 0041 #include "kopetemetacontact.h" 0042 #include "kopetemessage.h" 0043 #include "kopeteuiglobal.h" 0044 #include "jabbertransport.h" 0045 #include "dlgjabbervcard.h" 0046 0047 0048 /** 0049 * JabberBaseContact constructor 0050 */ 0051 JabberBaseContact::JabberBaseContact (const XMPP::RosterItem &rosterItem, Kopete::Account *account, Kopete::MetaContact * mc, const QString &legacyId) 0052 : Kopete::Contact (account, legacyId.isEmpty() ? rosterItem.jid().full() : legacyId , mc ) 0053 { 0054 setDontSync ( false ); 0055 0056 JabberTransport *t=transport(); 0057 m_account= t ? t->account() : static_cast<JabberAccount *>(Kopete::Contact::account()); 0058 0059 0060 // take roster item and update display name 0061 updateContact ( rosterItem ); 0062 0063 } 0064 0065 0066 JabberProtocol *JabberBaseContact::protocol () 0067 { 0068 0069 return static_cast<JabberProtocol *>(Kopete::Contact::protocol ()); 0070 } 0071 0072 0073 JabberTransport * JabberBaseContact::transport( ) 0074 { 0075 return dynamic_cast<JabberTransport*>(Kopete::Contact::account()); 0076 } 0077 0078 0079 /* Return if we are reachable (defaults to true because 0080 we can send on- and offline, only return false if the 0081 account itself is offline, too) */ 0082 bool JabberBaseContact::isReachable () 0083 { 0084 if (account()->isConnected()) 0085 return true; 0086 0087 return false; 0088 0089 } 0090 0091 void JabberBaseContact::updateContact ( const XMPP::RosterItem & item ) 0092 { 0093 qCDebug(JABBER_PROTOCOL_LOG) << "Synchronizing local copy of " << contactId() << " with information received from server. (name='" << item.name() << "' groups='" << item.groups() << "')"; 0094 0095 mRosterItem = item; 0096 0097 // if we don't have a meta contact yet, stop processing here 0098 if ( !metaContact () ) 0099 return; 0100 0101 /* 0102 * We received the information from the server, as such, 0103 * don't attempt to synch while we update our local copy. 0104 */ 0105 setDontSync ( true ); 0106 0107 // The myself contact is not in the roster on server, ignore this code 0108 // because the myself MetaContact displayname become the latest 0109 // Jabber acccount jid. 0110 if( metaContact() != Kopete::ContactList::self()->myself() ) 0111 { 0112 // only update the alias if it is not empty 0113 if ( !item.name().isEmpty () && item.name() != item.jid().bare() 0114 && metaContact()->customDisplayName() != item.name () ) 0115 { 0116 qCDebug(JABBER_PROTOCOL_LOG) << "setting display name of " << contactId () << " to " << item.name(); 0117 metaContact()->setDisplayName ( item.name () ); 0118 } 0119 } 0120 0121 /* 0122 * Set the contact's subscription status 0123 */ 0124 switch ( item.subscription().type () ) 0125 { 0126 case XMPP::Subscription::None: 0127 setProperty ( protocol()->propSubscriptionStatus, 0128 i18n ( "You cannot see each others' status." ) ); 0129 break; 0130 case XMPP::Subscription::To: 0131 setProperty ( protocol()->propSubscriptionStatus, 0132 i18n ( "You can see this contact's status, but he/she cannot see your status." ) ); 0133 break; 0134 case XMPP::Subscription::From: 0135 setProperty ( protocol()->propSubscriptionStatus, 0136 i18n ( "This contact can see your status, but you cannot see his/her status." ) ); 0137 break; 0138 case XMPP::Subscription::Both: 0139 setProperty ( protocol()->propSubscriptionStatus, 0140 i18n ( "You can see each others' status." ) ); 0141 break; 0142 } 0143 0144 if( !metaContact()->isTemporary() ) 0145 { 0146 /* 0147 * In this method, as opposed to KC::syncGroups(), 0148 * the group list from the server is authoritative. 0149 * As such, we need to find a list of all groups 0150 * that the meta contact resides in but does not 0151 * reside in on the server anymore, as well as all 0152 * groups that the meta contact does not reside in, 0153 * but resides in on the server. 0154 * Then, we'll have to synchronize the KMC using 0155 * that information. 0156 */ 0157 Kopete::GroupList groupsToRemoveFrom, groupsToAddTo; 0158 0159 // find all groups our contact is in but that are not in the server side roster 0160 for ( int i = 0; i < metaContact()->groups().count (); i++ ) 0161 { 0162 if ( !item.groups().contains ( metaContact()->groups().at(i)->displayName () ) ) 0163 groupsToRemoveFrom.append ( metaContact()->groups().at ( i ) ); 0164 } 0165 0166 // now find all groups that are in the server side roster but not in the local group 0167 for ( int i = 0; i < item.groups().count (); i++ ) 0168 { 0169 bool found = false; 0170 for ( int j = 0; j < metaContact()->groups().count (); j++) 0171 { 0172 if ( metaContact()->groups().at(j)->displayName () == item.groups().at(i) ) 0173 { 0174 found = true; 0175 break; 0176 } 0177 } 0178 0179 if ( !found ) 0180 { 0181 groupsToAddTo.append ( Kopete::ContactList::self()->findGroup ( item.groups().at(i) ) ); 0182 } 0183 } 0184 0185 /* 0186 * Special case: if we don't add the contact to any group and the 0187 * list of groups to remove from contains the top level group, we 0188 * risk removing the contact from the visible contact list. In this 0189 * case, we need to make sure at least the top level group stays. 0190 */ 0191 if ( ( groupsToAddTo.count () == 0 ) && ( groupsToRemoveFrom.contains ( Kopete::Group::topLevel () ) ) ) 0192 { 0193 groupsToRemoveFrom.removeAll ( Kopete::Group::topLevel () ); 0194 } 0195 0196 foreach ( Kopete::Group *group, groupsToRemoveFrom ) 0197 { 0198 qCDebug(JABBER_PROTOCOL_LOG) << "Removing " << contactId() << " from group " << group->displayName (); 0199 metaContact()->removeFromGroup ( group ); 0200 } 0201 0202 foreach ( Kopete::Group *group, groupsToAddTo ) 0203 { 0204 qCDebug(JABBER_PROTOCOL_LOG) << "Adding " << contactId() << " to group " << group->displayName (); 0205 metaContact()->addToGroup ( group ); 0206 } 0207 } 0208 0209 /* 0210 * Enable updates for the server again. 0211 */ 0212 setDontSync ( false ); 0213 0214 //can't do it now because it's called from contructor at a point some virtual function are not available 0215 QTimer::singleShot(0, this, SLOT(reevaluateStatus())); 0216 0217 } 0218 0219 void JabberBaseContact::updateResourceList () 0220 { 0221 /* 0222 * Set available resources. 0223 * This is a bit more complicated: We need to generate 0224 * all images dynamically from the KOS icons and store 0225 * them into the mime factory, then plug them into 0226 * the richtext. 0227 */ 0228 JabberResourcePool::ResourceList resourceList; 0229 account()->resourcePool()->findResources ( rosterItem().jid() , resourceList ); 0230 0231 if ( resourceList.isEmpty () ) 0232 { 0233 removeProperty ( protocol()->propAvailableResources ); 0234 return; 0235 } 0236 0237 QString resourceListStr = "<table cellspacing=\"0\">"; 0238 0239 for ( JabberResourcePool::ResourceList::iterator it = resourceList.begin (); it != resourceList.end (); ++it ) 0240 { 0241 // icon, resource name and priority 0242 resourceListStr += QString ( "<tr><td><img src=\"kopete-onlinestatus-icon:%1\" /> <b>%2</b> (Priority: %3)</td></tr>" ). 0243 arg ( protocol()->resourceToKOS((*it)->resource()).mimeSourceFor ( account () ), 0244 (*it)->resource().name (), QString::number ( (*it)->resource().priority () ) ); 0245 0246 // client name, version, OS 0247 if ( !(*it)->clientName().isEmpty () ) 0248 { 0249 resourceListStr += QString ( "<tr><td>%1: %2 (%3)</td></tr>" ). 0250 arg ( i18n ( "Client" ), (*it)->clientName (), (*it)->clientSystem () ); 0251 } 0252 0253 // Supported features 0254 #if 0 //disabled because it's just an ugly and long list of incomprehensible namespaces to the user 0255 QStringList supportedFeatures = (*it)->features().list(); 0256 QStringList::ConstIterator featuresIt, featuresItEnd = supportedFeatures.constEnd(); 0257 if( !supportedFeatures.empty() ) 0258 resourceListStr += QString( "<tr><td>Supported Features:" ); 0259 for( featuresIt = supportedFeatures.constBegin(); featuresIt != featuresItEnd; ++featuresIt ) 0260 { 0261 XMPP::Features tempFeature(*featuresIt); 0262 resourceListStr += QString("\n<br>"); 0263 if ( tempFeature.id() > XMPP::Features::FID_None ) 0264 resourceListStr += tempFeature.name() + QString(" ("); 0265 resourceListStr += *featuresIt; 0266 if ( tempFeature.id() > Features::FID_None ) 0267 resourceListStr += QString(")"); 0268 } 0269 if( !supportedFeatures.empty() ) 0270 resourceListStr += QString( "</td></tr>" ); 0271 #endif 0272 0273 // resource timestamp 0274 resourceListStr += QString ( "<tr><td>%1: %2</td></tr>" ). 0275 arg ( i18n ( "Timestamp" ), KLocale::global()->formatDateTime ( (*it)->resource().status().timeStamp(), KLocale::ShortDate, true ) ); 0276 0277 // message, if any 0278 if ( !(*it)->resource().status().status().trimmed().isEmpty () ) 0279 { 0280 resourceListStr += QString ( "<tr><td>%1: %2</td></tr>" ). 0281 arg ( 0282 i18n ( "Message" ), 0283 Kopete::Message::escape( (*it)->resource().status().status () ) 0284 ); 0285 } 0286 } 0287 0288 resourceListStr += "</table>"; 0289 0290 setProperty ( protocol()->propAvailableResources, resourceListStr ); 0291 } 0292 0293 void JabberBaseContact::reevaluateStatus () 0294 { 0295 qCDebug(JABBER_PROTOCOL_LOG) << "Determining new status for " << contactId (); 0296 0297 Kopete::OnlineStatus status; 0298 XMPP::Resource resource = account()->resourcePool()->bestResource ( mRosterItem.jid () ); 0299 0300 status = protocol()->resourceToKOS ( resource ); 0301 0302 0303 /* Add some icon to show the subscription */ 0304 if( ( mRosterItem.subscription().type() == XMPP::Subscription::None || mRosterItem.subscription().type() == XMPP::Subscription::From) 0305 && inherits ( "JabberContact" ) && metaContact() != Kopete::ContactList::self()->myself() && account()->isConnected() ) 0306 { 0307 status = Kopete::OnlineStatus(status.status() , 0308 status.weight() , 0309 protocol() , 0310 status.internalStatus() | 0x0100, 0311 status.overlayIcons() + QStringList("status_unknown_overlay") , //FIXME: find better icon 0312 status.description() ); 0313 } 0314 0315 0316 updateResourceList (); 0317 0318 qCDebug(JABBER_PROTOCOL_LOG) << "New status for " << contactId () << " is " << status.description (); 0319 setOnlineStatus ( status ); 0320 0321 /* 0322 * Set away message property. 0323 * We just need to read it from the current resource. 0324 */ 0325 setStatusMessage( resource.status().status() ); 0326 0327 } 0328 0329 QString JabberBaseContact::fullAddress () 0330 { 0331 0332 XMPP::Jid jid = rosterItem().jid(); 0333 0334 if ( jid.resource().isEmpty () ) 0335 { 0336 jid.setResource ( account()->resourcePool()->bestResource ( jid ).name () ); 0337 } 0338 0339 return jid.full (); 0340 0341 } 0342 0343 XMPP::Jid JabberBaseContact::bestAddress () 0344 { 0345 0346 // see if we are subscribed with a preselected resource 0347 if ( !mRosterItem.jid().resource().isEmpty () ) 0348 { 0349 // we have a preselected resource, so return our default full address 0350 return mRosterItem.jid (); 0351 } 0352 0353 // construct address out of user@host and current best resource 0354 XMPP::Jid jid = mRosterItem.jid (); 0355 jid.setResource ( account()->resourcePool()->bestResource( mRosterItem.jid() ).name () ); 0356 0357 return jid; 0358 0359 } 0360 0361 void JabberBaseContact::setDontSync ( bool flag ) 0362 { 0363 0364 mDontSync = flag; 0365 0366 } 0367 0368 bool JabberBaseContact::dontSync () 0369 { 0370 0371 return mDontSync; 0372 0373 } 0374 0375 void JabberBaseContact::serialize (QMap < QString, QString > &serializedData, QMap < QString, QString > & /* addressBookData */ ) 0376 { 0377 0378 // Contact id and display name are already set for us, only add the rest 0379 serializedData["JID"] = mRosterItem.jid().full(); 0380 0381 serializedData["groups"] = mRosterItem.groups ().join ( QLatin1String( QString::fromLatin1 ("," ))); 0382 } 0383 0384 void JabberBaseContact::slotUserInfo( ) 0385 { 0386 if ( !account()->isConnected () ) 0387 { 0388 account()->errorConnectFirst (); 0389 return; 0390 } 0391 0392 // Update the vCard 0393 //slotGetTimedVCard(); 0394 0395 new dlgJabberVCard ( account(), this, Kopete::UI::Global::mainWidget () ); 0396 } 0397 0398 void JabberBaseContact::setPropertiesFromVCard ( const XMPP::VCard &vCard ) 0399 { 0400 qCDebug(JABBER_PROTOCOL_LOG) << "Updating vCard for " << contactId (); 0401 0402 // update vCard cache timestamp if this is not a temporary contact 0403 if ( metaContact() && !metaContact()->isTemporary () ) 0404 { 0405 setProperty ( protocol()->propVCardCacheTimeStamp, QDateTime::currentDateTime().toString ( Qt::ISODate ) ); 0406 } 0407 0408 0409 /* 0410 * Set the nickname property. 0411 * but ignore it if we are in a groupchat, or it will clash with the normal nickname 0412 */ 0413 if(inherits ( "JabberContact" )) 0414 { 0415 if ( !vCard.nickName().isEmpty () ) 0416 { 0417 setProperty ( protocol()->propNickName, vCard.nickName () ); 0418 } 0419 else if ( !vCard.fullName().isEmpty () ) // google talk contacts for example do not have a nickname; better show fullname instead of jabber id 0420 { 0421 setProperty ( protocol()->propNickName, vCard.fullName () ); 0422 } 0423 else 0424 { 0425 removeProperty ( protocol()->propNickName ); 0426 } 0427 } 0428 0429 /** 0430 * Kopete does not allow a modification of the "full name" 0431 * property. However, some vCards specify only the full name, 0432 * some specify only first and last name. 0433 * Due to these inconsistencies, if first and last name don't 0434 * exist, it is attempted to parse the full name. 0435 */ 0436 0437 // remove all properties first 0438 removeProperty ( protocol()->propFirstName ); 0439 removeProperty ( protocol()->propLastName ); 0440 removeProperty ( protocol()->propFullName ); 0441 0442 if ( !vCard.fullName().isEmpty () && vCard.givenName().isEmpty () && vCard.familyName().isEmpty () ) 0443 { 0444 QString lastName = vCard.fullName().section ( ' ', 0, -1 ); 0445 QString firstName = vCard.fullName().left(vCard.fullName().length () - lastName.length ()).trimmed (); 0446 0447 setProperty ( protocol()->propFirstName, firstName ); 0448 setProperty ( protocol()->propLastName, lastName ); 0449 } 0450 else 0451 { 0452 if ( !vCard.givenName().isEmpty () ) 0453 setProperty ( protocol()->propFirstName, vCard.givenName () ); 0454 0455 if ( !vCard.familyName().isEmpty () ) 0456 setProperty ( protocol()->propLastName, vCard.familyName () ); 0457 } 0458 if( !vCard.fullName().isEmpty() ) 0459 setProperty ( protocol()->propFullName, vCard.fullName() ); 0460 0461 /* 0462 * Set the general information 0463 */ 0464 removeProperty( protocol()->propJid ); 0465 removeProperty( protocol()->propBirthday ); 0466 removeProperty( protocol()->propTimezone ); 0467 removeProperty( protocol()->propHomepage ); 0468 0469 setProperty( protocol()->propJid, vCard.jid() ); 0470 0471 if( !vCard.bdayStr().isEmpty () ) 0472 setProperty( protocol()->propBirthday, vCard.bdayStr() ); 0473 if( !vCard.timezone().isEmpty () ) 0474 setProperty( protocol()->propTimezone, vCard.timezone() ); 0475 if( !vCard.url().isEmpty () ) 0476 setProperty( protocol()->propHomepage, vCard.url() ); 0477 0478 /* 0479 * Set the work information. 0480 */ 0481 removeProperty( protocol()->propCompanyName ); 0482 removeProperty( protocol()->propCompanyDepartement ); 0483 removeProperty( protocol()->propCompanyPosition ); 0484 removeProperty( protocol()->propCompanyRole ); 0485 0486 if( !vCard.org().name.isEmpty() ) 0487 setProperty( protocol()->propCompanyName, vCard.org().name ); 0488 if( !vCard.org().unit.join( QLatin1String( "," )).isEmpty() ) 0489 setProperty( protocol()->propCompanyDepartement, vCard.org().unit.join( QLatin1String( "," ))) ; 0490 if( !vCard.title().isEmpty() ) 0491 setProperty( protocol()->propCompanyPosition, vCard.title() ); 0492 if( !vCard.role().isEmpty() ) 0493 setProperty( protocol()->propCompanyRole, vCard.role() ); 0494 0495 /* 0496 * Set the about information 0497 */ 0498 removeProperty( protocol()->propAbout ); 0499 0500 if( !vCard.desc().isEmpty() ) 0501 setProperty( protocol()->propAbout, vCard.desc() ); 0502 0503 0504 /* 0505 * Set the work and home addresses information 0506 */ 0507 removeProperty( protocol()->propWorkStreet ); 0508 removeProperty( protocol()->propWorkExtAddr ); 0509 removeProperty( protocol()->propWorkPOBox ); 0510 removeProperty( protocol()->propWorkCity ); 0511 removeProperty( protocol()->propWorkPostalCode ); 0512 removeProperty( protocol()->propWorkCountry ); 0513 0514 removeProperty( protocol()->propHomeStreet ); 0515 removeProperty( protocol()->propHomeExtAddr ); 0516 removeProperty( protocol()->propHomePOBox ); 0517 removeProperty( protocol()->propHomeCity ); 0518 removeProperty( protocol()->propHomePostalCode ); 0519 removeProperty( protocol()->propHomeCountry ); 0520 0521 for(XMPP::VCard::AddressList::const_iterator it = vCard.addressList().begin(); it != vCard.addressList().end(); it++) 0522 { 0523 XMPP::VCard::Address address = (*it); 0524 0525 if(address.work) 0526 { 0527 setProperty( protocol()->propWorkStreet, address.street ); 0528 setProperty( protocol()->propWorkExtAddr, address.extaddr ); 0529 setProperty( protocol()->propWorkPOBox, address.pobox ); 0530 setProperty( protocol()->propWorkCity, address.locality ); 0531 setProperty( protocol()->propWorkPostalCode, address.pcode ); 0532 setProperty( protocol()->propWorkCountry, address.country ); 0533 } 0534 else 0535 if(address.home) 0536 { 0537 setProperty( protocol()->propHomeStreet, address.street ); 0538 setProperty( protocol()->propHomeExtAddr, address.extaddr ); 0539 setProperty( protocol()->propHomePOBox, address.pobox ); 0540 setProperty( protocol()->propHomeCity, address.locality ); 0541 setProperty( protocol()->propHomePostalCode, address.pcode ); 0542 setProperty( protocol()->propHomeCountry, address.country ); 0543 } 0544 } 0545 0546 0547 /* 0548 * Delete emails first, they might not be present 0549 * in the vCard at all anymore. 0550 */ 0551 removeProperty ( protocol()->propEmailAddress ); 0552 removeProperty ( protocol()->propWorkEmailAddress ); 0553 0554 /* 0555 * Set the home and work email information. 0556 */ 0557 XMPP::VCard::EmailList::const_iterator emailEnd = vCard.emailList().end (); 0558 for(XMPP::VCard::EmailList::const_iterator it = vCard.emailList().begin(); it != emailEnd; ++it) 0559 { 0560 XMPP::VCard::Email email = (*it); 0561 0562 if(email.work) 0563 { 0564 if( !email.userid.isEmpty() ) 0565 setProperty ( protocol()->propWorkEmailAddress, email.userid ); 0566 } 0567 else 0568 if(email.home) 0569 { 0570 if( !email.userid.isEmpty() ) 0571 setProperty ( protocol()->propEmailAddress, email.userid ); 0572 } 0573 } 0574 0575 /* 0576 * Delete phone number properties first as they might have 0577 * been unset during an update and are not present in 0578 * the vCard at all anymore. 0579 */ 0580 removeProperty ( protocol()->propPrivatePhone ); 0581 removeProperty ( protocol()->propPrivateMobilePhone ); 0582 removeProperty ( protocol()->propWorkPhone ); 0583 removeProperty ( protocol()->propWorkMobilePhone ); 0584 0585 /* 0586 * Set phone numbers. Note that if a mobile phone number 0587 * is specified, it's assigned to the private mobile 0588 * phone number property. This might not be the desired 0589 * behavior for all users. 0590 */ 0591 XMPP::VCard::PhoneList::const_iterator phoneEnd = vCard.phoneList().end (); 0592 for(XMPP::VCard::PhoneList::const_iterator it = vCard.phoneList().begin(); it != phoneEnd; ++it) 0593 { 0594 XMPP::VCard::Phone phone = (*it); 0595 0596 if(phone.work) 0597 { 0598 setProperty ( protocol()->propWorkPhone, phone.number ); 0599 } 0600 else 0601 if(phone.fax) 0602 { 0603 setProperty ( protocol()->propPhoneFax, phone.number); 0604 } 0605 else 0606 if(phone.cell) 0607 { 0608 setProperty ( protocol()->propPrivateMobilePhone, phone.number ); 0609 } 0610 else 0611 if(phone.home) 0612 { 0613 setProperty ( protocol()->propPrivatePhone, phone.number ); 0614 } 0615 0616 } 0617 0618 /* 0619 * Set photo/avatar property. 0620 */ 0621 removeProperty( protocol()->propPhoto ); 0622 0623 QImage contactPhoto; 0624 0625 // photo() is a QByteArray 0626 if ( !vCard.photo().isEmpty() ) 0627 { 0628 qCDebug(JABBER_PROTOCOL_LOG) << "Contact has a photo embedded into his vCard."; 0629 0630 // QImage is used to save to disk in PNG later. 0631 contactPhoto = QImage::fromData( vCard.photo() ); 0632 } 0633 // Contact photo is a URI. 0634 else if( !vCard.photoURI().isEmpty() ) 0635 { 0636 QString tempPhotoPath = 0; 0637 0638 // Downalod photo from URI. 0639 if( !KIO::NetAccess::download( vCard.photoURI(), tempPhotoPath, 0) ) 0640 { 0641 KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget (), KMessageBox::Error, i18n( "Downloading of Jabber contact photo failed." ) ); 0642 return; 0643 } 0644 0645 0646 qCDebug(JABBER_PROTOCOL_LOG) << "Contact photo is a URI."; 0647 0648 contactPhoto = QImage( tempPhotoPath ); 0649 0650 KIO::NetAccess::removeTempFile( tempPhotoPath ); 0651 } 0652 0653 // add the entry using the avatar manager 0654 Kopete::AvatarManager::AvatarEntry entry; 0655 entry.name = contactId(); 0656 entry.image = contactPhoto; 0657 entry.category = Kopete::AvatarManager::Contact; 0658 entry.contact = this; 0659 entry = Kopete::AvatarManager::self()->add(entry); 0660 0661 // Save the image to the disk, then set the property. 0662 if(!entry.path.isNull()) 0663 { 0664 qCDebug(JABBER_PROTOCOL_LOG) << "Setting photo for contact: " << contactId(); 0665 setProperty( protocol()->propPhoto, entry.path ); 0666 } 0667 0668 } 0669 0670 #include "moc_jabberbasecontact.cpp" 0671 0672 // vim: set noet ts=4 sts=4 sw=4: