From 73f00336178a9f312bac2992649120d462e0ac2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Wed, 11 Dec 2019 01:41:26 +0100 Subject: kopete: Restore the MSN protocol because a replacement MSN server was created. This reverts commits 0486034738 - 2d5f9c55da and f6fd4ab6c0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slávek Banko --- kopete/protocols/msn/msncontact.cpp | 713 ++++++++++++++++++++++++++++++++++++ 1 file changed, 713 insertions(+) create mode 100644 kopete/protocols/msn/msncontact.cpp (limited to 'kopete/protocols/msn/msncontact.cpp') diff --git a/kopete/protocols/msn/msncontact.cpp b/kopete/protocols/msn/msncontact.cpp new file mode 100644 index 00000000..e58c3800 --- /dev/null +++ b/kopete/protocols/msn/msncontact.cpp @@ -0,0 +1,713 @@ +/* + msncontact.cpp - MSN Contact + + Copyright (c) 2002 by Duncan Mac-Vicar Prett + Copyright (c) 2002 by Ryan Cumming + Copyright (c) 2002-2003 by Martijn Klingens + Copyright (c) 2002-2005 by Olivier Goffart + Copyright (c) 2005 by Michaël Larouche + + Kopete (c) 2002-2005 by the Kopete developers + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include "msncontact.h" + +#include + +#undef KDE_NO_COMPAT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kopetecontactlist.h" +#include "kopetechatsessionmanager.h" +#include "kopetemetacontact.h" +#include "kopetegroup.h" +#include "kopeteuiglobal.h" +#include "kopeteglobal.h" + +#include "msninfo.h" +#include "msnchatsession.h" +#include "msnnotifysocket.h" +#include "msnaccount.h" + +MSNContact::MSNContact( Kopete::Account *account, const TQString &id, Kopete::MetaContact *parent ) +: Kopete::Contact( account, id, parent ) +{ + m_deleted = false; + m_allowed = false; + m_blocked = false; + m_reversed = false; + m_moving = false; + + m_clientFlags=0; + + setFileCapable( true ); + + // When we are not connected, it's because we are loading the contactlist. + // so we set the initial status to offline. + // We set offline directly because modifying the status after is too slow. + // (notification, contactlist updating,....) + // + // FIXME: Hacks like these shouldn't happen in the protocols, but should be + // covered properly at the libkopete level instead - Martijn + // + // When we are connected, it can be because the user added a contact with the + // wizard, and it can be because we are creating a temporary contact. + // if it's added by the wizard, the status will be set immediately after. + // if it's a temporary contact, better to set the unknown status. + setOnlineStatus( ( parent && parent->isTemporary() ) ? MSNProtocol::protocol()->UNK : MSNProtocol::protocol()->FLN ); + + actionBlock = 0L; + + setProperty(MSNProtocol::protocol()->propEmail, id); +} + +MSNContact::~MSNContact() +{ + kdDebug(14140) << k_funcinfo << endl; +} + +bool MSNContact::isReachable() +{ + if ( account()->isConnected() && isOnline() && account()->myself()->onlineStatus() != MSNProtocol::protocol()->HDN ) + return true; + + MSNChatSession *kmm=dynamic_cast(manager(Kopete::Contact::CannotCreate)); + if( kmm && kmm->service() ) //the chat socket is open. than mean message will be sent + return true; + + // When we are invisible we can't start a chat with others, make isReachable return false + // (This is an MSN limitation, not a problem in Kopete) + if ( !account()->isConnected() || account()->myself()->onlineStatus() == MSNProtocol::protocol()->HDN ) + return false; + + //if the contact is offline, it is impossible to send it a message. but it is impossible + //to be sure the contact is realy offline. For example, if the contact is not on the contactlist for + //some reason. + if( onlineStatus() == MSNProtocol::protocol()->FLN && ( isAllowed() || isBlocked() ) && !serverGroups().isEmpty() ) + return false; + + return true; +} + +Kopete::ChatSession *MSNContact::manager( Kopete::Contact::CanCreateFlags canCreate ) +{ + Kopete::ContactPtrList chatmembers; + chatmembers.append(this); + + Kopete::ChatSession *_manager = Kopete::ChatSessionManager::self()->findChatSession( account()->myself(), chatmembers, protocol() ); + MSNChatSession *manager = dynamic_cast( _manager ); + if(!manager && canCreate==Kopete::Contact::CanCreate) + { + manager = new MSNChatSession( protocol(), account()->myself(), chatmembers ); + static_cast( account() )->slotStartChatSession( contactId() ); + } + return manager; +} + +TQPtrList *MSNContact::customContextMenuActions() +{ + TQPtrList *m_actionCollection = new TQPtrList; + + // Block/unblock Contact + TQString label = isBlocked() ? i18n( "Unblock User" ) : i18n( "Block User" ); + if( !actionBlock ) + { + actionBlock = new TDEAction( label, "msn_blocked",0, this, TQT_SLOT( slotBlockUser() ), + this, "actionBlock" ); + + //show profile + actionShowProfile = new TDEAction( i18n("Show Profile") , 0, this, TQT_SLOT( slotShowProfile() ), + this, "actionShowProfile" ); + + // Send mail (only available if it is an hotmail account) + actionSendMail = new TDEAction( i18n("Send Email...") , "mail_generic",0, this, TQT_SLOT( slotSendMail() ), + this, "actionSendMail" ); + + // Invite to receive webcam + actionWebcamReceive = new TDEAction( i18n( "View Contact's Webcam" ), "webcamreceive", 0, this, TQT_SLOT(slotWebcamReceive() ), this, "msnWebcamReceive" ) ; + + //Send webcam action + actionWebcamSend = new TDEAction( i18n( "Send Webcam" ), "webcamsend", 0, this, TQT_SLOT(slotWebcamSend() ), this, "msnWebcamSend" ) ; + } + else + actionBlock->setText( label ); + + actionSendMail->setEnabled( static_cast(account())->isHotmail()); + + m_actionCollection->append( actionBlock ); + m_actionCollection->append( actionShowProfile ); + m_actionCollection->append( actionSendMail ); + m_actionCollection->append( actionWebcamReceive ); + m_actionCollection->append( actionWebcamSend ); + + + return m_actionCollection; +} + +void MSNContact::slotBlockUser() +{ + MSNNotifySocket *notify = static_cast( account() )->notifySocket(); + if( !notify ) + { + KMessageBox::error( Kopete::UI::Global::mainWidget(), + i18n( "Please go online to block or unblock a contact." ), + i18n( "MSN Plugin" )); + return; + } + + if( m_blocked ) + { + notify->removeContact( contactId(), MSNProtocol::BL, TQString(), TQString() ); + } + else + { + if(m_allowed) + notify->removeContact( contactId(), MSNProtocol::AL, TQString(), TQString() ); + else + notify->addContact( contactId(), MSNProtocol::BL, TQString(), TQString(), TQString() ); + } +} + +void MSNContact::slotUserInfo() +{ + KDialogBase *infoDialog=new KDialogBase( 0l, "infoDialog", /*modal = */false, TQString(), KDialogBase::Close , KDialogBase::Close, false ); + TQString nick=property( Kopete::Global::Properties::self()->nickName()).value().toString(); + TQString personalMessage=property( MSNProtocol::protocol()->propPersonalMessage).value().toString(); + MSNInfo *info=new MSNInfo ( infoDialog,"info"); + info->m_id->setText( contactId() ); + info->m_displayName->setText(nick); + info->m_personalMessage->setText(personalMessage); + info->m_phh->setText(m_phoneHome); + info->m_phw->setText(m_phoneWork); + info->m_phm->setText(m_phoneMobile); + info->m_reversed->setChecked(m_reversed); + + connect( info->m_reversed, TQT_SIGNAL(toggled(bool)) , this, TQT_SLOT(slotUserInfoDialogReversedToggled())); + + infoDialog->setMainWidget(info); + infoDialog->setCaption(nick); + infoDialog->show(); +} + +void MSNContact::slotUserInfoDialogReversedToggled() +{ + //workaround to make this checkboxe readonly + const TQCheckBox *cb=dynamic_cast(sender()); + if(cb && cb->isChecked()!=m_reversed) + const_cast(cb)->setChecked(m_reversed); +} + +void MSNContact::deleteContact() +{ + kdDebug( 14140 ) << k_funcinfo << endl; + + MSNNotifySocket *notify = static_cast( account() )->notifySocket(); + if( notify ) + { + if( hasProperty(MSNProtocol::protocol()->propGuid.key()) ) + { + // Remove from all groups he belongs (if applicable) + for( TQMap::Iterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it ) + { + kdDebug(14140) << k_funcinfo << "Removing contact from group \"" << it.key() << "\"" << endl; + notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() ); + } + + // Then trully remove it from server contact list, + // because only removing the contact from his groups isn't sufficent from MSNP11. + kdDebug( 14140 ) << k_funcinfo << "Removing contact from top-level." << endl; + notify->removeContact( contactId(), MSNProtocol::FL, guid(), TQString()); + } + else + { + kdDebug( 14140 ) << k_funcinfo << "The contact is already removed from server, just delete it" << endl; + deleteLater(); + } + } + else + { + // FIXME: This case should be handled by Kopete, not by the plugins :( - Martijn + // FIXME: We should be able to delete contacts offline, and remove it from server next time we go online - Olivier + KMessageBox::error( Kopete::UI::Global::mainWidget(), i18n( "Please go online to remove a contact from your contact list." ), i18n( "MSN Plugin" )); + } +} + +bool MSNContact::isBlocked() const +{ + return m_blocked; +} + +void MSNContact::setBlocked( bool blocked ) +{ + if( m_blocked != blocked ) + { + m_blocked = blocked; + //update the status + setOnlineStatus(m_currentStatus); + //m_currentStatus is used here. previously it was onlineStatus() but this may cause problem when + // the account is offline because of the Kopete::Contact::OnlineStatus() account offline hack. + } +} + +bool MSNContact::isAllowed() const +{ + return m_allowed; +} + +void MSNContact::setAllowed( bool allowed ) +{ + m_allowed = allowed; +} + +bool MSNContact::isReversed() const +{ + return m_reversed; +} + +void MSNContact::setReversed( bool reversed ) +{ + m_reversed= reversed; +} + +bool MSNContact::isDeleted() const +{ + return m_deleted; +} + +void MSNContact::setDeleted( bool deleted ) +{ + m_deleted= deleted; +} + +uint MSNContact::clientFlags() const +{ + return m_clientFlags; +} + +void MSNContact::setClientFlags( uint flags ) +{ + if(m_clientFlags != flags) + { + if(hasProperty( MSNProtocol::protocol()->propClient.key() )) + { + if( flags & MSNProtocol::WebMessenger) + setProperty( MSNProtocol::protocol()->propClient , i18n("Web Messenger") ); + else if( flags & MSNProtocol::WindowsMobile) + setProperty( MSNProtocol::protocol()->propClient , i18n("Windows Mobile") ); + else if( flags & MSNProtocol::MSNMobileDevice) + setProperty( MSNProtocol::protocol()->propClient , i18n("MSN Mobile") ); + else if( m_obj.contains("kopete") ) + setProperty( MSNProtocol::protocol()->propClient , i18n("Kopete") ); + } + + } + m_clientFlags=flags; +} + +void MSNContact::setInfo(const TQString &type,const TQString &data ) +{ + if( type == "PHH" ) + { + m_phoneHome = data; + setProperty(MSNProtocol::protocol()->propPhoneHome, data); + } + else if( type == "PHW" ) + { + m_phoneWork=data; + setProperty(MSNProtocol::protocol()->propPhoneWork, data); + } + else if( type == "PHM" ) + { + m_phoneMobile = data; + setProperty(MSNProtocol::protocol()->propPhoneMobile, data); + } + else if( type == "MOB" ) + { + if( data == "Y" ) + m_phone_mob = true; + else if( data == "N" ) + m_phone_mob = false; + else + kdDebug( 14140 ) << k_funcinfo << "Unknown MOB " << data << endl; + } + else if( type == "MFN" ) + { + setProperty(Kopete::Global::Properties::self()->nickName(), data ); + } + else + { + kdDebug( 14140 ) << k_funcinfo << "Unknow info " << type << " " << data << endl; + } +} + + +void MSNContact::serialize( TQMap &serializedData, TQMap & /* addressBookData */ ) +{ + // Contact id and display name are already set for us, only add the rest + TQString groups; + bool firstEntry = true; + for( TQMap::ConstIterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it ) + { + if( !firstEntry ) + { + groups += ","; + firstEntry = true; + } + groups += it.key(); + } + + TQString lists="C"; + if(m_blocked) + lists +="B"; + if(m_allowed) + lists +="A"; + if(m_reversed) + lists +="R"; + + serializedData[ "groups" ] = groups; + serializedData[ "PHH" ] = m_phoneHome; + serializedData[ "PHW" ] = m_phoneWork; + serializedData[ "PHM" ] = m_phoneMobile; + serializedData[ "lists" ] = lists; + serializedData[ "obj" ] = m_obj; + serializedData[ "contactGuid" ] = guid(); +} + + +TQString MSNContact::guid(){ return property(MSNProtocol::protocol()->propGuid).value().toString(); } + +TQString MSNContact::phoneHome(){ return m_phoneHome ;} +TQString MSNContact::phoneWork(){ return m_phoneWork ;} +TQString MSNContact::phoneMobile(){ return m_phoneMobile ;} + + +const TQMap MSNContact::serverGroups() const +{ + return m_serverGroups; +} +void MSNContact::clearServerGroups() +{ + m_serverGroups.clear(); +} + + +void MSNContact::sync( unsigned int changed ) +{ + if( ! (changed & Kopete::Contact::MovedBetweenGroup) ) + return; //we are only interested by a change in groups + + if(!metaContact() || metaContact()->isTemporary() ) + return; + + if(m_moving) + { + //We need to make sure that syncGroups is not called twice successively + // because m_serverGroups will be only updated with the reply of the server + // and then, the same command can be sent twice. + // FIXME: if this method is called a seconds times, that mean change can be + // done in the contactlist. we should found a way to recall this + // method later. (a TQTimer?) + kdDebug( 14140 ) << k_funcinfo << " This contact is already moving. Abort sync id: " << contactId() << endl; + return; + } + + MSNNotifySocket *notify = static_cast( account() )->notifySocket(); + if( !notify ) + { + //We are not connected, we will doing it next connection. + //Force to reload the whole contactlist from server to suync groups when connecting + account()->configGroup()->writeEntry("serial", 0 ); + return; + } + + if(m_deleted) //the contact hasn't been synced from server yet. + return; + + unsigned int count=m_serverGroups.count(); + + //Don't add the contact if it's myself. + if(count==0 && contactId() == account()->accountId()) + return; + + //STEP ONE : add the contact to every kopetegroups where the MC is + TQPtrList groupList = metaContact()->groups(); + for ( Kopete::Group *group = groupList.first(); group; group = groupList.next() ) + { + //For each group, ensure it is on the MSN server + if( !group->pluginData( protocol() , account()->accountId() + " id" ).isEmpty() ) + { + TQString Gid=group->pluginData( protocol(), account()->accountId() + " id" ); + if( !static_cast( account() )->m_groupList.contains(Gid) ) + { // ohoh! something is corrupted on the contactlist.xml + // anyway, we never should add a contact to an unexisting group on the server. + // This shouln't be possible anymore 2004-06-10 -Olivier + + //repair the problem + group->setPluginData( protocol() , account()->accountId() + " id" , TQString()); + group->setPluginData( protocol() , account()->accountId() + " displayName" , TQString()); + kdWarning( 14140 ) << k_funcinfo << " Group " << group->displayName() << " marked with id #" <displayName().isEmpty() && group->type() == Kopete::Group::Normal) //not the top-level + { + //Create the group and add the contact + static_cast( account() )->addGroup( group->displayName(),contactId() ); + count++; + m_moving=true; + } + } + else if( !m_serverGroups.contains(Gid) ) + { + //Add the contact to the group on the server + notify->addContact( contactId(), MSNProtocol::FL, TQString(), guid(), Gid ); + count++; + m_moving=true; + } + } + else + { + if(!group->displayName().isEmpty() && group->type() == Kopete::Group::Normal) //not the top-level + { + //Create the group and add the contact + static_cast( account() )->addGroup( group->displayName(),contactId() ); + + //WARNING: if contact is not correctly added (because the group was not aded corrdctly for hinstance), + // if we increment the count, the contact can be deleted from the old group, and be lost :-( + count++; + m_moving=true; + } + } + } + + //STEP TWO : remove the contact from groups where the MC is not, but let it at least in one group + + //contact is not in that group. on the server. we will remove them dirrectly after the loop + TQValueList removinglist; + + for( TQMap::Iterator it = m_serverGroups.begin();(count > 1 && it != m_serverGroups.end()); ++it ) + { + if( !static_cast( account() )->m_groupList.contains(it.key()) ) + { // ohoh! something is corrupted on the contactlist.xml + // anyway, we never should add a contact to an unexisting group on the server. + + //repair the problem ... //contactRemovedFromGroup( it.key() ); + // ... later (we can't remove it from the map now ) + removinglist.append(it.key()); + count--; + + kdDebug( 14140 ) << k_funcinfo << "the group marked with id #" << it.key() << " does not seems to be anymore on the server" << endl; + + continue; + } + + Kopete::Group *group=it.data(); + if(!group) //we can't trust the data of it() see in MSNProtocol::deserializeContact why + group=static_cast( account() )->m_groupList[it.key()]; + if( !metaContact()->groups().contains(group) ) + { + m_moving=true; + notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() ); + count--; + } + } + + for(TQValueList::Iterator it= removinglist.begin() ; it != removinglist.end() ; ++it ) + contactRemovedFromGroup(*it); + + //FINAL TEST: is the contact at least in a group.. + // this may happens if we just added a temporary contact to top-level + // we add the contact to the group #0 (the default one) + /*if(count==0) + { +// notify->addContact( contactId(), MSNProtocol::FL, TQString(), guid(), "0"); + }*/ +} + +void MSNContact::contactAddedToGroup( const TQString& groupId, Kopete::Group *group ) +{ + m_serverGroups.insert( groupId, group ); + m_moving=false; +} + +void MSNContact::contactRemovedFromGroup( const TQString& groupId ) +{ + m_serverGroups.remove( groupId ); + if(m_serverGroups.isEmpty() && !m_moving) + { + deleteLater(); + } + m_moving=false; +} + + +void MSNContact::rename( const TQString &newName ) +{ + //kdDebug( 14140 ) << k_funcinfo << "From: " << displayName() << ", to: " << newName << endl; + +/* if( newName == displayName() ) + return;*/ + + // FIXME: This should be called anymore. + MSNNotifySocket *notify = static_cast( account() )->notifySocket(); + if( notify ) + { + notify->changePublicName( newName, contactId() ); + } +} + +void MSNContact::slotShowProfile() +{ + KRun::runURL( KURL( TQString::fromLatin1("http://members.msn.com/?pgmarket=it-it&mem=") + contactId()) , "text/html" ); +} + + +/** + * FIXME: Make this a standard KMM API call + */ +void MSNContact::sendFile( const KURL &sourceURL, const TQString &altFileName, uint /*fileSize*/ ) +{ + TQString filePath; + + //If the file location is null, then get it from a file open dialog + if( !sourceURL.isValid() ) + filePath = KFileDialog::getOpenFileName( TQString() ,"*", 0l , i18n( "Kopete File Transfer" )); + else + filePath = sourceURL.path(-1); + + //kdDebug(14140) << "MSNContact::sendFile: File chosen to send:" << fileName << endl; + + if ( !filePath.isEmpty() ) + { + TQ_UINT32 fileSize = TQFileInfo(filePath).size(); + //Send the file + static_cast( manager(Kopete::Contact::CanCreate) )->sendFile( filePath, altFileName, fileSize ); + + } +} + +void MSNContact::setOnlineStatus(const Kopete::OnlineStatus& status) +{ + if(isBlocked() && status.internalStatus() < 15) + { + Kopete::Contact::setOnlineStatus( + Kopete::OnlineStatus(status.status() , + (status.weight()==0) ? 0 : (status.weight() -1) , + protocol() , + status.internalStatus()+15 , + status.overlayIcons() + TQStringList("msn_blocked") , + i18n("%1|Blocked").arg( status.description() ) ) ); + } + else if(!isBlocked() && status.internalStatus() >= 15) + { //the user is not blocked, but the status is blocked + switch(status.internalStatus()-15) + { + case 1: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->NLN); + break; + case 2: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->BSY); + break; + case 3: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->BRB); + break; + case 4: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->AWY); + break; + case 5: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->PHN); + break; + case 6: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->LUN); + break; + case 7: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->FLN); + break; + case 8: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->HDN); + break; + case 9: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->IDL); + break; + default: + Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->UNK); + break; + } + } + else + Kopete::Contact::setOnlineStatus(status); + m_currentStatus=status; +} + +void MSNContact::slotSendMail() +{ + MSNNotifySocket *notify = static_cast( account() )->notifySocket(); + if( notify ) + { + notify->sendMail( contactId() ); + } +} + +void MSNContact::setDisplayPicture(KTempFile *f) +{ + //copy the temp file somewere else. + // in a better world, the file could be dirrectly wrote at the correct location. + // but the custom emoticon code is to deeply merged in the display picture code while it could be separated. + TQString newlocation=locateLocal( "appdata", "msnpictures/"+ contactId().lower().replace(TQRegExp("[./~]"),"-") +".png" ) ; + + TDEIO::Job *j=TDEIO::file_move( KURL::fromPathOrURL( f->name() ) , KURL::fromPathOrURL( newlocation ) , -1, true /*overwrite*/ , false /*resume*/ , false /*showProgressInfo*/ ); + + f->setAutoDelete(false); + delete f; + + //let the time to TDEIO to copy the file + connect(j, TQT_SIGNAL(result(TDEIO::Job *)) , this, TQT_SLOT(slotEmitDisplayPictureChanged() )); +} + +void MSNContact::slotEmitDisplayPictureChanged() +{ + TQString newlocation=locateLocal( "appdata", "msnpictures/"+ contactId().lower().replace(TQRegExp("[./~]"),"-") +".png" ) ; + setProperty( Kopete::Global::Properties::self()->photo() , newlocation ); + emit displayPictureChanged(); +} + +void MSNContact::setObject(const TQString &obj) +{ + if(m_obj==obj && (obj.isEmpty() || hasProperty(Kopete::Global::Properties::self()->photo().key()))) + return; + + m_obj=obj; + + removeProperty( Kopete::Global::Properties::self()->photo() ) ; + emit displayPictureChanged(); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "MSN" ); + if ( config->readNumEntry( "DownloadPicture", 2 ) >= 2 && !obj.isEmpty() + && account()->myself()->onlineStatus().status() != Kopete::OnlineStatus::Invisible ) + manager(Kopete::Contact::CanCreate); //create the manager which will download the photo automatically. +} + +#include "msncontact.moc" + +// vim: set noet ts=4 sts=4 sw=4: + -- cgit v1.2.1