diff --git a/CMakeLists.txt b/CMakeLists.txt
index 337df7c9..589cc6f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,6 +72,7 @@ option( WITH_SLP "Enable OpenSLP support (krdc, krfb)" OFF )
option( BUILD_KOPETE_PROTOCOL_ALL "Build all kopete protocols" OFF )
option( BUILD_KOPETE_PROTOCOL_TESTBED "Build kopete protocol testbed" ${BUILD_KOPETE_PROTOCOL_ALL} )
option( BUILD_KOPETE_PROTOCOL_GROUPWISE "Build kopete protocol groupwise" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_MSN "Build kopete protocol msn" ${BUILD_KOPETE_PROTOCOL_ALL} )
option( BUILD_KOPETE_PROTOCOL_IRC "Build kopete protocol irc" ${BUILD_KOPETE_PROTOCOL_ALL} )
option( BUILD_KOPETE_PROTOCOL_OSCAR "Build kopete protocol oscar" ${BUILD_KOPETE_PROTOCOL_ALL} )
option( BUILD_KOPETE_PROTOCOL_YAHOO "Build kopete protocol yahoo" ${BUILD_KOPETE_PROTOCOL_ALL} )
diff --git a/doc/kopete/chatstyle.docbook b/doc/kopete/chatstyle.docbook
index 93bee59e..991bee25 100644
--- a/doc/kopete/chatstyle.docbook
+++ b/doc/kopete/chatstyle.docbook
@@ -224,7 +224,7 @@ This is the name of the contact associated with the message. It use MetaContact
%service%
-Display the name of the service associated with the message. Examples: Jabber, Yahoo.
+Display the name of the service associated with the message. Examples: Jabber, Yahoo, MSN.
diff --git a/doc/kopete/index.docbook b/doc/kopete/index.docbook
index acbaaf3e..ce6741ee 100644
--- a/doc/kopete/index.docbook
+++ b/doc/kopete/index.docbook
@@ -106,6 +106,7 @@ Appendix: Chat Window Style Guide (1st draft, Michaël)
Messaging
Jabber
IRC
+MSN
ICQ
AIM
Yahoo
@@ -167,7 +168,7 @@ Appendix: Chat Window Style Guide (1st draft, Michaël)
To use &kopete; you need to set up one or more accounts for the instant messaging services you wish to use.
You've probably already chosen a messaging service, either because you already use &im;, or you need to use the same service as your friends. If you don't fit into either of these categories, please consider using a messaging service based on open standards, because these are designed for use by Free Software. Other messaging services are prone to changing the underlying technology without making the details freely available, making them harder for Free Software developers to support.
The messaging services that &kopete; supports that are based on open standards are Jabber and IRC.
-The following section assumes you are registered with an &im; service already. If not, you can register with Gadu-Gadu and Jabber from inside &kopete;; for other services, you'll have to register using their respective web site before creating an account in &kopete;.
+The following section assumes you are registered with an &im; service already. If not, you can register with Gadu-Gadu, Jabber, and MSN from inside &kopete;; for other services, you'll have to register using their respective web site before creating an account in &kopete;.
Creating Accounts
To create an account, use Settings Configure &kopete;... to display the Configure window.
@@ -698,6 +699,11 @@ Shortcuts....
ICQ
ICQ has an Invisibility feature which allows you to hide from selected contacts. You may also search the ICQ user directory when adding a contact. A wide range of contact details can be set using the Properties option.
+
+ MSN
+ MSN supports the sending and receiving of webcams, if your camera is supported by the Video4Linux 2 (v4l2) standard. To view someone's webcam, right click on their MSN buttefly icon and select View Contact's Webcam. File transfer and multi user chats work. To transfer a file, drag the file from Konqueror or the desktop into the chat window. To invite someone else into a chat, drag them from the Contact List into the chat window. The File menu also contains these commands. In addition, MSN supports custom emoticons.
+ To use file transfer or a webcam, make sure port 6891 is forwarded to your computer.
+
Yahoo
Yahoo can send and receive webcam video. It also supports Yahoo mail and the Yahoo addressbook from the account menu. Conferencing is also possible.
@@ -895,7 +901,7 @@ Shortcuts....
I need to connect via a SOCKS proxy, but I can't find any proxy configuration options in &kopete;. How do I set up &kopete; to use SOCKS?
-ICQ, AIM, Jabber, and Yahoo use the &kde; network infrastructure. Their SOCKS proxy details are configured with the rest of &kde;, in Control Center, Internet & NetworkProxy.
+MSN, ICQ, AIM, Jabber, and Yahoo use the &kde; network infrastructure. Their SOCKS proxy details are configured with the rest of &kde;, in Control Center, Internet & NetworkProxy.
diff --git a/kopete/ConfigureChecks.cmake b/kopete/ConfigureChecks.cmake
index 44939818..d4c97769 100644
--- a/kopete/ConfigureChecks.cmake
+++ b/kopete/ConfigureChecks.cmake
@@ -9,8 +9,8 @@
#
#################################################
-# glib-2.0 (jabber)
-if( BUILD_KOPETE_PROTOCOL_JABBER AND WITH_JINGLE )
+# glib-2.0 (jabber, msn)
+if( (BUILD_KOPETE_PROTOCOL_JABBER AND WITH_JINGLE) OR (BUILD_KOPETE_PROTOCOL_MSN AND WITH_WEBCAM) )
pkg_search_module( GLIB2 glib-2.0 )
if( GLIB2_FOUND )
set( HAVE_GLIB 1 CACHE INTERNAL "" FORCE )
diff --git a/kopete/KABC_INTEG_NOTES b/kopete/KABC_INTEG_NOTES
index 87d22977..ea053dbe 100644
--- a/kopete/KABC_INTEG_NOTES
+++ b/kopete/KABC_INTEG_NOTES
@@ -38,7 +38,7 @@ E.g. we know someones telephone nr. but we don't want to put this information ba
brunes goals
the only points I wanted to make were
-1. I think the OSCAR picture support should somehow integrate with / use the picture in kaddressbook, and
+1. I think the MSN / OSCAR picture support should somehow integrate with / use the picture in kaddressbook, and
2. we need to get the KAB guys to add >1 field for IM account in KAB, and all the contacts for a MC should have their accounts there
Syncing policies
diff --git a/kopete/TODO b/kopete/TODO
index eab40274..e9a7a594 100644
--- a/kopete/TODO
+++ b/kopete/TODO
@@ -75,4 +75,16 @@ OSCAR ICQ/AIM TODO ITEMS
of AIM to take over just that part of the plugin.
+================================================================================
+
+
+ MSN TODO (for the Kopete 1.0 release)
+---------------------------------------
+
+ - Handle the MSN PLUS! color codes
+ - Show internals messages in chat window when filetransfers (go with
+ the new interface for invitation in libkopete)
+
+ - Search for an MSN User (not for Kopete 1.0)
+
================================================================================
diff --git a/kopete/kopete/eventsrc b/kopete/kopete/eventsrc
index 8e3216cc..9d3cf2f7 100644
--- a/kopete/kopete/eventsrc
+++ b/kopete/kopete/eventsrc
@@ -997,6 +997,181 @@ Comment[zh_HK]=您的 Yahoo 收件匣有新郵件
Comment[zh_TW]=新郵件送達您的 Yahoo 收件匣
default_presentation=16
+[msn_alert]
+Name=MSN Alert
+Name[bg]=MSN съобщение
+Name[ca]=Alerta del MSN
+Name[cs]=MSN upozornění
+Name[da]=MSN-alarm
+Name[de]=MSN-Warnung
+Name[el]=Ειδοποίηση του MSN
+Name[es]=Alerta MSN
+Name[et]=MSN teade
+Name[fa]=هشدار اماسان
+Name[fi]=MSN-varoitus
+Name[fr]=Alerte MSN
+Name[he]=אזהרה של MSN
+Name[hu]=MSN értesítő
+Name[is]=MSN skeyti
+Name[it]=Avviso MSN
+Name[km]=សេចក្ដីជូនដំណឹង MSN
+Name[lt]=MSN: „dėmesio!“
+Name[nb]=MSN-varsling
+Name[nds]=MSN-Alarm
+Name[ne]=एमएसएन सावधानी
+Name[nl]=MSN-melding
+Name[pa]=MSN ਚੇਤਾਵਨੀ
+Name[pl]=Alarm MSN
+Name[pt]=Alerta MSN
+Name[pt_BR]=Alerta do MSN
+Name[ru]=Предупреждение MSN
+Name[sk]=MSN Upozornenie
+Name[sl]=Alarm MSN
+Name[sr]=MSN аларм
+Name[sr@Latn]=MSN alarm
+Name[sv]=MSN-larm
+Name[tr]=MSN Uyarısı
+Name[uk]=Сигнал MSN
+Name[zh_CN]=MSN 提醒
+Name[zh_TW]=MSN 警告
+Comment=A new alert has been sent to you
+Comment[bg]=Изпратено ви е ново съобщение
+Comment[ca]=Se us ha enviat una nova alerta
+Comment[cs]=Bylo vám doručeno nové upozornění
+Comment[da]=En ny alarm er sendt til dig
+Comment[de]=Sie haben eine neue Warnung erhalten
+Comment[el]=Σας στάλθηκε μια νέα ειδοποίηση
+Comment[es]=Se le ha enviado una nueva alerta
+Comment[et]=Sulle saadeti uus teade
+Comment[fa]=هشدار جدیدی برای شما ارسال شده است
+Comment[fi]=Sinulle on lähetetty uusi varoitus
+Comment[fr]=Une nouvelle alerte vous a été envoyée
+Comment[he]=אזהרה חדשה נשלחה אליך
+Comment[hu]=Új értesítőt küldtek Önnek
+Comment[is]=Þér hefur verið sent nýtt skeyti
+Comment[it]=Ti è stato inviato un avviso
+Comment[ja]=新しいアラートを受信しました
+Comment[km]=បានផ្ញើសេចក្ដីជូនដំណឹងទៅឲ្យអ្នក
+Comment[lt]=Jums pasiųstas naujas „dėmesio!“ signalas
+Comment[nb]=En ny varsling er sendt til deg
+Comment[nds]=Een hett Di en niegen Alarm sendt
+Comment[ne]=तपाईँलाई एउटा नयाँ सावधानी सन्देश पठाएको छ
+Comment[nl]=U hebt een nieuwe melding ontvangen
+Comment[pl]=Nowy alarm został wysłany do Ciebie
+Comment[pt]=Foi enviada um novo alerta
+Comment[pt_BR]=Um novo alerta foi enviado para você
+Comment[ru]=Вам отправлено предупреждение
+Comment[sk]=Bolo vám poslané nové upozornenie
+Comment[sl]=Poslan vam je bil alarm
+Comment[sr]=Послат вам је нови аларм
+Comment[sr@Latn]=Poslat vam je novi alarm
+Comment[sv]=Ett nytt larm har skickats till dig
+Comment[tr]=Size yeni bir uyarı gönderildi
+Comment[uk]=Вам було відіслано новий сигнал
+Comment[zh_CN]=您收到了新提醒
+Comment[zh_TW]=一個新的警告已送達給您
+default_presentation=16
+
+[msn_mail]
+Name=MSN Mail
+Name[ar]=بريد MSN
+Name[be]=Пошта MSN
+Name[bg]=Пристигна нова поща в MSN
+Name[bn]=এমএসএন মেইল
+Name[br]=Postel MSN
+Name[bs]=MSN mail
+Name[ca]=Correu de MSN
+Name[cs]=MSN pošta
+Name[da]=MSN-Mail
+Name[de]=MSN-Mail
+Name[es]=Correo MSN
+Name[fa]=نامۀ اماسان
+Name[fi]=MSN-sähköposti
+Name[fr]=Courriel MSN
+Name[gl]=Correo MSN
+Name[he]=דוא"ל של MSN
+Name[hi]=एमएसएन मेल
+Name[hr]=MSN pošta
+Name[hu]=MSN e-mail
+Name[is]=MSN póstur
+Name[it]=Posta MSN
+Name[ja]=MSN メール
+Name[ka]=MSN ფოსტა
+Name[kk]=MSN поштасы
+Name[km]=សំបុត្រ MSN
+Name[lt]=MSN Paštas
+Name[mk]=MSN-пошта
+Name[nb]=MSN e-post
+Name[nds]=MSN-Nettpost
+Name[ne]=एमएसएन मेल
+Name[nn]=MSN-e-post
+Name[pa]=MSN ਮੇਲ
+Name[pl]=Poczta MSN
+Name[pt]=E-mail MSN
+Name[ru]=Почта MSN
+Name[sl]=E-pošta MSN
+Name[sr]=MSN пошта
+Name[sr@Latn]=MSN pošta
+Name[sv]=MSN e-post
+Name[ta]=MSN மின்னஞ்சல்
+Name[tg]=Пости MSN
+Name[tr]=MSN Posta
+Name[uk]=Пошта MSN
+Name[zh_CN]=MSN 邮件
+Comment=New email has arrived in your MSN inbox
+Comment[be]=У вашай электроннай скрыні MSN новая пошта
+Comment[bg]=Пристигна нова поща в MSN
+Comment[bn]=আপনার এমএসএন ইনবক্সে নতুন ই-মেইল উপস্থিত হয়েছে
+Comment[br]=Deuet eo ur postel nevez d'em voest degemer MSN
+Comment[bs]=Stigla je nova pošta u vaš MSN sandučić
+Comment[ca]=Ha arribat un nou correu a la vostra bústia de MSN
+Comment[cs]=Přišla nová pošta do vaší MSN schránky
+Comment[da]=Ny e-mail ankom til din MSN-indbakke
+Comment[de]=Eine neue Nachricht befindet sich im MSN-Eingangsordner
+Comment[el]=Μόλις έφτασε νέο e-mail στα εισερχόμενα του MSN σας
+Comment[eo]=Nova poŝto ricevita
+Comment[es]=Tiene correo nuevo en la cuenta de MSN
+Comment[et]=Saabus uus kiri sinu MSN Inboxi
+Comment[eu]=E-posta berri bat jaso da zure MSN-ko sarrerako ontzian
+Comment[fa]=یک رایانامۀ جدید در دریافتی اماسان شما رسیده است
+Comment[fi]=Uutta postia saapunut MSN-sähköpostilaatikkoon
+Comment[fr]=Un nouveau message est arrivé dans votre boîte aux lettres MSN
+Comment[gl]=Unha nova mensaxe chegou ao teu cartafol de entrada de MSN
+Comment[he]=התקבל עבורך דואר חדש בתיבת הדוא"ל של MSN
+Comment[hr]=Nova pošta je stigla u vaš MSN sandučić
+Comment[hu]=Új levél érkezett az MSN postaládába
+Comment[is]=Það er nýr póstur í MSN innhólfinu þínu
+Comment[it]=È arrivata nuova posta nella tua casella MSN
+Comment[ja]=MSN の受信箱に新しいメールが届きました
+Comment[ka]=ახალი ელფოსტა მოვიდა MSN საფოსტო ყუთში
+Comment[kk]=MSN пошта жәшігне хабарлама келді
+Comment[km]=អ៊ីមែលថ្មីបានមកដល់ក្នុងប្រអប់ទទួល MSN របស់អ្នកហើយ
+Comment[lt]=Į MSN pašto dėžutę gautas naujas laiškas
+Comment[mk]=Пристигна нова пошта во вашето MSN-сандаче
+Comment[nb]=Ny e-post er ankommet i MSN-innboksen
+Comment[nds]=Du hest niege Nettpost in Dien MSN-Postingang
+Comment[ne]=तपाईँको एमएसएन पत्रमञ्जूषामा नयाँ इमेल छ
+Comment[nl]=Er is een nieuwe e-mail aangekomen in uw MSN-inbox
+Comment[nn]=Ny e-post er komen til MSN-innboksen
+Comment[pl]=Nadeszła nowa wiadomość do Twojej skrzynki odbiorczej w MSN
+Comment[pt]=Chegou uma mensagem nova à sua caixa de correio do MSN
+Comment[pt_BR]=chegou um novo e-mail em sua caixa de entrada MSN
+Comment[ru]=Пришли новые письма в MSN
+Comment[se]=Ođđa e-boasta lea boahtán du MSN-boastaboksii
+Comment[sk]=Do vašej schránky MSN prišla nová správa
+Comment[sl]=Nova e-pošta je prispela v vaš nabiralnik MSN
+Comment[sr]=Нова порука је стигла у ваше MSN сандуче
+Comment[sr@Latn]=Nova poruka je stigla u vaše MSN sanduče
+Comment[sv]=Ett nytt brev har anlänt i din MSN-inkorg
+Comment[ta]=உங்கள் எம்எஸ்என் அஞ்சல் பெட்டிக்கு புதிய மின்னஞ்சல் வந்துள்ளது
+Comment[tg]=Ба қутии пости MSN-и шумо пайёми электронии нав омад
+Comment[tr]=MSN gelen kutunuza yeni bir e-posta geldi
+Comment[uk]=Прийшли нові листи у вашу скриньку MSN
+Comment[zh_CN]=您的 MSN 收件箱中有新邮件到达
+Comment[zh_HK]=您的 MSN 收件匣有新郵件
+Comment[zh_TW]=新郵件送達您的 MSN 收件匣
+default_presentation=16
+
[icq_authorization]
Name=ICQ Authorization
Name[be]=Спраўджванне асобы ICQ
diff --git a/kopete/kopete/kimiface.h b/kopete/kopete/kimiface.h
index 970d9698..b6413f29 100644
--- a/kopete/kopete/kimiface.h
+++ b/kopete/kopete/kimiface.h
@@ -107,7 +107,7 @@ k_dcop:
* Get the KABC uid corresponding to the supplied IM address
* Protocols should be
* @param contactId the protocol specific identifier for the contact, eg UIN for ICQ, screenname for AIM, nick for IRC.
- * @param protocol the protocol, eg one of "AIMProtocol", "ICQProtocol",
+ * @param protocol the protocol, eg one of "AIMProtocol", "MSNProtocol", "ICQProtocol",
* @return a KABC uid or null if none found/
*/
virtual TQString locate( const TQString & contactId, const TQString & protocol ) = 0;
@@ -167,7 +167,7 @@ k_dcop:
/**
* Add a contact to the contact list
* @param contactId the protocol specific identifier for the contact, eg UIN for ICQ, screenname for AIM, nick for IRC.
- * @param protocol the protocol, eg one of "AIMProtocol", "ICQProtocol", ...
+ * @param protocol the protocol, eg one of "AIMProtocol", "MSNProtocol", "ICQProtocol", ...
* @return whether the add succeeded. False may signal already present, protocol not supported, or add operation not supported.
*/
virtual bool addContact( const TQString &contactId, const TQString &protocol ) = 0;
diff --git a/kopete/kopete/kopeteiface.h b/kopete/kopete/kopeteiface.h
index d715018e..f68c3c57 100644
--- a/kopete/kopete/kopeteiface.h
+++ b/kopete/kopete/kopeteiface.h
@@ -105,13 +105,13 @@ k_dcop:
/**
* load a plugin
- * the name is the name of the library: example: kopete_icq
+ * the name is the name of the library: example: kopete_msn
* but you can ommit the kopete_ prefix
*/
bool loadPlugin( const TQString& name );
/**
* unload a plugin
- * the name is the name of the library: example: kopete_icq
+ * the name is the name of the library: example: kopete_msn
* but you can ommit the kopete_ prefix
*/
bool unloadPlugin( const TQString& name );
diff --git a/kopete/kopete/tdeconf_update/kopete-account-tdeconf_update.cpp b/kopete/kopete/tdeconf_update/kopete-account-tdeconf_update.cpp
index 67b39ad8..42ba47f1 100644
--- a/kopete/kopete/tdeconf_update/kopete-account-tdeconf_update.cpp
+++ b/kopete/kopete/tdeconf_update/kopete-account-tdeconf_update.cpp
@@ -55,7 +55,7 @@ void parseGroup( const TQString &group, const TQString &rawLine )
{
// Groups that are converted can almost certainly be removed entirely
- if ( group == "ICQ" || group == "Oscar" || group == "Gadu" || group == "Jabber" || group == "IRC" )
+ if ( group == "MSN" || group == "ICQ" || group == "Oscar" || group == "Gadu" || group == "Jabber" || group == "IRC" )
{
accountId = "EMPTY";
autoConnect = "true";
@@ -82,7 +82,21 @@ void parseGroup( const TQString &group, const TQString &rawLine )
void parseKey( const TQString &group, const TQString &key, const TQString &value, const TQString &rawLine )
{
//qcerr << "*** group='" << group << "'" << endl;
- if ( group == "ICQ" )
+ if ( group == "MSN" )
+ {
+ if ( key == "UserID" )
+ accountId = value;
+ else if ( key == "Password" )
+ password = value;
+ else if ( key == "AutoConnect" )
+ autoConnect = value;
+ else if ( key == "Nick" )
+ pluginData[ "displayName" ] = value;
+
+ // All other keys are ignored for MSN, as these apply to stuff that's
+ // now in libkopete (and the main app) instead.
+ }
+ else if ( group == "ICQ" )
{
if ( key == "UIN" )
accountId = value;
diff --git a/kopete/libkopete/API-TODO b/kopete/libkopete/API-TODO
index c9684b8a..4914b00c 100644
--- a/kopete/libkopete/API-TODO
+++ b/kopete/libkopete/API-TODO
@@ -85,7 +85,8 @@ KCL::selectedGroups can be removed outright.
Allow emoticons and emoticon sets to be flagged as being for only a specific protocol.
Allow the user to have more than one emoticon set enabled at once, and to set priorities.
-This way, the user will be able to have a base theme, a set of Gadu-Gadu-specific emoticons and so on.
+This way, the user will be able to have a base theme, a set of MSN-specific emoticons, a
+set of Gadu-Gadu-specific emoticons and so on.
Possibly move emoticon support into a plugin?
diff --git a/kopete/libkopete/kopeteawaydialog.h b/kopete/libkopete/kopeteawaydialog.h
index 0f4aaa29..b9470af9 100644
--- a/kopete/libkopete/kopeteawaydialog.h
+++ b/kopete/libkopete/kopeteawaydialog.h
@@ -128,7 +128,7 @@ public slots:
* Shows the away dialog, but maintains a "state"
* so you can specify if you're setting away,
* do not disturb, gone, etc for protocols that
- * support this like ICQ.
+ * support this like ICQ and MSN.
*
* This string does not have any special internal
* meaning, but rather will get passed to setAway()
diff --git a/kopete/libkopete/kopetecontact.h b/kopete/libkopete/kopetecontact.h
index b92322f5..f8a6052d 100644
--- a/kopete/libkopete/kopetecontact.h
+++ b/kopete/libkopete/kopetecontact.h
@@ -79,7 +79,7 @@ public:
* Across those boundaries ids may occur multiple times.
* The id is solely for comparing items safely (using pointers is
* more crash-prone). DO NOT assume anything regarding the id's
- * value! Even if it may look like an ICQ UIN,
+ * value! Even if it may look like an ICQ UIN or an MSN passport,
* this is undefined and may change at any time!
*
* @param account is the parent account. this constructor automatically register the contact to the account
@@ -106,7 +106,7 @@ public:
* Across those boundaries ids may occur multiple times.
* The id is solely for comparing items safely (using pointers is
* more crash-prone). DO NOT assume anything regarding the id's
- * value! Even if it may look like an ICQ UIN,
+ * value! Even if it may look like an ICQ UIN or an MSN passport,
* this is undefined and may change at any time!
*
* @return The unique id of the contact
@@ -274,7 +274,7 @@ public:
/**
* Returns the primary message manager affiliated with this contact
* Although a contact can have more than one active message manager
- * only one message manager will
+ * (as is the case with MSN at least), only one message manager will
* ever be the contacts "primary" message manager.. aka the 1 on 1 chat.
* This function should always return that instance.
*
diff --git a/kopete/libkopete/kopetecontactlist.cpp b/kopete/libkopete/kopetecontactlist.cpp
index dc8cdeb1..f8aecb32 100644
--- a/kopete/libkopete/kopetecontactlist.cpp
+++ b/kopete/libkopete/kopetecontactlist.cpp
@@ -358,6 +358,11 @@ void ContactList::slotPhotoChanged()
emit globalIdentityChanged(Kopete::Global::Properties::self()->photo().key(), myself()->picture().path());
mutex=false;
+ /* The mutex is usefull to don't have such as stack overflow
+ Kopete::ContactList::slotPhotoChanged -> Kopete::ContactList::globalIdentityChanged
+ MSNAccount::slotGlobalIdentityChanged -> Kopete::Contact::propertyChanged
+ Kopete::MetaContact::slotPropertyChanged -> Kopete::MetaContact::photoChanged -> Kopete::ContactList::slotPhotoChanged
+ */
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -517,7 +522,7 @@ void ContactList::convertContactList( const TQString &fileName, uint /* fromVers
{
// Convert address book fields.
// Jabber will be called "xmpp", Aim/Toc and Aim/Oscar both will
- // be called "aim". AIM, IRC, Oscar and SMS don't use address
+ // be called "aim". MSN, AIM, IRC, Oscar and SMS don't use address
// book fields yet; Gadu and ICQ can be converted as-is.
// As Yahoo is unfinished we won't try to convert at all.
TQString id = oldContactElement.attribute( TQString::fromLatin1( "id" ), TQString() );
@@ -607,7 +612,12 @@ void ContactList::convertContactList( const TQString &fileName, uint /* fromVers
bool convertOldAim = false;
uint fieldCount = 1;
TQString addressBookLabel;
- if( id == TQString::fromLatin1("IRCProtocol") )
+ if( id == TQString::fromLatin1("MSNProtocol") )
+ {
+ fieldCount = 3;
+ addressBookLabel = TQString::fromLatin1("msn");
+ }
+ else if( id == TQString::fromLatin1("IRCProtocol") )
{
fieldCount = 3;
addressBookLabel = TQString::fromLatin1("irc");
@@ -647,7 +657,7 @@ void ContactList::convertContactList( const TQString &fileName, uint /* fromVers
}
// Do the actual conversion
- if ( id == TQString::fromLatin1( "OscarProtocol" ) ||
+ if( id == TQString::fromLatin1( "MSNProtocol" ) || id == TQString::fromLatin1( "OscarProtocol" ) ||
id == TQString::fromLatin1( "AIMProtocol" ) || id == TQString::fromLatin1( "IRCProtocol" ) ||
id == TQString::fromLatin1( "ICQProtocol" ) || id == TQString::fromLatin1( "JabberProtocol" ) ||
id == TQString::fromLatin1( "SMSProtocol" ) || id == TQString::fromLatin1( "WPProtocol" ) ||
@@ -689,7 +699,14 @@ void ContactList::convertContactList( const TQString &fileName, uint /* fromVers
else
dataField.appendChild( newList.createTextNode( strList[ idx + 1 ] ) );
- if( id == TQString::fromLatin1("IRCProtocol") )
+ if( id == TQString::fromLatin1("MSNProtocol") )
+ {
+ dataField = newList.createElement( TQString::fromLatin1( "plugin-data-field" ) );
+ pluginData[ id ].appendChild( dataField );
+ dataField.setAttribute( TQString::fromLatin1( "key" ), TQString::fromLatin1( "groups" ) );
+ dataField.appendChild( newList.createTextNode( strList[ idx + 2 ] ) );
+ }
+ else if( id == TQString::fromLatin1("IRCProtocol") )
{
dataField = newList.createElement( TQString::fromLatin1( "plugin-data-field" ) );
pluginData[ id ].appendChild( dataField );
@@ -725,7 +742,7 @@ void ContactList::convertContactList( const TQString &fileName, uint /* fromVers
idx += 2;
}
- // AIM, IRC, Oscar and SMS didn't store address book fields up
+ // MSN, AIM, IRC, Oscar and SMS didn't store address book fields up
// to now, so create one
if( id != TQString::fromLatin1("ICQProtocol") && id != TQString::fromLatin1("JabberProtocol") && id != TQString::fromLatin1("WPProtocol") && id != TQString::fromLatin1("GaduProtocol") )
{
diff --git a/kopete/libkopete/kopetemetacontact.h b/kopete/libkopete/kopetemetacontact.h
index b7f9fbc7..15d82228 100644
--- a/kopete/libkopete/kopetemetacontact.h
+++ b/kopete/libkopete/kopetemetacontact.h
@@ -483,7 +483,7 @@ public slots:
*
* Like sendMessage, but this time a full-blown chat will be opened.
* Most protocols can't distinguish between the two and are either
- * completely session based like ICQ or completely message based like
+ * completely session based like MSN or completely message based like
* ICQ the only true difference is the GUI shown to the user.
*
* returns the Contact that was chosen as the preferred
diff --git a/kopete/libkopete/kopeteonlinestatus.h b/kopete/libkopete/kopeteonlinestatus.h
index dbdae1ff..6ad34c55 100644
--- a/kopete/libkopete/kopeteonlinestatus.h
+++ b/kopete/libkopete/kopeteonlinestatus.h
@@ -74,7 +74,10 @@ public:
/**
* Refers to protocols where state cannot be determined. This
* applies to SMS contacts (text messages via mobile phones),
- * since there's no presence information over SMS. Lastly, libkopete
+ * since there's no presence information over SMS, but also
+ * to e.g. MSN contacts that are not on your contact list,
+ * since MSN only allows a user to query online state for
+ * users that are formally on the contact list. Lastly, libkopete
* itself uses the Unknown state in @ref MetaContact for
* meta contacts that have no child contacts at all.
*/
diff --git a/kopete/plugins/CMakeLists.txt b/kopete/plugins/CMakeLists.txt
index f8eb63fc..a5c6b08c 100644
--- a/kopete/plugins/CMakeLists.txt
+++ b/kopete/plugins/CMakeLists.txt
@@ -22,6 +22,7 @@ tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_TEXTEFFECT texteffect )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_HIGHLIGHT highlight )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_ALIAS alias )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_MOTIONAUTOAWAY motionautoaway )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_NETMEETING netmeeting )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_ADDBOOKMARKS addbookmarks )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_STATISTICS statistics )
tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_SMPPPDCS smpppdcs )
diff --git a/kopete/plugins/Makefile.am b/kopete/plugins/Makefile.am
index ca0d0188..8b817465 100644
--- a/kopete/plugins/Makefile.am
+++ b/kopete/plugins/Makefile.am
@@ -8,5 +8,5 @@ endif
SUBDIRS = latex autoreplace history contactnotes cryptography\
connectionstatus translator nowlistening webpresence texteffect\
- highlight alias $(MOTIONAUTOAWAY_SUBDIR) addbookmarks\
+ highlight alias $(MOTIONAUTOAWAY_SUBDIR) netmeeting addbookmarks\
statistics $(SMPPPDCS_SUBDIR)
diff --git a/kopete/plugins/history/converter.cpp b/kopete/plugins/history/converter.cpp
index a3c6580a..c63833e8 100644
--- a/kopete/plugins/history/converter.cpp
+++ b/kopete/plugins/history/converter.cpp
@@ -68,7 +68,13 @@ void HistoryPlugin::convertOldHistory()
if(accountId.isNull() || protocolId.isNull())
{
- if(fi->fileName() == "ICQProtocol" || fi->fileName() == "icq_logs" )
+ if(fi->fileName() == "MSNProtocol" || fi->fileName() == "msn_logs" )
+ {
+ protocolId="MSNProtocol";
+ TDEGlobal::config()->setGroup("MSN");
+ accountId=TDEGlobal::config()->readEntry( "UserID" );
+ }
+ else if(fi->fileName() == "ICQProtocol" || fi->fileName() == "icq_logs" )
{
protocolId="ICQProtocol";
TDEGlobal::config()->setGroup("ICQ");
@@ -319,7 +325,9 @@ bool HistoryPlugin::detectOldHistory()
if( dynamic_cast( Kopete::PluginManager::self()->plugin( fi->fileName() ) ) )
return true;
- if(fi->fileName() == "ICQProtocol" || fi->fileName() == "icq_logs" )
+ if(fi->fileName() == "MSNProtocol" || fi->fileName() == "msn_logs" )
+ return true;
+ else if(fi->fileName() == "ICQProtocol" || fi->fileName() == "icq_logs" )
return true;
else if(fi->fileName() == "AIMProtocol" || fi->fileName() == "aim_logs" )
return true;
diff --git a/kopete/plugins/latex/latexplugin.cpp b/kopete/plugins/latex/latexplugin.cpp
index 8c6e0ad8..2773d21f 100644
--- a/kopete/plugins/latex/latexplugin.cpp
+++ b/kopete/plugins/latex/latexplugin.cpp
@@ -178,6 +178,7 @@ void LatexPlugin::slotMessageAboutToShow( Kopete::Message& msg )
void LatexPlugin::slotMessageAboutToSend( Kopete::Message& msg)
{
Q_UNUSED(msg)
+ //disabled because to work correctly, we need to find what special has the gif we can send over MSN
#if 0
TDEConfig *config = TDEGlobal::config();
config->setGroup("Latex Plugin");
@@ -188,6 +189,8 @@ void LatexPlugin::slotMessageAboutToSend( Kopete::Message& msg)
TQString messageText = msg.plainBody();
if( !messageText.contains("$$"))
return;
+/* if( msg.from()->protocol()->pluginId()!="MSNProtocol" )
+ return;*/
// this searches for $$formula$$
TQRegExp rg("^\\s*\\$\\$([^$]+)\\$\\$\\s*$");
@@ -223,6 +226,7 @@ TQString LatexPlugin::handleLatex(const TQString &latexFormula)
TQString argumentRes = "-r %1x%2";
TQString argumentOut = "-o %1";
+ //TQString argumentFormat = "-fgif"; //we uses gif format because MSN only handle gif
int hDPI, vDPI;
hDPI = LatexConfig::self()->horizontalDPI();
vDPI = LatexConfig::self()->verticalDPI();
diff --git a/kopete/plugins/netmeeting/CMakeLists.txt b/kopete/plugins/netmeeting/CMakeLists.txt
new file mode 100644
index 00000000..dfda84e3
--- /dev/null
+++ b/kopete/plugins/netmeeting/CMakeLists.txt
@@ -0,0 +1,56 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+if( NOT BUILD_KOPETE_PROTOCOL_MSN )
+ tde_message_fatal( "netmeeting plugin needs msn protocol.\n Add -DBUILD_KOPETE_PROTOCOL_MSN=ON to cmake flags." )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/protocols/msn
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_netmeeting.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_netmeeting_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/tdeconfiguredialog )
+install( FILES netmeetingchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_netmeeting )
+
+
+##### kopete_netmeeting (module) ################
+
+tde_add_kpart( kopete_netmeeting AUTOMOC
+ SOURCES
+ netmeetingplugin.cpp netmeetinginvitation.cpp
+ netmeetingguiclient.cpp
+ LINK kopete_msn_shared-shared kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_netmeeting (module) ############
+
+tde_add_kpart( kcm_kopete_netmeeting AUTOMOC
+ SOURCES
+ netmeetingprefs_ui.ui netmeetingpreferences.cpp
+ LINK tdeutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/netmeeting/Makefile.am b/kopete/plugins/netmeeting/Makefile.am
new file mode 100644
index 00000000..54b08a5b
--- /dev/null
+++ b/kopete/plugins/netmeeting/Makefile.am
@@ -0,0 +1,23 @@
+METASOURCES = AUTO
+
+AM_CPPFLAGS = $(KOPETE_INCLUDES) -I$(top_srcdir)/kopete/protocols/msn $(all_includes)
+
+kde_module_LTLIBRARIES = kopete_netmeeting.la kcm_kopete_netmeeting.la
+
+kopete_netmeeting_la_SOURCES = netmeetingplugin.cpp netmeetinginvitation.cpp netmeetingguiclient.cpp
+kopete_netmeeting_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+kopete_netmeeting_la_LIBADD = $(top_builddir)/kopete/libkopete/libkopete.la $(top_builddir)/kopete/protocols/msn/libkopete_msn_shared.la
+
+service_DATA = kopete_netmeeting.desktop
+servicedir = $(kde_servicesdir)
+
+mydatadir = $(kde_datadir)/kopete_netmeeting
+mydata_DATA = netmeetingchatui.rc
+
+kcm_kopete_netmeeting_la_SOURCES = netmeetingprefs_ui.ui netmeetingpreferences.cpp
+kcm_kopete_netmeeting_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+kcm_kopete_netmeeting_la_LIBADD = $(LIB_KOPETECOMPAT) $(LIB_TDEUTILS)
+
+
+kcm_DATA = kopete_netmeeting_config.desktop
+kcmdir = $(kde_servicesdir)/tdeconfiguredialog
diff --git a/kopete/plugins/netmeeting/kopete_netmeeting.desktop b/kopete/plugins/netmeeting/kopete_netmeeting.desktop
new file mode 100644
index 00000000..5c697fbe
--- /dev/null
+++ b/kopete/plugins/netmeeting/kopete_netmeeting.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Type=Service
+X-Kopete-Version=1000900
+Icon=phone
+ServiceTypes=Kopete/Plugin
+X-TDE-Library=kopete_netmeeting
+X-TDE-PluginInfo-Author=Olivier Goffart
+X-TDE-PluginInfo-Email=ogoffart@tiscalinet.be
+X-TDE-PluginInfo-Name=kopete_netmeeting
+X-TDE-PluginInfo-Version=0.8.0
+X-TDE-PluginInfo-Website=http://kopete.kde.org
+X-TDE-PluginInfo-Category=Plugins
+X-TDE-PluginInfo-Depends=kopete_msn
+X-TDE-PluginInfo-License=GPL
+X-TDE-PluginInfo-EnabledByDefault=false
+Name=Netmeeting
+Name[ar]=الاجتماع على الشبكة
+Name[bg]=Видео чат
+Name[bn]=নেট মিটিং
+Name[da]=Netmøde
+Name[eo]=Reta renkontiĝo
+Name[fa]=نت میتینگ
+Name[fr]=Vidéo-conférence
+Name[hi]=नेटमीटिंग
+Name[ja]=ネットミーティング
+Name[km]=ប្រជុំលើបណ្ដាញ
+Name[lt]=Bendravimas tinkle
+Name[nds]=Nettmööt
+Name[ne]=नेट मिटिङ
+Name[nl]=NetMeeting
+Name[pa]=ਨੈੱਟ-ਮੀਟਿੰਗ
+Name[sv]=Nätverksmöte
+Name[ta]=இணைய சந்திப்பு
+Name[tg]=Вохӯриҳои шабакавӣ
+Comment=Voice and Video with MSN Messenger
+Comment[be]=Гук і відэа праз MSN Messenger
+Comment[bg]=Приставка за разговор с глас и видео с MSN Messenger
+Comment[bn]=এমএসএন বার্তাবাহকের সঙ্গে স্বর এবং ভিডিও
+Comment[bs]=Glas i video sa MSN Messengerom
+Comment[ca]=Veu i vídeo amb MSN Messenger
+Comment[cs]=Hlas a video pomocí MSN Messenger
+Comment[da]=Stemme og video med MSN Messenger
+Comment[de]=Sprache und Video mit dem MSN-Messenger verwenden
+Comment[el]=Βίντεο και εικόνα με το MSN Messenger
+Comment[es]=Voz y vídeo con MSN Messenger
+Comment[et]=Audio ja video kasutamine MSN Messengeriga
+Comment[eu]=Ahotsa eta bideoa MSN Messenger-ekin
+Comment[fa]=ویدیو و صدا با پیامرسان اماسان
+Comment[fi]=Ääni ja videokuva MSN Messengerin kanssa
+Comment[fr]=Voix et vidéo avec MSN Messenger
+Comment[gl]=Voz e video con MSN Messenger
+Comment[he]=חוזי ושמע עם MSN Messenger
+Comment[hu]=Hang és videó az MSN Messengerrel
+Comment[is]=Hljóð og vídeó með MSN Messenger
+Comment[it]=Voce e video con MSN Messenger
+Comment[ja]=MSN メッセンジャーとボイス/ビデオチャット
+Comment[ka]=ხმა და ვიდეო MSN მესინჯერთან
+Comment[kk]=MSN Messenger дыбыс пен бейнемен
+Comment[km]=សំឡេង និងវីដេអូដោយប្រើកម្មវិធីផ្ញើសារ MSN
+Comment[lt]=Bendravimas balsu ir vaizdu per MSN Messenger
+Comment[mk]=Глас и видео со Гласникот на MSN
+Comment[nb]=Lyd og bilde med MSN Messenger
+Comment[nds]=Spraak un Video mit dat MSN-Kortnarichtenprogramm
+Comment[ne]=एमएसएन मेसेन्जरसँग आवाज र भिडियो
+Comment[nl]=Beeld en geluid met MSN Messenger
+Comment[nn]=Lyd og bilete med MSN Messenger
+Comment[pl]=Głos i wideo za pomocą MSN Messenger
+Comment[pt]=Voz e Vídeo com o MSN Messenger
+Comment[pt_BR]=Voz e Vídeo com o MSN Messenger
+Comment[ru]=Аудио и видео с MSN Messenger
+Comment[sk]=Hlas a video pomocou MSN Messenger
+Comment[sl]=Glas in video z MSN Messenger
+Comment[sr]=Глас и видео са MSN Messenger-ом
+Comment[sr@Latn]=Glas i video sa MSN Messenger-om
+Comment[sv]=Ljud och video med MSN Messenger
+Comment[ta]=எம்எஸ்என் செய்தியில் குரல் மற்றும் படக்காட்சி
+Comment[tr]=MSN Messenger ile Video ve Ses
+Comment[uk]=Аудіо і відео з MSN Messenger
+Comment[zh_CN]=与 MSN Messenger 一起使用影音
+Comment[zh_HK]=和 MSN Messenger 一起使用語音和視像
+Comment[zh_TW]=MSN Messenger 影像與聲音
diff --git a/kopete/plugins/netmeeting/kopete_netmeeting_config.desktop b/kopete/plugins/netmeeting/kopete_netmeeting_config.desktop
new file mode 100644
index 00000000..0d266c03
--- /dev/null
+++ b/kopete/plugins/netmeeting/kopete_netmeeting_config.desktop
@@ -0,0 +1,77 @@
+[Desktop Entry]
+Icon=highlight
+Type=Service
+ServiceTypes=TDECModule
+
+X-TDE-ModuleType=Library
+X-TDE-Library=kopete_netmeeting
+X-TDE-FactoryName=NetmeetingConfigFactory
+X-TDE-ParentApp=kopete_netmeeting
+X-TDE-ParentComponents=kopete_netmeeting
+
+Name=Netmeeting
+Name[ar]=الاجتماع على الشبكة
+Name[bg]=Видео чат
+Name[bn]=নেট মিটিং
+Name[da]=Netmøde
+Name[eo]=Reta renkontiĝo
+Name[fa]=نت میتینگ
+Name[fr]=Vidéo-conférence
+Name[hi]=नेटमीटिंग
+Name[ja]=ネットミーティング
+Name[km]=ប្រជុំលើបណ្ដាញ
+Name[lt]=Bendravimas tinkle
+Name[nds]=Nettmööt
+Name[ne]=नेट मिटिङ
+Name[nl]=NetMeeting
+Name[pa]=ਨੈੱਟ-ਮੀਟਿੰਗ
+Name[sv]=Nätverksmöte
+Name[ta]=இணைய சந்திப்பு
+Name[tg]=Вохӯриҳои шабакавӣ
+Comment=Voice and Video with MSN Messenger
+Comment[be]=Гук і відэа праз MSN Messenger
+Comment[bg]=Приставка за разговор с глас и видео с MSN Messenger
+Comment[bn]=এমএসএন বার্তাবাহকের সঙ্গে স্বর এবং ভিডিও
+Comment[bs]=Glas i video sa MSN Messengerom
+Comment[ca]=Veu i vídeo amb MSN Messenger
+Comment[cs]=Hlas a video pomocí MSN Messenger
+Comment[da]=Stemme og video med MSN Messenger
+Comment[de]=Sprache und Video mit dem MSN-Messenger verwenden
+Comment[el]=Βίντεο και εικόνα με το MSN Messenger
+Comment[es]=Voz y vídeo con MSN Messenger
+Comment[et]=Audio ja video kasutamine MSN Messengeriga
+Comment[eu]=Ahotsa eta bideoa MSN Messenger-ekin
+Comment[fa]=ویدیو و صدا با پیامرسان اماسان
+Comment[fi]=Ääni ja videokuva MSN Messengerin kanssa
+Comment[fr]=Voix et vidéo avec MSN Messenger
+Comment[gl]=Voz e video con MSN Messenger
+Comment[he]=חוזי ושמע עם MSN Messenger
+Comment[hu]=Hang és videó az MSN Messengerrel
+Comment[is]=Hljóð og vídeó með MSN Messenger
+Comment[it]=Voce e video con MSN Messenger
+Comment[ja]=MSN メッセンジャーとボイス/ビデオチャット
+Comment[ka]=ხმა და ვიდეო MSN მესინჯერთან
+Comment[kk]=MSN Messenger дыбыс пен бейнемен
+Comment[km]=សំឡេង និងវីដេអូដោយប្រើកម្មវិធីផ្ញើសារ MSN
+Comment[lt]=Bendravimas balsu ir vaizdu per MSN Messenger
+Comment[mk]=Глас и видео со Гласникот на MSN
+Comment[nb]=Lyd og bilde med MSN Messenger
+Comment[nds]=Spraak un Video mit dat MSN-Kortnarichtenprogramm
+Comment[ne]=एमएसएन मेसेन्जरसँग आवाज र भिडियो
+Comment[nl]=Beeld en geluid met MSN Messenger
+Comment[nn]=Lyd og bilete med MSN Messenger
+Comment[pl]=Głos i wideo za pomocą MSN Messenger
+Comment[pt]=Voz e Vídeo com o MSN Messenger
+Comment[pt_BR]=Voz e Vídeo com o MSN Messenger
+Comment[ru]=Аудио и видео с MSN Messenger
+Comment[sk]=Hlas a video pomocou MSN Messenger
+Comment[sl]=Glas in video z MSN Messenger
+Comment[sr]=Глас и видео са MSN Messenger-ом
+Comment[sr@Latn]=Glas i video sa MSN Messenger-om
+Comment[sv]=Ljud och video med MSN Messenger
+Comment[ta]=எம்எஸ்என் செய்தியில் குரல் மற்றும் படக்காட்சி
+Comment[tr]=MSN Messenger ile Video ve Ses
+Comment[uk]=Аудіо і відео з MSN Messenger
+Comment[zh_CN]=与 MSN Messenger 一起使用影音
+Comment[zh_HK]=和 MSN Messenger 一起使用語音和視像
+Comment[zh_TW]=MSN Messenger 影像與聲音
diff --git a/kopete/plugins/netmeeting/netmeetingchatui.rc b/kopete/plugins/netmeeting/netmeetingchatui.rc
new file mode 100644
index 00000000..b0d139ae
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingchatui.rc
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/kopete/plugins/netmeeting/netmeetingguiclient.cpp b/kopete/plugins/netmeeting/netmeetingguiclient.cpp
new file mode 100644
index 00000000..bf457b90
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingguiclient.cpp
@@ -0,0 +1,61 @@
+/*
+ netmeetingguiclient.cpp
+
+ Kopete NetMeeting plugin
+
+ Copyright (c) 2003-2004 by Olivier Goffart
+
+ Kopete (c) 2003-2004 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "msnchatsession.h"
+#include "msncontact.h"
+
+#include "netmeetingguiclient.h"
+#include "netmeetinginvitation.h"
+
+class NetMeetingPlugin;
+
+NetMeetingGUIClient::NetMeetingGUIClient( MSNChatSession *parent, const char *name )
+: TQObject( parent, name ) , KXMLGUIClient(parent)
+{
+ setInstance(KGenericFactory::instance());
+ m_manager=parent;
+
+ new TDEAction( i18n( "Invite to Use NetMeeting" ), 0, this, TQT_SLOT( slotStartInvitation() ), actionCollection() , "netmeeting" ) ;
+
+ setXMLFile("netmeetingchatui.rc");
+}
+
+NetMeetingGUIClient::~NetMeetingGUIClient()
+{
+
+}
+
+void NetMeetingGUIClient::slotStartInvitation()
+{
+ TQPtrList c=m_manager->members();
+ NetMeetingInvitation *i=new NetMeetingInvitation(false, static_cast(c.first()),m_manager);
+ m_manager->initInvitation(i);
+}
+
+#include "netmeetingguiclient.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/plugins/netmeeting/netmeetingguiclient.h b/kopete/plugins/netmeeting/netmeetingguiclient.h
new file mode 100644
index 00000000..882a7759
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingguiclient.h
@@ -0,0 +1,61 @@
+/*
+ netmeetingguiclient.h
+
+ Kopete NetMeeting Plugin
+
+ Copyright (c) 2003 by Olivier Goffart
+
+ Kopete (c) 2003 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef TRANSLATORGUICLIENT_H
+#define TRANSLATORGUICLIENT_H
+
+#include
+#include
+
+namespace Kopete { class ChatSession; }
+class MSNChatSession;
+class NetMeetingPlugin;
+
+/**
+ * @author Olivier Goffart
+ */
+
+class NetMeetingGUIClient : public TQObject , public KXMLGUIClient
+{
+ Q_OBJECT
+
+
+public:
+ NetMeetingGUIClient( MSNChatSession *parent, const char *name=0L);
+ ~NetMeetingGUIClient();
+
+private slots:
+ void slotStartInvitation();
+
+private:
+ MSNChatSession *m_manager;
+ NetMeetingPlugin *m_plugin;
+};
+
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: k&r
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/plugins/netmeeting/netmeetinginvitation.cpp b/kopete/plugins/netmeeting/netmeetinginvitation.cpp
new file mode 100644
index 00000000..b42f9e93
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetinginvitation.cpp
@@ -0,0 +1,183 @@
+/*
+ msninvitation.cpp
+
+ Copyright (c) 2003 by Olivier Goffart
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "netmeetinginvitation.h"
+
+#include "kopeteuiglobal.h"
+
+#include "msnchatsession.h"
+#include "msnswitchboardsocket.h"
+#include "msncontact.h"
+#include "kopetemetacontact.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+
+NetMeetingInvitation::NetMeetingInvitation(bool incoming, MSNContact *c, TQObject *parent)
+ : TQObject(parent) , MSNInvitation( incoming, NetMeetingInvitation::applicationID() , i18n("NetMeeting") )
+{
+ m_contact=c;
+ oki=false;
+}
+
+
+NetMeetingInvitation::~NetMeetingInvitation()
+{
+}
+
+
+TQString NetMeetingInvitation::invitationHead()
+{
+ TQTimer::singleShot( 10*60000, this, TQT_SLOT( slotTimeout() ) ); //send TIMEOUT in 10 minute if the invitation has not been accepted/refused
+ return TQString( MSNInvitation::invitationHead()+
+ "Session-Protocol: SM1\r\n"
+ "Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME i don't know what is the session id
+ "\r\n").utf8();
+}
+
+void NetMeetingInvitation::parseInvitation(const TQString& msg)
+{
+ TQRegExp rx("Invitation-Command: ([A-Z]*)");
+ rx.search(msg);
+ TQString command=rx.cap(1);
+ if( msg.contains("Invitation-Command: INVITE") )
+ {
+ MSNInvitation::parseInvitation(msg); //for the cookie
+
+ unsigned int result = KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
+ i18n("%1 wants to start a chat with NetMeeting; do you want to accept it? " ).arg(m_contact->metaContact()->displayName()),
+ i18n("MSN Plugin") , i18n("Accept"),i18n("Refuse"));
+
+ MSNChatSession* manager=dynamic_cast(m_contact->manager());
+
+ if(manager && manager->service())
+ {
+ if(result==3) // Yes == 3
+ {
+ TQCString message=TQString(
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
+ "\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
+ "Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME
+ "Session-Protocol: SM1\r\n"
+ "Launch-Application: TRUE\r\n"
+ "Request-Data: IP-Address:\r\n"
+ "IP-Address: " + manager->service()->getLocalIP()+ "\r\n"
+ "\r\n" ).utf8();
+
+
+ manager->service()->sendCommand( "MSG" , "N", true, message );
+ oki=false;
+ TQTimer::singleShot( 10* 60000, this, TQT_SLOT( slotTimeout() ) ); //TIMOUT afte 10 min
+ }
+ else //No
+ {
+ manager->service()->sendCommand( "MSG" , "N", true, rejectMessage() );
+ emit done(this);
+ }
+ }
+ }
+ else if( msg.contains("Invitation-Command: ACCEPT") )
+ {
+ if( ! incoming() )
+ {
+ MSNChatSession* manager=dynamic_cast(m_contact->manager());
+ if(manager && manager->service())
+ {
+ TQCString message=TQString(
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
+ "\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
+ "Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME: what is session id?
+ "Session-Protocol: SM1\r\n"
+ "Launch-Application: TRUE\r\n"
+ "Request-Data: IP-Address:\r\n"
+ "IP-Address: " + manager->service()->getLocalIP() + "\r\n"
+ "\r\n" ).utf8();
+ manager->service()->sendCommand( "MSG" , "N", true, message );
+ }
+ rx=TQRegExp("IP-Address: ([0-9\\:\\.]*)");
+ rx.search(msg);
+ TQString ip_address = rx.cap(1);
+ startMeeting(ip_address);
+ kdDebug() << k_funcinfo << ip_address << endl;
+ }
+ else
+ {
+ rx=TQRegExp("IP-Address: ([0-9\\:\\.]*)");
+ rx.search(msg);
+ TQString ip_address = rx.cap(1);
+
+ startMeeting(ip_address);
+ }
+ }
+ else //CANCEL
+ {
+ emit done(this);
+ }
+}
+
+void NetMeetingInvitation::slotTimeout()
+{
+ if(oki)
+ return;
+
+ MSNChatSession* manager=dynamic_cast(m_contact->manager());
+
+ if(manager && manager->service())
+ {
+ manager->service()->sendCommand( "MSG" , "N", true, rejectMessage("TIMEOUT") );
+ }
+ emit done(this);
+
+}
+
+
+void NetMeetingInvitation::startMeeting(const TQString & ip_address)
+{
+ //TODO: use TDEProcess
+
+ TDEConfig *config=TDEGlobal::config();
+ config->setGroup("Netmeeting Plugin");
+ TQString app=config->readEntry("NetmeetingApplication","ekiga -c callto://%1").arg(ip_address);
+
+ kdDebug() << k_funcinfo << app << endl ;
+
+ TQStringList args=TQStringList::split(" ", app);
+
+ TDEProcess p;
+ for(TQStringList::Iterator it=args.begin() ; it != args.end() ; ++it)
+ {
+ p << *it;
+ }
+ p.start();
+}
+
+#include "netmeetinginvitation.moc"
+
+
+
+
diff --git a/kopete/plugins/netmeeting/netmeetinginvitation.h b/kopete/plugins/netmeeting/netmeetinginvitation.h
new file mode 100644
index 00000000..8bf88e96
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetinginvitation.h
@@ -0,0 +1,57 @@
+/*
+ netmeetinginvitation.cpp
+
+ Copyright (c) 2003 by Olivier Goffart
+
+ Kopete (c) 2003 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+#ifndef MSNVOICEINVITATION_H
+#define MSNVOICEINVITATION_H
+
+#include
+#include "msninvitation.h"
+
+class MSNContact;
+
+/**
+ *@author Olivier Goffart
+ */
+class NetMeetingInvitation : public TQObject , public MSNInvitation
+{
+Q_OBJECT
+
+public:
+ NetMeetingInvitation(bool incoming ,MSNContact*, TQObject *parent = 0);
+ ~NetMeetingInvitation();
+
+ static TQString applicationID() { return "44BBA842-CC51-11CF-AAFA-00AA00B6015C"; }
+ TQString invitationHead();
+
+ virtual void parseInvitation(const TQString& invitation);
+
+ virtual TQObject* object() { return this; }
+
+signals:
+ void done( MSNInvitation * );
+
+private slots:
+ void slotTimeout();
+
+private:
+ MSNContact *m_contact;
+ bool oki;
+ void startMeeting(const TQString & ip_address);
+
+};
+
+
+#endif
diff --git a/kopete/plugins/netmeeting/netmeetingplugin.cpp b/kopete/plugins/netmeeting/netmeetingplugin.cpp
new file mode 100644
index 00000000..17dfcc0b
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingplugin.cpp
@@ -0,0 +1,91 @@
+/*
+ netmeetingplugin.cpp
+
+ Copyright (c) 2003-2004 by Olivier Goffart
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "netmeetingplugin.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "kopetepluginmanager.h"
+#include "kopetechatsessionmanager.h"
+
+#include "msnchatsession.h"
+#include "msnprotocol.h"
+#include "msncontact.h"
+
+#include "netmeetinginvitation.h"
+#include "netmeetingguiclient.h"
+
+
+static const TDEAboutData aboutdata("kopete_netmeeting", I18N_NOOP("NetMeeting") , "1.0" );
+K_EXPORT_COMPONENT_FACTORY( kopete_netmeeting, KGenericFactory( &aboutdata ) )
+
+NetMeetingPlugin::NetMeetingPlugin( TQObject *parent, const char *name, const TQStringList &/*args*/ )
+: Kopete::Plugin( TDEGlobal::instance(), parent, name )
+{
+ if(MSNProtocol::protocol())
+ slotPluginLoaded(MSNProtocol::protocol());
+ else
+ connect(Kopete::PluginManager::self() , TQT_SIGNAL(pluginLoaded(Kopete::Plugin*) ), this, TQT_SLOT(slotPluginLoaded(Kopete::Plugin*)));
+
+
+ connect( Kopete::ChatSessionManager::self(), TQT_SIGNAL( chatSessionCreated( Kopete::ChatSession * )) , TQT_SLOT( slotNewKMM( Kopete::ChatSession * ) ) );
+ //Add GUI action to all already existing kmm (if the plugin is launched when kopete already rining)
+ TQValueList sessions = Kopete::ChatSessionManager::self()->sessions();
+ for (TQValueListIterator it= sessions.begin(); it!=sessions.end() ; ++it)
+ {
+ slotNewKMM(*it);
+ }
+}
+
+NetMeetingPlugin::~NetMeetingPlugin()
+{
+
+}
+
+void NetMeetingPlugin::slotPluginLoaded(Kopete::Plugin *p)
+{
+ if(p->pluginId()=="MSNProtocol")
+ {
+ connect( p , TQT_SIGNAL(invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* )) ,
+ this, TQT_SLOT( slotInvitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* )));
+ }
+}
+
+void NetMeetingPlugin::slotNewKMM(Kopete::ChatSession *KMM)
+{
+ MSNChatSession *msnMM=dynamic_cast(KMM);
+ if(msnMM)
+ {
+ connect(this , TQT_SIGNAL( destroyed(TQObject*)) ,
+ new NetMeetingGUIClient(msnMM)
+ , TQT_SLOT(deleteLater()));
+ }
+}
+
+
+void NetMeetingPlugin::slotInvitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int /*cookie*/ , MSNChatSession* msnMM , MSNContact* c )
+{
+ if(!invitation && bodyMSG.contains(NetMeetingInvitation::applicationID()))
+ {
+ invitation=new NetMeetingInvitation(true,c,msnMM);
+ invitation->parseInvitation(bodyMSG);
+ }
+}
+
+#include "netmeetingplugin.moc"
diff --git a/kopete/plugins/netmeeting/netmeetingplugin.h b/kopete/plugins/netmeeting/netmeetingplugin.h
new file mode 100644
index 00000000..0456dadd
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingplugin.h
@@ -0,0 +1,47 @@
+/*
+ netmeetingplugin.h
+
+ Copyright (c) 2003 by Olivier Goffart
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+
+
+#ifndef NetMeetingPLUGIN_H
+#define NetMeetingPLUGIN_H
+
+#include "kopeteplugin.h"
+
+namespace Kopete { class ChatSession; }
+class MSNChatSession;
+class MSNContact;
+class MSNInvitation;
+
+
+class NetMeetingPlugin : public Kopete::Plugin
+{
+ Q_OBJECT
+
+
+public:
+ NetMeetingPlugin( TQObject *parent, const char *name, const TQStringList &args );
+ ~NetMeetingPlugin();
+
+private slots:
+ void slotNewKMM(Kopete::ChatSession *);
+ void slotPluginLoaded(Kopete::Plugin*);
+ void slotInvitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int cookie , MSNChatSession* msnMM , MSNContact* c );
+
+
+};
+
+#endif
+
diff --git a/kopete/plugins/netmeeting/netmeetingpreferences.cpp b/kopete/plugins/netmeeting/netmeetingpreferences.cpp
new file mode 100644
index 00000000..309d4d15
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingpreferences.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+ Netmeetingpreferences.cpp - description
+ -------------------
+ copyright : (C) 2004 by Olivier Goffart
+ email : ogoffart @ kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "netmeetingplugin.h"
+#include "netmeetingprefs_ui.h"
+#include "netmeetingpreferences.h"
+
+typedef KGenericFactory NetmeetingPreferencesFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kopete_netmeeting, NetmeetingPreferencesFactory( "kcm_kopete_netmeeting" ) )
+
+NetmeetingPreferences::NetmeetingPreferences(TQWidget *parent, const char* /*name*/, const TQStringList &args)
+ : TDECModule(NetmeetingPreferencesFactory::instance(), parent, args)
+{
+ ( new TQVBoxLayout( this ) )->setAutoAdd( true );
+ preferencesDialog = new NetmeetingPrefsUI(this);
+
+ connect(preferencesDialog->m_app , TQT_SIGNAL(textChanged(const TQString &)) , this , TQT_SLOT(slotChanged()));
+
+ load();
+}
+
+NetmeetingPreferences::~NetmeetingPreferences()
+{
+}
+
+void NetmeetingPreferences::load()
+{
+ TDEConfig *config=TDEGlobal::config();
+ config->setGroup("Netmeeting Plugin");
+ preferencesDialog->m_app->setCurrentText(config->readEntry("NetmeetingApplication","ekiga -c callto://%1"));
+ emit TDECModule::changed(false);
+}
+
+void NetmeetingPreferences::save()
+{
+ TDEConfig *config=TDEGlobal::config();
+ config->setGroup("Netmeeting Plugin");
+ config->writeEntry("NetmeetingApplication",preferencesDialog->m_app->currentText());
+ emit TDECModule::changed(false);
+}
+
+
+void NetmeetingPreferences::slotChanged()
+{
+ emit TDECModule::changed(true);
+}
+
+#include "netmeetingpreferences.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/plugins/netmeeting/netmeetingpreferences.h b/kopete/plugins/netmeeting/netmeetingpreferences.h
new file mode 100644
index 00000000..958860cf
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingpreferences.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ netmeetingpreferences.h - description
+ -------------------
+ copyright : (C) 2004 by Olivier Goffart
+ email : ogoffart @ kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef NetmeetingPREFERENCES_H
+#define NetmeetingPREFERENCES_H
+
+#include
+#include
+
+class NetmeetingPrefsUI;
+
+/**
+ *@author Olivier Goffart
+ */
+
+class NetmeetingPreferences : public TDECModule {
+ Q_OBJECT
+
+public:
+
+ NetmeetingPreferences(TQWidget *parent = 0, const char* name = 0, const TQStringList &args = TQStringList());
+ ~NetmeetingPreferences();
+
+ virtual void save();
+ virtual void load();
+
+private:
+ NetmeetingPrefsUI *preferencesDialog;
+
+private slots:
+ void slotChanged();
+};
+
+#endif
diff --git a/kopete/plugins/netmeeting/netmeetingprefs_ui.ui b/kopete/plugins/netmeeting/netmeetingprefs_ui.ui
new file mode 100644
index 00000000..0c0838fb
--- /dev/null
+++ b/kopete/plugins/netmeeting/netmeetingprefs_ui.ui
@@ -0,0 +1,148 @@
+
+NetmeetingPrefsUI
+Olivier Goffart
+
+
+ Form1
+
+
+
+ 0
+ 0
+ 424
+ 297
+
+
+
+
+ unnamed
+
+
+
+ textLabel1
+
+
+ The NetMeeting Plugin allows you to start a video or voice chat with your MSN Messenger contacts.
+
+This is not the same as webcam chat you can find in the newer Windows Messenger®, but uses the older NetMeeting chat you can find in old versions.
+
+
+ WordBreak|AlignVCenter
+
+
+
+
+ line1
+
+
+ HLine
+
+
+ Sunken
+
+
+ Horizontal
+
+
+
+
+ layout1
+
+
+
+ unnamed
+
+
+
+ textLabel2
+
+
+ Application to launch:
+
+
+
+ -
+
+ ekiga -c callto://%1
+
+
+ -
+
+ konference callto://%1
+
+
+
+ m_app
+
+
+
+ 3
+ 0
+ 0
+ 0
+
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ textLabel3
+
+
+ <b>%1</b> will be replaced by the ip to call
+
+
+ WordBreak|AlignVCenter
+
+
+
+
+ spacer1
+
+
+ Vertical
+
+
+ Expanding
+
+
+
+ 21
+ 60
+
+
+
+
+
+ kActiveLabel1
+
+
+
+ 5
+ 5
+ 0
+ 0
+
+
+
+ You can download Konference here: <a href="http://www.kde-apps.org/content/show.php?content=10395">http://www.kde-apps.org/content/show.php?content=10395</a>
+
+
+
+
+
+
+
+
+ kcombobox.h
+ klineedit.h
+ kactivelabel.h
+
+
diff --git a/kopete/plugins/nowlistening/nowlisteningplugin.cpp b/kopete/plugins/nowlistening/nowlisteningplugin.cpp
index 31284446..6fcc21cd 100644
--- a/kopete/plugins/nowlistening/nowlisteningplugin.cpp
+++ b/kopete/plugins/nowlistening/nowlisteningplugin.cpp
@@ -258,36 +258,84 @@ void NowListeningPlugin::slotAdvertCurrentMusic()
TQPtrList accountsList = Kopete::AccountManager::self()->accounts();
for( Kopete::Account* a = accountsList.first(); a; a = accountsList.next() )
{
- if( NowListeningConfig::self()->appendStatusAdvertising() )
- {
- // Check for the now listening message in parenthesis,
- // include the header to not override other messages in parenthesis.
- TQRegExp statusSong( TQString(" \\(%1.*\\)$").arg( NowListeningConfig::header()) );
-
- // HACK: Don't keep appending the now listened song. Replace it in the status message.
- advert = a->myself()->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
- // Remove the braces when they are no listened song.
- TQString mediaAdvert = mediaPlayerAdvert(false);
- if(!mediaAdvert.isEmpty())
- {
- if(statusSong.search(advert) != -1)
- {
- advert = advert.replace(statusSong, TQString(" (%1)").arg(mediaPlayerAdvert(false)) );
- }
- else
- {
- advert += TQString(" (%1)").arg( mediaPlayerAdvert(false) );
- }
- }
- else
- {
- advert = advert.replace(statusSong, "");
- }
- }
- else
- {
- advert = mediaPlayerAdvert(false); // newTrackPlaying has done the update.
- }
+ /*
+ NOTE:
+ MSN status message(personal message) use a special tag to advert the current music playing.
+ So, we don't send the all formatted string, send a special string seperated by ";".
+
+ Also, do not use MSN hack in appending mode.
+ */
+ if( a->protocol()->pluginId() == "MSNProtocol" && !NowListeningConfig::self()->appendStatusAdvertising() )
+ {
+ TQString track, artist, album, mediaList;
+ bool isPlaying=false;
+
+ if( NowListeningConfig::self()->useSpecifiedMediaPlayer() && d->m_currentMediaPlayer )
+ {
+ if( d->m_currentMediaPlayer->playing() )
+ {
+ track = d->m_currentMediaPlayer->track();
+ artist = d->m_currentMediaPlayer->artist();
+ album = d->m_currentMediaPlayer->album();
+ mediaList = track + ";" + artist + ";" + album;
+ isPlaying = true;
+ }
+ }
+ else
+ {
+ for ( NLMediaPlayer* i = d->m_mediaPlayerList.first(); i; i = d->m_mediaPlayerList.next() )
+ {
+ if( i->playing() )
+ {
+ track = i->track();
+ artist = i->artist();
+ album = i->album();
+ mediaList = track + ";" + artist + ";" + album;
+ isPlaying = true;
+ }
+ }
+ }
+
+ // KDE4 TODO: Use the new status message framework, and remove this "hack".
+ if( isPlaying )
+ {
+ advert = TQString("[Music]%1").arg(mediaList);
+ }
+
+ }
+ else
+ {
+ if( NowListeningConfig::self()->appendStatusAdvertising() )
+ {
+ // Check for the now listening message in parenthesis,
+ // include the header to not override other messages in parenthesis.
+ TQRegExp statusSong( TQString(" \\(%1.*\\)$").arg( NowListeningConfig::header()) );
+
+ // HACK: Don't keep appending the now listened song. Replace it in the status message.
+ advert = a->myself()->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
+ // Remove the braces when they are no listened song.
+ TQString mediaAdvert = mediaPlayerAdvert(false);
+ if(!mediaAdvert.isEmpty())
+ {
+ if(statusSong.search(advert) != -1)
+ {
+ advert = advert.replace(statusSong, TQString(" (%1)").arg(mediaPlayerAdvert(false)) );
+ }
+ else
+ {
+ advert += TQString(" (%1)").arg( mediaPlayerAdvert(false) );
+ }
+ }
+ else
+ {
+ advert = advert.replace(statusSong, "");
+ }
+ }
+ else
+ {
+ advert = mediaPlayerAdvert(false); // newTrackPlaying has done the update.
+ }
+ }
a->setOnlineStatus(a->myself()->onlineStatus(), advert);
}
diff --git a/kopete/plugins/webpresence/webpresence_html.xsl b/kopete/plugins/webpresence/webpresence_html.xsl
index e0e55589..f768ccf5 100644
--- a/kopete/plugins/webpresence/webpresence_html.xsl
+++ b/kopete/plugins/webpresence/webpresence_html.xsl
@@ -57,6 +57,9 @@
AIM
+
+ MSN
+
ICQ
diff --git a/kopete/plugins/webpresence/webpresence_html_images.xsl b/kopete/plugins/webpresence/webpresence_html_images.xsl
index bd97657b..5b707046 100644
--- a/kopete/plugins/webpresence/webpresence_html_images.xsl
+++ b/kopete/plugins/webpresence/webpresence_html_images.xsl
@@ -24,6 +24,9 @@
+
+
+
diff --git a/kopete/plugins/webpresence/webpresence_xhtml.xsl b/kopete/plugins/webpresence/webpresence_xhtml.xsl
index acec55ee..9d749c14 100644
--- a/kopete/plugins/webpresence/webpresence_xhtml.xsl
+++ b/kopete/plugins/webpresence/webpresence_xhtml.xsl
@@ -56,6 +56,9 @@
AIM
+
+ MSN
+
ICQ
diff --git a/kopete/plugins/webpresence/webpresence_xhtml_images.xsl b/kopete/plugins/webpresence/webpresence_xhtml_images.xsl
index cf8d0219..8254a674 100644
--- a/kopete/plugins/webpresence/webpresence_xhtml_images.xsl
+++ b/kopete/plugins/webpresence/webpresence_xhtml_images.xsl
@@ -25,6 +25,9 @@
+
+
+
diff --git a/kopete/plugins/webpresence/webpresenceprefs.ui b/kopete/plugins/webpresence/webpresenceprefs.ui
index 479f128e..dfe781f1 100644
--- a/kopete/plugins/webpresence/webpresenceprefs.ui
+++ b/kopete/plugins/webpresence/webpresenceprefs.ui
@@ -200,15 +200,16 @@ Note that some web browsers do not support XHTML. You should also make sure your
Repla&ce protocol text with images in (X)HTML
- Replaces the protocol names, such as IRC with images.
+ Replaces the protocol names, such as MSN and IRC with images.
- Replaces the protocol names, such as IRC with images.
+ Replaces the protocol names, such as MSN and IRC with images.
Note that you have to manually copy the PNG files into place.
The following files are used by default:
+images/msn_protocol.png
images/icq_protocol.png
images/jabber_protocol.png
images/yahoo_protocol.png
diff --git a/kopete/protocols/CMakeLists.txt b/kopete/protocols/CMakeLists.txt
index 9ed1a7bf..14127078 100644
--- a/kopete/protocols/CMakeLists.txt
+++ b/kopete/protocols/CMakeLists.txt
@@ -11,6 +11,7 @@
tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_TESTBED testbed )
tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_GROUPWISE groupwise )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_MSN msn )
tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_IRC irc )
tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_OSCAR oscar )
tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_YAHOO yahoo )
diff --git a/kopete/protocols/Makefile.am b/kopete/protocols/Makefile.am
index 86ff1356..6612e8a9 100644
--- a/kopete/protocols/Makefile.am
+++ b/kopete/protocols/Makefile.am
@@ -18,4 +18,4 @@ if include_smsgsm
SMS=sms
endif
-SUBDIRS = $(TESTBED) groupwise irc oscar yahoo winpopup $(SMS) $(JABBER) $(GADU) $(MEANWHILE)
+SUBDIRS = $(TESTBED) groupwise msn irc oscar yahoo winpopup $(SMS) $(JABBER) $(GADU) $(MEANWHILE)
diff --git a/kopete/protocols/configure.in.in b/kopete/protocols/configure.in.in
index 398ebfd0..7a96cc9a 100644
--- a/kopete/protocols/configure.in.in
+++ b/kopete/protocols/configure.in.in
@@ -104,13 +104,27 @@ AM_CONDITIONAL(include_testbed, test "$with_testbed" = "yes")
PKG_CHECK_MODULES(GLIB, glib-2.0 gmodule-2.0, have_glib=yes, have_glib=no)
if test x$have_glib = xno; then
- AC_MSG_WARN([GLib 2.0 is required for Jabber Jingle. You can get it from http://www.gtk.org/])
+ AC_MSG_WARN([GLib 2.0 is required for MSN webcam and Jabber Jingle. You can get it from http://www.gtk.org/])
else
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
AC_DEFINE(HAVE_GLIB, 1, [Glib is required for oRTP code and libmimic code])
fi
+if test "x$have_glib" != "xyes"; then
+ compile_msn_webcam=no
+ msn_webcam_val=0
+else
+ compile_msn_webcam=yes
+ msn_webcam_val=1
+fi
+
+AC_MSG_CHECKING([if MSN webcam support should be enabled])
+AC_MSG_RESULT($compile_msn_webcam)
+AC_DEFINE_UNQUOTED(MSN_WEBCAM, $msn_webcam_val, [Define if MSN webcam support can be enabled])
+
+AM_CONDITIONAL(include_msn_webcam, test "x$compile_msn_webcam" = "xyes")
+
# Check for sms protocol
AC_ARG_ENABLE(smsgsm,
AC_HELP_STRING([--disable-smsgsm], [disable the GSM SMS protocol]),
diff --git a/kopete/protocols/jabber/jabbertransport.cpp b/kopete/protocols/jabber/jabbertransport.cpp
index be962fad..d0c59e3a 100644
--- a/kopete/protocols/jabber/jabbertransport.cpp
+++ b/kopete/protocols/jabber/jabbertransport.cpp
@@ -54,7 +54,9 @@ JabberTransport::JabberTransport (JabberAccount * parentAccount, const XMPP::Ros
#if KOPETE_IS_VERSION(0,11,51) //setCustomIcon is new in kopete 0.12
TQString cIcon;
- if(gateway_type=="icq")
+ if(gateway_type=="msn")
+ cIcon="jabber_gateway_msn";
+ else if(gateway_type=="icq")
cIcon="jabber_gateway_icq";
else if(gateway_type=="aim")
cIcon="jabber_gateway_aim";
diff --git a/kopete/protocols/jabber/jabbertransport.h b/kopete/protocols/jabber/jabbertransport.h
index 21fa208d..83f5e502 100644
--- a/kopete/protocols/jabber/jabbertransport.h
+++ b/kopete/protocols/jabber/jabbertransport.h
@@ -47,7 +47,7 @@ public:
* constructor called when the transport is created by info from server (i.e not when loading kopete)
* @param parentAccount is the parent jabber account.
* @param item is the roster item of the gateway
- * @param gateway_type eg: "icq" only used when the account is not loaded from config file for determining the icon
+ * @param gateway_type eg: "msn" or "icq" only used when the account is not loaded from config file for determining the icon
*/
JabberTransport (JabberAccount * parentAccount, const XMPP::RosterItem &item, const TQString& gateway_type=TQString());
diff --git a/kopete/protocols/msn/CMakeLists.txt b/kopete/protocols/msn/CMakeLists.txt
new file mode 100644
index 00000000..f38683d8
--- /dev/null
+++ b/kopete/protocols/msn/CMakeLists.txt
@@ -0,0 +1,72 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+add_subdirectory( config )
+
+if( WITH_WEBCAM )
+ add_subdirectory( webcam )
+ add_definitions( -DMSN_WEBCAM )
+ set( WEBCAM_LIBRARIES mimicwrapper-static kopete_videodevice-shared ${GLIB2_LIBRARIES} )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/webcam
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_msn.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES msnchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_msn )
+
+
+##### kopete_msn (module) #######################
+
+tde_add_kpart( kopete_msn AUTOMOC
+ SOURCES
+ dummy.cpp webcam.cpp
+ LINK kopete_msn_shared-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kopete_msn_shared (shared) ################
+
+tde_add_library( kopete_msn_shared SHARED AUTOMOC
+ SOURCES
+ msnprotocol.cpp msnaccount.cpp msnaddcontactpage.cpp msncontact.cpp
+ msnsocket.cpp msnchatsession.cpp msndebugrawcmddlg.cpp
+ msnnotifysocket.cpp msnswitchboardsocket.cpp
+ msnfiletransfersocket.cpp msninvitation.cpp sha1.cpp
+ msnsecureloginhandler.cpp msnchallengehandler.cpp
+ dispatcher.cpp p2p.cpp messageformatter.cpp incomingtransfer.cpp
+ outgoingtransfer.cpp webcam.cpp
+ VERSION 0.0.0
+ LINK
+ kopetemsnui-static ${WEBCAM_LIBRARIES} kopete-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/kopete/protocols/msn/Changelog b/kopete/protocols/msn/Changelog
new file mode 100644
index 00000000..80f52264
--- /dev/null
+++ b/kopete/protocols/msn/Changelog
@@ -0,0 +1,106 @@
+Have fun using this all-improved plugin and feel free to contribute patches
+and other improvements to our mailing list! Although we all like to boast
+about our great work, we're sure there are still bugs remaining, which is
+why we don't call this release 1.0, but only 0.5.
+
+Nevertheless, we feel this new MSN plugin is an enormous step forward from
+the last 0.4.1 release and we recommend anyone to try out this all-improved
+plugin. Please read the release notes first before reporting bugs, but please
+do report anything not listed there!
+
+Thanks for your interest in Kopete!
+
+ October 2002, the Kopete team
+
+
+CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.4.1
+
+- Ported the plugin to the new MetaContact API, allowing a locally cached
+ copy of the contact list to be always available (even when offline) and
+ to combine your MSN contacts with other messaging systems in one entry
+ in the contact list.
+
+- Added additional online states ('be right back', 'out to lunch', 'busy',
+ 'invisible') and the possibility to connect directly with a particular
+ status (especially useful with 'invisible')
+
+- Fix multi-user chat now the API finally supports it properly
+
+- Fix a grave bug in Kopete 0.4.1 where Kopete would popup the 'new user'
+ dialog for every user in your block list, asking whether you want to
+ allow or block the user, often crashing Kopete completely
+
+- Fix support for Unicode messages
+
+- Fix the 'unhandled error 219' problem that caused Kopete to disconnect
+ unexpectedly for some people
+
+- Added possibility to talk with users who aren't in the contact list
+
+- Incoming filetransfers
+
+- As usual, several other bugfixes
+
+CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.4
+
+- Added block/unblock user
+
+- Don't show contacts from the allow list if they are not also in the
+ friend list (like deleted contacts). Small problem: there already was
+ a need to have a gui for manipulating blocked/allowed contacts, with
+ this change this is even a bit more urgent...
+
+- Hopefully fix a problem with an empty reverse list on a fresh MSN account.
+ can't test, because by the time the recompile was done the reverse list
+ was no longer empty...
+
+- Fix a problem with MSN users no longer receiving messages. Apparently
+ Microsoft changed the server so messages without an explicit font name are
+ no longer passed on.
+
+- Fixed UTF8 handling not really being UTF8. MSN should work fine now with
+ all unicode characters
+
+- Moved the plugin to use KGenericFactory as preparation for more KDE-style
+ plugin handling (as opposed to the current custom code)
+
+- Fixed crash when disconnecting while an earlier connect was still running
+
+- Made the connect code asynchronous, so connecting doesn't hang kopete
+ while processing
+
+- Fixed minor memory leak in the connect code
+
+CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.3
+
+Many things changed since 0.3. I won't mention them all, because so much of
+the internal code changed that the individual commits often fix more than I
+was even aware of at that time. Below are the bigger changes and fixes:
+
+- Ported the plugin to the new KopeteMessageManager. This move unifies the
+ handling of various resources like chat windows, balloons, system tray
+ flashing, and more. In Kopete 0.3 this was the exclusive domain of the
+ ICQ plugin, in this release all plugins except IRC already use the shared
+ code.
+
+- Rewrote almost all of the internal protocol handling, fixing an awful lot
+ of bugs during the process. The main goal was to make the code more
+ maintainable and extensible, but the gratuitous bug fixes are of course
+ much more useful for most people. The most important fix of all is a
+ grave bug that caused the plugin to read a fixed-size 1kb buffer in Kopete
+ 0.3 without checking for additional data, often causing the plugin to
+ seemingly 'hang'.
+
+- Added the ability to change the display name while connected. This can
+ currently only be done from the context menu. The option in the
+ preferences never worked, and still does not do what you'd expect it to
+ do. Sorry :)
+
+- Added much more useful debug code for developers, testers and other
+ interested people. It is also a lot *more* debug output, so if you're
+ scared of console output, better not start Kopete from it...
+
+- All those tiny bugfixes of which I don't even know whether they fix
+ regressions introduced during the development of version 0.4, or whether
+ they fix long-standing bugs.
+
diff --git a/kopete/protocols/msn/Makefile.am b/kopete/protocols/msn/Makefile.am
new file mode 100644
index 00000000..5248d295
--- /dev/null
+++ b/kopete/protocols/msn/Makefile.am
@@ -0,0 +1,47 @@
+if include_msn_webcam
+WEBCAM = webcam
+WEBCAM_LIBMINICWRAPPER = webcam/libmimicwrapper.la
+endif
+
+KDE_OPTIONS = nofinal
+METASOURCES = AUTO
+SUBDIRS = ui $(WEBCAM) . icons config
+AM_CPPFLAGS = -Iui \
+ -I$(srcdir)/webcam \
+ -I$(srcdir)/ui \
+ $(KOPETE_INCLUDES) \
+ -I$(top_srcdir)/kopete/libkopete/private \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = kopete_msn.la
+lib_LTLIBRARIES = libkopete_msn_shared.la
+
+CLEANFILES = dummy.cpp
+
+libkopete_msn_shared_la_SOURCES = msnprotocol.cpp msnaccount.cpp \
+ msnaddcontactpage.cpp msncontact.cpp msnsocket.cpp msnchatsession.cpp msndebugrawcmddlg.cpp \
+ msnnotifysocket.cpp msnswitchboardsocket.cpp msnfiletransfersocket.cpp msninvitation.cpp \
+ sha1.cpp msnsecureloginhandler.cpp msnchallengehandler.cpp dispatcher.cpp \
+ p2p.cpp messageformatter.cpp incomingtransfer.cpp outgoingtransfer.cpp \
+ webcam.cpp
+
+libkopete_msn_shared_la_LIBADD = ./ui/libkopetemsnui.la ../../libkopete/libkopete.la $(WEBCAM_LIBMINICWRAPPER) ../../libkopete/avdevice/libkopete_videodevice.la $(LIB_TDEIO)
+libkopete_msn_shared_la_LDFLAGS = -version-info 0:0:0 -no-undefined $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor -lkopete_videodevice -L../../libkopete/avdevice/
+
+kopete_msn_la_SOURCES = dummy.cpp webcam.cpp
+kopete_msn_la_LIBADD = libkopete_msn_shared.la
+
+kopete_msn_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor -lkopete_videodevice -L../../libkopete/avdevice/
+
+dummy.cpp: $(srcdir)/Makefile.am
+ echo '#include "kdemacros.h"' > $@
+ echo 'extern "C" KDE_EXPORT void *init_libkopete_msn_shared();' >> $@
+ echo 'extern "C" KDE_EXPORT void *init_kopete_msn() { return init_libkopete_msn_shared(); }' >> $@
+
+service_DATA = kopete_msn.desktop
+servicedir = $(kde_servicesdir)
+
+mydatadir = $(kde_datadir)/kopete_msn
+mydata_DATA = msnchatui.rc
+noinst_HEADERS = p2p.h dispatcher.h messageformatter.h incomingtransfer.h \
+ outgoingtransfer.h webcam.h
diff --git a/kopete/protocols/msn/ReleaseNotes b/kopete/protocols/msn/ReleaseNotes
new file mode 100644
index 00000000..1a36724a
--- /dev/null
+++ b/kopete/protocols/msn/ReleaseNotes
@@ -0,0 +1,31 @@
+If you can bear with beta-quality code, we welcome you to try out this
+highly improved plugin and use it as your primary instant messaging system!
+Patches are always welcome on kopete-devel@kde.org. Trivial fixes can be
+committed directly to KDE CVS if you have an account, but please coordinate
+larger changes with us to avoid double work.
+
+Thanks for your interest in Kopete!
+
+ October 2002, the Kopete team
+
+RELEASE NOTES FOR THE MSN PLUGIN IN KOPETE 0.5
+
+Most of the MSN plugin has seen an enormous improvement since the previous
+release, with many bugs fixed in all aspects of the plugin, most notably
+the contact list handling and group chats. See the Changelog for a more
+detailed description of what was changed in this release.
+
+Some issues in MSN are still remaining though. We hope to fix them in the
+next release, since we think they are not critical enough to delay this
+release:
+
+- MSN allows you to have multiple groups with the same name, because
+ internally a group ID is used. Kopete currently uses the name as a unique
+ identifier, however, and will likely get a bit confused by this. If you
+ do experience problems, you could join both groups using another MSN
+ client, like the official client, Trillian or Pidgin as a workaround.
+
+- Kopete contacts can be at Top-Level and in no groups. MSN doesn't
+ support this freature. The kopete's contact list can differe from server
+ if you have top-level contact
+
diff --git a/kopete/protocols/msn/TODO b/kopete/protocols/msn/TODO
new file mode 100644
index 00000000..be73e830
--- /dev/null
+++ b/kopete/protocols/msn/TODO
@@ -0,0 +1,5 @@
+Some things to think about as of 2003/04/15
+(according to Gof)
+Adding 'search for user'
+Adding MSN chatroom protocol
+Add MSN alerts
diff --git a/kopete/protocols/msn/config/CMakeLists.txt b/kopete/protocols/msn/config/CMakeLists.txt
new file mode 100644
index 00000000..d9fd401b
--- /dev/null
+++ b/kopete/protocols/msn/config/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_msn_config.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/tdeconfiguredialog )
+
+
+##### kcm_kopete_msn (module) ###################
+
+tde_add_kpart( kcm_kopete_msn AUTOMOC
+ SOURCES
+ msnprefs.ui msnpreferences.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/msn/config/Makefile.am b/kopete/protocols/msn/config/Makefile.am
new file mode 100644
index 00000000..2d84950e
--- /dev/null
+++ b/kopete/protocols/msn/config/Makefile.am
@@ -0,0 +1,12 @@
+METASOURCES = AUTO
+AM_CPPFLAGS = $(KOPETE_INCLUDES) $(all_includes)
+
+kde_module_LTLIBRARIES = kcm_kopete_msn.la
+
+kcm_kopete_msn_la_SOURCES = msnprefs.ui msnpreferences.cpp
+kcm_kopete_msn_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+kcm_kopete_msn_la_LIBADD = ../../../libkopete/libkopete.la $(LIB_TDEUTILS)
+
+service_DATA = kopete_msn_config.desktop
+servicedir = $(kde_servicesdir)/tdeconfiguredialog
+
diff --git a/kopete/protocols/msn/config/kopete_msn_config.desktop b/kopete/protocols/msn/config/kopete_msn_config.desktop
new file mode 100644
index 00000000..4754ae1f
--- /dev/null
+++ b/kopete/protocols/msn/config/kopete_msn_config.desktop
@@ -0,0 +1,123 @@
+[Desktop Entry]
+Icon=msn_protocol
+Type=Service
+ServiceTypes=TDECModule
+
+X-TDE-ModuleType=Library
+X-TDE-Library=kopete_msn
+X-TDE-FactoryName=MSNProtocolConfigFactory
+X-TDE-ParentApp=kopete_msn
+X-TDE-ParentComponents=kopete_msn
+
+Name=MSN Plugin
+Name[ar]=توصيلة MSN
+Name[be]=Модуль MSN
+Name[bg]=MSN
+Name[bn]=এমএসএন প্লাগিন
+Name[br]=Lugent MSN
+Name[bs]=MSN dodatak
+Name[ca]=Connector de MSN
+Name[cs]=MSN modul
+Name[cy]=Ategyn MSN
+Name[da]=MSN-Plugin
+Name[de]=MSN-Modul
+Name[el]=Πρόσθετο MSN
+Name[es]=Complemento de MSN
+Name[et]=MSN plugin
+Name[eu]=MSN Plugin-a
+Name[fa]=وصلۀ اماسان
+Name[fi]=MSN-liitännäinen
+Name[fr]=Module MSN
+Name[ga]=Breiseán MSN
+Name[gl]=Plugin para MSN
+Name[he]=תוסף MSN
+Name[hi]=एमएसएन प्लगइन
+Name[hr]=MSN umetak
+Name[hu]=MSN modul
+Name[is]=MSN íforrit
+Name[it]=Plugin MSN
+Name[ja]=MSN プラグイン
+Name[ka]=MSN მოდული
+Name[kk]=MSN плагин модулі
+Name[km]=កម្មវិធីជំនួយ MSN
+Name[lt]=MSN įskiepis
+Name[mk]=MSN-приклучок
+Name[nb]=MSN programtillegg
+Name[nds]=MSN-Moduul
+Name[ne]=एमएसएन प्लगइन
+Name[nl]=MSN-plugin
+Name[nn]=MSN-programtillegg
+Name[pa]=MSN ਪਲੱਗਇਨ
+Name[pl]=Wtyczka MSN
+Name[pt]='Plugin' MSN
+Name[pt_BR]=Plug-in MSN
+Name[ro]=Modul MSN
+Name[ru]=Модуль MSN
+Name[se]=MSN-lassemoduvla
+Name[sk]=Modul MSN
+Name[sl]=Vstavek za MSN
+Name[sr]=MSN прикључак
+Name[sr@Latn]=MSN priključak
+Name[sv]=MSN-insticksprogram
+Name[ta]=MSN செருகல்
+Name[tg]=Модули MSN
+Name[tr]=MSN Eklentisi
+Name[uk]=Втулок MSN
+Name[uz]=MSN plagini
+Name[uz@cyrillic]=MSN плагини
+Name[wa]=Tchôke-divins MSN
+Name[zh_CN]=MSN 插件
+Name[zh_HK]=MSN 插件
+Name[zh_TW]=MSN 外掛程式
+Comment=Microsoft Network Protocol
+Comment[ar]=بروتوكول شبكة Microsoft
+Comment[be]=Пратакол сеткі Microsoft Network
+Comment[bg]=Протокол за връзка с Microsoft Network
+Comment[bn]=মাইক্রোসফ্ট নেটওয়ার্ক প্রোটোকল
+Comment[br]=Komenad rouedad Microsoft
+Comment[bs]=Microsoft Network protokol
+Comment[ca]=Protocol per a la xarxa de Microsoft
+Comment[cs]=Protokol sítě Microsoft
+Comment[cy]=Protocol Rhwydwaith Microsoft
+Comment[de]=Microsoft Netzwerk-Protokoll
+Comment[el]=Πρωτόκολλο Microsoft Network
+Comment[es]=Protocolo de red de Microsoft
+Comment[et]=Microsofti võrguprotokoll
+Comment[fa]=قرارداد شبکۀ میکروسافت
+Comment[fi]=Microsoft Network -yhteyskäytäntö
+Comment[fr]=Protocole réseau Microsoft
+Comment[ga]=Prótacal Gréasáin Mhicrosoft
+Comment[gl]=Protocolo para a rede de Microsoft
+Comment[he]=תוסף חיבור לרשת מיקרוסופט
+Comment[hi]=माइक्रोसॉफ्ट नेटवर्क प्रोटोकॉल
+Comment[hr]=Microsoft mrežni protokol
+Comment[hu]=Microsoft hálózati protokoll
+Comment[is]=Microsoft Network Protocol
+Comment[it]=Protocollo di rete Microsoft
+Comment[ja]=Microsoft ネットワークプロトコル
+Comment[ka]=Microsoft ქსელის ოქმი
+Comment[kk]=Microsoft Network желі протоколы
+Comment[km]=ពិធីការបណ្ដាញម៉ៃក្រូសូហ្វ
+Comment[lt]=Microsoft tinklo protokolas
+Comment[mk]=Мрежен протокол на Microsoft
+Comment[nds]=Microsoft-Nettwarkprotokoll
+Comment[ne]=माइक्रोसफ्ट सञ्जाल प्रोटोकल
+Comment[nl]=Protocol voor Microsoft Network
+Comment[nn]=Microsoft Network-protokoll
+Comment[pl]=Protokół Microsoft Network
+Comment[pt]=Protocolo da Microsoft Network
+Comment[pt_BR]=Protocolo de Rede Microsoft
+Comment[ru]=Протокол сети Microsoft Network
+Comment[sl]=Protokol za povezavo na MSN
+Comment[sv]=Microsoft-nätverksprotokoll
+Comment[ta]=மைக்ரோசாப்ட் இணைய விதிமுறை
+Comment[tg]=Қарордоди Шабакаи Microsoft
+Comment[tr]=Microsoft Ağ Protokolü
+Comment[uk]=Мережний протокол Microsoft
+Comment[uz]=Microsoft tarmogʻi bilan aloqa oʻrnatish uchun protokol
+Comment[uz@cyrillic]=Microsoft тармоғи билан алоқа ўрнатиш учун протокол
+Comment[wa]=Protocole pol rantoele da Microsoft
+Comment[zh_CN]=Microsoft Network 协议
+Comment[zh_HK]=Microsoft 網絡通訊協定
+Comment[zh_TW]=Microsoft 網路協定
+
diff --git a/kopete/protocols/msn/config/msnpreferences.cpp b/kopete/protocols/msn/config/msnpreferences.cpp
new file mode 100644
index 00000000..a6f5371f
--- /dev/null
+++ b/kopete/protocols/msn/config/msnpreferences.cpp
@@ -0,0 +1,33 @@
+/*
+ msnpreferences.cpp - MSN Preferences Widget
+
+ Copyright (c) 2002-2003 by Olivier Goffart
+ Kopete (c) 2002-2003 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include
+#include "kcautoconfigmodule.h"
+#include "msnprefs.h"
+
+class MSNPreferences;
+
+typedef KGenericFactory MSNProtocolConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kopete_msn, MSNProtocolConfigFactory( "kcm_kopete_msn" ) )
+
+class MSNPreferences : public KCAutoConfigModule
+{
+public:
+ MSNPreferences( TQWidget *parent = 0, const char * = 0, const TQStringList &args = TQStringList() ) : KCAutoConfigModule( MSNProtocolConfigFactory::instance(), parent, args )
+ {
+ setMainWidget( new msnPrefsUI( this ) , "MSN");
+ }
+};
diff --git a/kopete/protocols/msn/config/msnprefs.ui b/kopete/protocols/msn/config/msnprefs.ui
new file mode 100644
index 00000000..13817584
--- /dev/null
+++ b/kopete/protocols/msn/config/msnprefs.ui
@@ -0,0 +1,217 @@
+
+msnPrefsUI
+Duncan Mac-Vicar P.
+
+
+ msnPrefsUI
+
+
+
+ 0
+ 0
+ 522
+ 347
+
+
+
+
+ unnamed
+
+
+
+ TextLabel3_2_2_2_3
+
+
+
+ 1
+
+
+
+ General
+
+
+
+
+ Frame3_3_3_2_3
+
+
+
+ 1
+ 0
+ 0
+ 0
+
+
+
+ HLine
+
+
+ Sunken
+
+
+
+
+ NotifyNewChat
+
+
+ &Automatically open a chat window when someone starts a conversation
+
+
+
+
+ AutoDownloadPicture
+
+
+ &Automatically download the display picture if possible
+
+
+ true
+
+
+
+
+ useCustomEmoticons
+
+
+ Download and show custom emoticons (experimental)
+
+
+
+
+ TextLabel1_3_3_3
+
+
+
+
+
+
+
+ TextLabel3_2_2_2_2
+
+
+
+ 1
+
+
+
+ Away Messages
+
+
+
+
+ Frame3_3_3_2_2
+
+
+
+ 1
+ 0
+ 0
+ 0
+
+
+
+ HLine
+
+
+ Sunken
+
+
+
+
+ SendAwayMessages
+
+
+
+ 7
+ 0
+ 0
+ 0
+
+
+
+ Send &away messages
+
+
+ true
+
+
+
+
+ layout18
+
+
+
+ unnamed
+
+
+
+ textLabel3
+
+
+ Do not send more than one away message every
+
+
+
+
+ AwayMessageSeconds
+
+
+ 90
+
+
+ 1
+
+
+
+
+ textLabel4
+
+
+ seconds
+
+
+
+
+
+
+ spacer7
+
+
+ Vertical
+
+
+ Expanding
+
+
+
+ 21
+ 70
+
+
+
+
+
+
+
+ SendAwayMessages
+ toggled(bool)
+ AwayMessageSeconds
+ setEnabled(bool)
+
+
+
+ NotifyNewChat
+ AutoDownloadPicture
+ useCustomEmoticons
+ SendAwayMessages
+ AwayMessageSeconds
+
+
+ knuminput.h
+
+
+
+ knuminput.h
+ knuminput.h
+
+
diff --git a/kopete/protocols/msn/dispatcher.cpp b/kopete/protocols/msn/dispatcher.cpp
new file mode 100644
index 00000000..70d43a14
--- /dev/null
+++ b/kopete/protocols/msn/dispatcher.cpp
@@ -0,0 +1,647 @@
+/*
+ dispatcher.cpp - msn p2p protocol
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "dispatcher.h"
+#include "incomingtransfer.h"
+#include "outgoingtransfer.h"
+
+#if MSN_WEBCAM
+#include "webcam.h"
+#endif
+
+using P2P::Dispatcher;
+using P2P::Message;
+using P2P::TransferContext;
+using P2P::IncomingTransfer;
+using P2P::OutgoingTransfer;
+
+#include "msnswitchboardsocket.h"
+
+// Kde includes
+#include
+#include
+#include
+#include
+
+// TQt includes
+#include
+#include
+#include
+#include
+#include
+
+// Kopete includes
+#include // Just for getting the contact
+#include
+#include
+
+#include
+
+Dispatcher::Dispatcher(TQObject *parent, const TQString& contact, const TQStringList &ip)
+ : TQObject(parent) , m_contact(contact) , m_callbackChannel(0l) , m_ip(ip)
+{}
+
+Dispatcher::~Dispatcher()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+
+ if(m_callbackChannel)
+ {
+ delete m_callbackChannel;
+ m_callbackChannel = 0l;
+ }
+}
+
+void Dispatcher::detach(TransferContext* transfer)
+{
+ m_sessions.remove(transfer->m_sessionId);
+ transfer->deleteLater();
+}
+
+TQString Dispatcher::localContact()
+{
+ return m_contact;
+}
+
+void Dispatcher::requestDisplayIcon(const TQString& from, const TQString& msnObject)
+{
+ TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
+ TransferContext* current =
+ new IncomingTransfer(from, this, sessionId);
+
+ current->m_branch = P2P::Uid::createUid();
+ current->m_callId = P2P::Uid::createUid();
+ current->setType(P2P::UserDisplayIcon);
+ current->m_object = msnObject;
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId, current);
+
+ kdDebug(14140) << k_funcinfo << "Requesting, " << msnObject << endl;
+
+ TQString context = TQString::fromUtf8(KCodecs::base64Encode(msnObject.utf8()));
+ // NOTE remove the \0 character automatically
+ // appended to a TQCString.
+ context.replace("=", TQString());
+ TQString content =
+ "EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}\r\n"
+ "SessionID: " + TQString::number(sessionId) + "\r\n"
+ "AppID: 1\r\n"
+ "Context: " + context + "\r\n"
+ "\r\n";
+ // Send the sending client an invitation message.
+ current->sendMessage(INVITE, content);
+}
+
+void Dispatcher::sendFile(const TQString& path, TQ_INT64 fileSize, const TQString& to)
+{
+ // Create a new transfer context that will handle
+ // the file transfer.
+ TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
+ TransferContext *current =
+ new OutgoingTransfer(to, this, sessionId);
+ current->m_branch = P2P::Uid::createUid();
+ current->m_callId = P2P::Uid::createUid();
+ current->setType(P2P::File);
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId, current);
+
+ // Set the transfer context file.
+ current->m_file = new TQFile(path);
+ // Create the file context data.
+ TQString context;
+
+ TQByteArray header(638);
+ header.fill('\0');
+ TQDataStream writer(header, IO_WriteOnly);
+ writer.setByteOrder(TQDataStream::LittleEndian);
+
+ // Write the header length to the stream.
+ writer << (TQ_INT32)638;
+ // Write client version to the stream.
+ writer << (TQ_INT32)3;
+ // Write the file size to the stream.
+ writer << fileSize;
+ // Write the file transfer flag to the stream.
+ // TODO support file preview. For now disable file preview.
+ writer << (TQ_INT32)1;
+ // Write the file name in utf-16 to the stream.
+ TQTextStream ts(header, IO_WriteOnly);
+ ts.setEncoding(TQTextStream::RawUnicode);
+ ts.device()->at(20);
+ ts << path.section('/', -1);
+ // NOTE Background Sharing base64 [540..569]
+ // TODO add support for background sharing.
+ // Write file exchange type to the stream.
+ // NOTE File - 0xFFFFFFFF
+ // NOTE Background Sharing - 0xFFFFFFFE
+ writer.device()->at(570);
+ writer << (TQ_UINT32)0xFFFFFFFF;
+
+ // Encode the file context header to base64 encoding.
+ context = TQString::fromUtf8(KCodecs::base64Encode(header));
+
+ // Send an INVITE message to the recipient.
+ TQString content = "EUF-GUID: {5D3E02AB-6190-11D3-BBBB-00C04F795683}\r\n"
+ "SessionID: " + TQString::number(sessionId) + "\r\n"
+ "AppID: 2\r\n"
+ "Context: " + context + "\r\n"
+ "\r\n";
+ current->sendMessage(INVITE, content);
+}
+
+void Dispatcher::sendImage(const TQString& /*fileName*/, const TQString& /*to*/)
+{
+// TODO kdDebug(14140) << k_funcinfo << endl;
+// TQFile imageFile(fileName);
+// if(!imageFile.open(IO_ReadOnly))
+// {
+// kdDebug(14140) << k_funcinfo << "Error opening image file."
+// << endl;
+// return;
+// }
+//
+// OutgoingTransfer *outbound =
+// new OutgoingTransfer(to, this, 64);
+//
+// outbound->sendImage(imageFile.readAll());
+}
+
+#if MSN_WEBCAM
+void Dispatcher::startWebcam(const TQString &/*myHandle*/, const TQString &msgHandle, bool wantToReceive)
+{
+ TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
+ Webcam::Who who= wantToReceive ? Webcam::wViewer : Webcam::wProducer;
+ TransferContext* current =
+ new Webcam(who, msgHandle, this, sessionId);
+
+ current->m_branch = P2P::Uid::createUid();
+ current->m_callId = P2P::Uid::createUid();
+ current->setType(P2P::WebcamType);
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId, current);
+
+ // {4BD96FC0-AB17-4425-A14A-439185962DC8} <- i want to show you my webcam
+ // {1C9AA97E-9C05-4583-A3BD-908A196F1E92} <- i want to see your webcam
+ TQString GUID= (who==Webcam::wProducer) ? "4BD96FC0-AB17-4425-A14A-439185962DC8" : "1C9AA97E-9C05-4583-A3BD-908A196F1E92" ;
+
+ TQString content="EUF-GUID: {"+GUID+"}\r\n"
+ "SessionID: "+ TQString::number(sessionId)+"\r\n"
+ "AppID: 4\r\n"
+ "Context: ewBCADgAQgBFADcAMABEAEUALTQBFADIAQwBBAC0ANAA0ADAAMAAtAEEARTQAwADMALQA4ADgARgBGADgANTQBCADkARgA0AEUAOAB9AA==\r\n\r\n";
+
+ // context is the base64 of the utf16 of {B8BE70DE-E2CA-4400-AE03-88FF85B9F4E8}
+
+ current->sendMessage( INVITE , content );
+}
+#endif
+
+
+
+void Dispatcher::slotReadMessage(const TQString &from, const TQByteArray& stream)
+{
+ P2P::Message receivedMessage =
+ m_messageFormatter.readMessage(stream);
+
+ receivedMessage.source = from;
+
+ if(receivedMessage.contentType == "application/x-msnmsgrp2p")
+ {
+ if((receivedMessage.header.dataSize == 0)/* && ((receivedMessage.header.flag & 0x02) == 0x02)*/)
+ {
+ TransferContext *current = 0l;
+ TQMap::Iterator it = m_sessions.begin();
+ for(; it != m_sessions.end(); it++)
+ {
+ if(receivedMessage.header.ackSessionIdentifier == it.data()->m_identifier){
+ current = it.data();
+ break;
+ }
+ }
+
+ if(current){
+ // Inform the transfer object of the acknowledge.
+ current->m_ackSessionIdentifier = receivedMessage.header.identifier;
+ current->m_ackUniqueIdentifier = receivedMessage.header.ackSessionIdentifier;
+ current->acknowledged();
+ }
+ else
+ {
+ kdDebug(14140) << k_funcinfo
+ << "no transfer context with identifier, "
+ << receivedMessage.header.ackSessionIdentifier
+ << endl;
+ }
+ return;
+ }
+
+ if(m_messageBuffer.contains(receivedMessage.header.identifier))
+ {
+ kdDebug(14140) << k_funcinfo
+ << TQString("retrieving buffered messsage, %1").arg(receivedMessage.header.identifier)
+ << endl;
+
+ // The message was split, try to reconstruct the message
+ // with this received piece.
+ Message bufferedMessage = m_messageBuffer[receivedMessage.header.identifier];
+ // Remove the buffered message.
+ m_messageBuffer.remove(receivedMessage.header.identifier);
+
+ bufferedMessage.body.resize(bufferedMessage.body.size() + receivedMessage.header.dataSize);
+ for(TQ_UINT32 i=0; i < receivedMessage.header.dataSize; i++){
+ // Add the remaining message data to the buffered message.
+ bufferedMessage.body[receivedMessage.header.dataOffset + i] = receivedMessage.body[i];
+ }
+ bufferedMessage.header.dataSize += receivedMessage.header.dataSize;
+ bufferedMessage.header.dataOffset = 0;
+
+ receivedMessage = bufferedMessage;
+ }
+
+ // Dispatch the received message.
+ dispatch(receivedMessage);
+ }
+}
+
+void Dispatcher::dispatch(const P2P::Message& message)
+
+{
+ TransferContext *messageHandler = 0l;
+
+ if(message.header.sessionId > 0)
+ {
+ if(m_sessions.contains(message.header.sessionId)){
+ messageHandler = m_sessions[message.header.sessionId];
+ }
+ }
+ else
+ {
+ TQString body =
+ TQCString(message.body.data(), message.header.dataSize);
+ TQRegExp regex("SessionID: ([0-9]*)\r\n");
+ if(regex.search(body) > 0)
+ {
+ TQ_UINT32 sessionId = regex.cap(1).toUInt();
+ if(m_sessions.contains(sessionId)){
+ // Retrieve the message handler associated with the specified session Id.
+ messageHandler = m_sessions[sessionId];
+ }
+ }
+ else
+ {
+ // Otherwise, try to retrieve the message handler
+ // based on the acknowlegded unique identifier.
+ if(m_sessions.contains(message.header.ackUniqueIdentifier)){
+ messageHandler =
+ m_sessions[message.header.ackUniqueIdentifier];
+ }
+
+ if(!messageHandler)
+ {
+ // If the message handler still has not been found,
+ // try to retrieve the handler based on the call id.
+ regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
+ regex.search(body);
+ TQString callId = regex.cap(1);
+
+ TransferContext *current = 0l;
+ TQMap::Iterator it = m_sessions.begin();
+ for(; it != m_sessions.end(); it++)
+ {
+ current = it.data();
+ if(current->m_callId == callId){
+ messageHandler = current;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(messageHandler){
+ // Process the received message using the
+ // retrieved registered handler.
+ messageHandler->m_ackSessionIdentifier = message.header.identifier;
+ messageHandler->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
+ messageHandler->processMessage(message);
+ }
+ else
+ {
+ // There are no objects registered, with the retrieved session Id,
+ // to handle the received message; default to this dispatcher.
+
+ if(message.header.totalDataSize > message.header.dataOffset + message.header.dataSize)
+ {
+ // The entire message has not been received;
+ // buffer the recevied portion of the original message.
+ kdDebug(14140) << k_funcinfo
+ << TQString("Buffering messsage, %1").arg(message.header.identifier)
+ << endl;
+ m_messageBuffer.insert(message.header.identifier, message);
+ return;
+ }
+
+ TQString body =
+ TQCString(message.body.data(), message.header.dataSize);
+ kdDebug(14140) << k_funcinfo << "received, " << body << endl;
+
+ if(body.startsWith("INVITE"))
+ {
+ // Retrieve the branch, call id, and session id.
+ // These fields will be used later on in the p2p
+ // transaction.
+ TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
+ regex.search(body);
+ TQString branch = regex.cap(1);
+ regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
+ regex.search(body);
+ TQString callId = regex.cap(1);
+ regex = TQRegExp("SessionID: ([0-9]*)\r\n");
+ regex.search(body);
+ TQString sessionId = regex.cap(1);
+ // Retrieve the contact that requested the session.
+ regex = TQRegExp("From: ]*)>");
+ regex.search(body);
+ TQString from = regex.cap(1);
+ // Retrieve the application identifier which
+ // is used to determine what type of session
+ // is being requested.
+ regex = TQRegExp("AppID: ([0-9]*)\r\n");
+ regex.search(body);
+ TQ_UINT32 applicationId = regex.cap(1).toUInt();
+
+ if(applicationId == 1 || applicationId == 11 || applicationId == 12 )
+ { //the AppID is 12 since Messenger 7.5
+ // A contact has requested a session to download
+ // a display icon (User Display Icon or CustomEmotion).
+
+ regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
+ regex.search(body);
+ TQCString msnobj;
+
+ // Decode the msn object from base64 encoding.
+ KCodecs::base64Decode(regex.cap(1).utf8() , msnobj);
+ kdDebug(14140) << k_funcinfo << "Contact requested, "
+ << msnobj << endl;
+
+ // Create a new transfer context that will handle
+ // the user display icon transfer.
+ TransferContext *current =
+ new OutgoingTransfer(from, this, sessionId.toUInt());
+ current->m_branch = branch;
+ current->m_callId = callId;
+ current->setType(P2P::UserDisplayIcon);
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId.toUInt(), current);
+
+ // Determine the display icon being requested.
+ TQString fileName = objectList.contains(msnobj)
+ ? objectList[msnobj]
+ : m_pictureUrl;
+ TQFile *source = new TQFile(fileName);
+ // Try to open the source file for reading.
+ // If an error occurs, send an internal
+ // error message to the recipient.
+ if(!source->open(IO_ReadOnly))
+ {
+ current->error();
+ return;
+ }
+
+ current->m_file = source;
+ // Acknowledge the session request.
+ current->acknowledge(message);
+
+ current->m_ackSessionIdentifier = message.header.identifier;
+ current->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
+ // Send a 200 OK message to the recipient.
+ TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
+ current->sendMessage(OK, content);
+ }
+ else if(applicationId == 2)
+ {
+ // A contact has requested a session to
+ // send a file.
+
+ kdDebug(14140) << k_funcinfo << "File transfer invitation." << endl;
+
+ // Create a new transfer context that will handle
+ // the file transfer.
+ TransferContext *transfer =
+ new IncomingTransfer(from, this, sessionId.toUInt());
+ transfer->m_branch = branch;
+ transfer->m_callId = callId;
+ transfer->setType(P2P::File);
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId.toUInt(), transfer);
+
+ regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
+ regex.search(body);
+ TQByteArray context;
+
+ // Decode the file context from base64 encoding.
+ KCodecs::base64Decode(regex.cap(1).utf8(), context);
+ TQDataStream reader(context, IO_ReadOnly);
+ reader.setByteOrder(TQDataStream::LittleEndian);
+ //Retrieve the file info from the context field.
+ // File Size [8..15] Int64
+ reader.device()->at(8);
+ TQ_INT64 fileSize;
+ reader >> fileSize;
+ // Flag [15..18] Int32
+ // 0x00 File transfer with preview data.
+ // 0x01 File transfer without preview data.
+ // 0x02 Background sharing.
+ TQ_INT32 flag;
+ reader >> flag;
+ kdDebug(14140) << flag << endl;
+ // FileName UTF16 (Unicode) [19..539]
+ TQByteArray bytes(520);
+ reader.readRawBytes(bytes.data(), bytes.size());
+ TQTextStream ts(bytes, IO_ReadOnly);
+ ts.setEncoding(TQTextStream::Unicode);
+ TQString fileName;
+ fileName = ts.readLine().utf8();
+
+ emit incomingTransfer(from, fileName, fileSize);
+
+ kdDebug(14140) <<
+ TQString("%1, %2 bytes.").arg(fileName, TQString::number(fileSize))
+ << endl
+ << endl;
+
+ // Get the contact that is sending the file.
+ Kopete::Contact *contact = getContactByAccountId(from);
+
+ if(contact)
+ {
+ // Acknowledge the file invitation message.
+ transfer->acknowledge(message);
+
+ transfer->m_ackSessionIdentifier = message.header.identifier;
+ transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
+
+ TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(accepted(Kopete::Transfer*, const TQString&)), transfer, TQT_SLOT(slotTransferAccepted(Kopete::Transfer*, const TQString&)));
+ TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(refused(const Kopete::FileTransferInfo&)), transfer, TQT_SLOT(slotTransferRefused(const Kopete::FileTransferInfo&)));
+
+ // Show the file transfer accept/decline dialog.
+ Kopete::TransferManager::transferManager()->askIncomingTransfer(contact, fileName, fileSize, TQString(), sessionId);
+ }
+ else
+ {
+ kdWarning(14140) << fileName << " from " << from
+ << " has failed; could not retrieve contact from contact list."
+ << endl;
+ transfer->m_ackSessionIdentifier = message.header.identifier;
+ transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
+ transfer->sendMessage(ERROR);
+ }
+ }
+ else if(applicationId == 4)
+ {
+#if MSN_WEBCAM
+ regex = TQRegExp("EUF-GUID: \\{([0-9a-zA-Z\\-]*)\\}");
+ regex.search(body);
+ TQString GUID=regex.cap(1);
+
+ kdDebug(14140) << k_funcinfo << "webcam " << GUID << endl;
+
+ Webcam::Who who;
+ if(GUID=="4BD96FC0-AB17-4425-A14A-439185962DC8")
+ { //that mean "I want to send MY webcam"
+ who=Webcam::wViewer;
+ }
+ else if(GUID=="1C9AA97E-9C05-4583-A3BD-908A196F1E92")
+ { //that mean "I want YOU to send YOUR webcam"
+ who=Webcam::wProducer;
+ }
+ else
+ { //unknown GUID
+ //current->error();
+ kdWarning(14140) << k_funcinfo << "Unknown GUID " << GUID << endl;
+ return;
+ }
+
+ TransferContext *current = new P2P::Webcam(who, from, this, sessionId.toUInt());
+ current->m_branch = branch;
+ current->m_callId = callId;
+
+ // Add the transfer to the list.
+ m_sessions.insert(sessionId.toUInt(), current);
+ // Acknowledge the session request.
+ current->acknowledge(message);
+ TQTimer::singleShot(0,current, TQT_SLOT(askIncommingInvitation()) );
+#endif
+ }
+ }
+ else if(message.header.sessionId == 64)
+ {
+ // A contact has sent an inkformat (handwriting) gif.
+ // NOTE The entire message body is UTF16 encoded.
+ TQString body = "";
+ for (TQ_UINT32 i=0; i < message.header.totalDataSize; i++){
+ if (message.body[i] != TQChar('\0')){
+ body += TQChar(message.body[i]);
+ }
+ }
+
+ TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
+ regex.search(body);
+ TQString contentType = regex.cap(1);
+
+ if(contentType == "image/gif")
+ {
+ IncomingTransfer transfer(message.source, this, message.header.sessionId);
+ transfer.acknowledge(message);
+
+ regex = TQRegExp("base64:([0-9a-zA-Z+/=]*)");
+ regex.search(body);
+ TQString base64 = regex.cap(1);
+ TQByteArray image;
+// Convert from base64 encoding to byte array.
+ KCodecs::base64Decode(base64.utf8(), image);
+// Create a temporary file to store the image data.
+ KTempFile *ink = new KTempFile(locateLocal("tmp", "inkformatgif-" ), ".gif");
+ ink->setAutoDelete(true);
+// Save the image data to disk.
+ ink->file()->writeBlock(image);
+ ink->file()->close();
+ displayIconReceived(ink, "inkformatgif");
+ ink = 0l;
+ }
+ }
+ }
+}
+
+void Dispatcher::messageAcknowledged(unsigned int correlationId, bool fullReceive)
+{
+ if(fullReceive)
+ {
+ TransferContext *current = 0l;
+ TQMap::Iterator it = m_sessions.begin();
+ for(; it != m_sessions.end(); it++)
+ {
+ current = it.data();
+ if(current->m_transactionId == correlationId)
+ {
+ // Inform the transfer object of the acknowledge.
+ current->readyWrite();
+ break;
+ }
+ }
+ }
+}
+
+Kopete::Contact* Dispatcher::getContactByAccountId(const TQString& accountId)
+{
+ Kopete::Contact *contact = 0l;
+ if(parent())
+ {
+ // Retrieve the contact from the current chat session context.
+ Kopete::ChatSession *session = dynamic_cast(parent()->parent());
+ if(session)
+ {
+ contact = session->account()->contacts()[accountId];
+ session->setCanBeDeleted(false);
+ }
+ }
+ return contact;
+}
+
+Dispatcher::CallbackChannel::CallbackChannel(MSNSwitchBoardSocket *switchboard)
+{
+ m_switchboard = switchboard;
+}
+
+Dispatcher::CallbackChannel::~CallbackChannel()
+{}
+
+TQ_UINT32 Dispatcher::CallbackChannel::send(const TQByteArray& stream)
+{
+ return m_switchboard->sendCommand("MSG", "D", true, stream, true);
+}
+
+Dispatcher::CallbackChannel* Dispatcher::callbackChannel()
+{
+ if(m_callbackChannel == 0l){
+ MSNSwitchBoardSocket *callback = dynamic_cast(parent());
+ if(callback == 0l) return 0l;
+ m_callbackChannel = new Dispatcher::CallbackChannel(callback);
+ }
+
+ return m_callbackChannel;
+}
+
+#include "dispatcher.moc"
diff --git a/kopete/protocols/msn/dispatcher.h b/kopete/protocols/msn/dispatcher.h
new file mode 100644
index 00000000..65b8dd3d
--- /dev/null
+++ b/kopete/protocols/msn/dispatcher.h
@@ -0,0 +1,108 @@
+/*
+ dispatcher.h - msn p2p protocol
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef DISPATCHER_H
+#define DISPATCHER_H
+
+#include
+#include
+
+#include "kopete_export.h"
+
+#include "p2p.h"
+#include "messageformatter.h"
+#include "incomingtransfer.h"
+#include "outgoingtransfer.h"
+
+
+namespace Kopete { class Contact; }
+class MSNSwitchBoardSocket;
+
+/**
+@author Kopete Developers
+*/
+namespace P2P{
+ class IncomingTransfer;
+ class OutgoingTransfer;
+
+ class KOPETE_EXPORT Dispatcher : public TQObject
+ { Q_OBJECT
+
+ public:
+ Dispatcher(TQObject *parent, const TQString& contact, const TQStringList &ip);
+ ~Dispatcher();
+
+ void detach(TransferContext* transfer);
+ TQString localContact();
+ void requestDisplayIcon(const TQString& from, const TQString& msnObject);
+ void sendFile(const TQString& path, TQ_INT64 fileSize, const TQString& to);
+ void sendImage(const TQString& fileName, const TQString& to);
+ TQString m_pictureUrl;
+ TQMap objectList;
+
+#if MSN_WEBCAM
+ void startWebcam(const TQString &myHandle, const TQString &msgHandle, bool wantToReceive);
+#endif
+
+
+ public slots:
+ void slotReadMessage(const TQString &from, const TQByteArray& stream);
+ void messageAcknowledged(unsigned int correlationId, bool fullReceive);
+
+ signals:
+ void sendCommand(const TQString &cmd, const TQString &args = TQString(), bool addId = true, const TQByteArray &body = TQByteArray(), bool binary=false);
+ void displayIconReceived(KTempFile* file, const TQString& msnObject);
+ void incomingTransfer(const TQString& from, const TQString& fileName, TQ_INT64 fileSize);
+
+ private:
+ class CallbackChannel
+ {
+ public:
+ CallbackChannel(MSNSwitchBoardSocket *switchboard);
+ ~CallbackChannel();
+
+ TQ_UINT32 send(const TQByteArray& stream);
+
+ private:
+ MSNSwitchBoardSocket *m_switchboard;
+ };
+
+ public:
+ CallbackChannel* callbackChannel();
+ /**
+ * IP's of this compiter, the first one is the one seen by the server.
+ */
+ TQStringList localIp() { return m_ip; }
+
+
+ private:
+ void dispatch(const P2P::Message& message);
+ Kopete::Contact* getContactByAccountId(const TQString& accountId);
+
+ P2P::MessageFormatter m_messageFormatter;
+ TQMap m_sessions;
+ TQMap m_messageBuffer;
+ TQString m_contact;
+ CallbackChannel *m_callbackChannel;
+ TQStringList m_ip;
+
+ friend class P2P::TransferContext;
+ friend class P2P::IncomingTransfer;
+ friend class P2P::OutgoingTransfer;
+ };
+}
+
+#endif
diff --git a/kopete/protocols/msn/dummy.cpp b/kopete/protocols/msn/dummy.cpp
new file mode 100644
index 00000000..6edd39fa
--- /dev/null
+++ b/kopete/protocols/msn/dummy.cpp
@@ -0,0 +1,3 @@
+#include "kdemacros.h"
+extern "C" KDE_EXPORT void *init_libkopete_msn_shared();
+extern "C" KDE_EXPORT void *init_kopete_msn() { return init_libkopete_msn_shared(); }
diff --git a/kopete/protocols/msn/icons/CMakeLists.txt b/kopete/protocols/msn/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/msn/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/msn/icons/Makefile.am b/kopete/protocols/msn/icons/Makefile.am
new file mode 100644
index 00000000..9143c6b4
--- /dev/null
+++ b/kopete/protocols/msn/icons/Makefile.am
@@ -0,0 +1,2 @@
+kopeteicondir = $(kde_datadir)/kopete/icons
+kopeteicon_ICON = AUTO
diff --git a/kopete/protocols/msn/icons/cr128-app-msn_protocol.png b/kopete/protocols/msn/icons/cr128-app-msn_protocol.png
new file mode 100644
index 00000000..dc94a4e9
Binary files /dev/null and b/kopete/protocols/msn/icons/cr128-app-msn_protocol.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_away.png b/kopete/protocols/msn/icons/cr16-action-msn_away.png
new file mode 100644
index 00000000..cbbd45fc
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_away.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_blocked.png b/kopete/protocols/msn/icons/cr16-action-msn_blocked.png
new file mode 100644
index 00000000..80efc4c7
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_blocked.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_brb.png b/kopete/protocols/msn/icons/cr16-action-msn_brb.png
new file mode 100644
index 00000000..3f1a0d30
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_brb.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_busy.png b/kopete/protocols/msn/icons/cr16-action-msn_busy.png
new file mode 100644
index 00000000..b3dcac08
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_busy.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_connecting.mng b/kopete/protocols/msn/icons/cr16-action-msn_connecting.mng
new file mode 100644
index 00000000..38629273
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_connecting.mng differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_invisible.png b/kopete/protocols/msn/icons/cr16-action-msn_invisible.png
new file mode 100644
index 00000000..ce42bef0
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_invisible.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_lunch.png b/kopete/protocols/msn/icons/cr16-action-msn_lunch.png
new file mode 100644
index 00000000..abf42e3f
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_lunch.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_na.png b/kopete/protocols/msn/icons/cr16-action-msn_na.png
new file mode 100644
index 00000000..b1aa91af
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_na.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_newmsg.png b/kopete/protocols/msn/icons/cr16-action-msn_newmsg.png
new file mode 100644
index 00000000..d42bb0ae
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_newmsg.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_offline.png b/kopete/protocols/msn/icons/cr16-action-msn_offline.png
new file mode 100644
index 00000000..5cf9ffd5
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_offline.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_online.png b/kopete/protocols/msn/icons/cr16-action-msn_online.png
new file mode 100644
index 00000000..71169ad2
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_online.png differ
diff --git a/kopete/protocols/msn/icons/cr16-action-msn_phone.png b/kopete/protocols/msn/icons/cr16-action-msn_phone.png
new file mode 100644
index 00000000..857ec14a
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-action-msn_phone.png differ
diff --git a/kopete/protocols/msn/icons/cr16-app-msn_protocol.png b/kopete/protocols/msn/icons/cr16-app-msn_protocol.png
new file mode 100644
index 00000000..a18ff5d4
Binary files /dev/null and b/kopete/protocols/msn/icons/cr16-app-msn_protocol.png differ
diff --git a/kopete/protocols/msn/icons/cr32-app-msn_protocol.png b/kopete/protocols/msn/icons/cr32-app-msn_protocol.png
new file mode 100644
index 00000000..2c9b130b
Binary files /dev/null and b/kopete/protocols/msn/icons/cr32-app-msn_protocol.png differ
diff --git a/kopete/protocols/msn/icons/cr48-app-msn_protocol.png b/kopete/protocols/msn/icons/cr48-app-msn_protocol.png
new file mode 100644
index 00000000..ad495100
Binary files /dev/null and b/kopete/protocols/msn/icons/cr48-app-msn_protocol.png differ
diff --git a/kopete/protocols/msn/icons/cr64-app-msn_protocol.png b/kopete/protocols/msn/icons/cr64-app-msn_protocol.png
new file mode 100644
index 00000000..338f81bf
Binary files /dev/null and b/kopete/protocols/msn/icons/cr64-app-msn_protocol.png differ
diff --git a/kopete/protocols/msn/incomingtransfer.cpp b/kopete/protocols/msn/incomingtransfer.cpp
new file mode 100644
index 00000000..0da4a04c
--- /dev/null
+++ b/kopete/protocols/msn/incomingtransfer.cpp
@@ -0,0 +1,384 @@
+/*
+ incomingtransfer.cpp - msn p2p protocol
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "incomingtransfer.h"
+using P2P::TransferContext;
+using P2P::IncomingTransfer;
+using P2P::Message;
+
+// Kde includes
+#include
+#include
+#include
+#include
+#include
+#include
+using namespace KNetwork;
+
+// TQt includes
+#include
+#include
+
+// Kopete includes
+#include
+
+IncomingTransfer::IncomingTransfer(const TQString& from, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId)
+: TransferContext(from,dispatcher,sessionId)
+{
+ m_direction = P2P::Incoming;
+ m_listener = 0l;
+}
+
+IncomingTransfer::~IncomingTransfer()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+ if(m_listener)
+ {
+ delete m_listener;
+ m_listener = 0l;
+ }
+
+ if(m_socket)
+ {
+ delete m_socket;
+ m_socket = 0l;
+ }
+}
+
+
+void IncomingTransfer::slotTransferAccepted(Kopete::Transfer* transfer, const TQString& /*fileName*/)
+{
+ TQ_UINT32 sessionId = transfer->info().internalId().toUInt();
+ if(sessionId!=m_sessionId)
+ return;
+
+ TQObject::connect(transfer , TQT_SIGNAL(transferCanceled()), this, TQT_SLOT(abort()));
+ m_transfer = transfer;
+
+ TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
+ sendMessage(OK, content);
+
+ TQObject::disconnect(Kopete::TransferManager::transferManager(), 0l, this, 0l);
+}
+
+void IncomingTransfer::slotTransferRefused(const Kopete::FileTransferInfo& info)
+{
+ TQ_UINT32 sessionId = info.internalId().toUInt();
+ if(sessionId!=m_sessionId)
+ return;
+
+ TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
+ // Send the sending client a cancelation message.
+ sendMessage(DECLINE, content);
+ m_state=Finished;
+
+ TQObject::disconnect(Kopete::TransferManager::transferManager(), 0l, this, 0l);
+}
+
+
+
+void IncomingTransfer::acknowledged()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+
+ switch(m_state)
+ {
+ case Invitation:
+ // NOTE UDI: base identifier acknowledge message, ignore.
+ // UDI: 200 OK message should follow.
+ if(m_type == File)
+ {
+ // FT: 200 OK acknowledged message.
+ // If this is the first connection between the two clients, a direct connection invitation
+ // should follow. Otherwise, the file transfer may start right away.
+ if(m_transfer)
+ {
+ TQFile *destination = new TQFile(m_transfer->destinationURL().path());
+ if(!destination->open(IO_WriteOnly))
+ {
+ m_transfer->slotError(TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, i18n("Cannot open file for writing"));
+ m_transfer = 0l;
+
+ error();
+ return;
+ }
+ m_file = destination;
+ }
+ m_state = Negotiation;
+ }
+ break;
+
+ case Negotiation:
+ // 200 OK acknowledge message.
+ break;
+
+ case DataTransfer:
+ break;
+
+ case Finished:
+ // UDI: Bye acknowledge message.
+ m_dispatcher->detach(this);
+ break;
+ }
+}
+
+void IncomingTransfer::processMessage(const Message& message)
+{
+ if(m_file && (message.header.flag == 0x20 || message.header.flag == 0x01000030))
+ {
+ // UserDisplayIcon data or File data is in this message.
+ // Write the recieved data to the file.
+ kdDebug(14140) << k_funcinfo << TQString("Received, %1 bytes").arg(message.header.dataSize) << endl;
+
+ m_file->writeBlock(message.body.data(), message.header.dataSize);
+ if(m_transfer){
+ m_transfer->slotProcessed(message.header.dataOffset + message.header.dataSize);
+ }
+
+ if((message.header.dataOffset + message.header.dataSize) == message.header.totalDataSize)
+ {
+ // Transfer is complete.
+ if(m_type == UserDisplayIcon){
+ m_tempFile->close();
+ m_dispatcher->displayIconReceived(m_tempFile, m_object);
+ m_tempFile = 0l;
+ m_file = 0l;
+ }
+ else
+ {
+ m_file->close();
+ }
+
+ m_isComplete = true;
+ // Send data acknowledge message.
+ acknowledge(message);
+
+ if(m_type == UserDisplayIcon)
+ {
+ m_state = Finished;
+ // Send BYE message.
+ sendMessage(BYE, "\r\n");
+ }
+ }
+ }
+ else if(message.header.dataSize == 4 && message.applicationIdentifier == 1)
+ {
+ // Data preparation message.
+ //if (m_tempFile->name().isEmpty() == false) {
+ // TQFile::remove(m_tempFile->name());
+ //}
+ m_tempFile = new KTempFile(locateLocal("tmp", "msnpicture--"), ".png");
+ m_tempFile->setAutoDelete(true);
+ m_file = m_tempFile->file();
+ m_state = DataTransfer;
+ // Send data preparation acknowledge message.
+ acknowledge(message);
+ }
+ else
+ {
+ TQString body =
+ TQCString(message.body.data(), message.header.dataSize);
+// kdDebug(14140) << k_funcinfo << "received, " << body << endl;
+
+ if(body.startsWith("INVITE"))
+ {
+ // Retrieve some MSNSLP headers used when
+ // replying to this INVITE message.
+ TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
+ regex.search(body);
+ m_branch = regex.cap(1);
+ // NOTE Call-ID never changes.
+ regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
+ regex.search(body);
+ m_callId = regex.cap(1);
+ regex = TQRegExp("Bridges: ([^\r\n]*)\r\n");
+ regex.search(body);
+ TQString bridges = regex.cap(1);
+ // The NetID field is 0 if the Conn-Type is
+ // Direct-Connect or Firewall, otherwise, it is
+ // a randomly generated number.
+ regex = TQRegExp("NetID: (\\-?\\d+)\r\n");
+ regex.search(body);
+ TQString netId = regex.cap(1);
+ kdDebug(14140) << "net id, " << netId << endl;
+ // Connection Types
+ // - Direct-Connect
+ // - Port-Restrict-NAT
+ // - IP-Restrict-NAT
+ // - Symmetric-NAT
+ // - Firewall
+ regex = TQRegExp("Conn-Type: ([^\r\n]+)\r\n");
+ regex.search(body);
+ TQString connType = regex.cap(1);
+
+ bool wouldListen = false;
+ if(netId.toUInt() == 0 && connType == "Direct-Connect"){
+ wouldListen = true;
+
+ }
+ else if(connType == "IP-Restrict-NAT"){
+ wouldListen = true;
+ }
+#if 1
+ wouldListen = false; // TODO Direct connection support
+#endif
+ TQString content;
+
+ if(wouldListen)
+ {
+ // Create a listening socket for direct file transfer.
+ m_listener = new TDEServerSocket("", "");
+ m_listener->setResolutionEnabled(true);
+ // Create the callback that will try to accept incoming connections.
+ TQObject::connect(m_listener, TQT_SIGNAL(readyAccept()), TQT_SLOT(slotAccept()));
+ TQObject::connect(m_listener, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotListenError(int)));
+ // Listen for incoming connections.
+ bool isListening = m_listener->listen(1);
+ kdDebug(14140) << k_funcinfo << (isListening ? "listening" : "not listening") << endl;
+ kdDebug(14140) << k_funcinfo
+ << "local endpoint, " << m_listener->localAddress().nodeName()
+ << endl;
+
+ content = "Bridge: TCPv1\r\n"
+ "Listening: true\r\n" +
+ TQString("Hashed-Nonce: {%1}\r\n").arg(P2P::Uid::createUid()) +
+ TQString("IPv4Internal-Addrs: %1\r\n").arg(m_listener->localAddress().nodeName()) +
+ TQString("IPv4Internal-Port: %1\r\n").arg(m_listener->localAddress().serviceName()) +
+ "\r\n";
+ }
+ else
+ {
+ content =
+ "Bridge: TCPv1\r\n"
+ "Listening: false\r\n"
+ "Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
+ "\r\n";
+ }
+
+ m_state = DataTransfer;
+
+ if (m_type != File)
+ {
+ // NOTE For file transfers, the connection invite *must not* be acknowledged in any way
+ // as this trips MSN 7.5
+
+ acknowledge(message);
+ // Send 200 OK message to the sending client.
+ sendMessage(OK, content);
+ }
+ }
+ else if(body.startsWith("BYE"))
+ {
+ m_state = Finished;
+ // Send the sending client an acknowledge message.
+ acknowledge(message);
+
+ if(m_file && m_transfer)
+ {
+ if(m_isComplete){
+ // The transfer is complete.
+ m_transfer->slotComplete();
+ }
+ else
+ {
+ // The transfer has been canceled remotely.
+ if(m_transfer){
+ // Inform the user of the file transfer cancelation.
+ m_transfer->slotError(TDEIO::ERR_ABORTED, i18n("File transfer canceled."));
+ }
+ // Remove the partially received file.
+ m_file->remove();
+ }
+ }
+
+ // Dispose of this transfer context.
+ m_dispatcher->detach(this);
+ }
+ else if(body.startsWith("MSNSLP/1.0 200 OK"))
+ {
+ if(m_type == UserDisplayIcon){
+ m_state = Negotiation;
+ // Acknowledge the 200 OK message.
+ acknowledge(message);
+ }
+ }
+ }
+}
+
+void IncomingTransfer::slotListenError(int /*errorCode*/)
+{
+ kdDebug(14140) << k_funcinfo << m_listener->errorString() << endl;
+}
+
+void IncomingTransfer::slotAccept()
+{
+ // Try to accept an incoming connection from the sending client.
+ m_socket = static_cast(m_listener->accept());
+ if(!m_socket)
+ {
+ // NOTE If direct connection fails, the sending
+ // client wil transfer the file data through the
+ // existing session.
+ kdDebug(14140) << k_funcinfo << "Direct connection failed." << endl;
+ // Close the listening endpoint.
+ m_listener->close();
+ return;
+ }
+
+ kdDebug(14140) << k_funcinfo << "Direct connection established." << endl;
+
+ // Set the socket to non blocking,
+ // enable the ready read signal and disable
+ // ready write signal.
+ // NOTE readyWrite consumes too much cpu usage.
+ m_socket->setBlocking(false);
+ m_socket->enableRead(true);
+ m_socket->enableWrite(false);
+
+ // Create the callback that will try to read bytes from the accepted socket.
+ TQObject::connect(m_socket, TQT_SIGNAL(readyRead()), this, TQT_SLOT(slotSocketRead()));
+ // Create the callback that will try to handle the socket close event.
+ TQObject::connect(m_socket, TQT_SIGNAL(closed()), this, TQT_SLOT(slotSocketClosed()));
+ // Create the callback that will try to handle the socket error event.
+ TQObject::connect(m_socket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
+}
+
+void IncomingTransfer::slotSocketRead()
+{
+ int available = m_socket->bytesAvailable();
+ kdDebug(14140) << k_funcinfo << available << ", bytes available." << endl;
+ if(available > 0)
+ {
+ TQByteArray buffer(available);
+ m_socket->readBlock(buffer.data(), buffer.size());
+
+ if(TQString(buffer) == "foo"){
+ kdDebug(14140) << "Connection Check." << endl;
+ }
+ }
+}
+
+void IncomingTransfer::slotSocketClosed()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+}
+
+void IncomingTransfer::slotSocketError(int errorCode)
+{
+ kdDebug(14140) << k_funcinfo << errorCode << endl;
+}
+
+#include "incomingtransfer.moc"
diff --git a/kopete/protocols/msn/incomingtransfer.h b/kopete/protocols/msn/incomingtransfer.h
new file mode 100644
index 00000000..3ce3f391
--- /dev/null
+++ b/kopete/protocols/msn/incomingtransfer.h
@@ -0,0 +1,58 @@
+/*
+ incomingtransfer.h - msn p2p protocol
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef INCOMINGTRANSFER_H
+#define INCOMINGTRANSFER_H
+
+#include "p2p.h"
+#include "dispatcher.h"
+
+namespace KNetwork{
+ class TDEServerSocket;
+}
+
+/**
+@author Kopete Developers
+*/
+namespace P2P{
+ class IncomingTransfer : public P2P::TransferContext
+ { Q_OBJECT
+
+ public:
+ IncomingTransfer(const TQString& from, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId);
+ virtual ~IncomingTransfer();
+
+ private slots:
+ void slotListenError(int errorCode);
+ void slotAccept();
+ void slotSocketRead();
+ void slotSocketClosed();
+ void slotSocketError(int errorCode);
+
+ void slotTransferAccepted(Kopete::Transfer* transfer, const TQString& fileName);
+ void slotTransferRefused(const Kopete::FileTransferInfo& info);
+
+
+ private:
+ virtual void acknowledged();
+ virtual void processMessage(const Message& message);
+
+ KTempFile *m_tempFile;
+ KNetwork::TDEServerSocket *m_listener;
+ };
+}
+
+#endif
diff --git a/kopete/protocols/msn/kopete_msn.desktop b/kopete/protocols/msn/kopete_msn.desktop
new file mode 100644
index 00000000..8f74c113
--- /dev/null
+++ b/kopete/protocols/msn/kopete_msn.desktop
@@ -0,0 +1,99 @@
+[Desktop Entry]
+Type=Service
+Icon=msn_protocol
+ServiceTypes=Kopete/Protocol
+X-TDE-Library=kopete_msn
+X-Kopete-Version=1000900
+X-Kopete-Messaging-Protocol=messaging/msn
+X-TDE-PluginInfo-Author=Kopete Developers
+X-TDE-PluginInfo-Email=kopete-devel@kde.org
+X-TDE-PluginInfo-Name=kopete_msn
+X-TDE-PluginInfo-Version=0.8.0
+X-TDE-PluginInfo-Website=http://kopete.kde.org
+X-TDE-PluginInfo-Category=Protocols
+X-TDE-PluginInfo-Depends=
+X-TDE-PluginInfo-License=GPL
+X-TDE-PluginInfo-EnabledByDefault=false
+Name=MSN Messenger
+Name[ar]=مرسال MSN
+Name[bn]=এমএসএন বার্তাবাহক
+Name[cy]=Negesydd MSN
+Name[da]=MSN-Messenger
+Name[de]=MSN-Messenger
+Name[eo]=MSN-mesaĝilo
+Name[fa]=پیامرسان اماسان
+Name[gl]=MSN Messanger
+Name[hi]=एमएसएन मैसेंजर
+Name[ja]=MSN メッセンジャー
+Name[km]=កម្មវិធីផ្ញើសារ MSN
+Name[lt]=MSN žinučių klientas
+Name[mk]=Гласник за MSN
+Name[nds]=MSN-Kortnarichtendeenst
+Name[ne]=एमएसएन मेसेन्जर
+Name[pa]=MSN ਸੁਨੇਹੇਦਾਰ
+Name[pl]=Komunikator MSN Messenger
+Name[pt_BR]=Mensageiro MSN
+Name[ro]=Mesaje instantanee MSN
+Name[tg]=MSN Пайёмбар
+Name[uk]=Кур'єр MSN
+Name[uz]=MSN mesenjer
+Name[uz@cyrillic]=MSN месенжер
+Comment=Protocol to connect to MSN Messenger
+Comment[ar]=البرتوكول سيتصل بمرسال MSN
+Comment[be]=Пратакол MSN Messenger
+Comment[bg]=Протокол за връзка с MSN Messenger
+Comment[bn]=এমএসএন বার্তাবাহকে সংযোগ করতে প্রোটোকল
+Comment[br]=Komenad kevreañ ouzh MSN Messenger
+Comment[bs]=MSN Messenger protokol
+Comment[ca]=Protocol per a connectar-se a MSN Messenger
+Comment[cs]=Protokol k připojení k MSN Messengeru
+Comment[cy]=Protocol i gysylltu â Negesydd MSN
+Comment[da]=Protokol til at forbinde til MSN-Messenger
+Comment[de]=Protokoll zur Verbindung mit dem MSN-Messenger
+Comment[el]=Πρωτόκολλο για σύνδεση στο MSN Messenger
+Comment[es]=Protocolo para conectar con MSN Messenger
+Comment[et]=Protokoll ühendumiseks MSN Messengeriga
+Comment[eu]=MSN Messenger-era konektatzeko protokoloa
+Comment[fa]=قرارداد برای اتصال به پیامرسان اماسان
+Comment[fi]=Yhteyskäytäntö MSN Messanger -verkkoon kytkeytymiseen
+Comment[fr]=Protocole pour se connecter sur MSN Messenger
+Comment[ga]=Prótacal chun ceangal le MSN Messenger
+Comment[gl]=Protocolo para se conectar ó MSN Messanger
+Comment[he]=פרוטוקול התחברות ל- MSN Messenger
+Comment[hi]=एमएसएन मैसेंजर से जुड़ने का प्रोटोकॉल
+Comment[hr]=Protokol za povezivanje na MSN Messenger
+Comment[hu]=Protokoll az MSN Messenger használatához
+Comment[is]=Samskiptamáti til að tengjast MSN Messenger
+Comment[it]=Protocollo per connessione a MSN Messenger
+Comment[ja]=MSN メッセンジャーに接続するプロトコル
+Comment[ka]=MSN Messenger დაკავშირების ოქმი
+Comment[kk]=MSN Messenger-ге қосылу протоколы
+Comment[km]=ពិធីការដើម្បីភ្ជាប់ទៅកម្មវិធីផ្ញើសារ MSN
+Comment[lt]=Protokolas prisijungimui prie MSN žinučių kliento
+Comment[mk]=Протокол за поврзување на Гласникот на MSN
+Comment[nb]=Protokoll for å koble til MSN Messenger
+Comment[nds]=Protokoll för't Tokoppeln na den MSN-Kortnarichtendeenst
+Comment[ne]=एमएसएन मेसेन्जरमा जडान गर्नुपर्ने प्रोटोकल
+Comment[nl]=Protocol voor MSN Messenger
+Comment[nn]=Protokoll for å kopla til MSN Messenger
+Comment[pl]=Protokół połączenia z serwerem MSN Messenger
+Comment[pt]=Um protocolo para ser ligar ao MSN Messenger
+Comment[pt_BR]=Protocolo para conexão ao MSN Messenger
+Comment[ro]=Protocol de conectare la MSN Messenger
+Comment[ru]=Протокол для подключения к MSN Messenger
+Comment[sk]=Protokol pre pripojenie k MSN Messenger
+Comment[sl]=Protokol za povezavo na MSN Messenger
+Comment[sr]=Протокол за повезивање на MSN Messenger
+Comment[sr@Latn]=Protokol za povezivanje na MSN Messenger
+Comment[sv]=Protokoll för att ansluta till MSN-meddelandeklient
+Comment[ta]= MSN Messenger யுடன் இணைக்க விதிமுறை
+Comment[tg]=Қарордоди пайвастшавӣ ба MSN Пайёмбар
+Comment[tr]=MSN Messenger'a bağlantı iletişim kuralı
+Comment[uk]=Протокол для з'єднання з MSN Messenger
+Comment[uz]=MSN mesenjer bilan aloqa oʻrnatish uchun protokol
+Comment[uz@cyrillic]=MSN месенжер билан алоқа ўрнатиш учун протокол
+Comment[wa]=Protocole po s' raloyî a MSN
+Comment[zh_CN]=连接到 MSN Messenger 协议
+Comment[zh_HK]=用來連接至 MSN Messenger 的通訊協定
+Comment[zh_TW]=連線到 MSN 的協定
+
diff --git a/kopete/protocols/msn/messageformatter.cpp b/kopete/protocols/msn/messageformatter.cpp
new file mode 100644
index 00000000..0ca71789
--- /dev/null
+++ b/kopete/protocols/msn/messageformatter.cpp
@@ -0,0 +1,192 @@
+/*
+ messageformatter.cpp - msn p2p protocol
+
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "messageformatter.h"
+#include "p2p.h"
+
+// TQt includes
+#include
+#include
+
+// Kde includes
+#include
+
+using P2P::MessageFormatter;
+using P2P::Message;
+
+MessageFormatter::MessageFormatter(TQObject *parent, const char *name) : TQObject(parent, name)
+{}
+
+MessageFormatter::~MessageFormatter()
+{}
+
+Message MessageFormatter::readMessage(const TQByteArray& stream, bool compact)
+{
+ Message inbound;
+
+ TQ_UINT32 index = 0;
+ if(compact == false)
+ {
+ // Determine the end position of the message header.
+ while(index < stream.size())
+ {
+ if(stream[index++] == '\n'){
+ if(stream[index - 3] == '\n')
+ break;
+ }
+ }
+
+ // Retrieve the message header.
+ TQString messageHeader = TQCString(stream.data(), index);
+
+ // Retrieve the message mime version, content type,
+ // and p2p destination.
+ TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
+ regex.search(messageHeader);
+ TQString contentType = regex.cap(1);
+
+ if(contentType != "application/x-msnmsgrp2p")
+ return inbound;
+
+// kdDebug(14140) << k_funcinfo << endl;
+
+ regex = TQRegExp("MIME-Version: (\\d.\\d)");
+ regex.search(messageHeader);
+ inbound.mimeVersion = regex.cap(1);
+ inbound.contentType = contentType;
+ regex = TQRegExp("P2P-Dest: ([^\r\n]*)");
+ regex.search(messageHeader);
+ TQString destination = regex.cap(1);
+ }
+
+ TQDataStream reader(stream, IO_ReadOnly);
+ reader.setByteOrder(TQDataStream::LittleEndian);
+ // Seek to the start position of the message
+ // transport header.
+ reader.device()->at(index);
+
+ // Read the message transport headers from the stream.
+ reader >> inbound.header.sessionId;
+ reader >> inbound.header.identifier;
+ reader >> inbound.header.dataOffset;
+ reader >> inbound.header.totalDataSize;
+ reader >> inbound.header.dataSize;
+ reader >> inbound.header.flag;
+ reader >> inbound.header.ackSessionIdentifier;
+ reader >> inbound.header.ackUniqueIdentifier;
+ reader >> inbound.header.ackDataSize;
+
+ /*kdDebug(14140)
+ << "session id, " << inbound.header.sessionId << endl
+ << "identifier, " << inbound.header.identifier << endl
+ << "data offset, " << inbound.header.dataOffset << endl
+ << "total size, " << inbound.header.totalDataSize << endl
+ << "data size, " << inbound.header.dataSize << endl
+ << "flag, " << inbound.header.flag << endl
+ << "ack session identifier, " << inbound.header.ackSessionIdentifier << endl
+ << "ack unique identifier, " << inbound.header.ackUniqueIdentifier << endl
+ << "ack data size, " << inbound.header.ackDataSize
+ << endl;*/
+
+ // Read the message body from the stream.
+ if(inbound.header.dataSize > 0){
+ inbound.body.resize(inbound.header.dataSize);
+ reader.readRawBytes(inbound.body.data(), inbound.header.dataSize);
+ }
+
+ if(compact == false)
+ {
+ reader.setByteOrder(TQDataStream::BigEndian);
+ // Read the message application identifier from the stream.
+ reader >> inbound.applicationIdentifier;
+
+/* kdDebug(14140)
+ << "application identifier, " << inbound.applicationIdentifier
+ << endl;*/
+ }
+
+ return inbound;
+}
+
+void MessageFormatter::writeMessage(const Message& message, TQByteArray& stream, bool compact)
+{
+// kdDebug(14140) << k_funcinfo << endl;
+
+ TQDataStream writer(stream, IO_WriteOnly);
+ writer.setByteOrder(TQDataStream::LittleEndian);
+
+ if(compact == false)
+ {
+ const TQCString messageHeader = TQString("MIME-Version: 1.0\r\n"
+ "Content-Type: application/x-msnmsgrp2p\r\n"
+ "P2P-Dest: " + message.destination + "\r\n"
+ "\r\n").utf8();
+ // Set the capacity of the message buffer.
+ stream.resize(messageHeader.length() + 48 + message.body.size() + 4);
+ // Write the message header to the stream
+ writer.writeRawBytes(messageHeader.data(), messageHeader.length());
+ }
+ else
+ {
+ // Set the capacity of the message buffer.
+ stream.resize(4 + 48 + message.body.size());
+ // Write the message size to the stream.
+ writer << (TQ_INT32)(48+message.body.size());
+ }
+
+
+ // Write the transport headers to the stream.
+ writer << message.header.sessionId;
+ writer << message.header.identifier;
+ writer << message.header.dataOffset;
+ writer << message.header.totalDataSize;
+ writer << message.header.dataSize;
+ writer << message.header.flag;
+ writer << message.header.ackSessionIdentifier;
+ writer << message.header.ackUniqueIdentifier;
+ writer << message.header.ackDataSize;
+
+/* kdDebug(14140)
+ << "session id, " << message.header.sessionId << endl
+ << "identifier, " << message.header.identifier << endl
+ << "data offset, " << message.header.dataOffset << endl
+ << "total size, " << message.header.totalDataSize << endl
+ << "data size, " << message.header.dataSize << endl
+ << "flag, " << message.header.flag << endl
+ << "ack session identifier, " << message.header.ackSessionIdentifier << endl
+ << "ack unique identifier, " << message.header.ackUniqueIdentifier << endl
+ << "ack data size, " << message.header.ackDataSize
+ << endl;
+*/
+ if(message.body.size() > 0){
+ // Write the messge body to the stream.
+ writer.writeRawBytes(message.body.data(), message.body.size());
+ }
+
+ if(compact == false)
+ {
+ // Seek to the message application identifier section.
+ writer.setByteOrder(TQDataStream::BigEndian);
+ // Write the message application identifier to the stream.
+ writer << message.applicationIdentifier;
+
+/* kdDebug(14140)
+ << "application identifier, " << message.applicationIdentifier
+ << endl;
+ */
+ }
+}
+
+#include "messageformatter.moc"
diff --git a/kopete/protocols/msn/messageformatter.h b/kopete/protocols/msn/messageformatter.h
new file mode 100644
index 00000000..fb29c300
--- /dev/null
+++ b/kopete/protocols/msn/messageformatter.h
@@ -0,0 +1,41 @@
+/*
+ messageformatter.h - msn p2p protocol
+
+ Copyright (c) 2005 by Gregg Edghill
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef MESSAGEFORMATTER_H
+#define MESSAGEFORMATTER_H
+
+#include
+
+namespace P2P{
+ class Message;
+}
+
+/**
+@author Kopete Developers
+*/
+namespace P2P{
+ class MessageFormatter : public TQObject
+ { Q_OBJECT
+
+ public:
+ MessageFormatter(TQObject *parent = 0, const char *name = 0);
+ ~MessageFormatter();
+
+ Message readMessage(const TQByteArray& stream, bool compact=false);
+ void writeMessage(const Message& message, TQByteArray& stream, bool compact=false);
+ };
+}
+
+#endif
diff --git a/kopete/protocols/msn/msnaccount.cpp b/kopete/protocols/msn/msnaccount.cpp
new file mode 100644
index 00000000..c987bf1d
--- /dev/null
+++ b/kopete/protocols/msn/msnaccount.cpp
@@ -0,0 +1,1499 @@
+/*
+ msnaccount.h - Manages a single MSN account
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2003 by Martijn Klingens
+ Copyright (c) 2005 by Michaël Larouche
+
+ Kopete (c) 2002-2005 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "msnaccount.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "msncontact.h"
+#include "msnnotifysocket.h"
+#include "msnchatsession.h"
+#include "kopetecontactlist.h"
+#include "kopetegroup.h"
+#include "kopetemetacontact.h"
+#include "kopetepassword.h"
+#include "kopeteuiglobal.h"
+#include "kopeteglobal.h"
+#include "kopetechatsessionmanager.h"
+#include "contactaddednotifydialog.h"
+#include "kopeteutils.h"
+
+#include "sha1.h"
+
+
+#if !defined NDEBUG
+#include "msndebugrawcmddlg.h"
+#include
+#endif
+
+#if MSN_WEBCAM
+#include "avdevice/videodevicepool.h"
+#endif
+
+MSNAccount::MSNAccount( MSNProtocol *parent, const TQString& AccountID, const char *name )
+ : Kopete::PasswordedAccount ( parent, AccountID.lower(), 0, name )
+{
+ m_notifySocket = 0L;
+ m_connectstatus = MSNProtocol::protocol()->NLN;
+ m_addWizard_metaContact = 0L;
+ m_newContactList=false;
+
+ // Init the myself contact
+ setMyself( new MSNContact( this, accountId(), Kopete::ContactList::self()->myself() ) );
+ //myself()->setOnlineStatus( MSNProtocol::protocol()->FLN );
+
+ TQObject::connect( Kopete::ContactList::self(), TQT_SIGNAL( groupRenamed( Kopete::Group *, const TQString & ) ),
+ TQT_SLOT( slotKopeteGroupRenamed( Kopete::Group * ) ) );
+ TQObject::connect( Kopete::ContactList::self(), TQT_SIGNAL( groupRemoved( Kopete::Group * ) ),
+ TQT_SLOT( slotKopeteGroupRemoved( Kopete::Group * ) ) );
+
+ TQObject::connect( Kopete::ContactList::self(), TQT_SIGNAL( globalIdentityChanged(const TQString&, const TQVariant& ) ), TQT_SLOT( slotGlobalIdentityChanged(const TQString&, const TQVariant& ) ));
+
+ m_openInboxAction = new TDEAction( i18n( "Open Inbo&x..." ), "mail_generic", 0, this, TQT_SLOT( slotOpenInbox() ), this, "m_openInboxAction" );
+ m_changeDNAction = new TDEAction( i18n( "&Change Display Name..." ), TQString(), 0, this, TQT_SLOT( slotChangePublicName() ), this, "renameAction" );
+ m_startChatAction = new TDEAction( i18n( "&Start Chat..." ), "mail_generic", 0, this, TQT_SLOT( slotStartChat() ), this, "startChatAction" );
+
+
+ TDEConfigGroup *config=configGroup();
+
+ m_blockList = config->readListEntry( "blockList" ) ;
+ m_allowList = config->readListEntry( "allowList" ) ;
+ m_reverseList = config->readListEntry( "reverseList" ) ;
+
+ // Load the avatar
+ m_pictureFilename = locateLocal( "appdata", "msnpicture-"+ accountId().lower().replace(TQRegExp("[./~]"),"-") +".png" );
+ resetPictureObject(true);
+
+ static_cast( myself() )->setInfo( "PHH", config->readEntry("PHH") );
+ static_cast( myself() )->setInfo( "PHM", config->readEntry("PHM") );
+ static_cast( myself() )->setInfo( "PHW", config->readEntry("PHW") );
+ //this is the display name
+ static_cast( myself() )->setInfo( "MFN", config->readEntry("MFN") );
+
+ //construct the group list
+ //Before 2003-11-14 the MSN server allowed us to download the group list without downloading the whole contactlist, but it's not possible anymore
+ TQPtrList groupList = Kopete::ContactList::self()->groups();
+ for ( Kopete::Group *g = groupList.first(); g; g = groupList.next() )
+ {
+ TQString groupGuid=g->pluginData( protocol(), accountId() + " id" );
+ if ( !groupGuid.isEmpty() )
+ m_groupList.insert( groupGuid , g );
+ }
+
+ // Set the client Id for the myself contact. It sets what MSN feature we support.
+ m_clientId = MSNProtocol::MSNC4 | MSNProtocol::InkFormatGIF | MSNProtocol::SupportMultiPacketMessaging;
+
+#if MSN_WEBCAM
+ Kopete::AV::VideoDevicePool::self()->scanDevices();
+ if( Kopete::AV::VideoDevicePool::self()->hasDevices() )
+ {
+ m_clientId |= MSNProtocol::SupportWebcam;
+ }
+#endif
+}
+
+
+TQString MSNAccount::serverName()
+{
+ return configGroup()->readEntry( "serverName" , "messenger.hotmail.com" );
+}
+
+uint MSNAccount::serverPort()
+{
+ return configGroup()->readNumEntry( "serverPort" , 1863 );
+}
+
+bool MSNAccount::useHttpMethod() const
+{
+ return configGroup()->readBoolEntry( "useHttpMethod" , false );
+}
+
+TQString MSNAccount::myselfClientId() const
+{
+ return TQString::number(m_clientId, 10);
+}
+
+void MSNAccount::connectWithPassword( const TQString &passwd )
+{
+ m_newContactList=false;
+ if ( isConnected() )
+ {
+ kdDebug( 14140 ) << k_funcinfo <<"Ignoring Connect request "
+ << "(Already Connected)" << endl;
+ return;
+ }
+
+ if ( m_notifySocket )
+ {
+ kdDebug( 14140 ) << k_funcinfo <<"Ignoring Connect request (Already connecting)" << endl;
+ return;
+ }
+
+ m_password = passwd;
+
+ if ( m_password.isNull() )
+ {
+ kdDebug( 14140 ) << k_funcinfo <<"Abort connection (null password)" << endl;
+ return;
+ }
+
+
+ if ( contacts().count() <= 1 )
+ {
+ // Maybe the contactlist.xml has been removed, and the serial number not updated
+ // ( the 1 is for the myself contact )
+ configGroup()->writeEntry( "serial", 0 );
+ }
+
+ m_openInboxAction->setEnabled( false );
+
+ createNotificationServer(serverName(), serverPort());
+}
+
+void MSNAccount::createNotificationServer( const TQString &host, uint port )
+{
+ if(m_notifySocket) //we are switching from one to another notifysocket.
+ {
+ //remove every slots to that socket, so we won't delete receive signals
+ // from the old socket thinking they are from the new one
+ TQObject::disconnect( m_notifySocket , 0, this, 0 );
+ m_notifySocket->deleteLater(); //be sure it will be deleted
+ m_notifySocket=0L;
+ }
+
+ m_msgHandle.clear();
+
+ myself()->setOnlineStatus( MSNProtocol::protocol()->CNT );
+
+
+ m_notifySocket = new MSNNotifySocket( this, accountId() , m_password);
+ m_notifySocket->setUseHttpMethod( useHttpMethod() );
+
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( groupAdded( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotGroupAdded( const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( groupRenamed( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotGroupRenamed( const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( groupListed( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotGroupAdded( const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( groupRemoved( const TQString& ) ),
+ TQT_SLOT( slotGroupRemoved( const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( contactList(const TQString&, const TQString&, const TQString&, uint, const TQString& ) ),
+ TQT_SLOT( slotContactListed(const TQString&, const TQString&, const TQString&, uint, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL(contactAdded(const TQString&, const TQString&, const TQString&, const TQString&, const TQString& ) ),
+ TQT_SLOT( slotContactAdded(const TQString&, const TQString&, const TQString&, const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( contactRemoved(const TQString&, const TQString&, const TQString&, const TQString& ) ),
+ TQT_SLOT( slotContactRemoved(const TQString&, const TQString&, const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( statusChanged( const Kopete::OnlineStatus & ) ),
+ TQT_SLOT( slotStatusChanged( const Kopete::OnlineStatus & ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( invitedToChat( const TQString&, const TQString&, const TQString&, const TQString&, const TQString& ) ),
+ TQT_SLOT( slotCreateChat( const TQString&, const TQString&, const TQString&, const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( startChat( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotCreateChat( const TQString&, const TQString& ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( socketClosed() ),
+ TQT_SLOT( slotNotifySocketClosed() ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( newContactList() ),
+ TQT_SLOT( slotNewContactList() ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( receivedNotificationServer(const TQString&, uint ) ),
+ TQT_SLOT(createNotificationServer(const TQString&, uint ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( hotmailSeted( bool ) ),
+ m_openInboxAction, TQT_SLOT( setEnabled( bool ) ) );
+ TQObject::connect( m_notifySocket, TQT_SIGNAL( errorMessage(int, const TQString& ) ),
+ TQT_SLOT( slotErrorMessageReceived(int, const TQString& ) ) );
+
+ m_notifySocket->setStatus( m_connectstatus );
+ m_notifySocket->connect(host, port);
+}
+
+void MSNAccount::disconnect()
+{
+ if ( m_notifySocket )
+ m_notifySocket->disconnect();
+}
+
+TDEActionMenu * MSNAccount::actionMenu()
+{
+ TDEActionMenu *m_actionMenu=Kopete::Account::actionMenu();
+ if ( isConnected() )
+ {
+ m_openInboxAction->setEnabled( true );
+ m_startChatAction->setEnabled( true );
+ m_changeDNAction->setEnabled( true );
+ }
+ else
+ {
+ m_openInboxAction->setEnabled( false );
+ m_startChatAction->setEnabled( false );
+ m_changeDNAction->setEnabled( false );
+ }
+
+ m_actionMenu->popupMenu()->insertSeparator();
+
+ m_actionMenu->insert( m_changeDNAction );
+ m_actionMenu->insert( m_startChatAction );
+
+// m_actionMenu->popupMenu()->insertSeparator();
+
+ m_actionMenu->insert( m_openInboxAction );
+
+#if !defined NDEBUG
+ TDEActionMenu *debugMenu = new TDEActionMenu( "Debug", m_actionMenu );
+ debugMenu->insert( new TDEAction( i18n( "Send Raw C&ommand..." ), 0,
+ this, TQT_SLOT( slotDebugRawCommand() ), debugMenu, "m_debugRawCommand" ) );
+ m_actionMenu->popupMenu()->insertSeparator();
+ m_actionMenu->insert( debugMenu );
+#endif
+
+ return m_actionMenu;
+}
+
+MSNNotifySocket *MSNAccount::notifySocket()
+{
+ return m_notifySocket;
+}
+
+
+void MSNAccount::setOnlineStatus( const Kopete::OnlineStatus &status , const TQString &reason)
+{
+ kdDebug( 14140 ) << k_funcinfo << status.description() << endl;
+
+ // HACK: When changing song, do don't anything while connected
+ if( reason.contains("[Music]") && ( status == MSNProtocol::protocol()->UNK || status == MSNProtocol::protocol()->CNT ) )
+ return;
+
+ // Only send personal message when logged.
+ if( m_notifySocket && m_notifySocket->isLogged() )
+ {
+ // Only update the personal/status message, don't change the online status
+ // since it's the same.
+ if( reason.contains("[Music]") )
+ {
+ TQString personalMessage = reason.section("[Music]", 1);
+ setPersonalMessage( MSNProtocol::PersonalMessageMusic, personalMessage );
+
+ // Don't send un-needed status change.
+ return;
+ }
+ else
+ {
+ setPersonalMessage( MSNProtocol::PersonalMessageNormal, reason );
+ }
+ }
+
+ if(status.status()== Kopete::OnlineStatus::Offline)
+ disconnect();
+ else if ( m_notifySocket )
+ {
+ m_notifySocket->setStatus( status );
+ }
+ else
+ {
+ m_connectstatus = status;
+ connect();
+ }
+
+
+}
+
+void MSNAccount::slotStartChat()
+{
+
+ bool ok;
+ TQString handle = KInputDialog::getText( i18n( "Start Chat - MSN Plugin" ),
+ i18n( "Please enter the email address of the person with whom you want to chat:" ), TQString(), &ok ).lower();
+ if ( ok )
+ {
+ if ( MSNProtocol::validContactId( handle ) )
+ {
+ if ( !contacts()[ handle ] )
+ addContact( handle, handle, 0L, Kopete::Account::Temporary );
+
+ contacts()[ handle ]->execute();
+ }
+ else
+ {
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
+ i18n( "You must enter a valid email address." ), i18n( "MSN Plugin" ) );
+ }
+ }
+}
+
+void MSNAccount::slotDebugRawCommand()
+{
+#if !defined NDEBUG
+ if ( !isConnected() )
+ return;
+
+ MSNDebugRawCmdDlg *dlg = new MSNDebugRawCmdDlg( 0L );
+ int result = dlg->exec();
+ if ( result == TQDialog::Accepted && m_notifySocket )
+ {
+ m_notifySocket->sendCommand( dlg->command(), dlg->params(),
+ dlg->addId(), dlg->msg().replace( "\n", "\r\n" ).utf8() );
+ }
+ delete dlg;
+#endif
+}
+
+void MSNAccount::slotChangePublicName()
+{
+ if ( !isConnected() )
+ {
+ return;
+ //TODO: change it anyway, and sync at the next connection
+ }
+
+ bool ok;
+ TQString name = KInputDialog::getText( i18n( "Change Display Name - MSN Plugin" ),
+ i18n( "Enter the new display name by which you want to be visible to your friends on MSN:" ),
+ myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString(), &ok );
+
+ if ( ok )
+ {
+ if ( name.length() > 387 )
+ {
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n( "The display name you entered is too long. Please use a shorter name.\n"
+ "Your display name has not been changed." ),
+ i18n( "Change Display Name - MSN Plugin" ) );
+ return;
+ }
+
+ setPublicName( name );
+ }
+}
+
+
+void MSNAccount::slotOpenInbox()
+{
+ if ( m_notifySocket )
+ m_notifySocket->slotOpenInbox();
+}
+
+
+void MSNAccount::slotNotifySocketClosed()
+{
+ kdDebug( 14140 ) << k_funcinfo << endl;
+
+ Kopete::Account::DisconnectReason reason=(Kopete::Account::DisconnectReason)(m_notifySocket->disconnectReason());
+ m_notifySocket->deleteLater();
+ m_notifySocket = 0l;
+ myself()->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ setAllContactsStatus( MSNProtocol::protocol()->FLN );
+ disconnected(reason);
+
+
+ if(reason == Kopete::Account::OtherClient)
+ { //close all chat sessions, so new message will arive to the other client.
+
+ TQValueList sessions = Kopete::ChatSessionManager::self()->sessions();
+ TQValueList::Iterator it;
+ for (it=sessions.begin() ; it != sessions.end() ; it++ )
+ {
+ MSNChatSession *msnCS = dynamic_cast( *it );
+ if ( msnCS && msnCS->account() == this )
+ {
+ msnCS->slotCloseSession();
+ }
+ }
+ }
+
+#if 0
+ else if ( state == 0x10 ) // connection died unexpectedly
+ {
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error , i18n( "The connection with the MSN server was lost unexpectedly.\n"
+ "If you cannot reconnect now, the server might be down. In that case, please try again later." ),
+ i18n( "Connection Lost - MSN Plugin" ), KMessageBox::Notify );
+ }
+#endif
+ m_msgHandle.clear();
+ // kdDebug( 14140 ) << "MSNAccount::slotNotifySocketClosed - done" << endl;
+}
+
+void MSNAccount::slotStatusChanged( const Kopete::OnlineStatus &status )
+{
+// kdDebug( 14140 ) << k_funcinfo << status.internalStatus() << endl;
+ myself()->setOnlineStatus( status );
+
+ if(m_newContactList)
+ {
+ m_newContactList=false;
+
+ TQDictIterator it( contacts() );
+ for ( ; it.current(); ++it )
+ {
+ MSNContact *c = static_cast( *it );
+ if(c && c->isDeleted() && c->metaContact() && !c->metaContact()->isTemporary() && c!=myself())
+ {
+ if(c->serverGroups().isEmpty())
+ { //the contact is new, add it on the server
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ addContactServerside( c->contactId() , c->metaContact()->groups() );
+ }
+ else //the contact had been deleted, remove it.
+ {
+ c->deleteLater();
+ }
+ }
+ }
+ }
+}
+
+
+void MSNAccount::slotPersonalMessageChanged( const TQString& personalMessage )
+{
+ TQString oldPersonalMessage=myself()->property(MSNProtocol::protocol()->propPersonalMessage).value().toString() ;
+ if ( personalMessage != oldPersonalMessage )
+ {
+ myself()->setProperty( MSNProtocol::protocol()->propPersonalMessage, personalMessage );
+ configGroup()->writeEntry( "personalMessage" , personalMessage );
+ }
+}
+
+void MSNAccount::setPublicName( const TQString &publicName )
+{
+ if ( m_notifySocket )
+ {
+ m_notifySocket->changePublicName( publicName, TQString() );
+ }
+}
+
+void MSNAccount::setPersonalMessage( MSNProtocol::PersonalMessageType type, const TQString &personalMessage )
+{
+ if ( m_notifySocket )
+ {
+ m_notifySocket->changePersonalMessage( type, personalMessage );
+ }
+ /* Eh, if we can't change the display name, don't let make the user think it has changed
+ else if(type == MSNProtocol::PersonalMessageNormal) // Normal personalMessage, not a dynamic one that need formatting.
+ {
+ slotPersonalMessageChanged( personalMessage );
+ }*/
+}
+
+void MSNAccount::slotGroupAdded( const TQString& groupName, const TQString &groupGuid )
+{
+ if ( m_groupList.contains( groupGuid ) )
+ {
+ // Group can already be in the list since the idle timer does a 'List Groups'
+ // command. Simply return, don't issue a warning.
+ // kdDebug( 14140 ) << k_funcinfo << "Group " << groupName << " already in list, skipped." << endl;
+ return;
+ }
+
+ //--------- Find the appropriate Kopete::Group, or create one ---------//
+ TQPtrList groupList = Kopete::ContactList::self()->groups();
+ Kopete::Group *fallBack = 0L;
+
+ //check if we have one in the old group list. if yes, update the id translate map.
+ for(TQMap::Iterator it=m_oldGroupList.begin() ; it != m_oldGroupList.end() ; ++it )
+ {
+ Kopete::Group *g=it.data();
+ if (g && g->pluginData( protocol(), accountId() + " displayName" ) == groupName &&
+ g->pluginData( protocol(), accountId() + " id" ).isEmpty() )
+ { //it has the same name! we got it. (and it is not yet an msn group)
+ fallBack=g;
+ /*if ( g->displayName() != groupName )
+ {
+ // The displayName was changed in Kopete while we were offline
+ // FIXME: update the server right now
+ }*/
+ break;
+ }
+ }
+
+ if(!fallBack)
+ {
+ //it's certenly a new group ! search if one already exist with the same displayname.
+ for ( Kopete::Group *g = groupList.first(); g; g = groupList.next() )
+ {
+ /* --This has been replaced by the loop right before.
+ if ( !g->pluginData( protocol(), accountId() + " id" ).isEmpty() )
+ {
+ if ( g->pluginData( protocol(), accountId() + " id" ).toUInt() == groupNumber )
+ {
+ m_groupList.insert( groupNumber, g );
+ TQString oldGroupName;
+ if ( g->pluginData( protocol(), accountId() + " displayName" ) != groupName )
+ {
+ // The displayName of the group has been modified by another client
+ slotGroupRenamed( groupName, groupNumber );
+ }
+ return;
+ }
+ }
+ else {*/
+ if ( g->displayName() == groupName && (groupGuid.isEmpty()|| g->type()==Kopete::Group::Normal) &&
+ g->pluginData( protocol(), accountId() + " id" ).isEmpty() )
+ {
+ fallBack = g;
+ kdDebug( 14140 ) << k_funcinfo << "We didn't found the group " << groupName <<" in the old MSN group. But kopete has already one with the same name." << endl;
+ break;
+ }
+ }
+ }
+
+ if ( !fallBack )
+ {
+ if( groupGuid.isEmpty() )
+ { // The group #0 is an unremovable group. his default name is "~" ,
+ // but the official client rename it i18n("others contact") at the first
+ // connection.
+ // In many case, the users don't use that group as a real group, or just as
+ // a group to put all contact that are not sorted.
+ fallBack = Kopete::Group::topLevel();
+ }
+ else
+ {
+ fallBack = new Kopete::Group( groupName );
+ Kopete::ContactList::self()->addGroup( fallBack );
+ kdDebug( 14140 ) << k_funcinfo << "We didn't found the group " << groupName <<" So we're creating a new one." << endl;
+
+ }
+ }
+
+ fallBack->setPluginData( protocol(), accountId() + " id", groupGuid );
+ fallBack->setPluginData( protocol(), accountId() + " displayName", groupName );
+ m_groupList.insert( groupGuid, fallBack );
+
+ // We have pending groups that we need add a contact to
+ if ( tmp_addToNewGroup.contains(groupName) )
+ {
+ TQStringList list=tmp_addToNewGroup[groupName];
+ for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ TQString contactId = *it;
+ kdDebug( 14140 ) << k_funcinfo << "Adding to new group: " << contactId << endl;
+ MSNContact *c = static_cast(contacts()[contactId]);
+ if(c && c->hasProperty(MSNProtocol::protocol()->propGuid.key()) )
+ notifySocket()->addContact( contactId, MSNProtocol::FL, TQString(), c->guid(), groupGuid );
+ else
+ {
+ // If we get to here, we're currently adding a new contact, add the groupGUID to the groupList
+ // to add when contact will be added to contactlist.
+ if( tmp_addNewContactToGroup.contains( contactId ) )
+ tmp_addNewContactToGroup[contactId].append(groupGuid);
+ else
+ tmp_addNewContactToGroup.insert(contactId, TQStringList(groupGuid) );
+ }
+ }
+ tmp_addToNewGroup.remove(groupName);
+ }
+}
+
+void MSNAccount::slotGroupRenamed( const TQString &groupGuid, const TQString& groupName )
+{
+ if ( m_groupList.contains( groupGuid ) )
+ {
+ m_groupList[ groupGuid ]->setPluginData( protocol(), accountId() + " id", groupGuid );
+ m_groupList[ groupGuid ]->setPluginData( protocol(), accountId() + " displayName", groupName );
+ m_groupList[ groupGuid ]->setDisplayName( groupName );
+ }
+ else
+ {
+ slotGroupAdded( groupName, groupGuid );
+ }
+}
+
+void MSNAccount::slotGroupRemoved( const TQString& groupGuid )
+{
+ if ( m_groupList.contains( groupGuid ) )
+ {
+ m_groupList[ groupGuid ]->setPluginData( protocol(), TQMap() );
+ m_groupList.remove( groupGuid );
+ }
+}
+
+void MSNAccount::addGroup( const TQString &groupName, const TQString& contactToAdd )
+{
+ if ( !contactToAdd.isNull() )
+ {
+ if( tmp_addToNewGroup.contains(groupName) )
+ {
+ tmp_addToNewGroup[groupName].append(contactToAdd);
+ //A group with the same name is about to be added,
+ // we don't need to add a second group with the same name
+ kdDebug( 14140 ) << k_funcinfo << "no need to re-add " << groupName << " for " << contactToAdd << endl;
+ return;
+ }
+ else
+ {
+ tmp_addToNewGroup.insert(groupName,TQStringList(contactToAdd));
+ kdDebug( 14140 ) << k_funcinfo << "preparing to add " << groupName << " for " << contactToAdd << endl;
+ }
+ }
+
+ if ( m_notifySocket )
+ m_notifySocket->addGroup( groupName );
+
+}
+
+void MSNAccount::slotKopeteGroupRenamed( Kopete::Group *g )
+{
+ if ( notifySocket() && g->type() == Kopete::Group::Normal )
+ {
+ if ( !g->pluginData( protocol(), accountId() + " id" ).isEmpty() &&
+ g->displayName() != g->pluginData( protocol(), accountId() + " displayName" ) &&
+ m_groupList.contains( g->pluginData( protocol(), accountId() + " id" ) ) )
+ {
+ notifySocket()->renameGroup( g->displayName(), g->pluginData( protocol(), accountId() + " id" ) );
+ }
+ }
+}
+
+void MSNAccount::slotKopeteGroupRemoved( Kopete::Group *g )
+{
+ //The old gorup list is only used whe syncing the contactlist.
+ //We can assume the contactlist is already fully synced at this time.
+ //The group g is maybe in the oldGroupList. We remove everithing since
+ //we don't need it anymore, no need to search it
+ m_oldGroupList.clear();
+
+
+ if ( !g->pluginData( protocol(), accountId() + " id" ).isEmpty() )
+ {
+ TQString groupGuid = g->pluginData( protocol(), accountId() + " id" );
+ if ( !m_groupList.contains( groupGuid ) )
+ {
+ // the group is maybe already removed in the server
+ slotGroupRemoved( groupGuid );
+ return;
+ }
+
+ //this is also done later, but he have to do it now!
+ // (in slotGroupRemoved)
+ m_groupList.remove(groupGuid);
+
+ if ( groupGuid.isEmpty() )
+ {
+ // the group #0 can't be deleted
+ // then we set it as the top-level group
+ if ( g->type() == Kopete::Group::TopLevel )
+ return;
+
+ Kopete::Group::topLevel()->setPluginData( protocol(), accountId() + " id", "" );
+ Kopete::Group::topLevel()->setPluginData( protocol(), accountId() + " displayName", g->pluginData( protocol(), accountId() + " displayName" ) );
+ g->setPluginData( protocol(), accountId() + " id", TQString() ); // the group should be soon deleted, but make sure
+
+ return;
+ }
+
+ if ( m_notifySocket )
+ {
+ bool still_have_contact=false;
+ // if contact are contains only in the group we are removing, abort the
+ TQDictIterator it( contacts() );
+ for ( ; it.current(); ++it )
+ {
+ MSNContact *c = static_cast( it.current() );
+ if ( c && c->serverGroups().contains( groupGuid ) )
+ {
+ /** don't do that becasue theses may already have been sent
+ m_notifySocket->removeContact( c->contactId(), groupNumber, MSNProtocol::FL );
+ */
+ still_have_contact=true;
+ break;
+ }
+ }
+ if(!still_have_contact)
+ m_notifySocket->removeGroup( groupGuid );
+ }
+ }
+}
+
+void MSNAccount::slotNewContactList()
+{
+ m_oldGroupList=m_groupList;
+ for(TQMap::Iterator it=m_oldGroupList.begin() ; it != m_oldGroupList.end() ; ++it )
+ { //they are about to be changed
+ if(it.data())
+ it.data()->setPluginData( protocol(), accountId() + " id", TQString() );
+ }
+
+ m_allowList.clear();
+ m_blockList.clear();
+ m_reverseList.clear();
+ m_groupList.clear();
+ TDEConfigGroup *config=configGroup();
+ config->writeEntry( "blockList" , TQString() ) ;
+ config->writeEntry( "allowList" , TQString() );
+ config->writeEntry( "reverseList" , TQString() );
+
+ // clear all date information which will be received.
+ // if the information is not anymore on the server, it will not be received
+ TQDictIterator it( contacts() );
+ for ( ; it.current(); ++it )
+ {
+ MSNContact *c = static_cast( *it );
+ c->setBlocked( false );
+ c->setAllowed( false );
+ c->setReversed( false );
+ c->setDeleted( true );
+ c->setInfo( "PHH", TQString() );
+ c->setInfo( "PHW", TQString() );
+ c->setInfo( "PHM", TQString() );
+ c->removeProperty( MSNProtocol::protocol()->propGuid );
+ }
+ m_newContactList=true;
+}
+
+void MSNAccount::slotContactListed( const TQString& handle, const TQString& publicName, const TQString &contactGuid, uint lists, const TQString& groups )
+{
+ // On empty lists handle might be empty, ignore that
+ // ignore also the myself contact.
+ if ( handle.isEmpty() || handle==accountId())
+ return;
+
+ MSNContact *c = static_cast( contacts()[ handle ] );
+
+ if ( lists & 1 ) // FL
+ {
+ TQStringList contactGroups = TQStringList::split( ",", groups, false );
+ if ( c )
+ {
+ if( !c->metaContact() )
+ {
+ kdWarning( 14140 ) << k_funcinfo << "the contact " << c->contactId() << " has no meta contact" <setMetaContact(metaContact);
+ Kopete::ContactList::self()->addMetaContact( metaContact );
+ }
+
+ // Contact exists, update data.
+ // Merging difference between server contact list and Kopete::Contact's contact list into MetaContact's contact-list
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ if(!publicName.isEmpty() && publicName!=handle)
+ c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName );
+ else
+ c->removeProperty( Kopete::Global::Properties::self()->nickName() );
+ c->setProperty( MSNProtocol::protocol()->propGuid, contactGuid);
+
+ const TQMap oldServerGroups = c->serverGroups();
+ c->clearServerGroups();
+ for ( TQStringList::ConstIterator it = contactGroups.begin(); it != contactGroups.end(); ++it )
+ {
+ TQString newServerGroupID = *it;
+ if(m_groupList.contains(newServerGroupID))
+ {
+ Kopete::Group *newServerGroup=m_groupList[ newServerGroupID ] ;
+ c->contactAddedToGroup( newServerGroupID, newServerGroup );
+ if( !c->metaContact()->groups().contains(newServerGroup) )
+ {
+ // The contact has been added in a group by another client
+ c->metaContact()->addToGroup( newServerGroup );
+ }
+ }
+ }
+
+ for ( TQMap::ConstIterator it = oldServerGroups.begin(); it != oldServerGroups.end(); ++it )
+ {
+ Kopete::Group *old_group=m_oldGroupList[it.key()];
+ if(old_group)
+ {
+ TQString oldnewID=old_group->pluginData(protocol() , accountId() +" id");
+ if ( !oldnewID.isEmpty() && contactGroups.contains( oldnewID ) )
+ continue; //ok, it's correctn no need to do anything.
+
+ c->metaContact()->removeFromGroup( old_group );
+ }
+ }
+
+ c->setDeleted(false);
+
+ // Update server if the contact has been moved to another group while MSN was offline
+ c->sync();
+ }
+ else
+ {
+ Kopete::MetaContact *metaContact = new Kopete::MetaContact();
+
+ c = new MSNContact( this, handle, metaContact );
+ c->setDeleted(true); //we don't want to sync
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ if(!publicName.isEmpty() && publicName!=handle)
+ c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName );
+ else
+ c->removeProperty( Kopete::Global::Properties::self()->nickName() );
+ c->setProperty( MSNProtocol::protocol()->propGuid, contactGuid );
+
+ for ( TQStringList::Iterator it = contactGroups.begin();
+ it != contactGroups.end(); ++it )
+ {
+ TQString groupGuid = *it;
+ if(m_groupList.contains(groupGuid))
+ {
+ c->contactAddedToGroup( groupGuid, m_groupList[ groupGuid ] );
+ metaContact->addToGroup( m_groupList[ groupGuid ] );
+ }
+ }
+ Kopete::ContactList::self()->addMetaContact( metaContact );
+
+ c->setDeleted(false);
+ }
+ }
+ else //the contact is _not_ in the FL, it has been removed
+ {
+ if(c)
+ {
+ c->setOnlineStatus( static_cast(protocol())->UNK );
+ c->clearServerGroups();
+ //TODO: display a message and suggest to remove the contact.
+ // but i fear a simple messageBox QuestionYesNo here gives a nice crash.
+ //delete ct;
+ }
+ }
+ if ( lists & 2 )
+ slotContactAdded( handle, "AL", publicName, TQString(), TQString() );
+ else if(c)
+ c->setAllowed(false);
+ if ( lists & 4 )
+ slotContactAdded( handle, "BL", publicName, TQString(), TQString() );
+ else if(c)
+ c->setBlocked(false);
+ if ( lists & 8 )
+ slotContactAdded( handle, "RL", publicName, TQString(), TQString() );
+ else if(c)
+ c->setReversed(false);
+ if ( lists & 16 ) // This contact is on the pending list. Add to the reverse list and delete from the pending list
+ {
+ notifySocket()->addContact( handle, MSNProtocol::RL, TQString(), TQString(), TQString() );
+ notifySocket()->removeContact( handle, MSNProtocol::PL, TQString(), TQString() );
+ }
+}
+
+void MSNAccount::slotContactAdded( const TQString& handle, const TQString& list, const TQString& publicName, const TQString& contactGuid, const TQString &groupGuid )
+{
+ if ( list == "FL" )
+ {
+ bool new_contact = false;
+ if ( !contacts()[ handle ] )
+ {
+ new_contact = true;
+
+ Kopete::MetaContact *m= m_addWizard_metaContact ? m_addWizard_metaContact : new Kopete::MetaContact();
+
+ MSNContact *c = new MSNContact( this, handle, m );
+ if(!publicName.isEmpty() && publicName!=handle)
+ c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName );
+ else
+ c->removeProperty( Kopete::Global::Properties::self()->nickName() );
+ c->setProperty( MSNProtocol::protocol()->propGuid, contactGuid );
+ // Add the new contact to the group he belongs.
+ if ( tmp_addNewContactToGroup.contains(handle) )
+ {
+ TQStringList list = tmp_addNewContactToGroup[handle];
+ for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ TQString groupGuid = *it;
+
+ // If the group didn't exist yet (yay for async operations), don't add the contact to the group
+ // Let slotGroupAdded do it.
+ if( m_groupList.contains(groupGuid) )
+ {
+ kdDebug( 14140 ) << k_funcinfo << "Adding " << handle << " to group: " << groupGuid << endl;
+ notifySocket()->addContact( handle, MSNProtocol::FL, TQString(), contactGuid, groupGuid );
+
+ c->contactAddedToGroup( groupGuid, m_groupList[ groupGuid ] );
+
+ m->addToGroup( m_groupList[ groupGuid ] );
+
+ }
+ if ( !m_addWizard_metaContact )
+ {
+ Kopete::ContactList::self()->addMetaContact( m );
+ }
+ }
+ tmp_addNewContactToGroup.remove(handle);
+ }
+
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+
+ m_addWizard_metaContact = 0L;
+ }
+ if ( !new_contact )
+ {
+ // Contact has been added to a group
+ MSNContact *c = findContactByGuid(contactGuid);
+ if(c != 0L)
+ {
+ // Make sure that the contact has always his contactGUID.
+ if( !c->hasProperty(MSNProtocol::protocol()->propGuid.key()) )
+ c->setProperty( MSNProtocol::protocol()->propGuid, contactGuid );
+
+ if ( c->onlineStatus() == MSNProtocol::protocol()->UNK )
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+
+ if ( c->metaContact() && c->metaContact()->isTemporary() )
+ c->metaContact()->setTemporary( false, m_groupList.contains( groupGuid ) ? m_groupList[ groupGuid ] : 0L );
+ else
+ {
+ if(m_groupList.contains(groupGuid))
+ {
+ if( c->metaContact() )
+ c->metaContact()->addToGroup( m_groupList[groupGuid] );
+ c->contactAddedToGroup( groupGuid, m_groupList[ groupGuid ] );
+ }
+ }
+ }
+ }
+
+ if ( !handle.isEmpty() && !m_allowList.contains( handle ) && !m_blockList.contains( handle ) )
+ {
+ kdDebug(14140) << k_funcinfo << "Trying to add contact to AL. " << endl;
+ notifySocket()->addContact(handle, MSNProtocol::AL, TQString(), TQString(), TQString() );
+ }
+ }
+ else if ( list == "BL" )
+ {
+ if ( contacts()[ handle ] )
+ static_cast( contacts()[ handle ] )->setBlocked( true );
+ if ( !m_blockList.contains( handle ) )
+ {
+ m_blockList.append( handle );
+ configGroup()->writeEntry( "blockList" , m_blockList ) ;
+ }
+ }
+ else if ( list == "AL" )
+ {
+ if ( contacts()[ handle ] )
+ static_cast( contacts()[ handle ] )->setAllowed( true );
+ if ( !m_allowList.contains( handle ) )
+ {
+ m_allowList.append( handle );
+ configGroup()->writeEntry( "allowList" , m_allowList ) ;
+ }
+ }
+ else if ( list == "RL" )
+ {
+ // search for new Contacts
+ Kopete::Contact *ct=contacts()[ handle ];
+ if ( !ct || !ct->metaContact() || ct->metaContact()->isTemporary() )
+ {
+ // Users in the allow list or block list now never trigger the
+ // 'new user' dialog, which makes it impossible to add those here.
+ // Not necessarily bad, but the usability effects need more thought
+ // before I declare it good :- )
+ if ( !m_allowList.contains( handle ) && !m_blockList.contains( handle ) )
+ {
+ TQString nick; //in most case, the public name is not know
+ if(publicName!=handle) // so we don't whos it if it is not know
+ nick=publicName;
+ Kopete::UI::ContactAddedNotifyDialog *dialog=
+ new Kopete::UI::ContactAddedNotifyDialog( handle,nick,this,
+ Kopete::UI::ContactAddedNotifyDialog::InfoButton );
+ TQObject::connect(dialog,TQT_SIGNAL(applyClicked(const TQString&)),
+ this,TQT_SLOT(slotContactAddedNotifyDialogClosed(const TQString& )));
+ dialog->show();
+ }
+ }
+ else
+ {
+ static_cast( ct )->setReversed( true );
+ }
+ m_reverseList.append( handle );
+ configGroup()->writeEntry( "reverseList" , m_reverseList ) ;
+ }
+}
+
+void MSNAccount::slotContactRemoved( const TQString& handle, const TQString& list, const TQString& contactGuid, const TQString& groupGuid )
+{
+ kdDebug( 14140 ) << k_funcinfo << "handle: " << handle << " list: " << list << " contact-uid: " << contactGuid << endl;
+ MSNContact *c=static_cast( contacts()[ handle ] );
+ if ( list == "BL" )
+ {
+ m_blockList.remove( handle );
+ configGroup()->writeEntry( "blockList" , m_blockList ) ;
+ if ( !m_allowList.contains( handle ) )
+ notifySocket()->addContact( handle, MSNProtocol::AL, TQString(), TQString(), TQString() );
+
+ if(c)
+ c->setBlocked( false );
+ }
+ else if ( list == "AL" )
+ {
+ m_allowList.remove( handle );
+ configGroup()->writeEntry( "allowList" , m_allowList ) ;
+ if ( !m_blockList.contains( handle ) )
+ notifySocket()->addContact( handle, MSNProtocol::BL, TQString(), TQString(), TQString() );
+
+ if(c)
+ c->setAllowed( false );
+ }
+ else if ( list == "RL" )
+ {
+ m_reverseList.remove( handle );
+ configGroup()->writeEntry( "reverseList" , m_reverseList ) ;
+
+ if ( c )
+ {
+ // Contact is removed from the reverse list
+ // only MSN can do this, so this is currently not supported
+ c->setReversed( false );
+ /*
+ InfoWidget *info = new InfoWidget( 0 );
+ info->title->setText( "" + i18n( "Contact removed!" ) +"" );
+ TQString dummy;
+ dummy = "" + imContact->getPublicName() + "( " +imContact->getHandle() +" )
";
+ dummy += i18n( "has removed you from his contact list!" ) + "
";
+ dummy += i18n( "This contact is now removed from your contact list" );
+ info->infoText->setText( dummy );
+ info->setCaption( "KMerlin - Info" );
+ info->show();
+ */
+ }
+ }
+ else if ( list == "FL" )
+ {
+ // The FL list only use the contact GUID, use the contact referenced by the GUID.
+ MSNContact *contactRemoved = findContactByGuid(contactGuid);
+ TQStringList groupGuidList;
+ bool deleteContact = groupGuid.isEmpty() ? true : false; // Delete the contact when the group GUID is empty.
+ // Remove the contact from the contact list for all the group he is a member.
+ if( groupGuid.isEmpty() )
+ {
+ if(contactRemoved)
+ {
+ TQPtrList groupList = contactRemoved->metaContact()->groups();
+ for( TQPtrList::Iterator it = groupList.begin(); it != groupList.end(); ++it )
+ {
+ Kopete::Group *group = *it;
+ if ( !group->pluginData( protocol(), accountId() + " id" ).isEmpty() )
+ {
+ groupGuidList.append( group->pluginData( protocol(), accountId() + " id" ) );
+ }
+ }
+ }
+ }
+ else
+ {
+ groupGuidList.append( groupGuid );
+ }
+
+ if( !groupGuidList.isEmpty() )
+ {
+ TQStringList::const_iterator stringIt;
+ for( stringIt = groupGuidList.begin(); stringIt != groupGuidList.end(); ++stringIt )
+ {
+ // Contact is removed from the FL list, remove it from the group
+ if(contactRemoved != 0L)
+ contactRemoved->contactRemovedFromGroup( *stringIt );
+
+ //check if the group is now empty to remove it
+ if ( m_notifySocket )
+ {
+ bool still_have_contact=false;
+ // if contact are contains only in the group we are removing, abort the
+ TQDictIterator it( contacts() );
+ for ( ; it.current(); ++it )
+ {
+ MSNContact *c2 = static_cast( it.current() );
+ if ( c2->serverGroups().contains( *stringIt ) )
+ {
+ still_have_contact=true;
+ break;
+ }
+ }
+ if(!still_have_contact)
+ m_notifySocket->removeGroup( *stringIt );
+ }
+ }
+ }
+ if(deleteContact && contactRemoved)
+ {
+ kdDebug(14140) << k_funcinfo << "Deleting the MSNContact " << contactRemoved->contactId() << endl;
+ contactRemoved->deleteLater();
+ }
+ }
+}
+
+void MSNAccount::slotCreateChat( const TQString& address, const TQString& auth )
+{
+ slotCreateChat( 0L, address, auth, m_msgHandle.first(), m_msgHandle.first() );
+}
+
+void MSNAccount::slotCreateChat( const TQString& ID, const TQString& address, const TQString& auth,
+ const TQString& handle_, const TQString& publicName )
+{
+ TQString handle = handle_.lower();
+
+ if ( handle.isEmpty() )
+ {
+ // we have lost the handle?
+ kdDebug(14140) << k_funcinfo << "Impossible to open a chat session, I forgot the contact to invite" <( contacts()[ handle ] );
+
+ if ( c && myself() )
+ {
+ // we can't use simply c->manager(true) here to get the manager, because this will re-open
+ // another chat session, and then, close this new one. We have to re-create the manager manualy.
+ MSNChatSession *manager = dynamic_cast( c->manager( Kopete::Contact::CannotCreate ) );
+ if(!manager)
+ {
+ Kopete::ContactPtrList chatmembers;
+ chatmembers.append(c);
+ manager = new MSNChatSession( protocol(), myself(), chatmembers );
+ }
+
+ manager->createChat( handle, address, auth, ID );
+
+ /**
+ * This code should open a chatwindow when a socket is open
+ * It has been disabled because pidgin open switchboeard too often
+ *
+ * the solution is to open the window only when the contact start typing
+ * see MSNChatSession::receivedTypingMsg
+ *
+
+ TDEGlobal::config()->setGroup( "MSN" );
+ bool notifyNewChat = TDEGlobal::config()->readBoolEntry( "NotifyNewChat", false );
+ if ( !ID.isEmpty() && notifyNewChat )
+ {
+ // this temporary message should open the window if they not exist
+ TQString body = i18n( "%1 has started a chat with you" ).arg( c->metaContact()->displayName() );
+ Kopete::Message tmpMsg = Kopete::Message( c, manager->members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
+ manager->appendMessage( tmpMsg );
+ }
+ */
+ }
+
+ if(!m_msgHandle.isEmpty())
+ m_msgHandle.pop_front();
+}
+
+void MSNAccount::slotStartChatSession( const TQString& handle )
+{
+ // First create a message manager, because we might get an existing
+ // manager back, in which case we likely also have an active switchboard
+ // connection to reuse...
+
+ MSNContact *c = static_cast( contacts()[ handle ] );
+ // if ( isConnected() && c && myself() && handle != m_msnId )
+ if ( m_notifySocket && c && myself() && handle != accountId() )
+ {
+ if ( !c->manager(Kopete::Contact::CannotCreate) || !static_cast( c->manager( Kopete::Contact::CanCreate ) )->service() )
+ {
+ m_msgHandle.prepend(handle);
+ m_notifySocket->createChatSession();
+ }
+ }
+}
+
+void MSNAccount::slotContactAddedNotifyDialogClosed(const TQString& handle)
+{
+ const Kopete::UI::ContactAddedNotifyDialog *dialog =
+ dynamic_cast(sender());
+ if(!dialog || !m_notifySocket)
+ return;
+
+ if(dialog->added())
+ {
+ Kopete::MetaContact *mc=dialog->addContact();
+ if(mc)
+ { //if the contact has been added this way, it's because the other user added us.
+ // don't forgot to set the reversed flag (Bug 114400)
+ MSNContact *c=dynamic_cast(mc->contacts().first());
+ if(c && c->contactId() == handle )
+ {
+ c->setReversed( true );
+ }
+ }
+ }
+
+ if ( !dialog->authorized() )
+ {
+ if ( m_allowList.contains( handle ) )
+ m_notifySocket->removeContact( handle, MSNProtocol::AL, TQString(), TQString() );
+ else if ( !m_blockList.contains( handle ) )
+ m_notifySocket->addContact( handle, MSNProtocol::BL, TQString(), TQString(), TQString() );
+ }
+ else
+ {
+ if ( m_blockList.contains( handle ) )
+ m_notifySocket->removeContact( handle, MSNProtocol::BL, TQString(), TQString() );
+ else if ( !m_allowList.contains( handle ) )
+ m_notifySocket->addContact( handle, MSNProtocol::AL, TQString(), TQString(), TQString() );
+ }
+
+
+}
+
+void MSNAccount::slotGlobalIdentityChanged( const TQString &key, const TQVariant &value )
+{
+ if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
+ {
+ if(key == Kopete::Global::Properties::self()->nickName().key())
+ {
+ TQString oldNick = myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString();
+ TQString newNick = value.toString();
+
+ if(newNick != oldNick)
+ {
+ setPublicName( value.toString() );
+ }
+ }
+ else if(key == Kopete::Global::Properties::self()->photo().key())
+ {
+ m_pictureFilename = value.toString();
+ kdDebug( 14140 ) << k_funcinfo << m_pictureFilename << endl;
+ resetPictureObject(false, true);
+ }
+ }
+}
+
+void MSNAccount::slotErrorMessageReceived( int type, const TQString &msg )
+{
+ TQString caption = i18n( "MSN Plugin" );
+
+ // Use different notification type based on the error context.
+ switch(type)
+ {
+ case MSNSocket::ErrorConnectionLost:
+ {
+ Kopete::Utils::notifyConnectionLost( this, caption, msg );
+ break;
+ }
+ case MSNSocket::ErrorConnectionError:
+ {
+ Kopete::Utils::notifyConnectionError( this, caption, msg );
+ break;
+ }
+ case MSNSocket::ErrorCannotConnect:
+ {
+ Kopete::Utils::notifyCannotConnect( this );
+ break;
+ }
+ case MSNSocket::ErrorInformation:
+ {
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Information, msg, caption );
+ break;
+ }
+ case MSNSocket::ErrorServerError:
+ default:
+ {
+ Kopete::Utils::notifyServerError( this, caption, msg );
+ break;
+ }
+ }
+}
+
+bool MSNAccount::createContact( const TQString &contactId, Kopete::MetaContact *metaContact )
+{
+ if ( !metaContact->isTemporary() && m_notifySocket)
+ {
+ m_addWizard_metaContact = metaContact;
+
+ addContactServerside(contactId, metaContact->groups());
+
+ // FIXME: Find out if this contact was really added or not!
+ return true;
+ }
+ else
+ {
+ // This is a temporary contact. ( a person who messaged us but is not on our conntact list.
+ // We don't want to create it on the server.Just create the local contact object and add it
+ // Or we are diconnected, and in that case, the contact will be added when connecting
+ MSNContact *newContact = new MSNContact( this, contactId, metaContact );
+ newContact->setDeleted(true);
+ return true;
+ }
+
+}
+
+void MSNAccount::addContactServerside(const TQString &contactId, TQPtrList groupList)
+{
+ // First of all, fill the temporary group list. The contact will be moved to his group(s).
+ // When we receive back his contact GUID(required to move a contact between groups)
+ for( Kopete::Group *group = groupList.first(); group; group = groupList.next() )
+ {
+ // TODO: It it time that libkopete generate a unique ID that contains protocols, account and contact id.
+ TQString groupId = group->pluginData( protocol(), accountId() + " id" );
+ // If the groupId is empty, that's mean the Kopete group is not on the MSN server.
+ if( !groupId.isEmpty() )
+ {
+ // Something got corrupted on contactlist.xml
+ if( !m_groupList.contains(groupId) )
+ {
+ // Clear the group plugin data.
+ group->setPluginData( protocol() , accountId() + " id" , TQString());
+ group->setPluginData( protocol() , accountId() + " displayName" , TQString());
+ kdDebug( 14140 ) << k_funcinfo << " Group " << group->displayName() << " marked with id #" << groupId << " does not seems to be anymore on the server" << endl;
+
+ // Add the group on MSN server, will fix the corruption.
+ kdDebug(14140) << k_funcinfo << "Fixing group corruption, re-adding " << group->displayName() << "to the server." << endl;
+ addGroup( group->displayName(), contactId);
+ }
+ else
+ {
+ // Add the group that the contact belong to add it when we will receive the contact GUID.
+ if( tmp_addNewContactToGroup.contains( contactId ) )
+ tmp_addNewContactToGroup[contactId].append(groupId);
+ else
+ tmp_addNewContactToGroup.insert(contactId, TQStringList(groupId) );
+ }
+ }
+ else
+ {
+ if( !group->displayName().isEmpty() && group->type() == Kopete::Group::Normal )
+ {
+ kdDebug(14140) << k_funcinfo << "Group not on MSN server, add it" << endl;
+ addGroup( group->displayName(), contactId );
+ }
+ }
+ }
+
+ // After add the contact to the top-level, it will be moved to required groups later.
+ kdDebug( 14140 ) << k_funcinfo << "Add the contact on the server " << endl;
+ m_notifySocket->addContact( contactId, MSNProtocol::FL, contactId, TQString(), TQString() );
+}
+
+MSNContact *MSNAccount::findContactByGuid(const TQString &contactGuid)
+{
+ kdDebug(14140) << k_funcinfo << "Looking for " << contactGuid << endl;
+ TQDictIterator it( contacts() );
+ for ( ; it.current(); ++it )
+ {
+ MSNContact *c = dynamic_cast( it.current() );
+
+ if(c && c->guid() == contactGuid )
+ {
+ kdDebug(14140) << k_funcinfo << "OK found a contact. " << endl;
+ // Found the contact GUID
+ return c;
+ }
+ }
+
+ return 0L;
+}
+
+bool MSNAccount::isHotmail() const
+{
+ if ( !m_openInboxAction )
+ return false;
+ return m_openInboxAction->isEnabled();
+}
+
+TQString MSNAccount::pictureUrl()
+{
+ return m_pictureFilename;
+}
+
+void MSNAccount::setPictureUrl(const TQString &url)
+{
+ m_pictureFilename = url;
+}
+
+TQString MSNAccount::pictureObject()
+{
+ if(m_pictureObj.isNull())
+ resetPictureObject(true); //silent=true to keep infinite loop away
+ return m_pictureObj;
+}
+
+void MSNAccount::resetPictureObject(bool silent, bool force)
+{
+ TQString old=m_pictureObj;
+
+ if(!configGroup()->readBoolEntry("exportCustomPicture") && !force)
+ {
+ m_pictureObj="";
+ myself()->removeProperty( Kopete::Global::Properties::self()->photo() );
+ }
+ else
+ {
+ // Check if the picture is a 96x96 image, if not scale, crop and save.
+ TQImage picture(m_pictureFilename);
+ if(picture.isNull())
+ {
+ m_pictureObj="";
+ myself()->removeProperty( Kopete::Global::Properties::self()->photo() );
+ }
+ else
+ {
+ if(picture.width() != 96 || picture.height() != 96)
+ {
+ // Save to a new location in msnpictures.
+ TQString newLocation( locateLocal( "appdata", "msnpictures/"+ KURL(m_pictureFilename).fileName().lower() ) );
+
+ // Scale and crop the picture.
+ picture = MSNProtocol::protocol()->scalePicture(picture);
+
+ // Use the cropped/scaled image now.
+ if(!picture.save(newLocation, "PNG"))
+ {
+ m_pictureObj="";
+ myself()->removeProperty( Kopete::Global::Properties::self()->photo() );
+ }
+ m_pictureFilename = newLocation;
+ }
+ }
+
+ TQFile pictFile( m_pictureFilename );
+ if(!pictFile.open(IO_ReadOnly))
+ {
+ m_pictureObj="";
+ myself()->removeProperty( Kopete::Global::Properties::self()->photo() );
+ }
+ else
+ {
+ TQByteArray ar=pictFile.readAll();
+ TQString sha1d= TQString((KCodecs::base64Encode(SHA1::hash(ar))));
+
+ TQString size=TQString::number( pictFile.size() );
+ TQString all= "Creator"+accountId()+"Size"+size+"Type3Locationkopete.tmpFriendlyAAA=SHA1D"+ sha1d;
+ m_pictureObj="";
+ myself()->setProperty( Kopete::Global::Properties::self()->photo() , m_pictureFilename );
+ }
+ }
+
+ if(old!=m_pictureObj && isConnected() && m_notifySocket && !silent)
+ {
+ //update the msn pict
+ m_notifySocket->setStatus( myself()->onlineStatus() );
+ }
+}
+
+#include "msnaccount.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
+
diff --git a/kopete/protocols/msn/msnaccount.h b/kopete/protocols/msn/msnaccount.h
new file mode 100644
index 00000000..e7a80f4a
--- /dev/null
+++ b/kopete/protocols/msn/msnaccount.h
@@ -0,0 +1,271 @@
+/*
+ msnaccount.h - Manages a single MSN account
+
+ Copyright (c) 2003-2005 by Olivier Goffart
+ Copyright (c) 2005 by Michaêl Larouche
+
+ Kopete (c) 2003-2005 by The Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef MSNACCOUNT_H
+#define MSNACCOUNT_H
+
+#include
+
+#include "kopetepasswordedaccount.h"
+
+#include "msnprotocol.h"
+
+class TDEAction;
+class TDEActionMenu;
+
+class MSNNotifySocket;
+class MSNContact;
+
+/**
+ * MSNAccount encapsulates everything that is account-based, as opposed to
+ * protocol based. This basically means sockets, current status, and account
+ * info are stored in the account, whereas the protocol is only the
+ * 'manager' class that creates and manages accounts.
+ */
+class MSNAccount : public Kopete::PasswordedAccount
+{
+ Q_OBJECT
+
+
+public:
+ MSNAccount( MSNProtocol *parent, const TQString &accountID, const char *name = 0L );
+
+ /*
+ * return the menu for this account
+ */
+ virtual TDEActionMenu* actionMenu();
+
+ //------ internal functions
+ /**
+ * change the publicName to this new name
+ */
+ void setPublicName( const TQString &name );
+ void setPersonalMessage(MSNProtocol::PersonalMessageType type, const TQString &personalMessage );
+
+ /**
+ * Returns the address of the MSN server
+ */
+ TQString serverName();
+
+ /**
+ * Returns the address of the MSN server port
+ */
+ uint serverPort();
+
+ MSNNotifySocket *notifySocket();
+
+ /**
+ * return true if we are able to send mail, or to open hotmail inbox
+ */
+ bool isHotmail() const;
+
+
+ /**
+ * Return the picture url.
+ */
+ TQString pictureUrl();
+
+ /**
+ * Set the picture url.
+ */
+ void setPictureUrl(const TQString &url);
+
+ /**
+ * return the tag of the display picture
+ */
+ TQString pictureObject();
+
+ /**
+ * reset the . This method should be called if the displayimage has changed
+ * If we are actualy connected, it will imediatly update the on the server, exepted
+ * if @param silent is set to true
+ * @param force Force the application of MSN picture
+ */
+ void resetPictureObject(bool silent=false, bool force=false);
+
+ //BEGIN Http
+
+ bool useHttpMethod() const;
+
+ //END
+
+ /**
+ * Return the client ID for the myself contact of this account.
+ * It is dynamic to see if we really have a webcam or not.
+ */
+ TQString myselfClientId() const;
+
+public slots:
+ virtual void connectWithPassword( const TQString &password ) ;
+ virtual void disconnect() ;
+ virtual void setOnlineStatus( const Kopete::OnlineStatus &status , const TQString &reason = TQString());
+
+ /**
+ * Ask to the account to create a new chat session
+ */
+ void slotStartChatSession( const TQString& handle );
+
+ /**
+ * Single slot to display error message.
+ */
+ void slotErrorMessageReceived( int type, const TQString &msg );
+
+protected:
+ virtual bool createContact( const TQString &contactId, Kopete::MetaContact *parentContact );
+
+
+private slots:
+ // Actions related
+ void slotStartChat();
+ void slotOpenInbox();
+ void slotChangePublicName();
+
+//#if !defined NDEBUG //(Stupid moc which don't see when he don't need to slot this slot)
+ /**
+ * Show simple debugging aid
+ */
+ void slotDebugRawCommand();
+//#endif
+
+ // notifySocket related
+ void slotStatusChanged( const Kopete::OnlineStatus &status );
+ void slotNotifySocketClosed();
+ void slotPersonalMessageChanged(const TQString& personalMessage);
+ void slotContactRemoved(const TQString& handle, const TQString& list, const TQString& contactGuid, const TQString& groupGuid );
+ void slotContactAdded(const TQString& handle, const TQString& list, const TQString& publicName, const TQString& contactGuid, const TQString &groupGuid );
+ void slotContactListed( const TQString& handle, const TQString& publicName, const TQString &contactGuid, uint lists, const TQString& groups );
+ void slotNewContactList();
+ /**
+ * The group has successful renamed in the server
+ * groupName: is new new group name
+ */
+ void slotGroupRenamed(const TQString &groupGuid, const TQString& groupName );
+ /**
+ * A new group was created on the server (or received durring an LSG command)
+ */
+ void slotGroupAdded( const TQString& groupName, const TQString &groupGuid );
+ /**
+ * Group was removed from the server
+ */
+ void slotGroupRemoved( const TQString &groupGuid );
+ /**
+ * Incoming RING command: connect to the Switchboard server and send
+ * the startChat signal
+ */
+ void slotCreateChat( const TQString& sessionID, const TQString& address, const TQString& auth,
+ const TQString& handle, const TQString& publicName );
+ /**
+ * Incoming XFR command: this is an result from
+ * slotStartChatSession(handle)
+ * connect to the switchboard server and sen startChat signal
+ */
+ void slotCreateChat( const TQString& address, const TQString& auth);
+
+
+ // ui related
+ /**
+ * A kopetegroup is renamed, rename group on the server
+ */
+ void slotKopeteGroupRenamed( Kopete::Group *g );
+
+ /**
+ * A kopetegroup is removed, remove the group in the server
+ **/
+ void slotKopeteGroupRemoved( Kopete::Group* );
+
+ /**
+ * add contact ui
+ */
+ void slotContactAddedNotifyDialogClosed( const TQString &handle);
+
+ /**
+ * When the dispatch server sends us the notification server to use.
+ */
+ void createNotificationServer( const TQString &host, uint port );
+
+ /**
+ * When a global identity key get changed.
+ */
+ void slotGlobalIdentityChanged( const TQString &key, const TQVariant &value );
+
+private:
+ MSNNotifySocket *m_notifySocket;
+ TDEAction *m_openInboxAction;
+ TDEAction *m_startChatAction;
+ TDEAction *m_changeDNAction;
+
+ // status which will be using for connecting
+ Kopete::OnlineStatus m_connectstatus;
+
+ TQStringList m_msgHandle;
+
+ bool m_newContactList;
+
+
+ /**
+ * Add the contact on the server in the given groups.
+ * this is a helper function called bu createContact and slotStatusChanged
+ */
+ void addContactServerside(const TQString &contactId, TQPtrList groupList);
+
+
+
+public: //FIXME: should be private
+ TQMap m_groupList;
+
+ void addGroup( const TQString &groupName, const TQString &contactToAdd = TQString() );
+
+ /**
+ * Find and retrive a MSNContact by its contactGuid. (Helper function)
+ */
+ MSNContact *findContactByGuid(const TQString &contactGuid);
+private:
+
+ // server data
+ TQStringList m_allowList;
+ TQStringList m_blockList;
+ TQStringList m_reverseList;
+
+ Kopete::MetaContact *m_addWizard_metaContact;
+ TQMap< TQString, TQStringList > tmp_addToNewGroup;
+ TQMap< TQString, TQStringList > tmp_addNewContactToGroup;
+
+ TQString m_pictureObj; //a cache of the
+ TQString m_pictureFilename; // the picture filename.
+
+ //this is the translation between old to new groups id when syncing from server.
+ TQMap m_oldGroupList;
+
+ /**
+ * I need the password in createNotificationServer.
+ * but i can't ask it there with password() because a nested loop will provoque crash
+ * at this place. so i'm forced to keep it here.
+ * I would like an API to request the password WITHOUT askling it.
+ */
+ TQString m_password;
+
+ /**
+ * Cliend ID is a bitfield that contains supported features for a MSN contact.
+ */
+ uint m_clientId;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/msn/msnaddcontactpage.cpp b/kopete/protocols/msn/msnaddcontactpage.cpp
new file mode 100644
index 00000000..74102e1d
--- /dev/null
+++ b/kopete/protocols/msn/msnaddcontactpage.cpp
@@ -0,0 +1,85 @@
+/*
+ Copyright (c) 2002-2005 by Olivier Goffart
+ Kopete (c) 2002-2005 by The Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+
+#include
+#include
+
+#include
+#include
+
+#include "msnadd.h"
+#include "msnaddcontactpage.h"
+#include "msnprotocol.h"
+#include "kopeteaccount.h"
+#include "kopeteuiglobal.h"
+
+MSNAddContactPage::MSNAddContactPage(bool connected, TQWidget *parent, const char *name )
+ : AddContactPage(parent,name)
+{
+ (new TQVBoxLayout(this))->setAutoAdd(true);
+/* if ( connected )
+ {*/
+ msndata = new msnAddUI(this);
+ /*
+ msndata->cmbGroup->insertStringList(owner->getGroups());
+ msndata->cmbGroup->setCurrentItem(0);
+ */
+ canadd = true;
+
+/* }
+ else
+ {
+ noaddMsg1 = new TQLabel( i18n( "You need to be connected to be able to add contacts." ), this );
+ noaddMsg2 = new TQLabel( i18n( "Please connect to the MSN network and try again." ), this );
+ canadd = false;
+}*/
+
+}
+MSNAddContactPage::~MSNAddContactPage()
+{
+}
+
+bool MSNAddContactPage::apply( Kopete::Account* i, Kopete::MetaContact*m )
+{
+ if ( validateData() )
+ {
+ TQString userid = msndata->addID->text();
+ return i->addContact( userid , m, Kopete::Account::ChangeKABC );
+ }
+ return false;
+}
+
+
+bool MSNAddContactPage::validateData()
+{
+ if(!canadd)
+ return false;
+
+ TQString userid = msndata->addID->text();
+
+ if(MSNProtocol::validContactId(userid))
+ return true;
+
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
+ i18n( "You must enter a valid email address." ), i18n( "MSN Plugin" ) );
+
+ return false;
+
+}
+
+#include "msnaddcontactpage.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/msn/msnaddcontactpage.h b/kopete/protocols/msn/msnaddcontactpage.h
new file mode 100644
index 00000000..dc81dc44
--- /dev/null
+++ b/kopete/protocols/msn/msnaddcontactpage.h
@@ -0,0 +1,34 @@
+
+#ifndef MSNADDCONTACTPAGE_H
+#define MSNADDCONTACTPAGE_H
+
+#include
+#include
+#include
+
+/**
+ *@author duncan
+ */
+class msnAddUI;
+class MSNProtocol;
+
+class MSNAddContactPage : public AddContactPage
+{
+ Q_OBJECT
+
+public:
+ MSNAddContactPage(bool connected, TQWidget *parent=0, const char *name=0);
+ ~MSNAddContactPage();
+ msnAddUI *msndata;
+ TQLabel *noaddMsg1;
+ TQLabel *noaddMsg2;
+ bool canadd;
+ virtual bool validateData();
+ virtual bool apply( Kopete::Account*, Kopete::MetaContact* );
+
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/msn/msnchallengehandler.cpp b/kopete/protocols/msn/msnchallengehandler.cpp
new file mode 100644
index 00000000..5492b9e7
--- /dev/null
+++ b/kopete/protocols/msn/msnchallengehandler.cpp
@@ -0,0 +1,151 @@
+/*
+ msnchallengehandler.h - Computes a msn challenge response hash key.
+
+ Copyright (c) 2005 by Gregg Edghill
+ Kopete (c) 2003-2005 by The Kopete developers
+
+ Portions taken from
+ http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "msnchallengehandler.h"
+
+#include
+
+#include
+#include
+
+MSNChallengeHandler::MSNChallengeHandler(const TQString& productKey, const TQString& productId)
+{
+ m_productKey = productKey;
+ m_productId = productId;
+}
+
+
+MSNChallengeHandler::~MSNChallengeHandler()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+}
+
+TQString MSNChallengeHandler::computeHash(const TQString& challengeString)
+{
+ // Step One: THe MD5 Hash.
+
+ // Combine the received challenge string with the product key.
+ KMD5 md5((challengeString + m_productKey).utf8());
+ TQCString digest = md5.hexDigest();
+
+ kdDebug(14140) << k_funcinfo << "md5: " << digest << endl;
+
+ TQValueVector md5Integers(4);
+ for(TQ_UINT32 i=0; i < md5Integers.count(); i++)
+ {
+ md5Integers[i] = hexSwap(digest.mid(i*8, 8)).toUInt(0, 16) & 0x7FFFFFFF;
+ kdDebug(14140) << k_funcinfo << ("0x" + hexSwap(digest.mid(i*8, 8))) << " " << md5Integers[i] << endl;
+ }
+
+ // Step Two: Create the challenge string key
+
+ TQString challengeKey = challengeString + m_productId;
+ // Pad to multiple of 8.
+ challengeKey = challengeKey.leftJustify(challengeKey.length() + (8 - challengeKey.length() % 8), '0');
+
+ kdDebug(14140) << k_funcinfo << "challenge key: " << challengeKey << endl;
+
+ TQValueVector challengeIntegers(challengeKey.length() / 4);
+ for(TQ_UINT32 i=0; i < challengeIntegers.count(); i++)
+ {
+ TQString sNum = challengeKey.mid(i*4, 4), sNumHex;
+
+ // Go through the number string, determining the hex equivalent of each value
+ // and add that to our new hex string for this number.
+ for(uint j=0; j < sNum.length(); j++) {
+ sNumHex += TQString::number((int)sNum[j].latin1(), 16);
+ }
+
+ // swap because of the byte ordering issue.
+ sNumHex = hexSwap(sNumHex);
+ // Assign the converted number.
+ challengeIntegers[i] = sNumHex.toInt(0, 16);
+ kdDebug(14140) << k_funcinfo << sNum << (": 0x"+sNumHex) << " " << challengeIntegers[i] << endl;
+ }
+
+ // Step Three: Create the 64-bit hash key.
+
+ // Get the hash key using the specified arrays.
+ TQ_INT64 key = createHashKey(md5Integers, challengeIntegers);
+ kdDebug(14140) << k_funcinfo << "key: " << key << endl;
+
+ // Step Four: Create the final hash key.
+
+ TQString upper = TQString::number(TQString(digest.mid(0, 16)).toULongLong(0, 16)^key, 16);
+ if(upper.length() % 16 != 0)
+ upper = upper.rightJustify(upper.length() + (16 - upper.length() % 16), '0');
+
+ TQString lower = TQString::number(TQString(digest.mid(16, 16)).toULongLong(0, 16)^key, 16);
+ if(lower.length() % 16 != 0)
+ lower = lower.rightJustify(lower.length() + (16 - lower.length() % 16), '0');
+
+ return (upper + lower);
+}
+
+TQ_INT64 MSNChallengeHandler::createHashKey(const TQValueVector& md5Integers,
+ const TQValueVector& challengeIntegers)
+{
+ kdDebug(14140) << k_funcinfo << "Creating 64-bit key." << endl;
+
+ TQ_INT64 magicNumber = 0x0E79A9C1L, high = 0L, low = 0L;
+
+ for(uint i=0; i < challengeIntegers.count(); i += 2)
+ {
+ TQ_INT64 temp = ((challengeIntegers[i] * magicNumber) % 0x7FFFFFFF) + high;
+ temp = ((temp * md5Integers[0]) + md5Integers[1]) % 0x7FFFFFFF;
+
+ high = (challengeIntegers[i + 1] + temp) % 0x7FFFFFFF;
+ high = ((high * md5Integers[2]) + md5Integers[3]) % 0x7FFFFFFF;
+
+ low += high + temp;
+ }
+
+ high = (high + md5Integers[1]) % 0x7FFFFFFF;
+ low = (low + md5Integers[3]) % 0x7FFFFFFF;
+
+ TQDataStream buffer(TQByteArray(8), IO_ReadWrite);
+ buffer.setByteOrder(TQDataStream::LittleEndian);
+ buffer << (TQ_INT32)high;
+ buffer << (TQ_INT32)low;
+
+ buffer.device()->reset();
+ buffer.setByteOrder(TQDataStream::BigEndian);
+ TQ_INT64 key;
+ buffer >> key;
+
+ return key;
+}
+
+TQString MSNChallengeHandler::hexSwap(const TQString& in)
+{
+ TQString sHex = in, swapped;
+ while(sHex.length() > 0)
+ {
+ swapped = swapped + sHex.mid(sHex.length() - 2, 2);
+ sHex = sHex.remove(sHex.length() - 2, 2);
+ }
+ return swapped;
+}
+
+TQString MSNChallengeHandler::productId()
+{
+ return m_productId;
+}
+
+#include "msnchallengehandler.moc"
diff --git a/kopete/protocols/msn/msnchallengehandler.h b/kopete/protocols/msn/msnchallengehandler.h
new file mode 100644
index 00000000..22024aee
--- /dev/null
+++ b/kopete/protocols/msn/msnchallengehandler.h
@@ -0,0 +1,65 @@
+/*
+ msnchallengehandler.h - Computes a msn challenge response hash key.
+
+ Copyright (c) 2005 by Gregg Edghill
+ Kopete (c) 2003-2005 by The Kopete developers
+
+ Portions taken from
+ http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef MSNCHALLENGEHANDLER_H
+#define MSNCHALLENGEHANDLER_H
+
+#include
+#include
+
+/**
+ * Provides a simple way to compute a msn challenge response hash key.
+ *
+ * @author Gregg Edghill
+ */
+class MSNChallengeHandler : public TQObject
+{
+Q_OBJECT
+
+public:
+ MSNChallengeHandler(const TQString& productKey, const TQString& productId);
+ ~MSNChallengeHandler();
+
+ /**
+ * Computes the response hash string for the specified challenge string.
+ */
+ TQString computeHash(const TQString& challengeString);
+
+ /**
+ * Returns the product id used by the challenge handler.
+ */
+ TQString productId();
+
+private:
+
+ /**
+ * Creates a 64-bit hash key.
+ */
+ TQ_INT64 createHashKey(const TQValueVector& md5Integers, const TQValueVector& challengeIntegers);
+
+ /**
+ * Swaps the bytes in a hex string.
+ */
+ TQString hexSwap(const TQString& in);
+
+ TQString m_productKey;
+ TQString m_productId;
+};
+
+#endif
diff --git a/kopete/protocols/msn/msnchatsession.cpp b/kopete/protocols/msn/msnchatsession.cpp
new file mode 100644
index 00000000..fabd62ab
--- /dev/null
+++ b/kopete/protocols/msn/msnchatsession.cpp
@@ -0,0 +1,775 @@
+/*
+ msnchatsession.cpp - MSN Message Manager
+
+ Copyright (c) 2002-2005 by Olivier Goffart
+
+ Kopete (c) 2002-2005 by the Kopete developers
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "msnchatsession.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "kopetecontactaction.h"
+#include "kopetemetacontact.h"
+#include "kopetecontactlist.h"
+#include "kopetechatsessionmanager.h"
+#include "kopeteuiglobal.h"
+#include "kopeteglobal.h"
+#include "kopeteview.h"
+
+#include "msncontact.h"
+#include "msnfiletransfersocket.h"
+#include "msnaccount.h"
+#include "msnswitchboardsocket.h"
+
+#include "config.h"
+
+#if !defined NDEBUG
+#include "msndebugrawcmddlg.h"
+#endif
+
+MSNChatSession::MSNChatSession( Kopete::Protocol *protocol, const Kopete::Contact *user,
+ Kopete::ContactPtrList others, const char *name )
+: Kopete::ChatSession( user, others, protocol, name )
+{
+ Kopete::ChatSessionManager::self()->registerChatSession( this );
+ m_chatService = 0l;
+ m_timeoutTimer =0L;
+ m_newSession = true;
+ m_connectionTry=0;
+
+ setInstance(protocol->instance());
+
+ connect( this, TQT_SIGNAL( messageSent( Kopete::Message&,
+ Kopete::ChatSession* ) ),
+ this, TQT_SLOT( slotMessageSent( Kopete::Message&,
+ Kopete::ChatSession* ) ) );
+
+ connect( this, TQT_SIGNAL( invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* ) ) ,
+ protocol, TQT_SIGNAL( invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* ) ) );
+
+
+ m_actionInvite = new TDEActionMenu( i18n( "&Invite" ), "kontact_contacts", actionCollection(), "msnInvite" );
+ connect ( m_actionInvite->popupMenu() , TQT_SIGNAL( aboutToShow() ) , this , TQT_SLOT(slotActionInviteAboutToShow() ) ) ;
+
+ #if !defined NDEBUG
+ new TDEAction( i18n( "Send Raw C&ommand..." ), 0, this, TQT_SLOT( slotDebugRawCommand() ), actionCollection(), "msnDebugRawCommand" ) ;
+ #endif
+
+
+ m_actionNudge=new TDEAction( i18n( "Send Nudge" ), "bell", 0, this, TQT_SLOT(slotSendNudge() ), actionCollection(), "msnSendNudge" ) ;
+#if MSN_WEBCAM
+ // Invite to receive webcam action
+ m_actionWebcamReceive=new TDEAction( i18n( "View Contact's Webcam" ), "webcamreceive", 0, this, TQT_SLOT(slotWebcamReceive()), actionCollection(), "msnWebcamReceive" ) ;
+
+ //Send webcam action
+ m_actionWebcamSend=new TDEAction( i18n( "Send Webcam" ), "webcamsend", 0, this, TQT_SLOT(slotWebcamSend()), actionCollection(), "msnWebcamSend" ) ;
+#endif
+
+ new TDEAction( i18n( "Send File" ),"attach", 0, this, TQT_SLOT( slotSendFile() ), actionCollection(), "msnSendFile" );
+
+ MSNContact *c = static_cast( others.first() );
+ (new TDEAction( i18n( "Request Display Picture" ), "image", 0, this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnRequestDisplayPicture" ))->setEnabled(!c->object().isEmpty());
+
+ if ( !c->object().isEmpty() )
+ {
+
+ connect( c, TQT_SIGNAL( displayPictureChanged() ), this, TQT_SLOT( slotDisplayPictureChanged() ) );
+ m_image = new TQLabel( 0L, "kde toolbar widget" );
+ new KWidgetAction( m_image, i18n( "MSN Display Picture" ), 0, this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnDisplayPicture" );
+ if(c->hasProperty(Kopete::Global::Properties::self()->photo().key()) )
+ {
+ //if the view doesn't exist yet, we will be unable to get the size of the toolbar
+ // so when the view will exist, we will show the displaypicture.
+ //How to know when a our view is created? We can't.
+ // but chances are the next created view will be for this KMM
+ // And if it is not? never mind. the icon will just be sized 22x22
+ connect( Kopete::ChatSessionManager::self() , TQT_SIGNAL(viewActivated(KopeteView* )) , this, TQT_SLOT(slotDisplayPictureChanged()) );
+ //it's viewActivated and not viewCreated because the view get his mainwindow only when it is shown.
+ }
+ }
+ else
+ {
+ m_image = 0L;
+ }
+
+ setXMLFile("msnchatui.rc");
+
+ setMayInvite( true );
+}
+
+MSNChatSession::~MSNChatSession()
+{
+ delete m_image;
+ //force to disconnect the switchboard
+ //not needed since the m_chatService has us as parent
+ // if(m_chatService)
+ // delete m_chatService;
+
+ TQMap::Iterator it;
+ for( it = m_invitations.begin(); it != m_invitations.end() ; it = m_invitations.begin())
+ {
+ delete *it;
+ m_invitations.remove( it );
+ }
+}
+
+void MSNChatSession::createChat( const TQString &handle,
+ const TQString &address, const TQString &auth, const TQString &ID )
+{
+ /* disabled because i don't want to reopen a chatwindow if we just closed it
+ * and the contact take much time to type his message
+ m_newSession= !(ID.isEmpty());
+ */
+
+ if( m_chatService )
+ {
+ kdDebug(14140) << k_funcinfo << "Service already exists, disconnect them." << endl;
+ delete m_chatService;
+ }
+
+// uncomment this line if you don't want to the peer know when you close the window
+// setCanBeDeleted( false );
+
+ m_chatService = new MSNSwitchBoardSocket( static_cast( myself()->account() ) , this);
+ m_chatService->setUseHttpMethod( static_cast( myself()->account() )->useHttpMethod() );
+ m_chatService->setHandle( myself()->account()->accountId() );
+ m_chatService->setMsgHandle( handle );
+ m_chatService->connectToSwitchBoard( ID, address, auth );
+
+ connect( m_chatService, TQT_SIGNAL( userJoined(const TQString&,const TQString&,bool)),
+ this, TQT_SLOT( slotUserJoined(const TQString&,const TQString&,bool) ) );
+ connect( m_chatService, TQT_SIGNAL( userLeft(const TQString&,const TQString&)),
+ this, TQT_SLOT( slotUserLeft(const TQString&,const TQString&) ) );
+ connect( m_chatService, TQT_SIGNAL( msgReceived( Kopete::Message & ) ),
+ this, TQT_SLOT( slotMessageReceived( Kopete::Message & ) ) );
+ connect( m_chatService, TQT_SIGNAL( switchBoardClosed() ),
+ this, TQT_SLOT( slotSwitchBoardClosed() ) );
+ connect( m_chatService, TQT_SIGNAL( receivedTypingMsg( const TQString &, bool ) ),
+ this, TQT_SLOT( receivedTypingMsg( const TQString &, bool ) ) );
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup( "MSN" );
+ if(config->readBoolEntry( "SendTypingNotification" , true) )
+ {
+ connect( this, TQT_SIGNAL( myselfTyping( bool ) ),
+ m_chatService, TQT_SLOT( sendTypingMsg( bool ) ) );
+ }
+ connect( m_chatService, TQT_SIGNAL( msgAcknowledgement(unsigned int, bool) ),
+ this, TQT_SLOT( slotAcknowledgement(unsigned int, bool) ) );
+ connect( m_chatService, TQT_SIGNAL( invitation( const TQString&, const TQString& ) ),
+ this, TQT_SLOT( slotInvitation( const TQString&, const TQString& ) ) );
+ connect( m_chatService, TQT_SIGNAL( nudgeReceived(const TQString&) ),
+ this, TQT_SLOT( slotNudgeReceived(const TQString&) ) );
+ connect( m_chatService, TQT_SIGNAL( errorMessage(int, const TQString& ) ), static_cast(myself()->account()), TQT_SLOT( slotErrorMessageReceived(int, const TQString& ) ) );
+
+ if(!m_timeoutTimer)
+ {
+ m_timeoutTimer=new TQTimer(this);
+ connect( m_timeoutTimer , TQT_SIGNAL(timeout()), this , TQT_SLOT(slotConnectionTimeout() ) );
+ }
+ m_timeoutTimer->start(20000,true);
+}
+
+void MSNChatSession::slotUserJoined( const TQString &handle, const TQString &publicName, bool IRO )
+{
+ delete m_timeoutTimer;
+ m_timeoutTimer=0L;
+
+ if( !account()->contacts()[ handle ] )
+ account()->addContact( handle, TQString(), 0L, Kopete::Account::Temporary);
+
+ MSNContact *c = static_cast( account()->contacts()[ handle ] );
+
+ c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName);
+
+ if(c->clientFlags() & MSNProtocol::MSNC4 )
+ {
+ m_actionNudge->setEnabled(true);
+ }
+#if MSN_WEBCAM
+ if(c->clientFlags() & MSNProtocol::SupportWebcam )
+ {
+ m_actionWebcamReceive->setEnabled(true);
+ }
+#endif
+
+ addContact(c , IRO); // don't show notificaions when we join wesalef
+ if(!m_messagesQueue.empty() || !m_invitations.isEmpty())
+ sendMessageQueue();
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup( "MSN" );
+ if ( members().count()==1 && config->readNumEntry( "DownloadPicture", 1 ) >= 1 && !c->object().isEmpty() && !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
+ slotRequestPicture();
+}
+
+void MSNChatSession::slotUserLeft( const TQString &handle, const TQString& reason )
+{
+ MSNContact *c = static_cast( myself()->account()->contacts()[ handle ] );
+ if(c)
+ removeContact(c, reason );
+}
+
+
+
+void MSNChatSession::slotSwitchBoardClosed()
+{
+ //kdDebug(14140) << "MSNChatSession::slotSwitchBoardClosed" << endl;
+ m_chatService->deleteLater();
+ m_chatService=0l;
+
+ cleanMessageQueue( i18n("Connection closed") );
+
+ if(m_invitations.isEmpty())
+ setCanBeDeleted( true );
+}
+
+void MSNChatSession::slotMessageSent(Kopete::Message &message,Kopete::ChatSession *)
+{
+ m_newSession=false;
+ if(m_chatService)
+ {
+ int id = m_chatService->sendMsg(message);
+ if(id == -1)
+ {
+ m_messagesQueue.append(message);
+ kdDebug(14140) << k_funcinfo << "Message added to the queue" <popupMenu()->clear();
+
+
+ TQDictIterator it( account()->contacts() );
+ for( ; it.current(); ++it )
+ {
+ if( !members().contains( it.current() ) && it.current()->isOnline() && it.current() != myself() )
+ {
+ TDEAction *a=new KopeteContactAction( it.current(), this,
+ TQT_SLOT( slotInviteContact( Kopete::Contact * ) ), m_actionInvite );
+ m_actionInvite->insert( a );
+ m_inviteactions.append( a ) ;
+ }
+ }
+ TDEAction *b=new TDEAction( i18n ("Other..."), 0, this, TQT_SLOT( slotInviteOtherContact() ), m_actionInvite, "actionOther" );
+ m_actionInvite->insert( b );
+ m_inviteactions.append( b ) ;
+}
+
+void MSNChatSession::slotCloseSession()
+{
+ kdDebug(14140) << k_funcinfo << m_chatService <slotCloseSession();
+}
+
+void MSNChatSession::slotInviteContact( Kopete::Contact *contact )
+{
+ if(contact)
+ inviteContact( contact->contactId() );
+}
+
+void MSNChatSession::inviteContact(const TQString &contactId)
+{
+ if( m_chatService )
+ m_chatService->slotInviteContact( contactId );
+ else
+ startChatSession();
+}
+
+void MSNChatSession::slotInviteOtherContact()
+{
+ bool ok;
+ TQString handle = KInputDialog::getText(i18n( "MSN Plugin" ),
+ i18n( "Please enter the email address of the person you want to invite:" ),
+ TQString(), &ok );
+ if( !ok )
+ return;
+
+ if( handle.contains('@') != 1 || handle.contains('.') <1)
+ {
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
+ i18n("You must enter a valid email address."), i18n("MSN Plugin"));
+ return;
+ }
+
+ inviteContact(handle);
+}
+
+
+void MSNChatSession::sendMessageQueue()
+{
+ if(!m_chatService)
+ {
+ kdDebug(14140) <::iterator it = m_messagesQueue.begin(); it!=m_messagesQueue.end(); it = m_messagesQueue.begin() )
+ {
+ //m_chatService->sendMsg( *it) ;
+ slotMessageSent(*it , this);
+ m_messagesQueue.remove(it);
+ }
+
+
+ TQMap::Iterator it;
+ for( it = m_invitations.begin(); it != m_invitations.end() ; ++it)
+ {
+ if(! (*it)->incoming() && (*it)->state()sendCommand( "MSG" , "N", true, (*it)->invitationHead().utf8() );
+ (*it)->setState(MSNInvitation::Invited);
+ }
+ }
+}
+
+void MSNChatSession::slotAcknowledgement(unsigned int id, bool ack)
+{
+ if ( !m_messagesSent.contains( id ) )
+ {
+ // This is maybe a ACK/NAK for a non-messaging message
+ return;
+ }
+
+ if ( !ack )
+ {
+ Kopete::Message m = m_messagesSent[ id ];
+ TQString body = i18n( "The following message has not been sent correctly:\n%1" ).arg( m.plainBody() );
+ Kopete::Message msg = Kopete::Message( m.to().first(), members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
+ appendMessage( msg );
+ //stop the stupid animation
+ messageSucceeded();
+ }
+ else
+ {
+ messageSucceeded();
+ }
+
+ m_messagesSent.remove( id );
+}
+
+void MSNChatSession::slotInvitation(const TQString &handle, const TQString &msg)
+{
+ //FIXME! a contact from another account can send a file
+ MSNContact *c = static_cast( myself()->account()->contacts()[ handle ] );
+ if(!c)
+ return;
+
+ TQRegExp rx("Invitation-Cookie: ([0-9]*)");
+ rx.search(msg);
+ long unsigned int cookie=rx.cap(1).toUInt();
+
+ if(m_invitations.contains(cookie))
+ {
+ MSNInvitation *msnI=m_invitations[cookie];
+ msnI->parseInvitation(msg);
+ }
+ else if( msg.contains("Invitation-Command: INVITE") )
+ {
+ if( msg.contains(MSNFileTransferSocket::applicationID()) )
+ {
+ MSNFileTransferSocket *MFTS=new MSNFileTransferSocket(myself()->account()->accountId(),c,true,this);
+ connect(MFTS, TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
+ m_invitations.insert( cookie , MFTS);
+ MFTS->parseInvitation(msg);
+ setCanBeDeleted(false);
+ }
+ else
+ {
+ MSNInvitation *i=0l;
+ emit invitation( i , msg, cookie, this, c );
+ if(i)
+ {
+ m_invitations.insert( cookie , i );
+ //don't delete this if all invitation are not done
+ setCanBeDeleted(false);
+ }
+ else
+ {
+ rx=TQRegExp("Application-Name: ([^\\r\\n]*)");
+ rx.search(msg);
+ TQString inviteName = rx.cap( 1 );
+
+ TQString body = i18n(
+ "%1 has sent an unimplemented invitation, the invitation was rejected.\n"
+ "The invitation was: %2" )
+ .arg( c->property( Kopete::Global::Properties::self()->nickName()).value().toString(), inviteName );
+ Kopete::Message tmpMsg = Kopete::Message( c , members() , body , Kopete::Message::Internal, Kopete::Message::PlainText);
+ appendMessage(tmpMsg);
+
+ m_chatService->sendCommand( "MSG" , "N", true, MSNInvitation::unimplemented(cookie) );
+ }
+ }
+ }
+}
+
+void MSNChatSession::invitationDone(MSNInvitation* MFTS)
+{
+ kdDebug(14140) << k_funcinfo <cookie());
+// MFTS->deleteLater();
+ delete MFTS;
+ if(!m_chatService && m_invitations.isEmpty())
+ setCanBeDeleted(true);
+}
+
+void MSNChatSession::sendFile(const TQString &fileLocation, const TQString &/*fileName*/,
+ long unsigned int fileSize)
+{
+ // TODO create a switchboard to send the file is one is not available.
+ if(m_chatService && members().getFirst())
+ {
+ m_chatService->PeerDispatcher()->sendFile(fileLocation, (TQ_INT64)fileSize, members().getFirst()->contactId());
+ }
+}
+
+void MSNChatSession::initInvitation(MSNInvitation* invitation)
+{
+ connect(invitation->object(), TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
+ m_invitations.insert( invitation->cookie() , invitation);
+
+ if(m_chatService)
+ {
+ m_chatService->sendCommand( "MSG" , "N", true, invitation->invitationHead().utf8() );
+ invitation->setState(MSNInvitation::Invited);
+ }
+ else
+ {
+ startChatSession();
+ }
+}
+
+void MSNChatSession::slotRequestPicture()
+{
+ TQPtrList mb=members();
+ MSNContact *c = static_cast( mb.first() );
+ if(!c)
+ return;
+
+ if( !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
+ {
+ if(m_chatService)
+ {
+ if( !c->object().isEmpty() )
+ m_chatService->requestDisplayPicture();
+ }
+ else if(myself()->onlineStatus().isDefinitelyOnline() && myself()->onlineStatus().status() != Kopete::OnlineStatus::Invisible )
+ startChatSession();
+ }
+ else
+ { //we already have the picture, just show it.
+ KRun::runURL( KURL::fromPathOrURL( c->property(Kopete::Global::Properties::self()->photo()).value().toString() ), "image/png" );
+ }
+
+}
+
+void MSNChatSession::slotDisplayPictureChanged()
+{
+ TQPtrList mb=members();
+ MSNContact *c = static_cast