rev 4532 - in trunk/packages/kdenetwork/debian: . patches

Fathi Boudra fboudra-guest at costa.debian.org
Tue Sep 19 13:58:40 UTC 2006


Author: fboudra-guest
Date: 2006-09-19 13:58:36 +0000 (Tue, 19 Sep 2006)
New Revision: 4532

Added:
   trunk/packages/kdenetwork/debian/patches/01_kdenetwork_branch_r586398.diff
Modified:
   trunk/packages/kdenetwork/debian/changelog
Log:
kdenetwork branch pull - add kopete 0.12

Modified: trunk/packages/kdenetwork/debian/changelog
===================================================================
--- trunk/packages/kdenetwork/debian/changelog	2006-09-19 11:24:49 UTC (rev 4531)
+++ trunk/packages/kdenetwork/debian/changelog	2006-09-19 13:58:36 UTC (rev 4532)
@@ -9,6 +9,11 @@
   * Pass --with-external-libgadu to configure, so that build fails if
     detection of the /usr library fails.
 
+  +++ Changes by Fathi Boudra
+
+  * KDE_3_5_BRANCH update (up to r586398).
+    + Introduce kopete 0.12 in.
+
  -- Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>  Sat, 26 Aug 2006 12:06:54 -0400
 
 kdenetwork (4:3.5.4-2) unstable; urgency=low

Added: trunk/packages/kdenetwork/debian/patches/01_kdenetwork_branch_r586398.diff
===================================================================
--- trunk/packages/kdenetwork/debian/patches/01_kdenetwork_branch_r586398.diff	                        (rev 0)
+++ trunk/packages/kdenetwork/debian/patches/01_kdenetwork_branch_r586398.diff	2006-09-19 13:58:36 UTC (rev 4532)
@@ -0,0 +1,139857 @@
+#DPATCHLEVEL=0
+--- kpf/kpfpropertiesdialogplugin.desktop	(revision 568672)
++++ kpf/kpfpropertiesdialogplugin.desktop	(revision 586398)
+@@ -16,6 +16,7 @@
+ Name[fi]=KPF-hakemiston ominaisuussivu
+ Name[fr]=Page des propriétés d'un dossier KPF
+ Name[gl]=Páxina coas propiedades do directorio KPF
++Name[he]=דף מאפייני ספריה של KPF
+ Name[hu]=KPF könyvtárjellemzők-adatlap
+ Name[is]=KPF möppustillingasíða
+ Name[it]=Pagina proprietà directory KPF
+--- kpf/kpfapplet.desktop	(revision 568672)
++++ kpf/kpfapplet.desktop	(revision 586398)
+@@ -78,6 +78,7 @@
+ Comment[eu]=Sarean zehar fitxtegiak partekatzea errazten duen web-zerbitzari txiki bat
+ Comment[fr]=Un petit serveur web permettant de partager facilement des fichiers sur le réseau
+ Comment[gl]=Un pequeno servidor web que fai doada a compartición de ficheiros por rede
++Comment[he]=שרת אינטרנט קטן שגורם לתעבורת קבצים ברשת להיות קלה
+ Comment[hu]=Mini webkiszolgáló egyszerű fájlmegosztáshoz
+ Comment[is]=Lítill vefþjónn sem auðveldar deilingu af skrám yfir netið
+ Comment[it]=Un piccolo server web che permette di condividere dei file attraverso la rete in modo semplice
+@@ -92,7 +93,7 @@
+ Comment[pt]=Um pequeno servidor Web que torna simples a partilha de ficheiros na rede
+ Comment[pt_BR]=Um pequeno servidor web que facilita o compartilhamento de arquivos na rede
+ Comment[ru]=Небольшой веб-сервер, облегчающий общий доступ к файлам по сети
+-Comment[sk]=Malý web server, ktorý robí zdielanie súborov v sieti jednoduchým
++Comment[sk]=Malý web server, ktorý robí zdieľanie súborov v sieti jednoduchým
+ Comment[sl]=Majhen spletni strežnik, ki poenostavi deljenje datotek prek omrežja
+ Comment[sr]=Мали веб сервер који дељење фајлова преко мреже чини лаким
+ Comment[sr at Latn]=Mali veb server koji deljenje fajlova preko mreže čini lakim
+--- krdc/rdp/rdpprefs.ui	(revision 568672)
++++ krdc/rdp/rdpprefs.ui	(revision 586398)
+@@ -150,6 +150,11 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>Czech (cs)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+                             <string>Danish (da)</string>
+                         </property>
+@@ -160,6 +165,11 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>Swiss German (de-ch)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+                             <string>British English (en-gb)</string>
+                         </property>
+@@ -175,6 +185,11 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>Estonian (et)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+                             <string>Finnish (fi)</string>
+                         </property>
+@@ -190,8 +205,18 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>French Canadian (fr-ca)</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text" >
++                            <string>Swiss French (fr-ch)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+-                            <string>Croation (hr)</string>
++                            <string>Croatian (hr)</string>
+                         </property>
+                     </item>
+                     <item>
+@@ -200,6 +225,11 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>Icelandic (is)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+                             <string>Italian (it)</string>
+                         </property>
+@@ -225,6 +255,16 @@
+                         </property>
+                     </item>
+                     <item>
++                        <property name="text" >
++                            <string>Dutch (nl)</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text" >
++                            <string>Belgian Dutch (nl-be)</string>
++                        </property>
++                    </item>
++                    <item>
+                         <property name="text">
+                             <string>Norwegian (no)</string>
+                         </property>
+--- krdc/rdp/rdphostpref.h	(revision 568672)
++++ krdc/rdp/rdphostpref.h	(revision 586398)
+@@ -23,21 +23,29 @@
+ #include "hostpreferences.h"
+ 
+ static const QString rdpKeymaps[] = { "ar",
++                                      "cs",
+                                       "da",
+                                       "de",
++                                      "de-ch",
+                                       "en-gb",
+                                       "en-us",
+                                       "es",
++                                      "et",
+                                       "fi",
+                                       "fr",
+                                       "fr-be",
++                                      "fr-ca",
++                                      "fr-ch",
+                                       "hr",
+                                       "hu",
++                                      "is",
+                                       "it",
+                                       "ja",
+                                       "lt",
+                                       "lv",
+                                       "mk",
++                                      "nl",
++                                      "nl-be",
+                                       "no",
+                                       "pl",
+                                       "pt",
+@@ -47,8 +55,8 @@
+                                       "sv",
+                                       "th",
+                                       "tr" };
+-static const int rdpNumKeymaps = 25;
+-static const int rdpDefaultKeymap = 4; // en-us
++static const int rdpNumKeymaps = 33;
++static const int rdpDefaultKeymap = 6; // en-us
+ 
+ inline int keymap2int(const QString &keymap)
+ {
+--- krdc/krdc.desktop	(revision 568672)
++++ krdc/krdc.desktop	(revision 586398)
+@@ -6,6 +6,7 @@
+ Terminal=false
+ Name=Krdc
+ Name[bn]=কে-আর-ডি-সি
++Name[zh_TW]=Krdc 遠端桌面連線
+ GenericName=Remote Desktop Connection
+ GenericName[bg]=Връзка с отд. раб. място
+ GenericName[bn]=প্রত্যন্ত ডেস্কটপ সংযোগ
+@@ -23,6 +24,7 @@
+ GenericName[fr]=Connexion à un bureau distant
+ GenericName[ga]=Nasc Deisce Cianda
+ GenericName[gl]=Conexión Remota de Escritorio
++GenericName[he]=חיבור לשולחן עבודה מרוחק
+ GenericName[hu]=Távoli munkaasztal elérése
+ GenericName[is]=Tengingar við fjarlæg skjáborð
+ GenericName[it]=Connessione a desktop remoto
+--- krdc/vidmode.cpp	(revision 568672)
++++ krdc/vidmode.cpp	(revision 586398)
+@@ -38,7 +38,9 @@
+ 	if (!XF86VidModeQueryExtension(dpy, &eventB, &errorB))
+ 		return;
+ 
+-	XF86VidModeGetAllModeLines(dpy,oldResolution.screen,&modecount, &modes);
++	if (!XF86VidModeGetAllModeLines(dpy, oldResolution.screen, &modecount, &modes))
++		return;
++
+ 	for (int i = 0; i < modecount; i++) {
+ 		int w = (*modes[i]).hdisplay;
+ 		int h = (*modes[i]).vdisplay;
+@@ -69,7 +71,9 @@
+ 	if (!XF86VidModeQueryExtension(dpy, &eventB, &errorB))
+ 		return Resolution();
+ 
+-	XF86VidModeGetAllModeLines(dpy,screen,&modecount, &modes);
++	if (!XF86VidModeGetAllModeLines(dpy,screen,&modecount, &modes))
++		return Resolution();
++
+ 	int cw = (*modes[0]).hdisplay;
+ 	int ch = (*modes[0]).vdisplay;
+ 	nx = cw;
+--- krdc/krdc.cpp	(revision 568672)
++++ krdc/krdc.cpp	(revision 586398)
+@@ -732,7 +732,7 @@
+ 
+ 	switch (m_isFullscreen) {
+ 	case WINDOW_MODE_AUTO:
+-		if ((w >= dw) || (h >= dh))
++		if ((w > dw) || (h > dh))
+ 			switchToFullscreen(m_windowScaling);
+ 		else
+ 			switchToNormal(m_windowScaling);
+--- krfb/krfb/krfb.desktop	(revision 568672)
++++ krfb/krfb/krfb.desktop	(revision 586398)
+@@ -7,6 +7,7 @@
+ Terminal=false
+ Name=Krfb
+ Name[bn]=কে-আর-এফ-বি
++Name[zh_TW]=Krfb 桌面分享
+ GenericName=Desktop Sharing
+ GenericName[bg]=Споделяне на раб. място
+ GenericName[bn]=ডেস্কটপ ভাগাভাগি
+--- krfb/krfb_httpd/kinetd_krfb_httpd.desktop	(revision 568672)
++++ krfb/krfb_httpd/kinetd_krfb_httpd.desktop	(revision 586398)
+@@ -46,7 +46,7 @@
+ Comment[bg]=Малък уеб сървър, който обслужва аплета за преглед на VNC
+ Comment[bn]=কে-আর-এফ-বির জন্য একটি মাইক্রো এইচটিটিপি ডিমন যে ভি-এন-সি প্রদর্শক অ্যাপলেট সরবরাহ করে।
+ Comment[bs]=Mikro HTTP demon za krfb koji služi za applet VNC preglednika.
+-Comment[ca]=Un micro-dimoni http per a krfb que serveix l'applet visor VNC.
++Comment[ca]=Un micro-dimoni http per a krfb que serveix l'aplet visor VNC.
+ Comment[cs]=Mikro HTTP server pro krfb sloužící VNC prohlížeči.
+ Comment[cy]=Meicro-daemon http sy'n gwasanaethu'r rhaglennig gwelydd VNC
+ Comment[da]=En mikro http-dæmon for krfb der betjener VNC visningsappletten.
+--- lanbrowsing/kio_lan/lisa.desktop	(revision 568672)
++++ lanbrowsing/kio_lan/lisa.desktop	(revision 586398)
+@@ -21,6 +21,7 @@
+ Name[fr]=Navigateur réseau
+ Name[ga]=Brabhsálaí an Ghréasáin Logánta
+ Name[gl]=Explorador LAN
++Name[he]=LAN דפדפן
+ Name[hr]=Preglednik LAN-a
+ Name[hu]=Hálózatböngésző
+ Name[is]=Netflakkari
+--- kdnssd/ioslave/invitation.protocol	(revision 568672)
++++ kdnssd/ioslave/invitation.protocol	(revision 586398)
+@@ -24,6 +24,7 @@
+ Description[es]=Invitaciones SD
+ Description[et]=SD kutsed
+ Description[eu]=SD gonbidapenak
++Description[fi]=SD-kutsut
+ Description[fr]=Invitations SD
+ Description[gl]=Invitacións SD
+ Description[hu]=SD meghívók
+--- kdnssd/ioslave/zeroconf.protocol	(revision 568672)
++++ kdnssd/ioslave/zeroconf.protocol	(revision 586398)
+@@ -27,6 +27,7 @@
+ Description[fi]=Siirräntätyöskentelijä ZeroConfille
+ Description[fr]=Un module d'entrée / sortie pour ZeroConf
+ Description[gl]=Un kioslabe para ZeroConf
++Description[he]=kioslave בשביל ZeroConf
+ Description[hu]=KDE-protokoll a Zeroconf használatához
+ Description[is]=kioslave fyrir ZeroConf
+ Description[it]=Un kioslave per Zeroconf
+--- kopete/plugins/nowlistening/nowlisteningconfig.kcfg	(revision 568672)
++++ kopete/plugins/nowlistening/nowlisteningconfig.kcfg	(revision 586398)
+@@ -33,9 +33,14 @@
+ 		</entry>
+ 
+ 		<entry name="StatusAdvertising" type="Bool">
+-			<label>Show the current music listened in your status message.</label>
++			<label>Show the current music listened in place of your status message.</label>
+ 			<default>false</default>
+ 		</entry>
++
++		<entry name="AppendStatusAdvertising" type="Bool">
++			<label>Show the current music listened appended to your status message.</label>
++			<default>false</default> 
++		</entry>
+ 	
+ 		<entry name="UseSpecifiedMediaPlayer" type="Bool">
+ 			<label>Use the specified media player.</label>
+--- kopete/plugins/nowlistening/nowlisteningplugin.cpp	(revision 568672)
++++ kopete/plugins/nowlistening/nowlisteningplugin.cpp	(revision 586398)
+@@ -4,9 +4,9 @@
+     Kopete Now Listening To plugin
+ 
+     Copyright (c) 2002,2003,2004 by Will Stephenson <will at stevello.free-online.co.uk>
+-    Copyright (c) 2005           by Michaël Larouche <michael.larouche at kdemail.net>
++    Copyright (c) 2005-2006           by Michaël Larouche <michael.larouche at kdemail.net>
+ 
+-    Kopete    (c) 2002-2005      by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2006      by the Kopete developers  <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -20,6 +20,7 @@
+ 
+ #include <qtimer.h>
+ #include <qstringlist.h>
++#include <qregexp.h>
+ 
+ #include <kdebug.h>
+ #include <kgenericfactory.h>
+@@ -245,7 +246,7 @@
+ void NowListeningPlugin::slotAdvertCurrentMusic()
+ {
+ 	// Do anything when statusAdvertising is off.
+-	if( !NowListeningConfig::self()->statusAdvertising() )
++	if( !NowListeningConfig::self()->statusAdvertising() && !NowListeningConfig::self()->appendStatusAdvertising() )
+ 		return; 
+ 
+ 	// This slot is called every 5 seconds, so we check if we have a new track playing.
+@@ -260,8 +261,10 @@
+ 				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" )
++			if( a->protocol()->pluginId() == "MSNProtocol" && !NowListeningConfig::self()->appendStatusAdvertising() )
+ 			{
+ 				QString track, artist, album, mediaList;
+ 				bool isPlaying=false;
+@@ -294,12 +297,45 @@
+ 
+ 				// KDE4 TODO: Use the new status message framework, and remove this "hack".
+ 				if( isPlaying )
++				{
+ 					advert = QString("[Music]%1").arg(mediaList);
++				}
++
+ 			}
+ 			else
+ 			{
+-				advert = mediaPlayerAdvert(false); // newTrackPlaying has done the update.
++				if( NowListeningConfig::self()->appendStatusAdvertising() )
++				{
++					// Check for the now listening message in parenthesis, 
++					// include the header to not override other messages in parenthesis.
++					QRegExp statusSong( QString("\\(%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.
++					QString mediaAdvert = mediaPlayerAdvert(false);
++					if(!mediaAdvert.isEmpty())
++					{
++						if(statusSong.search(advert) != -1)
++						{
++							advert = advert.replace(statusSong, QString("(%1)").arg(mediaPlayerAdvert(false)) );
++						}
++						else
++						{
++							advert += QString("(%1)").arg( mediaPlayerAdvert(false) );
++						}
++					}
++					else
++					{
++						advert = advert.replace(statusSong, "");
++					}
++				}
++				else
++				{
++					advert = mediaPlayerAdvert(false); // newTrackPlaying has done the update.
++				}
+ 			}
++
+ 			a->setOnlineStatus(a->myself()->onlineStatus(), advert);
+ 		}
+ 	}
+@@ -502,7 +538,7 @@
+ 				this,
+ 				SLOT(slotOutgoingMessage(Kopete::Message&)));
+ 	}
+-	else if( NowListeningConfig::self()->statusAdvertising() )
++	else if( NowListeningConfig::self()->statusAdvertising() || NowListeningConfig::self()->appendStatusAdvertising() )
+ 	{
+ 		kdDebug(14307) << k_funcinfo << "Now using status message advertising." << endl;
+ 
+--- kopete/plugins/nowlistening/nowlisteningprefs.ui	(revision 568672)
++++ kopete/plugins/nowlistening/nowlisteningprefs.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>443</width>
+-            <height>398</height>
++            <width>391</width>
++            <height>370</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -208,47 +208,46 @@
+                         <property name="title">
+                             <string></string>
+                         </property>
+-                        <grid>
++                        <vbox>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLayoutWidget" row="0" column="0">
++                            <widget class="QRadioButton">
+                                 <property name="name">
+-                                    <cstring>layout6</cstring>
++                                    <cstring>kcfg_ExplicitAdvertising</cstring>
+                                 </property>
+-                                <vbox>
+-                                    <property name="name">
+-                                        <cstring>unnamed</cstring>
+-                                    </property>
+-                                    <widget class="QRadioButton">
+-                                        <property name="name">
+-                                            <cstring>kcfg_ExplicitAdvertising</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string>Explicit &amp;via "Tools-&gt;Send Media Info",
++                                <property name="text">
++                                    <string>Explicit &amp;via "Tools-&gt;Send Media Info",
+ or by typing "/media" in the chat
+ window edit area.</string>
+-                                        </property>
+-                                    </widget>
+-                                    <widget class="QRadioButton">
+-                                        <property name="name">
+-                                            <cstring>kcfg_ChatAdvertising</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string>Show in chat &amp;window (automatic)</string>
+-                                        </property>
+-                                    </widget>
+-                                    <widget class="QRadioButton">
+-                                        <property name="name">
+-                                            <cstring>kcfg_StatusAdvertising</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string>Show in &amp;your status message (automatic)</string>
+-                                        </property>
+-                                    </widget>
+-                                </vbox>
++                                </property>
+                             </widget>
+-                        </grid>
++                            <widget class="QRadioButton">
++                                <property name="name">
++                                    <cstring>kcfg_ChatAdvertising</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>&amp;Show in chat window (automatic)</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton">
++                                <property name="name">
++                                    <cstring>kcfg_StatusAdvertising</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Show &amp;the music you are listening to 
++in place of your status message.</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton">
++                                <property name="name">
++                                    <cstring>kcfg_AppendStatusAdvertising</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Appe&amp;nd to your status message</string>
++                                </property>
++                            </widget>
++                        </vbox>
+                     </widget>
+                     <spacer>
+                         <property name="name">
+@@ -263,7 +262,7 @@
+                         <property name="sizeHint">
+                             <size>
+                                 <width>20</width>
+-                                <height>40</height>
++                                <height>80</height>
+                             </size>
+                         </property>
+                     </spacer>
+--- kopete/plugins/smpppdcs/smpppdlocationwidget.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdlocationwidget.cpp	(revision 586398)
+@@ -0,0 +1,30 @@
++/*
++    smpppdlocationwidget.cpp
++
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <klineedit.h>
++
++#include "smpppdlocationwidget.h"
++
++SMPPPDLocationWidget::SMPPPDLocationWidget(QWidget* parent, const char* name, WFlags fl)
++ : SMPPPDLocationWidgetBase(parent, name, fl) {}
++
++SMPPPDLocationWidget::~SMPPPDLocationWidget() {}
++
++void SMPPPDLocationWidget::setServer(const QString& serv) {
++    server->setText(serv);
++}
++
++#include "smpppdlocationwidget.moc"
+--- kopete/plugins/smpppdcs/kinternetiface.h	(revision 0)
++++ kopete/plugins/smpppdcs/kinternetiface.h	(revision 586398)
+@@ -0,0 +1,47 @@
++// -*- c++ -*-
++/***************************************************************************
++ *									   *
++ *   Copyright: SuSE Linux AG, Nuernberg				   *
++ *									   *
++ *   Author: Arvin Schnell <arvin at suse.de>				   *
++ *									   *
++ ***************************************************************************/
++
++/***************************************************************************
++ *									   *
++ *   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 KINTERNETIFACE_H
++#define KINTERNETIFACE_H
++
++
++#include <dcopobject.h>
++
++class KInternetIface : public DCOPObject
++{
++    K_DCOP
++
++public:
++
++    KInternetIface (const QCString& name) : DCOPObject (name) { }
++
++k_dcop:
++
++    // query function for susewatcher
++    bool isOnline () {
++#ifndef NDEBUG
++	fprintf (stderr, "%s\n", __PRETTY_FUNCTION__);
++#endif
++	return kinternet && kinternet->get_status () == KInternet::CONNECTED;
++    }
++
++};
++
++
++#endif
+--- kopete/plugins/smpppdcs/libsmpppdclient/smpppdclient.h	(revision 568672)
++++ kopete/plugins/smpppdcs/libsmpppdclient/smpppdclient.h	(revision 586398)
+@@ -43,19 +43,19 @@
+     bool connect(const QString& server, uint port = 3185);
+     void disconnect();
+ 
+-	QStringList getInterfaceConfigurations();
+-	bool statusInterface(const QString& ifcfg);
+-	
++    QStringList getInterfaceConfigurations();
++    bool statusInterface(const QString& ifcfg);
++
+     bool isOnline();
+     QString serverID() const;
+     QString serverVersion() const;
+-	
+-	void setPassword(const QString& password);
+ 
++    void setPassword(const QString& password);
++
+ private:
+     friend class State;
+-    
+-	void changeState(State * newState);
++
++    void changeState(State * newState);
+     QStringList read() const;
+     void write(const char * cmd);
+ 
+@@ -64,7 +64,7 @@
+     KNetwork::KStreamSocket * m_sock;
+     QString m_serverID;
+     QString m_serverVer;
+-	QString m_password;
++    QString m_password;
+ };
+ 
+ inline void Client::changeState(State * newState) {
+@@ -72,7 +72,7 @@
+ }
+ 
+ inline void Client::setPassword(const QString& password) {
+-	m_password = password;
++    m_password = password;
+ }
+ 
+ };
+--- kopete/plugins/smpppdcs/libsmpppdclient/Makefile.am	(revision 568672)
++++ kopete/plugins/smpppdcs/libsmpppdclient/Makefile.am	(revision 586398)
+@@ -7,4 +7,4 @@
+ libsmpppdclient_la_SOURCES = smpppdclient.cpp smpppdstate.cpp smpppdready.cpp \
+ 	smpppdunsettled.cpp
+ 
+-libsmpppdclient_la_LIBADD = -lcrypto
+\ No newline at end of file
++libsmpppdclient_la_LIBADD = -lcrypto
+--- kopete/plugins/smpppdcs/iconnector.h	(revision 568672)
++++ kopete/plugins/smpppdcs/iconnector.h	(revision 586398)
+@@ -28,7 +28,7 @@
+ 
+ public:
+     IConnector() {}
+-    ;
++
+     virtual ~IConnector() {}
+ 
+     /**
+--- kopete/plugins/smpppdcs/smpppdcsconfig.kcfgc	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcsconfig.kcfgc	(revision 586398)
+@@ -0,0 +1,6 @@
++File=smpppdcs.kcfg
++ClassName=SMPPPDCSConfig
++Singleton=true
++Mutators=true
++MemberVariables=private
++GlobalEnums=true
+\ No newline at end of file
+--- kopete/plugins/smpppdcs/smpppdcsprefsimpl.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcsprefsimpl.cpp	(revision 586398)
+@@ -0,0 +1,165 @@
++/*
++    smpppdcsprefsimpl.cpp
++ 
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++ 
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <arpa/inet.h>
++#include <netdb.h>
++
++#include <qradiobutton.h>
++
++#include <kstandarddirs.h>
++#include <kapplication.h>
++#include <kpushbutton.h>
++#include <kresolver.h>
++#include <knuminput.h>
++#include <klocale.h>
++#include <kdebug.h>
++
++#include "kopetepluginmanager.h"
++
++#include "../smpppdcsplugin.h"
++
++#include "smpppdlocationwidget.h"
++#include "smpppdcsprefsimpl.h"
++#include "smpppdsearcher.h"
++
++SMPPPDCSPrefs::SMPPPDCSPrefs(QWidget* parent, const char* name, WFlags fl)
++	: SMPPPDCSPrefsBase(parent, name, fl), m_plugin(NULL), m_scanProgressDlg(NULL), m_curSearcher(NULL) {
++
++	// search for our main-plugin instance
++	Kopete::Plugin * p = Kopete::PluginManager::self()->plugin("kopete_smpppdcs");
++	if(p) {
++		m_plugin = static_cast<SMPPPDCSPlugin *>(p);
++	}
++
++    // signals and slots connections
++    connect(useNetstat, SIGNAL(toggled(bool)), this, SLOT(disableSMPPPDSettings()));
++    connect(useSmpppd,  SIGNAL(toggled(bool)), this, SLOT(enableSMPPPDSettings()));
++    connect(autoCSTest, SIGNAL(clicked()),     this, SLOT(determineCSType()));
++	
++	if(m_plugin) {
++		connect((QObject *)SMPPPDLocation->server, SIGNAL(textChanged(const QString&)),
++				m_plugin, SLOT(smpppdServerChanged(const QString&)));
++	}
++
++    // if netstat is NOT available, disable the option and set to SMPPPD
++    if(KStandardDirs::findExe("netstat") == QString::null) {
++        autoCSTest->setEnabled(FALSE);
++        useNetstat->setEnabled(FALSE);
++        useNetstat->setChecked(FALSE);
++        useSmpppd->setChecked(TRUE);
++    }
++}
++
++SMPPPDCSPrefs::~SMPPPDCSPrefs() {
++    delete m_scanProgressDlg;
++}
++
++void SMPPPDCSPrefs::determineCSType() {
++
++    // while we search, we'll disable the button
++    autoCSTest->setEnabled(false);
++    //kapp->processEvents();
++
++    /* broadcast network for a smpppd.
++       If one is available set to smpppd method */
++
++    SMPPPDSearcher searcher;
++    m_curSearcher = &searcher;
++
++    connect(&searcher, SIGNAL(smpppdFound(const QString&)), this, SLOT(smpppdFound(const QString&)));
++    connect(&searcher, SIGNAL(smpppdNotFound()), this, SLOT(smpppdNotFound()));
++    connect(&searcher, SIGNAL(scanStarted(uint)), this, SLOT(scanStarted(uint)));
++    connect(&searcher, SIGNAL(scanProgress(uint)), this, SLOT(scanProgress(uint)));
++    connect(&searcher, SIGNAL(scanFinished()), this, SLOT(scanFinished()));
++
++    searcher.searchNetwork();
++    m_curSearcher = NULL;
++}
++
++void SMPPPDCSPrefs::scanStarted(uint total) {
++    kdDebug(14312) << k_funcinfo << "Scanning for a SMPPPD started. Will scan " << total << " IPs" << endl;
++
++    // setup the scanProgress Dialog
++    if(!m_scanProgressDlg) {
++        m_scanProgressDlg = new KProgressDialog(this, 0, i18n("Searching"), i18n("Searching for a SMPPPD on the local network..."), TRUE);
++        m_scanProgressDlg->setAutoClose(TRUE);
++        m_scanProgressDlg->setAllowCancel(TRUE);
++        m_scanProgressDlg->setMinimumDuration(2000);
++
++        connect(m_scanProgressDlg, SIGNAL(cancelClicked()), this, SLOT(cancelScanning()));
++    }
++    m_scanProgressDlg->progressBar()->setTotalSteps(total);
++    m_scanProgressDlg->progressBar()->setProgress(0);
++    m_scanProgressDlg->show();
++}
++
++void SMPPPDCSPrefs::scanProgress(uint cur) {
++    m_scanProgressDlg->progressBar()->setProgress(cur);
++    kapp->processEvents();
++}
++
++void SMPPPDCSPrefs::cancelScanning() {
++    kdDebug(14312) << k_funcinfo << endl;
++    Q_ASSERT(m_curSearcher);
++    m_curSearcher->cancelSearch();
++}
++
++void SMPPPDCSPrefs::smpppdFound(const QString& host) {
++    kdDebug(14312) << k_funcinfo << endl;
++
++    QString myHost = host;
++
++    // try to get the domain name
++    struct in_addr addr;
++    if(inet_aton(host.ascii(), &addr)) {
++        struct hostent * hostEnt = gethostbyaddr(&addr.s_addr, sizeof(addr.s_addr), AF_INET);
++        if(hostEnt) {
++            myHost = hostEnt->h_name;
++        } else {
++#ifndef NDEBUG
++            switch(h_errno) {
++            case HOST_NOT_FOUND:
++                kdDebug(14312) << k_funcinfo << "No such host is known in the database." << endl;
++                break;
++            case TRY_AGAIN:
++                kdDebug(14312) << k_funcinfo << "Couldn't contact DNS server." << endl;
++                break;
++            case NO_RECOVERY:
++                kdDebug(14312) << k_funcinfo << "A non-recoverable error occurred." << endl;
++                break;
++            case NO_ADDRESS:
++                kdDebug(14312) << k_funcinfo << "The host database contains an entry for the name, but it doesn't have an associated Internet address." << endl;
++                break;
++            }
++#endif
++
++        }
++    }
++
++    SMPPPDLocation->setServer(myHost);
++    useNetstat->setChecked(false);
++    useSmpppd->setChecked(true);
++    autoCSTest->setEnabled(true);
++}
++
++void SMPPPDCSPrefs::smpppdNotFound() {
++    kdDebug(14312) << k_funcinfo << endl;
++    useNetstat->setChecked(true);
++    useSmpppd->setChecked(false);
++    autoCSTest->setEnabled(true);
++}
++
++#include "smpppdcsprefsimpl.moc"
+--- kopete/plugins/smpppdcs/smpppdcspreferences.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcspreferences.cpp	(revision 586398)
+@@ -0,0 +1,187 @@
++/*
++    smpppdcspreferences.cpp
++
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qlayout.h>
++#include <qregexp.h>
++#include <qradiobutton.h>
++
++#include <klistview.h>
++#include <klineedit.h>
++#include <knuminput.h>
++#include <kgenericfactory.h>
++
++#include "kopeteaccount.h"
++#include "kopeteprotocol.h"
++#include "kopeteaccountmanager.h"
++
++#include "smpppdlocationwidget.h"
++#include "smpppdcspreferences.h"
++#include "smpppdcsprefsimpl.h"
++#include "smpppdcsconfig.h"
++
++typedef KGenericFactory<SMPPPDCSPreferences> SMPPPDCSPreferencesFactory;
++K_EXPORT_COMPONENT_FACTORY(kcm_kopete_smpppdcs, SMPPPDCSPreferencesFactory("kcm_kopete_smpppdcs"))
++
++SMPPPDCSPreferences::SMPPPDCSPreferences(QWidget * parent, const char * /* name */, const QStringList& args)
++ : KCModule(SMPPPDCSPreferencesFactory::instance(), parent, args), m_ui(NULL) {
++
++ 	Kopete::AccountManager * manager = Kopete::AccountManager::self(); 
++	(new QVBoxLayout(this))->setAutoAdd(true);
++	m_ui = new SMPPPDCSPrefs(this);
++
++	for(QPtrListIterator<Kopete::Account> it(manager->accounts()); it.current(); ++it)
++	{
++		QString protoName;
++		QRegExp rex("(.*)Protocol");
++		
++		if(rex.search((*it)->protocol()->pluginId()) > -1) {
++			protoName = rex.cap(1);
++		} else {
++			protoName = (*it)->protocol()->pluginId();
++		}
++		
++		if(it.current()->inherits("Kopete::ManagedConnectionAccount")) {
++			protoName += QString(", %1").arg(i18n("connection status is managed by Kopete"));
++		}
++		
++		QCheckListItem * cli = new QCheckListItem(m_ui->accountList, 
++				(*it)->accountId() + " (" + protoName + ")", QCheckListItem::CheckBox);
++		cli->setPixmap(0, (*it)->accountIcon());
++		
++		m_accountMapOld[cli->text(0)] = AccountPrivMap(FALSE, (*it)->protocol()->pluginId() + "_" + (*it)->accountId());
++		m_accountMapCur[cli->text(0)] = AccountPrivMap(FALSE, (*it)->protocol()->pluginId() + "_" + (*it)->accountId());;
++		m_ui->accountList->insertItem(cli);
++	}
++
++	connect(m_ui->accountList, SIGNAL(clicked(QListViewItem *)), this, SLOT(listClicked(QListViewItem *)));
++	
++	// connect for modified
++	connect(m_ui->useNetstat, SIGNAL(clicked()), this, SLOT(slotModified()));
++	connect(m_ui->useSmpppd,  SIGNAL(clicked()), this, SLOT(slotModified()));
++	
++	connect(m_ui->SMPPPDLocation->server,   SIGNAL(textChanged(const QString&)), this, SLOT(slotModified()));
++	connect(m_ui->SMPPPDLocation->port,     SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
++	connect(m_ui->SMPPPDLocation->Password, SIGNAL(textChanged(const QString&)), this, SLOT(slotModified()));
++	
++	load();
++}
++
++SMPPPDCSPreferences::~SMPPPDCSPreferences() {
++	delete m_ui;
++}
++
++void SMPPPDCSPreferences::listClicked(QListViewItem * item)
++{
++	QCheckListItem * cli = dynamic_cast<QCheckListItem *>(item);
++	
++	if(cli->isOn() != m_accountMapCur[cli->text(0)].m_on) {
++		AccountMap::iterator itOld = m_accountMapOld.begin();
++		AccountMap::iterator itCur;
++		bool change = FALSE;
++		
++		for(itCur = m_accountMapCur.begin(); itCur != m_accountMapCur.end(); ++itCur, ++itOld) {
++			if((*itCur).m_on != (*itOld).m_on){
++				change = TRUE;
++				break;
++			}
++		}
++		emit KCModule::changed(change);
++	}
++	m_accountMapCur[cli->text(0)].m_on = cli->isOn();
++}
++
++void SMPPPDCSPreferences::defaults()
++{
++	QListViewItemIterator it(m_ui->accountList);
++	while(it.current()) {
++		QCheckListItem * cli = dynamic_cast<QCheckListItem *>(it.current());
++		cli->setOn(FALSE);
++		++it;
++	}
++	
++	SMPPPDCSConfig::self()->setDefaults();
++	
++	m_ui->useNetstat->setChecked(SMPPPDCSConfig::self()->useNetstat());
++	m_ui->useSmpppd->setChecked(SMPPPDCSConfig::self()->useSmpppd());
++	
++	m_ui->SMPPPDLocation->server->setText(SMPPPDCSConfig::self()->server());
++	m_ui->SMPPPDLocation->port->setValue(SMPPPDCSConfig::self()->port());
++	m_ui->SMPPPDLocation->Password->setText(SMPPPDCSConfig::self()->password());
++}
++
++void SMPPPDCSPreferences::load()
++{
++	
++	SMPPPDCSConfig::self()->readConfig();
++	
++	static QString rexStr = "^(.*) \\((.*)\\)";
++	QRegExp rex(rexStr);
++	QStringList list = SMPPPDCSConfig::self()->ignoredAccounts();
++	QListViewItemIterator it(m_ui->accountList);
++	while(it.current()) {
++		QCheckListItem * cli = dynamic_cast<QCheckListItem *>(it.current());
++		if(rex.search(cli->text(0)) > -1) {
++			bool isOn = list.contains(rex.cap(2) + "Protocol_" + rex.cap(1));
++			// m_accountMapOld[cli->text(0)].m_on = isOn;
++			m_accountMapCur[cli->text(0)].m_on = isOn;
++			cli->setOn(isOn);
++		}
++		++it;
++	}
++	
++	m_ui->useNetstat->setChecked(SMPPPDCSConfig::self()->useNetstat());
++	m_ui->useSmpppd->setChecked(SMPPPDCSConfig::self()->useSmpppd());
++	
++	m_ui->SMPPPDLocation->server->setText(SMPPPDCSConfig::self()->server());
++	m_ui->SMPPPDLocation->port->setValue(SMPPPDCSConfig::self()->port());
++	m_ui->SMPPPDLocation->Password->setText(SMPPPDCSConfig::self()->password());
++	
++	emit KCModule::changed(false);
++}
++
++void SMPPPDCSPreferences::save()
++{
++	QStringList list;
++	QListViewItemIterator it(m_ui->accountList);
++	while(it.current()) {
++	
++		QCheckListItem * cli = dynamic_cast<QCheckListItem *>(it.current());
++		if(cli->isOn()) {
++			list.append(m_accountMapCur[cli->text(0)].m_id);
++		}
++		
++		++it;
++	}
++	
++	SMPPPDCSConfig::self()->setIgnoredAccounts(list);
++	
++	SMPPPDCSConfig::self()->setUseNetstat(m_ui->useNetstat->isChecked());
++	SMPPPDCSConfig::self()->setUseSmpppd(m_ui->useSmpppd->isChecked());
++	
++	SMPPPDCSConfig::self()->setServer(m_ui->SMPPPDLocation->server->text());
++	SMPPPDCSConfig::self()->setPort(m_ui->SMPPPDLocation->port->value());
++	SMPPPDCSConfig::self()->setPassword(m_ui->SMPPPDLocation->Password->text());
++	
++	SMPPPDCSConfig::self()->writeConfig();
++	
++	emit KCModule::changed(false);
++}
++
++void SMPPPDCSPreferences::slotModified() {
++	emit KCModule::changed(true);
++}
++
++#include "smpppdcspreferences.moc"
+--- kopete/plugins/smpppdcs/smpppdcsplugin.h	(revision 568672)
++++ kopete/plugins/smpppdcs/smpppdcsplugin.h	(revision 586398)
+@@ -62,7 +62,15 @@
+      */
+     virtual ~SMPPPDCSPlugin();
+ 
++    // Implementation of DCOP iface
+     /**
++     * @brief Checks if we are online.
++     * @note This method is reserved for future use. Do not use at the moment!
++     * @return <code>TRUE</code> if online, otherwise <code>FALSE</code>
++     */
++    virtual bool isOnline() const;
++
++    /**
+      * @brief Sets the status in all allowed accounts.
+      * Allowed accounts are set in the config dialog of the plugin.
+      *
+@@ -70,39 +78,27 @@
+      */
+     virtual void setConnectedStatus( bool newStatus );
+ 
+-    // Implementation of DCOP iface
+-
+-    /**
+-     * @brief Checks if we are online.
+-     * @note This method is reserved for future use. Do not use at the moment!
+-     * @return <code>TRUE</code> if online, otherwise <code>FALSE</code>
+-     */
+-    virtual bool isOnline();
+-
+     virtual QString detectionMethod() const;
+ 
+-protected:
+-    /**
+-     * @brief Should the smpppd be used for inquiring
+-     * @return <code>TRUE</code> for smpppd, <code>FALSE</code> for netstat
+-     */
+-    bool useSmpppd() const;
++    virtual void aboutToUnload();
+ 
+ public slots:
+-	void smpppdServerChanged(const QString& server);
++    void smpppdServerChanged(const QString& server);
+ 
+ private slots:
+     void slotCheckStatus();
+     void allPluginsLoaded();
+ 
+ private:
+-    void connectAllowed();
++    
++	void connectAllowed();
+     void disconnectAllowed();
+ 
+ private:
+ 
+     Detector      * m_detectorSMPPPD;
+     Detector      * m_detectorNetstat;
++    Detector      * m_detectorNetworkStatus;
+     bool            m_pluginConnected;
+     QTimer        * m_timer;
+     OnlineInquiry * m_onlineInquiry;
+--- kopete/plugins/smpppdcs/detectordcop.cpp	(revision 568672)
++++ kopete/plugins/smpppdcs/detectordcop.cpp	(revision 586398)
+@@ -18,24 +18,26 @@
+ #include <dcopclient.h>
+ #include <kdebug.h>
+ 
++#include "kinternetiface_stub.h"
++
+ #include "detectordcop.h"
+ #include "iconnector.h"
+ 
+ QCString DetectorDCOP::m_kinternetApp = "";
+ 
+ DetectorDCOP::DetectorDCOP(IConnector * connector)
+-        : Detector(connector) {}
++	: Detector(connector) {}
+ 
+ DetectorDCOP::~DetectorDCOP() {}
+ 
+ /*!
+     \fn DetectorDCOP::getKInternetDCOP()
+  */
+-QCString DetectorDCOP::getKInternetDCOP() {
+-    m_client = kapp->dcopClient();
+-    if(m_kinternetApp.isEmpty() && m_client && m_client->isAttached()) {
++QCString DetectorDCOP::getKInternetDCOP() const {
++    DCOPClient * client = kapp->dcopClient();
++    if(m_kinternetApp.isEmpty() && client && client->isAttached()) {
+         // get all registered dcop apps and search for kinternet
+-        QCStringList apps = m_client->registeredApplications();
++        QCStringList apps = client->registeredApplications();
+         QCStringList::iterator iter;
+         for(iter = apps.begin(); iter != apps.end(); ++iter) {
+             if((*iter).left(9) == "kinternet") {
+@@ -50,27 +52,26 @@
+ /*!
+     \fn DetectorDCOP::getConnectionStatusDCOP()
+  */
+-DetectorDCOP::KInternetDCOPState DetectorDCOP::getConnectionStatusDCOP() {
+-    QByteArray data, replyData;
+-    QCString replyType;
+-    QDataStream arg(data, IO_WriteOnly);
+-
++DetectorDCOP::KInternetDCOPState DetectorDCOP::getConnectionStatusDCOP() const {
+     kdDebug(14312) << k_funcinfo << "Start inquiring " << m_kinternetApp << " via DCOP" << endl;
++	
++	
++	KInternetIface_stub stub = KInternetIface_stub(kapp->dcopClient(), m_kinternetApp, "KInternetIface");
++	
++	bool status = stub.isOnline();
++	
++	if(stub.ok()) {
++		if(status) {
++			kdDebug(14312) << k_funcinfo << "isOnline() returned true" << endl;
++			return CONNECTED;
++		} else {
++			kdDebug(14312) << k_funcinfo << "isOnline() returned false" << endl;
++			return DISCONNECTED;
++		}
++	} else {
++		kdWarning(14312) << k_funcinfo << "DCOP call to " << m_kinternetApp << " failed!";
++	}
+ 
+-    if(!m_client->call(m_kinternetApp, "KInternetIface", "isOnline()", data, replyType, replyData)) {
+-        kdDebug(14312) << k_funcinfo << "there was some error using DCOP." << endl;
+-    } else {
+-        QDataStream reply(replyData, IO_ReadOnly);
+-        if(replyType == "bool") {
+-            bool result;
+-            reply >> result;
+-            kdDebug(14312) << k_funcinfo << "isOnline() returned " << result << endl;
+-            return result ? CONNECTED : DISCONNECTED;
+-        } else {
+-            kdDebug(14312) << k_funcinfo << "isOnline() returned an unexpected type of reply!" << endl;
+-        }
+-    }
+-
+-    return ERROR;
++	return ERROR;
+ }
+ 
+--- kopete/plugins/smpppdcs/smpppdcs.kcfg	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcs.kcfg	(revision 586398)
+@@ -0,0 +1,29 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
++<kcfg> 
++  <kcfgfile name="kopeterc"/> 
++  <group name="SMPPPDCS Plugin"> 
++    <entry name="Password" type="String"> 
++      <label>Password to connect to the SMPPPD.</label> 
++    </entry> 
++    <entry name="ignoredAccounts" type="StringList"> 
++      <label>Accounts to ignore in the plugin.</label> 
++    </entry> 
++    <entry name="server" type="String"> 
++      <label>SMPPPD-Server to connect.</label> 
++      <default>localhost</default>
++    </entry> 
++    <entry name="port" type="UInt"> 
++      <label>SMPPPD-Server port to connect.</label> 
++      <default>3185</default>
++    </entry> 
++    <entry name="useNetstat" type="Bool"> 
++      <label>Use the netstat tool to determine the connection status.</label> 
++      <default>true</default>
++    </entry> 
++    <entry name="useSmpppd" type="Bool"> 
++      <label>Use the SMPPPD to determine the connection status.</label> 
++      <default>false</default>
++    </entry> 
++  </group> 
++</kcfg>
+\ No newline at end of file
+--- kopete/plugins/smpppdcs/detectornetstat.h	(revision 568672)
++++ kopete/plugins/smpppdcs/detectornetstat.h	(revision 586398)
+@@ -37,7 +37,7 @@
+     DetectorNetstat(IConnector* connector);
+     virtual ~DetectorNetstat();
+ 
+-    virtual void checkStatus();
++    virtual void checkStatus() const;
+ 
+ private slots:
+     // Original cs-plugin code
+@@ -49,8 +49,8 @@
+     void slotProcessExited(KProcess *process);
+ 
+ private:
+-    QString m_buffer;
+-    KProcess * m_process;
++	mutable QString    m_buffer;
++    mutable KProcess * m_process;
+ };
+ 
+ #endif
+--- kopete/plugins/smpppdcs/smpppdlocationui.ui	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdlocationui.ui	(revision 586398)
+@@ -0,0 +1,149 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>SMPPPDLocationWidgetBase</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>SMPPPDLocationWidgetBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>365</width>
++            <height>167</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>SMPPPDLocation</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel1</cstring>
++            </property>
++            <property name="text">
++                <string>Ser&amp;ver:</string>
++            </property>
++            <property name="buddy" stdset="0">
++                <cstring>server</cstring>
++            </property>
++        </widget>
++        <widget class="KLineEdit">
++            <property name="name">
++                <cstring>server</cstring>
++            </property>
++            <property name="cursor">
++                <cursor>4</cursor>
++            </property>
++            <property name="text">
++                <string>localhost</string>
++            </property>
++            <property name="maxLength">
++                <number>256</number>
++            </property>
++            <property name="toolTip" stdset="0">
++                <string>The server on which the SMPPPD is running</string>
++            </property>
++        </widget>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel2</cstring>
++            </property>
++            <property name="text">
++                <string>P&amp;ort:</string>
++            </property>
++            <property name="buddy" stdset="0">
++                <cstring>port</cstring>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout14</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="KIntNumInput">
++                    <property name="name">
++                        <cstring>port</cstring>
++                    </property>
++                    <property name="cursor">
++                        <cursor>4</cursor>
++                    </property>
++                    <property name="value">
++                        <number>3185</number>
++                    </property>
++                    <property name="minValue">
++                        <number>0</number>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>The port on which the SMPPPD is running on</string>
++                    </property>
++                </widget>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>textLabel3</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Default: 3185</string>
++                    </property>
++                </widget>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer15</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>130</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++            </hbox>
++        </widget>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>m_passwordLabel</cstring>
++            </property>
++            <property name="text">
++                <string>Pass&amp;word:</string>
++            </property>
++            <property name="buddy" stdset="0">
++                <cstring>Password</cstring>
++            </property>
++        </widget>
++        <widget class="KLineEdit">
++            <property name="name">
++                <cstring>Password</cstring>
++            </property>
++            <property name="cursor">
++                <cursor>4</cursor>
++            </property>
++            <property name="echoMode">
++                <enum>Password</enum>
++            </property>
++            <property name="toolTip" stdset="0">
++                <string>The password to authenticate with the smpppd</string>
++            </property>
++        </widget>
++    </vbox>
++</widget>
++<customwidgets>
++</customwidgets>
++<layoutdefaults spacing="6" margin="0"/>
++<includehints>
++    <includehint>klineedit.h</includehint>
++    <includehint>knuminput.h</includehint>
++    <includehint>knuminput.h</includehint>
++    <includehint>klineedit.h</includehint>
++</includehints>
++</UI>
+--- kopete/plugins/smpppdcs/smpppdsearcher.h	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdsearcher.h	(revision 586398)
+@@ -0,0 +1,102 @@
++/*
++    smpppdsearcher.h
++ 
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++ 
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++
++#ifndef SMPPPDSEARCHER_H
++#define SMPPPDSEARCHER_H
++
++#include <kresolver.h>
++
++class KProcess;
++
++/**
++ * @brief Searches a network for a smpppd
++ *
++ * @todo Use of the SLP to find the smpppd
++ * @author Heiko Sch&auml;fer <heiko at rangun.de>
++ */
++class SMPPPDSearcher : public QObject {
++    Q_OBJECT
++
++    SMPPPDSearcher(const SMPPPDSearcher&);
++    SMPPPDSearcher& operator=(const SMPPPDSearcher&);
++
++public:
++    /**
++     * @brief Creates an <code>SMPPPDSearcher</code> instance
++     */
++    SMPPPDSearcher();
++	
++    /**
++     * @brief Destroys an <code>SMPPPDSearcher</code> instance
++     */
++    ~SMPPPDSearcher();
++
++    /**
++     * @brief Triggers a network scan to find a smpppd
++	 * @see smpppdFound
++	 * @see smpppdNotFound
++     */
++    void searchNetwork();
++	
++	void cancelSearch();
++
++protected:
++    /**
++     * @brief Scans a network for a smpppd
++	 *
++	 * Scans a network for a smpppd described by
++	 * ip and mask.
++	 *
++     * @param ip   the ntwork ip
++     * @param mask the network mask
++     * @return <code>TRUE</code> if an smpppd was found
++     */
++    bool scan(const QString& ip, const QString& mask);
++
++signals:
++    /**
++     * @brief A smppd was found
++	 * 
++     * @param host the host there the smpppd was found
++     */
++    void smpppdFound(const QString& host);
++	
++    /**
++     * @brief No smpppd was found 
++     */
++    void smpppdNotFound();
++	
++	void scanStarted(uint total);
++	void scanProgress(uint cur);
++	void scanFinished();
++
++protected slots:
++    void slotStdoutReceivedIfconfig(KProcess * proc, char * buf, int len);
++    void slotStdoutReceivedNetstat (KProcess * proc, char * buf, int len);
++
++private:
++	bool m_cancelSearchNow;
++    KProcess * m_procIfconfig;
++    KProcess * m_procNetstat;
++};
++
++inline void SMPPPDSearcher::cancelSearch() {
++	m_cancelSearchNow = TRUE;
++}
++
++#endif
++
+--- kopete/plugins/smpppdcs/smpppdcsiface.h	(revision 568672)
++++ kopete/plugins/smpppdcs/smpppdcsiface.h	(revision 586398)
+@@ -30,7 +30,7 @@
+   k_dcop:
+ 
+     virtual QString detectionMethod() const = 0;
+-    virtual bool isOnline() = 0;
++    virtual bool isOnline() const = 0;
+ };
+ 
+ #endif
+--- kopete/plugins/smpppdcs/detectornetworkstatus.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/detectornetworkstatus.cpp	(revision 586398)
+@@ -0,0 +1,68 @@
++/*
++	detectornetworkstatus.cpp
++
++	Copyright (c) 2006      by Heiko Schaefer        <heiko at rangun.de>
++
++	Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#include <kdebug.h>
++
++#include "kopeteuiglobal.h"
++#include "connectionmanager.h"
++
++#include "iconnector.h"
++#include "detectornetworkstatus.h"
++
++DetectorNetworkStatus::DetectorNetworkStatus(IConnector* connector) 
++	: Detector(connector), m_connManager(NULL) {
++	
++	m_connManager = ConnectionManager::self();
++	connect(m_connManager, SIGNAL(statusChanged(const QString&, NetworkStatus::EnumStatus)),
++			this, SLOT(statusChanged(const QString&, NetworkStatus::EnumStatus)));
++}
++
++DetectorNetworkStatus::~DetectorNetworkStatus() {}
++
++void DetectorNetworkStatus::checkStatus() const {
++	// needs to do nothing
++}
++
++void DetectorNetworkStatus::statusChanged(const QString& host, NetworkStatus::EnumStatus status) {
++	switch(status) {
++		case NetworkStatus::Offline:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::Offline" << endl;
++			break;
++		case NetworkStatus::OfflineFailed:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::OfflineFailed" << endl;
++			break;
++		case NetworkStatus::OfflineDisconnected:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::OfflineDisconnected" << endl;
++			break;
++		case NetworkStatus::ShuttingDown:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::ShuttingDown" << endl;
++			break;
++		case NetworkStatus::Establishing:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::Establishing" << endl;
++			break;
++		case NetworkStatus::Online:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::Online" << endl;
++			break;
++		case NetworkStatus::NoNetworks:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::NoNetworks" << endl;
++			break;
++		case NetworkStatus::Unreachable:
++			kdDebug(14312) << k_funcinfo << host << ": NetworkStatus::Unreachable" << endl;
++			break;
++	}
++}
++
++#include "detectornetworkstatus.moc"
+--- kopete/plugins/smpppdcs/Changelog.smpppdcs	(revision 568672)
++++ kopete/plugins/smpppdcs/Changelog.smpppdcs	(revision 586398)
+@@ -15,15 +15,22 @@
+ Changelog
+ =========
+ 
+-0.79 (2006/01/18)
++0.79 (2006/01/25)
++* using KConfigXT for configuration
++* using dcopidl2cpp stub generated from kinternetiface.h (from kinternet package),
++  no more own implementation
++* experimental implementation of the the KDED-NetworkStatus (not active, yet)
++* significantly speeded up automatic detection of a SMPPPD
++* BUGFIX: reloading the plugin in a already running Kopete will no more 
++  result in an inactive plugin
+ * refactoring to allow easy implementation of new detection methods
+-* speed improvements
++* even more speed improvements
+ 
+ 0.75 (2006/01/01)
+ * use of KSocketStream instead of deprecated KExtendedSocket
+ * progressbar while searching for an smpppd on the local network
+ * automatically found smpppd server is resolved via DNS
+-* Fixed Bug 111369: better detection of SMPPPD and no more freeze of Kopete
++* Fixed Bug 111369: better detection of a SMPPPD and no more freeze of Kopete
+ 
+ 0.74 (2005/12/27)
+ * minor bugfixes
+@@ -38,7 +45,7 @@
+   Accounts can be excluded from the plugin connect/disconnect
+   mechanism
+ * connection detection enhanced: first kinternet is asked via
+-  DCOP for a running connection, if this fails smpppdcs is asked
++  DCOP for a running connection, if this fails the smpppd is asked
+ * improved startup detection, compatible with recent CVS changes
+ * some API chages in the config module
+ 
+--- kopete/plugins/smpppdcs/unittest/clienttest.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/unittest/clienttest.cpp	(revision 586398)
+@@ -0,0 +1,121 @@
++/*
++	clienttest.cpp
++ 
++	Copyright (c) 2006      by Heiko Schaefer        <heiko at rangun.de>
++ 
++	Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#include "smpppdclient.h"
++
++#include "clienttest.h"
++
++ClientTest::ClientTest(const char * name)
++        : KUnitTest::SlotTester(name) {}
++
++ClientTest::~ClientTest() {}
++
++void ClientTest::testInitIsReady() {
++    SMPPPD::Client c;
++    CHECK(c.isReady(), false);
++}
++
++void ClientTest::testAfterConnectIsReady() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        CHECK(c.isReady(), true);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testConnect() {
++    SMPPPD::Client c;
++    CHECK(c.connect("warwar", 3185), true);
++    CHECK(c.connect("localhost", 3185), false);
++}
++
++void ClientTest::testCommunicationBeforeConnect() {
++    SMPPPD::Client c;
++    QStringList l = c.getInterfaceConfigurations();
++
++    CHECK(l.count() == 0, true);
++    CHECK(c.statusInterface("ifcfg0"), false);
++}
++
++void ClientTest::testServerIDBeforeConnect() {
++    SMPPPD::Client c;
++    CHECK(c.serverID(), QString::null);
++}
++
++void ClientTest::testServerVersionBeforeConnect() {
++    SMPPPD::Client c;
++    CHECK(c.serverVersion(), QString::null);
++}
++
++void ClientTest::testCommunicationAfterConnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        CHECK(c.getInterfaceConfigurations().count() > 0, true);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testServerIDAfterConnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        CHECK(c.serverID().isEmpty(), false);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testServerVersionAfterConnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        CHECK(c.serverVersion().isEmpty(), false);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testCommunicationAfterDisconnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        c.disconnect();
++        CHECK(c.getInterfaceConfigurations().count() == 0, true);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testServerIDAfterDisconnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        c.disconnect();
++        CHECK(c.serverID(), QString::null);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++void ClientTest::testServerVersionAfterDisconnect() {
++    SMPPPD::Client c;
++    if(c.connect("warwar", 3185)) {
++        c.disconnect();
++        CHECK(c.serverVersion(), QString::null);
++    } else {
++        SKIP("Test skipped because no smpppd at warwar:3185");
++    }
++}
++
++#include "clienttest.moc"
+--- kopete/plugins/smpppdcs/unittest/clienttest.h	(revision 0)
++++ kopete/plugins/smpppdcs/unittest/clienttest.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++	clienttest.h
++ 
++	Copyright (c) 2006      by Heiko Schaefer        <heiko at rangun.de>
++ 
++	Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#ifndef CLIENTTEST_H
++#define CLIENTTEST_H
++
++#include <kunittest/tester.h>
++
++/**
++	@author Heiko Sch&auml;fer <heiko at rangun.de>
++*/
++class ClientTest : public KUnitTest::SlotTester {
++    Q_OBJECT
++
++    ClientTest(const ClientTest&);
++    ClientTest& operator=(const ClientTest&);
++
++public:
++    ClientTest(const char * name = 0);
++    virtual ~ClientTest();
++
++private slots:
++    void testInitIsReady();
++    void testAfterConnectIsReady();
++    void testConnect();
++    void testCommunicationBeforeConnect();
++    void testServerIDBeforeConnect();
++    void testServerVersionBeforeConnect();
++    void testCommunicationAfterConnect();
++    void testServerIDAfterConnect();
++    void testServerVersionAfterConnect();
++    void testCommunicationAfterDisconnect();
++    void testServerIDAfterDisconnect();
++    void testServerVersionAfterDisconnect();
++};
++
++#endif
+--- kopete/plugins/smpppdcs/unittest/main.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/unittest/main.cpp	(revision 586398)
+@@ -0,0 +1,45 @@
++/*
++	main.cpp
++ 
++	Copyright (c) 2006      by Heiko Schaefer        <heiko at rangun.de>
++ 
++	Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#include <kaboutdata.h>
++#include <kapplication.h>
++#include <kcmdlineargs.h>
++#include <kcmdlineargs.h>
++#include <klocale.h>
++#include <kunittest/runnergui.h>
++
++#include "clienttest.h"
++
++static const char description[] = I18N_NOOP("SMPPPDClientTests");
++static const char version[] = "0.1";
++static KCmdLineOptions options[] = { KCmdLineLastOption };
++
++int main( int argc, char** argv ) {
++    KAboutData about("SMPPPDClientTests", I18N_NOOP("SMPPPDClientTests"), version, description,
++                     KAboutData::License_BSD, "(C) 2006 Heiko Schäfer", 0, 0, "heiko at rangun.de");
++
++    KCmdLineArgs::init(argc, argv, &about);
++    KCmdLineArgs::addCmdLineOptions(options);
++    KApplication app;
++
++    KUnitTest::Runner::registerTester("ClientTest", new ClientTest);
++
++    KUnitTest::RunnerGUI runner(0);
++    runner.show();
++    app.setMainWidget(&runner);
++
++    return app.exec();
++}
+--- kopete/plugins/smpppdcs/unittest/Makefile.am	(revision 0)
++++ kopete/plugins/smpppdcs/unittest/Makefile.am	(revision 586398)
+@@ -0,0 +1,15 @@
++INCLUDES = -I$(top_srcdir)/src $(all_includes) -I../libsmpppdclient
++METASOURCES = AUTO
++
++
++check_PROGRAMS = smpppdcstests
++
++smpppdcstests_SOURCES = main.cpp clienttest.cpp
++smpppdcstests_LDFLAGS = $(KDE_RPATH) $(all_libraries)
++smpppdcstests_LDADD = ../libsmpppdclient/libsmpppdclient.la -lkunittestgui
++
++noinst_HEADERS = clienttest.h
++
++check:
++	kunittest ./smpppdcstests ClientTest
++
+--- kopete/plugins/smpppdcs/detectorsmpppd.h	(revision 568672)
++++ kopete/plugins/smpppdcs/detectorsmpppd.h	(revision 586398)
+@@ -34,14 +34,13 @@
+ 
+     DetectorSMPPPD(const DetectorSMPPPD&);
+     DetectorSMPPPD& operator=(const DetectorSMPPPD&);
+-	
++
+ public:
+     DetectorSMPPPD(IConnector* connector);
+     virtual ~DetectorSMPPPD();
+ 
+-    virtual void checkStatus();
+-	
+-	virtual void smpppdServerChange();
++    virtual void checkStatus() const;
++
+ };
+ 
+ #endif
+--- kopete/plugins/smpppdcs/smpppdlocationwidget.h	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdlocationwidget.h	(revision 586398)
+@@ -0,0 +1,39 @@
++/*
++    smpppdlocationwidget.h
++
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SMPPPDLOCATIONWIDGET_H
++#define SMPPPDLOCATIONWIDGET_H
++
++#include "smpppdlocationui.h"
++
++/**
++	@author Heiko Sch&auml;fer <heiko at rangun.de>
++*/
++class SMPPPDLocationWidget : public SMPPPDLocationWidgetBase
++{
++	Q_OBJECT
++
++	SMPPPDLocationWidget(const SMPPPDLocationWidget&);
++	SMPPPDLocationWidget& operator=(const SMPPPDLocationWidget&);
++
++public:
++    SMPPPDLocationWidget(QWidget* parent = 0, const char* name = 0, WFlags fl = 0);
++    ~SMPPPDLocationWidget();
++
++    void setServer(const QString& serv);
++};
++
++#endif
+--- kopete/plugins/smpppdcs/smpppdcsplugin.cpp	(revision 568672)
++++ kopete/plugins/smpppdcs/smpppdcsplugin.cpp	(revision 586398)
+@@ -22,33 +22,47 @@
+ #include <qtimer.h>
+ 
+ #include <kdebug.h>
+-#include <kconfig.h>
+ #include <kgenericfactory.h>
+ 
+ #include "kopeteprotocol.h"
++#include "networkstatuscommon.h"
+ #include "kopetepluginmanager.h"
+ #include "kopeteaccountmanager.h"
+ 
++#include "detectornetworkstatus.h"
+ #include "detectornetstat.h"
+ #include "detectorsmpppd.h"
++#include "smpppdcsconfig.h"
+ 
+ typedef KGenericFactory<SMPPPDCSPlugin> SMPPPDCSPluginFactory;
+ K_EXPORT_COMPONENT_FACTORY(kopete_smpppdcs, SMPPPDCSPluginFactory("kopete_smpppdcs"))
+ 
+ SMPPPDCSPlugin::SMPPPDCSPlugin(QObject *parent, const char * name, const QStringList& /* args */)
+         : DCOPObject("SMPPPDCSIface"), Kopete::Plugin(SMPPPDCSPluginFactory::instance(), parent, name),
+-        m_detectorSMPPPD(NULL), m_detectorNetstat(NULL), m_timer(NULL),
++        m_detectorSMPPPD(NULL), m_detectorNetstat(NULL), m_detectorNetworkStatus(NULL), m_timer(NULL),
+ m_onlineInquiry(NULL) {
+ 
++    kdDebug(14312) << k_funcinfo << endl;
++
+     m_pluginConnected = false;
+ 
+-    // we wait for the allPluginsLoaded signal, to connect as early as possible after startup
++    m_onlineInquiry   = new OnlineInquiry();
++    m_detectorSMPPPD  = new DetectorSMPPPD(this);
++    m_detectorNetstat = new DetectorNetstat(this);
++
++    // experimental, not used yet
++    m_detectorNetworkStatus = new DetectorNetworkStatus(this);
++
++    // we wait for the allPluginsLoaded signal, to connect
++    // as early as possible after startup, but not before
++    // all accounts are ready
+     connect(Kopete::PluginManager::self(), SIGNAL(allPluginsLoaded()),
+             this, SLOT(allPluginsLoaded()));
+ 
+-    m_onlineInquiry   = new OnlineInquiry();
+-    m_detectorSMPPPD  = new DetectorSMPPPD(this);
+-    m_detectorNetstat = new DetectorNetstat(this);
++    // if kopete was already running and the plugin
++    // was loaded later, we check once after 15 secs
++    // if all other plugins have been loaded
++    QTimer::singleShot(15000, this, SLOT(allPluginsLoaded()));
+ }
+ 
+ SMPPPDCSPlugin::~SMPPPDCSPlugin() {
+@@ -58,30 +72,38 @@
+     delete m_timer;
+     delete m_detectorSMPPPD;
+     delete m_detectorNetstat;
++    delete m_detectorNetworkStatus;
+     delete m_onlineInquiry;
+ }
+ 
+ void SMPPPDCSPlugin::allPluginsLoaded() {
+ 
+-    m_timer = new QTimer();
+-    connect( m_timer, SIGNAL( timeout() ), this, SLOT( slotCheckStatus() ) );
++    if(Kopete::PluginManager::self()->isAllPluginsLoaded()) {
++        m_timer = new QTimer();
++        connect(m_timer, SIGNAL(timeout()), this, SLOT(slotCheckStatus()));
+ 
+-    if(useSmpppd()) {
+-        m_timer->start(30000);
+-    } else {
+-        // we use 1 min interval, because it reflects the old connectionstatus plugin behaviour
+-        m_timer->start(60000);
++		if(SMPPPDCSConfig::self()->useSmpppd()) {
++            m_timer->start(30000);
++        } else {
++            // we use 1 min interval, because it reflects
++            // the old connectionstatus plugin behaviour
++            m_timer->start(60000);
++        }
++
++        slotCheckStatus();
+     }
+-
+-    slotCheckStatus();
+ }
+ 
+-bool SMPPPDCSPlugin::isOnline() {
+-    return m_onlineInquiry->isOnline(useSmpppd());
++bool SMPPPDCSPlugin::isOnline() const {
++	return m_onlineInquiry->isOnline(SMPPPDCSConfig::self()->useSmpppd());
+ }
+ 
+ void SMPPPDCSPlugin::slotCheckStatus() {
+-    if(useSmpppd()) {
++	
++	// reread config to get changes
++	SMPPPDCSConfig::self()->readConfig();
++	
++	if(SMPPPDCSConfig::self()->useSmpppd()) {
+         m_detectorSMPPPD->checkStatus();
+     } else {
+         m_detectorNetstat->checkStatus();
+@@ -114,48 +136,56 @@
+ }
+ 
+ void SMPPPDCSPlugin::connectAllowed() {
+-    static KConfig *config = KGlobal::config();
+-    config->setGroup(SMPPPDCS_CONFIG_GROUP);
+-    QStringList list = config->readListEntry("ignoredAccounts");
+ 
++	QStringList list = SMPPPDCSConfig::self()->ignoredAccounts();
++
+     Kopete::AccountManager * m = Kopete::AccountManager::self();
+     for(QPtrListIterator<Kopete::Account> it(m->accounts())
+             ;
+             it.current();
+             ++it) {
+-        if(!list.contains(it.current()->protocol()->pluginId() + "_" + it.current()->accountId())) {
++
++#ifndef NDEBUG
++        if(it.current()->inherits("Kopete::ManagedConnectionAccount")) {
++            kdDebug(14312) << k_funcinfo << "Account " << it.current()->protocol()->pluginId() + "_" + it.current()->accountId() << " is an managed account!" << endl;
++        } else {
++            kdDebug(14312) << k_funcinfo << "Account " << it.current()->protocol()->pluginId() + "_" + it.current()->accountId() << " is an unmanaged account!" << endl;
++        }
++#endif
++
++        if(!list.contains(it.current()->protocol()->pluginId() + "_" + it.current()->
++                          accountId())) {
+             it.current()->connect();
+         }
+     }
+ }
+ 
+ void SMPPPDCSPlugin::disconnectAllowed() {
+-    static KConfig *config = KGlobal::config();
+-    config->setGroup(SMPPPDCS_CONFIG_GROUP);
+-    QStringList list = config->readListEntry("ignoredAccounts");
+ 
++	QStringList list = SMPPPDCSConfig::self()->ignoredAccounts();
++
+     Kopete::AccountManager * m = Kopete::AccountManager::self();
+     for(QPtrListIterator<Kopete::Account> it(m->accounts())
+             ;
+             it.current();
+             ++it) {
++
++#ifndef NDEBUG
++        if(it.current()->inherits("Kopete::ManagedConnectionAccount")) {
++            kdDebug(14312) << k_funcinfo << "Account " << it.current()->protocol()->pluginId() + "_" + it.current()->accountId() << " is an managed account!" << endl;
++        } else {
++            kdDebug(14312) << k_funcinfo << "Account " << it.current()->protocol()->pluginId() + "_" + it.current()->accountId() << " is an unmanaged account!" << endl;
++        }
++#endif
++
+         if(!list.contains(it.current()->protocol()->pluginId() + "_" + it.current()->accountId())) {
+             it.current()->disconnect();
+         }
+     }
+ }
+ 
+-/*!
+-    \fn SMPPPDCSPlugin::useSmpppd() const
+- */
+-bool SMPPPDCSPlugin::useSmpppd() const {
+-    static KConfig *config = KGlobal::config();
+-    config->setGroup(SMPPPDCS_CONFIG_GROUP);
+-    return config->readBoolEntry("useSmpppd", false);
+-}
+-
+ QString SMPPPDCSPlugin::detectionMethod() const {
+-    if(useSmpppd()) {
++	if(SMPPPDCSConfig::self()->useSmpppd()) {
+         return "smpppd";
+     } else {
+         return "netstat";
+@@ -165,18 +195,27 @@
+ /*!
+     \fn SMPPPDCSPlugin::smpppdServerChanged(const QString& server)
+  */
+-void SMPPPDCSPlugin::smpppdServerChanged(const QString& server)
+-{
+-	static KConfig *config = KGlobal::config();
+-	config->setGroup(SMPPPDCS_CONFIG_GROUP);
+-	QString oldServer = config->readEntry("server", "localhost").utf8();
+-	
+-	if(oldServer != server) {
+-		kdDebug(14312) << k_funcinfo << "Detected a server change" << endl;
+-		m_detectorSMPPPD->smpppdServerChange();
+-	}
++void SMPPPDCSPlugin::smpppdServerChanged(const QString& server) {
++
++	QString oldServer = SMPPPDCSConfig::self()->server().utf8();
++
++    if(oldServer != server) {
++        kdDebug(14312) << k_funcinfo << "Detected a server change" << endl;
++        m_detectorSMPPPD->smpppdServerChange();
++    }
+ }
+ 
++void SMPPPDCSPlugin::aboutToUnload() {
++
++    kdDebug(14312) << k_funcinfo << endl;
++
++    if(m_timer) {
++        m_timer->stop();
++    }
++
++    emit readyForUnload();
++}
++
+ #include "smpppdcsplugin.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/plugins/smpppdcs/detectornetstat.cpp	(revision 568672)
++++ kopete/plugins/smpppdcs/detectornetstat.cpp	(revision 586398)
+@@ -27,7 +27,7 @@
+     delete m_process;
+ }
+ 
+-void DetectorNetstat::checkStatus() {
++void DetectorNetstat::checkStatus() const {
+     kdDebug(14312) << k_funcinfo << endl;
+ 
+     if(m_process) {
+@@ -64,9 +64,10 @@
+ }
+ 
+ void DetectorNetstat::slotProcessExited(KProcess *process) {
++    kdDebug(14312) << k_funcinfo << m_buffer << endl;
+     if(process == m_process) {
+-	m_connector->setConnectedStatus(m_buffer.contains("default"));
+-	m_buffer = QString::null;
++        m_connector->setConnectedStatus(m_buffer.contains("default"));
++        m_buffer = QString::null;
+         delete m_process;
+         m_process = 0L;
+     }
+--- kopete/plugins/smpppdcs/kopete_smpppdcs_config.desktop	(revision 0)
++++ kopete/plugins/smpppdcs/kopete_smpppdcs_config.desktop	(revision 586398)
+@@ -0,0 +1,97 @@
++[Desktop Entry]
++Encoding=UTF-8
++Icon=smpppdcs
++Type=Service
++ServiceTypes=KCModule
++
++X-KDE-ModuleType=Library
++X-KDE-Library=kopete_smpppdcs
++X-KDE-FactoryName=SMPPPDCSConfigFactory
++X-KDE-ParentApp=kopete_smpppdcs
++X-KDE-ParentComponents=kopete_smpppdcs
++
++X-Kopete-Version=1000900
++
++Name=SUSE SMPPPD Connection Status
++Name[bn]=SUSE SMPPPD সংযোগ অবস্থা
++Name[bs]=SUSE SMPPPD status veze
++Name[ca]=Estatus de la connexió SUSE SMPPPD 
++Name[cs]=Stav spojení SUSE SMPPPD
++Name[da]=SUSE SMPPD Forbindelsesstatus
++Name[de]=SuSE SMPPPD-Verbindungsstatus
++Name[el]=Κατάσταση σύνδεσης του SuSE SMPPPD
++Name[es]=Estado de conexión de SUSE SMPPPD
++Name[et]=SUSE SMPPPD ühenduse staatus
++Name[eu]=SUSE SMPPPD konexioaren egoera
++Name[fi]=SUSE SMPPPD -yhteyden tila
++Name[fr]=État de la connexion SUSE SMPPPD
++Name[ga]=Stádas Ceangail SUSE SMPPPD
++Name[gl]=Estado da conexión de SUSE SMPPPD
++Name[he]=מצב החיבור של SUSE SMPPPD
++Name[hu]=SUSE SMPPPD kapcsolati állapot
++Name[is]=SUSE SMPPPD tengingarstaða
++Name[it]=Stato della connessione di SUSE SMPPPD
++Name[ja]=SUSE SMPPPD 接続状態
++Name[km]=ស្ថានភាព​ការ​តភ្ជាប់ SUSE SMPPPD
++Name[lt]=SUSE SMPPPD ryšio būklė
++Name[nb]=Tilstand for SUSE-SMPPPD-forbindelsen
++Name[nds]=SUSE SMPPPD-Verbinnenstatus
++Name[nl]=SUSE SMPPPD-verbindingsstatus
++Name[nn]=Tilstand for SUSE-SMPPPD-sambandet
++Name[pl]=Status połączenia SUSE SMPPPD
++Name[pt]=Estado da Ligação SUSE SMPPPD
++Name[pt_BR]=Status da Conexão SUSE SMPPPD
++Name[ru]=Статус соединения SUSE SMPPPD
++Name[sk]=Stav spojenia SUSE SMPPPD
++Name[sl]=Stanje povezave z uporabo SuSE SMPPPD
++Name[sr]=Статус SUSE-ове SMPPPD везе
++Name[sr at Latn]=Status SUSE-ove SMPPPD veze
++Name[sv]=SUSE SMPPPD anslutningsstatus
++Name[tr]=SUSE SMPPPD bağlantı durumu
++Name[uk]=Стан з'єднання SUSE SMPPPD
++Name[zh_CN]=SUSE SMPPPD 连接状态
++Name[zh_HK]=SUSE SMPPPD 連線狀態
++Name[zh_TW]=SUSE SMPPPD 連線狀態
++Comment=SMPPPDCS Plugin
++Comment[bn]=SMPPPDCS প্লাগিন
++Comment[br]=Lugant SMPPPDCS
++Comment[bs]=SMPPPDCS dodatak
++Comment[ca]=Connector SMPPPDCS
++Comment[cs]=SMPPPDCS modul
++Comment[da]=SMPPPDCS-Plugin
++Comment[de]=SMPPPDCS-Modul
++Comment[el]=Πρόσθετο SMPPPDCS
++Comment[es]=Extensión SMPPPDCS
++Comment[et]=SMPPPDCS plugin
++Comment[eu]=SMPPPDCS plugin-a
++Comment[fi]=SMPPPDCS-liitännäinen
++Comment[fr]=Module SMPPPDCS
++Comment[ga]=Breiseán SMPPPDCS
++Comment[gl]=Plugin SMPPPDCS
++Comment[he]=תוסף SMPPPDCS
++Comment[hu]=SMPPPDCS bővítőmodul
++Comment[is]=SMPPPDCS íforrit
++Comment[it]=Plugin SMPPPDCS
++Comment[ja]=SMPPPDCS プラグイン
++Comment[km]=កម្មវិធី​ជំនួយ SMPPPDCS
++Comment[lt]=SMPPPDCS įskiepis
++Comment[nb]=Programtillegg for SMPPPDCS
++Comment[nds]=SMPPPDCS-Moduul
++Comment[nl]=SMPPPDCS-plugin
++Comment[nn]=Programtillegg for SMPPPDCS
++Comment[pl]=Wtyczka SMPPPDCS
++Comment[pt]='Plugin' SMPPPDCS
++Comment[pt_BR]=Plugin SMPPPDCS
++Comment[ro]=Modul SMPPPDCS
++Comment[ru]=Модуль SMPPPDCS
++Comment[sk]=SMPPPDCS modul
++Comment[sl]=Vstavek SMPPPDCS
++Comment[sr]=Прикључак SMPPPDCS
++Comment[sr at Latn]=Priključak SMPPPDCS
++Comment[sv]=SMPPPDCS-insticksprogram
++Comment[tr]=SMPPPDCS Eklentisi
++Comment[uk]=Втулок SMPPPDCS
++Comment[uz]=SMPPPDCS плагини
++Comment[zh_CN]=SMPPPDCS 插件
++Comment[zh_HK]=SMPPPDCS 插件
++Comment[zh_TW]=SMPPPDCS 外掛程式
+--- kopete/plugins/smpppdcs/detector.h	(revision 568672)
++++ kopete/plugins/smpppdcs/detector.h	(revision 586398)
+@@ -17,10 +17,6 @@
+ #ifndef DETECTOR_H
+ #define DETECTOR_H
+ 
+-#include <qmutex.h>
+-
+-#define SMPPPDCS_CONFIG_GROUP "SMPPPDCS Plugin"
+-
+ class IConnector;
+ 
+ /**
+@@ -52,7 +48,7 @@
+      */
+ 	virtual ~Detector() {}
+ 
+-    virtual void checkStatus() = 0;
++    virtual void checkStatus() const = 0;
+ 	
+ 	virtual void smpppdServerChange() {}
+ 
+--- kopete/plugins/smpppdcs/smpppdcsprefsimpl.h	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcsprefsimpl.h	(revision 586398)
+@@ -0,0 +1,76 @@
++/*
++    smpppdcsprefsimpl.h
++ 
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++ 
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SMPPPDCSPREFSIMPL_H
++#define SMPPPDCSPREFSIMPL_H
++
++#include <qgroupbox.h>
++
++#include <kprogress.h>
++
++#include "smpppdcsprefs.h"
++
++class SMPPPDCSPlugin;
++class SMPPPDSearcher;
++
++/**
++ at author Heiko Sch&auml;fer <heiko at rangun.de>
++*/
++class SMPPPDCSPrefs : public SMPPPDCSPrefsBase 
++{
++	Q_OBJECT
++
++	SMPPPDCSPrefs(const SMPPPDCSPrefs&);
++	SMPPPDCSPrefs& operator=(const SMPPPDCSPrefs&);
++	
++public:
++
++    SMPPPDCSPrefs(QWidget* parent, const char* name = 0, WFlags fl = 0);
++    ~SMPPPDCSPrefs();
++
++signals:
++	void foundSMPPPD(bool found);
++	
++protected slots:
++    void enableSMPPPDSettings();
++    void disableSMPPPDSettings();
++    void determineCSType();
++    void smpppdFound(const QString & host);
++    void smpppdNotFound();
++	void scanStarted(uint total);
++	void scanProgress(uint cur);
++	void scanFinished();
++	void cancelScanning();
++
++private:
++	SMPPPDCSPlugin  * m_plugin;
++	KProgressDialog * m_scanProgressDlg;
++	SMPPPDSearcher  * m_curSearcher;
++};
++
++inline void SMPPPDCSPrefs::enableSMPPPDSettings() {
++	smpppdPrefs->setEnabled(true);
++}
++
++inline void SMPPPDCSPrefs::disableSMPPPDSettings() {
++	smpppdPrefs->setEnabled(false);
++}
++
++inline void SMPPPDCSPrefs::scanFinished() {
++	m_scanProgressDlg->hide();
++}
++
++#endif
+--- kopete/plugins/smpppdcs/smpppdcspreferences.h	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcspreferences.h	(revision 586398)
+@@ -0,0 +1,77 @@
++/*
++    smpppdcspreferences.h
++ 
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++ 
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SMPPPDCSPREFERENCES_H
++#define SMPPPDCSPREFERENCES_H
++
++#include <kcmodule.h>
++
++class QListViewItem;
++
++class SMPPPDCSPrefs;
++
++class AccountPrivMap {
++public:
++	AccountPrivMap(bool isOn = FALSE, const QString& id = QString::null)
++	 : m_on(isOn), m_id(id) {}
++	bool m_on;
++	QString m_id;
++};
++
++/**
++ * @brief Module for the configuration of the smpppdcs-plugin
++ *
++ * @author Heiko Sch&auml;fer <heiko at rangun.de>
++ */
++class SMPPPDCSPreferences : public KCModule {
++    Q_OBJECT
++
++    SMPPPDCSPreferences(const SMPPPDCSPreferences&);
++    SMPPPDCSPreferences& operator=(const SMPPPDCSPreferences&);
++
++public:
++	typedef QMap<QString, AccountPrivMap> AccountMap;
++
++    /**
++     * @brief Creates an <code>SMPPPDCSPreferences</code> instance
++     */
++    SMPPPDCSPreferences(QWidget * parent = 0, const char * name = 0, const QStringList &args = QStringList());
++	
++	/**
++     * @brief Destroys an <code>SMPPPDCSPreferences</code> instance
++     */
++    virtual ~SMPPPDCSPreferences();
++
++	virtual void load();
++	virtual void save();
++	virtual void defaults();
++	
++protected slots:
++	void listClicked(QListViewItem * item);
++
++private slots:
++	void slotModified();
++	
++protected:
++
++	/// The UI class generated by the QT-designer
++    SMPPPDCSPrefs * m_ui;
++	
++	AccountMap m_accountMapOld;
++	AccountMap m_accountMapCur;
++};
++
++#endif
+--- kopete/plugins/smpppdcs/smpppdsearcher.cpp	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdsearcher.cpp	(revision 586398)
+@@ -0,0 +1,189 @@
++/*
++    smpppdsearcher.h
++ 
++    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko at rangun.de>
++ 
++    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qregexp.h>
++#include <qfile.h>
++
++#include <kprocess.h>
++#include <kdebug.h>
++
++#include "smpppdclient.h"
++#include "smpppdsearcher.h"
++
++SMPPPDSearcher::SMPPPDSearcher()
++        : m_cancelSearchNow(FALSE),
++        m_procIfconfig(NULL),
++m_procNetstat(NULL) {}
++
++SMPPPDSearcher::~SMPPPDSearcher() {
++    delete m_procIfconfig;
++    delete m_procNetstat;
++}
++
++/*!
++    \fn SMPPPDSearcher::searchNetwork() const
++ */
++void SMPPPDSearcher::searchNetwork() {
++    kdDebug(14312) << k_funcinfo << endl;
++
++    // the first point to search is localhost
++    if(!scan("127.0.0.1", "255.0.0.0")) {
++
++        m_procNetstat  = new KProcess;
++        m_procNetstat->setEnvironment("LANG", "C"); // we want to force english output
++
++        *m_procNetstat << "/bin/netstat" << "-rn";
++        connect(m_procNetstat, SIGNAL(receivedStdout(KProcess *,char *,int)), this, SLOT(slotStdoutReceivedNetstat(KProcess *,char *,int)));
++        if(!m_procNetstat->start(KProcess::Block, KProcess::Stdout)) {
++            kdDebug(14312) << k_funcinfo << "Couldn't execute /sbin/netstat -rn" << endl << "Perhaps the package net-tools isn't installed." << endl;
++
++            emit smpppdNotFound();
++        }
++
++        delete m_procNetstat;
++        m_procNetstat = NULL;
++    }
++}
++
++/*!
++    \fn SMPPPDSearcher::slotStdoutReceived(KProcess * proc, char * buf, int len)
++ */
++void SMPPPDSearcher::slotStdoutReceivedIfconfig(KProcess * /* proc */, char * buf, int len) {
++    kdDebug(14312) << k_funcinfo << endl;
++
++    QString myBuf = QString::fromLatin1(buf,len);
++    QRegExp rex("^[ ]{10}.*inet addr:([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).*Mask:([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
++    // tokenize the string into lines
++    QStringList toks = QStringList::split("\n", myBuf);
++    for(QStringList::size_type i = 0; i < toks.count(); i++) {
++        if(rex.exactMatch(toks[i])) {
++            if(scan(rex.cap(1), rex.cap(2))) {
++                return;
++            }
++        }
++    }
++
++    emit smpppdNotFound();
++}
++void SMPPPDSearcher::slotStdoutReceivedNetstat(KProcess * /* proc */, char * buf, int len) {
++    kdDebug(14312) << k_funcinfo << endl;
++
++    QRegExp rexGW(".*\\n0.0.0.0[ ]*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).*");
++    QString myBuf = QString::fromLatin1(buf,len);
++
++    if(!(rexGW.exactMatch(myBuf) && scan(rexGW.cap(1), "255.255.255.255"))) {
++        // if netstat -r found no gateway we search the network
++        m_procIfconfig = new KProcess;
++        m_procIfconfig->setEnvironment("LANG", "C"); // we want to force english output
++
++        *m_procIfconfig << "/sbin/ifconfig";
++        connect(m_procIfconfig, SIGNAL(receivedStdout(KProcess *,char *,int)), this, SLOT(slotStdoutReceivedIfconfig(KProcess *,char *,int)));
++        if(!m_procIfconfig->start(KProcess::Block, KProcess::Stdout)) {
++            kdDebug(14312) << k_funcinfo << "Couldn't execute /sbin/ifconfig" << endl << "Perhaps the package net-tools isn't installed." << endl;
++
++            emit smpppdNotFound();
++        }
++
++        delete m_procIfconfig;
++        m_procIfconfig = NULL;
++    }
++}
++
++/*!
++    \fn SMPPPDSearcher::scan() const
++ */
++bool SMPPPDSearcher::scan(const QString& ip, const QString& mask) {
++    kdDebug(14312) << k_funcinfo << "Scanning " << ip << "/" << mask << "..." << endl;
++	
++	SMPPPD::Client client;
++	
++	if(ip == "127.0.0.1") { // if localhost, we only scan this one host
++		if(client.connect(ip, 3185)) {
++			client.disconnect();
++			emit smpppdFound(ip);
++			return true;
++		}
++		
++		return false;
++	}
++
++    uint min_range = 0;
++    uint max_range = 255;
++
++    // calculate ip range (only last mask entry)
++    QRegExp lastRex("([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})");
++    if(lastRex.exactMatch(ip)) {
++
++        uint lastWordIP = lastRex.cap(4).toUInt();
++
++        QStringList ipToks;
++        for(int i = 1; i < 5; i++) {
++            ipToks.push_back(lastRex.cap(i));
++        }
++
++        if(lastRex.exactMatch(mask)) {
++            uint lastWordMask = lastRex.cap(4).toUInt();
++
++            if(lastWordMask == 0) {
++                kdDebug(14312) << k_funcinfo << "IP-Range: " << ipToks[0] << "." << ipToks[1] << "." <<  ipToks[2] << ".0 - " << ipToks[0] << "." << ipToks[1] << "." << ipToks[2] << ".255" << endl;
++                max_range = 255;
++            } else if(lastWordMask == 255) {
++                min_range = max_range = lastWordIP;
++            } else {
++                kdDebug(14312) << k_funcinfo << "IP-Range: " << ipToks[0] << "." << ipToks[1] << "." <<  ipToks[2] << ".0 - " << ipToks[0] << "." << ipToks[1] << "." << ipToks[2] << "." << lastWordMask << endl;
++                max_range = lastWordMask;
++            }
++        }
++
++        uint range = max_range - min_range;
++        m_cancelSearchNow = FALSE;
++        if(range > 1) {
++            emit scanStarted(max_range);
++        }
++        for(uint i = min_range; i <= max_range; i++) {
++            if(m_cancelSearchNow) {
++                if(range > 1) {
++                    emit scanFinished();
++                }
++                break;
++            }
++            if(range > 1) {
++                emit scanProgress(i);
++            }
++			
++			if(client.connect(QString(ipToks[0] + "." + ipToks[1] + "." + ipToks[2] + "." + QString::number(i)), 3185)) {
++				client.disconnect();
++				emit smpppdFound(ip);
++                if(range > 1) {
++                    emit scanFinished();
++                }
++                return true;
++			} 
++#ifndef NDEBUG
++			else {
++				kdDebug(14312) << k_funcinfo << "No smpppd found at " << QString(ipToks[0] + "." + ipToks[1] + "." + ipToks[2] + "." + QString::number(i)) << endl;
++			}
++#endif
++        }
++        if(range > 1) {
++            emit scanFinished();
++        }
++    }
++
++    return false;
++}
++
++#include "smpppdsearcher.moc"
+--- kopete/plugins/smpppdcs/smpppdcsprefs.ui	(revision 0)
++++ kopete/plugins/smpppdcs/smpppdcsprefs.ui	(revision 586398)
+@@ -0,0 +1,284 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>SMPPPDCSPrefsBase</class>
++<author>Heiko Schaefer</author>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>SMPPPDCSPrefsBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>476</width>
++            <height>225</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>SMPPPDCS Preferences</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QTabWidget">
++            <property name="name">
++                <cstring>tabWidget</cstring>
++            </property>
++            <widget class="QWidget">
++                <property name="name">
++                    <cstring>tab</cstring>
++                </property>
++                <attribute name="title">
++                    <string>&amp;Connection</string>
++                </attribute>
++                <vbox>
++                    <property name="name">
++                        <cstring>unnamed</cstring>
++                    </property>
++                    <widget class="QLayoutWidget">
++                        <property name="name">
++                            <cstring>layout4</cstring>
++                        </property>
++                        <vbox>
++                            <property name="name">
++                                <cstring>unnamed</cstring>
++                            </property>
++                            <property name="margin">
++                                <number>6</number>
++                            </property>
++                            <property name="spacing">
++                                <number>6</number>
++                            </property>
++                            <widget class="QButtonGroup">
++                                <property name="name">
++                                    <cstring>csMethod</cstring>
++                                </property>
++                                <property name="title">
++                                    <string>Method of Connection Status Detection</string>
++                                </property>
++                                <vbox>
++                                    <property name="name">
++                                        <cstring>unnamed</cstring>
++                                    </property>
++                                    <property name="margin">
++                                        <number>6</number>
++                                    </property>
++                                    <property name="spacing">
++                                        <number>6</number>
++                                    </property>
++                                    <widget class="QRadioButton">
++                                        <property name="name">
++                                            <cstring>useNetstat</cstring>
++                                        </property>
++                                        <property name="text">
++                                            <string>&amp;netstat - Standard method of connection status detection</string>
++                                        </property>
++                                        <property name="checked">
++                                            <bool>true</bool>
++                                        </property>
++                                        <property name="toolTip" stdset="0">
++                                            <string>Uses the netstat command to find a gateway; suitable on dial-up computers</string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QRadioButton">
++                                        <property name="name">
++                                            <cstring>useSmpppd</cstring>
++                                        </property>
++                                        <property name="text">
++                                            <string>smpppd - Ad&amp;vanced method of connection status detection</string>
++                                        </property>
++                                        <property name="toolTip" stdset="0">
++                                            <string>Uses the smpppd on a gateway; suitable for a computer in a private network</string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QLayoutWidget">
++                                        <property name="name">
++                                            <cstring>autoCSLayout</cstring>
++                                        </property>
++                                        <hbox>
++                                            <property name="name">
++                                                <cstring>unnamed</cstring>
++                                            </property>
++                                            <widget class="KPushButton">
++                                                <property name="name">
++                                                    <cstring>autoCSTest</cstring>
++                                                </property>
++                                                <property name="text">
++                                                    <string>&amp;Try to Detect Automatically</string>
++                                                </property>
++                                                <property name="toolTip" stdset="0">
++                                                    <string>Tries to find an appropriate connection method</string>
++                                                </property>
++                                            </widget>
++                                            <spacer>
++                                                <property name="name">
++                                                    <cstring>spacer4</cstring>
++                                                </property>
++                                                <property name="orientation">
++                                                    <enum>Horizontal</enum>
++                                                </property>
++                                                <property name="sizeType">
++                                                    <enum>Expanding</enum>
++                                                </property>
++                                                <property name="sizeHint">
++                                                    <size>
++                                                        <width>341</width>
++                                                        <height>20</height>
++                                                    </size>
++                                                </property>
++                                            </spacer>
++                                        </hbox>
++                                    </widget>
++                                </vbox>
++                            </widget>
++                            <widget class="QGroupBox">
++                                <property name="name">
++                                    <cstring>smpppdPrefs</cstring>
++                                </property>
++                                <property name="enabled">
++                                    <bool>false</bool>
++                                </property>
++                                <property name="title">
++                                    <string>Location of the SMPPPD</string>
++                                </property>
++                                <vbox>
++                                    <property name="name">
++                                        <cstring>unnamed</cstring>
++                                    </property>
++                                    <property name="margin">
++                                        <number>6</number>
++                                    </property>
++                                    <property name="spacing">
++                                        <number>6</number>
++                                    </property>
++                                    <widget class="SMPPPDLocationWidget">
++                                        <property name="name">
++                                            <cstring>SMPPPDLocation</cstring>
++                                        </property>
++                                    </widget>
++                                </vbox>
++                            </widget>
++                            <spacer>
++                                <property name="name">
++                                    <cstring>spacer18</cstring>
++                                </property>
++                                <property name="orientation">
++                                    <enum>Vertical</enum>
++                                </property>
++                                <property name="sizeType">
++                                    <enum>Expanding</enum>
++                                </property>
++                                <property name="sizeHint">
++                                    <size>
++                                        <width>20</width>
++                                        <height>20</height>
++                                    </size>
++                                </property>
++                            </spacer>
++                        </vbox>
++                    </widget>
++                </vbox>
++            </widget>
++            <widget class="QWidget">
++                <property name="name">
++                    <cstring>tab</cstring>
++                </property>
++                <attribute name="title">
++                    <string>Acco&amp;unts</string>
++                </attribute>
++                <vbox>
++                    <property name="name">
++                        <cstring>unnamed</cstring>
++                    </property>
++                    <property name="spacing">
++                        <number>6</number>
++                    </property>
++                    <spacer>
++                        <property name="name">
++                            <cstring>spacer4_2</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Fixed</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>20</width>
++                                <height>6</height>
++                            </size>
++                        </property>
++                    </spacer>
++                    <widget class="QLabel">
++                        <property name="name">
++                            <cstring>toIgnoreLabel</cstring>
++                        </property>
++                        <property name="text">
++                            <string>Choose the accounts to ignore:</string>
++                        </property>
++                    </widget>
++                    <widget class="KListView">
++                        <column>
++                            <property name="text">
++                                <string>Account</string>
++                            </property>
++                            <property name="clickable">
++                                <bool>true</bool>
++                            </property>
++                            <property name="resizable">
++                                <bool>false</bool>
++                            </property>
++                        </column>
++                        <property name="name">
++                            <cstring>accountList</cstring>
++                        </property>
++                        <property name="allColumnsShowFocus">
++                            <bool>true</bool>
++                        </property>
++                        <property name="resizeMode">
++                            <enum>LastColumn</enum>
++                        </property>
++                    </widget>
++                </vbox>
++            </widget>
++        </widget>
++    </vbox>
++</widget>
++<customwidgets>
++    <customwidget>
++        <class>SMPPPDLocationWidget</class>
++	<header location="local">smpppdlocationwidget.h</header>
++        <sizehint>
++            <width>16</width>
++            <height>16</height>
++        </sizehint>
++        <container>1</container>
++        <sizepolicy>
++            <hordata>5</hordata>
++            <verdata>5</verdata>
++            <horstretch>0</horstretch>
++            <verstretch>0</verstretch>
++        </sizepolicy>
++        <pixmap>image0</pixmap>
++    </customwidget>
++</customwidgets>
++<images>
++    <image name="image0">
++        <data format="PNG" length="1125">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082</data>
++    </image>
++</images>
++<tabstops>
++    <tabstop>tabWidget</tabstop>
++    <tabstop>useNetstat</tabstop>
++    <tabstop>autoCSTest</tabstop>
++    <tabstop>useSmpppd</tabstop>
++    <tabstop>accountList</tabstop>
++</tabstops>
++<layoutdefaults spacing="0" margin="0"/>
++<includehints>
++    <includehint>kpushbutton.h</includehint>
++    <includehint>smpppdlocationwidget.h</includehint>
++    <includehint>klistview.h</includehint>
++</includehints>
++</UI>
+--- kopete/plugins/smpppdcs/detectordcop.h	(revision 568672)
++++ kopete/plugins/smpppdcs/detectordcop.h	(revision 586398)
+@@ -19,7 +19,6 @@
+ 
+ #include "detector.h"
+ 
+-class DCOPClient;
+ class IConnector;
+ 
+ /**
+@@ -42,12 +41,11 @@
+         ERROR
+     };
+ 
+-    QCString getKInternetDCOP();
+-    KInternetDCOPState getConnectionStatusDCOP();
++    QCString getKInternetDCOP() const;
++    KInternetDCOPState getConnectionStatusDCOP() const;
+ 
+ protected:
+-    static QCString  m_kinternetApp;
+-    DCOPClient     * m_client;
++    static QCString m_kinternetApp;
+ };
+ 
+ #endif
+--- kopete/plugins/smpppdcs/Makefile.am	(revision 568672)
++++ kopete/plugins/smpppdcs/Makefile.am	(revision 586398)
+@@ -1,25 +1,35 @@
+-if include_smpppdcs
+-SMPPPDCS_SUBDIR=config
+-endif
+-
+ METASOURCES = AUTO
+ 
+-SUBDIRS = icons libsmpppdclient $(SMPPPDCS_SUBDIR)
++SUBDIRS = icons libsmpppdclient unittest
+ 
+ EXTRA_DIST = Changelog.smpppdcs
+ 
+ AM_CPPFLAGS = $(KOPETE_INCLUDES) $(all_includes) -Ilibsmpppdclient
+ 
+-kde_module_LTLIBRARIES = kopete_smpppdcs.la
++kde_module_LTLIBRARIES = kopete_smpppdcs.la kcm_kopete_smpppdcs.la
+ 
+-kopete_smpppdcs_la_SOURCES = smpppdcsplugin.cpp onlineinquiry.cpp \
+-	smpppdcsiface.skel detectordcop.cpp detectorsmpppd.cpp detectornetstat.cpp
++kopete_smpppdcs_la_SOURCES = kinternetiface.stub smpppdcsplugin.cpp \
++	onlineinquiry.cpp 	smpppdcsiface.skel detectordcop.cpp detectorsmpppd.cpp \
++	detectornetstat.cpp detectornetworkstatus.cpp smpppdcsconfig.kcfgc
+ kopete_smpppdcs_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+ kopete_smpppdcs_la_LIBADD = \
+ 	libsmpppdclient/libsmpppdclient.la ../../libkopete/libkopete.la
+ 
++kcm_kopete_smpppdcs_la_SOURCES = smpppdcsprefs.ui smpppdcspreferences.cpp \
++	smpppdsearcher.cpp smpppdcsprefsimpl.cpp smpppdlocationui.ui smpppdlocationwidget.cpp \
++	smpppdcsconfig.kcfgc
++kcm_kopete_smpppdcs_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries)
++kcm_kopete_smpppdcs_la_LIBADD  = libsmpppdclient/libsmpppdclient.la \
++	../../libkopete/libkopete.la $(LIB_KUTILS)
++
+ service_DATA = kopete_smpppdcs.desktop
+ servicedir = $(kde_servicesdir)
+ 
++kcm_DATA = kopete_smpppdcs_config.desktop
++kcmdir = $(kde_servicesdir)/kconfiguredialog
++
++kde_kcfg_DATA = smpppdcs.kcfg
++
+ noinst_HEADERS = smpppdcsiface.h detectordcop.h detectorsmpppd.h \
+-	detectornetstat.h
++		detectornetstat.h kinternetiface.h detectornetworkstatus.h \
++		smpppdsearcher.h smpppdcsprefsimpl.h smpppdlocationwidget.h
+--- kopete/plugins/smpppdcs/detectornetworkstatus.h	(revision 0)
++++ kopete/plugins/smpppdcs/detectornetworkstatus.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++	detectornetworkstatus.h
++
++	Copyright (c) 2006      by Heiko Schaefer        <heiko at rangun.de>
++
++	Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#ifndef DETECTORNETWORKSTATUS_H
++#define DETECTORNETWORKSTATUS_H
++
++#include <qobject.h>
++
++#include "detector.h"
++
++class IConnector;
++class ConnectionManager;
++
++/**
++	@author Heiko Sch&auml;fer <heiko at rangun.de>
++*/
++class DetectorNetworkStatus : protected QObject, public Detector
++{
++	Q_OBJECT
++	
++	DetectorNetworkStatus(const DetectorNetworkStatus&);
++	DetectorNetworkStatus& operator=(const DetectorNetworkStatus&);
++
++public:
++    DetectorNetworkStatus(IConnector* connector);
++    virtual ~DetectorNetworkStatus();
++	
++	virtual void checkStatus() const;
++
++protected slots:
++	void statusChanged(const QString& host, NetworkStatus::EnumStatus status);
++	
++private:
++	ConnectionManager * m_connManager;
++};
++
++#endif
+--- kopete/plugins/smpppdcs/detectorsmpppd.cpp	(revision 568672)
++++ kopete/plugins/smpppdcs/detectorsmpppd.cpp	(revision 586398)
+@@ -17,54 +17,55 @@
+ #include <kdebug.h>
+ #include <kglobal.h>
+ #include <kconfig.h>
++#include <kapplication.h>
+ 
+ #include "iconnector.h"
+ #include "detectorsmpppd.h"
++#include "smpppdcsconfig.h"
+ 
+ #include "smpppdclient.h"
+ 
+ DetectorSMPPPD::DetectorSMPPPD(IConnector * connector)
+-	: DetectorDCOP(connector) {}
++        : DetectorDCOP(connector) {}
+ 
+ DetectorSMPPPD::~DetectorSMPPPD() {}
+ 
+ /*!
+     \fn DetectorSMPPPD::checkStatus()
+  */
+-void DetectorSMPPPD::checkStatus() {
++void DetectorSMPPPD::checkStatus() const {
+     kdDebug(14312) << k_funcinfo << "Checking for online status..." << endl;
+ 
+-	m_kinternetApp = getKInternetDCOP();
+-	if(m_client && m_kinternetApp != "") {
+-		switch(getConnectionStatusDCOP()) {
+-			case CONNECTED:
+-				m_connector->setConnectedStatus(true);
+-				return;
+-			case DISCONNECTED:
+-				m_connector->setConnectedStatus(false);
+-				return;
+-			default:
+-				break;
+-		}
+-	}
+-	
+-	SMPPPD::Client c;
+-	
+-	static KConfig *config = KGlobal::config();
+-	config->setGroup(SMPPPDCS_CONFIG_GROUP);
+-	unsigned int port = config->readUnsignedNumEntry("port", 3185);
+-	QString    server = config->readEntry("server", "localhost").utf8();
+-	
+-	c.setPassword(config->readEntry("Password", "").utf8());
+-	
+-	if(c.connect(server, port)) {
+-		m_connector->setConnectedStatus(c.isOnline());
+-	} else {
+-		kdDebug(14312) << k_funcinfo << "not connected to smpppd => I'll try again later" << endl;
+-		m_connector->setConnectedStatus(false);
+-	}
+-}
++#ifndef NOKINTERNETDCOP
++    m_kinternetApp = getKInternetDCOP();
++    if(kapp->dcopClient() && m_kinternetApp != "") {
++        switch(getConnectionStatusDCOP()) {
++        case CONNECTED:
++            m_connector->setConnectedStatus(true);
++            return;
++        case DISCONNECTED:
++            m_connector->setConnectedStatus(false);
++            return;
++        default:
++            break;
++        }
++    }
++#else
++#warning DCOP inquiry disabled
++	kdDebug(14312) << k_funcinfo << "DCOP inquiry disabled" << endl;
++#endif
+ 
+-void DetectorSMPPPD::smpppdServerChange() {
+-    kdDebug(14312) << k_funcinfo << "Server changed. Disconnect to SMPPPD" << endl;
++    SMPPPD::Client c;
++
++	unsigned int port = SMPPPDCSConfig::self()->port();
++	QString    server = SMPPPDCSConfig::self()->server();
++
++	c.setPassword(SMPPPDCSConfig::self()->password().utf8());
++
++    if(c.connect(server, port)) {
++        m_connector->setConnectedStatus(c.isOnline());
++    } else {
++        kdDebug(14312) << k_funcinfo << "not connected to smpppd => I'll try again later" << endl;
++        m_connector->setConnectedStatus(false);
++    }
+ }
+--- kopete/plugins/statistics/statisticsplugin.cpp	(revision 568672)
++++ kopete/plugins/statistics/statisticsplugin.cpp	(revision 586398)
+@@ -16,6 +16,7 @@
+ 
+ #include <qfile.h>
+ #include <qdict.h>
++#include <qtimer.h>
+ 
+ #include <kgenericfactory.h>
+ #include <kaboutdata.h>
+@@ -70,6 +71,13 @@
+ 
+ 	setXMLFile("statisticsui.rc");
+ 
++	/* Initialization reads the database, so it could be a bit time-consuming
++	due to disk access. This should overcome the problem and makes it non-blocking. */
++	QTimer::singleShot(0, this, SLOT(slotInitialize()));
++}	
++
++void StatisticsPlugin::slotInitialize()
++{
+ 	// Initializes the database
+ 	m_db = new StatisticsDB();
+ 	
+@@ -79,7 +87,7 @@
+ 	{
+ 		slotMetaContactAdded(it.current());
+ 	}
+-}	
++}
+ 
+ StatisticsPlugin::~StatisticsPlugin()
+ {
+--- kopete/plugins/statistics/statisticsplugin.h	(revision 568672)
++++ kopete/plugins/statistics/statisticsplugin.h	(revision 586398)
+@@ -106,7 +106,10 @@
+ 	
+ 	/// Method to access m_db member
+ 	StatisticsDB *db() { return m_db; }
+-		
++private slots:
++	// Do the initializations
++	void slotInitialize();
++
+ public slots:
+ 	
+ 	/** \brief This slot is called when the status of a contact changed.
+--- kopete/plugins/netmeeting/kopete_netmeeting_config.desktop	(revision 568672)
++++ kopete/plugins/netmeeting/kopete_netmeeting_config.desktop	(revision 586398)
+@@ -40,6 +40,7 @@
+ 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
+--- kopete/plugins/netmeeting/kopete_netmeeting.desktop	(revision 568672)
++++ kopete/plugins/netmeeting/kopete_netmeeting.desktop	(revision 586398)
+@@ -44,6 +44,7 @@
+ 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
+--- kopete/plugins/history/historyviewer.ui	(revision 568672)
++++ kopete/plugins/history/historyviewer.ui	(revision 586398)
+@@ -30,7 +30,7 @@
+         <property name="name">
+             <cstring>unnamed</cstring>
+         </property>
+-        <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
++        <widget class="QLayoutWidget" row="3" column="0">
+             <property name="name">
+                 <cstring>layout3</cstring>
+             </property>
+@@ -59,47 +59,8 @@
+                 </widget>
+             </hbox>
+         </widget>
+-        <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
++        <widget class="QLayoutWidget" row="2" column="0">
+             <property name="name">
+-                <cstring>layout6</cstring>
+-            </property>
+-            <hbox>
+-                <property name="name">
+-                    <cstring>unnamed</cstring>
+-                </property>
+-                <widget class="QLabel">
+-                    <property name="name">
+-                        <cstring>textLabel1</cstring>
+-                    </property>
+-                    <property name="sizePolicy">
+-                        <sizepolicy>
+-                            <hsizetype>1</hsizetype>
+-                            <vsizetype>5</vsizetype>
+-                            <horstretch>0</horstretch>
+-                            <verstretch>0</verstretch>
+-                        </sizepolicy>
+-                    </property>
+-                    <property name="text">
+-                        <string>Contact:</string>
+-                    </property>
+-                </widget>
+-                <widget class="KComboBox">
+-                    <property name="name">
+-                        <cstring>contactComboBox</cstring>
+-                    </property>
+-                    <property name="sizePolicy">
+-                        <sizepolicy>
+-                            <hsizetype>7</hsizetype>
+-                            <vsizetype>0</vsizetype>
+-                            <horstretch>0</horstretch>
+-                            <verstretch>0</verstretch>
+-                        </sizepolicy>
+-                    </property>
+-                </widget>
+-            </hbox>
+-        </widget>
+-        <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="2">
+-            <property name="name">
+                 <cstring>layout8</cstring>
+             </property>
+             <hbox>
+@@ -158,95 +119,212 @@
+                         </size>
+                     </property>
+                     <property name="text">
+-                        <string>&amp;Search</string>
++                        <string>Se&amp;arch</string>
+                     </property>
+                 </widget>
+             </hbox>
+         </widget>
+-        <widget class="QFrame" row="1" column="1" rowspan="2" colspan="1">
++        <widget class="QSplitter" row="1" column="0">
+             <property name="name">
+-                <cstring>htmlFrame</cstring>
++                <cstring>splitter2</cstring>
+             </property>
+-            <property name="sizePolicy">
+-                <sizepolicy>
+-                    <hsizetype>7</hsizetype>
+-                    <vsizetype>5</vsizetype>
+-                    <horstretch>0</horstretch>
+-                    <verstretch>0</verstretch>
+-                </sizepolicy>
++            <property name="orientation">
++                <enum>Horizontal</enum>
+             </property>
+-            <property name="minimumSize">
+-                <size>
+-                    <width>0</width>
+-                    <height>0</height>
+-                </size>
+-            </property>
+-            <property name="frameShape">
+-                <enum>WinPanel</enum>
+-            </property>
+-            <property name="frameShadow">
+-                <enum>Sunken</enum>
+-            </property>
+-        </widget>
+-        <widget class="KListView" row="2" column="0">
+-            <column>
+-                <property name="text">
+-                    <string>Date</string>
++            <widget class="QLayoutWidget">
++                <property name="name">
++                    <cstring>layout5</cstring>
+                 </property>
+-                <property name="clickable">
+-                    <bool>true</bool>
++                <vbox>
++                    <property name="name">
++                        <cstring>unnamed</cstring>
++                    </property>
++                    <widget class="KListViewSearchLine">
++                        <property name="name">
++                            <cstring>dateSearchLine</cstring>
++                        </property>
++                        <property name="enabled">
++                            <bool>true</bool>
++                        </property>
++                        <property name="sizePolicy">
++                            <sizepolicy>
++                                <hsizetype>5</hsizetype>
++                                <vsizetype>0</vsizetype>
++                                <horstretch>0</horstretch>
++                                <verstretch>0</verstretch>
++                            </sizepolicy>
++                        </property>
++                        <property name="minimumSize">
++                            <size>
++                                <width>140</width>
++                                <height>0</height>
++                            </size>
++                        </property>
++                        <property name="maximumSize">
++                            <size>
++                                <width>32767</width>
++                                <height>32767</height>
++                            </size>
++                        </property>
++                    </widget>
++                    <widget class="KListView">
++                        <column>
++                            <property name="text">
++                                <string>Date</string>
++                            </property>
++                            <property name="clickable">
++                                <bool>true</bool>
++                            </property>
++                            <property name="resizable">
++                                <bool>true</bool>
++                            </property>
++                        </column>
++                        <column>
++                            <property name="text">
++                                <string>Contact</string>
++                            </property>
++                            <property name="clickable">
++                                <bool>true</bool>
++                            </property>
++                            <property name="resizable">
++                                <bool>true</bool>
++                            </property>
++                        </column>
++                        <property name="name">
++                            <cstring>dateListView</cstring>
++                        </property>
++                        <property name="sizePolicy">
++                            <sizepolicy>
++                                <hsizetype>5</hsizetype>
++                                <vsizetype>7</vsizetype>
++                                <horstretch>0</horstretch>
++                                <verstretch>0</verstretch>
++                            </sizepolicy>
++                        </property>
++                        <property name="minimumSize">
++                            <size>
++                                <width>0</width>
++                                <height>0</height>
++                            </size>
++                        </property>
++                        <property name="maximumSize">
++                            <size>
++                                <width>32767</width>
++                                <height>32767</height>
++                            </size>
++                        </property>
++                        <property name="rootIsDecorated">
++                            <bool>false</bool>
++                        </property>
++                    </widget>
++                </vbox>
++            </widget>
++            <widget class="QFrame">
++                <property name="name">
++                    <cstring>htmlFrame</cstring>
+                 </property>
+-                <property name="resizable">
+-                    <bool>true</bool>
++                <property name="sizePolicy">
++                    <sizepolicy>
++                        <hsizetype>5</hsizetype>
++                        <vsizetype>5</vsizetype>
++                        <horstretch>10</horstretch>
++                        <verstretch>0</verstretch>
++                    </sizepolicy>
+                 </property>
+-            </column>
+-            <column>
+-                <property name="text">
+-                    <string>Contact</string>
++                <property name="minimumSize">
++                    <size>
++                        <width>0</width>
++                        <height>0</height>
++                    </size>
+                 </property>
+-                <property name="clickable">
+-                    <bool>true</bool>
++                <property name="frameShape">
++                    <enum>WinPanel</enum>
+                 </property>
+-                <property name="resizable">
+-                    <bool>true</bool>
++                <property name="frameShadow">
++                    <enum>Sunken</enum>
+                 </property>
+-            </column>
+-            <property name="name">
+-                <cstring>dateListView</cstring>
+-            </property>
+-            <property name="sizePolicy">
+-                <sizepolicy>
+-                    <hsizetype>5</hsizetype>
+-                    <vsizetype>7</vsizetype>
+-                    <horstretch>0</horstretch>
+-                    <verstretch>0</verstretch>
+-                </sizepolicy>
+-            </property>
+-            <property name="minimumSize">
+-                <size>
+-                    <width>0</width>
+-                    <height>0</height>
+-                </size>
+-            </property>
+-            <property name="rootIsDecorated">
+-                <bool>false</bool>
+-            </property>
++            </widget>
+         </widget>
+-        <widget class="KListViewSearchLine" row="1" column="0">
++        <widget class="QLayoutWidget" row="0" column="0">
+             <property name="name">
+-                <cstring>dateSearchLine</cstring>
++                <cstring>layout11</cstring>
+             </property>
+-            <property name="enabled">
+-                <bool>true</bool>
+-            </property>
+-            <property name="sizePolicy">
+-                <sizepolicy>
+-                    <hsizetype>1</hsizetype>
+-                    <vsizetype>0</vsizetype>
+-                    <horstretch>0</horstretch>
+-                    <verstretch>0</verstretch>
+-                </sizepolicy>
+-            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>1</hsizetype>
++                            <vsizetype>5</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="text">
++                        <string>Contact:</string>
++                    </property>
++                </widget>
++                <widget class="KComboBox">
++                    <property name="name">
++                        <cstring>contactComboBox</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                </widget>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>textLabel1_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Message Filter:</string>
++                    </property>
++                </widget>
++                <widget class="QComboBox">
++                    <item>
++                        <property name="text">
++                            <string>All messages</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>Only incoming</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>Only outgoing</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>messageFilterBox</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>0</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="minimumSize">
++                        <size>
++                            <width>200</width>
++                            <height>0</height>
++                        </size>
++                    </property>
++                </widget>
++            </hbox>
+         </widget>
+     </grid>
+ </widget>
+@@ -255,9 +333,9 @@
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
+     <includehint>kprogress.h</includehint>
+-    <includehint>kcombobox.h</includehint>
+     <includehint>klineedit.h</includehint>
++    <includehint>klistviewsearchline.h</includehint>
+     <includehint>klistview.h</includehint>
+-    <includehint>klistviewsearchline.h</includehint>
++    <includehint>kcombobox.h</includehint>
+ </includehints>
+ </UI>
+--- kopete/plugins/history/historydialog.cpp	(revision 568672)
++++ kopete/plugins/history/historydialog.cpp	(revision 586398)
+@@ -20,10 +20,10 @@
+ #include "historylogger.h"
+ #include "historyviewer.h"
+ #include "kopetemetacontact.h"
+-#include "kopetexsl.h"
+ #include "kopeteprotocol.h"
+ #include "kopeteaccount.h"
+ #include "kopetecontactlist.h"
++#include "kopeteprefs.h"
+ 
+ #include <dom/dom_doc.h>
+ #include <dom/dom_element.h>
+@@ -40,6 +40,7 @@
+ #include <qdatetime.h>
+ #include <qheader.h>
+ #include <qlabel.h>
++#include <qclipboard.h>
+ 
+ #include <kapplication.h>
+ #include <kdebug.h>
+@@ -52,6 +53,9 @@
+ #include <kprogress.h>
+ #include <kiconloader.h>
+ #include <kcombobox.h>
++#include <kpopupmenu.h>
++#include <kstdaction.h>
++#include <kaction.h>
+ 
+ class KListViewDateItem : public KListViewItem
+ {
+@@ -70,7 +74,7 @@
+ 
+ 
+ KListViewDateItem::KListViewDateItem(KListView* parent, QDate date, Kopete::MetaContact *mc)
+-		: KListViewItem(parent, date.toString(Qt::LocalDate), mc->displayName())
++		: KListViewItem(parent, date.toString(Qt::ISODate), mc->displayName())
+ {
+ 	mDate = date;
+ 	mMetaContact = mc;
+@@ -78,15 +82,14 @@
+ 
+ int KListViewDateItem::compare(QListViewItem *i, int col, bool ascending) const
+ {
+-	if (col) return QListViewItem::compare(i, col, ascending);
++	if (col) 
++		return QListViewItem::compare(i, col, ascending);
+ 
++	//compare dates - do NOT use ascending var here
+ 	KListViewDateItem* item = static_cast<KListViewDateItem*>(i);
+-	if (item->date() > mDate)
+-		return ascending ? -1 : 1;
+-	else if (item->date() < mDate)
+-		return ascending ? 1 : -1;
+-	
+-	return 0;
++	if ( mDate < item->date() )
++		return -1;
++	return ( mDate > item->date() );
+ }
+ 
+ 
+@@ -94,6 +97,10 @@
+ 	const char* name) : KDialogBase(parent, name, false,
+ 		i18n("History for %1").arg(mc->displayName()), 0)
+ {
++	QString fontSize;
++	QString htmlCode;
++	QString fontStyle;
++
+ 	kdDebug(14310) << k_funcinfo << "called." << endl;
+ 	setWFlags(Qt::WDestructiveClose);	// send SIGNAL(closing()) on quit
+ 
+@@ -108,7 +115,8 @@
+ 
+ 	// Widgets initializations
+ 	mMainWidget = new HistoryViewer(this, "HistoryDialog::mMainWidget");
+-	mMainWidget->searchLine->setFocus();
++	mMainWidget->searchLine->setFocus(); 
++	mMainWidget->searchLine->setTrapReturnKey (true);
+ 	mMainWidget->searchLine->setTrapReturnKey(true);
+ 	mMainWidget->searchErase->setPixmap(BarIcon("locationbar_erase"));
+ 
+@@ -124,6 +132,7 @@
+ 		mMainWidget->contactComboBox->setCurrentItem(mMetaContactList.find(mMetaContact)+1);
+ 
+ 	mMainWidget->dateSearchLine->setListView(mMainWidget->dateListView);
++	mMainWidget->dateListView->setSorting(0, 0); //newest-first
+ 
+ 	setMainWidget(mMainWidget);
+ 
+@@ -146,8 +155,12 @@
+ 	QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ 	l->addWidget(mHtmlView);
+ 
++	QTextOStream( &fontSize ) << KopetePrefs::prefs()->fontFace().pointSize();
++	fontStyle = "<style>.hf { font-size:" + fontSize + ".0pt; font-family:" + KopetePrefs::prefs()->fontFace().family() + "; color: " + KopetePrefs::prefs()->textColor().name() + "; }</style>";
++
+ 	mHtmlPart->begin();
+-	mHtmlPart->write( QString::fromLatin1( "<html><head></head><body></body></html>") );
++	htmlCode = "<html><head>" + fontStyle + "</head><body class=\"hf\"></body></html>";
++	mHtmlPart->write( QString::fromLatin1( htmlCode.latin1() ) );
+ 	mHtmlPart->end();
+ 
+ 	
+@@ -159,7 +172,14 @@
+ 	connect(mMainWidget->searchLine, SIGNAL(textChanged(const QString&)), this, SLOT(slotSearchTextChanged(const QString&)));
+ 	connect(mMainWidget->searchErase, SIGNAL(clicked()), this, SLOT(slotSearchErase()));
+ 	connect(mMainWidget->contactComboBox, SIGNAL(activated(int)), this, SLOT(slotContactChanged(int)));
++	connect(mMainWidget->messageFilterBox, SIGNAL(activated(int)), this, SLOT(slotFilterChanged(int )));
++	connect(mHtmlPart, SIGNAL(popupMenu(const QString &, const QPoint &)), this, SLOT(slotRightClick(const QString &, const QPoint &)));
+ 
++	//initActions
++	KActionCollection* ac = new KActionCollection(this);
++	mCopyAct = KStdAction::copy( this, SLOT(slotCopy()), ac );
++	mCopyURLAct = new KAction( i18n( "Copy Link Address" ), QString::fromLatin1( "editcopy" ), 0, this, SLOT( slotCopyURL() ), ac );
++
+ 	resize(650, 700);
+ 	centerOnScreen(this);
+ 
+@@ -345,39 +365,49 @@
+ 	// Populating HTML Part with messages
+ 	for ( it = msgs.begin(); it != msgs.end(); ++it )
+ 	{
+-		resultHTML = "";
+-
+-		if (accountLabel.isEmpty() || accountLabel != (*it).from()->account()->accountLabel())
+-		// If the message's account is new, just specify it to the user
++		if ( mMainWidget->messageFilterBox->currentItem() == 0
++			|| ( mMainWidget->messageFilterBox->currentItem() == 1 && (*it).direction() == Kopete::Message::Inbound )
++			|| ( mMainWidget->messageFilterBox->currentItem() == 2 && (*it).direction() == Kopete::Message::Outbound ) )
+ 		{
+-			if (!accountLabel.isEmpty())
+-				resultHTML += "<br/><br/><br/>";
+-			resultHTML += "<b><font color=\"blue\">" + (*it).from()->account()->accountLabel() + "</font></b><br/>";
++			resultHTML = "";
++	
++			if (accountLabel.isEmpty() || accountLabel != (*it).from()->account()->accountLabel())
++			// If the message's account is new, just specify it to the user
++			{
++				if (!accountLabel.isEmpty())
++					resultHTML += "<br/><br/><br/>";
++				resultHTML += "<b><font color=\"blue\">" + (*it).from()->account()->accountLabel() + "</font></b><br/>";
++			}
++			accountLabel = (*it).from()->account()->accountLabel();
++	
++			QString body = (*it).parsedBody();
++	
++			if (!mMainWidget->searchLine->text().isEmpty())
++			// If there is a search, then we hightlight the keywords
++			{
++				body = body.replace(mMainWidget->searchLine->text(), "<span style=\"background-color:yellow\">" + mMainWidget->searchLine->text() + "</span>", false);
++			}
++		
++			resultHTML += "(<b>" + (*it).timestamp().time().toString() + "</b>) "
++					+ ((*it).direction() == Kopete::Message::Outbound ?
++									"<font color=\"" + KopetePrefs::prefs()->textColor().dark().name() + "\"><b>&gt;</b></font> "
++									: "<font color=\"" + KopetePrefs::prefs()->textColor().light(200).name() + "\"><b>&lt;</b></font> ")
++					+ body + "<br/>";
++	
++			newNode = mHtmlPart->document().createElement(QString::fromLatin1("span"));
++			newNode.setAttribute(QString::fromLatin1("dir"), dir);
++			newNode.setInnerHTML(resultHTML);
++	
++			mHtmlPart->htmlDocument().body().appendChild(newNode);
+ 		}
+-		accountLabel = (*it).from()->account()->accountLabel();
+-
+-		QString body = (*it).parsedBody();
+-
+-		if (!mMainWidget->searchLine->text().isEmpty())
+-		// If there is a search, then we hightlight the keywords
+-		{
+-			body = body.replace(mMainWidget->searchLine->text(), "<span style=\"background-color:yellow\">" + mMainWidget->searchLine->text() + "</span>", false);
+-		}
+-	
+-		resultHTML += "(<b>" + (*it).timestamp().time().toString() + "</b>) "
+-				   + ((*it).direction() == Kopete::Message::Outbound ?
+-								"<font color=\"navy\"><b>&gt;</b></font> "
+-								: "<font color=\"orange\"><b>&lt;</b></font> ")
+-				   + body + "<br/>";
+-
+-		newNode = mHtmlPart->document().createElement(QString::fromLatin1("span"));
+-		newNode.setAttribute(QString::fromLatin1("dir"), dir);
+-		newNode.setInnerHTML(resultHTML);
+-
+-		mHtmlPart->htmlDocument().body().appendChild(newNode);
+ 	}
+ }
+ 
++void HistoryDialog::slotFilterChanged(int index)
++{
++	dateSelected(mMainWidget->dateListView->currentItem());
++}
++
+ void HistoryDialog::slotOpenURLRequest(const KURL &url, const KParts::URLArgs &/*args*/)
+ {
+ 	kdDebug(14310) << k_funcinfo << "url=" << url.url() << endl;
+@@ -527,7 +557,7 @@
+ 			if (mSearch->dateSearchMap[mSearch->item->date()].contains(mSearch->item->metaContact()))
+ 				mSearch->item->setVisible(true);
+ 		}
+-		while((mSearch->item = static_cast<KListViewDateItem *>(mSearch->item->nextSibling())));
++		while(mSearch->item = static_cast<KListViewDateItem *>(mSearch->item->nextSibling()));
+ 		mMainWidget->searchButton->setText(i18n("&Search"));
+ 
+ 		delete mSearch;
+@@ -544,12 +574,14 @@
+ 	mMainWidget->dateListView->clear();
+ 	if (index == 0)
+ 	{
+-		mMetaContact = 0;
++        setCaption(i18n("History for All Contacts"));
++        mMetaContact = 0;
+ 		init();
+ 	}
+ 	else
+ 	{
+ 		mMetaContact = mMetaContactList.at(index-1);
++        setCaption(i18n("History for %1").arg(mMetaContact->displayName()));
+ 		init();
+ 	}
+ }
+@@ -568,4 +600,42 @@
+ 		mMainWidget->statusLabel->setText(i18n("Ready"));
+ }
+ 
++void HistoryDialog::slotRightClick(const QString &url, const QPoint &point)
++{
++	KPopupMenu *chatWindowPopup = 0L;
++	chatWindowPopup = new KPopupMenu();
++	
++	if ( !url.isEmpty() )
++	{
++		mURL = url;
++		mCopyURLAct->plug( chatWindowPopup );
++		chatWindowPopup->insertSeparator();
++	}
++	mCopyAct->setEnabled( mHtmlPart->hasSelection() );
++	mCopyAct->plug( chatWindowPopup );
++	
++	connect( chatWindowPopup, SIGNAL( aboutToHide() ), chatWindowPopup, SLOT( deleteLater() ) );
++	chatWindowPopup->popup(point);
++}
++
++void HistoryDialog::slotCopy()
++{
++	QString qsSelection;
++	qsSelection = mHtmlPart->selectedText();
++	if ( qsSelection.isEmpty() ) return;
++	
++	disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), mHtmlPart, SLOT(slotClearSelection()));
++	QApplication::clipboard()->setText(qsSelection, QClipboard::Clipboard);
++	QApplication::clipboard()->setText(qsSelection, QClipboard::Selection);
++	connect( kapp->clipboard(), SIGNAL( selectionChanged()), mHtmlPart, SLOT(slotClearSelection()));
++}
++
++void HistoryDialog::slotCopyURL()
++{
++	disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), mHtmlPart, SLOT(slotClearSelection()));
++	QApplication::clipboard()->setText( mURL, QClipboard::Clipboard);
++	QApplication::clipboard()->setText( mURL, QClipboard::Selection);
++	connect( kapp->clipboard(), SIGNAL( selectionChanged()), mHtmlPart, SLOT(slotClearSelection()));
++}
++
+ #include "historydialog.moc"
+--- kopete/plugins/history/historydialog.h	(revision 568672)
++++ kopete/plugins/history/historydialog.h	(revision 586398)
+@@ -88,12 +88,16 @@
+ 		void slotSearchErase();
+ 		void slotSearchTextChanged(const QString& txt); // To enable/disable search button
+ 		void slotContactChanged(int index);
++		void slotFilterChanged(int index);
+ 
+ 		void searchFirstStep();
+ 
+ 		void init();
+ 		void slotLoadDays();
+ 
++		void slotRightClick(const QString &url, const QPoint &point);
++		void slotCopy();
++		void slotCopyURL();
+ 
+ 	private:
+ 		enum Disabled { Prev=1, Next=2 };
+@@ -150,6 +154,10 @@
+ 
+ 				Kopete::MetaContact *currentMetaContact;
+ 		} *mSearch;
++
++		KAction *mCopyAct;
++		KAction *mCopyURLAct;
++		QString mURL;
+ };
+ 
+ #endif
+--- kopete/plugins/addbookmarks/addbookmarksplugin.cpp	(revision 568672)
++++ kopete/plugins/addbookmarks/addbookmarksplugin.cpp	(revision 586398)
+@@ -20,6 +20,7 @@
+ #include "kopetecontact.h"
+ #include "kopetechatsessionmanager.h"
+ #include "kopeteglobal.h"
++#include "kopetemetacontact.h"
+ 
+ 
+ K_EXPORT_COMPONENT_FACTORY( kopete_addbookmarks, BookmarksPluginFactory( "kopete_addbookmarks" )  )
+@@ -53,8 +54,14 @@
+ 	URLsList = extractURLsFromString( msg.parsedBody() );
+ 	if (!URLsList->empty()) {
+ 		for( it = URLsList->begin() ; it != URLsList->end() ; ++it){
+-			addKopeteBookmark(*it, msg.from()->property(Kopete::Global::Properties::self()->nickName()).value().toString() );
+-			//kdDebug (14501) << "name:" << msg.from()->property(Kopete::Global::Properties::self()->nickName()).value().toString() << endl;
++			if( msg.from()->metaContact() ) {
++				addKopeteBookmark(*it, msg.from()->metaContact()->displayName() );
++				//kdDebug (14501) << "name:" << msg.from()->metaContact()->displayName() << endl;
++			}
++			else {
++				addKopeteBookmark(*it, msg.from()->property(Kopete::Global::Properties::self()->nickName()).value().toString() );
++				//kdDebug (14501) << "name:" << msg.from()->property(Kopete::Global::Properties::self()->nickName()).value().toString() << endl;
++			}
+ 		}
+ 	}
+ 	delete URLsList;
+--- kopete/plugins/webpresence/webpresenceplugin.cpp	(revision 568672)
++++ kopete/plugins/webpresence/webpresenceplugin.cpp	(revision 586398)
+@@ -191,7 +191,6 @@
+ 		delete xml; // might make debugging harder!
+ 		break;
+ 	default:
+-		delete xml;
+ 		return;
+ 	}
+ 
+--- kopete/plugins/connectionstatus/connectionstatusplugin.cpp	(revision 568672)
++++ kopete/plugins/connectionstatus/connectionstatusplugin.cpp	(revision 586398)
+@@ -83,6 +83,8 @@
+ 
+ void ConnectionStatusPlugin::slotProcessExited( KProcess *process )
+ {
++	kdDebug( 14301 ) << m_buffer << endl;
++
+ 	if ( process == m_process )
+ 	{
+ 		setConnectedStatus( m_buffer.contains( "default" ) );
+--- kopete/styles/Konsole.xsl	(revision 568672)
++++ kopete/styles/Konsole.xsl	(revision 586398)
+@@ -1,340 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-<xsl:output method="html"/>
+-
+-<!-- 
+-Author:   Urs Roesch <urs (a) synthetik dot ch>
+-Version:  0.5.2
+-Based on: XChat.xsl (but not much in common at this point)
+-License:  GPL (http://www.gnu.org/licenses/gpl.txt)
+-
+-Changelog:
+- - 2004-02-29 Urs Roesch
+-   * Added Changelog :)
+-   * Rewritten to make use of variables
+-   * Cleanup
+-   
+- - 2004-03-01 Urs Roesch  
+-   * template-ized
+-   * added experimental BiDi support
+-   * added experimental i18n support
+-   
+- - 2004-03-01 Urs Roesch 
+-   * Bugfixed contact name   
+-
+- - 2004-03-03 Urs Roesch 
+-   * simplyfied contact name logic
+-   * added the use-meta-name config option
+-   
+-Todo:
+-   * add more configuration variables
+-   * test BiDi (need help from 3rd party)
+-   * test i18n (need help from 3rd party) 
+-
+-Readme: 
+-   You can now configure style with xsl variables right below this message.
+-   Simply change the values to the ones you would like to use and in either
+-   your favorite text editor or the build in one of Kopete.
+-   
+--->
+-
+-
+-<!-- User definable variables -->
+-<xsl:variable name="body-font-weight">bold</xsl:variable>
+-
+-<!-- set the color of the timestamp -->
+-<xsl:variable name="time-color">#00FF00</xsl:variable>
+-<!-- set the font-weight of the timestamp (see the CSS spec for more info) -->
+-<xsl:variable name="time-font-weight">bold</xsl:variable>
+-
+-<!-- set the symbol for outgoing messages -->
+-<xsl:variable name="outgoing-symbol"> $ </xsl:variable>
+-<!-- set the color of the symbol for outgoing messages -->
+-<xsl:variable name="outgoing-color">#FF6600</xsl:variable>
+-<!-- set the font-weight of the symbol for outgoing messages -->
+-<xsl:variable name="outgoing-font-weight">bold</xsl:variable>
+-
+-<!-- set the symbol for incoming messages -->
+-<xsl:variable name="incoming-symbol"> $ </xsl:variable>
+-<!-- set the color of the symbol for incoming messages --> 
+-<xsl:variable name="incoming-color">#FFFF00</xsl:variable>
+-<!-- set the font-weight for the symbol for incoming messages -->
+-<xsl:variable name="incoming-font-weight">bold</xsl:variable>
+-
+-<!-- set the symbol for action messages -->
+-<xsl:variable name="action-symbol"> @ </xsl:variable>
+-<!-- set the color for the action message symbol -->
+-<xsl:variable name="action-color">#00FFFF</xsl:variable>
+-<!-- set the font-weight for the action message symbol -->
+-<xsl:variable name="action-font-weight">bold</xsl:variable>
+-<!-- set the font-color of the action messages -->
+-<xsl:variable name="action-body-color">darkgrey</xsl:variable>
+-
+-<!-- set the symbol for internal messages -->
+-<xsl:variable name="internal-symbol"> # </xsl:variable>
+-<!-- set the color for the internal message symbol -->
+-<xsl:variable name="internal-color">#FF00FF</xsl:variable>
+-<!-- set the font-weight for the internal message symbol -->
+-<xsl:variable name="internal-font-weight">bold</xsl:variable>
+-
+-<!-- 
+-	set to yes to display screen name in front of the timestamp seperated 
+-        by an @ e.g. [screen_name at 22:30:59] 
+--->
+-<xsl:variable name="show-screen-name">yes</xsl:variable>
+-<!-- use meta name instead of screen name -->
+-<xsl:variable name="use-meta-name">no</xsl:variable>
+-<!-- set to no to override the kopete background and font-colors -->
+-<xsl:variable name="use-kopete-colors">yes</xsl:variable>
+-
+-
+-
+-<!-- eof user definable user variables -->
+-
+-
+-
+-<!-- ============================================================================================ -->
+-<!-- Default variables are mine; read keep your greasy paws off ;) -->
+-<xsl:variable name="default-background">#000000</xsl:variable>
+-<xsl:variable name="default-foreground">#FFFFFF</xsl:variable>
+-
+-<xsl:variable name="default-time-color">#00FF00</xsl:variable>
+-<xsl:variable name="default-time-font-weight">bold</xsl:variable>
+-
+-<xsl:variable name="default-outgoing-symbol"> $ </xsl:variable>
+-<xsl:variable name="default-outgoing-color">#FF6600</xsl:variable>
+-<xsl:variable name="default-outgoing-font-weight">bold</xsl:variable>
+-
+-<xsl:variable name="default-incoming-symbol"> $ </xsl:variable>
+-<xsl:variable name="default-incoming-color">#FFFF00</xsl:variable>
+-<xsl:variable name="default-incoming-font-weight">bold</xsl:variable>
+-
+-<xsl:variable name="default-action-symbol"> @ </xsl:variable>
+-<xsl:variable name="default-action-color">#00FFFF</xsl:variable>
+-<xsl:variable name="default-action-font-weight">bold</xsl:variable>
+-<xsl:variable name="default-action-body-color">darkgrey</xsl:variable>
+-
+-<xsl:variable name="default-internal-symbol"> # </xsl:variable>
+-<xsl:variable name="default-internal-color">#FF00FF</xsl:variable>
+-<xsl:variable name="default-internal-font-weight">bold</xsl:variable>
+-
+-<xsl:variable name="test-dir">RTL</xsl:variable>
+-<xsl:variable name="lc">ltr</xsl:variable>
+-<xsl:variable name="uc">LTR</xsl:variable>
+-
+-<!-- let the games begin -->
+-
+-<xsl:template match="message">
+-
+-
+-<div class="KopeteMessage">
+-	<xsl:attribute name="id">
+-		<xsl:value-of select="@id"/>
+-	</xsl:attribute>
+-	<xsl:attribute name="style">
+-		<xsl:choose>
+-			<xsl:when test="$use-kopete-colors = 'yes' ">
+-				<xsl:if test="body/@color">
+-					color: <xsl:value-of select="body/@color"/>;
+-				</xsl:if>
+-  				<xsl:if test="body/@bgcolor">
+-    					background-color: <xsl:value-of select="body/@bgcolor"/>
+-  				</xsl:if>
+-			</xsl:when>
+-			<xsl:otherwise>
+-				background-color: <xsl:value-of select="$default-background" />;
+-				color: <xsl:value-of select="$default-foreground" />;
+-			</xsl:otherwise>
+-		</xsl:choose>
+-  		<xsl:text>
+-			padding-bottom: 0.2em;
+-			clear: both;
+-		</xsl:text>
+-	</xsl:attribute>
+-	<!-- 
+-	<xsl:attribute name="dir">
+-		<xsl:value-of select="body/@dir" />
+-	</xsl:attribute>
+-	-->
+-	
+-	
+-<div> <!-- floating info -->
+-	<xsl:attribute name="style">
+-		<xsl:choose>
+-			<xsl:when test="translate(body/@dir, $uc, $lc) = 'ltr'">
+-				float: left;
+-			</xsl:when>
+-			<xsl:otherwise>
+-				float: right;
+-			</xsl:otherwise>
+-		</xsl:choose>
+-	</xsl:attribute>
+-	<!--
+-	<xsl:attribute name="dir">
+-		<xsl:value-of select="body/@dir" /> -->
+-		<!-- <xsl:value-of select="/body/@dir" /> -->
+-	<!-- </xsl:attribute> -->
+-	<xsl:if test="translate(body/@dir, $uc, $lc) = 'rtl'">
+-		<xsl:call-template name="symbol" />
+-	</xsl:if>
+-<!-- Time stamp -->
+-<span><!-- time -->
+-	<xsl:attribute name="style">
+-		<xsl:choose>
+-			<xsl:when test="$time-color">
+-				color: <xsl:value-of select="$time-color" />;
+-			</xsl:when>
+-			<xsl:otherwise>
+-				color: <xsl:value-of select="$default-time-color" />;
+-			</xsl:otherwise>
+-		</xsl:choose>
+-		<xsl:choose>
+-			<xsl:when test="$time-font-weight">
+-				font-weight: <xsl:value-of select="$time-font-weight" />;
+-			</xsl:when>
+-			<xsl:otherwise>
+-				font-weight: <xsl:value-of select="$default-time-font-weight" />;
+-			</xsl:otherwise>
+-		</xsl:choose>
+-	</xsl:attribute>
+-		<xsl:text>[</xsl:text>
+-			<xsl:if test="$show-screen-name = 'yes'">
+-				<xsl:choose>	
+-					<xsl:when test="$use-meta-name = 'yes'">
+-						<xsl:value-of select="from/contact/metaContactDisplayName/@text" disable-output-escaping="yes"/>
+-					</xsl:when>
+-					<xsl:otherwise>
+-						<xsl:value-of select="from/contact/contactDisplayName/@text" disable-output-escaping="yes"/>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-				<xsl:text>@</xsl:text>
+-			</xsl:if>
+-			<xsl:value-of select="@time"/>]
+-		<!-- <xsl:value-of select="@time"/> -->
+-	
+-	<xsl:if test="translate(body/@dir, $uc, $lc) = 'ltr'">
+-		<xsl:call-template name="symbol" />
+-	</xsl:if>
+-</span><!-- eof time -->
+-
+-<!-- Choose based on message direction -->
+-</div><!-- eof floating info -->
+-
+-<div>
+-	<xsl:attribute name="style">
+-		<xsl:choose>
+-			<xsl:when test="translate(body/@dir, $uc, $lc) = 'ltr'">
+-				text-indent: 0.5em;
+-				margin-left: 4em;
+-			</xsl:when>
+-			<xsl:otherwise>
+-				text-indent: -0.5em;
+-				margin-right: 4em;
+-			</xsl:otherwise>
+-		</xsl:choose>
+-	</xsl:attribute>
+-	<xsl:attribute name="dir">
+-		<xsl:value-of select="body/@dir" />
+-		<!-- <xsl:value-of select="/body/@dir" /> -->
+-	</xsl:attribute>
+-<span>
+-	<xsl:attribute name="style">
+-		<xsl:if test="@direction = '3'"><!-- action message -->
+-			<xsl:choose>
+-				<xsl:when test="$action-body-color">
+-					color: <xsl:value-of select="$action-body-color" />;
+-				</xsl:when>
+-				<xsl:otherwise>
+-					color: <xsl:value-of select="$default-action-body-color" />;
+-				</xsl:otherwise>
+-			</xsl:choose>
+-		</xsl:if>
+-	</xsl:attribute>
+-	<xsl:if test="@importance = '2'">
+-		<xsl:attribute name="class"><xsl:text>KopeteMessage highlight</xsl:text></xsl:attribute>
+-	</xsl:if>
+-	<xsl:if test="@direction='3'"><!-- Action -->
+-		<xsl:value-of select="from/contact/contactDisplayname/@text" disable-output-escaping="yes"/>
+-	</xsl:if>
+-	<xsl:value-of disable-output-escaping="yes" select="body"/>
+-</span>
+-</div>
+-</div><!-- eof message -->
+-</xsl:template>
+-
+-<xsl:template name="symbol">
+-<!-- Choose based on message direction -->
+-<xsl:choose><!-- symbol -->
+-	<xsl:when test="@direction = '2'"><!--internal message-->
+-		<xsl:call-template name="display-symbol">
+-			<xsl:with-param name="symbol"><xsl:value-of select="$internal-symbol" /></xsl:with-param>
+-			<xsl:with-param name="color"><xsl:value-of select="$internal-color" /></xsl:with-param>
+-			<xsl:with-param name="font-weight"><xsl:value-of select="$internal-font-weight" /></xsl:with-param>
+-			<xsl:with-param name="default-color"><xsl:value-of select="$default-internal-color" /></xsl:with-param>
+-			<xsl:with-param name="default-font-weight"><xsl:value-of select="$default-internal-font-weight" /></xsl:with-param>
+-		</xsl:call-template>
+-	</xsl:when><!-- eof internal message -->
+-	
+-	<xsl:when test="@direction = '3'"><!--action message-->
+-		<xsl:call-template name="display-symbol">
+-			<xsl:with-param name="symbol"><xsl:value-of select="$action-symbol" /></xsl:with-param>
+-			<xsl:with-param name="color"><xsl:value-of select="$action-color" /></xsl:with-param>
+-			<xsl:with-param name="font-weight"><xsl:value-of select="$action-font-weight" /></xsl:with-param>
+-			<xsl:with-param name="default-color"><xsl:value-of select="$default-action-color" /></xsl:with-param>
+-			<xsl:with-param name="default-font-weight"><xsl:value-of select="$default-action-font-weight" /></xsl:with-param>
+-		</xsl:call-template>
+-	</xsl:when><!-- eof action message -->
+-
+-	<xsl:when test="@direction = '1'"><!-- outgoing -->
+-		<xsl:call-template name="display-symbol">
+-			<xsl:with-param name="symbol"><xsl:value-of select="$outgoing-symbol" /></xsl:with-param>
+-			<xsl:with-param name="color"><xsl:value-of select="$outgoing-color" /></xsl:with-param>
+-			<xsl:with-param name="font-weight"><xsl:value-of select="$outgoing-font-weight" /></xsl:with-param>
+-			<xsl:with-param name="default-color"><xsl:value-of select="$default-outgoing-color" /></xsl:with-param>
+-			<xsl:with-param name="default-font-weight"><xsl:value-of select="$default-outgoing-font-weight" /></xsl:with-param>
+-		</xsl:call-template>
+-	</xsl:when><!-- eof outgoing  -->	
+-	
+-	<xsl:otherwise><!-- other messages -->
+-		<xsl:call-template name="display-symbol">
+-			<xsl:with-param name="symbol"><xsl:value-of select="$incoming-symbol" /></xsl:with-param>
+-			<xsl:with-param name="color"><xsl:value-of select="$incoming-color" /></xsl:with-param>
+-			<xsl:with-param name="font-weight"><xsl:value-of select="$incoming-font-weight" /></xsl:with-param>
+-			<xsl:with-param name="default-color"><xsl:value-of select="$default-incoming-color" /></xsl:with-param>
+-			<xsl:with-param name="default-font-weight"><xsl:value-of select="$default-incoming-font-weight" /></xsl:with-param>
+-		</xsl:call-template>
+-	</xsl:otherwise><!-- eof other messages -->
+-</xsl:choose><!-- eof symbol -->
+-</xsl:template>
+-
+-<xsl:template name="display-symbol">
+-	<xsl:param name="symbol"><xsl:value-of select="symbol" /></xsl:param>
+-	<xsl:param name="color"><xsl:value-of select="color" /></xsl:param>
+-	<xsl:param name="font-weight"><xsl:value-of select="font-weight" /></xsl:param>
+-	<xsl:param name="default-color"><xsl:value-of select="default-color" /></xsl:param>
+-	<xsl:param name="default-font-weight"><xsl:value-of select="default-font-weight" /></xsl:param>
+-	
+-	<span>
+-		<xsl:attribute name="style">
+-			<xsl:choose>
+-				<xsl:when test="$color">
+-					color: <xsl:value-of select="$color" />;
+-				</xsl:when>
+-				<xsl:otherwise>
+-					color: <xsl:value-of select="$default-color" />;
+-				</xsl:otherwise>
+-			</xsl:choose>
+-			<xsl:choose>
+-				<xsl:when test="$font-weight">
+-					font-weight: <xsl:value-of select="$font-weight" />;
+-				</xsl:when>
+-				<xsl:otherwise>
+-					font-weight: <xsl:value-of select="$default-font-weight" />;
+-				</xsl:otherwise>
+-			</xsl:choose>
+-		</xsl:attribute>
+-		<xsl:value-of select="$symbol" />
+-	</span>
+-</xsl:template>
+-
+-</xsl:stylesheet>
+--- kopete/styles/Adium_JS.xsl	(revision 568672)
++++ kopete/styles/Adium_JS.xsl	(revision 586398)
+@@ -1,51 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:variable name="data"><xsl:value-of select="$appdata"/>/Adium</xsl:variable>
+-	<xsl:template match="message">
+-		<script type="text/javascript">
+-		function execute()
+-		{
+-			appendMessage(
+-				"<xsl:value-of disable-output-escaping="yes" select="from/contact/@contactId"/>",
+-				"<xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>",
+-				"<xsl:value-of disable-output-escaping="yes" select="from/contact/metaContactDisplayName/@text"/>",
+-				"<xsl:value-of select="@formattedTimestamp"/>",
+-				"<xsl:value-of select="from/contact/@color"/>",
+-				"<xsl:value-of select="translate(from/contact/@color,'0123456789AaBbCcDdEeFf','8899aabbccddddeeeeffff')"/>",
+-				'<xsl:call-template name="escape"><xsl:with-param name="string" select="body"/></xsl:call-template>',
+-				"<xsl:value-of select="@type"/>",
+-				"<xsl:value-of select="@route"/>",
+-				'<xsl:value-of select="from/contact/@userPhoto"/>',
+-				'<xsl:value-of select="from/contact/@protocolIcon"/>'
+-			);
+-		}
+-
+-		if( typeof( scriptLoaded ) == "undefined" )
+-		{
+-			document.write("\u003Cscript src=\"<xsl:value-of select="$data"/>/adium.js\"\u003E\u003C/script\u003E");
+-			window.setTimeout( execute, 500 );
+-		}
+-		else
+-			execute();
+-		</script>
+-	</xsl:template>
+-
+-	<xsl:template name="escape">
+-	    <xsl:param name="string" />
+-	    <xsl:choose>
+-		<xsl:when test='contains($string, "&apos;")'>
+-		    <xsl:value-of disable-output-escaping="yes" select='substring-before($string, "&apos;")' />
+-		    <xsl:text>\'</xsl:text>
+-		    <xsl:call-template name="escape">
+-			<xsl:with-param name="string" disable-output-escaping="yes" select='substring-after($string, "&apos;")' />
+-		    </xsl:call-template>
+-		</xsl:when>
+-		<xsl:otherwise>
+-		    <xsl:value-of disable-output-escaping="yes" select="$string" />
+-		</xsl:otherwise>
+-	    </xsl:choose>
+-	</xsl:template>
+-
+-</xsl:stylesheet>
+-
+--- kopete/styles/Enclosed.xsl	(revision 568672)
++++ kopete/styles/Enclosed.xsl	(revision 586398)
+@@ -1,101 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-		<div class="KopeteMessage" style="padding-bottom:5px;">
+-			<xsl:attribute name="id">
+-				<xsl:value-of select="@id"/>
+-			</xsl:attribute>
+-			<div style="border:1px solid grey;padding:1px;">
+-				<div>
+-					<xsl:choose>
+-						<xsl:when test="@direction='3'">
+-							<!-- action message -->
+-							<xsl:attribute name="style">
+-								<xsl:text>color:red;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-							<kopete-i18n>Message from %FROM_METACONTACT_DISPLAYNAME% (%FROM_CONTACT_ID%)</kopete-i18n>
+-						</xsl:when>
+-						<xsl:when test="@direction='2'">
+-							<!-- internal message -->
+-							<xsl:attribute name="style">
+-								<xsl:text>color:red;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-							<!-- System Message -->
+-							<kopete-i18n>System Message</kopete-i18n>
+-						</xsl:when>
+-						<xsl:when test="@direction='1'">
+-							<!-- Outgoing -->
+-							<xsl:attribute name="style">
+-								<xsl:text>color:red;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-							<kopete-i18n>Message to %TO_METACONTACT_DISPLAYNAME% (from %FROM_CONTACT_ID%)</kopete-i18n>
+-						</xsl:when>
+-						<xsl:otherwise>
+-							<!-- Incoming -->
+-							<xsl:attribute name="style">
+-								<xsl:text>color:blue;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-							<kopete-i18n>Message from %FROM_METACONTACT_DISPLAYNAME% (%FROM_CONTACT_ID%)</kopete-i18n>
+-						</xsl:otherwise>
+-					</xsl:choose>
+-				</div>
+-				<div style="text-align:right;margin-top:-1em;float:right;">
+-					<xsl:value-of select="@time"/>
+-				</div>
+-				<div>
+-					<xsl:attribute name="dir">
+-						<xsl:value-of select="body/@dir"/>
+-					</xsl:attribute>
+-					<xsl:attribute name="style">
+-						<xsl:text>padding-left:15px;padding-right:15px;</xsl:text>
+-						<xsl:if test="body/@color">
+-							<xsl:text>color:</xsl:text>
+-							<xsl:value-of select="body/@color"/>
+-							<xsl:text>;</xsl:text>
+-						</xsl:if>
+-						<xsl:if test="body/@bgcolor">
+-							<xsl:text>background-color:</xsl:text>
+-							<xsl:value-of select="body/@bgcolor"/>
+-						</xsl:if>
+-						<xsl:if test="body/@font">
+-							<xsl:text>; </xsl:text>
+-							<xsl:value-of select="body/@font"/>
+-						</xsl:if>
+-					</xsl:attribute>
+-					<xsl:if test="@importance='2'">
+-						<xsl:attribute name="class">
+-							<xsl:text>highlight</xsl:text>
+-						</xsl:attribute>
+-					</xsl:if>
+-					<xsl:choose>
+-						<xsl:when test="@direction='3'">
+-							<!--action message-->
+-							<span style="color:darkgreen">
+-								<xsl:text>* </xsl:text>
+-								<span>
+-									<xsl:attribute name="dir">
+-										<xsl:value-of select="from/contact/metaContactDisplayName/@dir"/>
+-									</xsl:attribute>
+-									<xsl:value-of disable-output-escaping="yes" select="from/contact/metaContactDisplayName/@text"/>
+-								</span>
+-								<xsl:text> </xsl:text>
+-								<xsl:value-of disable-output-escaping="yes" select="body"/>
+-							</span>
+-						</xsl:when>
+-						<xsl:when test="@direction='2'">
+-							<!--internal message-->
+-							<span style="color:darkviolet;font-weight:bold;">
+-								<xsl:value-of disable-output-escaping="yes" select="body"/>
+-							</span>
+-						</xsl:when>
+-						<xsl:otherwise>
+-							<xsl:value-of disable-output-escaping="yes" select="body"/>
+-						</xsl:otherwise>
+-					</xsl:choose>
+-				</div>
+-			</div>
+-		</div>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/Gaim.xsl	(revision 568672)
++++ kopete/styles/Gaim.xsl	(revision 586398)
+@@ -1,109 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-
+-<!--
+-
+-This is a Kopete messages stylesheet
+-Made by kanuso (kanuso at kanuso.net)
+-
+-Nothing is original :P
+-The theme is mainly based on:
+-- Gaim's style and colors
+-- XChat and Kopete stylesheets' code (so I suppose this is GPL code)
+-
+--->
+-
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-<xsl:output method="html"/>
+-<xsl:template match="message">
+-<div class="KopeteMessage">
+-
+-<xsl:attribute name="id">
+-	<xsl:value-of select="@id"/>
+-</xsl:attribute>
+-
+-<!-- First, decide the "full line" style -->
+-<xsl:attribute name="style">
+-		<!-- decide font color by message type -->
+-		<xsl:choose>
+-			<!-- internal message -->
+-			<xsl:when test="@direction='2'">
+-				<xsl:text>color:darkviolet;</xsl:text>
+-			</xsl:when>
+- 			<!-- action message -->
+-			<xsl:when test="@direction='3'">
+-				<xsl:text>color:darkgreen;</xsl:text>
+-			</xsl:when>
+-			<!-- incoming/outgoing message -->
+-			<xsl:otherwise>
+-				<xsl:if test="body/@color">
+-					<xsl:text>color:</xsl:text>
+-					<xsl:value-of select="body/@color"/>
+-					<xsl:text>;</xsl:text>
+-				</xsl:if>
+-			</xsl:otherwise>
+-		</xsl:choose>
+-		<!-- if there si a bgcolor, apply it -->
+-		<xsl:if test="body/@bgcolor">
+-			<xsl:text>background-color:</xsl:text>
+-			<xsl:value-of select="body/@bgcolor"/>
+-			<xsl:text>;</xsl:text>
+-		</xsl:if>
+-</xsl:attribute>
+-
+-<!-- Decide the Pre-body output by message type -->
+-<xsl:choose>
+-	<!--internal message-->
+-	<xsl:when test="@direction='2'">
+-		<span class="KopeteDisplayTimestamp">(<xsl:value-of select="@time"/>) </span>
+-		<span style="font-weight:bold;"><xsl:text disable-output-escaping="yes">#</xsl:text></span>
+-	</xsl:when>
+-	<!-- action message -->
+-	<xsl:when test="@direction='3'">
+-		<span class="KopeteDisplayTimestamp">(<xsl:value-of select="@time"/>) </span>
+-		<span class="KopeteDisplayName" style="font-weight:bold;">
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="from/contact/metaContactDisplayName/@dir"/>
+-			</xsl:attribute>
+-			<xsl:value-of disable-output-escaping="yes" select="from/contact/metaContactDisplayName/@text"/>
+-		</span>
+-	</xsl:when>
+-	<!-- incoming/outgoing messages -->
+-	<xsl:otherwise>
+-		<span>
+-			<xsl:attribute name="style">
+-				<xsl:choose>
+-					<!-- outgoing -->
+-					<xsl:when test="@direction='1'">
+-						color:<xsl:text>#16569E</xsl:text>
+-					</xsl:when>
+-					<!-- incoming -->
+-					<xsl:otherwise>
+-						color:<xsl:text>#A82F2F</xsl:text>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-			</xsl:attribute>
+-			<span class="KopeteDisplayTimestamp">(<xsl:value-of select="@time"/>) </span>
+-			<span class="KopeteDisplayName" style="font-weight:bold;">
+-				<xsl:attribute name="dir">
+-	                                <xsl:value-of select="from/contact/metaContactDisplayName/@dir"/>
+-	                        </xsl:attribute>
+-				<xsl:value-of disable-output-escaping="yes" select="from/contact/metaContactDisplayName/@text"/>:
+-			</span>
+-		</span>
+-	</xsl:otherwise>
+-</xsl:choose>
+-
+-<!-- Body output -->
+-<span>
+-<xsl:if test="@importance='2'">
+-	<xsl:attribute name="class"><xsl:text>KopeteMessage highlight</xsl:text></xsl:attribute>
+-</xsl:if>
+-<xsl:attribute name="dir">
+-	<xsl:value-of select="body/@dir"/>
+-</xsl:attribute>
+-&#160;<xsl:value-of disable-output-escaping="yes" select="body"/>
+-</span>
+-
+-</div>
+-</xsl:template>
+-</xsl:stylesheet>
+--- kopete/styles/MSN.xsl	(revision 568672)
++++ kopete/styles/MSN.xsl	(revision 586398)
+@@ -1,63 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-		<div style="padding-bottom:10px;" class="KopeteMessage">
+-			<xsl:attribute name="id">
+-				<xsl:value-of select="@id"/>
+-			</xsl:attribute>
+-			<xsl:if test="@direction &lt; 2">
+-				<div style="color:gray">
+-					<kopete-i18n>(%TIME%) %FROM_CONTACT_DISPLAYNAME% says:</kopete-i18n>
+-				</div>
+-				<xsl:text disable-output-escaping="yes">&#160;&#160;&#160;&#160;</xsl:text>
+-			</xsl:if>
+-			<span>
+-				<xsl:attribute name="dir">
+-					<xsl:value-of select="body/@dir"/>
+-				</xsl:attribute>
+-				<xsl:attribute name="style">
+-					<xsl:if test="body/@color">
+-						<xsl:text>color:</xsl:text>
+-						<xsl:value-of select="body/@color"/>
+-						<xsl:text>;</xsl:text>
+-					</xsl:if>
+-					<xsl:if test="body/@bgcolor">
+-						<xsl:text>background-color:</xsl:text>
+-						<xsl:value-of select="body/@bgcolor"/>
+-					</xsl:if>
+-					 <xsl:if test="body/@font">
+-						<xsl:text>; </xsl:text>
+-						<xsl:value-of select="body/@font"/>
+-					</xsl:if>
+-				</xsl:attribute>
+-				<xsl:if test="@importance='2'">
+-					<xsl:attribute name="class">
+-						<xsl:text>highlight</xsl:text>
+-					</xsl:attribute>
+-				</xsl:if>
+-				<xsl:if test="@direction='3'">
+-					<xsl:attribute name="style">
+-						<xsl:text>color:darkGreen;bold</xsl:text>
+-					</xsl:attribute>
+-					<xsl:text>* </xsl:text>
+-					<span>
+-						<xsl:attribute name="title">
+-							<xsl:value-of disable-output-escaping="yes" select="from/contact/@contactId"/>
+-						</xsl:attribute>
+-						<xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>
+-						<xsl:text> </xsl:text>
+-					</span>
+-				</xsl:if>
+-				<xsl:if test="@direction='2'">
+-					<xsl:attribute name="style">
+-						<xsl:text>color:darkviolet;italic</xsl:text>
+-					</xsl:attribute>
+-					<xsl:text disable-output-escaping="yes">-- </xsl:text>
+-				</xsl:if>
+-				<xsl:value-of disable-output-escaping="yes" select="body"/>
+-			</span>
+-		</div>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/Adium.xsl	(revision 568672)
++++ kopete/styles/Adium.xsl	(revision 586398)
+@@ -1,124 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<?Kopete Flag:TransformAllMessages?>
+-
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-
+-	<xsl:template match="document">
+-		<xsl:variable name="messages" select="message"/>
+-		<xsl:for-each select="message">
+-			<xsl:call-template name="processMessage">
+-				<xsl:with-param name="messages" select="$messages"/>
+-			</xsl:call-template>
+-		</xsl:for-each>
+-	</xsl:template>
+-
+-	<xsl:template name="processMessage">
+-		<xsl:param name="messages"/>
+-		<xsl:variable name="position" select="position()"/>
+-		<xsl:variable name="prev" select="$messages[position()=$position - 1]"/>
+-		<xsl:variable name="curr" select="$messages[position()=$position]"/>
+-		<xsl:variable name="prevId" select="$prev/from/contact/@contactId"/>
+-		<xsl:variable name="currId" select="$curr/from/contact/@contactId"/>
+-		<xsl:if test="not($prevId=$currId)">
+-			<table style="width:100%">
+-				<tr>
+-					<td style="vertical-align: top;">
+-						<img style="vertical-align: top; padding-top: 5px;">
+-							<xsl:attribute name="src">
+-								<xsl:value-of select="$curr/from/contact/@protocolIcon"/>
+-							</xsl:attribute>
+-						</img>
+-					</td>
+-					<td style="width:100%">
+-						<table style="width:100%">
+-							<tr>
+-								<td style="align:left">
+-									<span>
+-										<xsl:attribute name="style">
+-											color: <xsl:value-of select="$curr/from/contact/@color"/>;
+-										</xsl:attribute>
+-										<b><xsl:value-of select="$curr/from/contact/metaContactDisplayName/@text" disable-output-escaping="yes"/></b>
+-										<xsl:if test="$curr/from/contact/metaContactDisplayName/@text != $curr/from/contact/contactDisplayName/@text">
+-											<i> (<xsl:value-of select="$curr/from/contact/contactDisplayName/@text" disable-output-escaping="yes"/>)</i>
+-										</xsl:if>
+-									</span>
+-								</td>
+-								<td style="text-align: right; color: gray"><xsl:value-of select="$curr/@formattedTimestamp"/></td>
+-							</tr>
+-						</table>
+-						<div>
+-							<xsl:attribute name="style">
+-								border: medium solid <xsl:value-of select="$curr/from/contact/@color"/>;
+-								background-color: <xsl:call-template name="lightenColour"><xsl:with-param name="colour" select="$curr/from/contact/@color"/></xsl:call-template>;
+-								padding: 5px;
+-								margin: 0;
+-							</xsl:attribute>
+-							<xsl:call-template name="renderFirstMessage"/>
+-							<xsl:call-template name="renderRest">
+-								<xsl:with-param name="messages" select="$messages"/>
+-								<xsl:with-param name="withId" select="$currId"/>
+-								<xsl:with-param name="position" select="$position + 1"/>
+-							</xsl:call-template>
+-						</div>
+-					</td>
+-				</tr>
+-			</table>
+-		</xsl:if>
+-	</xsl:template>
+-
+-	<xsl:template name="renderRest">
+-		<xsl:param name="messages"/>
+-		<xsl:param name="withId"/>
+-		<xsl:param name="position"/>
+-		<xsl:variable name="curr" select="$messages[position()=$position]"/>
+-		<xsl:variable name="currId" select="$curr/from/contact/@contactId"/>
+-		<xsl:if test="$withId = $currId">
+-			<!-- call-template doesn't support select=. fake it. -->
+-			<xsl:for-each select="$curr">
+-				<xsl:call-template name="renderLaterMessage"/>
+-			</xsl:for-each>
+-			<xsl:call-template name="renderRest">
+-				<xsl:with-param name="messages" select="$messages"/>
+-				<xsl:with-param name="withId" select="$currId"/>
+-				<xsl:with-param name="position" select="$position + 1"/>
+-			</xsl:call-template>
+-		</xsl:if>
+-	</xsl:template>
+-
+-	<xsl:template name="renderFirstMessage">
+-		<xsl:call-template name="renderMessageBody"/>
+-	</xsl:template>
+-
+-	<xsl:template name="renderLaterMessage">
+-		<hr>
+-			<xsl:attribute name="style">
+-				border: thin dashed <xsl:value-of select="from/contact/@color"/>;
+-				margin: 0;
+-			</xsl:attribute>
+-		</hr>
+-		<xsl:call-template name="renderMessageBody"/>
+-	</xsl:template>
+-
+-	<xsl:template name="renderMessageBody">
+-		<xsl:choose>
+-			<xsl:when test="@type='action'">
+-				<i><xsl:value-of select="from/contact/contactDisplayName/@text" disable-output-escaping="yes"/><xsl:text> </xsl:text><xsl:value-of select="body" disable-output-escaping="yes"/></i>
+-			</xsl:when>
+-			<xsl:when test="@route='internal'">
+-				<span style="font-weight: bold; font-size: xx-small;">
+-					<xsl:value-of disable-output-escaping="yes" select="body"/>
+-				</span>
+-			</xsl:when>
+-			<xsl:otherwise>
+-				<xsl:value-of disable-output-escaping="yes" select="body"/>
+-			</xsl:otherwise>
+-		</xsl:choose>
+-	</xsl:template>
+-
+-	<xsl:template name="lightenColour">
+-		<xsl:param name="colour"/>
+-		<xsl:value-of select="translate($colour,'0123456789AaBbCcDdEeFf','8899aabbccddddeeeeffff')"/>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/Keramik.xsl	(revision 568672)
++++ kopete/styles/Keramik.xsl	(revision 586398)
+@@ -1,114 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-		<div style="height:5px;">
+-
+-		</div>
+-		<div class="KopeteMessage">
+-			<xsl:attribute name="id">
+-				<xsl:value-of select="@id"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:choose>
+-					<xsl:when test="@direction='2'">
+-						<!-- Internal message -->
+-						<xsl:text>border: 2px solid #800000; border-top:1.5em solid #800000;margin-top: 1.7em;</xsl:text>
+-					</xsl:when>
+-					<xsl:when test="@direction='1'">
+-						<!-- Outgoing -->
+-						<xsl:text>border: 2px solid #97ADC3; border-top:1.5em solid #97ADC3;margin-top: 1.7em;</xsl:text>
+-					</xsl:when>
+-					<xsl:otherwise>
+-						<!-- Incoming / Action message -->
+-						<xsl:text>border: 2px solid #4A98EB; border-top:1.5em solid #4A98EB;margin-top: 1.7em;</xsl:text>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-				<xsl:if test="@importance='2'">
+-					<xsl:text>background-color:#FFFA95;</xsl:text>
+-				</xsl:if>
+-			</xsl:attribute>
+-			<div>
+-				<xsl:attribute name="style">
+-					<xsl:choose>
+-						<xsl:when test="@direction='2'">
+-							<!-- Internal message -->
+-							<xsl:text>color:white;font-weight:bold;width:55%;margin-top:-2.7em;margin-left: 1em;padding:4px;padding-left:10px;border: 1px solid white;background-color:#800000;</xsl:text>
+-						</xsl:when>
+-						<xsl:when test="@direction='1'">
+-							<!-- Outgoing -->
+-							<xsl:text>color:white;font-weight:bold;width:55%;margin-top:-2.7em;margin-left: 1em;padding:4px;padding-left:10px;border: 1px solid white;background-color:#97ADC3;</xsl:text>
+-						</xsl:when>
+-						<xsl:otherwise>
+-							<!-- Incoming / Action message -->
+-							<xsl:text>color:white;font-weight:bold;width:55%;margin-top:-2.7em;margin-left: 1em;padding:4px;padding-left:10px;border: 1px solid white;background-color:#4A98EB;</xsl:text>
+-						</xsl:otherwise>
+-					</xsl:choose>
+-				</xsl:attribute>
+-				<xsl:choose>
+-					<xsl:when test="@direction='2'">
+-						<!-- Internal message -->
+-						<kopete-i18n>System Message</kopete-i18n>
+-					</xsl:when>
+-					<xsl:when test="@direction='1'">
+-						<!-- Outgoing -->
+-						<img width="16" height="16" align="center" border="0" style="margin-right:6px;">
+-							<xsl:attribute name="src">
+-								<xsl:value-of select="to/contact/@protocolIcon"/>
+-							</xsl:attribute>
+-						</img>
+-						<kopete-i18n>To %TO_CONTACT_DISPLAYNAME% at %FORMATTEDTIMESTAMP%</kopete-i18n>
+-					</xsl:when>
+-					<xsl:otherwise>
+-						<!-- Incoming / Action message -->
+-						<img width="16" height="16" align="center" border="0" style="margin-right:6px;">
+-							<xsl:attribute name="src">
+-								<xsl:value-of select="from/contact/@protocolIcon"/>
+-							</xsl:attribute>
+-						</img>
+-						<kopete-i18n>From %FROM_CONTACT_DISPLAYNAME% at %FORMATTEDTIMESTAMP%</kopete-i18n>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-			</div>
+-			<div>
+-				<xsl:attribute name="dir">
+-					<xsl:value-of select="body/@dir"/>
+-				</xsl:attribute>
+-				<xsl:attribute name="id">
+-					<xsl:value-of select="@id"/>
+-				</xsl:attribute>
+-				<xsl:attribute name="style">
+-					<xsl:if test="body/@color">
+-						<xsl:text>color:</xsl:text>
+-						<xsl:value-of select="body/@color"/>
+-						<xsl:text>;</xsl:text>
+-					</xsl:if>
+-					<xsl:if test="body/@bgcolor">
+-						<xsl:text>background-color:</xsl:text>
+-						<xsl:value-of select="body/@bgcolor"/>
+-						<xsl:text>; </xsl:text>
+-					</xsl:if>
+-					<xsl:if test="body/@font">
+-						<xsl:text>font-family:</xsl:text>
+-						<xsl:value-of select="body/@font"/>
+-						<xsl:text>; </xsl:text>
+-					</xsl:if>
+-					<xsl:text>margin-top:8px;padding:6px;</xsl:text>
+-					<xsl:if test="@direction='3'">
+-						<xsl:text>color:darkgreen;</xsl:text>
+-					</xsl:if>
+-				</xsl:attribute>
+-				<xsl:choose>
+-					<xsl:when test="@direction='3'">
+-						<!-- Action -->
+-						<kopete-i18n>* %FROM_CONTACT_DISPLAYNAME% &#160;%BODY%</kopete-i18n>
+-					</xsl:when>
+-					<xsl:otherwise>
+-						<xsl:value-of disable-output-escaping="yes" select="body"/>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-			</div>
+-		</div>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/Kopete-old.xsl	(revision 568672)
++++ kopete/styles/Kopete-old.xsl	(revision 586398)
+@@ -1,74 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-		<div class="KopeteMessage" style="padding-bottom:10px;">
+-			<xsl:attribute name="id">
+-				<xsl:value-of select="@id"/>
+-			</xsl:attribute>
+-			<xsl:if test="number(@direction) &lt; 2">
+-				<div>
+-					<xsl:choose>
+-						<xsl:when test="@direction='1'">
+-							<xsl:attribute name="style">
+-								<xsl:text>color:red;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-						    <kopete-i18n>Message to %TO_CONTACT_DISPLAYNAME% at %FORMATTEDTIMESTAMP%</kopete-i18n>
+-						</xsl:when>
+-						<xsl:otherwise>
+-							<xsl:attribute name="style">
+-								<xsl:text>color:blue;font-weight:bold;</xsl:text>
+-							</xsl:attribute>
+-							<kopete-i18n>Message from %FROM_CONTACT_DISPLAYNAME% at %FORMATTEDTIMESTAMP%</kopete-i18n>
+-						</xsl:otherwise>
+-					</xsl:choose>
+-				</div>
+-				<xsl:text disable-output-escaping="yes">&#160;&#160;&#160;&#160;</xsl:text>
+-			</xsl:if>
+-			<span>
+-				<xsl:attribute name="dir">
+-					<xsl:value-of select="body/@dir"/>
+-				</xsl:attribute>
+-				<xsl:attribute name="style">
+-					<xsl:if test="body/@color">
+-						<xsl:text>color:</xsl:text>
+-						<xsl:value-of select="body/@color"/>
+-						<xsl:text>;</xsl:text>
+-					</xsl:if>
+-					<xsl:if test="body/@bgcolor">
+-						<xsl:text>background-color:</xsl:text>
+-						<xsl:value-of select="body/@bgcolor"/>
+-					</xsl:if>
+-					<xsl:if test="body/@font">
+-						<xsl:text>; </xsl:text>
+-						<xsl:value-of select="body/@font"/>
+-					</xsl:if>
+-				</xsl:attribute>
+-				<xsl:if test="@importance='2'">
+-					<xsl:attribute name="class">
+-						<xsl:text>highlight</xsl:text>
+-					</xsl:attribute>
+-				</xsl:if>
+-				<xsl:choose>
+-					<xsl:when test="@direction='3'">
+-						<!-- Action Message -->
+-						<span style="color:darkgreen">
+-							<kopete-i18n>* %FROM_CONTACT_DISPLAYNAME%&#160;%BODY%</kopete-i18n>
+-						</span>
+-					</xsl:when>
+-					<xsl:when test="@direction='2'">
+-						<!-- Internal Message -->
+-						<span style="color:darkviolet;font-weight:bold;">
+-							<xsl:value-of disable-output-escaping="yes" select="body"/>
+-						</span>
+-					</xsl:when>
+-
+-					<xsl:otherwise>
+-						<xsl:value-of disable-output-escaping="yes" select="body"/>
+-					</xsl:otherwise>
+-				</xsl:choose>
+-			</span>
+-		</div>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/Minimal.xsl	(revision 568672)
++++ kopete/styles/Minimal.xsl	(revision 586398)
+@@ -1,135 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!-- Minimal Kopete style. Copyright (c)2004, Gav Wood. This file may be distributed under
+-       the GPL licence. -->
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-<xsl:output method="html"/>
+-<xsl:template match="message">
+-<div class="KopeteMessage"><xsl:attribute name="id"><xsl:value-of disable-output-escaping="yes" select="@id"/></xsl:attribute>
+-<!-- Choose based on message direction -->
+-<xsl:choose>
+-	<xsl:when test="@direction='2'"><!--internal message-->
+-		<span>
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="body/@dir"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color: </xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@font">
+-					<xsl:text>font: </xsl:text>
+-					<xsl:value-of select="body/@font"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:text>font-size: small; color: #dddddd; padding: 1px; border-width: 1px; border-style: solid; border-color: #cccccc; </xsl:text>
+-			</xsl:attribute>
+-			<xsl:value-of disable-output-escaping="yes" select="body"/>
+-		</span>
+-	</xsl:when>
+-	<xsl:when test="@direction='3'"><!--action message-->
+-		<span>
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="body/@dir"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color: </xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@font">
+-					<xsl:text>font: </xsl:text>
+-					<xsl:value-of select="body/@font"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:text>color: #80d380; </xsl:text>
+-			</xsl:attribute>
+-			<xsl:text>* </xsl:text><xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>
+-			<xsl:text> </xsl:text><xsl:value-of disable-output-escaping="yes" select="body"/>
+-		</span>
+-	</xsl:when>
+-	<xsl:when test="@direction='1'"><!-- outgoing -->
+-		<span>
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="body/@dir"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color:</xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@font">
+-					<xsl:text>font: </xsl:text>
+-					<xsl:value-of select="body/@font"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:text>color: #9999ff; </xsl:text>
+-			</xsl:attribute>
+-			<xsl:value-of disable-output-escaping="yes" select="body"/>
+-		</span>
+-	</xsl:when>
+-	<xsl:when test="@direction='0'"><!-- incoming -->
+-		<span>
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="body/@dir"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@color">
+-					<xsl:text>color: </xsl:text>
+-					<xsl:value-of select="body/@color"/>
+-					<xsl:text>;</xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color: </xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-					<xsl:text>;</xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@font">
+-					<xsl:text>font: </xsl:text>
+-					<xsl:value-of select="body/@font"/>
+-					<xsl:text>;</xsl:text>
+-				</xsl:if>
+-				<xsl:text>font-size: small; </xsl:text>
+-			</xsl:attribute>
+-			<xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>
+-			<xsl:text>: </xsl:text>
+-		</span>
+-		<span>
+-			<xsl:attribute name="dir">
+-				<xsl:value-of select="body/@dir"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@color">
+-					<xsl:text>color: </xsl:text>
+-					<xsl:value-of select="body/@color"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color: </xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@font">
+-					<xsl:text>font: </xsl:text>
+-					<xsl:value-of select="body/@font"/>
+-					<xsl:text>; </xsl:text>
+-				</xsl:if>
+-				<xsl:text>font-weight: bold; </xsl:text>
+-			</xsl:attribute>
+-			<xsl:value-of disable-output-escaping="yes" select="body"/>
+-		</span>
+-	</xsl:when>
+-</xsl:choose>
+-</div>
+-</xsl:template>
+-</xsl:stylesheet>
+-			<!--xsl:text>(</xsl:text>
+-			<xsl:value-of disable-output-escaping="yes" select="body/@font"/>
+-			<xsl:text>,</xsl:text>
+-			<xsl:value-of disable-output-escaping="yes" select="body/@bgcolor"/>
+-			<xsl:text>,</xsl:text>
+-			<xsl:value-of disable-output-escaping="yes" select="body/@color"/>
+-			<xsl:text>)</xsl:text-->
+--- kopete/styles/Kopete.xsl	(revision 568672)
++++ kopete/styles/Kopete.xsl	(revision 586398)
+@@ -1,297 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!--
+-  'Kopete' theme for Kopete
+-  Copyright (C) 2005:
+-  - Johann Ollivier Lapeyre <johann.ollivierlapeyre at gmail.com>
+-  - Original "Clean" theme, Jonas Lihnell <roze at roze.mine.nu> , Jid: yellowroze at jabber.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.
+-
+-  This program is distributed in the hope that it will be useful,
+-  but WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-  GNU General Public License for more details.
+-
+-  You should have received a copy of the GNU General Public License
+-  along with this program; if not, write to the Free Software
+-  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+--->
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-
+-		<div class="KopeteMessage" style="margin:1.4em .2em 0 .2em;">
+-			<xsl:choose>
+-				<xsl:when test="@route='inbound'">
+-
+-					<!-- Incoming normal messages -->
+-					<xsl:if test="@type='normal'">
+-							<!-- Header -->
+-							<div id="MessageHeader" style="">
+-							<xsl:attribute name="style">
+-							background-color:#dfedff;
+-							padding:.1em;
+-							border:solid;
+-							border-color:#fafafa #d1dfef #d1dfef #fafafa;
+-							border-width:2px;
+-							</xsl:attribute>
+-								<div>
+-								<xsl:attribute name="style">
+-								float:left;
+-								</xsl:attribute>
+-								<xsl:if test="from/contact/@userPhoto">
+-									<img>
+-										<xsl:attribute name="src">
+-										data:image/png;base64,<xsl:value-of select="from/contact/@userPhoto"/>;
+-										</xsl:attribute>
+-										<xsl:attribute name="style">
+-										border:1px solid #888;
+-										height:48px; 
+-										margin-top: 0.2em;
+-										margin-left: 0.2em;
+-										margin-right: 1ex;
+-										</xsl:attribute>
+-									</img>
+-								</xsl:if>
+-								</div>
+-								<!-- Protocol Icon -->
+-								<div style="float: left;">
+-									<img style="margin-top: 0.1em; margin-right: 1ex;"><xsl:attribute name="src"><xsl:value-of select="from/contact/@protocolIcon"/></xsl:attribute></img>
+-								</div>
+-								<div>
+-								<xsl:attribute name="style">
+-								float:right;
+-								</xsl:attribute>
+-									<xsl:value-of select="@time"/>
+-								</div>
+-								<div>
+-								<xsl:attribute name="style">
+-								<xsl:if test="from/contact/@userPhoto">
+-									margin-left:60px;
+-								</xsl:if>
+-								</xsl:attribute>
+-									<span>
+-									<xsl:attribute name="style">
+-									font-weight:bold;
+-									<!-- Set username to leftalign regardless of language-direction -->
+-									<xsl:if test="body/@dir='ltr'">text-align: left;</xsl:if>
+-									<xsl:if test="body/@dir='rtl'">text-align: left;</xsl:if>
+-									</xsl:attribute>
+-										<xsl:value-of select="from/contact/metaContactDisplayName/@text" />&#160;
+-									</span>
+-									
+-								</div>
+-							</div>
+-
+-							<div id="MessageBody">
+-
+-								<!-- Highlighted Importance -->
+-								<xsl:attribute name="class">
+-									<xsl:if test="@importance='2'">highlight</xsl:if>
+-								</xsl:attribute>
+-
+-								<xsl:attribute name="style">
+-									padding-left: 1ex;
+-									padding-right: 1ex;
+-									padding-top: 0.25em;
+-									padding-bottom: 0.5em;
+-									line-height: 1.2;
+-
+-									<!-- Align body text according to language direction -->
+-									<xsl:if test="body/@dir='ltr'">text-align: left;</xsl:if>
+-									<xsl:if test="body/@dir='rtl'">text-align: right;</xsl:if>
+-
+-									<!-- Colored Message -->
+-									<xsl:if test="body/@color">color: <xsl:value-of select="body/@color"/>;</xsl:if>
+-									<xsl:if test="body/@bgcolor">background-color: <xsl:value-of select="body/@bgcolor"/>;</xsl:if>
+-									<xsl:if test="body/@font">font: <xsl:value-of select="body/@font"/>;</xsl:if>
+-
+-									<!-- Normal Importance -->
+-									<xsl:if test="@importance='1'"></xsl:if>
+-
+-								</xsl:attribute>
+-
+-								<xsl:value-of disable-output-escaping="yes" select="body" />
+-							</div>
+-					</xsl:if>
+-
+-					<!-- Incoming actions -->
+-					<xsl:if test="@type='action'">
+-							<div id="MessageHeader" style="border-top: 2px solid #dae5f0; 
+-									border-right: 2px solid #aaccf0;
+-									border-bottom: 2px solid #aaccf0;
+-									border-left: 2px solid #dae5f0;
+-									padding: 0.1em; 
+-									vertical-align: middle;
+-									background-color:#c3d9f0;">
+-
+-								<!-- Action Icon -->
+-								<div style="float: left;">
+-									<img style="margin-right: 1ex;"><xsl:attribute name="src"><xsl:value-of select="$appdata"/>Kopete/action.png</xsl:attribute></img>
+-								</div>
+-
+-								<!-- MetaContacts Display Name && Messages Timestamp -->
+-								<div>
+-									<span style="font-weight: bold;"><xsl:value-of select="from/contact/metaContactDisplayName/@text" /></span>
+-									<span style="margin-left: 1ex;"><xsl:value-of disable-output-escaping="yes" select="body" /></span>
+-									<div style="float: right; font-weight: normal;"><xsl:value-of select="@time" /></div>
+-								</div>
+-							</div>
+-					</xsl:if>
+-
+-				</xsl:when>
+-				<xsl:when test="@route='outbound'">
+-
+-					<!-- Outgoing normal messages -->
+-					<xsl:if test="@type='normal'">
+-
+-							<div id="MessageHeader" style="">
+-							<xsl:attribute name="style">
+-							background-color:#f5f5f5;
+-							padding:.1em;
+-							border:solid;
+-							border-color:#fafafa #e3e3e3 #e3e3e3 #fafafa;
+-							border-width:2px;
+-							</xsl:attribute>
+-								<div>
+-								<xsl:attribute name="style">
+-								float:left;
+-								</xsl:attribute>
+-								<xsl:if test="from/contact/@userPhoto">
+-									<img>
+-										<xsl:attribute name="src">
+-										data:image/png;base64,<xsl:value-of select="from/contact/@userPhoto"/>;
+-										</xsl:attribute>
+-										<xsl:attribute name="style">
+-										border:1px solid #888;
+-										height:48px;
+-										margin-top: 0.2em;
+-										margin-left: 0.2em;
+-										margin-right: 1ex;
+-										</xsl:attribute>
+-									</img>
+-								</xsl:if>
+-								</div>
+-								<!-- Protocol Icon -->
+-								<div style="float: left;">
+-									<img style="margin-top: 0.1em; margin-right: 1ex;"><xsl:attribute name="src"><xsl:value-of select="from/contact/@protocolIcon"/></xsl:attribute></img>
+-								</div>
+-								<div>
+-								<xsl:attribute name="style">
+-								float:right;
+-								</xsl:attribute>
+-									<xsl:value-of select="@time"/>
+-								</div>
+-								<div>
+-								<xsl:attribute name="style">
+-								<xsl:if test="from/contact/@userPhoto">
+-									margin-left:60px;
+-								</xsl:if>
+-								</xsl:attribute>
+-									<span>
+-									<xsl:attribute name="style">
+-									font-weight:bold;
+-									<!-- Set username to leftalign regardless of language-direction -->
+-									<xsl:if test="body/@dir='ltr'">text-align: left;</xsl:if>
+-									<xsl:if test="body/@dir='rtl'">text-align: left;</xsl:if>
+-									</xsl:attribute>
+-										<xsl:value-of select="from/contact/metaContactDisplayName/@text" />&#160;
+-									</span>
+-									
+-								</div>
+-							</div>
+-
+-							<div id="MessageBody">
+-
+-								<!-- Highlighted Importance -->
+-								<xsl:attribute name="class">
+-									<xsl:if test="@importance='2'">highlight</xsl:if>
+-								</xsl:attribute>
+-
+-								<xsl:attribute name="style">
+-									padding-left: 1ex;
+-									padding-right: 1ex;
+-									padding-top: 0.25em;
+-									padding-bottom: 0.5em;
+-									line-height: 1.2;
+-
+-									<!-- Align body text according to language direction -->
+-									<xsl:if test="body/@dir='ltr'">text-align: left;</xsl:if>
+-									<xsl:if test="body/@dir='rtl'">text-align: right;</xsl:if>
+-
+-									<!-- Colored Message -->
+-									<xsl:if test="body/@color">color: <xsl:value-of select="body/@color"/>;</xsl:if>
+-									<xsl:if test="body/@bgcolor">background-color: <xsl:value-of select="body/@bgcolor"/>;</xsl:if>
+-									<xsl:if test="body/@font">font: <xsl:value-of select="body/@font"/>;</xsl:if>
+-
+-									<!-- Normal Importance -->
+-									<xsl:if test="@importance='1'"></xsl:if>
+-
+-								</xsl:attribute>
+-
+-								<xsl:value-of disable-output-escaping="yes" select="body" />
+-							</div>
+-					</xsl:if>
+-
+-					<!-- Outgoing actions -->
+-					<xsl:if test="@type='action'">
+-							<div id="MessageHeader" style="border-top: 2px solid fafafa #cfcfcf; 
+-									border-right: 2px solid fafafa #afafaf;
+-									border-bottom: 2px solid fafafa #afafaf;
+-									border-left: 2px solid fafafa #cfcfcf;
+-									padding: 0.1em; 
+-									vertical-align: middle;
+-									background-color:#dedede;">
+-
+-								<!-- Action Icon -->
+-								<div style="float: left;">
+-									<img style="margin-right: 1ex;"><xsl:attribute name="src"><xsl:value-of select="$appdata"/>Kopete/action.png</xsl:attribute></img>
+-								</div>
+-
+-								<!-- MetaContacts Display Name && Messages Timestamp -->
+-								<div>
+-									<span style="font-weight: bold;"><xsl:value-of select="from/contact/metaContactDisplayName/@text" /></span>
+-									<span style="margin-left: 1ex;"><xsl:value-of disable-output-escaping="yes" select="body" /></span>
+-									<div style="float: right; font-weight: normal;"><xsl:value-of select="@time" /></div>
+-								</div>
+-							</div>
+-					</xsl:if>
+-
+-				</xsl:when>
+-
+-				<xsl:when test="@route='internal'">
+-					<div id="MessageHeader" style="	border-top: 0.1em dashed #afafaf; 
+-									border-right: 0.1em dashed #afafaf;
+-									border-bottom: 0.1em dashed #afafaf;
+-									border-left: 0.1em dashed #afafaf;
+-									padding-left: 0.1em; 
+-									padding-bottom: 0.1em; 
+-									padding-right: 0.1em; 
+-									vertical-align: middle;">
+-
+-						<!-- Internal Icon -->
+-						<div style="float: left;">
+-							<img style="margin-right: 1ex;"><xsl:attribute name="src"><xsl:value-of select="$appdata"/>Kopete/system.png</xsl:attribute></img>
+-						</div>
+-
+-						<!-- Internal Message Display && Messages Timestamp -->
+-						<div>
+-							<span>
+-							<xsl:attribute name="style">
+-							text-align: left; font-size: 10px; font-weight: bold; color: #808080;
+-							</xsl:attribute>
+-							<xsl:value-of disable-output-escaping="yes" select="body" /></span>
+-							<div style="float: right; font-weight: normal;"><xsl:value-of select="@time" /></div>
+-						</div>
+-					</div>
+-				</xsl:when>
+-
+-			</xsl:choose>
+-		</div>
+-
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/XChat.xsl	(revision 568672)
++++ kopete/styles/XChat.xsl	(revision 586398)
+@@ -1,98 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-	<xsl:output method="html"/>
+-	<xsl:template match="message">
+-		<div class="KopeteMessage">
+-			<xsl:attribute name="id">
+-				<xsl:value-of select="@id"/>
+-			</xsl:attribute>
+-			<xsl:attribute name="style">
+-				<xsl:if test="body/@color">
+-					<xsl:text>color:</xsl:text>
+-					<xsl:value-of select="body/@color"/>
+-					<xsl:text>;</xsl:text>
+-				</xsl:if>
+-				<xsl:if test="body/@bgcolor">
+-					<xsl:text>background-color:</xsl:text>
+-					<xsl:value-of select="body/@bgcolor"/>
+-				</xsl:if>
+-			</xsl:attribute>
+-
+-			<xsl:if test="@direction='3'">
+-				<xsl:attribute name="style">
+-					<xsl:text>color:darkgreen</xsl:text>
+-				</xsl:attribute>
+-			</xsl:if>
+-			[<xsl:value-of select="@time"/>]
+-			<!-- Choose based on message direction -->
+-			<xsl:choose>
+-				<xsl:when test="@direction='2'">
+-					<!--internal message-->
+-					-
+-					<span style="color:cyan">--</span>
+-				</xsl:when>
+-				<xsl:when test="@direction='3'">
+-					<!--action message-->
+-					<span>
+-						<xsl:attribute name="dir">
+-							<xsl:value-of select="from/contact/contactDisplayName/@dir"/>
+-						</xsl:attribute>
+-						<xsl:attribute name="title">
+-							<xsl:value-of disable-output-escaping="yes" select="from/contact/@contactId"/>
+-						</xsl:attribute>
+-						<xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>
+-					</span>
+-				</xsl:when>
+-				<xsl:otherwise>
+-					<span style="color:blue">&lt;</span>
+-					<font>
+-						<xsl:attribute name="color">
+-							<xsl:choose>
+-								<xsl:when test="@direction='1'">
+-									<!-- Outgoing -->
+-									<xsl:text>yellow</xsl:text>
+-								</xsl:when>
+-								<xsl:otherwise>
+-									<!-- Incoming -->
+-									<xsl:value-of select="from/contact/@color"/>
+-								</xsl:otherwise>
+-							</xsl:choose>
+-						</xsl:attribute>
+-						<span>
+-							<xsl:attribute name="style">
+-								<xsl:choose>
+-									<xsl:when test="@direction='1'">
+-										<xsl:text>color:yellow</xsl:text>
+-									</xsl:when>
+-									<xsl:otherwise>
+-										color:<xsl:value-of select="from/contact/@color"/>
+-									</xsl:otherwise>
+-								</xsl:choose>
+-							</xsl:attribute>
+-							<xsl:attribute name="title">
+-								<xsl:value-of disable-output-escaping="yes" select="from/contact/@contactId"/>
+-							</xsl:attribute>
+-							<xsl:attribute name="dir">
+-								<xsl:value-of select="from/contact/contactDisplayName/@dir"/>
+-							</xsl:attribute>
+-							<xsl:value-of disable-output-escaping="yes" select="from/contact/contactDisplayName/@text"/>
+-						</span>
+-					</font>
+-					<span style="color:blue">&gt;</span>
+-				</xsl:otherwise>
+-			</xsl:choose>
+-			<span style="margin-left:0.5em;">
+-				<xsl:attribute name="dir">
+-					<xsl:value-of select="body/@dir"/>
+-				</xsl:attribute>
+-				<xsl:if test="@importance='2'">
+-					<xsl:attribute name="class">
+-						<xsl:text>KopeteMessage highlight</xsl:text>
+-					</xsl:attribute>
+-				</xsl:if>
+-				<xsl:value-of disable-output-escaping="yes" select="body"/>
+-			</span>
+-		</div>
+-	</xsl:template>
+-</xsl:stylesheet>
+-
+--- kopete/styles/iChat.xsl	(revision 568672)
++++ kopete/styles/iChat.xsl	(revision 586398)
+@@ -1,714 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+-  <xsl:output method="html"/>
+-  <xsl:param name="appdata"/>
+-
+-  <!-- You need a trailing slash on directories for the following 5 options -->
+-  <!-- Change iChat to iChat-Trans for the transparent images -->
+-  <xsl:variable name="image-location"><xsl:value-of select="$appdata"/>/iChat-Trans/</xsl:variable>
+-  <xsl:variable name="from-color-scheme">graphite/</xsl:variable>
+-  <xsl:variable name="to-color-scheme">blue/</xsl:variable>
+-  <xsl:variable name="action-color-scheme">purple/</xsl:variable>
+-  <xsl:variable name="system-color-scheme">clear/</xsl:variable>
+-  <xsl:variable name="highlight-color-scheme">yellow/</xsl:variable>
+-
+-  <xsl:variable name="allow-user-colors">yes</xsl:variable>
+-  <xsl:variable name="public-names">yes</xsl:variable>
+-  <xsl:variable name="show-timestamps">yes</xsl:variable>
+-
+-  <!-- Blank these values and it should use Kopete's settings (temporary workaround) -->
+-  <xsl:variable name="font-size"></xsl:variable>
+-  <xsl:variable name="font-family"></xsl:variable>
+-  <xsl:variable name="name-font-size">0.8em</xsl:variable>
+-  <xsl:variable name="timestamp-font-size">0.8em</xsl:variable>
+-  <xsl:variable name="timestamp-color"></xsl:variable>
+-
+-  <xsl:template match="message">
+-    <div class="KopeteMessage" style="padding-bottom:0px;">
+-      <xsl:attribute name="id">
+-        <xsl:value-of select="@id"/>
+-      </xsl:attribute>
+-      <xsl:choose>
+-        <xsl:when test="@direction='0'">
+-          <!-- Incoming Message -->
+-          <table width="100%" border="0" cellspacing="0" cellpadding="0" style="margin-bottom: 5px;">
+-            <tr>
+-              <td colspan="2" align="center">
+-                <span>
+-                  <xsl:attribute name="style">
+-                    <xsl:text>font-family:</xsl:text>
+-                    <xsl:value-of select="$font-family"/>
+-                    <xsl:text>;font-size:</xsl:text>
+-                    <xsl:value-of select="$timestamp-font-size"/>
+-                    <xsl:text>;color:</xsl:text>
+-                    <xsl:value-of select="$timestamp-color"/>
+-                  </xsl:attribute>
+-                  <xsl:value-of select="@time"/>
+-                </span>
+-              </td>
+-            </tr>
+-            <tr>
+-              <td width="32" valign="bottom" align="center">
+-	        <a style="text-decoration:none;" class="KopeteDisplayName">
+-		<xsl:attribute name="href">kopetemessage://<xsl:value-of select="from/contact/contactDisplayName/@text"/></xsl:attribute>
+-		<xsl:attribute name="contactid"><xsl:value-of select="from/contact/@contactId"/></xsl:attribute>
+-		<xsl:choose>
+-			<xsl:when test="from/contact/@userPhoto">
+-			    <img style="height:48px;margin:4px;margin-bottom:0px;border:1px solid black;">
+-				<xsl:attribute name="src">data:image/png;base64,<xsl:value-of select="from/contact/@userPhoto"/></xsl:attribute>
+-			    </img>
+-			</xsl:when>
+-			<xsl:otherwise>
+-				<img height="32" width="32">
+-				  <xsl:attribute name="src">
+-				   <xsl:value-of select="$image-location" />
+-				   <xsl:value-of select="$from-color-scheme" />
+-				   <xsl:text>them.png</xsl:text>
+-				  </xsl:attribute>
+-				  <xsl:attribute name="title">
+-				    <xsl:value-of select="from/contact/contactDisplayName/@text"/>
+-				  </xsl:attribute>
+-				</img>
+-		    	</xsl:otherwise>
+-		</xsl:choose>
+-		<xsl:if test="$public-names='yes'">
+-		      <span>
+-			<xsl:attribute name="style">
+-			  <xsl:text>font-family:</xsl:text>
+-			  <xsl:value-of select="$font-family"/>
+-			  <xsl:text>;font-size:</xsl:text>
+-			  <xsl:value-of select="$name-font-size"/>
+-			  <xsl:text>;</xsl:text>
+-			</xsl:attribute>
+-			<xsl:value-of select="from/contact/contactDisplayName/@text"/>
+-		      </span>
+-                 </xsl:if>
+-		</a>
+-              </td>
+-              <td>
+-                <table cellpadding="0" cellspacing="0" border="0" align="left">
+-                  <tr>
+-                    <td height="12" width="21">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/tl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/tm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/tr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="14" width="21">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/ml.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td>
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/mm.png</xsl:text>
+-                      </xsl:attribute>
+-                      <span>
+-                        <xsl:attribute name="dir">
+-                          <xsl:value-of select="body/@dir"/>
+-                        </xsl:attribute>
+-                        <xsl:attribute name="style">
+-                          <xsl:text>font-size:</xsl:text>
+-                          <xsl:value-of select="$font-size" />
+-                          <xsl:text>;</xsl:text>
+-                          <xsl:choose>
+-                            <xsl:when test="$allow-user-colors='yes'">
+-                              <xsl:if test="body/@color">
+-                                <xsl:text>color:</xsl:text>
+-                                <xsl:value-of select="body/@color"/>
+-                                <xsl:text>;</xsl:text>
+-                              </xsl:if>
+-                              <xsl:if test="body/@bgcolor">
+-                                <xsl:text>background-color:</xsl:text>
+-                                <xsl:value-of select="body/@bgcolor"/>
+-                                <xsl:text>;</xsl:text>
+-                              </xsl:if>
+-                              <xsl:if test="body/@font">
+-                                <xsl:value-of select="body/@font"/>
+-                                <xsl:text>; </xsl:text>
+-                              </xsl:if>
+-                            </xsl:when>
+-                            <xsl:otherwise>
+-                              <xsl:text>font-family:'</xsl:text>
+-                              <xsl:value-of select="$font-family" />
+-                              <xsl:text>';</xsl:text>
+-                              <xsl:text>color:black;</xsl:text>
+-                              <xsl:text>background-color:transparent;</xsl:text>
+-                            </xsl:otherwise>
+-                          </xsl:choose>
+-                        </xsl:attribute>
+-                        <xsl:value-of disable-output-escaping="yes" select="body"/>
+-                      </span>
+-                    </td>
+-                    <td height="14" width="17">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/mr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="12" width="21">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/bl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/bm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:choose>
+-                          <xsl:when test="@importance='2'">
+-                            <xsl:value-of select="$highlight-color-scheme"/>
+-                          </xsl:when>
+-                          <xsl:otherwise>
+-                            <xsl:value-of select="$from-color-scheme" />
+-                          </xsl:otherwise>
+-                        </xsl:choose>
+-                        <xsl:text>From/br.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                </table>
+-              </td>
+-            </tr>
+-          </table>
+-        </xsl:when>
+-        <xsl:when test="@direction='1'">
+-          <!-- Outgoing Message -->
+-          <table width="100%" border="0" cellspacing="0" cellpadding="0" style="margin-bottom: 5px;">
+-            <tr>
+-              <td colspan="2" align="center">
+-                <span>
+-                  <xsl:attribute name="style">
+-                    <xsl:text>font-family:</xsl:text>
+-                    <xsl:value-of select="$font-family"/>
+-                    <xsl:text>;font-size:</xsl:text>
+-                    <xsl:value-of select="$timestamp-font-size"/>
+-                    <xsl:text>;color:</xsl:text>
+-                    <xsl:value-of select="$timestamp-color"/>
+-                  </xsl:attribute>
+-                  <xsl:value-of select="@time"/>
+-                </span>
+-              </td>
+-            </tr>
+-            <tr>
+-              <td>
+-                <table cellpadding="0" cellspacing="0" border="0" align="right">
+-                  <tr>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:value-of select="$to-color-scheme" />
+-                        <xsl:text>To/tl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:value-of select="$to-color-scheme" />
+-                        <xsl:text>To/tm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="21">
+-                      <xsl:attribute name="background">
+-                        <xsl:value-of select="$image-location" />
+-                        <xsl:value-of select="$to-color-scheme" />
+-                        <xsl:text>To/tr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="14" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/ml.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td>
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/mm.png</xsl:text>
+-                      </xsl:attribute>
+-                      <span>
+-                        <xsl:attribute name="dir">
+-                          <xsl:value-of select="body/@dir"/>
+-                        </xsl:attribute>
+-                        <xsl:attribute name="style">
+-                          <xsl:text>font-size:</xsl:text>
+-                          <xsl:value-of select="$font-size" />
+-                          <xsl:text>;</xsl:text>
+-                          <xsl:choose>
+-                            <xsl:when test="$allow-user-colors='yes'">
+-                              <xsl:if test="body/@color">
+-                                <xsl:text>color:</xsl:text>
+-                                <xsl:value-of select="body/@color"/>
+-                                <xsl:text>;</xsl:text>
+-                              </xsl:if>
+-                              <xsl:if test="body/@bgcolor">
+-                                <xsl:text>background-color:</xsl:text>
+-                                <xsl:value-of select="body/@bgcolor"/>
+-                                <xsl:text>;</xsl:text>
+-                              </xsl:if>
+-                              <xsl:if test="body/@font">
+-                                <xsl:text>; </xsl:text>
+-                                <xsl:value-of select="body/@font"/>
+-                              </xsl:if>
+-                            </xsl:when>
+-                            <xsl:otherwise>
+-                              <xsl:text>font-family:'</xsl:text>
+-                              <xsl:value-of select="$font-family" />
+-                              <xsl:text>';</xsl:text>
+-                              <xsl:text>color:black;</xsl:text>
+-                              <xsl:text>background-color:transparent;</xsl:text>
+-                            </xsl:otherwise>
+-                          </xsl:choose>
+-                        </xsl:attribute>
+-                        <xsl:value-of disable-output-escaping="yes" select="body"/>
+-                      </span>
+-                    </td>
+-                    <td height="14" width="21">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/mr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/bl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/bm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="21">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$to-color-scheme" />
+-                       <xsl:text>To/br.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                </table>
+-              </td>
+-              <td width="32" valign="bottom">
+-		<a style="text-decoration:none;" class="KopeteDisplayName">
+-		<xsl:attribute name="href">kopetemessage://<xsl:value-of select="from/contact/contactDisplayName/@text"/></xsl:attribute>
+-		<xsl:attribute name="contactid"><xsl:value-of select="from/contact/@contactId"/></xsl:attribute>
+-		<xsl:choose>
+-		    <xsl:when test="from/contact/@userPhoto">
+-                        <img style="height:48px;margin:4px;margin-bottom:0px;border:1px solid black;">
+-			  <xsl:attribute name="src">data:image/png;base64,<xsl:value-of select="from/contact/@userPhoto"/></xsl:attribute>
+-			</img>
+-		    </xsl:when>
+-		    <xsl:otherwise>
+-			<img height="32" width="32">
+-			    <xsl:attribute name="src">
+-				<xsl:value-of select="$image-location" />
+-				<xsl:value-of select="$from-color-scheme" />
+-				<xsl:text>me.png</xsl:text>
+-			    </xsl:attribute>
+-			    <xsl:attribute name="title">
+-				<xsl:value-of select="from/contact/contactDisplayName/@text"/>
+-			    </xsl:attribute>
+-			</img>
+-		    </xsl:otherwise>
+-		</xsl:choose>
+-		</a>
+-              </td>
+-            </tr>
+-          </table>
+-        </xsl:when>
+-        <xsl:when test="@direction='2'">
+-          <!-- Internal Message -->
+-          <table width="100%" border="0" cellspacing="0" cellpadding="0" style="margin-bottom: 5px;">
+-            <tr>
+-              <td colspan="2" align="center">
+-                <span>
+-                  <xsl:attribute name="style">
+-                    <xsl:text>font-family:</xsl:text>
+-                    <xsl:value-of select="$font-family"/>
+-                    <xsl:text>;font-size:</xsl:text>
+-                    <xsl:value-of select="$timestamp-font-size"/>
+-                    <xsl:text>;color:</xsl:text>
+-                    <xsl:value-of select="$timestamp-color"/>
+-                  </xsl:attribute>
+-                  <xsl:value-of select="@time"/>
+-                </span>
+-              </td>
+-            </tr>
+-            <tr>
+-              <td>
+-                <table cellpadding="0" cellspacing="0" border="0" align="center">
+-                  <tr>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/tl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/tm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>From/tr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="14" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/ml.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td>
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/mm.png</xsl:text>
+-                      </xsl:attribute>
+-                      <span>
+-                        <xsl:attribute name="dir">
+-                          <xsl:value-of select="body/@dir"/>
+-                        </xsl:attribute>
+-                        <xsl:attribute name="style">
+-                          <xsl:text>color:black;</xsl:text>
+-                          <xsl:text>background-color:transparent;</xsl:text>
+-                          <xsl:text>font-size:</xsl:text>
+-                          <xsl:value-of select="$font-size" />
+-                          <xsl:text>;</xsl:text>
+-                          <xsl:text>font-family:'</xsl:text>
+-                          <xsl:value-of select="$font-family" />
+-                          <xsl:text>';</xsl:text>
+-                        </xsl:attribute>
+-                        <xsl:value-of disable-output-escaping="yes" select="body"/>
+-                      </span>
+-                    </td>
+-                    <td height="14" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>From/mr.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                  <tr>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/bl.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>To/bm.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                    <td height="12" width="17">
+-                      <xsl:attribute name="background">
+-                       <xsl:value-of select="$image-location" />
+-                       <xsl:value-of select="$system-color-scheme" />
+-                       <xsl:text>From/br.png</xsl:text>
+-                      </xsl:attribute>
+-                    </td>
+-                  </tr>
+-                </table>
+-              </td>
+-            </tr>
+-          </table>
+-        </xsl:when>
+-        <xsl:when test="@direction='3'">
+-          <!-- Action Message -->
+-              <table width="100%" border="0" cellspacing="0" cellpadding="0" style="margin-bottom: 5px;">
+-                <tr>
+-                  <td colspan="2" align="center">
+-                    <span>
+-                      <xsl:attribute name="style">
+-                        <xsl:text>font-family:</xsl:text>
+-                        <xsl:value-of select="$font-family"/>
+-                        <xsl:text>;font-size:</xsl:text>
+-                        <xsl:value-of select="$timestamp-font-size"/>
+-                        <xsl:text>;color:</xsl:text>
+-                        <xsl:value-of select="$timestamp-color"/>
+-                      </xsl:attribute>
+-                      <xsl:value-of select="@time"/>
+-                    </span>
+-                  </td>
+-                </tr>
+-                <tr>
+-                  <td width="32" valign="bottom">
+-		    <a style="text-decoration:none;" class="KopeteDisplayName">
+-		    <xsl:attribute name="href">kopetemessage://<xsl:value-of select="from/contact/contactDisplayName/@text"/></xsl:attribute>
+-		    <xsl:attribute name="contactid"><xsl:value-of select="from/contact/@contactId"/></xsl:attribute>
+-			<xsl:choose>
+-				<xsl:when test="from/contact/@userPhoto">
+-				    <img style="height:48px;margin:4px;margin-bottom:0px;;border:1px solid black;">
+-				      <xsl:attribute name="src">data:image/png;base64,<xsl:value-of select="from/contact/@userPhoto"/></xsl:attribute>
+-				    </img>
+-				</xsl:when>
+-				<xsl:otherwise>
+-				    <img height="32" width="32">
+-					<xsl:attribute name="src">
+-					    <xsl:value-of select="$image-location" />
+-					    <xsl:value-of select="$from-color-scheme" />
+-					    <xsl:text>them.png</xsl:text>
+-					</xsl:attribute>
+-					<xsl:attribute name="title">
+-					    <xsl:value-of select="from/contact/contactDisplayName/@text"/>
+-					</xsl:attribute>
+-				    </img>
+-				</xsl:otherwise>
+-			</xsl:choose>
+-		    </a>
+-                  </td>
+-                  <td>
+-                    <table cellpadding="0" cellspacing="0" border="0" align="left">
+-                      <tr>
+-                        <td height="12" width="21">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/tl.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                        <td height="12">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/tm.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                        <td height="12" width="17">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/tr.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                      </tr>
+-                      <tr>
+-                        <td height="14" width="21">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/ml.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                        <td>
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/mm.png</xsl:text>
+-                          </xsl:attribute>
+-                          <span>
+-                            <xsl:attribute name="dir">
+-                              <xsl:value-of select="body/@dir"/>
+-                            </xsl:attribute>
+-                            <xsl:attribute name="style">
+-                              <xsl:text>font-size:</xsl:text>
+-                              <xsl:value-of select="$font-size" />
+-                              <xsl:text>;</xsl:text>
+-                              <xsl:choose>
+-                                <xsl:when test="$allow-user-colors='yes'">
+-                                  <xsl:if test="body/@color">
+-                                    <xsl:text>color:</xsl:text>
+-                                    <xsl:value-of select="body/@color"/>
+-                                    <xsl:text>;</xsl:text>
+-                                  </xsl:if>
+-                                  <xsl:if test="body/@bgcolor">
+-                                    <xsl:text>background-color:</xsl:text>
+-                                    <xsl:value-of select="body/@bgcolor"/>
+-                                    <xsl:text>;</xsl:text>
+-                                  </xsl:if>
+-                                  <xsl:if test="body/@font">
+-                                    <xsl:text>; </xsl:text>
+-                                    <xsl:value-of select="body/@font"/>
+-                                  </xsl:if>
+-                                </xsl:when>
+-                                <xsl:otherwise>
+-                                  <xsl:text>font-family:'</xsl:text>
+-                                  <xsl:value-of select="$font-family" />
+-                                  <xsl:text>';</xsl:text>
+-                                  <xsl:text>color:black;</xsl:text>
+-                                  <xsl:text>background-color:transparent;</xsl:text>
+-                                </xsl:otherwise>
+-                              </xsl:choose>
+-                            </xsl:attribute>
+-                            <xsl:text>*&#160;</xsl:text>
+-                            <xsl:value-of disable-output-escaping="yes" select="body"/>
+-                            <xsl:text>&#160;*</xsl:text>
+-                          </span>
+-                        </td>
+-                        <td height="14" width="17">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/mr.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                      </tr>
+-                      <tr>
+-                        <td height="12" width="21">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/bl.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                        <td height="12">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/bm.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                        <td height="12" width="17">
+-                          <xsl:attribute name="background">
+-                           <xsl:value-of select="$image-location" />
+-                           <xsl:value-of select="$action-color-scheme" />
+-                           <xsl:text>From/br.png</xsl:text>
+-                          </xsl:attribute>
+-                        </td>
+-                      </tr>
+-                    </table>
+-                  </td>
+-                </tr>
+-                <xsl:choose>
+-                  <xsl:when test="$public-names='yes'">
+-                    <tr>
+-                      <td colspan="2">
+-                        <span>
+-                          <xsl:attribute name="style">
+-                            <xsl:text>font-family:</xsl:text>
+-                            <xsl:value-of select="$font-family"/>
+-                            <xsl:text>;font-size:</xsl:text>
+-                            <xsl:value-of select="$name-font-size"/>
+-                            <xsl:text>;</xsl:text>
+-                          </xsl:attribute>
+-                          <xsl:value-of select="from/contact/contactDisplayName/@text"/>
+-                        </span>
+-                      </td>
+-                    </tr>
+-                  </xsl:when>
+-                  <xsl:otherwise>
+-                  </xsl:otherwise>
+-                </xsl:choose>
+-              </table>
+-        </xsl:when>
+-        <xsl:otherwise>
+-          <xsl:value-of disable-output-escaping="yes" select="body"/>
+-        </xsl:otherwise>
+-      </xsl:choose>
+-    </div>
+-  </xsl:template>
+-</xsl:stylesheet>
+--- kopete/styles/Konqi/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Konqi/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,2 @@
++(%time{%H:%M:%S}%) : %message%
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="contenu_incoming">
++    <div class="corps_message" >
++	<img class="avatar" height="70" src="%userIconPath%"/>
++	<div class="texte" style="direction: %messageDirection%;">
++	<div class="nom">%sender%</div>
++	  (%time{%H:%M:%S}%) : %message%<br>
++	<div id="insert"></div>
++	</div>
++    </div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,4 @@
++  <div class="status">
++    <img src="puce.png" valign="middle">%time{%H:%M:%S}% : %message% 
++  </div>    
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_blue.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_blue.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #000000 url(konqui/konqui-blue.png) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre3.png");
++	border: 2px solid #365396;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre3.png");
++	border: 2px solid #365396;
++}
++
++.status
++{
++	background-color: transparent;
++	color: white;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_green_without_trans.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_green_without_trans.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-green.png) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre1.png");
++	border: 2px solid #194C15;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre1.png");
++	border: 2px solid #194C15;
++}
++
++.status
++{
++	background-color: transparent;
++	color: black;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_moon_without_transparency.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_moon_without_transparency.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-moon.jpg) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre6.png");
++	border: 2px solid #365396;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre6.png");
++	border: 2px solid #365396;
++}
++
++.status
++{
++	background-color: transparent;
++	color: white;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/konqui/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/konqui/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = cadre1.png cadre2.png cadre3.png cadre4.png cadre5.png cadre6.png konqui-blue.png konqui-green.png konqui-moon.jpg
++styledir = $(kde_datadir)/kopete/styles/Konqi/Contents/Resources/Variants/konqui
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_green_without_transparency.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_green_without_transparency.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-green.png) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre1.png");
++	border: 2px solid #194C15;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre1.png");
++	border: 2px solid #194C15;
++}
++
++.status
++{
++	background-color: transparent;
++	color: black;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = konqui
++style_DATA = Side_blue_moon.css Side_blue_without_transparency.css Side_green_without_trans.css Side_blue.css  Side_blue_moon_without_transparency.css Side_green.css Side_green_without_transparency.css
++styledir = $(kde_datadir)/kopete/styles/Konqi/Contents/Resources/Variants
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_moon.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_moon.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-moon.jpg) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre5.png");
++	border: 2px solid #2F4883;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre5.png");
++	border: 2px solid #2F4883;
++}
++
++.status
++{
++	background-color: transparent;
++	color: white;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_green.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_green.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-green.png) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre2.png");
++	border: 2px solid #194C15;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre2.png");
++	border: 2px solid #194C15;
++}
++
++.status
++{
++	background-color: transparent;
++	color: black;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_without_transparency.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Variants/Side_blue_without_transparency.css	(revision 586398)
+@@ -0,0 +1,39 @@
++body {	
++	background: #FFFFFF url(konqui/konqui-blue.png) fixed;
++	background-repeat : no-repeat;
++	background-size : 100% auto;
++	background-position : bottom right;
++}
++
++.contenu_incoming .corps_message
++{
++	background-color: transparente;
++	color: black; 
++	background: url("konqui/cadre4.png");
++	border: 2px solid #365396;
++}
++
++.contenu_outgoing .corps_message
++{
++	background-color: transparente;
++	color: black; 	
++	background: url("konqui/cadre4.png");
++	border: 2px solid #365396;
++}
++
++.status
++{
++	background-color: transparent;
++	color: white;
++}
++
++.nom 
++{
++	color: #0000FF;
++}
++
++.texte 
++{
++    	text-shadow: 1px 1px 3px #000000;
++    	color: white;
++}
+--- kopete/styles/Konqi/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = Incoming Outgoing Variants
++style_DATA = main.css Footer.html Header.html Status.html puce.png
++styledir = $(kde_datadir)/kopete/styles/Konqi/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Konqi/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Konqi/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,2 @@
++(%time{%H:%M:%S}%) : %message%
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="contenu_outgoing">
++    <div class="corps_message">
++	<img class="avatar" height="70" src="%userIconPath%"/>
++	<div class="texte" style="direction: %messageDirection%;">
++	<div class="nom">%sender%</div>
++	  (%time{%H:%M:%S}%) : %message%<br>
++	<div id="insert"></div>
++	</div>
++    </div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Konqi/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Konqi/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,50 @@
++body 
++{
++	font-family:Verdana, sans-serif;
++	font-size : 12px;
++}
++
++.contenu_incoming .corps_message
++{
++	text-decoration: none; 
++	padding-top: 2 px;
++	margin: 5px 15px 5px 15px;
++}
++
++.contenu_outgoing .corps_message
++{
++	text-decoration: none; 
++	padding-top: 2 px;
++	margin: 5px 15px 5px 15px;
++}
++
++.status
++{
++	margin-left: 15px;
++	font: 11px Verdana, sans-serif;
++}
++
++.avatar 
++{
++    	position: relative;
++    	top: 0;
++    	left: 0;
++	height: 80px;
++}
++
++.nom 
++{
++	position:relative;
++	top: -35px;
++	margin-bottom: -30px;
++	z-index:2;
++}
++    
++.texte
++{
++	position:relative;
++	top: -35px;
++	margin-left: 100px;
++	margin-bottom: -10px;
++	z-index:1;
++}
+\ No newline at end of file
+--- kopete/styles/Clean/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="IncomingAction" style="direction: %messageDirection%;">
++		<!-- Protocol Icon -->
++		<img class="inActionIcon" src="images/action.png" />
++		<!-- MetaContact display -->
++		<span class="inActionMetacontact">%sender% &#160;</span>
++		<!-- Action message -->
++		<span class="inActionMessage">%message%</span>
++		<!-- Time Display -->
++		<span class="inTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++</div>
++	
+--- kopete/styles/Clean/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Clean/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div class="NextIncomingMessage" style="direction: %messageDirection%;">%message%</div>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Clean/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,21 @@
++<div class="KopeteMessage">
++	<div class="IncomingMessageHeader" style="border-color: %senderColor%">
++		<!-- Protocol Icon -->
++		<img class="inStatusIcon" src="%senderStatusIcon%" />
++		<!-- Time Display -->
++		<div class="inTime">%time%</div>
++		<!-- MetaContact display -->
++		<div class="inMetacontact">%sender% &#160;</div>
++	</div>
++	<div class="IncomingMessage" style="direction: %messageDirection%;">
++		<!-- Contact photo -->
++		<img class="inUserPicture" src="%userIconPath%" />
++		%message%
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++		<div style="clear: both;">&nbsp;</div>
++
++	</div>
++
++</div>
++	
+--- kopete/styles/Clean/Contents/Resources/images/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/images/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = action.png important.png internal.png
++styledir = $(kde_datadir)/kopete/styles/Clean/Contents/Resources/images
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="KopeteMessage">
++	<div class="InternalMessageHeader" style="direction: %messageDirection%;">
++		<img class="systemLogo" src="images/internal.png" />
++		
++			<span class="InternalMessage">%message%</span>
++			<div class="InternalMessageHeaderTime">%time%</div>
++		
++		
++	</div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = images Incoming Outgoing
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Clean/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clean/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="OutgoingAction" style="direction: %messageDirection%;">
++		<!-- Protocol Icon -->
++		<img class="outActionIcon" src="images/action.png" />
++		<!-- MetaContact display -->
++		<span class="outActionMetacontact">%sender% &#160;</span>
++		<!-- Action message -->
++		<span class="outActionMessage">%message%</span>
++		<!-- Time Display -->
++		<span class="outTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++</div>
++	
+--- kopete/styles/Clean/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Clean/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Clean/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div class="NextOutgoingMessage" style="direction: %messageDirection%;">%message%</div>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Clean/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,21 @@
++<div class="KopeteMessage">
++	<div class="OutgoingMessageHeader">
++		<!-- Protocol Icon -->
++		<img class="outStatusIcon" src="%senderStatusIcon%" />
++		<!-- Time Display -->
++		<div class="outTime">%time%</div>
++		<!-- MetaContact display -->
++		<div class="outMetacontact">%sender% &#160;</div>
++	</div>
++	<div class="OutgoingMessage" style="direction: %messageDirection%;">
++		<!-- Contact photo -->
++		<img class="outUserPicture" src="%userIconPath%" />
++		%message%
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++		<div style="clear: both;">&nbsp;</div>
++	</div>
++
++</div>
++	
++ 
+--- kopete/styles/Clean/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Clean/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,169 @@
++.KopeteMessage
++{
++	margin:1.4em .2em 0 .2em;
++}
++
++.IncomingMessageHeader
++{
++	padding-left: 1ex; 
++	padding-right: 1ex;
++	border-bottom: 0.1em solid;
++}
++
++.IncomingMessage
++{
++	padding-left: 1ex;
++	padding-right: 1ex;
++	padding-top: 0.25em;
++}
++
++.NextIncomingMessage
++{
++	padding-left: 1ex;
++	padding-right: 1ex;
++	padding-top: 0.25em;
++	padding-bottom: 0.5em;
++}
++
++.inUserPicture
++{
++	float: left;
++	border: 1px solid #888;
++	height: 4.30em;
++	margin-top: 0.25em;
++	border: 0.1em solid black;
++	margin-left: 0.2em;
++	margin-right: 1ex;
++
++}
++
++.inStatusIcon
++{
++	float: left;
++	padding-right: 1ex;
++}
++
++.inTime
++{
++	float: right;
++}
++.inMetacontact
++{
++	padding-left: 1ex;
++	font-weight: bold;
++}
++
++.IncomingAction
++{
++	padding-left: 1ex; 
++	padding-right: 1ex; 
++	border-bottom: 0.1em dashed #ffafaf;
++}
++.inActionIcon
++{
++	float: left;
++	margin-right: 5px;
++}
++.inActionMetacontact
++{
++	margin-left: 5px;
++	font-weight: bold;
++}
++.inActionMessage
++{
++
++}
++
++.OutgoingMessageHeader
++{
++	padding-left: 1ex; padding-right: 1ex;
++	border-bottom: 0.1em solid #ffafaf;
++}
++
++.OutgoingMessage
++{
++	padding-left: 1ex;
++	padding-right: 1ex;
++	padding-top: 0.25em;
++	padding-bottom: 0.5em;
++}
++
++.NextOutgoingMessage
++{
++	padding-left: 1ex;
++	padding-right: 1ex;
++	padding-top: 0.25em;
++	padding-bottom: 0.5em;
++}
++
++.outUserPicture
++{
++	float: left;
++	border: 1px solid #888;
++	height: 4.30em;
++	margin-top: 0.2em;
++	margin-left: 0.2em;
++	margin-right: 1ex;
++}
++
++.outStatusIcon
++{
++	float: left;
++	padding-right: 1ex;
++}
++
++.outTime
++{
++	float: right;
++}
++.outMetacontact
++{
++	margin-left: 15px;
++	font-weight: bold;
++}
++
++.OutgoingAction
++{
++	padding-left: 1ex; 
++	padding-right: 1ex; 
++	border-bottom: 0.1em dashed #ffafaf;
++}
++.outActionIcon
++{
++	float: left;
++	padding-right: 1ex;
++}
++.outActionMetacontact
++{
++	margin-left: 10px;
++	font-weight: bold;
++}
++.outActionMessage
++{
++}
++
++.InternalMessageHeader
++{
++	padding-left: 1ex; 
++	padding-right: 1ex; 
++	border-bottom: 0.1em dashed #afffaf;
++}
++
++.InternalMessage
++{
++	width: 80%;
++	text-align: left;
++}
++
++.InternalMessageHeaderTime
++{
++	float: right; 
++}
++
++.systemLogo
++{
++	float: left;
++	vertical-align: middle;
++	padding-right: 1ex;
++}
++
+--- kopete/styles/Clear/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="IncomingAction">
++		<span class="IncomingActionBody">
++			<!-- MetaContact display -->
++			<span class="inActionMetacontact">%sender% &#160;</span>
++			<!-- Action message -->
++			<span class="inActionMessage">%message%</span>
++		</span>
++		<!-- Time Display -->
++		<span class="IncomingActionTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<!-- <div id="insert" /> -->
++</div>
++	
+--- kopete/styles/Clear/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html Action.html
++styledir = $(kde_datadir)/kopete/styles/Clear/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div class="NextIncomingMessage"><img src="images/body-inbound-arrow.png" style="padding-bottom: 2px; vertical-align: middle;"/>%message%</div>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Clear/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,33 @@
++<div class="KopeteMessage">
++	<div class="IncomingMessageHeader">
++		<div class="IncomingMessageHeader1">
++			<div class="IncomingMessageHeader2">
++				<!-- MetaContact display -->
++				<span class="inMetacontact">%sender% &#160;</span>
++				<!-- Time Display -->
++				<span class="inTime">%time%</span>
++			</div>
++		</div>
++	</div>
++	<div class="IncomingBody">
++		<div class="IncomingBody1">
++			<div class="IncomingBody2">
++				<div class="inUserPicture">
++				<!-- Contact photo -->
++				<img  width="46" height="46" src="%userIconPath%" />
++				</div>
++				<div class="IncomingMessage"  style="direction: %messageDirection%;">
++				<img src="images/body-inbound-arrow.png" style="padding-bottom: 2px; vertical-align: middle;"/>%message%
++				</div>
++				<!-- For support of consecutive messages -->
++				<div id="insert" />
++			</div>
++		</div>
++	</div>
++	<div class="IncomingFooter">
++		<div class="IncomingFooter1">
++			<div id="IncomingFooter2" />
++		</div>
++	</div>
++
++</div>
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/images/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/images/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = body-background.png footer-outbound-right.png body-inbound-arrow.png header-inbound-background.png body-inbound-avatar.png header-inbound-left.png  body-inbound-background.png header-inbound-right.png body-inbound-left.png           header-outbound-background.png body-inbound-right.png header-outbound-left.png body-outbound-arrow.png header-outbound-right.png body-outbound-avatar.png icon-action.png body-outbound-left.png icon-highlighted.png body-outbound-right.png icon-internal.png footer-inbound-background.png icon-me.png footer-inbound-left.png icon-time.png footer-inbound-right.png icon-you.png footer-outbound-background.png footer-outbound-left.png
++styledir = $(kde_datadir)/kopete/styles/Clear/Contents/Resources/images
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage">
++	<div class="InternalMessageHeader">
++		<span class="InternalMessage">%message%</span>
++		<div class="InternalMessageHeaderTime">%time%</div>
++	</div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/Variants/No avatars.css	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Variants/No avatars.css	(revision 586398)
+@@ -0,0 +1,23 @@
++.IncomingBody2
++{
++	min-height: 0;
++	padding-bottom: 7px;
++}
++
++.inUserPicture
++{
++	display: none;
++	float: none;
++}
++
++.OutgoingBody2
++{
++	min-height: 0;
++	padding-bottom: 7px;
++}
++
++.outUserPicture
++{
++	display: none;
++	float: none;
++}
+--- kopete/styles/Clear/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = images Incoming Outgoing
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Clear/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Clear/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="OutgoingAction">
++		<span class="OutgoingActionBody">
++			<!-- MetaContact display -->
++			<span class="outActionMetacontact">%sender% &#160;</span>
++			<!-- Action message -->
++			<span class="outActionMessage">%message%</span>
++		</span>
++		<!-- Time Display -->
++		<span class="OutgoingActionTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<!-- <div id="insert" /> -->
++</div>
++	
+--- kopete/styles/Clear/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html Action.html
++styledir = $(kde_datadir)/kopete/styles/Clear/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Clear/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div class="NextOutgoingMessage"><img src="images/body-outbound-arrow.png" style="padding-bottom: 2px; vertical-align: middle;"/>%message%</div>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Clear/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,32 @@
++<div class="KopeteMessage">
++	<div class="OutgoingMessageHeader">
++		<div class="OutgoingMessageHeader1">
++			<div class="OutgoingMessageHeader2">
++				<!-- MetaContact display -->
++				<span class="outMetacontact">%sender% &#160;</span>
++				<!-- Time Display -->
++				<span class="outTime">%time%</span>
++			</div>
++		</div>
++	</div>
++	<div class="OutgoingBody">
++		<div class="OutgoingBody1">
++			<div class="OutgoingBody2">
++				<div class="outUserPicture">
++				<!-- Contact photo -->
++				<img  width="46" height="46" src="%userIconPath%" />
++				</div>
++				<div class="OutgoingMessage"  style="direction: %messageDirection%;">
++				<img src="images/body-outbound-arrow.png" style="padding-bottom: 2px; vertical-align: middle;"/>%message%
++				</div>
++				<!-- For support of consecutive messages -->
++				<div id="insert" />
++			</div>
++		</div>
++	</div>
++	<div class="OutgoingFooter">
++		<div class="OutgoingFooter1">
++			<div id="OutgoingFooter2" />
++		</div>
++	</div>
++</div>
+--- kopete/styles/Clear/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Clear/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,376 @@
++.Chat
++{
++	letter-spacing: 1px;
++	font-family: arial;
++	font-size: 11px;
++	padding: 5px;
++
++}
++
++
++.KopeteMessage
++{
++	margin-left: 6px;
++	margin-right: 6px;
++	margin-bottom: 10px;
++}
++
++.IncomingMessageHeader
++{
++	background: url(images/header-inbound-background.png) repeat-x;
++	background-color: #c9d9f0;
++
++}
++.IncomingMessageHeader1
++{
++	background: url(images/header-inbound-left.png) no-repeat top left;
++	padding-left: 4px;
++
++}
++.IncomingMessageHeader2
++{
++	background: url(images/header-inbound-right.png) no-repeat top right;
++	padding-right: 4px;
++	padding-left: 4px;
++	vertical-align: middle;
++	line-height: 20px;
++	height: 20px;
++}
++.IncomingBody
++{
++	background: url(images/body-background.png) repeat-x top;
++	background-color: #f5f6fa;
++	border-bottom: 1px solid #c9d9f0;
++}
++.IncomingBody1
++{
++	background: url(images/body-inbound-left.png) no-repeat top left;
++}
++.IncomingBody2
++{
++	background: url(images/body-inbound-right.png) no-repeat top right;
++	padding: 5px;
++	min-height: 55px;
++}
++
++.IncomingMessage
++{
++            overflow: auto;
++            padding-left: 2px;
++            padding-right: 2px;
++}
++
++.NextIncomingMessage
++{
++           overflow: auto;
++            padding-left: 2px;
++            padding-right: 2px;
++}
++
++.inUserPicture
++{
++	float: left;
++	width: 60px;
++	height: 52px;
++	margin: -1px;
++	padding-top: 6px;
++	padding-left: 6px;
++	background: url(images/body-inbound-avatar.png) no-repeat top left;
++
++}
++
++.inStatusIcon
++{
++	float: left;
++	padding-right: 1ex;
++}
++
++.inTime
++{
++	background: url(images/icon-time.png) no-repeat center right;
++	position: relative;
++	padding-right: 18px;
++	padding-left: 5px;
++	text-align: right;
++	font-weight: bold;
++	font-size: 10px;
++	float: right;
++	z-index: 1;
++	color: #567199;
++}
++.inMetacontact
++{
++	position: absolute;
++	text-align: left; font-size: 10px; font-weight: bold;
++	padding-right: 20px;
++	padding-left: 20px;
++	overflow: hidden;
++	height: 20px;
++	background: url(images/icon-you.png) no-repeat center left;
++	color: #567199;
++}
++
++.IncomingFooter
++{
++	background: url(images/footer-inbound-background.png) repeat-x;
++	background-color: #ffffff;
++}
++.IncomingFooter1
++{
++	background: url(images/footer-inbound-left.png) no-repeat top left;
++	height: 9px;
++}
++.IncomingFooter2
++{
++	background: url(images/footer-inbound-right.png) no-repeat top right;	
++	height: 9px;
++}
++
++.IncomingAction
++{
++	background: #fafafa;
++	margin-left: 6px;
++	margin-right: 6px;
++	padding-left: 3px;
++	padding-right: 3px;
++	margin-bottom: 10px;
++	border: 1px solid #e0e0e0;
++	vertical-align: middle;
++	line-height: 20px;
++	height: 20px;
++}
++
++.IncomingActionBody
++{
++	position: absolute;
++	background: url(images/icon-action.png) no-repeat center left;
++	text-align: left; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 20px;
++	padding-left: 20px;
++	overflow: hidden;
++	height: 20px;
++	float: left;
++}
++
++.inActionMetacontact
++{
++/*	margin-left: 5px;
++	font-weight: bold;*/
++}
++.inActionMessage
++{
++
++}
++.IncomingActionTime
++{
++	position: relative;
++	background: url(images/icon-time.png) no-repeat center right;
++	text-align: right; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 18px;
++	padding-left: 5px;
++	float: right;
++	z-index: 1;
++}
++
++.OutgoingMessageHeader
++{
++	background: url(images/header-outbound-background.png) repeat-x;
++	background-color: #e1e1e1;
++
++}
++.OutgoingMessageHeader1
++{
++	background: url(images/header-outbound-left.png) no-repeat top left;
++	padding-left: 4px;
++}
++.OutgoingMessageHeader2
++{
++	background: url(images/header-outbound-right.png) no-repeat top right;
++	padding-right: 4px;
++	padding-left: 4px;
++	vertical-align: middle;
++	line-height: 20px;
++	height: 20px;
++}
++.OutgoingBody
++{
++	background: url(images/body-background.png) repeat-x top;
++	background-color: #f9f9f9;
++	border-bottom: 1px solid #e1e1e1;
++}
++.OutgoingBody1
++{
++	background: url(images/body-outbound-left.png) no-repeat top left;
++}
++.OutgoingBody2
++{
++	background: url(images/body-outbound-right.png) no-repeat top right;
++	padding: 5px;
++	min-height: 55px;
++}
++
++.OutgoingMessage
++{
++            overflow: auto;
++            padding-left: 2px;
++            padding-right: 2px;
++/* font:
++color:
++background-color:*/
++}
++
++.NextOutgoingMessage
++{
++           overflow: auto;
++            padding-left: 2px;
++            padding-right: 2px;
++}
++
++.outUserPicture
++{
++	float: left;
++	width: 60px;
++	height: 52px;
++	margin: -1px;
++	padding-top: 6px;
++	padding-left: 6px;
++	background: url(images/body-outbound-avatar.png) no-repeat top left;
++}
++
++.outStatusIcon
++{
++	float: left;
++	padding-right: 1ex;
++}
++
++.outTime
++{
++	background: url(images/icon-time.png) no-repeat center right;
++	position: relative;
++	padding-right: 18px;
++	padding-left: 5px;
++	text-align: right;
++	font-weight: bold;
++	font-size: 10px;
++	float: right;
++	z-index: 1;
++	color: #707070;
++}
++.outMetacontact
++{
++	position: absolute;
++	text-align: left; font-size: 10px; font-weight: bold;
++	padding-right: 20px;
++	padding-left: 20px;
++	overflow: hidden;
++	height: 20px;
++	background: url(images/icon-me.png) no-repeat center left;
++	color: #707070;
++}
++
++.OutgoingFooter
++{
++	background: url(images/footer-outbound-background.png) repeat-x;
++	background-color: #ffffff;
++}
++.OutgoingFooter1
++{
++	background: url(images/footer-outbound-right.png) no-repeat top right;
++	height: 9px;
++}
++.OutgoingFooter2
++{
++	background: url(images/footer-outbound-left.png) no-repeat top right;
++	height: 9px;
++}
++
++.OutgoingAction
++{
++	background: #fafafa;
++	margin-left: 6px;
++	margin-right: 6px;
++	padding-left: 3px;
++	padding-right: 3px;
++	margin-bottom: 10px;
++	border: 1px solid #e0e0e0;
++	vertical-align: middle;
++	line-height: 20px;
++	height: 20px;
++}
++
++.OutgoingActionBody
++{
++	position: absolute;
++	background: url(images/icon-action.png) no-repeat center left;
++	text-align: left; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 20px;
++	padding-left: 20px;
++	margin-left: 4px;
++	overflow: hidden;
++	height: 20px;
++	float: left;
++}
++
++.outActionMetacontact
++{
++	/*margin-left: 10px;
++	font-weight: bold;*/
++}
++.outActionMessage
++{
++}
++.OutgoingActionTime
++{
++	position: relative;
++	background: url(images/icon-time.png) no-repeat center right;
++	text-align: right; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 18px;
++	padding-left: 5px;
++	float: right;
++	z-index: 1;
++}
++.InternalMessageHeader
++{
++	background: #fafafa;
++	margin-left: 6px;
++	margin-right: 6px;
++	padding-left: 3px;
++	padding-right: 3px;
++	margin-bottom: 10px;
++	border: 1px solid #e0e0e0;
++	vertical-align: middle;
++	line-height: 20px;
++	height: 20px;
++}
++
++.InternalMessage
++{
++	position: absolute;
++	background: url(images/icon-internal.png) no-repeat center left;
++	text-align: left; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 20px;
++	padding-left: 20px;
++	margin-left: 4px;
++	overflow: hidden;
++	height: 20px;
++	float: left;
++}
++
++.InternalMessageHeaderTime
++{
++	position: relative;
++	background: url(images/icon-time.png) no-repeat center right;
++	text-align: right; font-size: 10px; font-weight: bold; color: #808080;
++	padding-right: 18px;
++	padding-left: 5px;
++	float: right;
++	z-index: 1;
++}
++
++.systemLogo
++{
++	float: left;
++	vertical-align: middle;
++	padding-right: 1ex;
++}
++
+--- kopete/styles/Kopete/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="IncomingAction" style="direction: %messageDirection%;">
++		<!-- Protocol Icon -->
++		<img class="inActionIcon" src="images/action.png" />
++		<!-- MetaContact display -->
++		<span class="inActionMetacontact">%sender% &#160;</span>
++		<!-- Action message -->
++		<span class="inActionMessage">%message%</span>
++		<!-- Time Display -->
++		<span class="inTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++</div>
++	
+--- kopete/styles/Kopete/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html Action.html
++styledir = $(kde_datadir)/kopete/styles/Kopete/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<li class="NextIncomingMessage" style="direction: %messageDirection%;">%message%</li>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Kopete/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,20 @@
++<div class="KopeteMessage">
++	<div style="padding:0;margin:0;border:none;border-color:%senderColor{180}% %senderColor{140}% %senderColor{140}% %senderColor{180}%;background-color:%senderColor{155}%">
++		<div class="IncomingMessageHeader">
++		<!-- Contact photo -->
++		<img class="inUserPicture" src="%userIconPath%" />
++		<!-- Protocol Icon -->
++		<img class="inStatusIcon" src="%senderStatusIcon%" />
++		<!-- Time Display -->
++		<div class="inTime">%time%</div>
++		<!-- MetaContact display -->
++		<div class="inMetacontact">%sender% &#160;</div>
++	</div>
++	</div>
++	<ul class="IncomingList" style="direction: %messageDirection%;">
++		<li class="IncomingMessage" style="direction: %messageDirection%;">%message%</li>
++		<!-- For support of consecutive messages -->
++		<div id="insert" />
++	</ul>	
++</div>
++	
+--- kopete/styles/Kopete/Contents/Resources/images/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/images/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = action.png important.png system.png
++styledir = $(kde_datadir)/kopete/styles/Kopete/Contents/Resources/images
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="KopeteMessage">
++	<div class="InternalMessageHeader" style="direction: %messageDirection%;">
++		<img class="systemLogo" src="images/system.png" />
++		
++			<span class="InternalMessage">%message%</span>
++			<div class="InternalMessageHeaderTime">%time%</div>
++		
++		
++	</div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Variants/Contact_color.css	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Variants/Contact_color.css	(revision 586398)
+@@ -0,0 +1,7 @@
++ @import url(../main.css);
++
++.IncomingMessageHeader /*, .OutgoingMessageHeader, .IncomingAction, .OutgoingAction*/
++{
++	background-color:inherit;
++	border-color:inherit;
++}
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Variants/Big_pictures.css	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Variants/Big_pictures.css	(revision 586398)
+@@ -0,0 +1,35 @@
++ @import url(../main.css);
++
++ .inUserPicture
++{
++	height: 96px;
++}
++
++.IncomingList, .OutgoingList
++{
++	/*margin-left: 110px;*/
++	margin-left :53px;
++}
++
++.IncomingMessage, .OutgoingMessage
++{
++
++}
++
++.NextIncomingMessage, .NextOutgoingMessage
++{
++
++}
++
++.outUserPicture
++{
++	height: 96px;
++}
++
++.KopeteMessage
++{
++	/*height: 96px;*/
++}
++
++
++
+--- kopete/styles/Kopete/Contents/Resources/Variants/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Variants/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++style_DATA = Big_pictures.css Contact_color.css
++
++styledir = $(kde_datadir)/kopete/styles/Kopete/Contents/Resources/Variants
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Kopete/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = images Incoming Outgoing Variants
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Kopete/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Kopete/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,16 @@
++<div class="KopeteMessage">
++	<div class="OutgoingAction" style="direction: %messageDirection%;">
++		<!-- Protocol Icon -->
++		<img class="outActionIcon" src="images/action.png" />
++		<!-- MetaContact display -->
++		<span class="outActionMetacontact">%sender% &#160;</span>
++		<!-- Action message -->
++		<span class="outActionMessage">%message%</span>
++		<!-- Time Display -->
++		<span class="outTime">%time%</span>
++
++	</div>
++	<!-- For support of consecutive messages -->
++	<div id="insert" />
++</div>
++	
+--- kopete/styles/Kopete/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = buddy_icon.png Content.html NextContent.html Action.html
++styledir = $(kde_datadir)/kopete/styles/Kopete/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Kopete/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<li class="NextOutgoingMessage" style="direction: %messageDirection%;">%message%</li>
++<!-- For support of consecutive messages -->
++<div id="insert" />
+--- kopete/styles/Kopete/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,21 @@
++<div class="KopeteMessage">
++	<div style="padding:0;margin:0;border:none;border-color:%senderColor{180}% %senderColor{140}% %senderColor{140}% %senderColor{180}%;background-color:%senderColor{155}%">
++	<div class="OutgoingMessageHeader">
++		<!-- Contact photo -->
++		<img class="outUserPicture" src="%userIconPath%" />
++		<!-- Protocol Icon -->
++		<img class="outStatusIcon" src="%senderStatusIcon%" />
++		<!-- Time Display -->
++		<div class="outTime">%time%</div>
++		<!-- MetaContact display -->
++		<div class="outMetacontact">%sender% &#160;</div>
++	</div>
++	</div>
++	<ul class="OutgoingList" style="direction: %messageDirection%;">
++		<li class="OutgoingMessage" style="direction: %messageDirection%;">%message%</li>
++		<!-- For support of consecutive messages -->
++		<div id="insert" />
++	</ul>
++</div>
++	
++ 
+--- kopete/styles/Kopete/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Kopete/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,211 @@
++.KopeteMessage
++{
++	margin:1.4em .2em 0 .2em;
++	clear: both;
++}
++
++.IncomingMessageHeader
++{
++	background-color:#dfedff;
++	padding:.1em;
++	border:solid;
++	border-color:#fafafa #d1dfef #d1dfef #fafafa;
++	border-width:2px;
++}
++
++.IncomingList, .OutgoingList
++{
++	margin-left: 5px;
++	padding-left: 40px;
++	padding-right: 5px;
++	padding-top: 0.25em;
++	padding-bottom: 0.5em;
++	line-height: 1.2em;
++	list-style: none;
++}
++
++
++.IncomingMessage, .NextIncomingMessage
++{
++	padding-left: 20px;
++	padding-right: 1ex;
++	padding-top: 0.2em;
++	padding-bottom: 0.2em;
++	line-height: 1.2em;
++	border-style: hidden; /* fix a strange bug*/
++	border-width: 0 0 1px 0;
++}
++
++
++.NextIncomingMessage
++{
++	margin-left: 17px;
++	padding-left: 20px;
++	border: dotted #d1dfef;
++	border-width: 1px 0 0 0;
++}
++
++.inUserPicture
++{
++	float: left;
++	border: 1px solid #888;
++	height: 48px;
++	margin-top: 0.2em;
++	margin-left: 0.2em;
++	margin-right: 1ex;
++}
++
++.inStatusIcon
++{
++	float: left;
++}
++
++.inTime
++{
++	float: right;
++}
++.inMetacontact
++{
++	margin-left: 60px;
++	font-weight: bold;
++}
++
++.IncomingAction
++{
++	border-top: 2px solid #dae5f0; 
++	border-right: 2px solid #aaccf0;
++	border-bottom: 2px solid #aaccf0;
++	border-left: 2px solid #dae5f0;
++	padding: 0.1em; 
++	vertical-align: middle;
++	background-color:#c3d9f0;
++}
++.inActionIcon
++{
++	float: left;
++	margin-right: 5px;
++}
++.inActionMetacontact
++{
++	margin-left: 10px;
++	font-weight: bold;
++}
++.inActionMessage
++{
++	margin-left: 1ex;
++}
++
++.OutgoingMessageHeader
++{
++	background-color:#f5f5f5;
++	padding:.1em;
++	border:solid;
++	border-color:#fafafa #e3e3e3 #e3e3e3 #fafafa;
++	border-width:2px;
++}
++
++.OutgoingMessage, .NextOutgoingMessage
++{
++	padding-left: 20px;
++	padding-right: 1ex;
++	padding-top: 0.2em;
++	padding-bottom: 0.2em;
++	line-height: 1.2em;
++	border-style: hidden; /* fix a strange bug*/
++	border-width: 0 0 1px 0;
++}
++
++.NextOutgoingMessage
++{
++	margin-left: 17px;
++	padding-left: 20px;
++	border: dotted #d1dfef;
++	border-width: 1px 0 0 0;
++}
++
++.outUserPicture
++{
++	float: left;
++	border: 1px solid #888;
++	height: 48px;
++	margin-top: 0.2em;
++	margin-left: 0.2em;
++	margin-right: 1ex;
++}
++
++.outStatusIcon
++{
++	float: left;
++}
++
++.outTime
++{
++	float: right;
++}
++.outMetacontact
++{
++	margin-left: 70px;
++	font-weight: bold;
++}
++
++.OutgoingAction
++{
++	border-top: 2px solid fafafa #cfcfcf; 
++	border-right: 2px solid fafafa #afafaf;
++	border-bottom: 2px solid fafafa #afafaf;
++	border-left: 2px solid fafafa #cfcfcf;
++	padding: 0.1em; 
++	vertical-align: middle;
++	background-color:#dedede;
++}
++.outActionIcon
++{
++	float: left;
++	margin-right: 5px;
++}
++.outActionMetacontact
++{
++	margin-left: 10px;
++	font-weight: bold;
++}
++.outActionMessage
++{
++	margin-left: 5px;
++}
++
++.InternalMessageHeader
++{
++	border-top: 0.1em dashed #afafaf; 
++	border-right: 0.1em dashed #afafaf;
++	border-bottom: 0.1em dashed #afafaf;
++	border-left: 0.1em dashed #afafaf;
++	padding-left: 0.1em; 
++	padding-bottom: 0.1em; 
++	padding-right: 0.1em; 
++	vertical-align: middle;
++}
++
++.InternalMessage
++{
++	width: 80%;
++	text-align: left;
++	font-size: 10px;
++	font-weight: bold;
++	color: #808080;
++}
++
++.InternalMessageHeaderTime
++{
++	font-size: 10px;
++	float: right; 
++	font-weight: normal;
++	margin-right: 1ex;
++}
++
++.systemLogo
++{
++	float: left;
++	margin-right: 1ex;
++	vertical-align: middle;
++}
++
+--- kopete/styles/Makefile.am	(revision 568672)
++++ kopete/styles/Makefile.am	(revision 586398)
+@@ -1,18 +1,2 @@
+-SUBDIRS = . data
++SUBDIRS = Kopete Hacker Clean Clear Konqi Retropete Gaim
+ 
+-styles_DATA = \
+-	Adium.xsl \
+-	Enclosed.xsl \
+-	Gaim.xsl \
+-	iChat.xsl \
+-	Keramik.xsl \
+-	Konsole.xsl \
+-	Kopete.xsl \
+-	Kopete-old.xsl \
+-	Minimal.xsl \
+-	MSN.xsl \
+-	XChat.xsl
+-
+-stylesdir = $(kde_datadir)/kopete/styles
+-EXTRA_DIST = $(styles_DATA)
+-
+--- kopete/styles/Retropete/Makefile.am	(revision 0)
++++ kopete/styles/Retropete/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+--- kopete/styles/Retropete/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Retropete/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+--- kopete/styles/Retropete/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="KopeteMessage">
++	<!-- Time Display -->
++	%time{%H:%M:%S}%: 
++	<!-- MetaContact name -->
++	<span class="inMetacontact">%sender% </span>
++	<!-- Message -->
++	<span class="inAction" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</span>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Action.html Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Retropete/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Retropete/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage">
++	<span class="inIntro">Message from %sender% at %time{%H:%M:%S}%</span>
++	<div class="inMessage" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</div>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage">
++	<span class="inIntro">Message from %sender% at %time{%H:%M:%S}%</span>
++	<div class="inMessage" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</div>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div class="KopeteMessage">
++	<span class="statusMessage" style="direction: %messageDirection%;">*** %time{%H:%M:%S}%: %message% ***</span>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = Incoming Outgoing
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Retropete/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Retropete/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,10 @@
++<div class="KopeteMessage">
++	<!-- Time Display -->
++	%time{%H:%M:%S}%: 
++	<!-- MetaContact name -->
++	<span class="outMetacontact">%sender% </span>
++	<!-- Message -->
++	<span class="outAction" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</span>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Action.html Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Retropete/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Retropete/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage">
++	<span class="outIntro">Message from %sender% at %time{%H:%M:%S}%</span>
++	<div class="outMessage" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</div>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage">
++	<span class="outIntro">Message from %sender% at %time{%H:%M:%S}%</span>
++	<div class="outMessage" style="direction: %messageDirection%; background-color: %textbackgroundcolor{#4386CF}%;">
++		 %message%
++	</div>
++</div>
+--- kopete/styles/Retropete/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Retropete/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,55 @@
++.KopeteMessage
++{
++	margin: 5px;
++}
++
++.inIntro
++{
++	font-weight: bold;
++	color: blue;
++}
++
++.inMetacontact
++{
++	font-weight: bold;
++	color: blue;
++}
++
++.inMessage
++{
++	padding-left: 10px;
++}
++
++.inAction
++{
++	font-style: italic;
++	color: blue;
++}
++
++.outIntro
++{
++	font-weight: bold;
++	color: red;
++}
++
++.outMetacontact
++{
++	font-weight: bold;
++	color: red;
++}
++
++.outMessage
++{
++	padding-left: 10px;
++}
++
++.outAction
++{
++	font-style: italic;
++	color: red;
++}
++
++.statusMessage
++{
++	color: #333333;
++}
+--- kopete/styles/Gaim/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Contents
+\ No newline at end of file
+--- kopete/styles/Gaim/CREDITS	(revision 0)
++++ kopete/styles/Gaim/CREDITS	(revision 586398)
+@@ -0,0 +1,7 @@
++Original textonly Style for Adium written by Mark Fickett
++http://www.adiumxtras.com/index.php?a=xtras&xtra_id=44
++
++Modified justtext Style for Adium written by Huw Rowlands
++http://www.adiumxtras.com/index.php?a=xtras&xtra_id=990
++
++Modified Gaim Style for Kopete written by Thanos Kyritsis
+--- kopete/styles/Gaim/Contents/Info.plist	(revision 0)
++++ kopete/styles/Gaim/Contents/Info.plist	(revision 586398)
+@@ -0,0 +1,31 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
++        "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
++<plist version="1.0">
++<dict>
++	<key>CFBundleDevelopmentRegion</key>
++	<string>English</string>
++	<key>CFBundleGetInfoString</key>
++	<string>Gaim Kopete chat Style</string>
++	<key>CFBundleIdentifier</key>
++	<string>Kopete.Gaim.style</string>
++	<key>CFBundleInfoDictionaryVersion</key>
++	<string>1.0</string>
++	<key>CFBundleName</key>
++	<string>Gaim</string>
++	<key>CFBundlePackageType</key>
++	<string>KopeteChatStyle</string>
++	<key>DefaultBackgroundColor</key>
++	<string>FFFFFF</string>
++	<key>DefaultFontFamily</key>
++	<string>DejaVu Sans Mono</string>
++	<key>DefaultFontSize</key>
++	<integer>12</integer>
++	<key>DisableCustomBackground</key>
++	<false/>
++	<key>DisplayNameForNoVariant</key>
++	<string>grays</string>
++	<key>ShowsUserIcons</key>
++	<false/>
++</dict>
++</plist>
+--- kopete/styles/Gaim/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS = Resources
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;s"><span class="inActionTime">(%time{%H:%M:%S}%) </span>
++	 <span class="inActionMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="inActionMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Action.html Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Gaim/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;"><span class="inContentTime">(%time{%H:%M:%S}%) </span>
++	 <span class="inMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="IncomingMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;"><span class="inContentTime">(%time{%H:%M:%S}%) </span>
++	 <span class="inMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="IncomingMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,5 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span class="InternalTime">(%time{%H:%M:%S}%) </span>
++    <span class="InternalDelim">#&nbsp;</span>
++	 <span class="InternalMessage">%message%</span>
++</div>
+--- kopete/styles/Gaim/Contents/Resources/Variants/Contact-Colors.css	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Variants/Contact-Colors.css	(revision 586398)
+@@ -0,0 +1,10 @@
++
++ at import url(../main.css);
++
++.inContentTime, .inMetacontact {
++	color: inherit;
++}
++
++.outContentTime, .outMetacontact {
++	color: inherit;
++}
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Variants/No-Colors.css	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Variants/No-Colors.css	(revision 586398)
+@@ -0,0 +1,22 @@
++ at import url(../main.css);
++
++.inContentTime, .inMetacontact {
++	color: #000000;
++}
++
++.outContentTime, .outMetacontact {
++	color: #000000;
++}
++
++.inActionTime, .inActionMetacontact, .inActionMessage {
++	color: #000000;
++}
++
++.outActionTime, .outActionMetacontact, .outActionMessage {
++	color: #000000;
++}
++
++.InternalTime, .InternalDelim, .InternalMessage {
++	color: #000000;
++}
++
+--- kopete/styles/Gaim/Contents/Resources/Variants/Name-Colors.css	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Variants/Name-Colors.css	(revision 586398)
+@@ -0,0 +1,13 @@
++ at import url(../main.css);
++
++.inActionTime, .inActionMetacontact, .inActionMessage {
++	color: #000000;
++}
++
++.outActionTime, .outActionMetacontact, .outActionMessage {
++	color: #000000;
++}
++
++.InternalTime, .InternalDelim, .InternalMessage {
++	color: #000000;
++}
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Variants/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Variants/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = No-Colors.css Name-Colors.css Status-Colors.css Contact-Colors.css
++styledir = $(kde_datadir)/kopete/styles/Gaim/Contents/Resources/Variants
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Variants/Status-Colors.css	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Variants/Status-Colors.css	(revision 586398)
+@@ -0,0 +1,9 @@
++ at import url(../main.css);
++
++.inContentTime, .inMetacontact {
++	color: #000000;
++}
++
++.outContentTime, .outMetacontact {
++	color: #000000;
++}
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = Incoming Outgoing Variants
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Gaim/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Gaim/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;"><span class="outActionTime">(%time{%H:%M:%S}%) </span>
++	 <span class="outActionMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="outActionMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Action.html Content.html NextContent.html
++styledir = $(kde_datadir)/kopete/styles/Gaim/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Gaim/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;"><span class="outContentTime">(%time{%H:%M:%S}%) </span>
++    <span class="outMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="OutgoingMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="KopeteMessage" style="direction: %messageDirection%;">
++    <span style="color:%senderColor%;"><span class="outContentTime">(%time{%H:%M:%S}%) </span>
++    <span class="outMetacontact">%sender%:&nbsp;</span></span>
++	 <span class="OutgoingMessage" style="background-color: %textbackgroundcolor{#4386cf}%;">%message%</span>
++</div>
++<div id="insert"></div>
+--- kopete/styles/Gaim/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Gaim/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,40 @@
++/* textonly by Mark Fickett, 2004. Poke/edit/maul, but leave credit - think GPL */
++/* Generally: naib.webhop.org Adium-related: naib.webhop.org/~markfickett/adium */
++
++body {
++	background: #ffffff;
++}
++
++div {
++	overflow: auto;
++}
++
++a:link { text-decoration: none; }
++a:visited { text-decoration: none; }
++a:hover { text-decoration: underline; }
++a:active { text-decoration: none; }
++
++.inMetacontact, .outMetacontact, .inActionMetacontact, .outActionMetacontact, .InternalDelim {
++	font-weight: bold;
++}
++
++.inContentTime, .inMetacontact {
++	color: #a82f2f;
++}
++
++.outContentTime, .outMetacontact {
++	color: #16569e;
++}
++
++.inActionTime, .inActionMetacontact, .inActionMessage {
++	color: green;
++}
++
++.outActionTime, .outActionMetacontact, .outActionMessage {
++	color: green;
++}
++
++.InternalTime, .InternalDelim, .InternalMessage {
++	color: #9400d3;
++}
++
+--- kopete/styles/Hacker/gpl.txt	(revision 0)
++++ kopete/styles/Hacker/gpl.txt	(revision 586398)
+@@ -0,0 +1,340 @@
++		    GNU GENERAL PUBLIC LICENSE
++		       Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++			    Preamble
++
++  The licenses for most software are designed to take away your
++freedom to share and change it.  By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users.  This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it.  (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.)  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++  To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have.  You must make sure that they, too, receive or can get the
++source code.  And you must show them these terms so they know their
++rights.
++
++  We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++  Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software.  If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++  Finally, any free program is threatened constantly by software
++patents.  We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary.  To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++		    GNU GENERAL PUBLIC LICENSE
++   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++  0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License.  The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language.  (Hereinafter, translation is included without limitation in
++the term "modification".)  Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope.  The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++  1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++  2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++    a) You must cause the modified files to carry prominent notices
++    stating that you changed the files and the date of any change.
++
++    b) You must cause any work that you distribute or publish, that in
++    whole or in part contains or is derived from the Program or any
++    part thereof, to be licensed as a whole at no charge to all third
++    parties under the terms of this License.
++
++    c) If the modified program normally reads commands interactively
++    when run, you must cause it, when started running for such
++    interactive use in the most ordinary way, to print or display an
++    announcement including an appropriate copyright notice and a
++    notice that there is no warranty (or else, saying that you provide
++    a warranty) and that users may redistribute the program under
++    these conditions, and telling the user how to view a copy of this
++    License.  (Exception: if the Program itself is interactive but
++    does not normally print such an announcement, your work based on
++    the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole.  If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works.  But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++  3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++    a) Accompany it with the complete corresponding machine-readable
++    source code, which must be distributed under the terms of Sections
++    1 and 2 above on a medium customarily used for software interchange; or,
++
++    b) Accompany it with a written offer, valid for at least three
++    years, to give any third party, for a charge no more than your
++    cost of physically performing source distribution, a complete
++    machine-readable copy of the corresponding source code, to be
++    distributed under the terms of Sections 1 and 2 above on a medium
++    customarily used for software interchange; or,
++
++    c) Accompany it with the information you received as to the offer
++    to distribute corresponding source code.  (This alternative is
++    allowed only for noncommercial distribution and only if you
++    received the program in object code or executable form with such
++    an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it.  For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable.  However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++  4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License.  Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++  5. You are not required to accept this License, since you have not
++signed it.  However, nothing else grants you permission to modify or
++distribute the Program or its derivative works.  These actions are
++prohibited by law if you do not accept this License.  Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++  6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions.  You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++  7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all.  For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices.  Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++  8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded.  In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++  9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number.  If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation.  If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++  10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission.  For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this.  Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++			    NO WARRANTY
++
++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++		     END OF TERMS AND CONDITIONS
++
++	    How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) <year>  <name of author>
++
++    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.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++    Gnomovision version 69, Copyright (C) year name of author
++    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary.  Here is a sample; alter the names:
++
++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++  `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++  <signature of Ty Coon>, 1 April 1989
++  Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs.  If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library.  If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+--- kopete/styles/Hacker/COPYRIGHT	(revision 0)
++++ kopete/styles/Hacker/COPYRIGHT	(revision 586398)
+@@ -0,0 +1,18 @@
++"Hacker" Kopete chat window Style
++
++Copyright (C) 2005  Jussi Kekkonen (Tm_T)
++(see README for more information)
++
++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.
++
++This program is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this program; if not, write to the Free Software
++Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+\ No newline at end of file
+--- kopete/styles/Hacker/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = Contents
++style_DATA = COPYRIGHT README gpl.txt
++styledir = $(kde_datadir)/kopete/styles/Hacker
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Info.plist	(revision 0)
++++ kopete/styles/Hacker/Contents/Info.plist	(revision 586398)
+@@ -0,0 +1,42 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
++        "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
++<plist version="1.0">
++<dict>
++        <key>CFBundleDevelopmentRegion</key>
++        <string>English</string>
++        <key>CFBundleGetInfoString</key>
++        <string>Hacker Kopete chat style</string>
++        <key>CFBundleIdentifier</key>
++        <string>Kopete.Hacker.style</string>
++        <key>CFBundleInfoDictionaryVersion</key>
++        <string>1.0</string>
++        <key>CFBundleName</key>
++        <string>Hacker</string>
++        <key>CFBundlePackageType</key>
++        <string>KopeteChatStyle</string>
++        <key>MessageViewVersion</key>
++        <integer>1</integer>
++        <key>DefaultFontFamily</key>
++	<string>DejaVu Sans Mono</string>
++	<key>DefaultFontSize</key>
++	<integer>12</integer>
++        <key>DisableCustomBackground</key>
++        <false/>
++        <key>DefaultBackgroundColor</key>
++        <string>000000</string>
++	<key>DisplayNameForNoVariant</key>
++        <string>Dark</string>
++        <key>AllowTextColors:Dark</key>
++        <false/>
++	<key>DefaultBackgroundColor:Dark2</key>
++        <string>000000</string>
++	<key>AllowTextColors:Dark2</key>
++        <false/>
++	<key>DefaultBackgroundColor:Light</key>
++        <string>ffffff</string>
++	<key>DefaultBackgroundColor:Light2</key>
++        <string>ffffff</string>
++	
++</dict>
++</plist>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = Resources
++style_DATA = Info.plist
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/Action.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/Action.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="Buddy"> &nbsp;*&nbsp;%sender%&nbsp;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/NextContext.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/NextContext.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="pastBuddy"> &nbsp;&nbsp;&nbsp;
++	<span class="pastMessage"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/Context.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/Context.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="pastBuddy"> &lt;&nbsp;%sender%&nbsp;&gt;
++	<span class="pastMessage"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Content.html Context.html NextContent.html NextContext.html buddy_icon.png Action.html
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents/Resources/Incoming
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="Buddy"> &nbsp;&nbsp;&nbsp;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="Buddy"> &lt;&nbsp;%sender%&nbsp;&gt;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/images/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/images/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = background.png background2.png kopete.png 
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents/Resources/images
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Status.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,11 @@
++<div class="statusContainer">
++<table border=0 colspan=0>
++<tr><td>
++<div class="statusTime">--- %time% ---</div>
++</td>
++<td> : </td>
++<td>
++<div class="statusMessage">%message%</div>
++</td></tr>
++</table>
++</div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Variants/Light2.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Light2.css	(revision 586398)
+@@ -0,0 +1,4 @@
++ at import url(./Light.css);
++
++.imageContainer  { margin: 4px 4px 4px 4px; display: block }
++.buddyIcon  { width: 48px; float: right; border-style: dotted none; border-width: 2px medium; border-color: #666 white }
+--- kopete/styles/Hacker/Contents/Resources/Variants/Dark-Noback.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Dark-Noback.css	(revision 586398)
+@@ -0,0 +1,6 @@
++ at import url(../main.css);
++
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background-color: black
++	}
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Variants/Dark2-Noback.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Dark2-Noback.css	(revision 586398)
+@@ -0,0 +1,9 @@
++ at import url(../main.css);
++
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background-color: black
++	}
++
++.imageContainer  { margin: 4px 4px 4px 4px; display: block }
++.buddyIcon  { width: 48px; float: right; border-style: dotted none; border-width: 2px medium; border-color: #666 white }
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Variants/Dark.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Dark.css	(revision 586398)
+@@ -0,0 +1,6 @@
++ at import url(../main.css);
++
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background: url("../images/kopete.png"); background-position: center; background-attachment: fixed; background-repeat: no-repeat; background-color: black
++	}
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Variants/Light-Noback.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Light-Noback.css	(revision 586398)
+@@ -0,0 +1,40 @@
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background: white; background-color: white
++	}
++
++#Chat  { padding-top: 80px; margin: 4px; overflow: hidden }
++
++#Header { background: url("../images/background2.png") repeat-x right top; position: fixed; z-index: 100; top: 0; right: 0; left: 0; height: 80px; border-bottom: 0 none }
++
++.imageContainer  { display: none; }
++
++.chatName  { color: #3d4f51; font-size: 14px; font-weight: bold; text-align: center; position: relative; margin-left: 2px; margin-right: 5px }
++
++.headerContainer  { padding: 1px 1px; position: relative; border-style: dotted none; border-width: 2px medium; border-color: #666 black }
++
++.container  { margin-bottom: 2px;  overflow: auto; }
++
++a:link  { color: #5099ff }
++a:visited  { color: #5099ff }
++a:hover  { color: #82b6ff }
++
++.messageTime  { color: #3d3d3d; font-size: 10px; font-weight: normal; text-align: left; position: relative; z-index: 60; top: 0px; float: left; margin-right: 4px }
++
++.Message  { color: black; font-style: normal; font-weight: normal; position: relative; margin-left: 2px; margin-right: 5px }
++
++.pastMessage  { color: #a0a3a6; font-style: normal; font-weight: normal }
++
++.statusContainer  { margin-bottom: 2px }
++
++.statusTime  { color: #2d425f; font-size: 10px; font-weight: bold; top: 0px; text-align: right; margin-right: 5px; position: relative; width: 150px; float: left }
++
++.statusMessage  { color: #4d6581; font-size: 12px; font-weight: bold; position: relative; right: 5px }
++
++.buddy  { color: #5099ff; font-weight: bold; text-align: left; display: block; position: relative; margin-left: 2px }
++
++.user  { color: gray; font-weight: bold; text-align: left; display: block; position: relative; margin-left: 2px }
++
++.pastBuddy  { color: #7ab382; font-size: 11px; font-weight: bold; text-align: left; position: relative }
++
++.pastUser  { color: #7b95b4; font-size: 11px; font-weight: bold; text-align: left; position: relative }
+--- kopete/styles/Hacker/Contents/Resources/Variants/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++style_DATA = Dark2.css Dark.css Light2.css Light.css Dark2-Noback.css Dark-Noback.css Light2-Noback.css Light-Noback.css
++
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents/Resources/Variants
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Hacker/Contents/Resources/Variants/Dark2.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Dark2.css	(revision 586398)
+@@ -0,0 +1,9 @@
++ at import url(../main.css);
++
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background: url("../images/kopete.png"); background-position: center; background-attachment: fixed; background-repeat: no-repeat; background-color: black
++	}
++
++.imageContainer  { margin: 4px 4px 4px 4px; display: block }
++.buddyIcon  { width: 48px; float: right; border-style: dotted none; border-width: 2px medium; border-color: #666 white }
+--- kopete/styles/Hacker/Contents/Resources/Variants/Light2-Noback.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Light2-Noback.css	(revision 586398)
+@@ -0,0 +1,4 @@
++ at import url(./Light-Noback.css);
++
++.imageContainer  { margin: 4px 4px 4px 4px; display: block }
++.buddyIcon  { width: 48px; float: right; border-style: dotted none; border-width: 2px medium; border-color: #666 white }
+--- kopete/styles/Hacker/Contents/Resources/Variants/Light.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Variants/Light.css	(revision 586398)
+@@ -0,0 +1,6 @@
++ at import url(./Light-Noback.css);
++
++body	{
++	font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0;
++	background: url("../images/kopete.png"); background-position: center; background-attachment: fixed; background-repeat: no-repeat; background-color: white
++	}
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Makefile.am	(revision 586398)
+@@ -0,0 +1,5 @@
++SUBDIRS = images Incoming Outgoing Variants
++style_DATA = main.css Footer.html Header.html Status.html
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents/Resources
++
++EXTRA_DIST = $(style_DATA)
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Header.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Header.html	(revision 586398)
+@@ -0,0 +1,8 @@
++<div id="Header">
++<div class="headerContainer">
++<div class="imageContainer">
++<img class="buddyIcon" src="%incomingIconPath%" width="96px"/>
++</div>
++<div class="chatName">%chatName%</div>
++</div>
++</div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/Action.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/Action.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="User"> &nbsp;*&nbsp;%sender%&nbsp;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/NextContext.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/NextContext.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="pastUser"> &nbsp;&nbsp;&nbsp;
++	<span class="pastMessage"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/Context.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/Context.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="pastUser"> &lt;&nbsp;%sender%&nbsp;&gt;
++	<span class="pastMessage"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/Makefile.am	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++style_DATA = Content.html NextContent.html Context.html NextContext.html buddy_icon.png Action.html
++styledir = $(kde_datadir)/kopete/styles/Hacker/Contents/Resources/Outgoing
++
++EXTRA_DIST = $(style_DATA)
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="user"> &nbsp;&nbsp;&nbsp;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,6 @@
++<div class="container" style="direction: %messageDirection%;">
++	<span class="messageTime">%time{%H:%M:%S}%</span>
++	<div class="user"> &lt;&nbsp;%sender%&nbsp;&gt;
++	<span class="Message"> %message% </span></div>
++</div>
++<div id="insert"></div>
+\ No newline at end of file
+--- kopete/styles/Hacker/Contents/Resources/main.css	(revision 0)
++++ kopete/styles/Hacker/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1,37 @@
++body  { font-size: 12px; font-family: "DejaVu Sans Mono", monospace; font-style: normal; font-weight: normal; margin: 0; color: #5099ff; background: black; background-color: black }
++
++#Chat  { padding-top: 80px; margin: 4px; overflow: hidden }
++
++#Header { background: url("images/background.png") repeat-x right top; position: fixed; z-index: 100; top: 0; right: 0; left: 0; height: 80px; border-bottom: 0 none }
++
++.imageContainer  { display: none; }
++
++.chatName  { color: #cdcfd1; font-size: 14px; font-weight: bold; text-align: center; position: relative; margin-left: 2px; margin-right: 5px }
++
++.headerContainer  { padding: 1px 1px; position: relative; border-style: dotted none; border-width: 2px medium; border-color: #666 white }
++
++.container  { margin-bottom: 2px; overflow: auto; }
++
++a:link  { color: #5099ff }
++a:visited  { color: #5099ff }
++a:hover  { color: #82b6ff }
++
++.messageTime   { color: #dcdcdc; font-size: 10px; font-weight: normal; text-align: left; position: relative; z-index: 60; top: 0px; float: left; margin-right: 4px }
++
++.Message  { color: #cdcfd1; font-style: normal; font-weight: normal; position: relative; margin-left: 2px; margin-right: 5px }
++
++.pastMessage  { color: #a0a3a6; font-style: normal; font-weight: normal }
++
++.statusContainer  { margin-bottom: 2px }
++
++.statusTime  { color: #cde2ff; font-size: 10px; font-weight: bold; top: 0px; text-align: right; margin-right: 5px; position: relative; width: 150px; float: left }
++
++.statusMessage  { color: #dddfe1; font-size: 12px; font-weight: bold; position: relative; right: 5px }
++
++.buddy  { color: #5099ff; font-weight: bold; text-align: left; position: relative; margin-left: 2px }
++
++.user  { color: white; font-weight: bold; text-align: left; position: relative; margin-left: 2px }
++
++.pastBuddy  { color: #7c91af; font-size: 11px; font-weight: bold; text-align: left; position: relative }
++
++.pastUser  { color: gray; font-size: 11px; font-weight: bold; text-align: left; position: relative }
+--- kopete/styles/Hacker/README	(revision 0)
++++ kopete/styles/Hacker/README	(revision 586398)
+@@ -0,0 +1,8 @@
++This is Kopete style using new POWERFUL xhtml+css engine
++made by Tm_T with help of Linux community all over the world
++
++contact me: 
++	irc: Tm_T at ircnet & freenode
++	email: tm_travolta at kapsi dot fi
++
++see COPYRIGHT and gpl.txt for copyright
+--- kopete/protocols/yahoo/kyahoo.h	(revision 568672)
++++ kopete/protocols/yahoo/kyahoo.h	(revision 586398)
+@@ -1,371 +0,0 @@
+-/*
+-    kyahoo.h - Qt based libyahoo2 wrapper II
+-
+-    Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett <duncan at kde.org>
+-
+-    Copyright (c) 2002 by the Kopete developers  <kopete-devel at 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 KYAHOO_H
+-#define KYAHOO_H
+-
+-// QT Includes
+-#include <qobject.h>
+-#include <qstring.h>
+-#include <qfile.h>
+-#include <qmap.h>
+-#include <qpixmap.h>
+-#include <qbuffer.h>
+-#include <qpair.h>
+-
+-#include "libyahoo2/yahoo2.h"
+-#include "libyahoo2/yahoo2_callbacks.h"
+-
+-// KDE Includes
+-#include <kstreamsocket.h>
+-#include <ksocketdevice.h>
+-
+-using namespace KNetwork;
+-
+-class YahooSession;
+-class YahooBuddyIconLoader;
+-struct YahooUserInfo;
+-class QSocketNotifier;
+-class KTempFile;
+-struct KURL;
+-namespace KIO	{ 
+-	class Job;
+-	class TransferJob; 
+-}
+-namespace Kopete{
+-class Transfer;
+-class Contact;
+-}
+-
+-struct YahooUploadData
+-{
+-	int size;
+-	uint transmitted;
+-	QFile file;
+-	bool reportSuccess;
+-};
+-
+-class YahooConnectionManager
+-{
+-public:
+-	YahooConnectionManager();
+-	~YahooConnectionManager();
+-	
+-	/**
+-	 * Registers a connection with the connection manager so that it
+-	 * can be kept track of. When a connection is closed, it is unregistered
+-	 * from the connection manager and a new connection of that type is expected
+-	 * to be created.
+-	 */
+-	void addConnection( QPair< KStreamSocket*, void * > *connection );
+-	
+-	/**
+-	 * Get the connection by its file descriptor
+-	 */
+-	QPair< KStreamSocket*, void *> *connectionForFD( int fd );
+-	
+-	/**
+-	 * Remove a connection from the manager
+-	 * @overload
+-	 */
+-	void remove( KStreamSocket* socket );
+-	
+-	/**
+-	 * Reset the connection manager.
+-	 */
+-	void reset();
+-	
+-private:
+-	QValueList< QPair< KStreamSocket*, void *> *> m_connectionList;
+-};
+-	
+-	
+-
+-/* Yahoo Protocol Connection Manager */
+-class YahooSessionManager : public QObject
+-{
+-	Q_OBJECT
+-
+-public:
+-	static YahooSessionManager *manager();
+-	YahooSessionManager();
+-	~YahooSessionManager();
+-
+-
+-	/* Creates a new session */
+-	YahooSession* createSession(const QString username, const QString password);
+-	bool cleanSessions();
+-	YahooSession* session(int id);
+-	int sessionCount() const;
+-
+-	/* Sets the host and port for connection to the pager and f.t. servers */
+-	void setPager(QString host, int port);
+-	void setFileTransfer(QString host, int port);
+-
+-	int _hostConnectReceiver(char *host, int port);
+-
+-private:
+-	QMap< int, YahooSession*> m_sessionsMap;
+-	static YahooSessionManager *managerStatic_;
+-};
+-
+-// Yahoo Protocol Connection
+-class YahooSession : public QObject
+-{
+-	friend class YahooSessionManager;
+-	Q_OBJECT
+-
+-public:
+-	~YahooSession();
+-	int sessionId() const;
+-
+-	int setLogLevel(enum yahoo_log_level level);
+-
+-	/* YahooSession public API */
+-
+-	void login(int initial);
+-	void logOff();
+-
+-	void setIdentityStatus( const QString &identity, int active);
+-	void getList();
+-
+-public slots:
+-	void keepalive();
+-	void refresh();
+-
+-public:
+-	void sendIm( const QString &from, const QString &who, const QString &msg, int picture);
+-	void sendTyping( const QString &from, const QString &who, int typ);
+- 	void buzzContact( const QString &from, const QString&who, int picture );
+-	void setAway( enum yahoo_status state, const QString &msg, int away);
+-	void addBuddy( const QString &who, const QString &group);
+-	void removeBuddy( const QString &who, const QString &group);
+-	void rejectBuddy( const QString &who, const QString &msg);
+-	void ignoreBuddy( const QString &who, int unignore);
+-	void changeBuddyGroup( const QString &who, const QString &old_group, const QString &new_group);
+-	void conferenceInvite( const QString & from, const QStringList &who, const QString &room, const QString &msg);
+-	void conferenceAddinvite( const QString & from, const QString &who, const QString &room, const QStringList & members, const QString &msg);
+-	void conferenceDecline( const QString & from, const QStringList &who, const QString &room, const QString &msg);
+-	void conferenceMessage( const QString & from, const QStringList &who, const QString &room, const QString &msg);
+-	void conferenceLogon( const QString & from, const QStringList &who, const QString &room);
+-	void conferenceLogoff( const QString & from, const QStringList &who, const QString &room);
+-	int sendFile( const QString &who, const QString &msg, const QString &name, long size);	
+-	int getUrlHandle( Kopete::Transfer *trans );
+-	enum yahoo_status currentStatus();
+-	const YList *getLegacyBuddyList();
+-	QStringList getBuddylist();
+-	QStringList getIgnorelist();
+-	QStringList getIdentities();
+-	QString getCookie( const QString &which);
+-	QString getProfile_url( void );
+-	void getUserInfo( const QString &who );
+-	void viewUserProfile( const QString &who );
+-	void stealthContact( const QString &who, int unstealth );
+-	void saveAdressBookEntry( const YahooUserInfo &entry);
+-
+-	void requestBuddyIcon( const QString &who );
+-	void downloadBuddyIcon( const QString &who, KURL url, int checksum );
+-	void sendBuddyIconInfo( const QString &who, const QString &url, int checksum );
+-	void sendBuddyIconUpdate( const QString &who, int type );
+-	void sendBuddyIconChecksum( int checksum, const QString &who );
+-	void uploadBuddyIcon( const QString &url, int size );
+-	
+-	//webcam handlers
+-	void requestWebcam( const QString& from );
+-	void closeWebcam( const QString& from );
+-
+-	/* Private Receivers for libyahoo callbacks, we capture them  and emit signals
+-	   called only by libyahoo callbacks, don't use them */
+-
+-	void _receiveFileProceed( int id, int fd, int error,
+-	                          const char *filename, unsigned long size, void *data );
+-	void _loginResponseReceiver(int succ, const char *url);
+-	void _gotIgnoreReceiver(YList *igns);
+-	void _gotBuddiesReceiver(YList *buds);
+-	void _gotidentitiesReceiver(char *who, int stat, char *msg, int away);
+-	void _gotIdentitiesReceiver(YList *ids);
+-	void _statusChangedReceiver(char *who, int stat, char *msg, int away);
+-	void _gotImReceiver(char *who, char *msg, long tm, int stat, int utf8);
+-	void _gotConfInviteReceiver(char *who, char *room, char *msg, YList *members);
+-	void _confUserDeclineReceiver(char *who, char *room, char *msg);
+-	void _confUserJoinReceiver(char *who, char *room);
+-	void _confUserLeaveReceiver(char *who, char *room);
+-	void _confMessageReceiver(char *who, char *room, char *msg, int utf8);
+-	void _gotFileReceiver(char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize);
+-	void _contactAddedReceiver(char *myid, char *who, char *msg);
+-	void _rejectedReceiver(char *who, char *msg);
+-	void _typingNotifyReceiver(char *who, int stat);
+-	void _gameNotifyReceiver(char *who, int stat);
+-	void _mailNotifyReceiver(char *from, char *subj, int cnt);
+-	void _systemMessageReceiver(char *msg);
+-	void _errorReceiver(char *err, int fatal);
+-	int _logReceiver(char *fmt, ...);
+-	int _addHandlerReceiver(int fd, yahoo_input_condition cond, void *data);
+-	void _removeHandlerReceiver(int tag);
+-	int _hostAsyncConnectReceiver(char *host, int port,  yahoo_connect_callback callback, void *callback_data);
+-	void _gotBuddyIconReceiver( int id, char *who, char *url, int checksum );
+-	void _gotBuddyIconChecksumReceiver( int id, char *who, int checksum );
+-	void _gotBuddyIconRequestReceiver( int id, char *who );
+-	void _gotBuddyIconUploadResponseReceiver( int id, const char *url);
+-	void _uploadFileReceiver( int id, int fd, int error, void *data );
+-	
+-	//webcam callback receivers
+-	void _gotWebcamInvite( const char* who );
+-	void _gotWebcamImage( const char* who, const unsigned char* image, unsigned int image_size,
+-	                      unsigned int real_size, unsigned int timestamp );
+-	void _webcamDisconnected( const char* who, int reason );
+-
+-signals:	
+-	/** emitted when server says login OK */
+-	void loginResponse( int succ, const QString &url);
+-
+-	/** emitted when servers send us our contact list */
+-	void gotBuddy(const QString &userid, const QString &alias, const QString &group);
+-
+-	/** emitted when we've finished getting the buddy list */
+-	void buddyListFetched( int numBuddies );
+-
+-	/** emitted when server notifies us our ignore list */
+-	void gotIgnore( const QStringList &igns);
+-
+-	/** emitted when server notify us our identities */
+-	void gotIdentities( const QStringList &ids);
+-
+-	/** emitted when a contact changes status */
+-	void statusChanged( const QString &who, int stat, const QString &msg, int away);
+-
+-	/** emitted when someone send us a message */
+-	void gotIm( const QString &who, const QString &msg, long tm, int stat);
+-
+-	/** emitted when someone buzz us */
+-	void gotBuzz( const QString &who, long tm );
+-	
+-	/** emitted when someone invites us into a conference room */
+-	void gotConfInvite( const QString &who, const QString &room, const QString &msg, const QStringList &members);
+-
+-	/** emitted when someone declines joining a conference room */
+-	void confUserDecline( const QString &who, const QString &room, const QString &msg);
+-
+-	/** emitted when someone joins a conference */
+-	void confUserJoin( const QString &who, const QString &room);
+-
+-	/** emitted when someone leaves a conference */
+-	void confUserLeave( const QString &who, const QString &room);
+-
+-	/** emitted when someone send us a Conference message */
+-	void confMessage( const QString &who, const QString &room, const QString &msg);
+-
+-	/** emitted when someone wants to send us a file */
+-	void gotFile( const QString &who, const QString &url, long expires, const QString &msg, const QString &fname, unsigned long fesize);
+-
+-	/** emitted when a contact is added */
+-	void contactAdded( const QString &myid, const QString &who, const QString &msg);
+-
+-	/** emitted when someone rejects our auth request */
+-	void rejected( const QString &who, const QString &msg);
+-
+-	/** emitted when someone is typing a message */
+-	void typingNotify( const QString &who, int stat);
+-
+-	/** emitted when someone invites us to join a game */
+-	void gameNotify( const QString &who, int stat);
+-
+-	/** Notify that we have mail */
+-	void mailNotify( const QString &from, const QString &subject, int cnt);
+-
+-	/** emitted when Yahoo servers send us a admin message */
+-	void systemMessage( const QString &msg);
+-
+-	/** emitted when error */
+-	void error( const QString &err, int fatal);
+-	//void hostConnect(char *host, int port);
+-	
+-	/** emitted when a webcam invite is received */
+-	void gotWebcamInvite( const QString& from );
+-	
+-	/** emitted when we have a webcam image available */
+-	void webcamImageReceived( const QString& from, const QPixmap& pic );
+-	
+-	/** emitted when the webcam has been closed from the other side */
+-	void remoteWebcamClosed( const QString& from, int reason );
+-	
+-	/** emitted when a buddy icon was successfully downloaded */
+-	void gotBuddyIcon( const QString &who, KTempFile *file, int checksum );
+-	
+-	/** emitted when someone send information about his buddy icon */
+-	void gotBuddyIconInfo( const QString &who, KURL url, int checksum );
+-
+-	/** emitted when someone sends a icon checksum, probably because he changed his icon */
+-	void gotBuddyIconChecksum( const QString &who, int checksum );
+-	
+-	/** emitted when someone requests our buddy icon */
+-	void gotBuddyIconRequest( const QString &who );
+-	
+-	/** emitted when our buddy icon was successfully uploaded*/
+-	void buddyIconUploaded( const QString &url );
+-private slots:
+-
+-	void slotLoginResponseReceiver( int succ, char *url);
+-	void slotAsyncConnectFailed( int error );
+-	void slotAsyncConnectSucceeded();
+-	void slotReadReady();
+-	void slotWriteReady();
+-	void slotUserInfoResult( KIO::Job* );
+-	void slotUserInfoData( KIO::Job*, const QByteArray & );
+-	void slotUserInfoSaved( KIO::Job* );
+-    void slotBuddyIconFetched(const QString &who, KTempFile *file, int checksum);
+-	void slotTransmitFile( int fd, YahooUploadData *uploadData );
+-	
+-private:
+-	/* Private constructor */
+-	YahooSession(int id, const QString username, const QString password);
+-
+-	void addHandler(int fd, yahoo_input_condition cond);
+-	void removeHandler(int fd);
+-	
+-	struct connect_callback_data *m_ccd;
+-	
+-	YahooConnectionManager m_connManager;
+-	
+-	Kopete::Contact* m_contact;
+-	Kopete::Transfer* m_kopeteTransfer;
+-	QString m_Filename;							  // Filename for Send file
+-	QFile m_File;
+-	QString m_Username, m_Password, m_Server; // User data
+-	QString m_UserInfo;
+-	QString m_targetID;					// userID of the target user, e.g. for UserInfo() or SendFile() ...
+-	KIO::TransferJob *mTransferJob;
+-
+-	int m_Port;
+-	int m_Status;
+-	int m_connId;
+-	int m_fd;
+-
+-	QString m_BuddyListServer; // Buddy List server
+-	int m_BuddyListPort;
+-	
+-	unsigned int m_lastWebcamTimestamp;
+-	QBuffer* currentImage;
+-
+-	YahooBuddyIconLoader *m_iconLoader;
+-};
+-
+-#endif
+-
+-// vim: set noet ts=4 sts=4 sw=4:
+-// kate: indent-mode csands; tab-width 4; auto-insert-doxygen on;
+-
+--- kopete/protocols/yahoo/yahoouserinfo.h	(revision 568672)
++++ kopete/protocols/yahoo/yahoouserinfo.h	(revision 586398)
+@@ -1,66 +0,0 @@
+-/*
+-    yahoouserinfo.h - hold and display buddy information
+-
+-    Copyright (c) 2005 by Andre Duffeck <andre at duffeck.de>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * 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 YAHOOUSERINFO_H
+-#define YAHOOUSERINFO_H
+-
+-// QT Includes
+-#include <qstring.h>
+-
+-// KDE Includes
+-#include <kdialogbase.h>
+-
+-// Local Includes
+-#include "yahoouserinfobase.h"
+-
+-struct YahooUserInfo {
+-	QString	userID;
+-	QString	abID;
+-	QString	firstName;
+-	QString	lastName;
+-	QString	nickName;
+-	QString	email;
+-	QString	phoneHome;
+-	QString	phoneWork;
+-	QString	phoneMobile;
+-};
+-
+-class YahooSession;
+-
+-class YahooUserInfoDialog : public KDialogBase
+-{
+-	Q_OBJECT
+-
+-public:
+-	YahooUserInfoDialog( QWidget* parent = 0, const char* name = 0 );
+-	~YahooUserInfoDialog();
+-
+-	void setSession( YahooSession * );
+-	void setUserInfo( const YahooUserInfo & );
+-public slots:
+-
+-protected slots:
+-	virtual void slotClose();
+-	virtual void slotApply();
+-	virtual void slotUser1();
+-
+-private:
+-	YahooUserInfoWidget *mMainWidget;
+-	YahooSession *m_theSession;
+-	YahooUserInfo m_userInfo;
+-};
+-
+-#endif
+-
+--- kopete/protocols/yahoo/yahoobuddyiconloader.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahoobuddyiconloader.cpp	(revision 586398)
+@@ -1,100 +0,0 @@
+-/*
+-    yahoobuddyiconloader.cpp - Fetches YahooBuddyIcons
+-
+-    Copyright (c) 2005 by André Duffeck <andre at duffeck.de>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * 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 "yahoobuddyiconloader.h"
+-
+-// QT Includes
+-#include <qfile.h>
+-
+-// KDE Includes
+-#include <kdebug.h>
+-#include <ktempfile.h>
+-#include <kio/global.h>
+-#include <kio/job.h>
+-#include <kio/jobclasses.h>
+-#include <kurl.h>
+-#include <kstandarddirs.h>
+-
+-YahooBuddyIconLoader::YahooBuddyIconLoader()
+-{
+-}
+-
+-YahooBuddyIconLoader::~YahooBuddyIconLoader()
+-{
+-}
+-
+-void YahooBuddyIconLoader::fetchBuddyIcon( const QString &who, KURL url, int checksum )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	KIO::TransferJob *transfer;
+-	QString Url = url.url();
+-	QString ext = Url.left( Url.findRev( "?" ) );
+-	ext = ext.right( ext.length() - ext.findRev( "." ) );
+-	//Url.mid( Url.findRev( "."), Url.findRev( "?") - Url.findRev( ".") - 1);
+-	
+-	transfer = KIO::get( url, false, false );
+-	connect( transfer, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotComplete( KIO::Job* ) ) );
+-	connect( transfer, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
+-
+-	m_jobs[transfer].url = url;
+-	m_jobs[transfer].who = who;
+-	m_jobs[transfer].checksum = checksum;
+-	m_jobs[transfer].file = new KTempFile( locateLocal( "tmp", "yahoobuddyicon-" ), ext );
+-	m_jobs[transfer].file->setAutoDelete( true );
+-
+-}
+-
+-void YahooBuddyIconLoader::slotData( KIO::Job *job, const QByteArray& data )
+-{
+-
+-	kdDebug(14180) << k_funcinfo << endl;
+-
+-	KIO::TransferJob *transfer = static_cast< KIO::TransferJob * >(job);
+-
+-	if( m_jobs[transfer].file )
+-		m_jobs[transfer].file->file()->writeBlock( data.data() , data.size() );
+-
+-}
+-
+-void YahooBuddyIconLoader::slotComplete( KIO::Job *job )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-
+-	KIO::TransferJob *transfer = static_cast< KIO::TransferJob * >(job);
+-
+-	if ( job->error () || transfer->isErrorPage () )
+-	{
+-		kdDebug(14180) << k_funcinfo << "An error occured while downloading buddy icon!" << endl;
+-	}
+-	else
+-	{
+-		if ( m_jobs[transfer].file )
+-		{
+-			m_jobs[transfer].file->close();
+-			emit fetchedBuddyIcon( m_jobs[transfer].who, m_jobs[transfer].file, m_jobs[transfer].checksum );
+-		}
+-		else
+-		{
+-			kdDebug(14180) << k_funcinfo << "Fatal Error! IconLoadJob has an empty KTempFile pointer." << endl;
+-		}
+-	}
+-
+-	m_jobs.remove( transfer );
+-}
+-
+-
+-
+-#include "yahoobuddyiconloader.moc"
+-
+--- kopete/protocols/yahoo/yahoobuddyiconloader.h	(revision 568672)
++++ kopete/protocols/yahoo/yahoobuddyiconloader.h	(revision 586398)
+@@ -1,75 +0,0 @@
+-/*
+-    yahoobuddyiconloader.h - Fetches YahooBuddyIcons
+-
+-    Copyright (c) 2005 by André Duffeck <andre at duffeck.de>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * 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 YAHOOBUDDYICONLOADER_
+-#define	YAHOOBUDDYICONLOADER_
+-
+-// QT Includes
+-#include <qobject.h>
+-#include <qstring.h>
+-#include <qmap.h>
+-
+-// KDE Includes
+-#include <kurl.h>
+-
+-class KTempFile;
+-namespace KIO {
+-	class Job;
+-	class TransferJob;
+-}
+-
+-struct IconLoadJob {
+-	KURL url;
+-	QString who;
+-	int checksum;
+-	KTempFile *file;
+-};
+-
+-/**
+- * @author André Duffeck
+- *
+- * This class handles the download of a Buddy icon.
+- * If the download was succesfull it emits a signal with a pointer
+- * to the temporary file, the icon was stored at
+- */
+-class YahooBuddyIconLoader : public QObject
+-{
+-	Q_OBJECT
+-public:
+-	YahooBuddyIconLoader();
+-	~YahooBuddyIconLoader();
+-
+-	/**
+-	 *	Add a BuddyIcon for download.
+-	 */
+-	void fetchBuddyIcon( const QString &who, KURL url, int checksum );
+-
+-signals:
+-	/**
+-	 * 	The account can connect to this signal and append the icon
+-	 * 	stored in 'file' to the apropriate contact
+-	 */
+-		void fetchedBuddyIcon( const QString &who, KTempFile *file, int checksum );
+-
+-private slots:
+-		void slotData( KIO::Job *job, const QByteArray &data );
+-		void slotComplete( KIO::Job *job );
+-
+-private:
+-		typedef QMap< KIO::TransferJob *, IconLoadJob > TransferJobMap;
+-		TransferJobMap m_jobs;
+-};
+-
+-#endif
+--- kopete/protocols/yahoo/kyahoo.cpp	(revision 568672)
++++ kopete/protocols/yahoo/kyahoo.cpp	(revision 586398)
+@@ -1,1688 +0,0 @@
+- /*
+-    kyahoo.cpp - Qt Based libyahoo2 wrapper II
+-
+-    Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett <duncan at kde.org>
+-    Copyright (c) 2003 by Matt Rogers <mattrogers at sbcglobal.net>
+-
+-    Copyright (c) 2002 by the Kopete developers  <kopete-devel at 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.                                   *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-// Local Includes
+-#include "kyahoo.h"
+-#include "kopeteuiglobal.h"
+-#include "kopetetransfermanager.h"
+-#include "kopetecontact.h"
+-#include "kopetemetacontact.h"
+-#include "yahoouserinfo.h"
+-#include "yahoobuddyiconloader.h"
+-
+-// QT Includes
+-#include <qfile.h>
+-#include <qtimer.h>
+-#include <qdom.h>
+-#include <qurl.h>
+-#include <qtextstream.h>
+-
+-// KDE Includes
+-#include <klocale.h>
+-#include <kdebug.h>
+-#include <kmessagebox.h>
+-#include <kiconloader.h>
+-#include <krun.h>
+-#include <kurl.h>
+-#include <kio/global.h>
+-#include <kio/job.h>
+-#include <kio/jobclasses.h>
+-//#include <kimageio.h>
+-#include <kprocess.h>
+-#include <ktempfile.h>
+-#include <kstandarddirs.h>
+-
+-// System Includes
+-#include <cstdlib>
+-#include <cstring>
+-
+-#include <iostream>
+-#include <errno.h>
+-
+-/* exported to libyahoo */
+-#define MAX_PREF_LEN 255
+-char pager_host[MAX_PREF_LEN] = "scs.msg.yahoo.com";
+-char pager_port[MAX_PREF_LEN] = "5050";
+-char filetransfer_host[MAX_PREF_LEN] = "filetransfer.msg.yahoo.com";
+-char filetransfer_port[MAX_PREF_LEN] = "80";
+-
+-char webcam_host[MAX_PREF_LEN] = "webcam.yahoo.com";
+-char webcam_port[MAX_PREF_LEN] = "5100";
+-char webcam_description[MAX_PREF_LEN] = "Philips ToUcam Pro";
+-char local_host[MAX_PREF_LEN] = "";
+-int conn_type = 1;
+-
+-extern "C" {
+-	void receive_file_callback( int id, int fd, int error,
+-	                            const char *filename, unsigned long size, void *data );
+-	void upload_file_callback( int id, int fd, int error, void *data );
+-}
+-
+-struct connect_callback_data
+-{
+-	yahoo_connect_callback callback;
+-	void * callback_data;
+-	int id;
+-};
+-
+-YahooConnectionManager::YahooConnectionManager()
+-{
+-}
+-
+-YahooConnectionManager::~ YahooConnectionManager()
+-{
+-}
+-
+-void YahooConnectionManager::addConnection( QPair< KStreamSocket*, void *> *connection )
+-{
+-	kdDebug(14181) << k_funcinfo << "Adding socket with fd " << connection->first->socketDevice()->socket() << endl;
+-	
+-	m_connectionList.append( connection );
+-}
+-
+-QPair< KStreamSocket*, void *> *YahooConnectionManager::connectionForFD( int fd )
+-{
+-	//kdDebug(14181) << k_funcinfo << "Looking for socket with fd " << fd << endl;
+-	QValueList< QPair< KStreamSocket*, void *> *>::const_iterator it, ycEnd = m_connectionList.constEnd();
+-	KSocketDevice *dev;
+-	
+-	for ( it = m_connectionList.begin(); it != ycEnd; ++it )
+-	{
+-		dev = ( *it )->first->socketDevice();
+-		if ( dev->socket() == fd )
+-		{
+-			//kdDebug(14181) << k_funcinfo << "Found socket" << endl;
+-			return *it;
+-		}
+-	}
+-	
+-	return 0L;
+-}
+-
+-void YahooConnectionManager::remove( KStreamSocket* socket )
+-{
+-	QValueList< QPair< KStreamSocket*, void *> *>::iterator it, ycEnd = m_connectionList.end();
+-	
+-	for ( it = m_connectionList.begin(); it != ycEnd; it++ )
+-	{
+-		if ( ( *it )->first == socket )
+-		{
+-			socket->reset();
+-			m_connectionList.remove( it );
+-			delete socket;
+-			return;
+-		}
+-	}
+-}
+-
+-void YahooConnectionManager::reset()
+-{
+-	QValueList< QPair< KStreamSocket*, void *> *>::iterator it, ycEnd = m_connectionList.end();
+-	
+-	for ( it = m_connectionList.begin(); it != ycEnd; it++ )
+-	{
+-		KStreamSocket *socket = ( *it )->first;
+-		socket->reset();
+-		it = m_connectionList.remove( it );
+-		delete socket;
+-	}
+-}
+-
+-
+-YahooSessionManager::YahooSessionManager()
+-{
+-	if ( managerStatic_ )
+-		kdDebug(14181) << "Yahoo manager already initialized" << endl;
+-	else
+-		managerStatic_ = this;
+-}
+-
+-YahooSessionManager::~YahooSessionManager()
+-{
+-	managerStatic_ = 0L;
+-}
+-
+-void YahooSessionManager::setPager( QString host, int port )
+-{
+-	strcpy( pager_host, host.utf8() );
+-	strcpy( pager_port, QString::number( port ).latin1() );
+-}
+-
+-void YahooSessionManager::setFileTransfer( QString host, int port )
+-{
+-	strcpy( filetransfer_host, host.utf8() );
+-	strcpy( filetransfer_port, QString::number( port ).latin1() );
+-}
+-
+-YahooSession* YahooSessionManager::createSession( const QString username, const QString password )
+-{
+-	int id;
+-	YahooSession *session;
+-
+-	kdDebug(14181) << k_funcinfo << " Initializing" << endl;
+-	id = yahoo_init_with_attributes( username.local8Bit(), password.local8Bit(), "pager_host", pager_host, "pager_port", QString(pager_port).toInt(), 0L );
+-
+-	session = new YahooSession(id, username, password);
+-
+-	kdDebug(14181) << k_funcinfo << " Session created, got id "<< id << " !"<< endl;
+-	m_sessionsMap[id] = session;
+-
+-	return session;
+-
+-}
+-
+-bool YahooSessionManager::cleanSessions()
+-{
+-	QMap< int, YahooSession* >::iterator it;
+-	for ( it=m_sessionsMap.begin(); it != m_sessionsMap.end(); it++)
+-	{
+-		it.data()->logOff();
+-		delete it.data();
+-		m_sessionsMap.remove( it.key() );
+-		kdDebug(14181) << k_funcinfo << " logout " << it.key() << endl;
+-	}
+-	return true;
+-}
+-
+-YahooSession* YahooSessionManager::session(int id)
+-{
+-	return m_sessionsMap[id] ? m_sessionsMap[id] : 0L;
+-}
+-
+-YahooSessionManager* YahooSessionManager::managerStatic_ = 0L;
+-
+-YahooSessionManager* YahooSessionManager::manager()
+-{
+-	if ( managerStatic_ )
+-		return managerStatic_;
+-	else
+-		return ( new YahooSessionManager );
+-}
+-
+- /*
+-    *************************************************************************
+-    * YahooSession Methods                                                  *
+-    *************************************************************************
+-*/
+-
+-YahooSession::YahooSession(int id, const QString username, const QString password)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	m_connId = id;
+-	m_Username = username;
+-	m_Password = password;
+-	m_lastWebcamTimestamp = 0;
+-	currentImage = 0L;
+-	m_iconLoader = new YahooBuddyIconLoader();
+-	
+-	connect( m_iconLoader, SIGNAL(fetchedBuddyIcon(const QString&, KTempFile*, int )), this, SLOT(slotBuddyIconFetched(const QString&, KTempFile*,  int ) ) );
+-}
+-
+-int YahooSession::sessionId() const
+-{
+-	return m_connId;
+-}
+-
+-void YahooSession::login(int initial)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	m_Status = initial;
+-
+-	/* We try to login */
+-	yahoo_login( m_connId, initial );
+-}
+-
+-YahooSession::~YahooSession()
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_logoff( m_connId );
+-	yahoo_close( m_connId );
+-	m_connManager.reset();
+-	delete m_iconLoader;
+-}
+-
+-int YahooSession::setLogLevel(enum yahoo_log_level level)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	return yahoo_set_log_level( level );
+-}
+-
+-void YahooSession::logOff()
+-{
+-	kdDebug(14181)<< k_funcinfo << " " << m_connId <<endl;
+-	yahoo_logoff( m_connId );
+-
+-	m_connManager.reset();
+-
+-}
+-
+-void YahooSession::refresh()
+-{
+-	kdDebug(14181) << k_funcinfo << endl;	
+-	yahoo_refresh( m_connId );
+-}
+-
+-void YahooSession::setIdentityStatus( const QString &identity, int active)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_set_identity_status( m_connId, identity.local8Bit(), active );
+-}
+-
+-void YahooSession::getList()
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_get_list( m_connId );
+-}
+-
+-void YahooSession::keepalive()
+-{
+-	kdDebug(14181) << k_funcinfo << "Sending keepalive packet." << endl;
+-	yahoo_keepalive( m_connId );
+-}
+-
+-void YahooSession::sendIm( const QString &from, const QString &who, const QString &msg, int picture )
+-{
+-	kdDebug(14181) << k_funcinfo << " Picture: " << picture <<  endl;
+-	yahoo_send_im( m_connId, from.local8Bit(), who.local8Bit(), (const char *)msg.utf8(), 1, picture );
+-}
+-
+-void YahooSession::sendTyping( const QString &from, const QString &who, int typ)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_send_typing( m_connId, from.local8Bit(), who.local8Bit(), typ );
+-}
+-
+-void YahooSession::buzzContact( const QString &from, const QString &who, int pictureFlag )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_send_im( m_connId, from.local8Bit(), who.local8Bit(), "<ding>", 1, pictureFlag );
+-}
+-
+-void YahooSession::setAway( enum yahoo_status state, const QString &msg, int away)
+-{
+-	kdDebug(14181)<< k_funcinfo << state << ", " << msg << ", " << away << "]" << m_connId << endl;
+-
+-	yahoo_set_away( m_connId, state, msg.isNull() ? QCString() : msg.local8Bit(), away );
+-}
+-
+-void YahooSession::addBuddy( const QString &who, const QString &group)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_add_buddy( m_connId, who.local8Bit(), group.local8Bit(), "Please add me" );
+-}
+-
+-void YahooSession::removeBuddy( const QString &who, const QString &group)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_remove_buddy( m_connId, who.local8Bit(), group.local8Bit() );
+-}
+-
+-void YahooSession::rejectBuddy( const QString &who, const QString &msg)
+-{
+-	yahoo_reject_buddy( m_connId, who.local8Bit(), msg.local8Bit() );
+-}
+-
+-void YahooSession::ignoreBuddy( const QString &who, int unignore)
+-{
+-	yahoo_ignore_buddy( m_connId, who.local8Bit(), unignore );
+-
+-}
+-
+-void YahooSession::requestBuddyIcon( const QString &who )
+-{
+-	kdDebug(14181) << k_funcinfo << "Requesting avatar for: " << who << endl;
+-	yahoo_buddyicon_request( m_connId, who.local8Bit() );
+-}
+-
+-void YahooSession::downloadBuddyIcon( const QString &who, KURL url, int checksum )
+-{
+-	m_iconLoader->fetchBuddyIcon( QString(who), KURL(url), checksum );
+-}
+-
+-void YahooSession::sendBuddyIconChecksum( int checksum, const QString &who )
+-{
+-	kdDebug(14181) << k_funcinfo << checksum << " sent to " << who << endl;
+-	if ( who.isEmpty() )
+-		yahoo_send_picture_checksum( m_connId, 0, checksum );
+-	else
+-		yahoo_send_picture_checksum( m_connId, who.local8Bit(), checksum );
+-}
+-
+-void YahooSession::sendBuddyIconInfo( const QString &who, const QString &url, int checksum )
+-{
+-	kdDebug(14180) << k_funcinfo << "Url: " << url << " checksum: " << checksum << endl;
+-	yahoo_send_picture_info( m_connId, who.local8Bit(), url.local8Bit(), checksum );
+-}
+-
+-void YahooSession::sendBuddyIconUpdate( const QString &who, int type )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	yahoo_send_picture_update( m_connId, who.local8Bit(), type );
+-}
+-
+-void YahooSession::uploadBuddyIcon( const QString &url, int size )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	YahooUploadData *uploadData = new YahooUploadData();
+-	uploadData->size = size;
+-	uploadData->transmitted = 0;
+-	uploadData->file.setName( url );
+-	uploadData->reportSuccess = false;
+-	
+-	yahoo_send_picture( m_connId, url.local8Bit(), size, upload_file_callback, reinterpret_cast< void*>( uploadData ) );
+-}
+-
+-void YahooSession::changeBuddyGroup( const QString &who, const QString &old_group, const QString &new_group)
+-{
+-	yahoo_change_buddy_group( m_connId, who.local8Bit(), old_group.local8Bit(), new_group.local8Bit() );
+-}
+-
+-void YahooSession::conferenceInvite( const QString & from, const QStringList &who,
+-		const QString &room, const QString &msg )
+-{
+-	YList *tmplist;
+-	tmplist = (YList *) malloc(sizeof(YList));
+-
+-	for ( QStringList::ConstIterator it = who.begin(); it != who.end(); ++it )
+-	{
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_invite( m_connId, from.local8Bit(), tmplist, room.local8Bit(), msg.local8Bit() );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-void YahooSession::conferenceAddinvite( const QString & from, const QString &who, const QString &room,
+-		const QStringList &members, const QString &msg )
+-{
+-
+-	YList *tmplist;
+-	tmplist = (YList *) malloc( sizeof( YList ) );
+-
+-	for ( QStringList::ConstIterator it = members.begin(); it != members.end(); ++it )
+-	{
+-
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_addinvite( m_connId, from.local8Bit(), who.local8Bit(), room.local8Bit(), tmplist, msg.local8Bit() );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-void YahooSession::conferenceDecline( const QString & from, const QStringList &who,
+-		const QString &room, const QString &msg )
+-{
+-	YList *tmplist;
+-	tmplist = (YList *) malloc( sizeof( YList ) );
+-
+-	for ( QStringList::ConstIterator it = who.begin(); it != who.end(); ++it )
+-	{
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_decline( m_connId, from.local8Bit(), tmplist, room.local8Bit(), msg.local8Bit() );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-void YahooSession::conferenceMessage( const QString & from, const QStringList &who,
+-		const QString &room, const QString &msg )
+-{
+-	YList *tmplist;
+-	tmplist = (YList *) malloc( sizeof( YList ) );
+-
+-	for ( QStringList::ConstIterator it = who.begin(); it != who.end(); ++it )
+-	{
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_message( m_connId, from.local8Bit(), tmplist,
+-		room.local8Bit(), (const char *) msg.utf8(), 1 );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-void YahooSession::YahooSession::conferenceLogon( const QString & from, const QStringList &who,
+-		const QString &room)
+-{
+-	YList *tmplist;
+-	tmplist = (YList *) malloc( sizeof( YList ) );
+-
+-	for ( QStringList::ConstIterator it = who.begin(); it != who.end(); ++it )
+-	{
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_logon( m_connId, from.local8Bit(), tmplist, room.local8Bit() );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-void YahooSession::conferenceLogoff( const QString &from, const QStringList &who,
+-		const QString &room )
+-{
+-	YList *tmplist;
+-	tmplist = (YList *) malloc(sizeof(YList));
+-
+-	for ( QStringList::ConstIterator it = who.begin(); it != who.end(); ++it )
+-	{
+-		char *member;
+-		member = strdup( (*it).local8Bit() );
+-		y_list_append( tmplist, member );
+-	}
+-
+-	yahoo_conference_logoff( m_connId, from.local8Bit(), tmplist, room.local8Bit() );
+-
+-	y_list_free_1( tmplist );
+-	y_list_free( tmplist );
+-}
+-
+-int YahooSession::sendFile( const QString& who, const QString& msg,
+-               const QString& name, long size )
+-{	
+-	kdDebug(14181) << k_funcinfo << "Offering file " << name << " (" << size << ") to " << who << endl;
+-	YahooUploadData *upload = new YahooUploadData();
+-	upload->size = size;
+-	upload->transmitted = 0;
+-	upload->file.setName( name );
+-	upload->reportSuccess = true;
+-	
+-	yahoo_send_file( m_connId, who.local8Bit(), msg.local8Bit(), name.local8Bit(), size, upload_file_callback, upload );
+-	
+-	return 0;
+-}
+-
+-
+-int YahooSession::getUrlHandle( Kopete::Transfer *trans )
+-{
+-	char *_url;
+-
+-	m_kopeteTransfer = trans;
+-	_url = strdup( trans->info().internalId().local8Bit() );
+-	m_Filename = strdup( QFile::encodeName(trans->destinationURL().path()) );
+-
+-	yahoo_get_url_handle(m_connId, _url, receive_file_callback, 0);
+-
+-	free(_url);
+-	return 0;
+-}
+-
+-enum yahoo_status YahooSession::currentStatus()
+-{
+-	return yahoo_current_status( m_connId );
+-}
+-
+-const YList *YahooSession::getLegacyBuddyList()
+-{
+-	return yahoo_get_buddylist( m_connId );
+-}
+-
+-QStringList YahooSession::getBuddylist()
+-{
+-	//return yahoo_get_buddylist(m_connId);
+-	return QStringList();
+-}
+-
+-QStringList YahooSession::getIgnorelist()
+-{
+-	//return yahoo_get_ignorelist(m_connId);
+-	return QStringList();
+-}
+-
+-QStringList YahooSession::getIdentities()
+-{
+-	//return yahoo_get_identities(m_connId);
+-	return QStringList();
+-}
+-
+-QString YahooSession::getCookie( const QString &which)
+-{
+-	return QString( yahoo_get_cookie( m_connId, which.latin1() ) );
+-}
+-
+-QString YahooSession::getProfile_url( void )
+-{
+-	return QString( yahoo_get_profile_url() );
+-}
+-
+-void YahooSession::requestWebcam( const QString& from )
+-{
+-	yahoo_webcam_get_feed( m_connId, from.latin1() );
+-}
+-
+-void YahooSession::closeWebcam( const QString& from )
+-{
+-	yahoo_webcam_close_feed( m_connId, from.latin1() );
+-}
+-
+-void YahooSession::slotLoginResponseReceiver( int /* succ */, char * /* url */ )
+-{
+-	kdDebug(14181)<< k_funcinfo << endl;
+-}
+-
+-void YahooSession::stealthContact( const QString &who, int unstealth )
+-{
+-	kdDebug(14181)<< k_funcinfo << "Unstealth: " << unstealth << endl;
+-	yahoo_stealth_buddy( m_connId, who.local8Bit(), unstealth );
+-}
+-
+-void YahooSession::getUserInfo( const QString &who )
+-{
+-	m_targetID = who;
+-	m_UserInfo = QString::null;
+-	//QString url = QString::fromLatin1("http://insider.msg.yahoo.com/ycontent/?filter=timef&ab2=0&intl=us&os=win&%1&%2").arg(getCookie("y")).arg(getCookie("t"));
+-	QString url = QString::fromLatin1("http://insider.msg.yahoo.com/ycontent/?filter=timef&ab2=0&intl=us&os=win");
+-	
+-	mTransferJob = KIO::get( url , false, false );
+-	mTransferJob->addMetaData("cookies", "manual");
+-	mTransferJob->addMetaData("setcookies", QString::fromLatin1("Cookie: Y=%1; T=%2").arg(getCookie("y")).arg(getCookie("t")) );
+-	connect( mTransferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotUserInfoData( KIO::Job*, const QByteArray & ) ) );
+-	connect( mTransferJob, SIGNAL( result( KIO::Job *) ), this, SLOT( slotUserInfoResult( KIO::Job* ) ) );
+-}
+-
+-void YahooSession::slotUserInfoResult( KIO::Job* job )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	if ( job->error () || mTransferJob->isErrorPage () )
+-		kdDebug(14180) << k_funcinfo << "Could not retrieve server side addressbook for user info." << endl;
+-	else {
+-		QDomDocument doc;
+-		QDomNodeList list;
+-		QDomElement e;
+-		QString msg;
+-		uint it = 0;
+-		
+-		kdDebug(14180) << k_funcinfo << "Server side Adressbook successfully retrieved." << endl;
+-		//kdDebug(14180) << "Adressbook:" << endl << m_UserInfo << endl;
+-		
+-		doc.setContent( m_UserInfo );
+-		list = doc.elementsByTagName( "record" );			// Get records
+-		
+-		for( it = 0; it < list.count(); it++ )	{
+-			if( !list.item( it ).isElement() )
+-				continue;
+-			e = list.item( it ).toElement();
+-			if( e.attribute("userid") != m_targetID )
+-				continue;
+-			
+-			YahooUserInfo info;
+-			kdDebug(14180) << k_funcinfo << "dbID: " << e.attribute("dbid")  << endl;
+-			info.userID = e.attribute("userid");
+-			info.abID = e.attribute("dbid");
+-			info.firstName = e.attribute( "fname" );
+-			info.lastName = e.attribute( "lname" );
+-			info.nickName = e.attribute( "nname" );
+-			info.email =  e.attribute( "email" );
+-			info.phoneHome = e.attribute( "hphone" );
+-			info.phoneWork = e.attribute( "wphone" );
+-			info.phoneMobile = e.attribute( "mphone" );
+-			
+-			YahooUserInfoDialog* theDialog = new YahooUserInfoDialog( Kopete::UI::Global::mainWidget(), "User Information" );
+-			theDialog->setUserInfo( info );
+-			theDialog->setSession( this );
+-			theDialog->show();
+-			
+-			return;
+-		}
+-		
+-		// If we get here, no entry was found --> ask to create a new one
+-    	if( KMessageBox::Yes == KMessageBox::questionYesNo(Kopete::UI::Global::mainWidget(), i18n( "Do you want to create a new entry?" ), i18n( "No Yahoo Addressbook Entry Found" ), i18n("Create Entry"), i18n("Do Not Create")) ){
+-			YahooUserInfo info;
+-			info.userID = m_targetID;
+-			info.abID = "-1";
+-			
+-			YahooUserInfoDialog* theDialog = new YahooUserInfoDialog( Kopete::UI::Global::mainWidget(), "User Information" );
+-			theDialog->setUserInfo( info );
+-			theDialog->setSession( this );
+-			theDialog->show();
+-		} else {
+-			viewUserProfile( m_targetID );
+-		}
+-	}	
+-}
+-
+-void YahooSession::slotUserInfoData( KIO::Job* /*job*/, const QByteArray &info  )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;	
+-	m_UserInfo += info;	
+-}
+-
+-void YahooSession::saveAdressBookEntry( const YahooUserInfo &entry)
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	QString url;
+-
+-
+-	// FIX for bug 107472 by Heiko Schaefer <heiko at rangun.de>
+-        // The fields in the YahooUserInfo should get encoded into an valid
+-        // URL. Before we turn them into latin1()
+-	QString firstName = QString::fromUtf8(entry.firstName.latin1());
+-	QString lastName  = QString::fromUtf8(entry.lastName.latin1());
+-	QString nickName  = QString::fromUtf8(entry.nickName.latin1());
+-
+-	QUrl::encode(firstName);
+-	QUrl::encode(lastName);
+-	QUrl::encode(nickName);
+-
+-	if( entry.abID.toInt() > 0 )	{		// This is an Update --> append entry-ID
+-		url = QString("http://insider.msg.yahoo.com/ycontent/?addab2=0&ee=1&ow=1&id=%0&fn=%1&ln=%2&yid=%3&nn=%4&e=%5&hp=%6&wp=%7")
+-			.arg(entry.abID).arg(firstName).arg(lastName).arg(entry.userID).
+-			arg(nickName).arg(entry.email).arg(entry.phoneHome).arg(entry.phoneWork);
+-		//url += QString::fromLatin1("&%1&%2&%3&%4").arg(getCookie("y")).arg(getCookie("t")).arg(getCookie("b")).arg(getCookie("q"));
+-	} else {
+-		url = QString("http://address.yahoo.com/yab/us?A=m&v=PG&ver=2&fn=%0&ln=%1&yid=%2&nn=%3&e=%4&hp=%5&wp=%6")
+-			.arg(firstName).arg(lastName).arg(entry.userID).arg(nickName)
+-			.arg(entry.email).arg(entry.phoneHome).arg(entry.phoneWork);
+-	/*url = QString::fromLatin1("http://insider.msg.yahoo.com/ycontent/?addab2=0&fn=%0&ln=%1&yid=%2&nn=%3&e=%4&hp=%5&wp=%6").arg(entry.firstName).arg(entry.lastName).arg(entry.userID).arg(entry.nickName).arg(entry.email).arg(entry.phoneHome).arg(entry.phoneWork);*/
+-		//url += QString::fromLatin1("&%1&%2&%3&%4").arg(getCookie("y")).arg(getCookie("t")).arg(getCookie("b")).arg(getCookie("q"));
+-
+-	}
+-	kdDebug(14180) << url << endl;
+-	
+-	m_UserInfo = QString::null;
+-	mTransferJob = KIO::get( url , false, false );
+-	mTransferJob->addMetaData("cookies", "manual");
+-	mTransferJob->addMetaData("setcookies", QString::fromLatin1("Cookie: Y=%1; T=%2").arg(getCookie("y")).arg(getCookie("t")) );
+-	connect( mTransferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotUserInfoData( KIO::Job*, const QByteArray & ) ) );
+-	connect( mTransferJob, SIGNAL( result( KIO::Job *) ), this, SLOT( slotUserInfoSaved( KIO::Job* ) ) );
+-}
+-void YahooSession::slotUserInfoSaved( KIO::Job* job )
+-{
+-	kdDebug(14180) << k_funcinfo << endl << "Return data:" << m_UserInfo << endl;
+-	
+-	if ( job->error() || mTransferJob->isErrorPage() || m_UserInfo.find(m_targetID) < 0 )	{
+-		kdDebug(14180) << "Could not save the adressbook entry." << endl;
+-		KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n( "An unknown error occurred. A possible reason is a invalid email address." ), i18n("Error") );
+-	} else {
+-		kdDebug(14180) << "Adressbook entry succesfully saved." << endl;		
+-	}
+-}
+-
+-void YahooSession::viewUserProfile( const QString &who )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	
+-	QString profileSiteString = QString::fromLatin1("http://profiles.yahoo.com/") + who;
+-	KRun::runURL( KURL( profileSiteString ) , "text/html" );	
+-}
+-
+- /*
+-    *************************************************************************
+-    * Callback implementation                                               *
+-    *************************************************************************
+-*/
+-
+-extern "C"
+-{
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_login_response ) ( int id, int succ, const char *url )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session(id);
+-	session->_loginResponseReceiver( succ, url );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_buddies ) ( int id, YList * buds )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotBuddiesReceiver( buds );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_ignore ) ( int id, YList * igns )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotIgnoreReceiver( igns );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_identities ) ( int id, YList * ids )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session(id);
+-	session->_gotIdentitiesReceiver(ids);
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_cookies )( int /*id*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ping)(int /*id*/, const char */*errormsg*/)
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_status_changed )( int id, const char *who, int stat,
+-	const char *msg, int away, int /*idle*/, int /*mobile*/ )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_statusChangedReceiver( (char*)who, stat, (char*)msg, away );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_im )( int id, const char */*me*/, const char *who, 		const char *msg, long tm, int stat, int utf8 )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotImReceiver( (char*)who, (char*)msg, tm, stat, utf8 );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_conf_invite )(int id, const char */*me*/, const char *who, const char *room, const char *msg, YList *members)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotConfInviteReceiver( (char*)who, (char*)room, (char*)msg, members );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_conf_userdecline )(int id, const char */*me*/, const char *who, const char *room, const char *msg)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_confUserDeclineReceiver( (char*)who, (char*)room, (char*)msg );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_conf_userjoin )(int id, const char */*me*/, const char *who, const char *room)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_confUserJoinReceiver( (char*)who, (char*)room );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_conf_userleave )(int id, const char */*me*/, const char *who, const char *room)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_confUserLeaveReceiver( (char*)who, (char*)room );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_conf_message )(int id, const char */*me*/, const char *who, const char *room, const char *msg, int utf8)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_confMessageReceiver( (char*)who, (char*)room, (char*)msg, utf8 );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_chat_cat_xml )( int /*id*/, const char* /*xml*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_chat_join )( int /*id*/, const char */*me*/, const char */*room*/, const char */*topic*/, YList */*members*/, int /*fd*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_chat_userjoin )( int /*id*/, const char */*me*/, const char */*room*/, struct yahoo_chat_member */*who*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_chat_userleave )( int /*id*/, const char */*me*/, const char */*room*/, const char */*who*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_chat_message )( int /*id*/, const char */*me*/, const char */*who*/, const char */*room*/, const char */*msg*/, int /*msgtype*/, int /*utf8*/)
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int /*id*/, const char */*me*/)
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int /*id*/, const char */*me*/)
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_file )( int id, const char */*me*/, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotFileReceiver( (char*)who, (char*)url, expires, (char*)msg, (char*)fname, fesize );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_contact_added )( int id, const char *myid, const char *who, const char *msg )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_contactAddedReceiver( (char*)myid, (char*)who, (char*)msg );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_rejected )( int id, const char *who, const char *msg )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_rejectedReceiver( (char*)who, (char*)msg );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_typing_notify )( int id, const char */*me*/, const char *who, int stat )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_typingNotifyReceiver( (char*)who, stat );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_game_notify )(int id, const char */*me*/, const char *who, int stat)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gameNotifyReceiver( (char*)who, stat );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_mail_notify )( int id, const char *from, const char *subj, int cnt )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_mailNotifyReceiver( (char*)from, (char*)subj, cnt );
+-
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_system_message )( int id, const char *msg )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_systemMessageReceiver( (char*)msg );
+-
+-}
+-
+-	void YAHOO_CALLBACK_TYPE( ext_yahoo_error )( int id, const char *err, int fatal, int /*num*/ )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_errorReceiver( (char*)err, fatal );
+-
+-}
+-
+-int YAHOO_CALLBACK_TYPE( ext_yahoo_log )( const char* /*fmt*/, ... )
+-{
+-	/* Do nothing? */
+-	return 0;
+-}
+-
+-int YAHOO_CALLBACK_TYPE( ext_yahoo_add_handler )( int id, int fd, yahoo_input_condition cond, void * data )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	return session->_addHandlerReceiver( fd, cond, data );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_remove_handler )( int id, int fd )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_removeHandlerReceiver( fd );
+-
+-}
+-
+-int YAHOO_CALLBACK_TYPE( ext_yahoo_connect )( const char *host, int port )
+-{
+-	return YahooSessionManager::manager()->_hostConnectReceiver( (char*)host, port );
+-}
+-
+-int YAHOO_CALLBACK_TYPE( ext_yahoo_connect_async )( int id, const char *host, int port,
+-		yahoo_connect_callback callback, void *callback_data )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	return session->_hostAsyncConnectReceiver( (char*)host, port, callback, callback_data );
+-}
+-
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_got_webcam_image )( int id, const char* who,
+-		const unsigned char* image, unsigned int image_size, unsigned int real_size,
+-		unsigned int timestamp )
+-{
+-	YahooSession* session = YahooSessionManager::manager()->session( id );
+-	return session->_gotWebcamImage( (char*)who, (unsigned char*)image, image_size, real_size, timestamp );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_webcam_invite )( int id, const char */*me*/, const char* from )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	session->_gotWebcamInvite( (char*)from );
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_webcam_invite_reply )( int /*id*/, const char */*me*/, const char* /*from*/, int /*accept*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_webcam_closed )( int id, const char* who, int reason )
+-{
+-	YahooSession* session = YahooSessionManager::manager()->session( id );
+-	session->_webcamDisconnected( (char*)who, reason );
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int /*id*/, int /*found*/, int /*start*/, int /*total*/, YList */*contacts*/)
+-{
+-	
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_webcam_viewer )( int /*id*/, const char* /*who*/, int /*connect*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE( ext_yahoo_webcam_data_request )( int /*id*/, int /*send*/ )
+-{
+-	/* Not implemented , No receiver yet */
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon)(int id, const char */*me*/, const char *who, const char *url, int checksum)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if ( session )
+-		session->_gotBuddyIconReceiver( id, (char*)who, (char*)url, checksum );
+-}
+-
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon_checksum)(int id, const char */*me*/, const char *who, int checksum)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if( session )
+-		session->_gotBuddyIconChecksumReceiver( id, (char*)who, checksum );
+-}
+-	
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyiconrequest)(int id, const char */*me*/, const char *who)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if ( session )
+-		session->_gotBuddyIconRequestReceiver( id, (char*)who );
+-}
+-	
+-void YAHOO_CALLBACK_TYPE(ext_yahoo_buddyicon_uploaded)(int id, const char *url)
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if ( session )
+-		session->_gotBuddyIconUploadResponseReceiver( id, (char*)url );
+-}
+-	
+-void receive_file_callback( int id, int fd, int error,
+-	                            const char *filename, unsigned long size, void *data )
+-{
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if ( session )
+-		session->_receiveFileProceed( id, fd, error, (char*)filename, size, (char*)data );
+-}
+-
+-void upload_file_callback( int id, int fd, int error, void *data )
+-{
+-	
+-	YahooSession *session = YahooSessionManager::manager()->session( id );
+-	if ( session )
+-		session->_uploadFileReceiver( id, fd, error, data );
+-}
+-/* End of extern C */
+-}
+-
+-
+-/*
+-    *************************************************************************
+-    * Private Session Callback Receiver, don't use them                     *
+-    *************************************************************************
+-*/
+-
+-void YahooSession::_uploadFileReceiver( int /*id*/, int fd, int error, void *data )
+-{
+-	YahooUploadData *uploadData = reinterpret_cast< YahooUploadData *>( data );
+-	kdDebug(14181) << k_funcinfo << "Url: " << uploadData->file.name() << " Size: " << uploadData->size << endl;
+-
+-	if ( error )
+-	{
+-		kdDebug(14180) << "Could not upload file " << uploadData->file.name() << ". Error: " << error << endl;
+-		KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n( "An unknown error occurred when trying to upload the file."
+-			" The file was not transferred." ), i18n("Error") );
+-		return;
+-	}
+-	
+-	if ( !uploadData->file.open(IO_ReadOnly) )
+-	{
+-		kdDebug(14180) << "Could not open local file." << endl;
+-		KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n( "Could not open local file." ), i18n("Error") );
+-		return;
+-	}
+-	
+-	slotTransmitFile( fd, uploadData );
+-}
+-
+-void YahooSession::slotTransmitFile( int fd, YahooUploadData *uploadData )
+-{
+-	QPair< KStreamSocket*, void *> *connection =  m_connManager.connectionForFD( fd );
+-	if( !connection )
+-		return;
+-		
+-	KStreamSocket* socket = connection->first;
+-	if( !socket )
+-		return;
+-	
+-	if( uploadData->transmitted >= uploadData->file.size() )
+-	{
+-		kdDebug(14181) << k_funcinfo << "File successfully uploaded." << endl;
+-		if( uploadData->reportSuccess )
+-			KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Information, i18n("The file was successfully transmitted.") );
+-		uploadData->file.close();
+-		delete uploadData;
+-		m_connManager.remove( socket );
+-		return;
+-	}
+-	
+-	
+-	uint written;
+-	uint read;
+-	char buf[2048];
+-	
+-	socket->setBlocking( true );
+-	
+-	read = uploadData->file.readBlock( buf, 2048 );
+-	
+-	written = socket->writeBlock( buf, read );
+-	
+-	uploadData->transmitted += written;
+-	
+-	if( written != read )
+-	{
+-		kdDebug(14181) << k_funcinfo << "An error occurred while sending the file: " << socket->error() << " transmitted: " << uploadData->transmitted << endl;
+-		if( uploadData->reportSuccess )
+-			KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Error, i18n("An error occured while sending the file: %1").arg( socket->error() ) );
+-		uploadData->file.close();
+-		delete uploadData;
+-		m_connManager.remove( socket );
+-	}
+-	else
+-		slotTransmitFile( fd, uploadData );
+-}
+-
+-void YahooSession::_gotBuddyIconUploadResponseReceiver( int /*id*/, const char *url)
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	emit buddyIconUploaded( QString( url ) );
+-}
+-
+-void YahooSession::_gotBuddyIconReceiver( int /*id*/, char *who, char *url, int checksum )
+-{
+-	kdDebug(14181) << k_funcinfo << "BuddyIcon reveived from: " << who << " checksum: " << checksum <<endl;
+-	kdDebug(14181) << k_funcinfo << "BuddyIcon-Url: " << url <<endl;
+-
+-	emit gotBuddyIconInfo( QString( who ), KURL( url ), checksum );
+-}
+-
+-void YahooSession::_gotBuddyIconChecksumReceiver( int /*id*/, char *who, int checksum )
+-{
+-	kdDebug(14181) << k_funcinfo << "checksum: " << checksum << " received from: " << who << endl;
+-
+-	emit gotBuddyIconChecksum( QString( who ), checksum );
+-	
+-}
+-
+-void YahooSession::_gotBuddyIconRequestReceiver( int /*id*/, char *who )
+-{
+-	kdDebug(14181) << k_funcinfo << "Got Buddy Icon Request from: " << who << endl;
+-
+-	emit gotBuddyIconRequest ( QString( who ) );
+-}
+-
+-void YahooSession::slotBuddyIconFetched(const QString &who, KTempFile *file, int checksum)
+-{
+-	emit gotBuddyIcon( who, file, checksum );
+-}
+-
+-void YahooSession::_receiveFileProceed( int id, int fd, int error,
+-                                        const char */*filename*/, unsigned long /*size*/, void */*data*/ )
+-{
+-	kdDebug(14181) << k_funcinfo << "FD:" << fd << " Filename:" << m_Filename <<endl;
+-	int read = 0, received = 0;
+-	char buf[1024];
+-
+-	if ( error )
+-	{
+-		kdDebug(14180) << "Could not download file. Error: " << error << endl;
+-		KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n( "An error occurred when trying to download the file." ), i18n("Error") );
+-		return;
+-	}
+-	QPair< KStreamSocket*, void *> *connection =  m_connManager.connectionForFD( fd );
+-	if( !connection )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No connection found for fd." << endl;
+-		return;
+-	}
+-	
+-	KStreamSocket* socket = connection->first;
+-	if( !socket )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No existing socket for connection found. We're screwed" << endl;
+-		return;
+-	}
+-	
+-	QFile file( m_Filename );
+-	if ( file.open(IO_WriteOnly ) )
+-	{
+-		QTextStream stream( &file );
+-		while( (read = socket->readBlock( buf, 1024 )) > 0 )
+-		{
+-			stream << buf;
+-			received += read;
+-			m_kopeteTransfer->slotProcessed( received );
+-		}
+-		m_kopeteTransfer->slotComplete();
+-		file.close();
+-	} else	
+-		m_kopeteTransfer->slotError( KIO::ERR_CANNOT_OPEN_FOR_WRITING, i18n("Cannot open file %1 for writing.\n%2")
+-									.arg( m_Filename, file.errorString() ) );
+-	
+-	ext_yahoo_remove_handler( id, fd );
+-	return;
+-}
+-
+-void YahooSession::_loginResponseReceiver( int succ, const char *url )
+-{
+-
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-	emit loginResponse( succ, QString( url ) );
+-}
+-
+-void YahooSession::_gotIgnoreReceiver( YList * igns )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-	YList *l;
+-	QStringList ign_list;
+-
+-	for ( l = igns; l; l = l->next )
+-	{
+-		struct yahoo_buddy *bud = ( yahoo_buddy* ) l->data;
+-
+-		if( !bud )
+-		{
+-			kdDebug(14181) << k_funcinfo << " Null Id" << endl;
+-			continue;
+-		}
+-		else
+-		{
+-			kdDebug(14181) << k_funcinfo << "Got buddy: " << bud->id << endl;
+-			ign_list.append( QString( bud->id ) );
+-		}
+-	}
+-
+-	emit gotIgnore(ign_list);
+-}
+-
+-void YahooSession::_gotBuddiesReceiver( YList * buds )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-	int buddyListCount = 0;
+-	YList *l;
+-
+-	for ( l = buds; l; l = l->next )
+-	{
+-		struct yahoo_buddy *bud = ( yahoo_buddy* )l->data;
+-
+-		if( !bud )
+-		{
+-			kdDebug(14181) << k_funcinfo << " Null Buddy" << endl;
+-			continue;
+-		}
+-		else
+-		{
+-			kdDebug(14181) << k_funcinfo << " " << bud->id << endl;
+-			emit gotBuddy( QString( bud->id ) , QString::fromLocal8Bit( bud->real_name ),
+-					QString::fromLocal8Bit( bud->group ) );
+-			buddyListCount++;
+-		}
+-	}
+-
+-	emit buddyListFetched( buddyListCount );
+-}
+-
+-void YahooSession::_gotIdentitiesReceiver( YList *ids )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-
+-	YList *l;
+-	QStringList idslist;
+-
+-	for ( l = ids; l; l = l->next )
+-	{
+-		char *userid = ( char* ) l->data;
+-
+-		if ( !userid )
+-		{
+-			kdDebug(14181) << k_funcinfo << endl;
+-			continue;
+-		}
+-		else
+-		{
+-			kdDebug(14181) << k_funcinfo << userid << endl;
+-			idslist.append( QString( userid ) );
+-		}
+-	}
+-
+-	emit gotIdentities( idslist );
+-}
+-
+-void YahooSession::_statusChangedReceiver( char *who, int stat, char *msg, int away )
+-{
+-//	kdDebug(14181) << k_funcinfo << endl;
+-	emit statusChanged( QString::fromLocal8Bit( who ), stat, QString::fromLocal8Bit( msg ), away );
+-}
+-
+-void YahooSession::_gotImReceiver( char *who, char *msg, long tm, int stat, int utf8 )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-	QString convertedMessage;
+-
+-	if ( utf8 )
+-		convertedMessage = QString::fromUtf8( msg );
+-	else
+-		convertedMessage = QString::fromLocal8Bit( msg );
+-
+-	if ( convertedMessage == "<ding>" ) {
+-		kdDebug(14181)<<"got BUZZ"<<endl;
+-		emit gotBuzz( QString::fromLocal8Bit( who ), tm );
+-	}
+-	else {
+-		kdDebug(14181)<<"got IM"<<endl;
+-		emit gotIm( QString::fromLocal8Bit( who ), convertedMessage, tm, stat );
+-	}
+-}
+-
+-void YahooSession::_gotConfInviteReceiver( char *who, char *room, char *msg, YList *members )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-
+-	YList *l;
+-	QStringList member_list;
+-
+-	for ( l = members; l; l = l->next )
+-	{
+-		char *buddy = ( char* ) l->data;
+-		if ( !buddy )
+-		{
+-			kdDebug(14181) << k_funcinfo << " Null Id" << endl;
+-			continue;
+-		}
+-		else
+-		{
+-			member_list.append( QString::fromLocal8Bit( buddy ) );
+-		}
+-	}
+-
+-	emit gotConfInvite( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( room ),
+-		 QString::fromLocal8Bit( msg ), member_list) ;
+-}
+-
+-void YahooSession::_confUserDeclineReceiver( char *who, char *room, char *msg )
+-{
+-	kdDebug(14181) <<  k_funcinfo << endl;
+-	emit confUserDecline( QString::fromLocal8Bit(who), QString::fromLocal8Bit( room ),
+-			QString::fromLocal8Bit(msg));
+-}
+-
+-void YahooSession::_confUserJoinReceiver( char *who, char *room )
+-{
+-
+-	emit confUserJoin( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( room ) );
+-}
+-
+-void YahooSession::_confUserLeaveReceiver( char *who, char *room )
+-{
+-
+-	emit confUserLeave( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( room ) );
+-}
+-
+-void YahooSession::_confMessageReceiver( char *who, char *room, char *msg, int utf8 )
+-{
+-	QString convertedMessage;
+-
+-	if ( utf8 )
+-		convertedMessage = QString::fromUtf8( msg );
+-	else
+-		convertedMessage = QString::fromLocal8Bit( msg );
+-
+-	emit confMessage( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( room ), convertedMessage);
+-}
+-
+-void YahooSession::_gotFileReceiver( char *who, char *url, long expires, char *msg,
+-		char *fname, unsigned long fesize )
+-{
+-
+-	emit gotFile( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( url ),
+-			expires, QString::fromLocal8Bit( msg ), QString::fromLocal8Bit( fname ), fesize );
+-}
+-
+-void YahooSession::_contactAddedReceiver( char *myid, char *who, char *msg )
+-{
+-
+-	emit contactAdded( QString::fromLocal8Bit( myid ), QString::fromLocal8Bit( who ),
+-			QString::fromLocal8Bit( msg ) );
+-}
+-
+-void YahooSession::_rejectedReceiver( char *who, char *msg )
+-{
+-
+-	emit rejected( QString::fromLocal8Bit( who ), QString::fromLocal8Bit( msg ) );
+-}
+-
+-void YahooSession::_typingNotifyReceiver( char *who, int stat )
+-{
+-
+-	emit typingNotify( QString::fromLocal8Bit( who ), stat );
+-}
+-
+-void YahooSession::_gameNotifyReceiver( char *who, int stat )
+-{
+-	emit gameNotify( QString::fromLocal8Bit( who ), stat );
+-}
+-
+-void YahooSession::_mailNotifyReceiver( char *from, char *subj, int cnt )
+-{
+-	//kdDebug(14181) << k_funcinfo << " session: " <<  endl;
+-
+-	emit mailNotify( QString::fromLocal8Bit( from ), QString::fromLocal8Bit( subj ), cnt);
+-}
+-
+-void YahooSession::_systemMessageReceiver( char *msg )
+-{
+-	kdDebug(14181) << k_funcinfo << " session: " << endl;
+-
+-	emit systemMessage( QString::fromLocal8Bit( msg ) );
+-}
+-
+-void YahooSession::_errorReceiver( char *err, int fatal )
+-{
+-	kdDebug(14181) << k_funcinfo << " session: " << m_connId <<  endl;
+-
+-	emit error( err, fatal );
+-}
+-
+-int YahooSession::_logReceiver( char */*fmt*/, ... )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	return 0;
+-}
+-
+-int YahooSession::_addHandlerReceiver( int fd, yahoo_input_condition cond, void *data )
+-{
+-	//kdDebug(14181) << k_funcinfo << " " << m_connId << " Socket: " << fd << endl;
+-
+-	if ( fd == -1 )
+-	{
+-		kdDebug(14181) << k_funcinfo << "why is fd -1?" << endl;
+-		return -1;
+-	}
+-	
+-	QPair< KStreamSocket*, void *> *connection = m_connManager.connectionForFD( fd );
+-	if ( !connection )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No existing socket for connection found. We're screwed"
+-			<< endl;
+-		return -1;
+-	}
+-	
+-	KStreamSocket *socket = connection->first;
+-	connection->second = data;
+-	
+-	/* This works ONLY IF (YAHOO_INPUT_READ==1 && YAHOO_INPUT_WRITE==2) */
+-	int tag = 0;
+-	if ( cond == YAHOO_INPUT_READ )
+-	{
+-		//kdDebug(14181) << k_funcinfo << " add handler read" << endl;
+-		socket->enableRead( true );
+-		connect ( socket, SIGNAL( readyRead() ), this, SLOT( slotReadReady() ) );
+-		tag = 2*fd + YAHOO_INPUT_READ;
+-	}
+-	else if ( cond == YAHOO_INPUT_WRITE )
+-	{
+-		//kdDebug(14181) << k_funcinfo << " add handler write" << endl;
+-		socket->enableWrite( true );
+-		connect ( socket, SIGNAL( readyWrite() ), this, SLOT( slotWriteReady() ) );
+-		tag = 2*fd + YAHOO_INPUT_WRITE;
+-	}
+-	return tag;
+-}
+-
+-void YahooSession::addHandler( int /*fd*/, yahoo_input_condition /*cond*/ )
+-{
+-}
+-
+-void YahooSession::_removeHandlerReceiver( int tag )
+-{
+-	//kdDebug(14181) << k_funcinfo << " " << m_connId << " tag: " << tag << endl;
+-
+-	if ( tag == 0 )
+-		return;
+-
+-	QPair< KStreamSocket*, void *> *connection = m_connManager.connectionForFD( (tag-1)/2 );
+-	if ( !connection )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No existing socket for connection found. We're screwed"
+-			<< endl;
+-		return;
+-	}
+-	KStreamSocket *socket = connection->first;
+-	/* This works ONLY IF (YAHOO_INPUT_READ==1 && YAHOO_INPUT_WRITE==2) */
+-	if( tag % 2 == YAHOO_INPUT_READ ) {
+-		//kdDebug(14181) << k_funcinfo << " read off" << endl;
+-		socket->enableRead( false );
+-		disconnect ( socket, SIGNAL( readyRead() ), this, SLOT( slotReadReady() ) );
+-	}
+-	else 
+-	{
+-		//kdDebug(14181) << k_funcinfo << " write off" << endl;
+-		socket->enableWrite( false );
+-		disconnect ( socket, SIGNAL( readyWrite() ), this, SLOT( slotWriteReady() ) );
+-	}
+-}
+-
+-void YahooSession::removeHandler( int /*fd*/ )
+-{
+-}
+-
+-int YahooSessionManager::_hostConnectReceiver( char* /*host*/, int /*port*/ )
+-{
+-	kdDebug(14181) << k_funcinfo << endl;
+-	return 0;
+-}
+-
+-int YahooSession::_hostAsyncConnectReceiver( char *host, int port,
+-		yahoo_connect_callback callback, void *callback_data )
+-{
+-	kdDebug(14181) << k_funcinfo << "Establishing connection to " << host << " on port " << port << endl;
+-	KStreamSocket* yahooSocket = new KStreamSocket( host, QString::number( port ) );
+-
+-	m_ccd = ( struct connect_callback_data* ) calloc( 1, sizeof( struct connect_callback_data ) );
+-	m_ccd->callback = callback;
+-	m_ccd->callback_data = callback_data;
+-	m_ccd->id = m_connId;
+-	
+-	connect( yahooSocket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotAsyncConnectSucceeded() ) );
+-	connect( yahooSocket, SIGNAL( gotError(int) ), this, SLOT( slotAsyncConnectFailed(int) ) );
+-	
+-	yahooSocket->connect();
+-	
+-	return 0;
+-}
+-
+-void YahooSession::slotAsyncConnectSucceeded()
+-{
+-	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
+-	kdDebug(14181) << k_funcinfo << " Connected! fd "<< socket->socketDevice()->socket() << endl;
+-	QPair< KStreamSocket*, void * > *connection = new QPair< KStreamSocket*, void * >( socket, 0L );
+-	m_connManager.addConnection( connection );
+-	
+-	disconnect( socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotAsyncConnectSucceeded() ) );
+-	disconnect( socket, SIGNAL( gotError(int) ), this, SLOT( slotAsyncConnectFailed(int) ) );
+-	
+-	m_ccd->callback( socket->socketDevice()->socket(), 0, m_ccd->callback_data );
+-}
+-
+-void YahooSession::slotAsyncConnectFailed( int error)
+-{
+-	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
+-	kdDebug(14181) << k_funcinfo << " Failed with error " << error << endl;
+-	socket->close();
+-	delete socket;
+-	//_errorReceiver(0, 1);
+-	_errorReceiver(0, 0);
+-}
+-
+-void YahooSession::_gotWebcamInvite( const char* who )
+-{
+-	emit gotWebcamInvite( QString::fromLocal8Bit( who ) );
+-}
+-
+-void YahooSession::_gotWebcamImage( const char* who, const unsigned char* image,
+-                                    unsigned int image_size, unsigned int real_size,
+-                                    unsigned int timestamp )
+-{
+-	m_lastWebcamTimestamp = timestamp;
+-	if ( image_size == 0 || real_size == 0)
+-	{
+-		// use timestamp to handle syncronization here???
+-		return;
+-	}
+-	
+-	if ( currentImage == NULL )
+-	{
+-		currentImage = new QBuffer();
+-		currentImage->open(IO_ReadWrite);
+-	}
+-	currentImage->writeBlock( (char *) image, real_size );
+-	//kdDebug(14181) << " real_size " << real_size << " image_size " << image_size << " timestamp " << timestamp << " " << who << endl;
+-	
+-	if ( currentImage->size() == image_size ) {
+-		QPixmap webcamImage;
+-		currentImage->close();
+-		// uncomment the following line when jpc is supported by kdelibs
+-		//webcamImage.loadFromData( currentImage->buffer() );
+-		
+-		/****** DELETE below once kdelibs has jpc support ******/
+-		KTempFile jpcTmpImageFile;
+-		KTempFile bmpTmpImageFile;
+-		QFile *file = jpcTmpImageFile.file();;
+-		file->writeBlock((currentImage->buffer()).data(), currentImage->size());
+-		file->close();
+-		
+-		KProcess p;
+-		p << "jasper";
+-		p << "--input" << jpcTmpImageFile.name() << "--output" << bmpTmpImageFile.name() << "--output-format" << "bmp";
+-		
+-		p.start( KProcess::Block );
+-		if( p.exitStatus() != 0 )
+-		{
+-			kdDebug(14181) << " jasper exited with status " << p.exitStatus() << " " << who << endl;
+-		}
+-		else
+-		{
+-			webcamImage.load( bmpTmpImageFile.name() );
+-			/******* UPTO THIS POINT ******/
+-			kdDebug(14181) << " emitting image " << currentImage->size() << endl;
+-			emit webcamImageReceived( QString::fromLatin1( who ), webcamImage );
+-		}
+-		QFile::remove(jpcTmpImageFile.name());
+-		QFile::remove(bmpTmpImageFile.name());
+-		
+-		delete currentImage;
+-		currentImage = NULL;
+-	}
+-}
+-
+-void YahooSession::_webcamDisconnected( const char* who, int reason )
+-{
+-	kdDebug(14181) << k_funcinfo << "Webcam closed remotely, reason: " << reason << endl;
+-	emit remoteWebcamClosed( QString::fromLocal8Bit( who ), reason );
+-}
+-
+-
+-void YahooSession::slotReadReady()
+-{
+-	int ret = 1;
+-	
+-	//using sender is the only way to reliably get the socket 
+-	const KStreamSocket* socket = dynamic_cast<const KStreamSocket*>( sender() );
+-	if ( !socket )
+-	{
+-		kdDebug(14181) << k_funcinfo << "sender() was not a KStreamSocket!" << endl;
+-		return;
+-	}
+-	
+-	int fd = socket->socketDevice()->socket();
+-	//kdDebug(14181) << k_funcinfo << "Socket FD: " << fd << endl;
+-	
+-	QPair< KStreamSocket*, void *> *connection = m_connManager.connectionForFD( fd );
+-	if ( !connection )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No connection found for socket!" << endl;
+-		return;
+-	}
+-	
+-	ret = yahoo_read_ready( m_connId , fd, connection->second );
+-
+-	if ( ret == -1 )
+-		kdDebug(14181) << k_funcinfo << "Read Error (" << errno << ": " << strerror(errno) << endl;
+-	else if ( ret == 0 )
+-		kdDebug(14181) << k_funcinfo << "Server closed socket" << endl;
+-
+-}
+-
+-void YahooSession::slotWriteReady()
+-{
+-	int ret = 1;
+-	
+-	//using sender is the only way to reliably get the socket 
+-	const KStreamSocket* socket = dynamic_cast<const KStreamSocket*>( sender() );
+-	if ( !socket )
+-	{
+-		kdDebug(14181) << k_funcinfo << "sender() was not a KStreamSocket!" << endl;
+-		return;
+-	}
+-	
+-	int fd = socket->socketDevice()->socket();
+-	//kdDebug(14181) << k_funcinfo << "Socket FD: " << fd << endl;
+-	
+-	QPair< KStreamSocket*, void *> *connection = m_connManager.connectionForFD( fd );
+-	if ( !connection )
+-	{
+-		kdDebug(14181) << k_funcinfo << "No connection found for socket!" << endl;
+-		return;
+-	}
+-	
+-	ret = yahoo_write_ready( m_connId , fd, connection->second );
+-
+-	if ( ret == -1 )
+-		kdDebug(14181) << k_funcinfo << "Read Error (" << errno << ": " << strerror(errno) << endl;
+-	else if ( ret == 0 )
+-		kdDebug(14181) << k_funcinfo << "Server closed socket" << endl;
+-}
+-
+-#include "kyahoo.moc"
+-
+-// vim: set noet ts=4 sts=4 sw=4:
+-// kate: indent-mode csands; tab-width 4;
+--- kopete/protocols/yahoo/yahoouserinfo.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahoouserinfo.cpp	(revision 586398)
+@@ -1,103 +0,0 @@
+-/*
+-    yahoouserinfo.cpp - hold and display buddy information
+-
+-    Copyright (c) 2005 by Andre Duffeck <andre at duffeck.de>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * 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.                                   *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-// KDE Includes
+-#include <klocale.h>
+-#include <kdebug.h>
+-
+-// Local Includes
+-#include "yahoouserinfo.h"
+-#include "kyahoo.h"
+-
+-// QT Includes
+-#include <qlineedit.h>
+-
+-YahooUserInfoDialog::YahooUserInfoDialog(QWidget* parent, const char* name)
+-: KDialogBase(parent, name, true, i18n("User Information"), Cancel|Apply|User1,
+-              Cancel, true, i18n("&View Yahoo Profile") )
+-{
+-	mMainWidget = new YahooUserInfoWidget(this);
+-	setMainWidget( mMainWidget );
+-	setEscapeButton( Cancel );
+-}
+-
+-YahooUserInfoDialog::~YahooUserInfoDialog()
+-{
+-}
+-
+-void YahooUserInfoDialog::slotClose()
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	QDialog::done(0);
+-}
+-
+-void YahooUserInfoDialog::slotApply()
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-
+-	m_userInfo.firstName = mMainWidget->m_fname->text();
+-	m_userInfo.lastName = mMainWidget->m_lname->text();
+-	m_userInfo.nickName = mMainWidget->m_nname->text(),
+-	m_userInfo.email = mMainWidget->m_email->text();
+-	m_userInfo.phoneHome = mMainWidget->m_hphone->text();
+-	m_userInfo.phoneWork = mMainWidget->m_wphone->text();
+-	//m_userInfo.phoneMobile 	mMainWidget->= m_mphone->text();
+-
+-	if( m_theSession )
+-		m_theSession->saveAdressBookEntry( m_userInfo );
+-	QDialog::done(0);
+-}
+-
+-void YahooUserInfoDialog::slotUser1()
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	if( m_theSession )
+-		m_theSession->viewUserProfile( m_userInfo.userID );
+-}
+-
+-void YahooUserInfoDialog::setSession( YahooSession *session)
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	m_theSession = session;
+-}
+-
+-void YahooUserInfoDialog::setUserInfo( const YahooUserInfo &info)
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	m_userInfo.userID = info.userID;
+-	m_userInfo.abID = info.abID;
+-	m_userInfo.firstName = info.firstName;
+-	m_userInfo.lastName = info.lastName;
+-	m_userInfo.nickName	= info.nickName,
+-	m_userInfo.email = info.email;
+-	m_userInfo.phoneHome = info.phoneHome;
+-	m_userInfo.phoneWork = info.phoneWork;
+-	//m_userInfo.phoneMobile 	= info.phoneMobile;
+-
+-	mMainWidget->m_userID->setText( m_userInfo.userID );
+-	mMainWidget->m_fname->setText( m_userInfo.firstName );
+-	mMainWidget->m_lname->setText( m_userInfo.lastName );
+-	mMainWidget->m_nname->setText( m_userInfo.nickName );
+-	mMainWidget->m_email->setText( m_userInfo.email );
+-	mMainWidget->m_hphone->setText( m_userInfo.phoneHome );
+-	mMainWidget->m_wphone->setText( m_userInfo.phoneWork );
+-	//m_mphone->setText( m_userInfo.phoneMobile );
+-
+-}
+-
+-
+-
+-#include "yahoouserinfo.moc"
+-
+--- kopete/protocols/yahoo/yahoowebcam.cpp	(revision 0)
++++ kopete/protocols/yahoo/yahoowebcam.cpp	(revision 586398)
+@@ -0,0 +1,137 @@
++/*
++    yahoowebcam.cpp - Send webcam images
++
++    Copyright (c) 2005 by André Duffec <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * 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 <kdebug.h>
++#include <kprocess.h>
++#include <ktempfile.h>
++#include <qtimer.h>
++
++#include "client.h"
++#include "yahoowebcam.h"
++#include "yahooaccount.h"
++#include "yahoowebcamdialog.h"
++#include "avdevice/videodevicepool.h"
++
++
++YahooWebcam::YahooWebcam( YahooAccount *account ) : QObject( 0, "yahoo_webcam" )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	theAccount = account;
++	theDialog = 0L;
++	origImg = new KTempFile();
++	convertedImg = new KTempFile();
++	m_img = new QImage();
++
++	m_sendTimer = new QTimer( this );
++	connect( m_sendTimer, SIGNAL(timeout()), this, SLOT(sendImage()) );	
++
++	m_updateTimer = new QTimer( this );
++	connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(updateImage()) );	
++
++	theDialog = new YahooWebcamDialog( "YahooWebcam" );
++	connect( theDialog, SIGNAL(closingWebcamDialog()), this, SLOT(webcamDialogClosing()) );
++
++	m_devicePool = Kopete::AV::VideoDevicePool::self();
++	m_devicePool->open();
++	m_devicePool->setSize(320, 240);
++	m_devicePool->startCapturing();
++	m_updateTimer->start( 250 );
++}
++
++YahooWebcam::~YahooWebcam()
++{
++	QFile::remove( origImg->name() );
++	QFile::remove( convertedImg->name() );
++	delete origImg;
++	delete convertedImg;
++	delete m_img;
++}
++
++void YahooWebcam::stopTransmission()
++{
++	m_sendTimer->stop();
++}
++
++void YahooWebcam::startTransmission()
++{
++	m_sendTimer->start( 1000 );
++}
++
++void YahooWebcam::webcamDialogClosing()
++{
++	m_sendTimer->stop();
++	theDialog->delayedDestruct();
++	emit webcamClosing();
++	m_devicePool->stopCapturing(); 
++	m_devicePool->close();
++}
++
++void YahooWebcam::updateImage()
++{
++	m_devicePool->getFrame();
++	m_devicePool->getImage(m_img);
++	theDialog->newImage( *m_img );
++}
++
++void YahooWebcam::sendImage()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++
++	m_devicePool->getFrame();
++	m_devicePool->getImage(m_img);
++	
++	origImg->close();
++	convertedImg->close();
++	
++	m_img->save( origImg->name(), "JPEG");
++	
++	KProcess p;
++	p << "jasper";
++	p << "--input" << origImg->name() << "--output" << convertedImg->name() << "--output-format" << "jpc" << "-O" <<"cblkwidth=64\ncblkheight=64\nnumrlvls=4\nrate=0.0165\nprcheight=128\nprcwidth=2048\nmode=real";
++	
++	
++	p.start( KProcess::Block );
++	if( p.exitStatus() != 0 )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << " jasper exited with status " << p.exitStatus() << endl;
++	}
++	else
++	{
++		QFile file( convertedImg->name() );
++		if( file.open( IO_ReadOnly ) )
++		{
++			QByteArray ar = file.readAll();
++			theAccount->yahooSession()->sendWebcamImage( ar );
++		}
++		else
++			kdDebug(YAHOO_GEN_DEBUG) << "Error opening the converted webcam image." << endl;
++	}
++}
++
++void YahooWebcam::addViewer( const QString &viewer )
++{
++	m_viewer.push_back( viewer );
++	if( theDialog )
++		theDialog->setViewer( m_viewer );
++}
++
++void YahooWebcam::removeViewer( const QString &viewer )
++{
++	m_viewer.remove( viewer );
++	if( theDialog )
++		theDialog->setViewer( m_viewer );
++}
++
++#include "yahoowebcam.moc"
+--- kopete/protocols/yahoo/yahoochatui.rc	(revision 568672)
++++ kopete/protocols/yahoo/yahoochatui.rc	(revision 586398)
+@@ -1,16 +1,24 @@
+ <!DOCTYPE kpartgui>
+-<kpartgui version="4" name="kopete_yahoo_chat">
++<kpartgui version="9" name="kopete_yahoo_chat">
+ 	<MenuBar>
+ 		<Menu noMerge="1" name="file">
++			<Action name="yahooRequestWebcam" />
++			<Action name="yahooSendWebcam" />	
++			<Action name="yahooSendFile" />			
+ 			<Action name="yahooBuzz" />
+ 			<Action name="yahooShowInfo" />
+-			<Action name="yahooRequestWebcam" />
+ 		</Menu>
+ 	</MenuBar>
+ 
+ 
+ 	<ToolBar name="statusToolBar">
+ 		<Action name="yahooDisplayPicture" />
++		<Action name="yahooRequestWebcam" />	
++		<Action name="yahooSendWebcam" />		
++		<Action name="yahooSendFile" />
++		<Action name="yahooBuzz" />
++		<Action name="yahooShowInfo" />	
++	
+ 	</ToolBar>
+ 
+ 
+--- kopete/protocols/yahoo/libkyahoo/conferencetask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/conferencetask.h	(revision 586398)
+@@ -0,0 +1,57 @@
++/*
++    Kopete Yahoo Protocol
++    Handles conferences
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CONFERENCETASK_H
++#define CONFERENCETASK_H
++
++#include "task.h"
++
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class ConferenceTask : public Task
++{
++	Q_OBJECT
++public:
++	ConferenceTask(Task *parent);
++	~ConferenceTask();
++	
++	bool take(Transfer *transfer);
++	bool forMe( Transfer* transfer ) const;
++
++	void joinConference( const QString &room, const QStringList &members );
++	void declineConference( const QString &room, const QStringList &members, const QString &msg );
++	void leaveConference( const QString &room, const QStringList &members );
++	void sendMessage( const QString &room, const QStringList &members, const QString &msg );
++	void inviteConference( const QString &room, const QStringList &members, const QString &msg );
++	void addInvite( const QString &room, const QStringList &who, const QStringList &members, const QString &msg );
++signals:
++	void gotInvite( const QString &who, const QString &room, const QString &msg, const QStringList &members);
++	void gotMessage( const QString &who, const QString &room, const QString &msg );
++	void userJoined( const QString &who, const QString &room );
++	void userLeft( const QString &who, const QString &room );
++	void userDeclined( const QString &who, const QString &room, const QString &msg );
++private:
++	void parseInvitation( YMSGTransfer *transfer );
++	void parseMessage( YMSGTransfer *transfer );
++	void parseUserJoined( YMSGTransfer *transfer );
++	void parseUserLeft( YMSGTransfer *transfer );
++	void parseUserDeclined( YMSGTransfer *transfer );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yahooclientstream.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahooclientstream.h	(revision 586398)
+@@ -0,0 +1,159 @@
++/*
++	oscarclientstream.h - Kopete Yahoo Protocol
++	
++	Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++	
++	Based on code Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++	Based on Iris, Copyright (C) 2003  Justin Karneges
++	
++	Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++	
++	*************************************************************************
++	*                                                                       *
++	* This library is free software; you can redistribute it and/or         *
++	* modify it under the terms of the GNU Lesser General Public            *
++	* License as published by the Free Software Foundation; either          *
++	* version 2 of the License, or (at your option) any later version.      *
++	*                                                                       *
++	*************************************************************************
++*/
++
++#ifndef YAHOO_CLIENTSTREAM_H
++#define YAHOO_CLIENTSTREAM_H
++
++#include "stream.h"
++
++class QHostAddress;
++
++// forward defines
++class ByteStream;
++class Connector;
++class Transfer;
++
++class ClientStream : public Stream
++{
++	Q_OBJECT
++public:
++	enum Error {
++		ErrConnection = ErrCustom,  // Connection error, ask Connector-subclass what's up
++		ErrNeg,                     // Negotiation error, see condition
++		ErrAuth,                    // Auth error, see condition
++		ErrBind                     // Resource binding error
++	};
++	
++	enum Warning {
++		WarnOldVersion,             // server uses older XMPP/Jabber "0.9" protocol  // can be customised for novell versions
++		WarnNoTLS                   // there is no chance for TLS at this point
++	};
++	
++	enum NegCond {
++		HostGone,                   // host no longer hosted
++		HostUnknown,                // unknown host
++		RemoteConnectionFailed,     // unable to connect to a required remote resource
++		SeeOtherHost,               // a 'redirect', see errorText() for other host
++		UnsupportedVersion          // unsupported XMPP version
++	};
++
++	enum AuthCond {
++		GenericAuthError,           // all-purpose "can't login" error
++		NoMech,                     // No appropriate auth mech available
++		BadProto,                   // Bad SASL auth protocol
++		BadServ,                    // Server failed mutual auth
++		InvalidUserId,             // bad user id
++		InvalidMech,                // bad mechanism
++		InvalidRealm,               // bad realm
++		MechTooWeak,                // can't use mech with this authzid
++		NotAuthorized,              // bad user, bad password, bad creditials
++		TemporaryAuthFailure        // please try again later!
++	};
++	
++	enum BindCond {
++		BindNotAllowed,             // not allowed to bind a resource
++		BindConflict                // resource in-use
++	};
++
++	ClientStream(Connector *conn, QObject *parent=0);
++	~ClientStream();
++
++	void connectToServer(const QString& server, bool auth=true);
++	void accept(); // server
++	bool isActive() const;
++	bool isAuthenticated() const;
++
++	// login params
++	void setUsername(const QString &s);
++	void setPassword(const QString &s);
++
++	void setLocalAddr(const QHostAddress &addr, Q_UINT16 port);
++
++	void close();
++	
++	/**
++	 * Are there any messages waiting to be read
++	 */
++	bool transfersAvailable() const;
++	
++	/**
++	 * Read a message received from the server
++	 */
++	Transfer * read();
++
++	/**
++	 * Send a message to the server
++	 */
++	void write( Transfer* request );
++
++	int errorCondition() const;
++	QString errorText() const;
++
++	// extrahttp://bugs.kde.org/show_bug.cgi?id=85158
++/*#	void writeDirect(const QString &s); // must be for debug testing*/
++	void setNoopTime(int mills);
++
++signals:
++	void connected();
++	void securityLayerActivated(int);
++	void authenticated(); // this signal is ordinarily emitted in processNext
++	void warning(int);
++	void readyRead(); //signals that there is a transfer ready to be read
++public slots:
++	void continueAfterWarning();
++
++private slots:
++	void cr_connected();
++	void cr_error();
++	/**
++	 * collects wire ready outgoing data from the core protocol and sends
++	 */ 
++	void cp_outgoingData( const QByteArray& );
++	/**
++	 * collects parsed incoming data as a transfer from the core protocol and queues
++	 */
++	void cp_incomingData();
++
++	void bs_connectionClosed();
++	void bs_delayedCloseFinished();
++	void bs_error(int); // server only
++	void bs_readyRead();
++	void bs_bytesWritten(int);
++
++	void doNoop();
++	void doReadyRead();
++
++private:
++	class Private;
++	Private *d;
++
++	void reset(bool all=false);
++	void processNext();
++	bool handleNeed();
++	void handleError();
++	void srvProcessNext();
++	
++	/** 
++	 * convert internal method representation to wire
++	 */
++	static char* encode_method(Q_UINT8 method);
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/crypt.c	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/crypt.c	(revision 586398)
+@@ -0,0 +1,210 @@
++/* One way encryption based on MD5 sum.
++   Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   Contributed by Ulrich Drepper <drepper at cygnus.com>, 1996.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, write to the Free
++   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++   02111-1307 USA.  */
++
++/* warmenhoven took this file and made it work with the md5.[ch] we
++ * already had. isn't that lovely. people should just use linux or
++ * freebsd, crypt works properly on those systems. i hate solaris */
++
++#if HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#if HAVE_STRING_H
++#  include <string.h>
++#elif HAVE_STRINGS_H
++#  include <strings.h>
++#endif
++
++#include <stdlib.h>
++
++#include "md5.h"
++/* for MIN and MAX */
++#include "libyahoo.h"
++
++/* Define our magic string to mark salt for MD5 "encryption"
++   replacement.  This is meant to be the same as for other MD5 based
++   encryption implementations.  */
++static const char md5_salt_prefix[] = "$1$";
++
++/* Table with characters for base64 transformation.  */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++char *yahoo_crypt(const char *key, const char *salt);
++
++char *yahoo_crypt(const char *key, const char *salt)
++{
++	char *buffer = NULL;
++	int buflen = 0;
++	int needed = 3 + strlen (salt) + 1 + 26 + 1;
++
++	md5_byte_t alt_result[16];
++	md5_state_t ctx;
++	md5_state_t alt_ctx;
++	size_t salt_len;
++	size_t key_len;
++	size_t cnt;
++	char *cp;
++
++	if (buflen < needed) {
++		buflen = needed;
++		if ((buffer = realloc(buffer, buflen)) == NULL)
++			return NULL;
++	}
++
++	/* Find beginning of salt string.  The prefix should normally always
++	   be present.  Just in case it is not.  */
++	if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
++		/* Skip salt prefix.  */
++		salt += sizeof (md5_salt_prefix) - 1;
++
++	salt_len = MIN (strcspn (salt, "$"), 8);
++	key_len = strlen (key);
++
++	/* Prepare for the real work.  */
++	md5_init(&ctx);
++
++	/* Add the key string.  */
++	md5_append(&ctx, (md5_byte_t *)key, key_len);
++
++	/* Because the SALT argument need not always have the salt prefix we
++	   add it separately.  */
++	md5_append(&ctx, (md5_byte_t *)md5_salt_prefix, sizeof (md5_salt_prefix) - 1);
++
++	/* The last part is the salt string.  This must be at most 8
++	   characters and it ends at the first `$' character (for
++	   compatibility which existing solutions).  */
++	md5_append(&ctx, (md5_byte_t *)salt, salt_len);
++
++	/* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
++	   final result will be added to the first context.  */
++	md5_init(&alt_ctx);
++
++	/* Add key.  */
++	md5_append(&alt_ctx, (md5_byte_t *)key, key_len);
++
++	/* Add salt.  */
++	md5_append(&alt_ctx, (md5_byte_t *)salt, salt_len);
++
++	/* Add key again.  */
++	md5_append(&alt_ctx, (md5_byte_t *)key, key_len);
++
++	/* Now get result of this (16 bytes) and add it to the other
++	   context.  */
++	md5_finish(&alt_ctx, alt_result);
++
++	/* Add for any character in the key one byte of the alternate sum.  */
++	for (cnt = key_len; cnt > 16; cnt -= 16)
++		md5_append(&ctx, alt_result, 16);
++	md5_append(&ctx, alt_result, cnt);
++
++	/* For the following code we need a NUL byte.  */
++	alt_result[0] = '\0';
++
++	/* The original implementation now does something weird: for every 1
++	   bit in the key the first 0 is added to the buffer, for every 0
++	   bit the first character of the key.  This does not seem to be
++	   what was intended but we have to follow this to be compatible.  */
++	for (cnt = key_len; cnt > 0; cnt >>= 1)
++		md5_append(&ctx, (cnt & 1) != 0 ? alt_result : (md5_byte_t *)key, 1);
++
++	/* Create intermediate result.  */
++	md5_finish(&ctx, alt_result);
++
++	/* Now comes another weirdness.  In fear of password crackers here
++	   comes a quite long loop which just processes the output of the
++	   previous round again.  We cannot ignore this here.  */
++	for (cnt = 0; cnt < 1000; ++cnt) {
++		/* New context.  */
++		md5_init(&ctx);
++
++		/* Add key or last result.  */
++		if ((cnt & 1) != 0)
++			md5_append(&ctx, (md5_byte_t *)key, key_len);
++		else
++			md5_append(&ctx, alt_result, 16);
++
++		/* Add salt for numbers not divisible by 3.  */
++		if (cnt % 3 != 0)
++			md5_append(&ctx, (md5_byte_t *)salt, salt_len);
++
++		/* Add key for numbers not divisible by 7.  */
++		if (cnt % 7 != 0)
++			md5_append(&ctx, (md5_byte_t *)key, key_len);
++
++		/* Add key or last result.  */
++		if ((cnt & 1) != 0)
++			md5_append(&ctx, alt_result, 16);
++		else
++			md5_append(&ctx, (md5_byte_t *)key, key_len);
++
++		/* Create intermediate result.  */
++		md5_finish(&ctx, alt_result);
++	}
++
++	/* Now we can construct the result string.  It consists of three
++	   parts.  */
++
++	strncpy(buffer, md5_salt_prefix, MAX (0, buflen));
++	cp = buffer + strlen(buffer);
++	buflen -= sizeof (md5_salt_prefix);
++
++	strncpy(cp, salt, MIN ((size_t) buflen, salt_len));
++	cp = cp + strlen(cp);
++	buflen -= MIN ((size_t) buflen, salt_len);
++
++	if (buflen > 0) {
++		*cp++ = '$';
++		--buflen;
++	}
++
++#define b64_from_24bit(B2, B1, B0, N) \
++	do { \
++		unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
++		int n = (N); \
++		while (n-- > 0 && buflen > 0) { \
++			*cp++ = b64t[w & 0x3f]; \
++			--buflen; \
++			w >>= 6; \
++		}\
++	} while (0)
++
++	b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
++	b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
++	b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
++	b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
++	b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
++	b64_from_24bit (0, 0, alt_result[11], 2);
++	if (buflen <= 0) {
++		FREE(buffer);
++	} else
++		*cp = '\0';	/* Terminate the string.  */
++
++	/* Clear the buffer for the intermediate result so that people
++	   attaching to processes or reading core dumps cannot get any
++	   information.  We do it in this way to clear correct_words[]
++	   inside the MD5 implementation as well.  */
++	md5_init(&ctx);
++	md5_finish(&ctx, alt_result);
++	memset (&ctx, '\0', sizeof (ctx));
++	memset (&alt_ctx, '\0', sizeof (alt_ctx));
++
++	return buffer;
++}
+--- kopete/protocols/yahoo/libkyahoo/picturenotifiertask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/picturenotifiertask.h	(revision 586398)
+@@ -0,0 +1,51 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about buddy icons
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef PICTURENOTIFIERTASK_H
++#define PICTURENOTIFIERTASK_H
++
++#include "task.h"
++
++class QString;
++class KURL;
++class YMSGTransfer;
++/**
++ at author André Duffeck
++*/
++class PictureNotifierTask : public Task
++{
++Q_OBJECT
++public:
++	PictureNotifierTask(Task *parent);
++	~PictureNotifierTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++	void parsePictureChecksum( YMSGTransfer *transfer );
++	void parsePictureStatus( YMSGTransfer *transfer );
++	void parsePicture( YMSGTransfer *transfer );
++	void parsePictureUploadResponse( YMSGTransfer *transfer );
++signals:
++	void pictureStatusNotify( const QString &, int );
++	void pictureChecksumNotify( const QString &, int );
++	void pictureInfoNotify( const QString &, KURL, int ); 
++	void pictureRequest( const QString & );
++	void pictureUploaded( const QString & );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yabtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yabtask.h	(revision 586398)
+@@ -0,0 +1,60 @@
++/*
++    Kopete Yahoo Protocol
++    yabtask.h - Handles the Yahoo Address Book
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef YABTASK_H
++#define YABTASK_H
++
++#include "task.h"
++#include "yabentry.h"
++
++class YMSGTransfer;
++struct KURL;
++namespace KIO	{ 
++	class Job;
++	class TransferJob; 
++}
++class QDomElement;
++
++/**
++ at author André Duffeck
++*/
++class YABTask : public Task
++{
++	Q_OBJECT
++public:
++	YABTask(Task *parent);
++	~YABTask();
++	
++	bool take(Transfer *transfer);
++	bool forMe( Transfer* transfer ) const;
++
++	void getAllEntries( long lastMerge, long lastRemoteRevision );
++	void saveEntry( const YABEntry & );
++signals:
++	void gotEntry( YABEntry * );
++	void gotRevision( long rev, bool merged );
++protected:
++	void parseContactDetails( YMSGTransfer* t );
++private slots:
++	void slotData( KIO::Job*, const QByteArray & );
++	void slotResult( KIO::Job* );
++private:
++	KIO::TransferJob *m_transferJob;
++	QString m_data;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/safedelete.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/safedelete.h	(revision 586398)
+@@ -0,0 +1,79 @@
++/*
++    gwclientstream.h - Kopete Groupwise Protocol
++  
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SAFEDELETE_H
++#define SAFEDELETE_H
++
++#include<qobject.h>
++#include<qobjectlist.h>
++
++class SafeDelete;
++class SafeDeleteLock
++{
++public:
++	SafeDeleteLock(SafeDelete *sd);
++	~SafeDeleteLock();
++
++private:
++	SafeDelete *_sd;
++	bool own;
++	friend class SafeDelete;
++	void dying();
++};
++
++class SafeDelete
++{
++public:
++	SafeDelete();
++	~SafeDelete();
++
++	void deleteLater(QObject *o);
++
++	// same as QObject::deleteLater()
++	static void deleteSingle(QObject *o);
++
++private:
++	QObjectList list;
++	void deleteAll();
++
++	friend class SafeDeleteLock;
++	SafeDeleteLock *lock;
++	void unlock();
++};
++
++class SafeDeleteLater : public QObject
++{
++	Q_OBJECT
++public:
++	static SafeDeleteLater *ensureExists();
++	void deleteItLater(QObject *o);
++
++private slots:
++	void explode();
++
++private:
++	SafeDeleteLater();
++	~SafeDeleteLater();
++
++	QObjectList list;
++	friend class SafeDelete;
++	static SafeDeleteLater *self;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/modifyyabtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/modifyyabtask.cpp	(revision 586398)
+@@ -0,0 +1,205 @@
++/*
++    Kopete Yahoo Protocol
++    modifyyabtask.h - Handles the Yahoo Address Book
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "modifyyabtask.h"
++#include "yabtask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qdatastream.h>
++#include <qdom.h>
++#include <klocale.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++#include <kbufferedsocket.h>
++
++using namespace KNetwork;
++ModifyYABTask::ModifyYABTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_socket = 0;
++}
++
++ModifyYABTask::~ModifyYABTask()
++{
++	delete m_socket;
++}
++
++void ModifyYABTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_socket = new KBufferedSocket( "address.yahoo.com", QString::number(80) );
++	connect( m_socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( connectSucceeded() ) );
++	connect( m_socket, SIGNAL( gotError(int) ), this, SLOT( connectFailed(int) ) );
++
++	m_socket->connect();
++}
++
++void ModifyYABTask::setAction( Action action )
++{
++	m_action = action;
++}
++
++void ModifyYABTask::setEntry( const YABEntry &entry )
++{
++	QDomDocument doc("");
++	QDomElement root = doc.createElement( "ab" );
++	QDomProcessingInstruction instr = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\" ");
++  	doc.appendChild(instr);
++	root.setAttribute( "k", client()->userId() );
++	root.setAttribute( "cc", "1" );
++	doc.appendChild( root );
++	
++	QDomElement contact = doc.createElement( "ct" );
++	entry.fillQDomElement( contact );
++	switch( m_action )
++	{
++	case EditEntry:
++		contact.setAttribute( "e", "1" );
++		break;
++	case AddEntry:
++		contact.setAttribute( "a", "1" );
++		break;
++	case DeleteEntry:
++		contact.setAttribute( "d", "1" );
++		break;
++	}
++	root.appendChild( contact );
++
++	entry.dump();
++	m_postData = doc.toString();
++}
++
++void ModifyYABTask::connectFailed( int i)
++{
++	m_socket->close();
++	client()->notifyError( i18n( "An error occured saving the Addressbook entry." ), 
++			QString( "%1 - %2").arg(i).arg(static_cast<const KBufferedSocket*>( sender() )->errorString()), Client::Error );
++}
++
++void ModifyYABTask::connectSucceeded()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString header = QString::fromLatin1("POST /yab/us?v=XM&prog=ymsgr&.intl=us&sync=1&tags=short&noclear=1& HTTP/1.1\r\n"
++			"Cookie: Y=%1; T=%2; C=%3 ;B=fckeert1kk1nl&b=2\r\n"
++			"User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
++			"Host: address.yahoo.com\r\n"
++			"Content-length: %4\r\n"
++			"Cache-Control: no-cache\r\n\r\n")
++			.arg(client()->yCookie()).arg(client()->tCookie())
++			.arg(client()->cCookie()).arg(m_postData.utf8().size());
++
++	QByteArray buffer;
++	QByteArray paket;
++	QDataStream stream( buffer, IO_WriteOnly );
++	stream.writeRawBytes( header.local8Bit(), header.length() );
++	stream.writeRawBytes( m_postData.utf8(), m_postData.utf8().size() );
++	
++	if( m_socket->writeBlock( buffer, buffer.size() ) )
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Upload Successful. Waiting for confirmation..." << endl;
++	else
++	{
++		client()->notifyError( i18n( "An error occured saving the Addressbook entry." ), m_socket->errorString(), Client::Error );
++		setSuccess( false );
++		return;
++	}
++	
++	connect( m_socket, SIGNAL( readyRead() ), this, SLOT( slotRead() ) );
++}
++
++void ModifyYABTask::slotRead()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	QByteArray ar( m_socket->bytesAvailable() );
++	m_socket->readBlock ( ar.data (), ar.size () );
++	QString buf( ar );
++	m_data += buf.right( buf.length() - buf.find("<?xml") );
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << m_data.find("</ab>") << endl;
++	if( m_data.find("</ab>") < 0 )
++		return;						// Need more data
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << m_data.find("</ab>") << endl;
++
++	m_socket->close();
++	QDomDocument doc;
++	QDomNodeList list;
++	QDomElement e;
++	uint it = 0;
++	
++	doc.setContent( m_data );
++
++	list = doc.elementsByTagName( "ab" );			// Get the Addressbook
++	for( it = 0; it < list.count(); it++ )	{
++		if( !list.item( it ).isElement() )
++			continue;
++		e = list.item( it ).toElement();
++		
++		if( !e.attribute( "lm" ).isEmpty() )
++			emit gotRevision( e.attribute( "lm" ).toLong(), true );
++
++		if( !e.attribute( "rt" ).isEmpty() )
++			emit gotRevision( e.attribute( "rt" ).toLong(), false );
++	}
++
++	list = doc.elementsByTagName( "ct" );			// Get records
++	for( it = 0; it < list.count(); it++ )	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Parsing entry..." << endl;
++		if( !list.item( it ).isElement() )
++			continue;
++		e = list.item( it ).toElement();
++		
++		YABEntry *entry = new YABEntry;
++		entry->fromQDomElement( e );
++		entry->source = YABEntry::SourceYAB;
++
++		switch( m_action )
++		{
++		case EditEntry:
++			if( !e.attribute( "es" ).isEmpty() && e.attribute( "es" ) != "0" )		// Check for edit errors
++			{
++				emit error( entry, i18n("The Yahoo Addressbook entry could not be saved:\n%1 - %2").arg( e.attribute("es") ).arg( e.attribute("ee") ) );
++				continue;
++			}
++			break;
++		case AddEntry:
++			if( !e.attribute( "as" ).isEmpty() && e.attribute( "as" ) != "0" )		// Check for add errors
++			{
++				emit error( entry, i18n("The Yahoo Addressbook entry could not be created:\n%1 - %2").arg( e.attribute("as") ).arg( e.attribute("ae") ) );
++				continue;
++			}
++			break;
++		case DeleteEntry:
++			if( !e.attribute( "ds" ).isEmpty() && e.attribute( "ds" ) != "0" )		// Check for delete errors
++			{
++				emit error( entry, i18n("The Yahoo Addressbook entry could not be deleted:\n%1 - %2").arg( e.attribute("ds") ).arg( e.attribute("de") ) );
++				continue;
++			}
++			break;
++		}
++
++		// No errors occured
++		emit gotEntry( entry );
++	}
++
++	
++	setSuccess( true );
++}
++#include "modifyyabtask.moc"
+--- kopete/protocols/yahoo/libkyahoo/modifybuddytask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/modifybuddytask.h	(revision 586398)
+@@ -0,0 +1,53 @@
++/*
++    Kopete Yahoo Protocol
++    Add, remove or move a buddy to the Contactlist
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef MODIFYBUDDYTASK_H
++#define MODIFYBUDDYTASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class ModifyBuddyTask : public Task
++{
++public:
++	enum Type { AddBuddy, RemoveBuddy, MoveBuddy };
++	ModifyBuddyTask(Task *parent);
++	~ModifyBuddyTask();
++	
++	virtual void onGo();
++	
++	void setType( Type type );
++	void setMessage( const QString &text );
++	void setTarget( const QString &target );
++	void setGroup( const QString &group );
++	void setOldGroup( const QString &group );
++private:
++	void addBuddy();
++	void removeBuddy();
++	void moveBuddy();
++
++	QString m_message;
++	QString m_target;
++	QString m_group;
++	QString m_oldGroup;
++	Type m_type;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/mailnotifiertask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/mailnotifiertask.h	(revision 586398)
+@@ -0,0 +1,44 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about new mails
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef MAILNOTIFIERTASK_H
++#define MAILNOTIFIERTASK_H
++
++#include "task.h"
++
++class QString;
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class MailNotifierTask : public Task
++{
++Q_OBJECT
++public:
++	MailNotifierTask(Task *parent);
++	~MailNotifierTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++	void parseMail( YMSGTransfer *transfer );
++signals:
++	void mailNotify(const QString&, const QString&, int);
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/filetransfernotifiertask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/filetransfernotifiertask.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about incoming filetransfers
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef FILETRANSFERNOTIFIERTASK_H
++#define FILETRANSFERNOTIFIERTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++
++class QString;
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class FileTransferNotifierTask : public Task
++{
++Q_OBJECT
++public:
++	FileTransferNotifierTask(Task *parent);
++	~FileTransferNotifierTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++signals:
++	void incomingFileTransfer( const QString &who, const QString &url, long expires, const QString &msg ,
++	const QString &fname, unsigned long size );
++private:
++	void parseFileTransfer( YMSGTransfer *transfer );
++	void parseFileTransfer7( YMSGTransfer *transfer );
++	void acceptFileTransfer( YMSGTransfer *t );
++	void parseFileTransfer7Info( YMSGTransfer *YMSGtransfer );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/inputprotocolbase.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/inputprotocolbase.cpp	(revision 586398)
+@@ -0,0 +1,98 @@
++/*
++    Kopete Groupwise Protocol
++    inputprotocolbase.cpp - Ancestor of all protocols used for reading GroupWise input
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "inputprotocolbase.h"
++
++InputProtocolBase::InputProtocolBase(QObject *parent, const char *name)
++ : QObject(parent, name)
++{
++}
++
++
++InputProtocolBase::~InputProtocolBase()
++{
++}
++
++uint InputProtocolBase::state() const
++{
++	return m_state;
++}
++
++bool InputProtocolBase::readString( QString &message )
++{
++	uint len;
++	QCString rawData;
++	if ( !safeReadBytes( rawData, len ) )
++		return false;
++	message = QString::fromUtf8( rawData.data(), len - 1 );
++	return true;
++}
++
++
++bool InputProtocolBase::okToProceed()
++{
++	if ( m_din )
++	{
++		if ( m_din->atEnd() )
++		{
++			m_state = NeedMore;
++			qDebug( "InputProtocol::okToProceed() - Server message ended prematurely!" );
++		}
++		else
++			return true;
++	}
++	return false;
++}
++
++bool InputProtocolBase::safeReadBytes( QCString & data, uint & len )
++{
++	// read the length of the bytes
++	Q_UINT32 val;
++	if ( !okToProceed() )
++		return false;
++	*m_din >> val;
++	m_bytes += sizeof( Q_UINT32 );
++	if ( val > 1024 )
++		return false;
++	//qDebug( "EventProtocol::safeReadBytes() - expecting %i bytes", val );
++	QCString temp( val );
++	if ( val != 0 )
++	{
++		if ( !okToProceed() )
++			return false;
++		// if the server splits packets here we are in trouble,
++		// as there is no way to see how much data was actually read
++		m_din->readRawBytes( temp.data(), val );
++		// the rest of the string will be filled with FF,
++		// so look for that in the last position instead of \0
++		// this caused a crash - guessing that temp.length() is set to the number of bytes actually read...
++		// if ( (Q_UINT8)( * ( temp.data() + ( temp.length() - 1 ) ) ) == 0xFF )
++		if ( temp.length() < ( val - 1 ) )
++		{
++			qDebug( "InputProtocol::safeReadBytes() - string broke, giving up, only got: %i bytes out of %i",  temp.length(), val );
++			m_state = NeedMore;
++			return false;
++		}
++	}
++	data = temp;
++	len = val;
++	m_bytes += val;
++	return true;
++}
++
++#include "inputprotocolbase.moc"
+--- kopete/protocols/yahoo/libkyahoo/yahoobuddyiconloader.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoobuddyiconloader.h	(revision 586398)
+@@ -0,0 +1,77 @@
++/*
++    yahoobuddyiconloader.h - Fetches YahooBuddyIcons
++
++    Copyright (c) 2005 by André Duffeck <andre at duffeck.de>
++
++    *************************************************************************
++    *                                                                       *
++    * 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 YAHOOBUDDYICONLOADER_
++#define	YAHOOBUDDYICONLOADER_
++
++// QT Includes
++#include <qobject.h>
++#include <qstring.h>
++#include <qmap.h>
++
++// KDE Includes
++#include <kurl.h>
++
++class KTempFile;
++class Client;
++namespace KIO {
++	class Job;
++	class TransferJob;
++}
++
++struct IconLoadJob {
++	KURL url;
++	QString who;
++	int checksum;
++	KTempFile *file;
++};
++
++/**
++ * @author André Duffeck
++ *
++ * This class handles the download of a Buddy icon.
++ * If the download was succesfull it emits a signal with a pointer
++ * to the temporary file, the icon was stored at
++ */
++class YahooBuddyIconLoader : public QObject
++{
++	Q_OBJECT
++public:
++	YahooBuddyIconLoader( Client *c );
++	~YahooBuddyIconLoader();
++
++	/**
++	 *	Add a BuddyIcon for download.
++	 */
++	void fetchBuddyIcon( const QString &who, KURL url, int checksum );
++
++signals:
++	/**
++	 * 	The account can connect to this signal and append the icon
++	 * 	stored in 'file' to the apropriate contact
++	 */
++	void fetchedBuddyIcon( const QString &who, KTempFile *file, int checksum );
++
++private slots:
++	void slotData( KIO::Job *job, const QByteArray &data );
++	void slotComplete( KIO::Job *job );
++
++private:
++	typedef QMap< KIO::TransferJob *, IconLoadJob > TransferJobMap;
++	TransferJobMap m_jobs;
++	Client *m_client;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/sendpicturetask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendpicturetask.h	(revision 586398)
+@@ -0,0 +1,77 @@
++/*
++    Kopete Yahoo Protocol
++    sendpicturetask.h - Send our picture or information about it
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SENDPICTURETASK_H
++#define SENDPICTURETASK_H
++
++#include "task.h"
++
++class QString;
++class QFile;
++namespace KIO	{ 
++	class Job;
++	class TransferJob; 
++}
++namespace KNetwork	{ 
++	class KBufferedSocket;
++}
++
++/**
++ at author André Duffeck
++*/
++class SendPictureTask : public Task
++{
++Q_OBJECT
++public:
++	enum Type { UploadPicture, SendChecksum, SendInformation, SendStatus };
++
++	SendPictureTask(Task *parent);
++	~SendPictureTask();
++	
++	virtual void onGo();
++
++	void setType( Type type );
++	void setTarget( const QString &to );
++	void setFilename( const QString & );
++	void setFilesize( int );
++	void setPath( const QString & );
++	void setChecksum( int );
++	void setStatus( int );
++	void setUrl( const QString & );
++private:
++	void initiateUpload();
++	void sendChecksum();
++	void sendInformation();
++	void sendStatus();
++private slots:
++	void connectSucceeded();
++	void connectFailed( int );
++	void readResult();
++private:
++	Type m_type;
++	QString m_target;
++	QString m_fileName;
++	int m_fileSize;
++	QString m_path;
++	int m_checksum;
++	int m_status;
++	QString m_url;
++	int m_transmitted;
++	QFile *m_file;
++	KNetwork::KBufferedSocket *m_socket;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yahoobytestream.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoobytestream.cpp	(revision 586398)
+@@ -0,0 +1,140 @@
++/*
++    YMSG - Yahoo Protocol Knetwork Bytestream
++
++    Copyright (C) 2004 by Till Gerken <till at tantalo.net>
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library 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 <qobject.h>
++#include <kbufferedsocket.h>
++#include <kdebug.h>
++#include <kresolver.h>
++
++#include "yahoobytestream.h"
++
++KNetworkByteStream::KNetworkByteStream( QObject *parent, const char */*name*/ )
++ : ByteStream ( parent )
++{
++	kdDebug( 14181 ) << k_funcinfo << "Instantiating new KNetwork byte stream." << endl;
++
++	// reset close tracking flag
++	mClosing = false;
++
++	mSocket = new KNetwork::KBufferedSocket;
++
++	// make sure we get a signal whenever there's data to be read
++	mSocket->enableRead( true );
++
++	// connect signals and slots
++	QObject::connect( mSocket, SIGNAL ( gotError ( int ) ), this, SLOT ( slotError ( int ) ) );
++	QObject::connect( mSocket, SIGNAL ( connected ( const KResolverEntry& ) ), this, SLOT ( slotConnected () ) );
++	QObject::connect( mSocket, SIGNAL ( closed () ), this, SLOT ( slotConnectionClosed () ) );
++	QObject::connect( mSocket, SIGNAL ( readyRead () ), this, SLOT ( slotReadyRead () ) );
++	QObject::connect( mSocket, SIGNAL ( bytesWritten ( int ) ), this, SLOT ( slotBytesWritten ( int ) ) );
++}
++
++bool KNetworkByteStream::connect( QString host, QString service )
++{
++	kdDebug( 14181 ) << k_funcinfo << "Connecting to " << host << ", service " << service << endl;
++
++	return socket()->connect( host, service );
++}
++
++bool KNetworkByteStream::isOpen() const
++{
++	// determine if socket is open
++	return socket()->isOpen();
++}
++
++void KNetworkByteStream::close ()
++{
++	kdDebug ( 14181 ) << k_funcinfo << "Closing stream." << endl;
++
++	// close the socket and set flag that we are closing it ourselves
++	mClosing = true;
++	socket()->close();
++}
++
++int KNetworkByteStream::tryWrite ()
++{
++	// send all data from the buffers to the socket
++	QByteArray writeData = takeWrite();
++	kdDebug( 14181 ) << k_funcinfo << "[writeData.size() = " << writeData.size() << "]" <<   endl;
++	
++	socket()->writeBlock( writeData.data(), writeData.size () );
++
++	return writeData.size();
++}
++
++KNetwork::KBufferedSocket *KNetworkByteStream::socket() const
++{
++	return mSocket;
++}
++
++KNetworkByteStream::~KNetworkByteStream()
++{
++	delete mSocket;
++}
++
++void KNetworkByteStream::slotConnected()
++{
++	emit connected();
++}
++
++void KNetworkByteStream::slotConnectionClosed()
++{
++	kdDebug( 14181 ) << k_funcinfo << "Socket has been closed." << endl;
++
++	// depending on who closed the socket, emit different signals
++	if ( mClosing )
++	{
++		kdDebug( 14181 ) << "..by ourselves!" << endl;
++		kdDebug( 14181 ) << "socket error is " << socket()->errorString( socket()->error() ) << endl;
++		emit connectionClosed ();
++	}
++	else
++	{
++		kdDebug( 14181 ) << "..by the other end" << endl;
++		emit delayedCloseFinished ();
++	}
++}
++
++void KNetworkByteStream::slotReadyRead()
++{
++	kdDebug( 14181 ) <<  endl;
++	// stuff all available data into our buffers
++	QByteArray readBuffer( socket()->bytesAvailable () );
++
++	socket()->readBlock( readBuffer.data (), readBuffer.size () );
++
++	appendRead( readBuffer );
++
++	emit readyRead();
++}
++
++void KNetworkByteStream::slotBytesWritten( int bytes )
++{
++	kdDebug( 14181 ) << "[int bytes]: " << bytes << endl;
++	emit bytesWritten(bytes);
++}
++
++void KNetworkByteStream::slotError( int code )
++{
++	kdDebug( 14181 ) << k_funcinfo << "Socket error " << code << endl;
++
++	emit error( code );
++}
++
++#include "yahoobytestream.moc"
++
++// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
+--- kopete/protocols/yahoo/libkyahoo/bytestream.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/bytestream.h	(revision 586398)
+@@ -0,0 +1,78 @@
++/*
++ * bytestream.h - base class for bytestreams
++ * Copyright (C) 2003  Justin Karneges
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef CS_BYTESTREAM_H
++#define CS_BYTESTREAM_H
++
++#include <qobject.h>
++#include <qcstring.h>
++
++// CS_NAMESPACE_BEGIN
++
++// CS_EXPORT_BEGIN
++class ByteStream : public QObject
++{
++	Q_OBJECT
++public:
++	enum Error { ErrRead, ErrWrite, ErrCustom = 10 };
++	ByteStream(QObject *parent=0);
++	virtual ~ByteStream()=0;
++
++	virtual bool isOpen() const;
++	virtual void close();
++	virtual void write(const QByteArray &);
++	virtual QByteArray read(int bytes=0);
++	virtual int bytesAvailable() const;
++	virtual int bytesToWrite() const;
++
++	void write(const QCString &);
++
++	static void appendArray(QByteArray *a, const QByteArray &b);
++	static QByteArray takeArray(QByteArray *from, int size=0, bool del=true);
++
++signals:
++	void connectionClosed();
++	void delayedCloseFinished();
++	void readyRead();
++	void bytesWritten(int);
++	void error(int);
++
++protected:
++	void clearReadBuffer();
++	void clearWriteBuffer();
++	void appendRead(const QByteArray &);
++	void appendWrite(const QByteArray &);
++	QByteArray takeRead(int size=0, bool del=true);
++	QByteArray takeWrite(int size=0, bool del=true);
++	QByteArray & readBuf();
++	QByteArray & writeBuf();
++	virtual int tryWrite();
++
++private:
++//! \if _hide_doc_
++	class Private;
++	Private *d;
++//! \endif
++};
++// CS_EXPORT_END
++
++// CS_NAMESPACE_END
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/pingtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/pingtask.h	(revision 586398)
+@@ -0,0 +1,36 @@
++/*
++    pingtask.h
++    Send a ping to the server
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef PINGTASK_H
++#define PINGTASK_H
++
++#include "task.h"
++
++/**
++ at author André Duffeck
++*/
++class PingTask : public Task
++{
++public:
++	PingTask(Task *parent);
++	~PingTask();
++	
++	virtual void onGo();
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/md5.c	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/md5.c	(revision 586398)
+@@ -0,0 +1,408 @@
++/*
++  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
++
++  This software is provided 'as-is', without any express or implied
++  warranty.  In no event will the authors be held liable for any damages
++  arising from the use of this software.
++
++  Permission is granted to anyone to use this software for any purpose,
++  including commercial applications, and to alter it and redistribute it
++  freely, subject to the following restrictions:
++
++  1. The origin of this software must not be misrepresented; you must not
++     claim that you wrote the original software. If you use this software
++     in a product, an acknowledgment in the product documentation would be
++     appreciated but is not required.
++  2. Altered source versions must be plainly marked as such, and must not be
++     misrepresented as being the original software.
++  3. This notice may not be removed or altered from any source distribution.
++
++  L. Peter Deutsch
++  ghost at aladdin.com
++
++ */
++/*
++  Independent implementation of MD5 (RFC 1321).
++
++  This code implements the MD5 Algorithm defined in RFC 1321.
++  It is derived directly from the text of the RFC and not from the
++  reference implementation.
++
++  The original and principal author of md5.c is L. Peter Deutsch
++  <ghost at aladdin.com>.  Other authors are noted in the change history
++  that follows (in reverse chronological order):
++
++  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
++  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
++  1999-05-03 lpd Original version.
++ */
++
++#if HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "md5.h"
++
++#if STDC_HEADERS
++# include <string.h>
++#else
++# if !HAVE_STRCHR
++#  define strchr index
++#  define strrchr rindex
++# endif
++char *strchr (), *strrchr ();
++# if !HAVE_MEMCPY
++#  define memcpy(d, s, n) bcopy ((s), (d), (n))
++#  define memmove(d, s, n) bcopy ((s), (d), (n))
++# endif
++#endif
++
++#ifdef TEST
++/*
++ * Compile with -DTEST to create a self-contained executable test program.
++ * The test program should print out the same values as given in section
++ * A.5 of RFC 1321, reproduced below.
++ */
++main()
++{
++    static const char *const test[7] = {
++	"", /*d41d8cd98f00b204e9800998ecf8427e*/
++	"945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/
++	"abc", /*900150983cd24fb0d6963f7d28e17f72*/
++	"message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/
++	"abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/
++	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
++				/*d174ab98d277d9f5a5611c2c9f419d9f*/
++	"12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/
++    };
++    int i;
++
++    for (i = 0; i < 7; ++i) {
++	md5_state_t state;
++	md5_byte_t digest[16];
++	int di;
++
++	md5_init(&state);
++	md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i]));
++	md5_finish(&state, digest);
++	printf("MD5 (\"%s\") = ", test[i]);
++	for (di = 0; di < 16; ++di)
++	    printf("%02x", digest[di]);
++	printf("\n");
++    }
++    return 0;
++}
++#endif /* TEST */
++
++
++/*
++ * For reference, here is the program that computed the T values.
++ */
++#if 0
++#include <math.h>
++main()
++{
++    int i;
++    for (i = 1; i <= 64; ++i) {
++	unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i)));
++	printf("#define T%d 0x%08lx\n", i, v);
++    }
++    return 0;
++}
++#endif
++/*
++ * End of T computation program.
++ */
++#define T1 0xd76aa478
++#define T2 0xe8c7b756
++#define T3 0x242070db
++#define T4 0xc1bdceee
++#define T5 0xf57c0faf
++#define T6 0x4787c62a
++#define T7 0xa8304613
++#define T8 0xfd469501
++#define T9 0x698098d8
++#define T10 0x8b44f7af
++#define T11 0xffff5bb1
++#define T12 0x895cd7be
++#define T13 0x6b901122
++#define T14 0xfd987193
++#define T15 0xa679438e
++#define T16 0x49b40821
++#define T17 0xf61e2562
++#define T18 0xc040b340
++#define T19 0x265e5a51
++#define T20 0xe9b6c7aa
++#define T21 0xd62f105d
++#define T22 0x02441453
++#define T23 0xd8a1e681
++#define T24 0xe7d3fbc8
++#define T25 0x21e1cde6
++#define T26 0xc33707d6
++#define T27 0xf4d50d87
++#define T28 0x455a14ed
++#define T29 0xa9e3e905
++#define T30 0xfcefa3f8
++#define T31 0x676f02d9
++#define T32 0x8d2a4c8a
++#define T33 0xfffa3942
++#define T34 0x8771f681
++#define T35 0x6d9d6122
++#define T36 0xfde5380c
++#define T37 0xa4beea44
++#define T38 0x4bdecfa9
++#define T39 0xf6bb4b60
++#define T40 0xbebfbc70
++#define T41 0x289b7ec6
++#define T42 0xeaa127fa
++#define T43 0xd4ef3085
++#define T44 0x04881d05
++#define T45 0xd9d4d039
++#define T46 0xe6db99e5
++#define T47 0x1fa27cf8
++#define T48 0xc4ac5665
++#define T49 0xf4292244
++#define T50 0x432aff97
++#define T51 0xab9423a7
++#define T52 0xfc93a039
++#define T53 0x655b59c3
++#define T54 0x8f0ccc92
++#define T55 0xffeff47d
++#define T56 0x85845dd1
++#define T57 0x6fa87e4f
++#define T58 0xfe2ce6e0
++#define T59 0xa3014314
++#define T60 0x4e0811a1
++#define T61 0xf7537e82
++#define T62 0xbd3af235
++#define T63 0x2ad7d2bb
++#define T64 0xeb86d391
++
++static void
++md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
++{
++    md5_word_t
++	a = pms->abcd[0], b = pms->abcd[1],
++	c = pms->abcd[2], d = pms->abcd[3];
++    md5_word_t t;
++
++#ifndef ARCH_IS_BIG_ENDIAN
++# define ARCH_IS_BIG_ENDIAN 1	/* slower, default implementation */
++#endif
++#if ARCH_IS_BIG_ENDIAN
++
++    /*
++     * On big-endian machines, we must arrange the bytes in the right
++     * order.  (This also works on machines of unknown byte order.)
++     */
++    md5_word_t X[16];
++    const md5_byte_t *xp = data;
++    int i;
++
++    for (i = 0; i < 16; ++i, xp += 4)
++	X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
++
++#else  /* !ARCH_IS_BIG_ENDIAN */
++
++    /*
++     * On little-endian machines, we can process properly aligned data
++     * without copying it.
++     */
++    md5_word_t xbuf[16];
++    const md5_word_t *X;
++
++    if (!((data - (const md5_byte_t *)0) & 3)) {
++	/* data are properly aligned */
++	X = (const md5_word_t *)data;
++    } else {
++	/* not aligned */
++	memcpy(xbuf, data, 64);
++	X = xbuf;
++    }
++#endif
++
++#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
++
++    /* Round 1. */
++    /* Let [abcd k s i] denote the operation
++       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
++#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
++#define SET(a, b, c, d, k, s, Ti)\
++  t = a + F(b,c,d) + X[k] + Ti;\
++  a = ROTATE_LEFT(t, s) + b
++    /* Do the following 16 operations. */
++    SET(a, b, c, d,  0,  7,  T1);
++    SET(d, a, b, c,  1, 12,  T2);
++    SET(c, d, a, b,  2, 17,  T3);
++    SET(b, c, d, a,  3, 22,  T4);
++    SET(a, b, c, d,  4,  7,  T5);
++    SET(d, a, b, c,  5, 12,  T6);
++    SET(c, d, a, b,  6, 17,  T7);
++    SET(b, c, d, a,  7, 22,  T8);
++    SET(a, b, c, d,  8,  7,  T9);
++    SET(d, a, b, c,  9, 12, T10);
++    SET(c, d, a, b, 10, 17, T11);
++    SET(b, c, d, a, 11, 22, T12);
++    SET(a, b, c, d, 12,  7, T13);
++    SET(d, a, b, c, 13, 12, T14);
++    SET(c, d, a, b, 14, 17, T15);
++    SET(b, c, d, a, 15, 22, T16);
++#undef SET
++
++     /* Round 2. */
++     /* Let [abcd k s i] denote the operation
++          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
++#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
++#define SET(a, b, c, d, k, s, Ti)\
++  t = a + G(b,c,d) + X[k] + Ti;\
++  a = ROTATE_LEFT(t, s) + b
++     /* Do the following 16 operations. */
++    SET(a, b, c, d,  1,  5, T17);
++    SET(d, a, b, c,  6,  9, T18);
++    SET(c, d, a, b, 11, 14, T19);
++    SET(b, c, d, a,  0, 20, T20);
++    SET(a, b, c, d,  5,  5, T21);
++    SET(d, a, b, c, 10,  9, T22);
++    SET(c, d, a, b, 15, 14, T23);
++    SET(b, c, d, a,  4, 20, T24);
++    SET(a, b, c, d,  9,  5, T25);
++    SET(d, a, b, c, 14,  9, T26);
++    SET(c, d, a, b,  3, 14, T27);
++    SET(b, c, d, a,  8, 20, T28);
++    SET(a, b, c, d, 13,  5, T29);
++    SET(d, a, b, c,  2,  9, T30);
++    SET(c, d, a, b,  7, 14, T31);
++    SET(b, c, d, a, 12, 20, T32);
++#undef SET
++
++     /* Round 3. */
++     /* Let [abcd k s t] denote the operation
++          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++#define SET(a, b, c, d, k, s, Ti)\
++  t = a + H(b,c,d) + X[k] + Ti;\
++  a = ROTATE_LEFT(t, s) + b
++     /* Do the following 16 operations. */
++    SET(a, b, c, d,  5,  4, T33);
++    SET(d, a, b, c,  8, 11, T34);
++    SET(c, d, a, b, 11, 16, T35);
++    SET(b, c, d, a, 14, 23, T36);
++    SET(a, b, c, d,  1,  4, T37);
++    SET(d, a, b, c,  4, 11, T38);
++    SET(c, d, a, b,  7, 16, T39);
++    SET(b, c, d, a, 10, 23, T40);
++    SET(a, b, c, d, 13,  4, T41);
++    SET(d, a, b, c,  0, 11, T42);
++    SET(c, d, a, b,  3, 16, T43);
++    SET(b, c, d, a,  6, 23, T44);
++    SET(a, b, c, d,  9,  4, T45);
++    SET(d, a, b, c, 12, 11, T46);
++    SET(c, d, a, b, 15, 16, T47);
++    SET(b, c, d, a,  2, 23, T48);
++#undef SET
++
++     /* Round 4. */
++     /* Let [abcd k s t] denote the operation
++          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
++#define I(x, y, z) ((y) ^ ((x) | ~(z)))
++#define SET(a, b, c, d, k, s, Ti)\
++  t = a + I(b,c,d) + X[k] + Ti;\
++  a = ROTATE_LEFT(t, s) + b
++     /* Do the following 16 operations. */
++    SET(a, b, c, d,  0,  6, T49);
++    SET(d, a, b, c,  7, 10, T50);
++    SET(c, d, a, b, 14, 15, T51);
++    SET(b, c, d, a,  5, 21, T52);
++    SET(a, b, c, d, 12,  6, T53);
++    SET(d, a, b, c,  3, 10, T54);
++    SET(c, d, a, b, 10, 15, T55);
++    SET(b, c, d, a,  1, 21, T56);
++    SET(a, b, c, d,  8,  6, T57);
++    SET(d, a, b, c, 15, 10, T58);
++    SET(c, d, a, b,  6, 15, T59);
++    SET(b, c, d, a, 13, 21, T60);
++    SET(a, b, c, d,  4,  6, T61);
++    SET(d, a, b, c, 11, 10, T62);
++    SET(c, d, a, b,  2, 15, T63);
++    SET(b, c, d, a,  9, 21, T64);
++#undef SET
++
++     /* Then perform the following additions. (That is increment each
++        of the four registers by the value it had before this block
++        was started.) */
++    pms->abcd[0] += a;
++    pms->abcd[1] += b;
++    pms->abcd[2] += c;
++    pms->abcd[3] += d;
++}
++
++void
++md5_init(md5_state_t *pms)
++{
++    pms->count[0] = pms->count[1] = 0;
++    pms->abcd[0] = 0x67452301;
++    pms->abcd[1] = 0xefcdab89;
++    pms->abcd[2] = 0x98badcfe;
++    pms->abcd[3] = 0x10325476;
++}
++
++void
++md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
++{
++    const md5_byte_t *p = data;
++    int left = nbytes;
++    int offset = (pms->count[0] >> 3) & 63;
++    md5_word_t nbits = (md5_word_t)(nbytes << 3);
++
++    if (nbytes <= 0)
++	return;
++
++    /* Update the message length. */
++    pms->count[1] += nbytes >> 29;
++    pms->count[0] += nbits;
++    if (pms->count[0] < nbits)
++	pms->count[1]++;
++
++    /* Process an initial partial block. */
++    if (offset) {
++	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
++
++	memcpy(pms->buf + offset, p, copy);
++	if (offset + copy < 64)
++	    return;
++	p += copy;
++	left -= copy;
++	md5_process(pms, pms->buf);
++    }
++
++    /* Process full blocks. */
++    for (; left >= 64; p += 64, left -= 64)
++	md5_process(pms, p);
++
++    /* Process a final partial block. */
++    if (left)
++	memcpy(pms->buf, p, left);
++}
++
++void
++md5_finish(md5_state_t *pms, md5_byte_t digest[16])
++{
++    static const md5_byte_t pad[64] = {
++	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++    };
++    md5_byte_t data[8];
++    int i;
++
++    /* Save the length before padding. */
++    for (i = 0; i < 8; ++i)
++	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
++    /* Pad to 56 bytes mod 64. */
++    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
++    /* Append the length. */
++    md5_append(pms, data, 8);
++    for (i = 0; i < 16; ++i)
++	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
++}
+--- kopete/protocols/yahoo/libkyahoo/webcamtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/webcamtask.h	(revision 586398)
+@@ -0,0 +1,112 @@
++/*
++    Kopete Yahoo Protocol
++    Handles incoming webcam connections
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef WEBCAMTASK_H
++#define WEBCAMTASK_H
++
++#include "task.h"
++#include <qmap.h>
++#include <qpixmap.h>
++#include <qstringlist.h>
++
++class QString;
++class YMSGTransfer;
++class QBuffer;
++namespace KNetwork {
++	class KStreamSocket;
++}
++using namespace KNetwork;
++
++enum ConnectionStatus{ InitialStatus, ConnectedStage1, ConnectedStage2, Receiving, Sending, SendingEmpty };
++enum PacketType { Image, ConnectionClosed, UserRequest, NewWatcher, WatcherLeft };
++enum Direction { Incoming, Outgoing };
++
++struct YahooWebcamInformation
++{
++	QString		sender;
++	QString		server;
++	QString		key;
++	ConnectionStatus status;
++	PacketType	type;
++	Direction	direction;
++	uchar		reason;
++	Q_INT32		dataLength;
++	Q_INT32		timestamp;
++	bool		headerRead;
++	QBuffer 	*buffer;
++};
++
++typedef QMap< KStreamSocket *, YahooWebcamInformation > SocketInfoMap;
++
++/**
++ at author André Duffeck
++*/
++class WebcamTask : public Task
++{
++	Q_OBJECT
++public:
++	WebcamTask(Task *parent);
++	~WebcamTask();
++	
++	bool take(Transfer *transfer);
++	bool forMe( Transfer* transfer ) const;
++
++	bool transmitting() { return transmittingData; }
++	
++	void requestWebcam( const QString &who );
++	void closeWebcam( const QString &who );
++	
++	void registerWebcam();
++	void sendWebcamImage( const QByteArray &image );
++	void addPendingInvitation( const QString &userId );
++	void grantAccess( const QString &userId );
++	void closeOutgoingWebcam();
++signals:
++	void webcamNotAvailable( const QString & );
++	void webcamClosed( const QString &, int );
++	void webcamPaused( const QString& );
++	void webcamImageReceived( const QString &, const QPixmap &);
++	void readyForTransmission();
++	void stopTransmission();
++	void viewerJoined( const QString & );
++	void viewerLeft( const QString & );
++	void viewerRequest( const QString & );
++private slots:
++	void slotConnectionStage1Established();
++	void slotConnectionStage2Established();
++	void slotConnectionFailed(int);
++	void slotRead();
++	void sendEmptyWebcamImage();
++	void transmitWebcamImage();
++private:
++	void parseWebcamInformation( YMSGTransfer *transfer );
++	void parseData( QByteArray &data, KStreamSocket *socket );
++
++	void connectStage2( KStreamSocket *socket );
++	void processData( KStreamSocket *socket );
++	void cleanUpConnection( KStreamSocket *socket );	
++
++	QString keyPending;	// the buddy we have requested the webcam from
++	SocketInfoMap socketMap;
++	bool transmittingData;
++	QStringList pendingInvitations;
++	QStringList accessGranted;
++	int timestamp;
++	QByteArray pictureBuffer;
++	bool transmissionPending;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/ymsgtransfer.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/ymsgtransfer.h	(revision 586398)
+@@ -0,0 +1,76 @@
++/*
++    Kopete Yahoo Protocol
++    Handles logging into to the Yahoo service
++
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef YMSG_TRANSFER_H
++#define YMSG_TRANSFER_H
++
++#include "transfer.h"
++
++#include "yahootypes.h"
++#include <qcstring.h>
++#include <qpair.h>
++#include <qvaluelist.h>
++
++class YMSGTransferPrivate;
++class QString;
++
++typedef QPair< int, QCString > Param;
++typedef QValueList< Param > ParamList;
++
++/**
++ at author Duncan Mac-Vicar Prett
++*/
++class YMSGTransfer : public Transfer
++{
++public:
++	YMSGTransfer(Yahoo::Service service);
++	YMSGTransfer(Yahoo::Service service, Yahoo::Status status);
++	YMSGTransfer();
++	~YMSGTransfer();
++
++
++	TransferType type();
++
++	//! Get the validity of the transfer object
++	bool isValid();
++	Yahoo::Service service();
++	void setService(Yahoo::Service service);
++	Yahoo::Status status();
++	void setStatus(Yahoo::Status status);
++	unsigned int id();
++	void setId(unsigned int id);
++
++	ParamList paramList();
++	QCString firstParam( int index );
++	QCString nthParam( int index, int occurence );
++	QCString nthParamSeparated( int index, int occurence, int separator );
++	int paramCount( int index );
++	
++
++	void setParam(int index, const QCString &data);
++	void setParam(int index, int data);
++	QByteArray serialize();
++	
++	int length();
++private:
++	YMSGTransferPrivate* d;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/md5.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/md5.h	(revision 586398)
+@@ -0,0 +1,93 @@
++/*
++  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
++
++  This software is provided 'as-is', without any express or implied
++  warranty.  In no event will the authors be held liable for any damages
++  arising from the use of this software.
++
++  Permission is granted to anyone to use this software for any purpose,
++  including commercial applications, and to alter it and redistribute it
++  freely, subject to the following restrictions:
++
++  1. The origin of this software must not be misrepresented; you must not
++     claim that you wrote the original software. If you use this software
++     in a product, an acknowledgment in the product documentation would be
++     appreciated but is not required.
++  2. Altered source versions must be plainly marked as such, and must not be
++     misrepresented as being the original software.
++  3. This notice may not be removed or altered from any source distribution.
++
++  L. Peter Deutsch
++  ghost at aladdin.com
++
++ */
++/*
++  Independent implementation of MD5 (RFC 1321).
++
++  This code implements the MD5 Algorithm defined in RFC 1321.
++  It is derived directly from the text of the RFC and not from the
++  reference implementation.
++
++  The original and principal author of md5.h is L. Peter Deutsch
++  <ghost at aladdin.com>.  Other authors are noted in the change history
++  that follows (in reverse chronological order):
++
++  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
++  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
++	added conditionalization for C++ compilation from Martin
++	Purschke <purschke at bnl.gov>.
++  1999-05-03 lpd Original version.
++ */
++
++#ifndef md5_INCLUDED
++#  define md5_INCLUDED
++
++/*
++ * This code has some adaptations for the Ghostscript environment, but it
++ * will compile and run correctly in any environment with 8-bit chars and
++ * 32-bit ints.  Specifically, it assumes that if the following are
++ * defined, they have the same meaning as in Ghostscript: P1, P2, P3,
++ * ARCH_IS_BIG_ENDIAN.
++ */
++
++typedef unsigned char md5_byte_t; /* 8-bit byte */
++typedef unsigned int md5_word_t; /* 32-bit word */
++
++/* Define the state of the MD5 Algorithm. */
++typedef struct md5_state_s {
++    md5_word_t count[2];	/* message length in bits, lsw first */
++    md5_word_t abcd[4];		/* digest buffer */
++    md5_byte_t buf[64];		/* accumulate block */
++} md5_state_t;
++
++#ifdef __cplusplus
++extern "C" 
++{
++#endif
++
++/* Initialize the algorithm. */
++#ifdef P1
++void md5_init(P1(md5_state_t *pms));
++#else
++void md5_init(md5_state_t *pms);
++#endif
++
++/* Append a string to the message. */
++#ifdef P3
++void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes));
++#else
++void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
++#endif
++
++/* Finish the message and return the digest. */
++#ifdef P2
++void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16]));
++#else
++void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
++#endif
++
++#ifdef __cplusplus
++}  /* end extern "C" */
++#endif
++
++#endif /* md5_INCLUDED */
+--- kopete/protocols/yahoo/libkyahoo/connector.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/connector.cpp	(revision 586398)
+@@ -0,0 +1,62 @@
++/*
++    Kopete Oscar Protocol
++    connector.cpp - the Oscar socket connector
++
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "connector.h"
++
++Connector::Connector(QObject *parent)
++:QObject(parent)
++{
++	setPeerAddressNone();
++}
++
++Connector::~Connector()
++{
++}
++
++bool Connector::havePeerAddress() const
++{
++	return haveaddr;
++}
++
++QHostAddress Connector::peerAddress() const
++{
++	return addr;
++}
++
++Q_UINT16 Connector::peerPort() const
++{
++	return port;
++}
++
++void Connector::setPeerAddressNone()
++{
++	haveaddr = false;
++	addr = QHostAddress();
++	port = 0;
++}
++
++void Connector::setPeerAddress(const QHostAddress &_addr, Q_UINT16 _port)
++{
++	haveaddr = true;
++	addr = _addr;
++	port = _port;
++}
++
++#include "connector.moc"
+--- kopete/protocols/yahoo/libkyahoo/sendauthresptask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendauthresptask.h	(revision 586398)
+@@ -0,0 +1,46 @@
++/*
++    Kopete Yahoo Protocol
++    Send a authorization request response
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete    (c) 2003-2006 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SENDAUTHRESPTASK_H
++#define SENDAUTHRESPTASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class SendAuthRespTask : public Task
++{
++Q_OBJECT
++public:
++	SendAuthRespTask(Task *parent);
++	~SendAuthRespTask();
++	
++	virtual void onGo();
++
++	void setGranted( bool );
++	void setTarget( const QString &to );
++	void setMessage( const QString &msg );
++private:
++	QString m_target;
++	bool m_granted;
++	QString m_msg;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/listtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/listtask.cpp	(revision 586398)
+@@ -0,0 +1,107 @@
++/*
++    Kopete Yahoo Protocol
++    Handles several lists such as buddylist, ignorelist and so on
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qstring.h>
++
++#include "listtask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "client.h"
++#include <qstring.h>
++#include <qstringlist.h>
++#include <kdebug.h>
++
++ListTask::ListTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++ListTask::~ListTask()
++{
++
++}
++
++bool ListTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++	
++	YMSGTransfer *t = static_cast<YMSGTransfer *>(transfer);
++
++	parseBuddyList( t );
++	parseStealthList( t );
++
++	return true;
++}
++
++bool ListTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++
++	if ( t->service() == Yahoo::ServiceList )
++		return true;
++	else
++		return false;
++}
++
++void ListTask::parseBuddyList( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString raw;
++	raw = t->firstParam( 87 );
++	
++	if( raw.isEmpty() )
++		return;
++
++	QStringList groups;
++	groups = QStringList::split( "\n", raw );
++
++	for ( QStringList::Iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt ) 
++	{
++		QString group = (*groupIt).section(":", 0, 0);
++		QStringList buddies;
++		buddies = QStringList::split( ",", (*groupIt).section(":", 1,1) );
++		for ( QStringList::Iterator buddyIt = buddies.begin(); buddyIt != buddies.end(); ++buddyIt ) 
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Parsed buddy: " << *buddyIt << " in group " << group << endl;
++			emit gotBuddy( *buddyIt, QString::null, group );
++		}
++	}
++}
++
++void ListTask::parseStealthList( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString raw;
++	raw = t->firstParam( 185 );
++
++	QStringList buddies = QStringList::split( ",", raw );
++	for ( QStringList::Iterator it = buddies.begin(); it != buddies.end(); ++it ) 
++	{
++		emit stealthStatusChanged( *it, Yahoo::StealthActive );
++	}
++}
++
++#include "listtask.moc"
+--- kopete/protocols/yahoo/libkyahoo/yahooconnector.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahooconnector.h	(revision 586398)
+@@ -0,0 +1,67 @@
++
++/***************************************************************************
++                   oscarconnector.h  -  Socket Connector for KNetwork
++                             -------------------
++    begin                : Wed Jul 7 2004
++    copyright            : (C) 2004 by Till Gerken <till at tantalo.net>
++                           (C) 2004 by Matt Rogers <matt.rogers at kdemail.net>
++
++    Kopete (C) 2004 Kopete developers <kopete-devel at kde.org>
++ ***************************************************************************/
++
++/***************************************************************************
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU Lesser General Public License as        *
++ *   published by the Free Software Foundation; either version 2.1 of the  *
++ *   License, or (at your option) any later version.                       *
++ *                                                                         *
++ ***************************************************************************/
++
++#ifndef YAHOOCONNECTOR_H
++#define YAHOOCONNECTOR_H
++
++#include "connector.h"
++
++class ByteStream;
++class KNetworkByteStream;
++class KResolverEntry;
++
++/**
++ at author Till Gerken
++ at author Matt Rogers
++*/
++class KNetworkConnector : public Connector
++{
++
++Q_OBJECT
++
++public:
++	KNetworkConnector( QObject *parent = 0, const char *name = 0 );
++
++	virtual ~KNetworkConnector();
++
++	virtual void connectToServer( const QString &server );
++	virtual ByteStream *stream() const;
++	virtual void done();
++
++	void setOptHostPort( const QString &host, Q_UINT16 port );
++
++	int errorCode();
++
++private slots:
++	void slotConnected();
++	void slotError( int );
++
++private:
++	QString mHost;
++	Q_UINT16 mPort;
++	int mErrorCode;
++
++	KNetworkByteStream *mByteStream;
++
++};
++
++#endif
++
++// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
+--- kopete/protocols/yahoo/libkyahoo/safedelete.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/safedelete.cpp	(revision 586398)
+@@ -0,0 +1,139 @@
++/*
++    safedelete.cpp - Kopete Groupwise Protocol
++  
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "safedelete.h"
++
++#include <qtimer.h>
++
++//----------------------------------------------------------------------------
++// SafeDelete
++//----------------------------------------------------------------------------
++SafeDelete::SafeDelete()
++{
++	lock = 0;
++}
++
++SafeDelete::~SafeDelete()
++{
++	if(lock)
++		lock->dying();
++}
++
++void SafeDelete::deleteLater(QObject *o)
++{
++	if(!lock)
++		deleteSingle(o);
++	else
++		list.append(o);
++}
++
++void SafeDelete::unlock()
++{
++	lock = 0;
++	deleteAll();
++}
++
++void SafeDelete::deleteAll()
++{
++	if(list.isEmpty())
++		return;
++
++	QObjectListIt it(list);
++	for(QObject *o; (o = it.current()); ++it)
++		deleteSingle(o);
++	list.clear();
++}
++
++void SafeDelete::deleteSingle(QObject *o)
++{
++#if QT_VERSION < 0x030000
++	// roll our own QObject::deleteLater()
++	SafeDeleteLater *sdl = SafeDeleteLater::ensureExists();
++	sdl->deleteItLater(o);
++#else
++	o->deleteLater();
++#endif
++}
++
++//----------------------------------------------------------------------------
++// SafeDeleteLock
++//----------------------------------------------------------------------------
++SafeDeleteLock::SafeDeleteLock(SafeDelete *sd)
++{
++	own = false;
++	if(!sd->lock) {
++		_sd = sd;
++		_sd->lock = this;
++	}
++	else
++		_sd = 0;
++}
++
++SafeDeleteLock::~SafeDeleteLock()
++{
++	if(_sd) {
++		_sd->unlock();
++		if(own)
++			delete _sd;
++	}
++}
++
++void SafeDeleteLock::dying()
++{
++	_sd = new SafeDelete(*_sd);
++	own = true;
++}
++
++//----------------------------------------------------------------------------
++// SafeDeleteLater
++//----------------------------------------------------------------------------
++SafeDeleteLater *SafeDeleteLater::self = 0;
++
++SafeDeleteLater *SafeDeleteLater::ensureExists()
++{
++	if(!self)
++		new SafeDeleteLater();
++	return self;
++}
++
++SafeDeleteLater::SafeDeleteLater()
++{
++	list.setAutoDelete(true);
++	self = this;
++	QTimer::singleShot(0, this, SLOT(explode()));
++}
++
++SafeDeleteLater::~SafeDeleteLater()
++{
++	list.clear();
++	self = 0;
++}
++
++void SafeDeleteLater::deleteItLater(QObject *o)
++{
++	list.append(o);
++}
++
++void SafeDeleteLater::explode()
++{
++	delete this;
++}
++
++#include "safedelete.moc"
++
+--- kopete/protocols/yahoo/libkyahoo/messagereceivertask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/messagereceivertask.h	(revision 586398)
+@@ -0,0 +1,49 @@
++/*
++    Kopete Yahoo Protocol
++    Receive Messages
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef MESSAGERECEIVERTASK_H
++#define MESSAGERECEIVERTASK_H
++
++#include "task.h"
++
++class QString;
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class MessageReceiverTask : public Task
++{
++Q_OBJECT
++public:
++	MessageReceiverTask(Task *parent);
++	~MessageReceiverTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++	void parseMessage( YMSGTransfer *transfer );
++	void parseNotify( YMSGTransfer *transfer );
++signals:
++	void gotIm(const QString&, const QString&, long, int);
++	void gotBuzz( const QString &who, long tm );
++	void systemMessage(const QString&);
++	void gotTypingNotify(const QString &, int);
++	void gotWebcamInvite(const QString &);
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yabentry.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yabentry.h	(revision 586398)
+@@ -0,0 +1,91 @@
++/*
++    yabentry.h - Encapsulate Yahoo Adressbook information
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++#ifndef YABEntry_H
++#define YABEntry_H
++
++#include <kdebug.h>
++#include <qdatetime.h>
++#include <qdom.h>
++
++struct YABEntry
++{
++	enum Source { SourceYAB, SourceContact };
++
++	// Personal
++	QString		firstName;
++	QString		secondName;
++	QString		lastName;
++	QString		nickName;
++	QString		title;
++
++	// Primary Information	
++	QString		phoneMobile;
++	QString		email;
++	QString		yahooId;
++	int		YABId;
++	Source		source;
++
++	// Additional Information
++	QString		pager;
++	QString		fax;
++	QString		additionalNumber;
++	QString		altEmail1;
++	QString		altEmail2;
++	QString		imAIM;
++	QString		imICQ;
++	QString		imMSN;
++	QString		imGoogleTalk;
++	QString		imSkype;
++	QString		imIRC;
++	QString		imQQ;
++
++	// Private Information
++	QString		privateAdress;
++	QString		privateCity;
++	QString		privateState;
++	QString		privateZIP;
++	QString		privateCountry;
++	QString		privatePhone;
++	QString		privateURL;
++		
++	// Work Information
++	QString		corporation;
++	QString		workAdress;
++	QString		workCity;
++	QString		workState;
++	QString		workZIP;
++	QString		workCountry;
++	QString		workPhone;
++	QString		workURL;
++
++	// Miscellanous
++	QDate		birthday;
++	QDate		anniversary;
++	QString		notes;
++	QString		additional1;
++	QString		additional2;
++	QString		additional3;
++	QString		additional4;
++
++	
++	void fromQDomElement( const QDomElement &e );
++	void fromQDomDocument( const QDomDocument &e );
++	void fillQDomElement( QDomElement &e ) const;
++
++	void dump() const;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yahoo_fn.c	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoo_fn.c	(revision 586398)
+@@ -0,0 +1,4620 @@
++/*
++ * gaim
++ *
++ * Some code copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
++ * libfaim code copyright 1998, 1999 Adam Fritzler <afritz at auk.cx>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include "yahoo_fn.h"
++
++unsigned char table_0[256] = {
++   0x5A, 0x41, 0x11, 0x77, 0x29, 0x9C, 0x31, 0xAD,
++   0x4A, 0x32, 0x1A, 0x6D, 0x56, 0x9F, 0x39, 0xA6,
++   0x0C, 0xE8, 0x49, 0x40, 0xA4, 0x21, 0xE9, 0x01,
++   0x91, 0x86, 0x2F, 0xB9, 0xED, 0x80, 0x51, 0xAB,
++   0x7F, 0x92, 0xF2, 0x73, 0xCD, 0xD9, 0x75, 0x2A,
++   0x70, 0x34, 0x35, 0x8D, 0xA8, 0x72, 0x7D, 0x9B,
++   0x2E, 0xC5, 0x2D, 0x76, 0x1E, 0xBB, 0xE7, 0x37,
++   0xBA, 0xB7, 0xB2, 0x03, 0x20, 0x17, 0x8A, 0x07,
++   0xD6, 0x96, 0x13, 0x95, 0xE5, 0xF1, 0x18, 0x3B,
++   0xA5, 0x62, 0x33, 0xC1, 0x44, 0x3D, 0x6C, 0xA7,
++   0xBF, 0x1C, 0x60, 0xFF, 0x5B, 0xF5, 0x8E, 0xE6,
++   0x5C, 0xCC, 0xF7, 0x69, 0x15, 0x0F, 0x0B, 0xBD,
++   0x12, 0x9D, 0xB3, 0x65, 0x53, 0xB1, 0x14, 0xF4,
++   0x19, 0x3E, 0xB6, 0x45, 0xCB, 0xA2, 0x7A, 0xD3,
++   0xF8, 0xD1, 0x61, 0xEE, 0xBC, 0xC6, 0xB0, 0x5D,
++   0x4B, 0x09, 0x26, 0xE1, 0x1D, 0x6E, 0xC3, 0xFB,
++   0x68, 0x4C, 0x42, 0x52, 0x5F, 0xDE, 0xFD, 0xEF,
++   0x81, 0x04, 0x6F, 0xE0, 0xF0, 0x1F, 0x0D, 0x7C,
++   0x58, 0x4F, 0x1B, 0x30, 0xCF, 0x9A, 0x2B, 0x05,
++   0xF6, 0x3F, 0x78, 0xAC, 0xD8, 0xEC, 0xE2, 0x25,
++   0x93, 0xDA, 0x84, 0x8C, 0x4E, 0xD5, 0x38, 0x0A,
++   0x06, 0x7E, 0xD4, 0x59, 0x98, 0xE3, 0x36, 0xC2,
++   0xD2, 0xA3, 0x10, 0x79, 0xFA, 0xC9, 0x16, 0x27,
++   0x66, 0x89, 0xFE, 0x57, 0xF3, 0x83, 0xB8, 0x28,
++   0x3C, 0xC7, 0xCE, 0x71, 0xC8, 0xDB, 0x22, 0xE4,
++   0xDD, 0xDF, 0x02, 0x8F, 0x5E, 0xEB, 0x48, 0x2C,
++   0x08, 0xC4, 0x43, 0xEA, 0x50, 0x55, 0x90, 0x54,
++   0x87, 0xCA, 0x00, 0x24, 0x6B, 0x85, 0x97, 0xD7,
++   0xDC, 0x6A, 0x67, 0xD0, 0x88, 0xA1, 0x9E, 0xC0,
++   0x46, 0xAE, 0x64, 0x74, 0x4D, 0xA0, 0x99, 0xB5,
++   0x0E, 0x8B, 0xAA, 0x3A, 0xB4, 0xFC, 0xA9, 0x94,
++   0x7B, 0xBE, 0xF9, 0xAF, 0x82, 0x63, 0x47, 0x23 };
++
++unsigned char table_1[256] = {
++   0x08, 0xCB, 0x54, 0xCF, 0x97, 0x53, 0x59, 0xF1,
++   0x66, 0xEC, 0xDB, 0x1B, 0xB1, 0xE2, 0x36, 0xEB,
++   0xB3, 0x8F, 0x71, 0xA8, 0x90, 0x7D, 0xDA, 0xDC,
++   0x2C, 0x2F, 0xE8, 0x6A, 0x73, 0x37, 0xAE, 0xCC,
++   0xA1, 0x16, 0xE6, 0xFC, 0x9C, 0xA9, 0x2A, 0x3F,
++   0x58, 0xFD, 0x56, 0x4C, 0xA5, 0xF2, 0x33, 0x99,
++   0x1A, 0xB7, 0xFE, 0xA6, 0x1E, 0x32, 0x9E, 0x48,
++   0x03, 0x4A, 0x78, 0xEE, 0xCA, 0xC3, 0x88, 0x7A,
++   0xAC, 0x23, 0xAA, 0xBD, 0xDE, 0xD3, 0x67, 0x43,
++   0xFF, 0x64, 0x8A, 0xF9, 0x04, 0xD0, 0x7B, 0xC2,
++   0xBC, 0xF3, 0x89, 0x0E, 0xDD, 0xAB, 0x9D, 0x84,
++   0x5A, 0x62, 0x7F, 0x6D, 0x82, 0x68, 0xA3, 0xED,
++   0x2E, 0x07, 0x41, 0xEF, 0x2D, 0x70, 0x4F, 0x69,
++   0x8E, 0xE7, 0x0F, 0x11, 0x19, 0xAF, 0x31, 0xFB,
++   0x8D, 0x4B, 0x5F, 0x96, 0x75, 0x42, 0x6C, 0x46,
++   0xE4, 0x55, 0xD6, 0x3B, 0xE1, 0xD1, 0xB0, 0xB5,
++   0x45, 0x29, 0xC0, 0x94, 0x9F, 0xD4, 0x15, 0x17,
++   0x3C, 0x47, 0xC8, 0xD9, 0xC6, 0x76, 0xB9, 0x02,
++   0xE0, 0xC9, 0xB2, 0x01, 0xC1, 0x5D, 0x4E, 0x14,
++   0xF4, 0xAD, 0xB6, 0x00, 0x72, 0xF0, 0x49, 0x0D,
++   0xD8, 0x5E, 0x6F, 0x2B, 0x8C, 0x51, 0x83, 0xC5,
++   0x0A, 0x85, 0xE5, 0x38, 0x7E, 0x26, 0xEA, 0x22,
++   0x6B, 0x06, 0xD5, 0x8B, 0xBF, 0xC7, 0x35, 0x1D,
++   0xF6, 0x24, 0x28, 0xCE, 0x9B, 0x77, 0x20, 0x60,
++   0xF5, 0x87, 0x3D, 0x65, 0x86, 0x0C, 0xDF, 0xBA,
++   0x12, 0xA4, 0x3A, 0x34, 0xD7, 0xA0, 0xF8, 0x63,
++   0x52, 0x27, 0xB8, 0x18, 0xA7, 0x13, 0x91, 0x09,
++   0x93, 0x5C, 0x10, 0x9A, 0xB4, 0xE9, 0x44, 0xC4,
++   0x21, 0x57, 0x1C, 0x0B, 0xA2, 0x74, 0x4D, 0xBE,
++   0xD2, 0x1F, 0xCD, 0xE3, 0x6E, 0x7C, 0x40, 0x50,
++   0x39, 0x80, 0x98, 0xFA, 0x25, 0x92, 0x30, 0x5B,
++   0x05, 0x95, 0xBB, 0x79, 0x61, 0x3E, 0x81, 0xF7 };
++
++unsigned char table_2[32] = {
++   0x19, 0x05, 0x09, 0x1C, 0x0B, 0x1A, 0x12, 0x03,
++   0x06, 0x04, 0x0D, 0x1D, 0x15, 0x0E, 0x1B, 0x18,
++   0x00, 0x07, 0x08, 0x02, 0x13, 0x1F, 0x0C, 0x1E,
++   0x16, 0x0A, 0x10, 0x0F, 0x01, 0x14, 0x11, 0x17 };
++
++unsigned char table_3[256] = {
++   0xBC, 0x1B, 0xCC, 0x1E, 0x5B, 0x59, 0x4F, 0xA8,
++   0x62, 0xC6, 0xC1, 0xBB, 0x83, 0x2D, 0xA3, 0xA6,
++   0x5A, 0xDC, 0xE5, 0x93, 0xFB, 0x5C, 0xD6, 0x2A,
++   0x97, 0xC7, 0x1C, 0x73, 0x08, 0x45, 0xD2, 0x89,
++   0x4A, 0xD4, 0xCF, 0x0C, 0x1D, 0xD8, 0xCD, 0x26,
++   0x8F, 0x11, 0x55, 0x8B, 0xD3, 0x53, 0xCE, 0x00,
++   0xB5, 0x3B, 0x2E, 0x39, 0x88, 0x7B, 0x85, 0x46,
++   0x54, 0xA5, 0x31, 0x40, 0x3E, 0x0A, 0x4C, 0x68,
++   0x70, 0x0F, 0xBA, 0x0E, 0x75, 0x8A, 0xEB, 0x44,
++   0x60, 0x6C, 0x05, 0xC9, 0xF0, 0xDD, 0x0D, 0x66,
++   0xAB, 0xA1, 0xAD, 0xF2, 0x12, 0x6A, 0xE6, 0x27,
++   0xF6, 0x9F, 0xDB, 0xB8, 0xF4, 0x56, 0x5E, 0x2C,
++   0xDA, 0xFE, 0x34, 0x86, 0xF5, 0xC2, 0xB0, 0xF1,
++   0xCB, 0xF3, 0x78, 0x9B, 0x7F, 0xB4, 0xD7, 0x58,
++   0x74, 0x07, 0x72, 0x96, 0x02, 0xCA, 0xAC, 0xE8,
++   0x5D, 0xA7, 0x32, 0xBD, 0x81, 0x43, 0x18, 0xF8,
++   0x15, 0x0B, 0xE9, 0x76, 0x30, 0xBF, 0x3A, 0x22,
++   0x9E, 0xD1, 0x79, 0x37, 0xBE, 0x8C, 0x7A, 0x98,
++   0x21, 0x95, 0x10, 0x8D, 0xDF, 0xC0, 0x69, 0xC8,
++   0x03, 0x6E, 0x4B, 0x36, 0xFC, 0x6F, 0xA9, 0x48,
++   0x63, 0xE1, 0xB9, 0x24, 0x87, 0x13, 0xB2, 0xA4,
++   0x84, 0x06, 0x14, 0x61, 0x3D, 0x92, 0xB1, 0x41,
++   0xE2, 0x71, 0xAF, 0x16, 0xDE, 0x25, 0x82, 0xD9,
++   0x2B, 0x33, 0x51, 0xA2, 0x4E, 0x7D, 0x94, 0xFF,
++   0xFD, 0x5F, 0x80, 0xED, 0x64, 0xE7, 0x50, 0x6D,
++   0xD0, 0x3C, 0x6B, 0x65, 0x77, 0x17, 0x1A, 0xEC,
++   0xD5, 0xAA, 0xF9, 0xC4, 0x9C, 0x35, 0xE3, 0x42,
++   0xE4, 0x19, 0x52, 0x67, 0xB7, 0x9D, 0x28, 0xC5,
++   0x47, 0x38, 0x91, 0x57, 0xAE, 0x3F, 0x29, 0x9A,
++   0x2F, 0xF7, 0x90, 0x04, 0xEE, 0xFA, 0x20, 0xB6,
++   0xEA, 0x49, 0x23, 0x4D, 0xB3, 0x8E, 0xC3, 0x1F,
++   0x7C, 0xEF, 0xE0, 0x99, 0x09, 0xA0, 0x01, 0x7E };
++
++unsigned char table_4[32] = {
++   0x1F, 0x0B, 0x00, 0x1E, 0x03, 0x0E, 0x15, 0x01,
++   0x1A, 0x17, 0x1D, 0x1B, 0x11, 0x0F, 0x0A, 0x12,
++   0x13, 0x18, 0x02, 0x04, 0x09, 0x06, 0x0D, 0x07,
++   0x08, 0x05, 0x10, 0x19, 0x0C, 0x14, 0x16, 0x1C };
++
++unsigned char table_5[256] = {
++   0x9A, 0xAB, 0x61, 0x28, 0x0A, 0x23, 0xFC, 0xBA,
++   0x90, 0x22, 0xB7, 0x62, 0xD9, 0x09, 0x91, 0xF4,
++   0x7B, 0x5D, 0x6B, 0x80, 0xAC, 0x9E, 0x21, 0x72,
++   0x64, 0x2D, 0xFF, 0x66, 0xEB, 0x5B, 0x05, 0xC8,
++   0x1B, 0xD1, 0x55, 0xF5, 0x97, 0x08, 0xAE, 0xC7,
++   0x00, 0xDE, 0xE1, 0x78, 0xD8, 0xB6, 0xF0, 0x17,
++   0xE4, 0x32, 0xCD, 0x76, 0x07, 0x14, 0x7F, 0x7A,
++   0xBF, 0xB4, 0x1D, 0x94, 0x48, 0x75, 0xFA, 0xA7,
++   0x99, 0x7E, 0x65, 0x38, 0x29, 0x51, 0xC3, 0x83,
++   0x7C, 0x0D, 0xA0, 0xCC, 0xF1, 0xDD, 0xE2, 0x49,
++   0xF8, 0xD2, 0x25, 0x54, 0x9B, 0x0E, 0xB9, 0xFE,
++   0x67, 0xC4, 0xCE, 0x13, 0xD4, 0xE7, 0xB8, 0x41,
++   0x77, 0xDB, 0xA6, 0xB0, 0x11, 0x6A, 0x5E, 0x68,
++   0x8D, 0xF9, 0x36, 0xD3, 0xC2, 0x3A, 0xAA, 0x59,
++   0x03, 0xE0, 0xE3, 0xF3, 0x42, 0x2C, 0x04, 0x47,
++   0xE6, 0x93, 0xCB, 0x6E, 0x20, 0xCA, 0x01, 0xA1,
++   0x40, 0x2B, 0x2F, 0x5F, 0x87, 0xD0, 0xEC, 0x88,
++   0x27, 0x58, 0xC6, 0x3E, 0xDF, 0x26, 0x5C, 0xE9,
++   0x1F, 0x0F, 0x95, 0x1C, 0xFB, 0xA5, 0x12, 0x39,
++   0x1E, 0x3C, 0x33, 0x43, 0x56, 0xE8, 0x82, 0xF7,
++   0x7D, 0x89, 0xF2, 0xD7, 0x50, 0x92, 0x60, 0x4C,
++   0x2A, 0x86, 0x16, 0x6C, 0x37, 0xC0, 0xAD, 0xB3,
++   0x24, 0x45, 0xB1, 0xA2, 0x71, 0xA4, 0xA3, 0xED,
++   0xC9, 0x5A, 0x4D, 0x84, 0x0C, 0x3F, 0xC5, 0x9D,
++   0x63, 0x19, 0x79, 0x57, 0x96, 0x30, 0x74, 0xBB,
++   0xDA, 0x1A, 0x9F, 0x44, 0xC1, 0x98, 0xE5, 0x81,
++   0xD6, 0x18, 0x8F, 0xFD, 0x8E, 0x06, 0x6F, 0xF6,
++   0x2E, 0x3B, 0xB5, 0x85, 0x8A, 0x9C, 0x53, 0x4A,
++   0xA9, 0x52, 0x3D, 0x4E, 0xBE, 0xAF, 0xBC, 0xA8,
++   0x4F, 0x6D, 0x15, 0x35, 0x8C, 0xBD, 0x34, 0x8B,
++   0xDC, 0x0B, 0xCF, 0x31, 0xEA, 0xB2, 0x70, 0x4B,
++   0x46, 0x73, 0x69, 0xD5, 0x10, 0xEE, 0x02, 0xEF };
++
++unsigned char table_6[32] = {
++   0x1A, 0x1C, 0x0F, 0x0C, 0x00, 0x02, 0x13, 0x09,
++   0x11, 0x05, 0x0D, 0x12, 0x18, 0x0B, 0x04, 0x10,
++   0x14, 0x1B, 0x1E, 0x16, 0x07, 0x08, 0x03, 0x17,
++   0x19, 0x1F, 0x01, 0x0E, 0x15, 0x06, 0x0A, 0x1D };
++
++unsigned char table_7[256] = {
++   0x52, 0x11, 0x72, 0xD0, 0x76, 0xD7, 0xAE, 0x03,
++   0x7F, 0x19, 0xF4, 0xB8, 0xB3, 0x5D, 0xCA, 0x2D,
++   0x5C, 0x30, 0x53, 0x1A, 0x57, 0xF6, 0xAD, 0x83,
++   0x29, 0x79, 0xD5, 0xF0, 0x0F, 0xC3, 0x8B, 0xD3,
++   0x8E, 0x37, 0x01, 0xA6, 0xF1, 0x10, 0x04, 0x71,
++   0xCC, 0xC6, 0xE7, 0xC2, 0x85, 0x94, 0xBD, 0x6F,
++   0xCB, 0xEA, 0xFC, 0xA1, 0x38, 0x5E, 0x08, 0x2E,
++   0x35, 0x42, 0x67, 0xD4, 0x56, 0x6D, 0x7C, 0xE5,
++   0x0E, 0x7D, 0x12, 0x65, 0xF5, 0x33, 0x82, 0xC4,
++   0x1D, 0xD2, 0x16, 0x58, 0xEC, 0xCD, 0xA8, 0xBF,
++   0xAB, 0x07, 0x45, 0x55, 0xB7, 0x6A, 0x70, 0xF2,
++   0xBE, 0x05, 0x6B, 0x9D, 0xEB, 0x13, 0x0D, 0x9F,
++   0xE8, 0xA7, 0xC8, 0x31, 0x3C, 0xB6, 0x21, 0xC0,
++   0x20, 0x60, 0x6C, 0xE2, 0xCE, 0x8C, 0xFD, 0x95,
++   0xE3, 0x4A, 0xB5, 0xB2, 0x40, 0xB1, 0xF3, 0x17,
++   0xF9, 0x24, 0x06, 0x22, 0x2F, 0x25, 0x93, 0x8A,
++   0x2A, 0x7E, 0x28, 0x3D, 0x47, 0xF8, 0x89, 0xA5,
++   0x7B, 0x9B, 0xC5, 0x84, 0x59, 0x46, 0x90, 0x74,
++   0x69, 0xC7, 0xAA, 0xEE, 0x6E, 0xD6, 0xB0, 0x18,
++   0x66, 0xA0, 0x7A, 0x1E, 0xFB, 0xDB, 0x4E, 0x51,
++   0x92, 0xE4, 0xE0, 0x3E, 0xB4, 0xD8, 0x23, 0x3B,
++   0xC1, 0x5F, 0xFE, 0x98, 0x99, 0x73, 0x09, 0xA9,
++   0xA3, 0xDF, 0x14, 0x5A, 0x26, 0x8F, 0x0B, 0xAF,
++   0x4C, 0x97, 0x54, 0xE1, 0x63, 0x48, 0xED, 0xBA,
++   0xCF, 0xBB, 0x1F, 0xDC, 0xA4, 0xFA, 0x64, 0x75,
++   0xDE, 0x81, 0x9A, 0xFF, 0x49, 0x41, 0x27, 0x62,
++   0x02, 0x15, 0xD9, 0x86, 0xAC, 0x3F, 0x0C, 0x61,
++   0xD1, 0x77, 0x2B, 0x1B, 0x96, 0xDA, 0x68, 0x1C,
++   0x44, 0x32, 0xBC, 0xA2, 0x87, 0xF7, 0x91, 0x8D,
++   0x80, 0xDD, 0x0A, 0x50, 0x34, 0x4B, 0x00, 0xB9,
++   0x36, 0xE6, 0x78, 0x4F, 0xC9, 0xE9, 0x2C, 0x43,
++   0x88, 0x9E, 0x9C, 0x5B, 0x4D, 0x3A, 0x39, 0xEF };
++
++unsigned char table_8[32] = {
++   0x13, 0x08, 0x1E, 0x1D, 0x17, 0x16, 0x07, 0x1F,
++   0x0E, 0x03, 0x1A, 0x19, 0x01, 0x12, 0x11, 0x10,
++   0x09, 0x0C, 0x0F, 0x14, 0x0B, 0x05, 0x00, 0x04,
++   0x1C, 0x18, 0x0A, 0x15, 0x02, 0x1B, 0x06, 0x0D };
++
++unsigned char table_9[256] = {
++   0x20, 0x2A, 0xDA, 0xFE, 0x76, 0x0D, 0xED, 0x39,
++   0x51, 0x4C, 0x46, 0x9A, 0xF1, 0xB0, 0x10, 0xC7,
++   0xD1, 0x6F, 0x18, 0x24, 0xB9, 0x7A, 0x4F, 0x47,
++   0xE0, 0x4E, 0x88, 0x09, 0x8A, 0xBA, 0x60, 0xBD,
++   0xC2, 0x27, 0x93, 0x7D, 0x94, 0x40, 0xCB, 0x80,
++   0xB8, 0x41, 0x84, 0x5D, 0xC1, 0x0F, 0x5E, 0x78,
++   0x2B, 0x48, 0x28, 0x29, 0xEE, 0x81, 0x90, 0x86,
++   0x50, 0x9C, 0xF3, 0xB2, 0x35, 0x52, 0x0C, 0x9D,
++   0xFC, 0x69, 0xD6, 0xA6, 0x06, 0xD7, 0xC6, 0xFF,
++   0x1C, 0x14, 0x57, 0x33, 0xE2, 0x1F, 0x83, 0xA8,
++   0xF7, 0x99, 0xC5, 0xDC, 0x70, 0x9E, 0xF4, 0x6B,
++   0x0A, 0x77, 0x95, 0x4A, 0x2E, 0x53, 0xF2, 0x62,
++   0x98, 0xF8, 0x96, 0xDB, 0xE6, 0x32, 0x3C, 0x58,
++   0xD5, 0x6D, 0xE7, 0x4B, 0xCE, 0x91, 0x43, 0xD8,
++   0xFA, 0xE3, 0x4D, 0xD9, 0x68, 0xDE, 0xEC, 0x01,
++   0x08, 0xD3, 0x8F, 0x19, 0xC4, 0xA7, 0x6E, 0x3E,
++   0x63, 0x12, 0x72, 0x42, 0x9F, 0xB4, 0x04, 0x1B,
++   0x7E, 0x11, 0x17, 0x73, 0xB5, 0x22, 0x56, 0xA1,
++   0x89, 0xDD, 0xF5, 0x3F, 0x49, 0x26, 0x8D, 0x15,
++   0x85, 0x75, 0x5F, 0x65, 0x82, 0xB6, 0xF6, 0xD2,
++   0xA4, 0x55, 0x37, 0xC8, 0xA0, 0xCC, 0x66, 0x5C,
++   0xC9, 0x25, 0x36, 0x67, 0x7C, 0xE1, 0xA3, 0xCF,
++   0xA9, 0x59, 0x2F, 0xFB, 0xBB, 0x07, 0x87, 0xA2,
++   0x44, 0x92, 0x13, 0x00, 0x16, 0x61, 0x38, 0xEB,
++   0xAE, 0xD4, 0x1E, 0x64, 0x6A, 0xE4, 0xCA, 0x1D,
++   0x6C, 0xDF, 0xAB, 0x5B, 0x03, 0x7B, 0x9B, 0x8C,
++   0x5A, 0xFD, 0xC3, 0xB3, 0x0B, 0xAA, 0xAC, 0x8B,
++   0xBE, 0xBC, 0x3D, 0x97, 0xCD, 0x05, 0x21, 0x8E,
++   0xAD, 0xEA, 0x54, 0x30, 0xAF, 0x02, 0xB1, 0x34,
++   0x0E, 0xA5, 0x3B, 0x45, 0x1A, 0x23, 0xE8, 0x7F,
++   0xEF, 0xB7, 0x31, 0xD0, 0xBF, 0x3A, 0x79, 0xE5,
++   0xF9, 0xF0, 0x2C, 0x74, 0xE9, 0x71, 0xC0, 0x2D };
++
++unsigned char table_10[32] = {
++   0x1D, 0x12, 0x11, 0x0D, 0x1E, 0x19, 0x16, 0x1B,
++   0x18, 0x13, 0x07, 0x17, 0x0C, 0x02, 0x00, 0x15,
++   0x0E, 0x08, 0x05, 0x01, 0x10, 0x06, 0x04, 0x0F,
++   0x1F, 0x1A, 0x0B, 0x09, 0x0A, 0x14, 0x1C, 0x03 };
++
++unsigned char table_11[256] = {
++   0x6B, 0x1D, 0xC6, 0x0A, 0xB7, 0xAC, 0xB2, 0x11,
++   0x29, 0xD3, 0xA2, 0x4D, 0xCB, 0x03, 0xEF, 0xA6,
++   0xC1, 0x5D, 0x75, 0x48, 0x35, 0x6C, 0xE2, 0x84,
++   0xAB, 0xAA, 0xD8, 0x2C, 0x0E, 0x95, 0x25, 0x27,
++   0x7D, 0x0B, 0xD0, 0xFB, 0x14, 0xE5, 0xF2, 0x4E,
++   0x7F, 0x2A, 0x63, 0x3C, 0xC9, 0xF6, 0xDC, 0x07,
++   0x26, 0x55, 0xCF, 0x2B, 0xCD, 0xA7, 0x17, 0xD2,
++   0x9A, 0x7B, 0x93, 0x78, 0x9E, 0xE6, 0x2F, 0x49,
++   0x1E, 0xFD, 0xF0, 0xFE, 0x7C, 0x33, 0x92, 0xA3,
++   0xC8, 0xA0, 0xA9, 0xC4, 0xA1, 0x94, 0x6D, 0x44,
++   0x0C, 0x90, 0x3A, 0x8C, 0x8E, 0x85, 0xAF, 0x40,
++   0x36, 0xA4, 0xD1, 0xB9, 0x19, 0x6F, 0xF4, 0xBA,
++   0x1A, 0x73, 0xD9, 0xB5, 0xB4, 0x7A, 0xF9, 0x83,
++   0x58, 0xAD, 0xCE, 0x60, 0x98, 0xDB, 0x1C, 0x1B,
++   0x52, 0xB8, 0xF3, 0x96, 0xED, 0xDE, 0xB3, 0xEE,
++   0x4F, 0xBD, 0x10, 0xD4, 0x43, 0xEA, 0xE7, 0x37,
++   0x12, 0x3D, 0xA8, 0x22, 0x65, 0xEC, 0x5B, 0x08,
++   0x9D, 0x0D, 0x5C, 0xB6, 0x8A, 0x79, 0x3F, 0x04,
++   0xD6, 0x01, 0xE1, 0xBE, 0xDD, 0x50, 0xFA, 0x41,
++   0x13, 0x91, 0xF7, 0xDA, 0x18, 0xB0, 0x45, 0x81,
++   0x4C, 0xF5, 0x32, 0x23, 0x56, 0x5A, 0xEB, 0x97,
++   0x34, 0x00, 0x77, 0x71, 0x4B, 0x70, 0xD5, 0x31,
++   0x72, 0x05, 0xDF, 0xE8, 0x15, 0x3B, 0x54, 0x16,
++   0x89, 0xE4, 0xF1, 0xD7, 0x80, 0x82, 0x4A, 0xE3,
++   0x39, 0x06, 0x47, 0x28, 0xC2, 0x86, 0x87, 0xB1,
++   0x62, 0x74, 0x53, 0x21, 0x67, 0x38, 0x42, 0xCA,
++   0x9B, 0xC3, 0x51, 0x99, 0x8B, 0x1F, 0x24, 0x8D,
++   0xF8, 0x68, 0x3E, 0x59, 0xBB, 0x61, 0x5F, 0xBC,
++   0x09, 0x6E, 0x8F, 0x0F, 0x2D, 0xC0, 0xE0, 0x46,
++   0x66, 0x69, 0xA5, 0xE9, 0x30, 0x9C, 0x5E, 0xAE,
++   0xBF, 0xC7, 0x20, 0x7E, 0x6A, 0xC5, 0x88, 0xFC,
++   0x64, 0x76, 0xFF, 0x9F, 0x2E, 0x02, 0xCC, 0x57 };
++
++unsigned char table_12[32] = {
++   0x14, 0x1B, 0x18, 0x00, 0x1F, 0x15, 0x17, 0x07,
++   0x11, 0x1A, 0x0E, 0x13, 0x12, 0x06, 0x01, 0x03,
++   0x1C, 0x0C, 0x0B, 0x1D, 0x10, 0x0F, 0x09, 0x19,
++   0x0D, 0x1E, 0x04, 0x05, 0x08, 0x16, 0x0A, 0x02 };
++
++unsigned char table_13[256] = {
++   0x37, 0x8A, 0x1B, 0x91, 0xA5, 0x2B, 0x2D, 0x88,
++   0x8E, 0xFE, 0x0E, 0xD3, 0xF3, 0xE9, 0x7D, 0xD1,
++   0x24, 0xEA, 0xB1, 0x8B, 0x5C, 0xA4, 0x44, 0x7E,
++   0x8C, 0x2C, 0x73, 0xD5, 0x50, 0x3E, 0xD7, 0x18,
++   0xB9, 0xD6, 0xBA, 0x94, 0x0C, 0xFC, 0xCB, 0xB4,
++   0x0D, 0x63, 0x4C, 0xDE, 0x77, 0x16, 0xFD, 0x81,
++   0x3C, 0x11, 0x45, 0x36, 0xF6, 0x67, 0x95, 0x6D,
++   0x6A, 0x1A, 0xA3, 0xC5, 0x92, 0x10, 0x28, 0x84,
++   0x48, 0xA6, 0x23, 0xE3, 0x4B, 0xE1, 0xF5, 0x19,
++   0xE0, 0x2E, 0x00, 0x61, 0x74, 0xCC, 0xF7, 0xB0,
++   0x68, 0xC8, 0x40, 0x6F, 0x59, 0x52, 0x26, 0x99,
++   0xC9, 0xF9, 0xC4, 0x53, 0x9B, 0xEC, 0x03, 0x17,
++   0xE2, 0x06, 0x30, 0x7B, 0xBE, 0xCD, 0x1D, 0x3B,
++   0xD2, 0x5B, 0x65, 0x21, 0x49, 0xB7, 0x79, 0xCF,
++   0x82, 0x86, 0xC7, 0x62, 0xEE, 0x8D, 0xFF, 0xD4,
++   0xC3, 0x85, 0xA7, 0xFA, 0xA9, 0x6B, 0xF2, 0x69,
++   0x9C, 0x38, 0x78, 0xBD, 0x7F, 0xDD, 0xCE, 0xA1,
++   0x33, 0xC2, 0x43, 0xEB, 0xD8, 0xE6, 0x2A, 0xE4,
++   0x76, 0x6C, 0xAA, 0x46, 0x05, 0xE7, 0xA0, 0x0A,
++   0x71, 0x98, 0x41, 0x5F, 0x0F, 0xEF, 0x51, 0xAD,
++   0xF0, 0xED, 0x96, 0x5A, 0x42, 0x3F, 0xBF, 0x6E,
++   0xBC, 0x5D, 0xC1, 0x15, 0x70, 0x54, 0x4D, 0x14,
++   0xB5, 0xCA, 0x27, 0x80, 0x87, 0x39, 0x60, 0x47,
++   0x9D, 0x2F, 0x56, 0x1F, 0xBB, 0x31, 0xF1, 0xE8,
++   0xB3, 0x9E, 0x5E, 0x7C, 0xD0, 0xC6, 0xB2, 0x57,
++   0x83, 0xAC, 0x09, 0x8F, 0xA2, 0x90, 0x13, 0x25,
++   0x01, 0x08, 0x64, 0xB6, 0x02, 0xDB, 0x55, 0x32,
++   0xAF, 0x9A, 0xC0, 0x1C, 0x12, 0x29, 0x0B, 0x72,
++   0x4F, 0xDA, 0xAB, 0x35, 0xF8, 0x22, 0xD9, 0x4E,
++   0x3D, 0x1E, 0xDC, 0x58, 0x20, 0x34, 0xAE, 0x66,
++   0x75, 0x93, 0x9F, 0x3A, 0x07, 0xE5, 0x89, 0xDF,
++   0x97, 0x4A, 0xB8, 0x7A, 0xF4, 0xFB, 0x04, 0xA8 };
++
++unsigned char table_14[32] = {
++   0x04, 0x14, 0x13, 0x15, 0x1A, 0x1B, 0x0F, 0x16,
++   0x02, 0x0D, 0x0C, 0x06, 0x10, 0x17, 0x01, 0x0B,
++   0x1E, 0x08, 0x1C, 0x18, 0x19, 0x0A, 0x1F, 0x05,
++   0x11, 0x09, 0x1D, 0x07, 0x0E, 0x12, 0x03, 0x00 };
++
++unsigned char table_15[256] = {
++   0x61, 0x48, 0x58, 0x41, 0x7F, 0x88, 0x43, 0x42,
++   0xD9, 0x80, 0x81, 0xFE, 0xC6, 0x49, 0xD7, 0x2C,
++   0xE6, 0x5B, 0xEE, 0xFF, 0x2A, 0x6F, 0xBF, 0x98,
++   0xD6, 0x20, 0xB9, 0xB1, 0x5D, 0x95, 0x72, 0x1E,
++   0x82, 0x96, 0xDE, 0xC1, 0x40, 0xD8, 0x70, 0xA3,
++   0xD1, 0x1F, 0xF0, 0x9F, 0x2D, 0xDC, 0x3F, 0xF9,
++   0x5E, 0x0D, 0x15, 0x2F, 0x67, 0x31, 0x9D, 0x84,
++   0x97, 0x0C, 0xF6, 0x79, 0xC2, 0xA7, 0xC0, 0x32,
++   0xB3, 0xEB, 0xED, 0x71, 0x30, 0xCC, 0x4B, 0xA0,
++   0xF5, 0xC4, 0xCD, 0x27, 0xFA, 0x11, 0x25, 0xDB,
++   0x4F, 0xE2, 0x7E, 0xA6, 0xAF, 0x34, 0x69, 0x63,
++   0x8F, 0x08, 0x1C, 0x85, 0xF1, 0x57, 0x78, 0xC8,
++   0xA2, 0x83, 0xB5, 0x68, 0xF7, 0x64, 0x45, 0x26,
++   0x3B, 0x03, 0xAD, 0x3C, 0x50, 0xD5, 0x77, 0xFC,
++   0xFB, 0x18, 0xC9, 0xD2, 0x9C, 0xBB, 0xBA, 0x76,
++   0x23, 0x55, 0xD3, 0x5A, 0x01, 0xE9, 0x87, 0x07,
++   0x19, 0x09, 0x39, 0x8A, 0x91, 0x93, 0x12, 0xDF,
++   0x22, 0xA8, 0xCF, 0x4E, 0x4D, 0x65, 0xB0, 0x0F,
++   0x13, 0x53, 0x21, 0x8C, 0xE5, 0xB7, 0x0B, 0x0E,
++   0x6C, 0x44, 0xCA, 0x7B, 0xC5, 0x6E, 0xCE, 0xE3,
++   0x14, 0x29, 0xAC, 0x2E, 0xE7, 0x59, 0xE8, 0x0A,
++   0xEA, 0x66, 0x7C, 0x94, 0x6D, 0x05, 0x9E, 0x9A,
++   0x2B, 0x38, 0x6A, 0xCB, 0x51, 0xEF, 0x06, 0xDA,
++   0xFD, 0x47, 0x92, 0x1D, 0xA5, 0x37, 0x33, 0xEC,
++   0xB4, 0x52, 0x56, 0xC3, 0xF4, 0xF8, 0x8B, 0xD0,
++   0xA4, 0x5F, 0x28, 0x89, 0x75, 0xC7, 0x04, 0x00,
++   0xE4, 0x86, 0x36, 0x3A, 0x99, 0x16, 0x7D, 0xE0,
++   0x7A, 0x4C, 0x54, 0x46, 0x73, 0xB2, 0xF3, 0xE1,
++   0x62, 0xBE, 0x90, 0x4A, 0x24, 0x6B, 0x3E, 0xAA,
++   0x1B, 0xF2, 0x60, 0xD4, 0xA9, 0x9B, 0x1A, 0xB8,
++   0xA1, 0x35, 0xAE, 0xB6, 0x10, 0x5C, 0x17, 0xBC,
++   0xAB, 0x8D, 0x02, 0x74, 0xBD, 0x3D, 0x8E, 0xDD };
++
++unsigned char table_16[256] = {
++   0x3F, 0x9C, 0x17, 0xC1, 0x59, 0xC6, 0x23, 0x93,
++   0x4B, 0xDF, 0xCB, 0x55, 0x2B, 0xDE, 0xCD, 0xAD,
++   0xB3, 0xE7, 0x42, 0x2F, 0x02, 0x5A, 0x7B, 0x5C,
++   0x8F, 0xD1, 0x11, 0xCE, 0xEC, 0xF6, 0xA4, 0xE6,
++   0x58, 0x98, 0x6A, 0x99, 0xFB, 0x9B, 0x53, 0x21,
++   0x8A, 0x09, 0x2E, 0x3C, 0x22, 0x38, 0xAC, 0x07,
++   0x91, 0x46, 0xA9, 0x95, 0xC3, 0x14, 0x84, 0xDB,
++   0x36, 0x68, 0x1D, 0xDD, 0xF9, 0x12, 0xE0, 0x3D,
++   0x8D, 0x4D, 0x05, 0x86, 0x69, 0xC0, 0xD3, 0xD5,
++   0xA5, 0xC9, 0xE5, 0x67, 0x6D, 0xE2, 0x7F, 0xFE,
++   0xB2, 0x0F, 0x62, 0xCF, 0x37, 0x35, 0xF3, 0x28,
++   0x16, 0xA6, 0x50, 0x76, 0x80, 0x00, 0x31, 0x97,
++   0x39, 0x7C, 0x25, 0x0C, 0x64, 0xF2, 0x52, 0x1A,
++   0x92, 0x4F, 0x2A, 0x56, 0x03, 0x4C, 0xBD, 0x10,
++   0xB7, 0x2C, 0x8C, 0xAE, 0x73, 0xB9, 0xE9, 0xF7,
++   0xA7, 0xE1, 0x75, 0xBC, 0xC5, 0x1C, 0x3A, 0x63,
++   0x7A, 0x4A, 0x29, 0xD2, 0x71, 0xE8, 0x08, 0xA1,
++   0xD4, 0xFD, 0x13, 0xFA, 0xA0, 0x27, 0x41, 0x72,
++   0x82, 0x18, 0x51, 0x60, 0x5E, 0x66, 0x0D, 0xAA,
++   0xD8, 0x1F, 0xAF, 0x45, 0xD0, 0xF1, 0x9F, 0x6B,
++   0xE4, 0x44, 0x89, 0xEE, 0xC4, 0x0B, 0x6C, 0xCC,
++   0x83, 0x77, 0xA2, 0x87, 0x0A, 0xA8, 0xED, 0x90,
++   0x74, 0x6E, 0xF5, 0xAB, 0xA3, 0xB6, 0x5F, 0x0E,
++   0x04, 0x9A, 0xB4, 0x8E, 0xF0, 0xFF, 0x88, 0xB5,
++   0xF8, 0xBF, 0x8B, 0x6F, 0x4E, 0x79, 0x40, 0xCA,
++   0x24, 0x26, 0xDC, 0x33, 0xEB, 0x2D, 0x5B, 0x1B,
++   0x9D, 0xC7, 0x49, 0x48, 0x54, 0x85, 0xEF, 0xD7,
++   0xC2, 0xB8, 0xC8, 0x5D, 0xD9, 0x3B, 0x15, 0xBB,
++   0x65, 0xE3, 0xD6, 0x30, 0x3E, 0x1E, 0x32, 0x9E,
++   0x57, 0x81, 0x34, 0x06, 0xFC, 0xBA, 0x7D, 0x20,
++   0x70, 0xDA, 0x7E, 0x47, 0x94, 0x61, 0xB0, 0x78,
++   0xF4, 0xBE, 0xEA, 0x19, 0x43, 0x01, 0xB1, 0x96 };
++
++unsigned char table_17[256] = {
++   0x7E, 0xF1, 0xD3, 0x75, 0x87, 0xA6, 0xED, 0x9E,
++   0xA9, 0xD5, 0xC6, 0xBF, 0xE6, 0x6A, 0xEE, 0x4B,
++   0x34, 0xDF, 0x4C, 0x7D, 0xDD, 0xFE, 0x3F, 0xAF,
++   0x66, 0x2D, 0x74, 0x6F, 0xFC, 0x4F, 0x5F, 0x88,
++   0x29, 0x7B, 0xC7, 0x2A, 0x70, 0xE8, 0x1D, 0xDE,
++   0xD0, 0x55, 0x71, 0x81, 0xC4, 0x0D, 0x50, 0x4E,
++   0x58, 0x00, 0x96, 0x97, 0xBB, 0xD7, 0x53, 0x15,
++   0x6C, 0x40, 0x17, 0xC9, 0xFF, 0x8F, 0x94, 0xFB,
++   0x19, 0x9A, 0x3E, 0xB5, 0x5A, 0x5E, 0x86, 0x24,
++   0xB8, 0x77, 0xBA, 0x85, 0x51, 0x18, 0xBE, 0x59,
++   0x79, 0xF3, 0xD4, 0xC3, 0xAB, 0x28, 0xFD, 0x25,
++   0x41, 0x91, 0x07, 0x8D, 0xAE, 0x49, 0xF5, 0x80,
++   0x35, 0xA1, 0x9C, 0x3C, 0xE2, 0x65, 0xB3, 0xE0,
++   0x16, 0xCB, 0x12, 0x6B, 0xF7, 0xB1, 0x93, 0x8A,
++   0xCE, 0x54, 0x4D, 0xF8, 0x13, 0xA2, 0x95, 0x46,
++   0xEA, 0x61, 0x57, 0x9D, 0x27, 0x8B, 0x3D, 0x60,
++   0x36, 0x68, 0x06, 0x56, 0xB6, 0x1B, 0xD2, 0x89,
++   0x10, 0xA7, 0xC5, 0x1A, 0x0B, 0x2C, 0xBD, 0x14,
++   0x0A, 0xDC, 0x23, 0xA8, 0xE1, 0x04, 0x02, 0xC0,
++   0xB2, 0x9B, 0xE3, 0x2E, 0x33, 0x7C, 0x32, 0xAC,
++   0x7A, 0x39, 0xB0, 0xF9, 0x98, 0x5B, 0x3A, 0x48,
++   0x21, 0x90, 0xB9, 0x20, 0xF0, 0xA0, 0x09, 0x1F,
++   0x2F, 0xEF, 0xEB, 0x22, 0x78, 0x82, 0x37, 0xD6,
++   0xD1, 0x84, 0x76, 0x01, 0xDB, 0x43, 0xC2, 0xB7,
++   0x7F, 0xA4, 0xE5, 0xC1, 0x1C, 0x69, 0x05, 0xEC,
++   0xD8, 0x38, 0x67, 0x42, 0x72, 0xBC, 0x73, 0xAD,
++   0xA3, 0xE9, 0x4A, 0x8E, 0x47, 0x1E, 0xC8, 0x6E,
++   0xDA, 0x5D, 0x2B, 0xF6, 0x30, 0x63, 0xCC, 0xF4,
++   0xCD, 0x8C, 0x0F, 0x3B, 0xE7, 0xD9, 0xCF, 0xB4,
++   0x03, 0x92, 0x0E, 0x31, 0xE4, 0x08, 0xF2, 0x45,
++   0xCA, 0x83, 0x26, 0x5C, 0xA5, 0x44, 0x64, 0x6D,
++   0x9F, 0x99, 0x62, 0xAA, 0xFA, 0x11, 0x0C, 0x52 };
++
++unsigned char table_18[256] = {
++   0x0F, 0x42, 0x3D, 0x86, 0x3E, 0x66, 0xFE, 0x5C,
++   0x52, 0xE2, 0xA3, 0xB3, 0xCE, 0x16, 0xCC, 0x95,
++   0xB0, 0x8B, 0x82, 0x3B, 0x93, 0x7D, 0x62, 0x08,
++   0x1C, 0x6E, 0xBB, 0xCB, 0x1D, 0x88, 0x69, 0xD4,
++   0xC9, 0x40, 0x1F, 0xBE, 0x27, 0xBC, 0xDB, 0x38,
++   0xE5, 0xA1, 0x71, 0xBA, 0x8A, 0x5E, 0xFD, 0x36,
++   0x8F, 0x26, 0x6B, 0xE4, 0x20, 0x6D, 0xC5, 0xDE,
++   0xE0, 0x83, 0x7C, 0xD5, 0xD9, 0x4D, 0xDC, 0xE3,
++   0x0D, 0x32, 0xED, 0x0E, 0x2F, 0x21, 0xA7, 0x79,
++   0xA0, 0xD3, 0x8C, 0x14, 0x6F, 0xB7, 0xF8, 0x85,
++   0x5D, 0x37, 0x24, 0xD6, 0x25, 0xD2, 0x8E, 0xA5,
++   0xB8, 0xCD, 0x5A, 0x9F, 0x05, 0xAD, 0x65, 0x9E,
++   0x4F, 0x5B, 0x56, 0xF0, 0xAA, 0xC2, 0x28, 0xA8,
++   0x6A, 0x01, 0x99, 0x2E, 0xA6, 0x77, 0x74, 0x64,
++   0x76, 0x15, 0x90, 0x75, 0xAF, 0xE8, 0x39, 0x48,
++   0x09, 0x11, 0xE1, 0x2D, 0xEC, 0xB5, 0x7A, 0xB1,
++   0x94, 0x13, 0x41, 0x4C, 0x02, 0xA9, 0x97, 0xDF,
++   0xC3, 0x8D, 0xEA, 0x3A, 0x9C, 0xD1, 0xA2, 0x9A,
++   0xD7, 0x59, 0xD8, 0x18, 0xDA, 0x47, 0x89, 0x81,
++   0xC7, 0xF5, 0xFC, 0x98, 0xCA, 0x91, 0x06, 0x68,
++   0xC8, 0x07, 0x4A, 0x84, 0x0A, 0xE7, 0x33, 0x2C,
++   0xEB, 0xDD, 0x5F, 0xAC, 0x23, 0x1A, 0x35, 0x70,
++   0x43, 0x80, 0x61, 0xAE, 0xC1, 0xD0, 0x7B, 0x92,
++   0x49, 0x51, 0x53, 0xC4, 0x34, 0x30, 0x0C, 0x4B,
++   0x00, 0x04, 0x10, 0xFF, 0x63, 0x44, 0xB4, 0x0B,
++   0x57, 0x72, 0xF1, 0x9D, 0x19, 0xF6, 0xB2, 0x87,
++   0x1B, 0xEE, 0x46, 0x2A, 0xF3, 0xBF, 0x12, 0x96,
++   0x58, 0x2B, 0xF9, 0xB6, 0xCF, 0x22, 0x3C, 0xAB,
++   0x1E, 0x6C, 0x31, 0xC6, 0xF7, 0x78, 0x45, 0x17,
++   0xE9, 0x7E, 0x73, 0xF2, 0x55, 0xFB, 0x3F, 0x9B,
++   0xF4, 0xBD, 0xA4, 0x29, 0x60, 0x03, 0xB9, 0x50,
++   0xFA, 0x4E, 0xEF, 0x54, 0xE6, 0x7F, 0xC0, 0x67 };
++
++unsigned char table_19[256] = {
++   0xEA, 0xE7, 0x13, 0x14, 0xB9, 0xC0, 0xC4, 0x42,
++   0x49, 0x6E, 0x2A, 0xA6, 0x65, 0x3C, 0x6A, 0x40,
++   0x07, 0xCD, 0x4F, 0xFE, 0xF2, 0x2D, 0xC8, 0x30,
++   0x9D, 0xBE, 0x1B, 0x9B, 0x4A, 0x7E, 0x9F, 0xA7,
++   0x78, 0xAB, 0x4D, 0x1D, 0xF1, 0x96, 0x32, 0x84,
++   0xFB, 0x80, 0x88, 0xE8, 0x41, 0x97, 0xDC, 0xD0,
++   0x4E, 0x33, 0xA4, 0x3B, 0xE0, 0xDD, 0x36, 0xC9,
++   0x72, 0x48, 0x8A, 0x2F, 0x35, 0xF0, 0xDF, 0x21,
++   0xE1, 0xE5, 0x6C, 0x9A, 0x60, 0x8F, 0xB7, 0x24,
++   0xE4, 0x9E, 0x8C, 0x0F, 0x3D, 0x28, 0xBB, 0xD6,
++   0x69, 0xA0, 0x66, 0xC7, 0xE3, 0xD8, 0x11, 0x27,
++   0xD9, 0x37, 0xF4, 0xF5, 0x8E, 0xD4, 0x76, 0xE2,
++   0xDB, 0x15, 0xA2, 0x5C, 0x9C, 0xEE, 0x44, 0xED,
++   0x2B, 0xB3, 0x75, 0x74, 0x71, 0x8B, 0x3A, 0x91,
++   0x06, 0x19, 0xC1, 0x57, 0x89, 0xCC, 0x82, 0x10,
++   0x17, 0xB2, 0x08, 0x70, 0x39, 0xCA, 0xBA, 0xB5,
++   0xAA, 0xBF, 0x02, 0xBD, 0x26, 0x58, 0x04, 0x54,
++   0x23, 0x4B, 0x90, 0x51, 0x6D, 0x98, 0xD5, 0xB0,
++   0xAF, 0x22, 0xDA, 0xB4, 0x87, 0xFC, 0x7D, 0x18,
++   0x6F, 0x64, 0x59, 0x09, 0x0C, 0xA5, 0x5D, 0x03,
++   0x0A, 0xD3, 0xCE, 0x99, 0x8D, 0xC2, 0xC3, 0x62,
++   0xD2, 0x83, 0x1A, 0xAC, 0x7C, 0x93, 0xD7, 0xA9,
++   0x16, 0xF7, 0x77, 0xE6, 0x3E, 0x05, 0x73, 0x55,
++   0x43, 0x95, 0x7A, 0x6B, 0x38, 0x67, 0x3F, 0xC6,
++   0xAD, 0x0E, 0x29, 0x46, 0x45, 0xFA, 0xBC, 0xEC,
++   0x5B, 0x7F, 0x0B, 0x1C, 0x01, 0x12, 0x85, 0x50,
++   0xF9, 0xEF, 0x25, 0x34, 0x79, 0x2E, 0xEB, 0x00,
++   0x5F, 0x86, 0xF8, 0x4C, 0xA8, 0x56, 0xB6, 0x5A,
++   0xF3, 0x31, 0x94, 0x92, 0xB1, 0xB8, 0x52, 0xD1,
++   0xCF, 0xCB, 0xA1, 0x81, 0x68, 0x47, 0xFF, 0xC5,
++   0xFD, 0x1F, 0xDE, 0x53, 0xA3, 0x2C, 0x20, 0xF6,
++   0x1E, 0x0D, 0xAE, 0x7B, 0x5E, 0x61, 0xE9, 0x63 };
++
++unsigned char table_20[32] = {
++   0x0D, 0x0B, 0x11, 0x02, 0x05, 0x1B, 0x08, 0x1D,
++   0x04, 0x14, 0x01, 0x09, 0x00, 0x19, 0x1E, 0x15,
++   0x1F, 0x0A, 0x0F, 0x1C, 0x10, 0x16, 0x0C, 0x07,
++   0x13, 0x1A, 0x06, 0x17, 0x0E, 0x12, 0x18, 0x03 };
++
++unsigned char table_21[256] = {
++   0x4C, 0x94, 0xAD, 0x66, 0x9E, 0x69, 0x04, 0xA8,
++   0x61, 0xE0, 0xE1, 0x3D, 0xFD, 0x9C, 0xFB, 0x19,
++   0x1E, 0x80, 0x8C, 0xA0, 0xFC, 0x27, 0x26, 0x3B,
++   0x48, 0x6D, 0x07, 0xE4, 0xEA, 0x17, 0x64, 0x9B,
++   0xD0, 0xE2, 0xD1, 0x13, 0x39, 0xF5, 0x73, 0xD3,
++   0x0C, 0x3A, 0x6E, 0x77, 0xFA, 0xE3, 0x2F, 0x44,
++   0x7E, 0x72, 0x30, 0x43, 0xD4, 0x7F, 0x36, 0xD9,
++   0xBD, 0x3E, 0x3F, 0x91, 0xBE, 0x54, 0x79, 0xA6,
++   0x7C, 0x0E, 0xC5, 0x7A, 0x70, 0xC4, 0xD7, 0xCE,
++   0xDA, 0xAA, 0x68, 0x8F, 0xBC, 0x96, 0x1B, 0x16,
++   0xA2, 0xC6, 0x67, 0x09, 0x45, 0x9F, 0xCF, 0x41,
++   0xC8, 0x60, 0x74, 0x99, 0x5D, 0x85, 0x5F, 0x50,
++   0x33, 0x52, 0x22, 0xA9, 0xB5, 0x2D, 0x98, 0x87,
++   0x15, 0x9A, 0xAC, 0x2C, 0xDE, 0xC0, 0xB8, 0x37,
++   0x88, 0x1F, 0xC1, 0x4F, 0x65, 0x0F, 0x3C, 0x84,
++   0x4B, 0x1A, 0xAB, 0xA4, 0x23, 0xCB, 0xB1, 0xC7,
++   0xDB, 0xEF, 0x40, 0x0D, 0x46, 0xE8, 0xF4, 0x71,
++   0x38, 0x01, 0x5C, 0x0B, 0x5E, 0xC9, 0xAF, 0xC3,
++   0xF6, 0xB6, 0x10, 0x1D, 0xE5, 0x8A, 0x90, 0xA7,
++   0xA3, 0x05, 0x4E, 0x14, 0x63, 0x25, 0x34, 0xEC,
++   0x6B, 0x95, 0x21, 0x55, 0xF2, 0xF0, 0x47, 0x9D,
++   0xF8, 0x8E, 0x02, 0x0A, 0xED, 0x97, 0xAE, 0x00,
++   0x2A, 0xEB, 0xB2, 0xA5, 0x32, 0x06, 0x2E, 0xFE,
++   0x8D, 0x7B, 0x7D, 0x35, 0x5A, 0xD2, 0xF1, 0xE9,
++   0xF9, 0x62, 0xB7, 0xB9, 0x53, 0x75, 0x5B, 0x8B,
++   0xCC, 0x6C, 0x18, 0x49, 0x89, 0x31, 0xB0, 0x92,
++   0x6F, 0xDF, 0x03, 0x57, 0xF3, 0x58, 0xCA, 0x2B,
++   0x93, 0xA1, 0xD6, 0x24, 0x29, 0xCD, 0x59, 0x1C,
++   0x83, 0xB3, 0x42, 0xBF, 0x82, 0xB4, 0x11, 0x4A,
++   0x08, 0xEE, 0x76, 0x4D, 0x12, 0xDC, 0xE6, 0xC2,
++   0x56, 0xBA, 0x86, 0x28, 0x6A, 0x20, 0x51, 0xF7,
++   0xFF, 0xD8, 0xE7, 0xDD, 0xBB, 0x78, 0xD5, 0x81 };
++
++unsigned char table_22[32] = {
++   0x0B, 0x15, 0x1C, 0x0C, 0x06, 0x0A, 0x1D, 0x16,
++   0x12, 0x0E, 0x04, 0x11, 0x1F, 0x0F, 0x07, 0x02,
++   0x17, 0x13, 0x19, 0x18, 0x0D, 0x10, 0x1A, 0x05,
++   0x03, 0x00, 0x01, 0x08, 0x09, 0x14, 0x1B, 0x1E };
++
++unsigned char table_23[256] = {
++   0x36, 0x53, 0x2D, 0xD0, 0x7A, 0xF0, 0xD5, 0x1C,
++   0x50, 0x61, 0x9A, 0x90, 0x0B, 0x29, 0x20, 0x77,
++   0xF1, 0x82, 0xFE, 0xC1, 0xA7, 0xB6, 0x78, 0x87,
++   0x02, 0x05, 0xCB, 0x28, 0xAE, 0xD6, 0x17, 0x1A,
++   0x91, 0x5D, 0xB9, 0xE2, 0xDE, 0x6A, 0x4E, 0x07,
++   0xAC, 0x38, 0x13, 0x3B, 0x46, 0xFD, 0xB7, 0xD1,
++   0x79, 0xFB, 0x58, 0x76, 0x08, 0x47, 0x95, 0xA6,
++   0x99, 0x9E, 0x12, 0x67, 0xC2, 0xED, 0x9C, 0x1B,
++   0x89, 0x71, 0xB5, 0x4A, 0xAA, 0x5F, 0x34, 0x85,
++   0x40, 0x2B, 0x9F, 0x37, 0x7C, 0x0F, 0xD4, 0x75,
++   0x48, 0x27, 0x2E, 0xC9, 0xEB, 0x06, 0xDF, 0x8C,
++   0x14, 0xAF, 0xEE, 0xA2, 0x74, 0x45, 0x8D, 0x70,
++   0x6B, 0xD7, 0x56, 0xCF, 0xBC, 0x7B, 0x01, 0xC8,
++   0x54, 0xB0, 0x3C, 0x39, 0xFA, 0x81, 0xDC, 0xBB,
++   0x0D, 0xB2, 0xAD, 0x93, 0xC7, 0x8A, 0x73, 0x6C,
++   0xC3, 0x04, 0x2F, 0xEF, 0x52, 0x33, 0x9D, 0x1E,
++   0xC5, 0x65, 0x23, 0xD8, 0xB1, 0xD2, 0xE5, 0x25,
++   0x2C, 0xE6, 0x92, 0xB4, 0xF7, 0xF4, 0x8F, 0x6E,
++   0xE8, 0x5A, 0x8E, 0x7D, 0x4C, 0xB3, 0xFF, 0x41,
++   0x26, 0xE3, 0x30, 0x69, 0xF8, 0x80, 0x57, 0x4F,
++   0xA0, 0x7F, 0x66, 0x68, 0xE1, 0x7E, 0x0E, 0x31,
++   0xE7, 0xEA, 0x3E, 0x8B, 0x4B, 0x94, 0xE9, 0xCD,
++   0x19, 0x35, 0xA3, 0x98, 0xD9, 0x5B, 0x44, 0x2A,
++   0xE0, 0x6D, 0xF3, 0xE4, 0x72, 0x18, 0x03, 0x59,
++   0x84, 0x09, 0xA1, 0x9B, 0xBD, 0xDA, 0x4D, 0x63,
++   0xCC, 0x3A, 0x10, 0xFC, 0x3F, 0x0A, 0x88, 0x24,
++   0xF5, 0x21, 0xC4, 0x6F, 0x1F, 0x42, 0x62, 0x64,
++   0x51, 0xDD, 0xCA, 0xF9, 0x22, 0xCE, 0xA8, 0x86,
++   0xBA, 0xB8, 0x5C, 0xAB, 0x32, 0x00, 0x0C, 0xF2,
++   0x83, 0xDB, 0xF6, 0x60, 0x3D, 0x16, 0xEC, 0x11,
++   0xA4, 0xBE, 0x96, 0x5E, 0x97, 0xD3, 0xA5, 0x55,
++   0x1D, 0x15, 0xC6, 0xBF, 0xA9, 0x43, 0xC0, 0x49 };
++
++unsigned char table_24[256] = {
++   0xDC, 0x5A, 0xE6, 0x59, 0x64, 0xDA, 0x58, 0x40,
++   0x95, 0xF8, 0x2A, 0xE0, 0x39, 0x7E, 0x32, 0x89,
++   0x09, 0x93, 0xED, 0x55, 0xC3, 0x5B, 0x1A, 0xD1,
++   0xA5, 0x8B, 0x0F, 0x13, 0xC9, 0xE1, 0x34, 0xD0,
++   0xB6, 0xA2, 0xD9, 0x52, 0x57, 0x83, 0xFD, 0xE9,
++   0xAC, 0x73, 0x6E, 0x21, 0xF1, 0x0E, 0x25, 0xCC,
++   0x36, 0xFB, 0xF7, 0x92, 0x15, 0x30, 0x54, 0x91,
++   0xD6, 0x9E, 0xAA, 0x35, 0x70, 0xB2, 0xC0, 0x27,
++   0xFE, 0x04, 0xBC, 0xC7, 0x02, 0xFA, 0x7D, 0xE3,
++   0xBE, 0x62, 0x79, 0x2B, 0x31, 0x6A, 0x8F, 0x7F,
++   0x56, 0xF0, 0xB4, 0x0C, 0x1F, 0x68, 0xB7, 0xB9,
++   0x0B, 0x14, 0x3E, 0xA9, 0x4B, 0x03, 0x10, 0xEE,
++   0x2C, 0xAB, 0x8A, 0x77, 0xB1, 0xE7, 0xCA, 0xD4,
++   0x98, 0x01, 0xAD, 0x1E, 0x50, 0x26, 0x82, 0x44,
++   0xF3, 0xBF, 0xD3, 0x6B, 0x33, 0x0A, 0x3C, 0x5D,
++   0xCE, 0x81, 0xC5, 0x78, 0x9F, 0xB8, 0x23, 0xDB,
++   0x4E, 0xA1, 0x41, 0x76, 0xAE, 0x51, 0x86, 0x06,
++   0x7A, 0x66, 0xA0, 0x5E, 0x29, 0x17, 0x84, 0x4A,
++   0xB0, 0x3B, 0x3D, 0x71, 0x07, 0x7B, 0x0D, 0x9A,
++   0x6F, 0x9B, 0x5C, 0x88, 0xB3, 0xD7, 0x24, 0xD5,
++   0x48, 0xF5, 0xE8, 0xE4, 0xCF, 0x16, 0xA4, 0xC8,
++   0xEF, 0x42, 0x22, 0xEC, 0x47, 0x69, 0x90, 0x63,
++   0xE2, 0x1B, 0x87, 0x85, 0x3F, 0xDE, 0x8C, 0x60,
++   0x99, 0xE5, 0x8E, 0x4F, 0xF4, 0xBA, 0xB5, 0x9C,
++   0x37, 0x67, 0xBD, 0xA6, 0x97, 0xDD, 0xCB, 0x43,
++   0x45, 0x19, 0x49, 0x1C, 0x75, 0xC1, 0xBB, 0xF2,
++   0x46, 0xFC, 0x53, 0x9D, 0xD8, 0xA3, 0xDF, 0x2F,
++   0xEB, 0x72, 0x94, 0xA8, 0x6D, 0xC6, 0x28, 0x4C,
++   0x00, 0x38, 0xC2, 0x65, 0x05, 0x2E, 0xD2, 0x12,
++   0xFF, 0x18, 0x61, 0x6C, 0x7C, 0x11, 0xAF, 0x96,
++   0xCD, 0x20, 0x74, 0x08, 0x1D, 0xC4, 0xF9, 0x4D,
++   0xEA, 0x8D, 0x2D, 0x5F, 0xF6, 0xA7, 0x80, 0x3A };
++
++unsigned char table_25[32] = {
++   0x0A, 0x11, 0x17, 0x03, 0x05, 0x0B, 0x18, 0x13,
++   0x09, 0x02, 0x00, 0x1C, 0x0C, 0x08, 0x1B, 0x14,
++   0x06, 0x0E, 0x01, 0x0D, 0x16, 0x1E, 0x1D, 0x19,
++   0x0F, 0x1A, 0x10, 0x04, 0x12, 0x15, 0x07, 0x1F };
++
++unsigned char table_26[32] = {
++   0x19, 0x13, 0x1B, 0x01, 0x1C, 0x0D, 0x0C, 0x15,
++   0x0B, 0x00, 0x1A, 0x0F, 0x12, 0x16, 0x08, 0x0A,
++   0x03, 0x06, 0x14, 0x10, 0x18, 0x04, 0x11, 0x1D,
++   0x1F, 0x07, 0x17, 0x05, 0x02, 0x0E, 0x1E, 0x09 };
++
++unsigned char table_27[256] = {
++   0x72, 0xF0, 0x14, 0xCB, 0x61, 0xA5, 0xB2, 0x02,
++   0x75, 0x22, 0xC3, 0x9D, 0x5A, 0x63, 0xFA, 0x5F,
++   0xD9, 0x55, 0x58, 0x43, 0x24, 0x7D, 0x77, 0x93,
++   0xBA, 0x50, 0x1D, 0xF7, 0x49, 0x18, 0xB0, 0x42,
++   0xBB, 0xEC, 0x52, 0x38, 0xDC, 0xC8, 0x16, 0x54,
++   0x17, 0x19, 0x89, 0x67, 0x33, 0x3C, 0x0A, 0xAD,
++   0xC9, 0xDE, 0x81, 0xED, 0xBD, 0x0E, 0x0B, 0x6D,
++   0x46, 0x30, 0x35, 0x2B, 0x8C, 0xA0, 0x1C, 0x0D,
++   0xFD, 0xA1, 0x70, 0xC6, 0xD8, 0x41, 0xB3, 0xC0,
++   0x44, 0xEB, 0x92, 0xBE, 0x6B, 0x98, 0x1A, 0x76,
++   0x71, 0xC5, 0x51, 0x56, 0x80, 0xFC, 0x01, 0x53,
++   0x4B, 0xD0, 0x8B, 0xD2, 0x7B, 0xE7, 0x15, 0x5D,
++   0xE5, 0xA6, 0x8A, 0xD3, 0x9B, 0xF4, 0x69, 0x23,
++   0xE8, 0xB6, 0xC7, 0xE2, 0x73, 0x9F, 0x88, 0xDF,
++   0xB4, 0x28, 0xEE, 0xC2, 0x94, 0xB8, 0xF9, 0x7F,
++   0x4A, 0x57, 0x06, 0xF6, 0xBF, 0xC1, 0xAB, 0xFB,
++   0xA4, 0x8E, 0xD1, 0xD7, 0xF5, 0x7C, 0xA3, 0x1E,
++   0x3B, 0x32, 0x03, 0xAA, 0x90, 0x5C, 0x48, 0xE0,
++   0xE3, 0xCF, 0xD4, 0xEF, 0x59, 0xD5, 0x1B, 0x34,
++   0x1F, 0x95, 0xCE, 0x7A, 0x20, 0x26, 0x87, 0xB7,
++   0x78, 0x9C, 0x4F, 0xA2, 0x12, 0x97, 0x27, 0x3F,
++   0xFF, 0x07, 0x84, 0x96, 0x04, 0xAF, 0xA8, 0xEA,
++   0x2C, 0x6C, 0xAE, 0x37, 0x91, 0xA9, 0x10, 0xDB,
++   0xCD, 0xDA, 0x08, 0x99, 0xF1, 0x4D, 0xCC, 0x68,
++   0x79, 0x2E, 0xB1, 0x39, 0x9E, 0xE9, 0x2F, 0x6A,
++   0x3D, 0x0F, 0x85, 0x8D, 0xCA, 0x29, 0x86, 0xD6,
++   0xDD, 0x05, 0x25, 0x3A, 0x40, 0x21, 0x45, 0xAC,
++   0x11, 0xF3, 0xA7, 0x09, 0x2A, 0x31, 0xE4, 0x0C,
++   0xF8, 0x6E, 0x3E, 0xB5, 0x82, 0xFE, 0x74, 0x13,
++   0x65, 0xE1, 0x2D, 0x8F, 0xE6, 0xC4, 0x00, 0x5B,
++   0x4E, 0xB9, 0x66, 0xF2, 0x62, 0x36, 0x4C, 0x83,
++   0x5E, 0x6F, 0x47, 0x64, 0xBC, 0x9A, 0x60, 0x7E };
++
++unsigned char table_28[32] = {
++   0x15, 0x05, 0x08, 0x19, 0x02, 0x18, 0x1E, 0x07,
++   0x0D, 0x0C, 0x1A, 0x06, 0x17, 0x03, 0x10, 0x09,
++   0x01, 0x11, 0x1C, 0x04, 0x0F, 0x1F, 0x12, 0x0B,
++   0x1B, 0x13, 0x0A, 0x16, 0x0E, 0x00, 0x1D, 0x14 };
++
++unsigned char table_29[256] = {
++   0x34, 0x59, 0x05, 0x13, 0x09, 0x1D, 0xDF, 0x77,
++   0x11, 0xA5, 0x92, 0x27, 0xCD, 0x7B, 0x5E, 0x80,
++   0xF9, 0x50, 0x18, 0x24, 0xD4, 0x70, 0x4A, 0x39,
++   0x66, 0xA4, 0xDB, 0xE9, 0xED, 0x48, 0xD9, 0xE7,
++   0x32, 0xDA, 0x53, 0x8F, 0x72, 0xE1, 0xF6, 0xFE,
++   0xD3, 0xAD, 0xA6, 0x1F, 0xB9, 0xD1, 0x0F, 0x4C,
++   0x23, 0x90, 0x68, 0xBC, 0x4B, 0x9B, 0x3D, 0xAB,
++   0xF0, 0x94, 0x4F, 0x1C, 0x07, 0x65, 0x7F, 0x01,
++   0x5C, 0xD7, 0x21, 0x8C, 0xBF, 0x8E, 0xB8, 0x86,
++   0x6C, 0x33, 0x36, 0xC1, 0x06, 0x74, 0x37, 0x84,
++   0x41, 0xAE, 0x67, 0x29, 0xB4, 0x85, 0xCE, 0x2A,
++   0xCB, 0x1E, 0x61, 0x9E, 0x7A, 0x44, 0x3E, 0x89,
++   0x14, 0x20, 0x19, 0xBB, 0xE0, 0xAA, 0xCF, 0x83,
++   0xA8, 0x93, 0x43, 0xF2, 0xAC, 0x0E, 0xD2, 0xCC,
++   0xDD, 0x47, 0x58, 0xC9, 0xCA, 0x1B, 0x54, 0x6E,
++   0x8A, 0x79, 0xF8, 0xC4, 0xFB, 0xD5, 0x91, 0xDE,
++   0x12, 0x31, 0x99, 0xFA, 0x6D, 0xC8, 0x57, 0xEC,
++   0xB7, 0x28, 0x0C, 0x52, 0xF1, 0x0D, 0xB1, 0x9A,
++   0x26, 0x98, 0x16, 0x7D, 0xD0, 0x2E, 0x8B, 0xD8,
++   0xE6, 0xE8, 0x30, 0xFD, 0x7C, 0x64, 0x5A, 0xBD,
++   0x87, 0xE2, 0xA1, 0x3F, 0xC3, 0x38, 0x96, 0xA3,
++   0x2D, 0xF3, 0x3A, 0xEE, 0xC0, 0x10, 0xEA, 0x6F,
++   0x8D, 0x03, 0xF4, 0x51, 0x97, 0x7E, 0x56, 0x42,
++   0x3C, 0x5D, 0x5F, 0xF5, 0x6A, 0xAF, 0xE4, 0xBE,
++   0xBA, 0x78, 0xA0, 0x5B, 0x49, 0xA7, 0xC7, 0x9C,
++   0x63, 0x6B, 0x00, 0x17, 0x69, 0x75, 0x3B, 0x40,
++   0xEF, 0x45, 0xB5, 0x2B, 0x2F, 0x02, 0xC6, 0x22,
++   0x9F, 0xFC, 0x73, 0x08, 0x81, 0xB2, 0x2C, 0x71,
++   0x35, 0xA2, 0xE3, 0xB3, 0x9D, 0xC5, 0x0A, 0xC2,
++   0x25, 0x82, 0xDC, 0x88, 0xA9, 0xE5, 0xF7, 0xEB,
++   0xD6, 0x60, 0x76, 0x55, 0x0B, 0x4E, 0xFF, 0x1A,
++   0x46, 0x62, 0xB6, 0xB0, 0x15, 0x04, 0x95, 0x4D };
++
++unsigned char table_30[32] = {
++   0x00, 0x1C, 0x0E, 0x0C, 0x06, 0x16, 0x09, 0x12,
++   0x01, 0x13, 0x0B, 0x14, 0x11, 0x08, 0x04, 0x18,
++   0x10, 0x1B, 0x15, 0x03, 0x02, 0x19, 0x1A, 0x17,
++   0x1E, 0x1F, 0x0F, 0x07, 0x0D, 0x05, 0x1D, 0x0A };
++
++unsigned char table_31[256] = {
++   0xDF, 0xD8, 0x3F, 0xBC, 0x5F, 0xC9, 0x8E, 0x4C,
++   0x0B, 0x3C, 0xE5, 0xBF, 0x39, 0xD5, 0x30, 0xDD,
++   0x23, 0xC7, 0x72, 0x63, 0x1F, 0xF8, 0x96, 0x31,
++   0x70, 0xD6, 0x9E, 0xE8, 0x9D, 0xF5, 0xEF, 0x65,
++   0xC2, 0x50, 0x62, 0x77, 0xD3, 0x6C, 0x1A, 0x91,
++   0xBB, 0xFF, 0xCD, 0x9B, 0xB6, 0xBA, 0xB8, 0x7A,
++   0x14, 0xA7, 0x74, 0x89, 0xD4, 0x6E, 0x19, 0x69,
++   0xAB, 0x01, 0x15, 0x0E, 0x87, 0x55, 0x79, 0x1C,
++   0x18, 0xBE, 0xA8, 0xDB, 0x52, 0xD2, 0x8F, 0x7E,
++   0x81, 0xAF, 0xFD, 0x5C, 0x3E, 0x1B, 0xB9, 0xB2,
++   0xB7, 0x51, 0x57, 0x8C, 0xCF, 0x5B, 0xA4, 0x75,
++   0xDE, 0x22, 0x8B, 0x10, 0x12, 0xC8, 0x35, 0x2D,
++   0x45, 0xB5, 0xF0, 0x47, 0x88, 0x16, 0xEB, 0x67,
++   0xD9, 0x0C, 0xF1, 0xC1, 0x34, 0x33, 0xC6, 0x78,
++   0xB3, 0x26, 0xE3, 0xBD, 0x5D, 0x4E, 0x66, 0xE4,
++   0xD7, 0xC4, 0xE6, 0xA1, 0xB0, 0x95, 0x2B, 0x9A,
++   0x4A, 0x3A, 0xCB, 0x40, 0xE1, 0x60, 0x49, 0xCC,
++   0x03, 0xAC, 0xF4, 0x97, 0x32, 0x0F, 0x38, 0x17,
++   0xF9, 0xE0, 0xD1, 0xFB, 0x04, 0x5E, 0x68, 0x06,
++   0xAE, 0xFA, 0xAA, 0xED, 0x24, 0x0D, 0x00, 0x61,
++   0x20, 0xA3, 0x7B, 0x6B, 0x76, 0x27, 0xEA, 0xCE,
++   0x6A, 0x82, 0x9F, 0x6D, 0x9C, 0x64, 0xA2, 0x11,
++   0x37, 0x2A, 0xCA, 0x84, 0x25, 0x7C, 0x2F, 0x8D,
++   0x90, 0xE7, 0x09, 0x93, 0xF3, 0x43, 0x71, 0xEC,
++   0xA9, 0x7D, 0x94, 0xA6, 0x3D, 0x7F, 0x54, 0x44,
++   0x99, 0x80, 0x41, 0xC0, 0xA0, 0x8A, 0x1E, 0xDC,
++   0x08, 0xD0, 0x2E, 0x42, 0x05, 0x85, 0x86, 0xFE,
++   0x3B, 0x59, 0xC3, 0x58, 0x13, 0xB4, 0x36, 0xA5,
++   0x73, 0x28, 0x29, 0xDA, 0x4F, 0x1D, 0xB1, 0x53,
++   0x46, 0x2C, 0xF2, 0x4D, 0xAD, 0xFC, 0x83, 0x02,
++   0x6F, 0x07, 0xE9, 0xEE, 0x21, 0x98, 0x5A, 0xC5,
++   0x92, 0x48, 0xF7, 0x0A, 0xF6, 0xE2, 0x4B, 0x56 };
++
++unsigned char table_32[256] = {
++   0x7B, 0x0F, 0x56, 0x2F, 0x1E, 0x2A, 0x7A, 0xD1,
++   0x02, 0x91, 0x4E, 0x37, 0x6C, 0x10, 0xA7, 0xF2,
++   0x38, 0xAC, 0x9E, 0x2B, 0x5E, 0x23, 0xE3, 0x19,
++   0x9B, 0xF6, 0xB0, 0x59, 0x14, 0xB9, 0xA9, 0x46,
++   0x84, 0x1D, 0xC0, 0x98, 0xF3, 0xE1, 0xE8, 0x94,
++   0x52, 0x35, 0xBA, 0xD8, 0x07, 0xEF, 0x31, 0xF8,
++   0x03, 0x76, 0x9C, 0xD7, 0xE4, 0x8B, 0xAF, 0x60,
++   0xDD, 0x51, 0x00, 0xDF, 0x11, 0x7F, 0x1C, 0xED,
++   0x49, 0xC9, 0xF4, 0x87, 0x64, 0xFC, 0x5D, 0xAD,
++   0x88, 0x85, 0xF7, 0x5A, 0x92, 0xDB, 0x72, 0x1A,
++   0x83, 0x15, 0x30, 0x24, 0x9F, 0xFF, 0x5B, 0xF1,
++   0xD2, 0xFD, 0xC2, 0xB5, 0x25, 0x22, 0x18, 0x3D,
++   0xCD, 0x97, 0x8C, 0xCC, 0x78, 0x90, 0xAA, 0x5F,
++   0x0A, 0x57, 0x05, 0x61, 0xD4, 0xA0, 0x3A, 0xDE,
++   0x3B, 0xF9, 0x65, 0x68, 0x4F, 0x28, 0xFA, 0xEB,
++   0x63, 0x2D, 0x8D, 0xD0, 0xA1, 0xFE, 0x12, 0x96,
++   0x3C, 0x42, 0x29, 0xD6, 0xA4, 0x34, 0xBD, 0x70,
++   0x89, 0xBE, 0xF5, 0x79, 0xAB, 0x8F, 0x32, 0xB4,
++   0xEE, 0xE7, 0x2C, 0x04, 0x4B, 0xD5, 0xB1, 0x54,
++   0xF0, 0xDA, 0x16, 0x77, 0xA6, 0x53, 0xB2, 0xE2,
++   0x73, 0xBF, 0x17, 0xA8, 0x75, 0x26, 0xE0, 0xBC,
++   0x0C, 0x71, 0xFB, 0x6D, 0x7E, 0xC5, 0xEA, 0x21,
++   0x9D, 0x95, 0x8E, 0xA5, 0x48, 0xB8, 0x7D, 0xCB,
++   0x01, 0x99, 0xE5, 0xBB, 0x82, 0xC4, 0xCA, 0xC1,
++   0x58, 0x6E, 0x5C, 0x7C, 0xDC, 0x33, 0xB6, 0xC3,
++   0x09, 0xC7, 0x1F, 0x0D, 0x43, 0x6F, 0xE9, 0x86,
++   0x27, 0xC8, 0x44, 0xB3, 0xD3, 0xCF, 0x08, 0x66,
++   0x1B, 0x20, 0x4D, 0xD9, 0xC6, 0x36, 0x40, 0x74,
++   0x62, 0x6A, 0x55, 0xEC, 0x06, 0x2E, 0xE6, 0x80,
++   0x13, 0x93, 0x50, 0xCE, 0x69, 0x3E, 0x67, 0x4A,
++   0x81, 0x4C, 0x0B, 0x3F, 0xB7, 0x0E, 0x39, 0xAE,
++   0x47, 0x6B, 0x8A, 0xA2, 0x9A, 0xA3, 0x45, 0x41 };
++
++unsigned char table_33[256] = {
++   0xDE, 0xD3, 0x79, 0x67, 0x13, 0x5C, 0x04, 0xF2,
++   0xD9, 0x9F, 0x65, 0x56, 0xCC, 0x3B, 0xA4, 0x9A,
++   0x08, 0xBF, 0x26, 0xB2, 0xA7, 0x5E, 0xAA, 0xCA,
++   0xBB, 0x2B, 0x38, 0x3F, 0xD8, 0x87, 0xFA, 0x5D,
++   0x73, 0x8E, 0x1E, 0x93, 0x05, 0xAF, 0x3E, 0x4E,
++   0x90, 0xDB, 0x0B, 0x33, 0x0D, 0x2F, 0x86, 0x4F,
++   0xFD, 0xD0, 0x39, 0xB1, 0x8A, 0x1A, 0x20, 0xE6,
++   0xCF, 0xA2, 0x82, 0xDF, 0x42, 0x9C, 0x30, 0x40,
++   0xE3, 0xB0, 0x88, 0x5A, 0xEC, 0x25, 0xE2, 0xC4,
++   0x12, 0x54, 0x50, 0x97, 0x96, 0x21, 0x23, 0x7B,
++   0x1D, 0x61, 0x52, 0x34, 0x7D, 0x69, 0x16, 0xC3,
++   0x31, 0xF8, 0x48, 0x19, 0x95, 0x01, 0x29, 0x8C,
++   0x15, 0xAC, 0x84, 0x74, 0xAB, 0x70, 0xDA, 0x36,
++   0xD6, 0x8F, 0xFE, 0x35, 0xD7, 0x2E, 0x89, 0x07,
++   0x62, 0x17, 0xDC, 0x92, 0x45, 0x83, 0xB5, 0xE5,
++   0x8B, 0xC0, 0x27, 0x85, 0x7C, 0x9D, 0x55, 0x81,
++   0x71, 0xCD, 0xC9, 0x00, 0x02, 0xC1, 0x0A, 0x37,
++   0xED, 0xEA, 0xC2, 0x98, 0x49, 0x06, 0x1C, 0x78,
++   0x64, 0xCE, 0x9E, 0x4C, 0x7A, 0xB4, 0x43, 0x0F,
++   0xE0, 0x7E, 0xBC, 0x5B, 0x51, 0xE7, 0x18, 0xF9,
++   0x11, 0xA1, 0xF5, 0xC7, 0xCB, 0x4D, 0x6A, 0x0E,
++   0x57, 0xF1, 0xFB, 0xB3, 0x99, 0xF0, 0x32, 0xD5,
++   0xA9, 0x4B, 0x6F, 0x6D, 0xA8, 0xC5, 0xDD, 0x7F,
++   0xEB, 0xBE, 0xFC, 0x2C, 0x22, 0x58, 0x03, 0x9B,
++   0x77, 0xF7, 0xBD, 0xBA, 0xD2, 0x6B, 0xAD, 0x5F,
++   0x10, 0x6E, 0x09, 0xD1, 0x1B, 0x24, 0xEF, 0x72,
++   0x3D, 0x59, 0x28, 0xE1, 0xB7, 0x44, 0x8D, 0xB8,
++   0xAE, 0x2D, 0x60, 0xA6, 0xC8, 0x0C, 0xF4, 0x41,
++   0xA3, 0x68, 0x46, 0x6C, 0x76, 0xA0, 0xB6, 0x66,
++   0xE4, 0x1F, 0x75, 0x4A, 0xFF, 0x2A, 0x94, 0xD4,
++   0xF3, 0xE9, 0x91, 0x63, 0xA5, 0xB9, 0xE8, 0x14,
++   0x80, 0x3C, 0xEE, 0x47, 0xC6, 0x3A, 0x53, 0xF6 };
++
++unsigned char table_34[256] = {
++   0xF0, 0xE9, 0x3E, 0xD6, 0x89, 0xC8, 0xC7, 0x23,
++   0x75, 0x26, 0x5F, 0x9C, 0x57, 0xB8, 0x2A, 0x29,
++   0xE5, 0xB5, 0x68, 0xA4, 0x92, 0x46, 0x40, 0x7F,
++   0xF2, 0xBC, 0x6A, 0xE0, 0x8F, 0x0F, 0xE4, 0x3A,
++   0xE1, 0x30, 0x84, 0x6E, 0x82, 0x8E, 0x56, 0xC5,
++   0x32, 0x85, 0xFB, 0x59, 0x43, 0x41, 0xC2, 0xF6,
++   0x67, 0x5A, 0x7C, 0x34, 0xA1, 0xD0, 0x4B, 0xAC,
++   0x61, 0x72, 0x6B, 0xAF, 0xC4, 0x20, 0x9A, 0xD4,
++   0x74, 0x8D, 0x87, 0x83, 0xE2, 0x62, 0x6D, 0xE6,
++   0xE7, 0xF9, 0x76, 0xCB, 0x18, 0x90, 0x4F, 0xFF,
++   0xD3, 0x3C, 0x08, 0x79, 0x93, 0x2D, 0x95, 0xA3,
++   0xDD, 0x5B, 0xDA, 0x7A, 0x39, 0x4D, 0xC1, 0x2E,
++   0xCC, 0x53, 0xE8, 0xA2, 0xCF, 0x15, 0x78, 0x1C,
++   0xEB, 0x9B, 0x7B, 0xAD, 0x31, 0x2F, 0xE3, 0xC9,
++   0x3B, 0xEC, 0x2C, 0x49, 0x02, 0x52, 0x28, 0xBA,
++   0x0C, 0x19, 0x24, 0xF7, 0x97, 0x09, 0xA6, 0xA0,
++   0xDF, 0xD1, 0xD2, 0xDC, 0x51, 0xA5, 0x94, 0xFD,
++   0x71, 0xF5, 0x50, 0x0A, 0x69, 0x25, 0x88, 0x5C,
++   0x91, 0xD5, 0x47, 0x0B, 0x27, 0x13, 0x96, 0xD9,
++   0xF1, 0xA9, 0x70, 0xC3, 0xBE, 0x42, 0x4E, 0x4A,
++   0xB1, 0x07, 0xA7, 0x54, 0xFE, 0x48, 0x9F, 0x63,
++   0x17, 0xAE, 0xB9, 0x58, 0x21, 0x35, 0xED, 0x5D,
++   0x9D, 0x3D, 0xB4, 0xFC, 0xEA, 0x8C, 0x80, 0xA8,
++   0x1E, 0xB0, 0xDE, 0x0D, 0x11, 0x6F, 0x04, 0x12,
++   0xF4, 0x10, 0x64, 0x0E, 0xD7, 0x2B, 0xB3, 0x8B,
++   0xB7, 0x01, 0x86, 0xCA, 0xFA, 0x9E, 0xEE, 0x66,
++   0x37, 0x65, 0x81, 0x38, 0x1F, 0xAA, 0x73, 0xAB,
++   0xBD, 0xDB, 0x14, 0xCD, 0x00, 0xBB, 0x98, 0x44,
++   0x45, 0xB6, 0x99, 0x5E, 0xD8, 0x1D, 0x36, 0xF8,
++   0x55, 0x6C, 0x16, 0x7E, 0x77, 0x3F, 0x22, 0xEF,
++   0xF3, 0x7D, 0xC6, 0xCE, 0x8A, 0xB2, 0x33, 0x4C,
++   0x03, 0x05, 0xBF, 0x06, 0x1B, 0xC0, 0x1A, 0x60 };
++
++unsigned char table_35[256] = {
++   0xCC, 0x40, 0xEF, 0x1F, 0xDB, 0xE5, 0x71, 0x51,
++   0x3B, 0x0F, 0x7D, 0x9C, 0x83, 0x17, 0x6F, 0x8F,
++   0x13, 0xDC, 0x7F, 0xA9, 0xA5, 0xA2, 0x9D, 0xDF,
++   0xE7, 0x97, 0x2A, 0x30, 0xF2, 0x73, 0xCF, 0x87,
++   0x29, 0xB3, 0x86, 0x43, 0x09, 0xB0, 0x2E, 0x10,
++   0x8E, 0xBC, 0x57, 0xBA, 0x68, 0xF5, 0xCB, 0x89,
++   0x32, 0xC1, 0x6B, 0x1E, 0xAC, 0xB2, 0x2D, 0x6A,
++   0x50, 0xEB, 0x18, 0x06, 0xD8, 0xC7, 0x36, 0x31,
++   0xC5, 0xAF, 0x12, 0x15, 0xB7, 0x37, 0x4E, 0x01,
++   0x14, 0x21, 0x44, 0x5E, 0xF4, 0xB4, 0xE4, 0x65,
++   0xFE, 0x8A, 0xEA, 0x0D, 0xBB, 0x45, 0x8B, 0x25,
++   0x80, 0x35, 0x61, 0xA8, 0x4A, 0x47, 0xAB, 0x91,
++   0x1B, 0x1C, 0x05, 0x4D, 0x5A, 0xD4, 0xF1, 0x9B,
++   0x0E, 0x98, 0xCA, 0x96, 0x42, 0x7E, 0x03, 0x5F,
++   0xE2, 0x90, 0xBF, 0x82, 0xC9, 0x3D, 0xE0, 0x5C,
++   0xFA, 0x3E, 0x41, 0x11, 0x79, 0x58, 0x24, 0x2C,
++   0xC0, 0x28, 0x5D, 0xA3, 0xDE, 0x67, 0xFF, 0xA4,
++   0x63, 0xB1, 0x22, 0x04, 0xFD, 0x70, 0x39, 0x46,
++   0xAA, 0x0A, 0x34, 0x6C, 0xD7, 0x92, 0xA1, 0x3C,
++   0x19, 0xD5, 0xFC, 0xAD, 0x85, 0x07, 0x00, 0x23,
++   0xF8, 0x69, 0x56, 0x53, 0x55, 0x7A, 0xB8, 0xC8,
++   0xDA, 0xCE, 0xF3, 0x5B, 0x49, 0xE1, 0xBE, 0xEC,
++   0x1A, 0x88, 0x02, 0xBD, 0xF7, 0x1D, 0x64, 0xA0,
++   0x4F, 0xD9, 0xE3, 0x95, 0xC6, 0x48, 0x2B, 0xED,
++   0x9A, 0x9E, 0x26, 0x6E, 0xD1, 0x94, 0xB9, 0x93,
++   0xDD, 0xF6, 0xA6, 0xFB, 0xC2, 0xB6, 0x0C, 0xE9,
++   0x77, 0xF9, 0xCD, 0x08, 0xEE, 0x3F, 0xE6, 0x75,
++   0xD6, 0x84, 0x76, 0x8C, 0xF0, 0xAE, 0xD2, 0x78,
++   0x2F, 0x4B, 0x16, 0x4C, 0x27, 0x81, 0x6D, 0x99,
++   0x38, 0xD3, 0x54, 0x62, 0x74, 0x20, 0x60, 0xC3,
++   0x7C, 0x8D, 0x72, 0x0B, 0x52, 0xE8, 0xA7, 0x3A,
++   0x59, 0xC4, 0x9F, 0xD0, 0x66, 0x7B, 0x33, 0xB5 };
++
++unsigned char table_36[256] = {
++   0xDB, 0x6F, 0xFE, 0xB3, 0x5C, 0x1F, 0xB8, 0xBF,
++   0xA3, 0x71, 0x11, 0x56, 0x90, 0xE2, 0x63, 0x18,
++   0x83, 0x51, 0x21, 0xEB, 0x66, 0x08, 0xA6, 0xA5,
++   0x1C, 0xF5, 0x14, 0x24, 0x41, 0x33, 0xA7, 0xB5,
++   0xC7, 0x79, 0x57, 0x50, 0x85, 0xE1, 0x6D, 0xF7,
++   0x0E, 0xDE, 0x67, 0xAB, 0xA1, 0x0B, 0xD9, 0x4A,
++   0xCA, 0x36, 0xEA, 0xDA, 0x16, 0xEF, 0x9F, 0x0A,
++   0x09, 0x9A, 0x1D, 0xC5, 0xD7, 0x5F, 0x19, 0xDC,
++   0x15, 0x06, 0xE8, 0x94, 0x0C, 0x0D, 0xC9, 0x7C,
++   0xD6, 0x62, 0xBB, 0x49, 0xF9, 0x61, 0x07, 0x9B,
++   0x28, 0xC3, 0x9E, 0xF4, 0x38, 0x78, 0x20, 0x03,
++   0xA2, 0x7F, 0xC2, 0x9D, 0x5E, 0x65, 0x52, 0x17,
++   0x2E, 0x1B, 0xB0, 0x42, 0xBC, 0xFD, 0xF1, 0xD2,
++   0xF6, 0x60, 0xD3, 0x29, 0x97, 0x3D, 0x0F, 0xB1,
++   0x2F, 0x22, 0xDD, 0x80, 0x32, 0xF8, 0xAD, 0x70,
++   0xB9, 0x8F, 0x37, 0xCE, 0x46, 0x58, 0xB7, 0x30,
++   0xED, 0x7A, 0xE9, 0xC0, 0x7D, 0x13, 0x64, 0x23,
++   0x4E, 0xC8, 0xF0, 0xCC, 0x3B, 0x45, 0x68, 0x8D,
++   0xBE, 0x8B, 0xD8, 0x43, 0x02, 0x27, 0xE4, 0xAA,
++   0x10, 0xF2, 0x59, 0x72, 0x40, 0x26, 0x69, 0xE5,
++   0x05, 0x84, 0x4F, 0xE0, 0x6B, 0xC1, 0xAC, 0x4C,
++   0xFB, 0x31, 0x77, 0x8E, 0xD4, 0x12, 0xA9, 0xB4,
++   0xEC, 0x00, 0x76, 0x1E, 0x25, 0xAE, 0xE7, 0x3C,
++   0x35, 0x93, 0x9C, 0xC4, 0xFC, 0x2D, 0x91, 0x04,
++   0xAF, 0x53, 0x3F, 0xE6, 0xA4, 0xD0, 0x1A, 0xDF,
++   0x3A, 0x55, 0x99, 0x01, 0xCB, 0x6C, 0x82, 0x3E,
++   0x5D, 0xA8, 0x88, 0x54, 0x5B, 0x95, 0xCD, 0x8C,
++   0x81, 0x34, 0xD1, 0x39, 0xFF, 0xEE, 0xFA, 0x8A,
++   0x6E, 0x86, 0x92, 0x89, 0xF3, 0x6A, 0xBA, 0x2C,
++   0xD5, 0x44, 0xC6, 0x96, 0xBD, 0xB2, 0x2B, 0x87,
++   0x74, 0xA0, 0x73, 0x5A, 0x2A, 0x98, 0x75, 0x47,
++   0x4B, 0xB6, 0x7B, 0x4D, 0xCF, 0x7E, 0x48, 0xE3 };
++
++unsigned char table_37[256] = {
++   0x1F, 0xD6, 0xB1, 0xB3, 0x40, 0xAD, 0xDE, 0xB7,
++   0x19, 0xB4, 0xE7, 0x0B, 0x9C, 0x2D, 0xE0, 0xF5,
++   0xCF, 0x2C, 0x30, 0x65, 0x2F, 0xCD, 0x02, 0x91,
++   0xCE, 0x2B, 0xBF, 0x78, 0xE6, 0xFA, 0x51, 0x48,
++   0xFB, 0x4D, 0xBE, 0x71, 0x1A, 0x56, 0xFD, 0x81,
++   0x33, 0x75, 0x89, 0x96, 0x37, 0x82, 0x9E, 0x93,
++   0x41, 0x18, 0x5B, 0x2E, 0x22, 0x0F, 0xAF, 0x4B,
++   0xB9, 0xD5, 0xEE, 0x6C, 0xE4, 0x05, 0xCC, 0x99,
++   0xE5, 0x3B, 0x62, 0xBD, 0x7B, 0xAA, 0x4A, 0xE2,
++   0x34, 0x43, 0xF7, 0x39, 0xFE, 0x14, 0x1D, 0xE3,
++   0xF0, 0xA7, 0x77, 0xDF, 0xA0, 0xD3, 0xAC, 0xD9,
++   0xEA, 0x76, 0xDD, 0xA4, 0xC5, 0xC9, 0x61, 0xF3,
++   0xA8, 0xB0, 0x35, 0xE8, 0x68, 0xD4, 0x15, 0xF9,
++   0x97, 0xED, 0x25, 0x0A, 0x88, 0x8F, 0x06, 0xA3,
++   0x16, 0x36, 0x32, 0xA2, 0xC6, 0x64, 0xD7, 0x94,
++   0xD2, 0x6D, 0x74, 0xFC, 0x44, 0x27, 0x5C, 0xFF,
++   0x60, 0x1E, 0x58, 0x8B, 0x5E, 0xC7, 0x90, 0x17,
++   0x63, 0xAE, 0xC3, 0x12, 0x13, 0x84, 0xEC, 0x49,
++   0xA5, 0x9B, 0x31, 0x8D, 0xE1, 0x79, 0xF1, 0x00,
++   0x28, 0x3D, 0xC2, 0x55, 0x20, 0x52, 0x95, 0x7E,
++   0x42, 0x1C, 0x66, 0x92, 0x7D, 0xB6, 0xC4, 0xF4,
++   0x80, 0xB2, 0x72, 0x6E, 0x11, 0xF6, 0x0D, 0x5A,
++   0xEF, 0x9D, 0x69, 0x9A, 0x45, 0x67, 0x3F, 0xDA,
++   0x8E, 0x57, 0x09, 0x7C, 0x38, 0xA6, 0x83, 0x87,
++   0x7A, 0x08, 0x4C, 0x5F, 0x85, 0x7F, 0xD0, 0x04,
++   0x50, 0xCB, 0xB8, 0x07, 0x24, 0x26, 0x29, 0x46,
++   0x01, 0x03, 0xC1, 0xD8, 0xDC, 0x0E, 0x3C, 0x4F,
++   0x53, 0x4E, 0xB5, 0xF8, 0xC0, 0x8A, 0xF2, 0xBB,
++   0xE9, 0x5D, 0x2A, 0xBA, 0x0C, 0x1B, 0x3A, 0xA9,
++   0x21, 0x6A, 0x70, 0xBC, 0xEB, 0xA1, 0x54, 0x10,
++   0x98, 0x9F, 0x23, 0xD1, 0x6B, 0x59, 0x3E, 0xCA,
++   0x73, 0xC8, 0x86, 0x47, 0xDB, 0xAB, 0x6F, 0x8C };
++
++unsigned char table_38[256] = {
++   0xAA, 0x8D, 0x37, 0x94, 0x99, 0xDD, 0x70, 0x77,
++   0x78, 0xC9, 0x0F, 0xFA, 0xE2, 0x05, 0xC2, 0x16,
++   0x02, 0x4D, 0x44, 0x65, 0xAC, 0xB0, 0x39, 0xF8,
++   0x06, 0x60, 0xD8, 0xE1, 0x19, 0xB4, 0x36, 0x20,
++   0x59, 0x1D, 0xAD, 0xE4, 0xE8, 0xFF, 0x9D, 0x0D,
++   0x51, 0x28, 0xE7, 0x8C, 0x0E, 0x97, 0xE3, 0xAE,
++   0x6A, 0x27, 0x98, 0xDB, 0x26, 0xF6, 0xEC, 0xC6,
++   0xC0, 0xBD, 0x68, 0x61, 0x83, 0x86, 0xE0, 0x2C,
++   0xEE, 0x47, 0xF9, 0x5F, 0x6D, 0xBA, 0xE9, 0x72,
++   0x8A, 0xBB, 0x08, 0x29, 0xAF, 0x1C, 0xD3, 0x5D,
++   0xF7, 0x87, 0x6F, 0x9A, 0x2F, 0x11, 0xD9, 0x90,
++   0x66, 0x8E, 0xEB, 0xB1, 0x2E, 0xEA, 0xA3, 0x55,
++   0x2B, 0xCC, 0x4C, 0x4B, 0x48, 0x71, 0x3B, 0xFC,
++   0xA4, 0x45, 0x0A, 0x8F, 0x7A, 0x13, 0x01, 0x22,
++   0xC1, 0xF1, 0xA2, 0xB8, 0x7C, 0xF4, 0xB3, 0xB7,
++   0x5B, 0xE5, 0x07, 0x50, 0x7E, 0x18, 0xEF, 0x91,
++   0x5C, 0x15, 0x69, 0xBE, 0x0C, 0x93, 0x56, 0x35,
++   0x7B, 0xCF, 0x34, 0x74, 0x3E, 0x5E, 0x31, 0x21,
++   0x12, 0x63, 0x7F, 0x2A, 0x9B, 0xD4, 0x6B, 0xBC,
++   0x33, 0x62, 0x30, 0x75, 0x17, 0x23, 0xB2, 0xF0,
++   0x57, 0x67, 0x95, 0x3D, 0xCD, 0x10, 0xE6, 0xC8,
++   0x8B, 0xA9, 0x73, 0xC4, 0x43, 0xBF, 0xA7, 0xCA,
++   0xB5, 0xD5, 0xD6, 0x3F, 0x1A, 0x7D, 0x82, 0xA8,
++   0x40, 0x64, 0xAB, 0x04, 0xC3, 0x1F, 0xA0, 0x5A,
++   0x85, 0xF3, 0xDE, 0xFE, 0xDA, 0x1E, 0x81, 0x92,
++   0x9C, 0x2D, 0x9F, 0x32, 0xB9, 0xA1, 0x96, 0xD0,
++   0x4F, 0x38, 0x80, 0xCB, 0x6C, 0x14, 0x84, 0x1B,
++   0xD7, 0xC5, 0xED, 0xD2, 0x3A, 0x0B, 0x88, 0xFD,
++   0xDC, 0x49, 0x9E, 0xF5, 0xF2, 0x52, 0xA6, 0x24,
++   0xC7, 0xB6, 0x03, 0x3C, 0xD1, 0x54, 0x41, 0xDF,
++   0x89, 0x58, 0x79, 0xFB, 0x6E, 0xA5, 0x42, 0x25,
++   0x09, 0x76, 0x00, 0x46, 0x4E, 0x53, 0xCE, 0x4A };
++
++unsigned char table_39[32] = {
++   0x12, 0x18, 0x0E, 0x08, 0x16, 0x05, 0x06, 0x00,
++   0x11, 0x17, 0x15, 0x1B, 0x14, 0x01, 0x1F, 0x19,
++   0x04, 0x0D, 0x0A, 0x0F, 0x10, 0x07, 0x1D, 0x03,
++   0x0B, 0x13, 0x0C, 0x09, 0x1E, 0x02, 0x1A, 0x1C };
++
++unsigned char table_40[32] = {
++   0x16, 0x02, 0x06, 0x0E, 0x0D, 0x1C, 0x08, 0x0A,
++   0x0F, 0x13, 0x0B, 0x18, 0x07, 0x04, 0x14, 0x01,
++   0x1B, 0x05, 0x17, 0x1E, 0x11, 0x1A, 0x10, 0x1F,
++   0x12, 0x19, 0x1D, 0x03, 0x0C, 0x00, 0x09, 0x15 };
++
++unsigned char table_41[32] = {
++   0x13, 0x18, 0x04, 0x1F, 0x1D, 0x11, 0x03, 0x00,
++   0x10, 0x12, 0x06, 0x0A, 0x1C, 0x07, 0x15, 0x0E,
++   0x08, 0x05, 0x0C, 0x09, 0x01, 0x02, 0x16, 0x0B,
++   0x1A, 0x17, 0x14, 0x1E, 0x0D, 0x0F, 0x19, 0x1B };
++
++unsigned char table_42[32] = {
++   0x00, 0x08, 0x15, 0x1D, 0x05, 0x18, 0x06, 0x07,
++   0x1F, 0x01, 0x0B, 0x03, 0x19, 0x13, 0x02, 0x1C,
++   0x17, 0x11, 0x0E, 0x1E, 0x0C, 0x0F, 0x09, 0x1A,
++   0x1B, 0x16, 0x10, 0x0D, 0x0A, 0x14, 0x12, 0x04 };
++
++unsigned char table_43[256] = {
++   0x34, 0xB7, 0x36, 0x85, 0x5F, 0x93, 0x98, 0x70,
++   0x1E, 0x59, 0x83, 0x60, 0x6F, 0xBF, 0xF9, 0xD0,
++   0xB3, 0x22, 0x12, 0x38, 0xF5, 0x01, 0xC9, 0x5B,
++   0xEF, 0x1D, 0x81, 0x64, 0xFA, 0x8F, 0x7F, 0xBC,
++   0x05, 0x08, 0xE0, 0x8B, 0xE8, 0x86, 0x95, 0xCB,
++   0xCA, 0x5A, 0xEB, 0x10, 0x92, 0xE2, 0x7E, 0x28,
++   0xD9, 0xC7, 0x0D, 0x24, 0xA7, 0x02, 0x0B, 0xF1,
++   0x7B, 0xD3, 0xFE, 0x2B, 0x89, 0x0E, 0xAE, 0xAD,
++   0xC8, 0x82, 0x79, 0x43, 0x96, 0xDE, 0x0C, 0x9A,
++   0x57, 0x84, 0xB4, 0x19, 0xF8, 0xF0, 0xAF, 0xBE,
++   0x99, 0x9F, 0x46, 0xE4, 0x31, 0xDF, 0x30, 0x51,
++   0xD4, 0xE5, 0xFC, 0x32, 0x04, 0x56, 0x7D, 0x33,
++   0xF7, 0x18, 0x23, 0x4E, 0xC2, 0x7C, 0x6C, 0xD2,
++   0xB1, 0x9B, 0x40, 0xA2, 0x88, 0x00, 0xA1, 0xAB,
++   0xC6, 0x5C, 0x87, 0x3B, 0xD7, 0x27, 0x2E, 0x45,
++   0xDA, 0x8E, 0x61, 0x5E, 0xFB, 0x09, 0x5D, 0x6B,
++   0xA3, 0x29, 0x4F, 0xAC, 0xD1, 0x77, 0x4A, 0xA9,
++   0xC4, 0x7A, 0x15, 0xD8, 0xAA, 0x17, 0xB9, 0x2D,
++   0xE7, 0xBD, 0x2C, 0x62, 0x2F, 0xB2, 0xED, 0x3F,
++   0x48, 0x26, 0x1B, 0x35, 0x20, 0x72, 0x4D, 0xFF,
++   0xBB, 0x78, 0x1F, 0xCC, 0xEC, 0xA8, 0x9D, 0x90,
++   0x4B, 0x13, 0xE1, 0xBA, 0xF3, 0x3C, 0x42, 0x65,
++   0x14, 0xDD, 0x75, 0xE3, 0x4C, 0x74, 0x94, 0xCD,
++   0xF2, 0x66, 0x06, 0xE9, 0x49, 0xB8, 0x71, 0x41,
++   0xA0, 0x25, 0x55, 0x47, 0x97, 0x9E, 0x11, 0x54,
++   0x1A, 0xB0, 0x3E, 0x37, 0x39, 0x1C, 0x8D, 0x03,
++   0x6E, 0xF6, 0x80, 0x6D, 0x8C, 0x9C, 0xB6, 0xCF,
++   0xC3, 0x91, 0x63, 0xC0, 0x07, 0x67, 0xE6, 0xF4,
++   0xCE, 0x3D, 0xDB, 0x16, 0xFD, 0xEA, 0xD6, 0x68,
++   0xD5, 0xA6, 0x0F, 0x58, 0x44, 0x52, 0xB5, 0xDC,
++   0x0A, 0x69, 0xC5, 0xA5, 0xC1, 0x8A, 0x2A, 0xEE,
++   0x73, 0x76, 0x3A, 0x21, 0x53, 0xA4, 0x50, 0x6A };
++
++unsigned char table_44[32] = {
++   0x1A, 0x0E, 0x0A, 0x17, 0x1F, 0x08, 0x10, 0x14,
++   0x0C, 0x0F, 0x09, 0x1C, 0x06, 0x18, 0x1E, 0x12,
++   0x15, 0x00, 0x11, 0x13, 0x0D, 0x01, 0x0B, 0x03,
++   0x16, 0x19, 0x05, 0x1D, 0x02, 0x07, 0x04, 0x1B };
++
++unsigned char table_45[256] = {
++   0x5E, 0xD6, 0xE2, 0x54, 0x35, 0xC2, 0xAC, 0x9D,
++   0x92, 0x64, 0x57, 0x65, 0xC8, 0xAE, 0x21, 0xA9,
++   0x89, 0x48, 0x12, 0x59, 0xEC, 0xEF, 0x9F, 0xF7,
++   0x19, 0x03, 0x83, 0xC0, 0x79, 0x5D, 0x4A, 0x10,
++   0x8C, 0xEB, 0xFF, 0xB5, 0x3B, 0x51, 0x2D, 0xD1,
++   0x6B, 0xC5, 0x24, 0x5C, 0xE6, 0x11, 0x94, 0x3F,
++   0xD0, 0x2F, 0x0E, 0x95, 0x3C, 0xFE, 0x5B, 0x20,
++   0x23, 0xE0, 0x91, 0x6F, 0xCA, 0x56, 0x0C, 0x73,
++   0xDA, 0x67, 0x37, 0xA3, 0xA5, 0x70, 0x93, 0x1C,
++   0x18, 0xD9, 0x42, 0x5F, 0x44, 0xF0, 0xF2, 0x14,
++   0x58, 0x8A, 0x1D, 0x40, 0x4E, 0x0B, 0x74, 0x84,
++   0x52, 0xCB, 0x60, 0xED, 0xAD, 0x66, 0x43, 0x6C,
++   0x81, 0xA1, 0x27, 0xB9, 0xBA, 0x4D, 0xF5, 0x04,
++   0xB8, 0x96, 0xA6, 0xA2, 0x7D, 0xD4, 0xEA, 0x45,
++   0x4F, 0x55, 0xD3, 0x3E, 0x8E, 0x4C, 0xBF, 0x8B,
++   0x9A, 0x06, 0x7A, 0xF4, 0x02, 0x88, 0x80, 0x22,
++   0xF3, 0xBD, 0x78, 0xEE, 0xAF, 0xF8, 0x15, 0x09,
++   0x0F, 0xB0, 0xDD, 0x99, 0x72, 0xE7, 0x90, 0xE1,
++   0x25, 0x62, 0x8D, 0x9C, 0x13, 0x08, 0xC9, 0x28,
++   0x2A, 0x47, 0x69, 0xDE, 0x77, 0x87, 0xBB, 0xE9,
++   0xAA, 0x33, 0x05, 0x29, 0x34, 0x97, 0xFD, 0xA0,
++   0x1E, 0xFC, 0xBE, 0xB1, 0x71, 0x9B, 0x50, 0xDC,
++   0xB7, 0x31, 0x63, 0x3A, 0xDF, 0xC3, 0x1B, 0x7C,
++   0x0A, 0xD7, 0xF6, 0xDB, 0x49, 0x53, 0x7F, 0xD2,
++   0x30, 0xA4, 0xB3, 0x6E, 0xB2, 0x6D, 0xCD, 0x7E,
++   0x26, 0xE8, 0x76, 0xCF, 0xE5, 0xCE, 0x16, 0xF1,
++   0xC6, 0x68, 0x36, 0x46, 0x1F, 0x38, 0x0D, 0x41,
++   0x17, 0xBC, 0x86, 0x9E, 0x6A, 0x7B, 0xB4, 0x01,
++   0xCC, 0x2C, 0xE3, 0x5A, 0xB6, 0xFA, 0x00, 0x75,
++   0x39, 0xA7, 0xC1, 0xD5, 0x98, 0xAB, 0x1A, 0x85,
++   0xD8, 0xE4, 0xC4, 0xA8, 0x4B, 0x61, 0x2E, 0x3D,
++   0xF9, 0x2B, 0x32, 0x8F, 0xFB, 0xC7, 0x07, 0x82 };
++
++unsigned char table_46[256] = {
++   0x85, 0x78, 0xFE, 0x6C, 0x61, 0xA0, 0x71, 0xCC,
++   0x45, 0x54, 0x7A, 0xE6, 0x82, 0x1D, 0xA6, 0x02,
++   0x47, 0xD0, 0x23, 0x55, 0x62, 0xFA, 0x76, 0x3E,
++   0xE3, 0x66, 0x74, 0x10, 0x5D, 0x49, 0x69, 0x0B,
++   0x75, 0x12, 0x8D, 0x9F, 0xEE, 0x93, 0x50, 0x70,
++   0x32, 0xBC, 0x1E, 0xD3, 0xEF, 0x7B, 0xB4, 0x92,
++   0xFD, 0x16, 0xC2, 0xD8, 0xDE, 0x68, 0xD1, 0x64,
++   0xC3, 0xA3, 0xB3, 0xC9, 0x08, 0xFB, 0x84, 0xC1,
++   0x28, 0x53, 0xCF, 0xD2, 0x35, 0xD7, 0x4A, 0x01,
++   0x44, 0xA4, 0x07, 0xAC, 0x98, 0xF1, 0xB2, 0x9A,
++   0x94, 0x2D, 0xD4, 0x34, 0x27, 0x60, 0x1A, 0xB9,
++   0xAF, 0x89, 0xEB, 0x8F, 0x6A, 0x13, 0x05, 0xF0,
++   0x77, 0x5F, 0x4F, 0x58, 0x2C, 0xE7, 0xCE, 0xED,
++   0xC0, 0x0D, 0x3A, 0xA7, 0xE2, 0x38, 0x5B, 0xE9,
++   0x3D, 0xF2, 0xDF, 0x86, 0xE0, 0x72, 0xF7, 0x88,
++   0xAD, 0xB7, 0x11, 0xDB, 0x73, 0x87, 0xC5, 0x22,
++   0xE1, 0x5C, 0xD6, 0x57, 0x7E, 0x7D, 0xA2, 0xF9,
++   0xF5, 0x9C, 0x25, 0x6F, 0x26, 0x51, 0xC8, 0x80,
++   0x2B, 0xA8, 0x19, 0xD9, 0x65, 0xCD, 0x97, 0xEA,
++   0xFF, 0x5E, 0x24, 0x3B, 0x4D, 0xB1, 0x1C, 0x79,
++   0x39, 0x6B, 0xA5, 0x2A, 0x09, 0xCA, 0x04, 0xEC,
++   0xBA, 0x18, 0x31, 0x46, 0x20, 0xBE, 0x1F, 0x3C,
++   0x6D, 0xAA, 0xF6, 0xDD, 0xF4, 0x96, 0x03, 0x0A,
++   0x9E, 0x83, 0xA1, 0x9D, 0xD5, 0xB0, 0x17, 0xBF,
++   0x56, 0xAB, 0xAE, 0x1B, 0x52, 0xC6, 0x81, 0x4B,
++   0xDC, 0x90, 0x5A, 0x9B, 0xB6, 0x0F, 0xF3, 0x67,
++   0x30, 0x63, 0x7C, 0x40, 0x0E, 0x7F, 0x95, 0x36,
++   0xC4, 0x4E, 0x43, 0xCB, 0x15, 0xB8, 0x00, 0x91,
++   0x8A, 0x4C, 0x8E, 0x14, 0x06, 0x6E, 0xA9, 0x2E,
++   0x3F, 0x48, 0x2F, 0x0C, 0xB5, 0x21, 0xBB, 0xDA,
++   0x8B, 0x42, 0x29, 0x8C, 0x33, 0x59, 0xE8, 0xF8,
++   0xC7, 0xE4, 0x37, 0xE5, 0xFC, 0xBD, 0x99, 0x41 };
++
++unsigned char table_47[32] = {
++   0x18, 0x1D, 0x16, 0x10, 0x11, 0x04, 0x1E, 0x08,
++   0x19, 0x0E, 0x0F, 0x02, 0x14, 0x1C, 0x07, 0x17,
++   0x0D, 0x09, 0x12, 0x1A, 0x05, 0x01, 0x0B, 0x0A,
++   0x13, 0x15, 0x0C, 0x00, 0x06, 0x1F, 0x03, 0x1B };
++
++unsigned char table_48[32] = {
++   0x13, 0x08, 0x15, 0x01, 0x17, 0x10, 0x0F, 0x1F,
++   0x1D, 0x0D, 0x12, 0x03, 0x06, 0x0A, 0x1C, 0x19,
++   0x1A, 0x04, 0x1B, 0x02, 0x16, 0x1E, 0x11, 0x00,
++   0x14, 0x09, 0x0C, 0x18, 0x05, 0x07, 0x0E, 0x0B };
++
++unsigned char table_49[32] = {
++   0x1F, 0x0F, 0x19, 0x07, 0x18, 0x05, 0x1E, 0x1D,
++   0x15, 0x08, 0x17, 0x10, 0x0A, 0x0E, 0x0C, 0x1B,
++   0x02, 0x13, 0x03, 0x0D, 0x04, 0x1A, 0x06, 0x09,
++   0x12, 0x1C, 0x0B, 0x16, 0x14, 0x01, 0x11, 0x00 };
++
++unsigned char table_50[32] = {
++   0x16, 0x18, 0x1C, 0x0E, 0x12, 0x00, 0x04, 0x1B,
++   0x1F, 0x13, 0x17, 0x0A, 0x1E, 0x03, 0x0C, 0x01,
++   0x0F, 0x10, 0x02, 0x08, 0x14, 0x09, 0x19, 0x15,
++   0x06, 0x0D, 0x0B, 0x1D, 0x05, 0x07, 0x11, 0x1A };
++
++unsigned char table_51[32] = {
++   0x1C, 0x0D, 0x1B, 0x07, 0x17, 0x0E, 0x06, 0x01,
++   0x12, 0x19, 0x03, 0x0B, 0x10, 0x08, 0x00, 0x1E,
++   0x0A, 0x04, 0x1A, 0x1D, 0x0C, 0x18, 0x02, 0x13,
++   0x0F, 0x11, 0x05, 0x09, 0x15, 0x16, 0x1F, 0x14 };
++
++unsigned char table_52[256] = {
++   0x34, 0x0B, 0x47, 0xA3, 0x56, 0x30, 0x73, 0xD4,
++   0x4B, 0xF6, 0xA6, 0x80, 0x22, 0x95, 0xA5, 0xBB,
++   0xFE, 0xCD, 0x27, 0x88, 0x87, 0x18, 0x86, 0x6E,
++   0xB9, 0x07, 0x37, 0x52, 0x0A, 0x28, 0x2C, 0xC4,
++   0x75, 0xA1, 0x29, 0x54, 0x84, 0x08, 0x72, 0x51,
++   0xDD, 0xF1, 0x4E, 0x1A, 0x90, 0x57, 0x20, 0xAD,
++   0x68, 0x61, 0xAF, 0x50, 0x6B, 0x1B, 0x71, 0xEB,
++   0x63, 0xC9, 0xB0, 0x58, 0x26, 0x40, 0xC7, 0xD9,
++   0x70, 0xA2, 0x9A, 0x09, 0x3F, 0x92, 0x0D, 0x8C,
++   0xC1, 0x96, 0x9F, 0x77, 0x4D, 0x5A, 0xEA, 0x11,
++   0xD7, 0xF3, 0x33, 0x93, 0x10, 0xF2, 0x9D, 0x83,
++   0xFF, 0x7E, 0xD2, 0x41, 0x24, 0xB4, 0x8D, 0x5C,
++   0xCF, 0xEF, 0xE9, 0x64, 0x76, 0xD1, 0xDE, 0xE4,
++   0x91, 0x35, 0x89, 0x19, 0x02, 0x0E, 0xF4, 0x2A,
++   0x0F, 0xE1, 0xA8, 0x2D, 0x21, 0x23, 0xAA, 0x7C,
++   0x78, 0x45, 0xA9, 0xDC, 0x06, 0xF9, 0xDF, 0xF7,
++   0x03, 0xAB, 0xB5, 0x1C, 0x36, 0x7B, 0x97, 0xFA,
++   0xE5, 0x3B, 0x2F, 0x1F, 0x9E, 0xED, 0xA7, 0x55,
++   0x42, 0x6F, 0x1E, 0xB7, 0xE6, 0xFB, 0x12, 0xD5,
++   0x99, 0xC6, 0x66, 0x4A, 0xE8, 0x48, 0x60, 0xB1,
++   0x05, 0x53, 0x8A, 0xB6, 0x25, 0x8F, 0xA4, 0xD8,
++   0x9C, 0xC0, 0x59, 0x3A, 0xBD, 0xDB, 0x44, 0x5E,
++   0xE3, 0xDA, 0x1D, 0x32, 0xF5, 0xBA, 0x43, 0x13,
++   0x82, 0x4C, 0xE7, 0x17, 0x15, 0x3E, 0x69, 0x2E,
++   0xC3, 0xF0, 0x5F, 0xFD, 0xCE, 0xD3, 0xCA, 0x39,
++   0xD6, 0x79, 0x3D, 0xC8, 0x67, 0x8B, 0x31, 0x4F,
++   0xB3, 0xBC, 0x65, 0x00, 0x7A, 0x98, 0xC5, 0x6C,
++   0x2B, 0x94, 0x6D, 0x74, 0x14, 0xAC, 0xCC, 0xA0,
++   0x5B, 0xF8, 0xCB, 0x7F, 0xB2, 0xEC, 0xBF, 0x3C,
++   0xE0, 0xAE, 0xFC, 0x62, 0x04, 0x8E, 0x85, 0x49,
++   0x9B, 0xC2, 0x38, 0xD0, 0xEE, 0x81, 0x46, 0xE2,
++   0x01, 0x0C, 0x5D, 0x7D, 0xB8, 0xBE, 0x6A, 0x16 };
++
++unsigned char table_53[256] = {
++   0xE3, 0xF4, 0x8D, 0x72, 0x45, 0x32, 0x9D, 0xCE,
++   0x1F, 0x6B, 0xBC, 0xDC, 0xF1, 0xEC, 0x5A, 0x3B,
++   0xA5, 0xA2, 0x2B, 0xDD, 0x8A, 0xA3, 0x76, 0xE4,
++   0xAF, 0xE9, 0xE1, 0x21, 0xDB, 0x9F, 0x19, 0xD3,
++   0x26, 0x80, 0x15, 0xC2, 0x46, 0xB8, 0x17, 0x56,
++   0x99, 0x81, 0x08, 0xD7, 0xEF, 0x8E, 0x04, 0x05,
++   0x97, 0x2F, 0x78, 0xAD, 0xA1, 0x52, 0x36, 0x58,
++   0x53, 0x68, 0x22, 0x70, 0x0B, 0x79, 0xE6, 0xFA,
++   0xC3, 0x91, 0xE2, 0xF7, 0xF6, 0x75, 0x2D, 0x0A,
++   0x90, 0xEB, 0xA6, 0x35, 0xA7, 0x10, 0xB5, 0xFB,
++   0xE7, 0xAA, 0x1E, 0x43, 0xBB, 0x3C, 0x65, 0x25,
++   0x2C, 0x59, 0x62, 0x2A, 0xF9, 0x4B, 0x95, 0x5E,
++   0x20, 0x11, 0x42, 0x27, 0x44, 0xE8, 0x14, 0x6F,
++   0xD1, 0xD8, 0x00, 0x3A, 0x5B, 0x18, 0x89, 0x02,
++   0x61, 0xD6, 0xC5, 0x98, 0xD0, 0x5F, 0x34, 0x29,
++   0xFD, 0x31, 0x1A, 0xCD, 0x0F, 0x9E, 0xCA, 0x7B,
++   0xEA, 0x93, 0x71, 0x5C, 0x0E, 0x57, 0x33, 0xC4,
++   0x37, 0xF5, 0x83, 0xB0, 0xDF, 0x49, 0x74, 0x54,
++   0x1D, 0x24, 0xB9, 0x16, 0x1C, 0x28, 0xDE, 0x4A,
++   0xF0, 0x01, 0x86, 0x82, 0xCC, 0x12, 0x8C, 0x06,
++   0x30, 0xA8, 0x7A, 0x73, 0x66, 0x7C, 0xC6, 0xB6,
++   0xF2, 0x13, 0xBF, 0x40, 0x85, 0x77, 0x09, 0x3D,
++   0x67, 0x63, 0x3F, 0x7F, 0xF3, 0x87, 0x8F, 0xFF,
++   0x92, 0xC7, 0x4C, 0x23, 0xBA, 0xCB, 0xB1, 0xED,
++   0x0C, 0x60, 0x47, 0xFE, 0x38, 0x5D, 0xCF, 0x8B,
++   0x4D, 0xA9, 0x2E, 0xE5, 0xA4, 0x1B, 0x88, 0x3E,
++   0x7D, 0xF8, 0xC0, 0xD5, 0x6D, 0x6C, 0x48, 0xAC,
++   0x9B, 0x51, 0x7E, 0x6E, 0x50, 0x0D, 0x9A, 0xB3,
++   0xEE, 0x07, 0x4F, 0x69, 0x9C, 0x03, 0xD9, 0xD4,
++   0xB4, 0xD2, 0xAE, 0x4E, 0x55, 0xB7, 0xC9, 0x41,
++   0x39, 0x6A, 0xC8, 0xA0, 0xB2, 0xC1, 0x84, 0xFC,
++   0xAB, 0x64, 0xE0, 0xBE, 0xDA, 0xBD, 0x96, 0x94 };
++
++unsigned char table_54[32] = {
++   0x01, 0x02, 0x1D, 0x10, 0x0E, 0x11, 0x08, 0x14,
++   0x12, 0x09, 0x15, 0x17, 0x16, 0x04, 0x06, 0x1B,
++   0x07, 0x1A, 0x18, 0x13, 0x0A, 0x1E, 0x1C, 0x1F,
++   0x0C, 0x0B, 0x0D, 0x05, 0x0F, 0x00, 0x19, 0x03 };
++
++unsigned char table_55[32] = {
++   0x01, 0x12, 0x13, 0x09, 0x0B, 0x19, 0x03, 0x0E,
++   0x02, 0x1F, 0x1D, 0x1B, 0x1E, 0x11, 0x06, 0x05,
++   0x00, 0x16, 0x07, 0x0C, 0x15, 0x0D, 0x1A, 0x08,
++   0x18, 0x10, 0x0F, 0x17, 0x1C, 0x0A, 0x04, 0x14 };
++
++unsigned char table_56[256] = {
++   0xEF, 0x06, 0x5F, 0x11, 0x4B, 0x60, 0x13, 0xBB,
++   0x79, 0xD7, 0xE4, 0x6D, 0x22, 0xB4, 0x15, 0x50,
++   0x29, 0x17, 0xD2, 0xE3, 0x37, 0x8C, 0x46, 0x7C,
++   0xA2, 0xF5, 0x65, 0x16, 0xCB, 0x04, 0x3E, 0xDF,
++   0x8E, 0xDE, 0x53, 0xF1, 0xF4, 0xD1, 0x3B, 0xEE,
++   0x9A, 0x09, 0x9B, 0x6C, 0xF6, 0xCC, 0xFB, 0x40,
++   0xE0, 0xFD, 0x2B, 0x1D, 0x73, 0x18, 0xCD, 0x31,
++   0x3F, 0x9E, 0xAD, 0xC9, 0x43, 0x4E, 0x99, 0x3A,
++   0x8F, 0x92, 0x85, 0xFC, 0x12, 0x41, 0x20, 0xE8,
++   0x2A, 0xC0, 0x1C, 0x38, 0x74, 0x0B, 0xF3, 0x05,
++   0x0D, 0x1F, 0x94, 0x9C, 0xAC, 0x00, 0x59, 0x0C,
++   0xB3, 0x8D, 0xA8, 0x75, 0xB7, 0x68, 0x2F, 0x27,
++   0x6F, 0x69, 0x76, 0xD8, 0xEC, 0xA5, 0xB2, 0x6A,
++   0x19, 0x72, 0x1A, 0xB6, 0xE5, 0x77, 0xC6, 0x44,
++   0x9D, 0xCA, 0x82, 0x35, 0x36, 0x5E, 0xA9, 0x25,
++   0xFA, 0x5C, 0x24, 0x30, 0x39, 0x0E, 0x2C, 0x7D,
++   0xE6, 0x88, 0xA0, 0x63, 0xB8, 0x6B, 0x01, 0xDD,
++   0xDA, 0x9F, 0x45, 0x83, 0xE2, 0x7F, 0x1B, 0x56,
++   0xAF, 0x14, 0xC3, 0x49, 0xBF, 0x78, 0x70, 0x58,
++   0x23, 0xA3, 0xBD, 0x34, 0x47, 0x2D, 0x0A, 0xD4,
++   0x33, 0x03, 0x1E, 0xC1, 0x87, 0xAE, 0x3C, 0x95,
++   0xB0, 0x42, 0x91, 0xB9, 0x5A, 0x61, 0xAA, 0xCF,
++   0xF2, 0x51, 0xA6, 0xF8, 0xDC, 0x71, 0xAB, 0x48,
++   0x66, 0x90, 0x97, 0xC4, 0x08, 0xF9, 0xD0, 0x7B,
++   0xDB, 0xBA, 0x8B, 0xC2, 0xC5, 0x2E, 0xF7, 0x5B,
++   0xFF, 0x21, 0x81, 0x54, 0xD3, 0x62, 0x57, 0x4C,
++   0x6E, 0x02, 0x98, 0xFE, 0x7E, 0xE7, 0xBC, 0x07,
++   0x28, 0x5D, 0x86, 0xCE, 0xEA, 0x84, 0xF0, 0xE1,
++   0x93, 0x80, 0xE9, 0xC7, 0x4A, 0xED, 0xB1, 0x26,
++   0x89, 0x3D, 0x4F, 0xA7, 0xA1, 0xD6, 0xB5, 0x4D,
++   0x67, 0xA4, 0x55, 0x10, 0x0F, 0xD9, 0x52, 0x32,
++   0x96, 0xD5, 0xEB, 0x64, 0x8A, 0xC8, 0x7A, 0xBE };
++
++unsigned char table_57[256] = {
++   0xD1, 0x9B, 0x15, 0x06, 0xB4, 0xF6, 0x97, 0xF0,
++   0xC6, 0x5B, 0x88, 0x12, 0x25, 0xFA, 0x7B, 0x79,
++   0xD6, 0xAB, 0xDC, 0x47, 0x85, 0x61, 0x67, 0x0B,
++   0xF3, 0x20, 0x44, 0x53, 0x2A, 0x3B, 0x2D, 0xE8,
++   0x17, 0x71, 0xC3, 0xB7, 0x7F, 0x35, 0xEB, 0x10,
++   0x03, 0x0D, 0x60, 0x96, 0x27, 0xBB, 0x39, 0x50,
++   0x95, 0x55, 0xCC, 0xD4, 0x2F, 0x51, 0xB3, 0x05,
++   0xA5, 0xAD, 0xBC, 0x18, 0xE2, 0xAE, 0x07, 0x87,
++   0xC4, 0x8D, 0xBE, 0x77, 0xC2, 0x16, 0xFC, 0x33,
++   0x4C, 0x4F, 0xE6, 0xA6, 0x57, 0x9F, 0x37, 0x91,
++   0xED, 0x4A, 0xF7, 0xB5, 0x52, 0x7C, 0xBD, 0x30,
++   0xA0, 0x2C, 0x8C, 0xB0, 0x0C, 0xDA, 0x6F, 0x9E,
++   0xEE, 0x43, 0x40, 0x8F, 0x8B, 0x76, 0xA4, 0x68,
++   0xFF, 0x6D, 0x58, 0xC9, 0xF9, 0x6E, 0x3F, 0x56,
++   0xCA, 0x49, 0xC8, 0x5D, 0xCD, 0xC7, 0x99, 0xEC,
++   0x72, 0x38, 0x0A, 0xA9, 0xC5, 0x04, 0x64, 0xBF,
++   0xB6, 0x29, 0x80, 0x2E, 0x19, 0x0E, 0x82, 0x45,
++   0xBA, 0xD7, 0x1E, 0x86, 0xA8, 0xD8, 0x24, 0xDB,
++   0xCF, 0xE1, 0x54, 0xB2, 0x3E, 0x4D, 0x90, 0x42,
++   0x5F, 0x59, 0x0F, 0xCE, 0x8E, 0xA2, 0xA7, 0x1D,
++   0x22, 0xFD, 0x81, 0x63, 0xE5, 0x6A, 0xE7, 0x93,
++   0x41, 0x46, 0x66, 0x89, 0x13, 0xEA, 0x69, 0x1C,
++   0x83, 0xF2, 0x08, 0xB8, 0x01, 0x23, 0x26, 0xFB,
++   0x78, 0xAA, 0x31, 0x11, 0x1B, 0x98, 0xDD, 0xAC,
++   0xB9, 0xFE, 0x94, 0x74, 0xAF, 0x32, 0xD0, 0x5A,
++   0xA1, 0xF4, 0x6B, 0x8A, 0xE3, 0x65, 0xDE, 0xCB,
++   0x73, 0x3D, 0xA3, 0x7E, 0xDF, 0xD2, 0x6C, 0x7A,
++   0x36, 0xD9, 0x62, 0x4B, 0xEF, 0xC1, 0x1F, 0x00,
++   0x34, 0xB1, 0xF8, 0xE4, 0xD5, 0x09, 0x1A, 0x9A,
++   0x70, 0x48, 0x9D, 0xF1, 0xE0, 0x9C, 0xD3, 0x5C,
++   0x75, 0x02, 0x2B, 0x92, 0x21, 0x7D, 0xF5, 0x5E,
++   0x4E, 0x3C, 0x84, 0x14, 0x28, 0x3A, 0xE9, 0xC0 };
++
++unsigned char table_58[256] = {
++   0xE9, 0x81, 0x60, 0xA7, 0x18, 0xA0, 0x0F, 0x55,
++   0x2B, 0x52, 0xE0, 0x8B, 0x9D, 0x85, 0xD2, 0xA3,
++   0x3F, 0x6E, 0xB1, 0xAF, 0xE3, 0x36, 0xE2, 0x19,
++   0x56, 0xB0, 0x09, 0xB5, 0x79, 0x43, 0xE1, 0x06,
++   0x45, 0xB6, 0xC0, 0x22, 0xEE, 0x41, 0xEC, 0x01,
++   0x66, 0x2D, 0x87, 0x38, 0x16, 0x37, 0xFA, 0x29,
++   0x96, 0xA4, 0xC3, 0x23, 0x59, 0x7E, 0x92, 0x78,
++   0x10, 0x2A, 0x4C, 0x0E, 0x9B, 0x4A, 0x35, 0xF4,
++   0x42, 0x0C, 0xD8, 0xD7, 0x24, 0x2C, 0xDD, 0x8E,
++   0x5B, 0xF5, 0x33, 0x48, 0xEF, 0xDE, 0x4B, 0xBC,
++   0x51, 0xAB, 0x7C, 0xE4, 0x63, 0x70, 0x9A, 0xAC,
++   0x54, 0x1D, 0x25, 0xC5, 0xEA, 0xB3, 0x05, 0xF7,
++   0xC1, 0x1F, 0xE8, 0x97, 0xBB, 0x32, 0x6D, 0xC7,
++   0x28, 0x61, 0xDB, 0x4D, 0x77, 0x72, 0x65, 0x8C,
++   0x80, 0x3A, 0x76, 0x47, 0xA8, 0x03, 0x04, 0x12,
++   0xCE, 0xA9, 0x75, 0x3C, 0x49, 0xF8, 0x64, 0xDF,
++   0x57, 0xA2, 0x69, 0x44, 0xAD, 0x3E, 0x4F, 0x0B,
++   0x74, 0x67, 0xC9, 0x1A, 0x17, 0xAA, 0x02, 0x6F,
++   0xDA, 0xF2, 0xC6, 0x27, 0x53, 0xD6, 0xFD, 0xCA,
++   0x8D, 0x93, 0x89, 0xD5, 0x6B, 0x4E, 0x90, 0x82,
++   0x30, 0xE7, 0xC4, 0xD9, 0x8A, 0x7F, 0xB4, 0xFC,
++   0xCF, 0xA1, 0xAE, 0x1C, 0x39, 0x1B, 0x7B, 0x5E,
++   0x88, 0x7D, 0xD3, 0x71, 0x2E, 0x98, 0x13, 0x8F,
++   0xCC, 0x84, 0x73, 0xCD, 0x21, 0x0D, 0x5C, 0xA5,
++   0x3D, 0x9E, 0x99, 0xC2, 0xF3, 0x34, 0x14, 0x62,
++   0x46, 0x0A, 0x07, 0x08, 0xFF, 0xFB, 0xB7, 0xBF,
++   0x5D, 0x91, 0xB8, 0x83, 0xBE, 0x94, 0xBA, 0xF9,
++   0xEB, 0xE5, 0xCB, 0x95, 0x40, 0x31, 0xE6, 0x86,
++   0xD4, 0xFE, 0xD0, 0x7A, 0x26, 0xB9, 0xDC, 0x2F,
++   0xBD, 0xF0, 0x5F, 0x00, 0x9C, 0x6A, 0x5A, 0x3B,
++   0xF1, 0xC8, 0x9F, 0xED, 0x50, 0x20, 0x15, 0x11,
++   0x68, 0x1E, 0xF6, 0xA6, 0x6C, 0xB2, 0xD1, 0x58 };
++
++unsigned char table_59[256] = {
++   0x4C, 0x85, 0x2B, 0x14, 0xCC, 0x4D, 0x5F, 0xD7,
++   0xCE, 0x28, 0xC5, 0x0B, 0xA1, 0x99, 0x08, 0xDE,
++   0x42, 0xD1, 0x82, 0x5C, 0xC9, 0x8F, 0x72, 0x12,
++   0xCB, 0x0D, 0x04, 0xFA, 0xCD, 0xE5, 0x9A, 0x6F,
++   0xCF, 0x92, 0xB5, 0x88, 0x87, 0xBF, 0x90, 0x7C,
++   0xAC, 0xBE, 0x36, 0x21, 0x7D, 0x7F, 0xC7, 0x9F,
++   0x75, 0xBB, 0x61, 0x16, 0x17, 0x63, 0xAE, 0xC4,
++   0x23, 0x89, 0xE0, 0x37, 0x91, 0x5E, 0xC8, 0xE4,
++   0xFD, 0xD5, 0xA2, 0xC6, 0x5A, 0xEF, 0x9B, 0xD6,
++   0x27, 0xEE, 0x60, 0x1C, 0xDF, 0xDA, 0xF1, 0xD2,
++   0x1E, 0x01, 0x9D, 0x44, 0x03, 0xD8, 0x11, 0x53,
++   0x4F, 0x6C, 0x8B, 0xB7, 0x40, 0xF2, 0x79, 0x20,
++   0x74, 0x97, 0x3E, 0x3D, 0x05, 0xD4, 0x70, 0x30,
++   0x54, 0x59, 0xE7, 0x15, 0xE1, 0xEB, 0x71, 0x83,
++   0xFE, 0x66, 0xB1, 0xA6, 0xF7, 0x8E, 0x6A, 0xEA,
++   0x65, 0x7E, 0xA3, 0xCA, 0x2D, 0x4B, 0xB8, 0x9C,
++   0x35, 0xC3, 0xB6, 0x49, 0x32, 0x25, 0xB3, 0xB0,
++   0x76, 0xC0, 0xF5, 0x00, 0x8A, 0xAF, 0x19, 0xDB,
++   0xDD, 0x47, 0xDC, 0x07, 0xB2, 0x4A, 0x55, 0xE6,
++   0x69, 0xEC, 0xED, 0x06, 0x94, 0xB9, 0xA7, 0x56,
++   0x2C, 0xAA, 0xE3, 0x22, 0x3B, 0x98, 0x77, 0x52,
++   0x3C, 0x64, 0xF8, 0x13, 0x78, 0xFC, 0xFB, 0xF3,
++   0xD3, 0xF9, 0x29, 0x45, 0x51, 0x8C, 0xA0, 0x38,
++   0xD9, 0xA5, 0x62, 0x3A, 0x6E, 0xD0, 0xE8, 0x7A,
++   0x33, 0x1D, 0xB4, 0x73, 0x02, 0xFF, 0x10, 0x80,
++   0x6B, 0xF0, 0xA4, 0xBA, 0xF6, 0xC2, 0x0E, 0xE2,
++   0x81, 0x43, 0x84, 0x86, 0x1F, 0x31, 0x2F, 0xA9,
++   0x1B, 0x2A, 0x4E, 0xF4, 0x95, 0x5B, 0x3F, 0x34,
++   0x39, 0x7B, 0x0A, 0x26, 0x6D, 0x57, 0x50, 0x09,
++   0x9E, 0xA8, 0xBC, 0x24, 0x93, 0x67, 0x41, 0x96,
++   0x0C, 0x46, 0xBD, 0xE9, 0x68, 0x18, 0xAB, 0x2E,
++   0x5D, 0x1A, 0x8D, 0xC1, 0x58, 0x48, 0xAD, 0x0F };
++
++unsigned char table_60[32] = {
++   0x1C, 0x06, 0x1E, 0x10, 0x1D, 0x05, 0x00, 0x0E,
++   0x0C, 0x02, 0x11, 0x19, 0x15, 0x18, 0x16, 0x07,
++   0x1F, 0x0B, 0x14, 0x01, 0x0F, 0x09, 0x0D, 0x13,
++   0x03, 0x08, 0x12, 0x04, 0x1B, 0x0A, 0x17, 0x1A };
++
++unsigned char table_61[256] = {
++   0xC5, 0xA6, 0xF2, 0x6B, 0x4B, 0x58, 0xE0, 0x41,
++   0xC6, 0x2F, 0x13, 0xFE, 0xC1, 0x34, 0x3F, 0x24,
++   0x10, 0xBF, 0x8B, 0xC9, 0x26, 0x2E, 0x68, 0xBE,
++   0x28, 0x54, 0x93, 0x11, 0x21, 0x03, 0xFF, 0x50,
++   0x31, 0x71, 0x2C, 0x6C, 0x91, 0x8F, 0x3B, 0x40,
++   0x3E, 0xE5, 0xA5, 0x80, 0xEA, 0x7C, 0x9D, 0x18,
++   0x84, 0x5A, 0x73, 0x3A, 0x33, 0x43, 0xA1, 0x47,
++   0xB1, 0xEE, 0xFB, 0x79, 0x5E, 0xAF, 0xB9, 0x48,
++   0x0F, 0x88, 0x65, 0x67, 0x6F, 0xDB, 0x25, 0xE4,
++   0xB0, 0x87, 0xD0, 0x46, 0xB5, 0xB7, 0x53, 0xD4,
++   0x1E, 0x76, 0xB4, 0x90, 0xDD, 0xA3, 0xF7, 0x57,
++   0xD2, 0xCC, 0x5D, 0xE3, 0xB3, 0xD8, 0x5F, 0x2B,
++   0x69, 0x4A, 0x9B, 0x39, 0x1A, 0x8D, 0x05, 0x8A,
++   0x44, 0x15, 0xAE, 0xF3, 0xA8, 0x92, 0x02, 0xAB,
++   0xB8, 0xDA, 0x0A, 0x0C, 0xED, 0xD7, 0x77, 0x98,
++   0x3D, 0x19, 0x95, 0x36, 0xE7, 0x7F, 0x66, 0xEF,
++   0x86, 0xDC, 0xCB, 0x9C, 0x63, 0xE6, 0x1D, 0x14,
++   0x9A, 0x22, 0xBD, 0xD6, 0x89, 0x2D, 0xD1, 0xF9,
++   0xA2, 0xDE, 0xF5, 0x5C, 0x8E, 0x2A, 0x29, 0xCA,
++   0x7A, 0x8C, 0x38, 0x9F, 0xBB, 0xDF, 0xEC, 0x30,
++   0x00, 0xFC, 0xAC, 0x81, 0xB2, 0xE8, 0xC0, 0xA7,
++   0x7B, 0x07, 0x52, 0x74, 0x70, 0x0E, 0x51, 0x6A,
++   0x62, 0x0D, 0x85, 0x1B, 0x4F, 0x96, 0x55, 0x1C,
++   0x32, 0x6E, 0x01, 0xF6, 0x08, 0xFD, 0x17, 0x35,
++   0xF0, 0x16, 0xC8, 0x23, 0xE9, 0x59, 0x3C, 0x37,
++   0x5B, 0x42, 0xD3, 0x49, 0x7D, 0x83, 0x78, 0xAD,
++   0x94, 0x9E, 0x56, 0xB6, 0xF1, 0xC3, 0x75, 0xF8,
++   0xFA, 0x09, 0x4C, 0xD9, 0x97, 0xF4, 0x7E, 0x6D,
++   0xBC, 0x4D, 0x64, 0xCD, 0x12, 0x99, 0x45, 0xCE,
++   0x61, 0x20, 0x0B, 0xA0, 0x82, 0xD5, 0xE1, 0x72,
++   0xA9, 0x1F, 0x06, 0x27, 0xC7, 0x04, 0xE2, 0xBA,
++   0xCF, 0x60, 0xAA, 0xA4, 0xEB, 0xC4, 0x4E, 0xC2 };
++
++unsigned char table_62[256] = {
++   0x01, 0x59, 0xEC, 0xFC, 0x51, 0xD2, 0xE4, 0x9D,
++   0xAA, 0x61, 0xD5, 0xCA, 0x63, 0x5D, 0xCE, 0x36,
++   0xB9, 0x49, 0x76, 0xA9, 0x14, 0x4C, 0x90, 0x28,
++   0x66, 0x17, 0x4F, 0x1E, 0x1A, 0x47, 0x30, 0xE8,
++   0xFD, 0x86, 0x2E, 0x7B, 0x7E, 0xCC, 0x34, 0x13,
++   0x94, 0x45, 0x38, 0x74, 0x29, 0xB0, 0x37, 0xC3,
++   0x26, 0x6C, 0x39, 0xA3, 0x89, 0xEB, 0xA2, 0x20,
++   0x00, 0xE0, 0x73, 0xE7, 0xB5, 0xCB, 0xED, 0x3E,
++   0x79, 0x09, 0xFA, 0x32, 0x54, 0xBA, 0x05, 0x96,
++   0xDE, 0x23, 0xD0, 0xA1, 0xAB, 0xFE, 0xF2, 0x22,
++   0xB2, 0x9B, 0x7D, 0x44, 0x12, 0x3D, 0x40, 0x82,
++   0xA0, 0xA8, 0x33, 0xDC, 0xF7, 0xFB, 0xAC, 0x41,
++   0x8A, 0x9C, 0x60, 0x11, 0xC8, 0xF0, 0xEA, 0x57,
++   0x3A, 0x42, 0xCD, 0x1D, 0x3C, 0xC6, 0x97, 0x62,
++   0x55, 0x9F, 0xF3, 0x93, 0x91, 0xDA, 0x6A, 0xE5,
++   0x27, 0x8E, 0x4E, 0xFF, 0xA4, 0x80, 0x04, 0xE1,
++   0x2B, 0x5E, 0xC0, 0x64, 0xC2, 0xD8, 0x46, 0x8C,
++   0xD4, 0x0F, 0xC4, 0x43, 0xD9, 0x9E, 0x4B, 0x5C,
++   0x0A, 0x8B, 0xBF, 0xD7, 0x7A, 0x81, 0x3B, 0x4A,
++   0x58, 0xB6, 0x21, 0x1F, 0xC1, 0xBD, 0xB1, 0x77,
++   0x72, 0x1C, 0x4D, 0xBC, 0xA5, 0x65, 0xC7, 0xF5,
++   0xB4, 0x2D, 0x69, 0x71, 0xE6, 0x8F, 0xBB, 0x03,
++   0xAF, 0xD6, 0x08, 0x75, 0xB7, 0x31, 0xF4, 0x2A,
++   0x48, 0x70, 0x0C, 0x8D, 0xD1, 0x87, 0x2F, 0x16,
++   0x5A, 0x5B, 0x98, 0xA6, 0xC5, 0x99, 0x50, 0x07,
++   0xDD, 0x92, 0x25, 0x68, 0x0D, 0xBE, 0x78, 0x0B,
++   0xAD, 0x84, 0x6B, 0x19, 0x52, 0x7C, 0xF6, 0xB3,
++   0x56, 0x83, 0x88, 0xEE, 0x2C, 0x1B, 0x6E, 0x53,
++   0x67, 0xE2, 0x6F, 0x15, 0x06, 0x10, 0x18, 0x85,
++   0xF1, 0x6D, 0xF9, 0xC9, 0xAE, 0x3F, 0xB8, 0x95,
++   0x35, 0xDF, 0xEF, 0xA7, 0x7F, 0x24, 0xF8, 0xE3,
++   0xCF, 0xE9, 0xDB, 0xD3, 0x02, 0x9A, 0x0E, 0x5F };
++
++unsigned char table_63[256] = {
++   0x0C, 0x02, 0xEE, 0x94, 0x2D, 0x76, 0x96, 0x75,
++   0x21, 0xDC, 0x37, 0x03, 0xC0, 0xF7, 0xDF, 0xEF,
++   0xB1, 0x1D, 0xCF, 0x15, 0x5A, 0xB4, 0xCC, 0x81,
++   0x89, 0x6B, 0xA5, 0x2E, 0x6D, 0xD4, 0x08, 0x44,
++   0x2A, 0x60, 0x50, 0xBF, 0x40, 0x7D, 0x5F, 0x64,
++   0x93, 0x70, 0xA4, 0x7F, 0xC9, 0xEB, 0x0A, 0xF8,
++   0x9F, 0xA8, 0xBC, 0x25, 0xE5, 0xF3, 0x1B, 0xD7,
++   0x29, 0x13, 0x0D, 0x69, 0x20, 0x5C, 0x0F, 0x91,
++   0x4F, 0x62, 0x06, 0x26, 0x41, 0xED, 0xDA, 0x53,
++   0x65, 0xFF, 0xCD, 0x3F, 0xF6, 0x01, 0xCE, 0xA2,
++   0x04, 0xDE, 0x27, 0x87, 0xBA, 0x86, 0x24, 0x78,
++   0xAF, 0xE1, 0x3D, 0xD0, 0xC8, 0x1F, 0x4A, 0x2C,
++   0x9A, 0xF0, 0xCB, 0xAD, 0x0B, 0x59, 0xC5, 0x58,
++   0xEA, 0x8A, 0xA1, 0x45, 0xB7, 0x5D, 0xB5, 0x77,
++   0x2B, 0x47, 0x05, 0x00, 0xAC, 0x61, 0xFA, 0x33,
++   0x74, 0x31, 0xCA, 0x22, 0x42, 0x8B, 0xFE, 0x09,
++   0xB2, 0x6E, 0x1A, 0xBE, 0xAA, 0x7B, 0xEC, 0xF4,
++   0x51, 0x66, 0x28, 0x12, 0xFC, 0x5E, 0x67, 0xF5,
++   0xB9, 0x82, 0x90, 0x8E, 0x8D, 0x17, 0xE7, 0xE8,
++   0xB0, 0xC3, 0x16, 0xA0, 0x4B, 0xB6, 0xFB, 0x7E,
++   0xC4, 0x85, 0x4C, 0x1E, 0xC7, 0x39, 0x4E, 0xA9,
++   0xE3, 0x4D, 0x32, 0x72, 0x35, 0x80, 0xE0, 0x34,
++   0xB8, 0x73, 0x98, 0x49, 0x92, 0x30, 0xD5, 0xD2,
++   0xA3, 0x54, 0x7A, 0x84, 0x8F, 0x6C, 0xFD, 0x43,
++   0x3A, 0x36, 0x3B, 0xD9, 0x48, 0x6A, 0x14, 0x79,
++   0xD1, 0x57, 0x88, 0xDB, 0xE4, 0x9B, 0xF9, 0x99,
++   0x10, 0x71, 0xC1, 0x68, 0x9E, 0x11, 0xAB, 0xBD,
++   0x7C, 0x3E, 0x3C, 0x18, 0x9D, 0x97, 0xF2, 0xE6,
++   0xA6, 0xF1, 0x46, 0xC2, 0x19, 0xBB, 0x52, 0xD8,
++   0x95, 0xD3, 0x23, 0xAE, 0x07, 0x2F, 0xE9, 0x63,
++   0x1C, 0x55, 0x6F, 0x9C, 0x56, 0x38, 0xC6, 0x5B,
++   0x8C, 0xE2, 0x83, 0xA7, 0xD6, 0x0E, 0xB3, 0xDD };
++
++unsigned char table_64[32] = {
++   0x03, 0x05, 0x0D, 0x09, 0x1A, 0x16, 0x08, 0x10,
++   0x06, 0x1E, 0x1C, 0x15, 0x02, 0x04, 0x17, 0x0C,
++   0x18, 0x0B, 0x19, 0x11, 0x1B, 0x14, 0x13, 0x0A,
++   0x0E, 0x00, 0x1D, 0x1F, 0x01, 0x0F, 0x07, 0x12 };
++
++unsigned char table_65[32] = {
++   0x01, 0x0A, 0x1E, 0x14, 0x10, 0x1D, 0x0D, 0x17,
++   0x0E, 0x0C, 0x0F, 0x12, 0x04, 0x1A, 0x05, 0x02,
++   0x08, 0x1C, 0x09, 0x1F, 0x0B, 0x13, 0x19, 0x1B,
++   0x11, 0x00, 0x16, 0x06, 0x03, 0x18, 0x15, 0x07 };
++
++unsigned char table_66[32] = {
++   0x1C, 0x18, 0x0C, 0x09, 0x05, 0x03, 0x15, 0x12,
++   0x0D, 0x02, 0x08, 0x0E, 0x19, 0x07, 0x13, 0x17,
++   0x1E, 0x1D, 0x1F, 0x11, 0x06, 0x0A, 0x0B, 0x14,
++   0x0F, 0x10, 0x01, 0x1B, 0x00, 0x04, 0x1A, 0x16 };
++
++unsigned char table_67[256] = {
++   0x6B, 0x49, 0xC8, 0x86, 0xFF, 0xC0, 0x5D, 0xEF,
++   0xF7, 0x06, 0xE0, 0x98, 0xA9, 0x72, 0x71, 0xD5,
++   0xBA, 0x7F, 0x10, 0xD1, 0xBE, 0x41, 0x9C, 0x40,
++   0x28, 0x8E, 0xE5, 0x74, 0x47, 0x9E, 0x3E, 0x7C,
++   0xB5, 0xCD, 0x3F, 0x20, 0xF2, 0xA6, 0xDC, 0x97,
++   0x32, 0x6D, 0x52, 0xF5, 0x16, 0x05, 0xFE, 0x04,
++   0x3D, 0x53, 0x50, 0x23, 0x39, 0x77, 0x08, 0x60,
++   0x75, 0x18, 0x4A, 0xC6, 0xBB, 0xE7, 0xF1, 0xAB,
++   0xEB, 0x88, 0xB6, 0x82, 0x6E, 0x91, 0xF3, 0x34,
++   0x3A, 0x42, 0x1A, 0xDF, 0xA1, 0xB3, 0x92, 0xBF,
++   0xB7, 0x00, 0xD4, 0xDE, 0x31, 0xF0, 0x1C, 0xDA,
++   0x4F, 0x61, 0x67, 0x2C, 0x07, 0xF9, 0x15, 0xA4,
++   0x7A, 0x26, 0x45, 0x2A, 0x12, 0x9F, 0xF4, 0x14,
++   0x8C, 0x90, 0xFC, 0xC5, 0x4B, 0x87, 0xE2, 0xC7,
++   0xD0, 0x8A, 0xE8, 0xDD, 0xEE, 0x3C, 0x2F, 0x22,
++   0x6A, 0x54, 0x37, 0x9B, 0x84, 0x25, 0x8F, 0xE3,
++   0xD7, 0xD8, 0x4E, 0xAD, 0x0F, 0x4C, 0x56, 0xA2,
++   0xD3, 0xB0, 0x73, 0x0B, 0xAE, 0xEA, 0x1D, 0x01,
++   0x36, 0xB4, 0x2D, 0xC4, 0x19, 0x58, 0x1E, 0x62,
++   0xE9, 0xB2, 0x5B, 0x5A, 0xBD, 0xD6, 0x65, 0x94,
++   0x9A, 0x55, 0xCC, 0x99, 0x1B, 0x85, 0x2B, 0xBC,
++   0x8D, 0x46, 0x81, 0xB8, 0xA3, 0x29, 0x5F, 0x35,
++   0x5C, 0xB1, 0x1F, 0x13, 0x17, 0xCB, 0x51, 0x02,
++   0x09, 0x7E, 0xA7, 0x69, 0x6F, 0x95, 0x30, 0x7B,
++   0xCA, 0x48, 0xAF, 0xAA, 0x0E, 0x44, 0x38, 0xB9,
++   0x0D, 0x11, 0xA0, 0xD9, 0x0C, 0xDB, 0xF8, 0x68,
++   0x33, 0x79, 0x59, 0x66, 0x4D, 0x03, 0xE1, 0x89,
++   0xE4, 0x3B, 0x78, 0xC2, 0x64, 0x6C, 0x27, 0xC9,
++   0xCF, 0xAC, 0xED, 0xFA, 0x5E, 0x2E, 0x76, 0x57,
++   0x93, 0xEC, 0x80, 0xA8, 0xE6, 0xCE, 0xC1, 0xA5,
++   0x9D, 0xD2, 0xC3, 0x0A, 0x7D, 0x70, 0xF6, 0x63,
++   0x24, 0x43, 0x21, 0x83, 0xFB, 0xFD, 0x8B, 0x96 };
++
++unsigned char table_68[256] = {
++   0x93, 0xFF, 0x83, 0x70, 0x12, 0x2D, 0x1C, 0xD6,
++   0xF9, 0xEE, 0xCF, 0x94, 0x7B, 0xB5, 0xA4, 0x84,
++   0x99, 0xF7, 0x67, 0x32, 0xFC, 0x8A, 0xE3, 0xE4,
++   0xCE, 0xC6, 0x77, 0x7E, 0xDA, 0x42, 0x85, 0xF0,
++   0x7D, 0x48, 0x28, 0x79, 0xDE, 0x5B, 0xE2, 0x0F,
++   0x75, 0xC5, 0x2C, 0x4F, 0xF3, 0xEC, 0x14, 0x10,
++   0x9C, 0x6E, 0x59, 0x4A, 0x20, 0x34, 0xA3, 0x89,
++   0xE0, 0x4E, 0x52, 0x88, 0x81, 0x5F, 0x6F, 0x71,
++   0x17, 0x3B, 0x21, 0xB4, 0xCB, 0x9B, 0x18, 0x13,
++   0xE8, 0xE1, 0x02, 0x2E, 0xED, 0x00, 0xA7, 0x1B,
++   0x06, 0xF4, 0x27, 0xDC, 0x35, 0x2F, 0x08, 0x9D,
++   0x7C, 0xC0, 0x36, 0xA6, 0x6B, 0xDF, 0x4C, 0xBC,
++   0xFE, 0xDB, 0xA5, 0xA8, 0x8D, 0x73, 0x7F, 0xC7,
++   0x8E, 0x60, 0x31, 0x61, 0x4B, 0x29, 0xD7, 0xE9,
++   0xBD, 0xAB, 0xCC, 0xFA, 0xD9, 0xEF, 0xC2, 0xD4,
++   0x19, 0x11, 0x15, 0xC9, 0xB1, 0xD5, 0x64, 0x97,
++   0xE7, 0x8F, 0x05, 0x44, 0xF8, 0xF1, 0x58, 0x47,
++   0x2A, 0x03, 0x1F, 0xAF, 0x0D, 0x04, 0x23, 0xB8,
++   0x24, 0x51, 0xB2, 0x54, 0x41, 0x53, 0x5C, 0xAE,
++   0xB7, 0xB3, 0xB6, 0x3D, 0x37, 0x39, 0x55, 0xBF,
++   0x0B, 0x7A, 0x57, 0x3C, 0x0E, 0x40, 0x6A, 0xF5,
++   0x72, 0xDD, 0xBB, 0x8B, 0xAA, 0x46, 0xA0, 0x30,
++   0x56, 0x78, 0x38, 0xBA, 0x9E, 0x92, 0x87, 0xFB,
++   0x66, 0x90, 0x1E, 0xB9, 0x96, 0x65, 0xA2, 0x50,
++   0x1D, 0xC3, 0x26, 0x22, 0xD0, 0x0A, 0x43, 0xF2,
++   0xB0, 0xEB, 0xAC, 0x62, 0x98, 0x3F, 0xD3, 0x69,
++   0xA1, 0x9F, 0x16, 0x95, 0xE6, 0xF6, 0x2B, 0x25,
++   0x1A, 0xD2, 0xBE, 0x09, 0x5D, 0x45, 0xC4, 0xFD,
++   0x5A, 0x07, 0x0C, 0x82, 0x3E, 0x49, 0x74, 0x6C,
++   0x68, 0x5E, 0xCA, 0xEA, 0xCD, 0x9A, 0xAD, 0xD1,
++   0x33, 0x86, 0x76, 0x80, 0xE5, 0xC8, 0xD8, 0xA9,
++   0x8C, 0x6D, 0x91, 0x63, 0x3A, 0x4D, 0xC1, 0x01 };
++
++unsigned char table_69[256] = {
++   0x21, 0x6B, 0x9B, 0xAE, 0x11, 0x5A, 0x91, 0xC2,
++   0x47, 0x8E, 0x87, 0x86, 0x4F, 0xFC, 0x8F, 0x66,
++   0x97, 0x2F, 0x61, 0x9C, 0x5B, 0x4C, 0xB3, 0x14,
++   0x77, 0x48, 0x62, 0xE1, 0x54, 0x64, 0xDD, 0xCD,
++   0x30, 0xB7, 0x2D, 0xD2, 0xC3, 0xC0, 0x0B, 0xD8,
++   0x53, 0x98, 0x16, 0x56, 0x7A, 0x35, 0x50, 0xD9,
++   0xE8, 0x2C, 0x32, 0x55, 0x17, 0x5D, 0x79, 0xEB,
++   0xC8, 0x75, 0x67, 0xE2, 0x4B, 0xBA, 0xFE, 0x57,
++   0x10, 0xF4, 0x70, 0x2A, 0xBB, 0xA6, 0x72, 0x36,
++   0xAF, 0x8D, 0xAB, 0x90, 0xE3, 0x2B, 0xB2, 0x26,
++   0x93, 0x01, 0xBD, 0x71, 0xF9, 0x05, 0xC7, 0x80,
++   0x29, 0xCC, 0x3B, 0x22, 0xF2, 0x12, 0x81, 0x34,
++   0xF6, 0x1A, 0x8B, 0xDF, 0x28, 0x46, 0x9E, 0x6A,
++   0x23, 0x85, 0x74, 0xE7, 0xE6, 0x52, 0xA0, 0x49,
++   0xF0, 0x19, 0x25, 0xAC, 0x78, 0x42, 0xD6, 0xA2,
++   0x37, 0x65, 0x4D, 0x94, 0x02, 0x6F, 0xB4, 0xC6,
++   0x99, 0xD3, 0x9A, 0x33, 0xB8, 0x00, 0xCA, 0xE4,
++   0x45, 0xAD, 0x1B, 0x6C, 0x03, 0xA8, 0x07, 0x8A,
++   0x60, 0x69, 0xFF, 0xF7, 0xA7, 0x27, 0x95, 0xF5,
++   0x82, 0xCB, 0xEC, 0xED, 0x4E, 0xFB, 0xA4, 0x59,
++   0xDA, 0xCF, 0x2E, 0x20, 0xFA, 0x31, 0xD1, 0xEA,
++   0x4A, 0xE9, 0x5E, 0xA9, 0xA1, 0x08, 0x1C, 0x96,
++   0x38, 0xB9, 0xEE, 0x7F, 0xAA, 0xF1, 0x7D, 0x3A,
++   0xA5, 0x43, 0xC5, 0xE0, 0x24, 0x39, 0x0D, 0xDE,
++   0xB0, 0xF8, 0xBE, 0x58, 0x7E, 0x51, 0xD4, 0x89,
++   0x15, 0x40, 0x3E, 0xB1, 0x1F, 0x5F, 0x68, 0x63,
++   0x84, 0x3D, 0x88, 0xBC, 0x41, 0xEF, 0xB5, 0xBF,
++   0x06, 0x6E, 0x9D, 0x3F, 0x0E, 0x76, 0x5C, 0xDC,
++   0x13, 0xF3, 0xE5, 0x8C, 0x7C, 0x04, 0x0A, 0xD5,
++   0x18, 0xC4, 0x44, 0x09, 0xC9, 0x1D, 0x9F, 0xFD,
++   0xD0, 0x0F, 0x6D, 0xD7, 0x92, 0x7B, 0x0C, 0xA3,
++   0x73, 0xDB, 0xB6, 0x83, 0xCE, 0x1E, 0xC1, 0x3C };
++
++unsigned char table_70[256] = {
++   0x54, 0x23, 0xF1, 0x09, 0x9D, 0xEB, 0x26, 0xD9,
++   0x6C, 0xC1, 0xBC, 0x3D, 0x6E, 0xB0, 0x5F, 0xE2,
++   0x59, 0x4D, 0x95, 0xFA, 0xD8, 0x29, 0xAA, 0x8E,
++   0xF5, 0xEF, 0x43, 0x76, 0xFD, 0x0D, 0x4F, 0xAD,
++   0xB7, 0xFC, 0xA8, 0x9F, 0x62, 0xC2, 0x7B, 0x10,
++   0x0B, 0xF2, 0x73, 0xA9, 0x46, 0x4C, 0x53, 0xD7,
++   0x0A, 0x50, 0x89, 0x63, 0x48, 0xD6, 0xA2, 0x44,
++   0xE6, 0x8D, 0x69, 0x2C, 0xF9, 0xC0, 0x35, 0x06,
++   0x66, 0x21, 0x9E, 0xD2, 0x98, 0xF7, 0x9B, 0xE7,
++   0x12, 0xB8, 0xA5, 0xBA, 0xE0, 0x79, 0x71, 0x7E,
++   0x8C, 0x24, 0xED, 0x7C, 0x60, 0x81, 0xC3, 0x5C,
++   0x2B, 0xE5, 0xEE, 0xB5, 0xA4, 0x05, 0x03, 0x34,
++   0x16, 0x2A, 0xA3, 0x2D, 0x3F, 0xDF, 0x07, 0x5B,
++   0xAE, 0x47, 0x61, 0x08, 0x18, 0xDB, 0x6D, 0x3C,
++   0x96, 0xD5, 0xAB, 0x78, 0x94, 0x45, 0x20, 0x9A,
++   0xE4, 0x13, 0x68, 0xDD, 0xDE, 0x31, 0x14, 0x57,
++   0x02, 0x52, 0x56, 0x1C, 0x1B, 0xE9, 0xD0, 0xA1,
++   0x22, 0x64, 0xB2, 0x7A, 0xCF, 0x5D, 0x00, 0x0F,
++   0xF8, 0x5E, 0x36, 0x58, 0x40, 0xAF, 0x19, 0x32,
++   0x2E, 0xB3, 0x72, 0xBE, 0xB9, 0xD3, 0xCD, 0x7D,
++   0x4A, 0x1D, 0x33, 0x2F, 0xAC, 0x27, 0x41, 0xE8,
++   0x55, 0xCB, 0x0E, 0x5A, 0x77, 0xFB, 0x8B, 0x86,
++   0x75, 0x8A, 0x51, 0xEC, 0xDA, 0xC6, 0xA6, 0xCC,
++   0x91, 0x4B, 0x11, 0xF6, 0xEA, 0xD1, 0xB6, 0x4E,
++   0x82, 0x04, 0x92, 0x30, 0xF4, 0x25, 0x88, 0x1E,
++   0x9C, 0xA0, 0xC8, 0x6A, 0x93, 0x87, 0x1F, 0xB4,
++   0xB1, 0x8F, 0x65, 0xCA, 0xFE, 0xFF, 0x97, 0x15,
++   0x99, 0x28, 0x80, 0x42, 0x70, 0x85, 0x0C, 0x3B,
++   0xBD, 0xE1, 0xA7, 0x17, 0xC9, 0x3A, 0xBB, 0x6B,
++   0x37, 0xF0, 0xC5, 0x39, 0x6F, 0x01, 0x83, 0x67,
++   0x74, 0xCE, 0xDC, 0x90, 0x3E, 0xF3, 0x7F, 0xC4,
++   0x49, 0x84, 0x38, 0xC7, 0xE3, 0xD4, 0x1A, 0xBF };
++
++unsigned char table_71[32] = {
++   0x17, 0x13, 0x0E, 0x1A, 0x0D, 0x18, 0x19, 0x10,
++   0x14, 0x11, 0x16, 0x05, 0x04, 0x00, 0x12, 0x0A,
++   0x02, 0x07, 0x03, 0x0B, 0x09, 0x1F, 0x1C, 0x0F,
++   0x0C, 0x06, 0x1B, 0x08, 0x1D, 0x01, 0x15, 0x1E };
++
++unsigned char table_72[256] = {
++   0xC9, 0xA7, 0x1B, 0xEC, 0x2B, 0x8B, 0xB0, 0xEB,
++   0x7F, 0x39, 0x25, 0xD9, 0x1D, 0xD5, 0x67, 0xA0,
++   0xB3, 0xAC, 0x3B, 0xC8, 0x82, 0xC0, 0xE3, 0x9E,
++   0x4C, 0x9B, 0xAF, 0xFD, 0x91, 0x86, 0x5F, 0x92,
++   0xB4, 0x42, 0x3C, 0x45, 0x12, 0xC4, 0xE2, 0xE1,
++   0x6C, 0x1F, 0xC6, 0x40, 0x93, 0x2A, 0xC2, 0x72,
++   0x2E, 0x14, 0x51, 0xA5, 0x70, 0xBD, 0xA2, 0xC7,
++   0x7D, 0xF1, 0x9F, 0x64, 0xC1, 0xF7, 0x80, 0xFF,
++   0x50, 0x49, 0x8C, 0x66, 0x13, 0x48, 0x6A, 0x0A,
++   0x26, 0x94, 0x83, 0x1E, 0x84, 0xBB, 0x57, 0x27,
++   0x44, 0x5B, 0x62, 0xF6, 0x09, 0x4F, 0x77, 0x76,
++   0x2D, 0x7E, 0xCD, 0x0B, 0x24, 0xFE, 0x81, 0xB8,
++   0x21, 0x85, 0xCF, 0xA8, 0x75, 0x56, 0x37, 0x17,
++   0xAA, 0x23, 0xE5, 0xE8, 0x9A, 0x9D, 0x2F, 0x04,
++   0x31, 0x4A, 0x7C, 0xFC, 0xD6, 0xE4, 0x29, 0xC3,
++   0xFB, 0x36, 0x1C, 0x0C, 0xCE, 0xEE, 0x0D, 0xF3,
++   0x46, 0xF8, 0x41, 0x0E, 0x68, 0xAB, 0x2C, 0x69,
++   0x96, 0x90, 0x28, 0xED, 0x02, 0x63, 0x07, 0xAD,
++   0xB2, 0xDC, 0x05, 0xE6, 0x78, 0x03, 0xA4, 0x7A,
++   0x5C, 0x52, 0x95, 0x5D, 0x88, 0x01, 0xDF, 0x35,
++   0x5E, 0xB6, 0x06, 0x4D, 0x15, 0x89, 0x59, 0x3F,
++   0xF0, 0xA1, 0xA3, 0x99, 0x19, 0xEA, 0xDB, 0xE0,
++   0x6B, 0x71, 0x6E, 0xB7, 0x65, 0x54, 0x9C, 0xBC,
++   0x98, 0xDD, 0x4B, 0x60, 0x3D, 0xBF, 0xF5, 0xD1,
++   0xD7, 0xF9, 0x55, 0x61, 0xA9, 0xB1, 0x6D, 0xDE,
++   0x79, 0xAE, 0x1A, 0x34, 0x3A, 0x4E, 0xCB, 0x38,
++   0xBA, 0x97, 0x00, 0x74, 0xEF, 0xD8, 0x18, 0x33,
++   0x7B, 0xFA, 0x22, 0x32, 0x20, 0xCA, 0x8A, 0xBE,
++   0xA6, 0x43, 0x11, 0x10, 0xD0, 0xD3, 0x87, 0x73,
++   0x6F, 0xF4, 0x8D, 0xCC, 0x30, 0x0F, 0x16, 0xDA,
++   0xB5, 0xC5, 0xD4, 0x47, 0x8E, 0xE7, 0x58, 0x8F,
++   0x08, 0x53, 0xF2, 0xB9, 0x5A, 0x3E, 0xE9, 0xD2 };
++
++unsigned char table_73[256] = {
++   0x36, 0x37, 0xED, 0xD8, 0xBF, 0xD7, 0x12, 0xB7,
++   0x40, 0x32, 0x19, 0x4A, 0x44, 0x2A, 0xCE, 0xA5,
++   0x29, 0x13, 0x43, 0x51, 0x5C, 0xD0, 0x76, 0x6E,
++   0x41, 0xD6, 0xE2, 0x4F, 0xB8, 0x27, 0x2E, 0xCF,
++   0xD9, 0xE0, 0x69, 0xC0, 0x59, 0x77, 0x62, 0x6F,
++   0x53, 0xE7, 0x93, 0xD4, 0xAD, 0xC8, 0x4C, 0xC2,
++   0x2C, 0xBE, 0xAA, 0xA0, 0x22, 0x78, 0x14, 0xB3,
++   0xB0, 0xEA, 0xBA, 0x9A, 0x33, 0x1B, 0x31, 0x6C,
++   0xFC, 0x0A, 0x0B, 0xA1, 0xE4, 0x75, 0x7C, 0xE3,
++   0x65, 0x21, 0xA9, 0xA4, 0x4E, 0x3C, 0x5F, 0x39,
++   0x74, 0xA2, 0x9E, 0x03, 0x70, 0xD2, 0xFD, 0x1D,
++   0x25, 0x72, 0x73, 0x8E, 0x7B, 0xB2, 0x6A, 0x92,
++   0x81, 0xF3, 0xF0, 0x46, 0x08, 0x85, 0xE6, 0x30,
++   0x05, 0x7E, 0xEC, 0x0D, 0xDD, 0x42, 0x2F, 0x5B,
++   0xB9, 0xCB, 0x84, 0x0C, 0x16, 0xC7, 0x24, 0xFA,
++   0xF9, 0x8F, 0x20, 0xAC, 0x10, 0x55, 0xC3, 0x1A,
++   0x8B, 0x94, 0x3D, 0xDB, 0xC9, 0x04, 0xB5, 0xCC,
++   0xC6, 0x98, 0xB6, 0x8D, 0x0F, 0x3A, 0x06, 0x4B,
++   0xEF, 0x35, 0x68, 0x3F, 0xEE, 0xE5, 0x63, 0xC5,
++   0x60, 0x88, 0x52, 0x2D, 0x6D, 0xAB, 0xCD, 0xC4,
++   0x1F, 0xF4, 0xCA, 0x67, 0x7D, 0x1C, 0xDA, 0x34,
++   0xDE, 0x86, 0xAE, 0xF1, 0x61, 0x09, 0xF5, 0xF6,
++   0x49, 0xE9, 0xF2, 0x48, 0x1E, 0xD3, 0x56, 0x18,
++   0x9B, 0xB1, 0x57, 0x9D, 0xBB, 0x5E, 0xAF, 0x87,
++   0x9F, 0x8A, 0xC1, 0x79, 0xA7, 0xA8, 0xFB, 0xDC,
++   0x47, 0x3E, 0x97, 0x80, 0x91, 0xA6, 0x7A, 0xA3,
++   0x9C, 0x11, 0x02, 0x2B, 0x58, 0xD1, 0xF7, 0x00,
++   0x83, 0x01, 0xE8, 0xFE, 0x50, 0x23, 0x66, 0x4D,
++   0xD5, 0x82, 0x89, 0x3B, 0xEB, 0xE1, 0xF8, 0x5A,
++   0x15, 0x7F, 0x8C, 0x17, 0x96, 0x28, 0x5D, 0x64,
++   0x26, 0x38, 0x71, 0x0E, 0x45, 0xDF, 0xB4, 0x99,
++   0xFF, 0x90, 0x6B, 0xBC, 0x54, 0x95, 0xBD, 0x07 };
++
++unsigned char table_74[256] = {
++   0xA7, 0xCF, 0x99, 0x1A, 0x13, 0xC7, 0xE9, 0xC4,
++   0xB6, 0x0E, 0x15, 0x09, 0xFF, 0xDF, 0xBE, 0x03,
++   0xAD, 0xF1, 0xB0, 0x3C, 0x4A, 0x9B, 0xF5, 0x12,
++   0xA1, 0x2C, 0xDB, 0x51, 0x5E, 0x6F, 0xE6, 0x49,
++   0x27, 0xBB, 0xAE, 0x56, 0xC0, 0x0C, 0x77, 0x60,
++   0x5B, 0x69, 0xA2, 0xF0, 0x24, 0x8E, 0xE1, 0xA4,
++   0xBC, 0x9F, 0x50, 0xD4, 0x61, 0x19, 0x67, 0x00,
++   0x7B, 0xAB, 0xDD, 0x26, 0xCD, 0x6C, 0xE8, 0xA8,
++   0x7A, 0x93, 0xEF, 0x20, 0x52, 0x1F, 0x1B, 0x46,
++   0x25, 0x3B, 0x1E, 0x65, 0xC2, 0xF9, 0x10, 0xB2,
++   0xB3, 0xD9, 0x21, 0xD2, 0x11, 0x94, 0xE2, 0xFC,
++   0x38, 0x9E, 0x36, 0x87, 0xAA, 0x53, 0x45, 0x68,
++   0x2B, 0xE7, 0x07, 0xFA, 0xD3, 0x8D, 0x3F, 0x17,
++   0xC1, 0x06, 0x72, 0x62, 0x8C, 0x55, 0x73, 0x8A,
++   0xC9, 0x2E, 0x5A, 0x7D, 0x02, 0x6D, 0xF8, 0x4B,
++   0xE4, 0xBF, 0xEC, 0xB7, 0x31, 0xDC, 0xF4, 0xB8,
++   0x47, 0x64, 0x0A, 0x33, 0x48, 0xAC, 0xFB, 0x05,
++   0x3E, 0x34, 0x1C, 0x97, 0x1D, 0x63, 0x37, 0x2D,
++   0xB1, 0x92, 0xED, 0x9D, 0x4C, 0xD5, 0x4E, 0x9A,
++   0x0D, 0x79, 0x0F, 0xBD, 0x95, 0xBA, 0x08, 0x2A,
++   0xC6, 0x7E, 0x88, 0xCB, 0xA6, 0x29, 0x70, 0x35,
++   0x66, 0xCA, 0x89, 0x75, 0x6A, 0x4F, 0xB5, 0x6B,
++   0x74, 0xDE, 0x01, 0x04, 0x81, 0x91, 0x90, 0x18,
++   0x32, 0x0B, 0x7F, 0x44, 0xB4, 0xAF, 0xF2, 0xEB,
++   0x22, 0xFD, 0x14, 0xA0, 0xFE, 0x8B, 0xB9, 0x16,
++   0x86, 0xE3, 0xD7, 0xDA, 0xC5, 0x3A, 0x41, 0x83,
++   0xD1, 0x28, 0x54, 0x30, 0xE0, 0x40, 0xA5, 0x57,
++   0x8F, 0x84, 0xD6, 0x96, 0x39, 0xE5, 0x42, 0x80,
++   0xA9, 0x58, 0xCE, 0x5D, 0xEE, 0x5F, 0xA3, 0xD0,
++   0xC8, 0x59, 0x43, 0x4D, 0x5C, 0xF7, 0xCC, 0x76,
++   0x6E, 0xF3, 0x23, 0x3D, 0x85, 0x82, 0x78, 0xF6,
++   0x2F, 0xD8, 0xC3, 0x7C, 0x9C, 0x98, 0xEA, 0x71 };
++
++unsigned char table_75[256] = {
++   0xE7, 0xA5, 0x30, 0xE1, 0x9D, 0x81, 0xBE, 0x83,
++   0xB2, 0x1E, 0xE4, 0x69, 0x2F, 0x2B, 0x0D, 0xEB,
++   0x7C, 0x59, 0x2D, 0xAA, 0x01, 0x0C, 0xDB, 0xED,
++   0xC4, 0xEE, 0x5D, 0x38, 0x72, 0xD8, 0x70, 0xCE,
++   0x0B, 0xF6, 0x7F, 0x48, 0x26, 0x9E, 0xA3, 0x44,
++   0xD6, 0xCF, 0x0F, 0x6B, 0xFD, 0x23, 0x98, 0xAB,
++   0x11, 0xD4, 0x92, 0x91, 0x5E, 0x08, 0x4D, 0xC6,
++   0xF0, 0xA8, 0x7E, 0x8A, 0x1D, 0xA1, 0x97, 0x76,
++   0x3E, 0x64, 0x07, 0x24, 0xDE, 0x75, 0xA4, 0xCC,
++   0x1A, 0x04, 0x4B, 0x6C, 0xFA, 0xB0, 0xC7, 0x35,
++   0xE2, 0x56, 0x61, 0xA0, 0xE9, 0x27, 0xDF, 0xC3,
++   0xE5, 0xF4, 0x8D, 0xB4, 0xD3, 0x52, 0xD7, 0x49,
++   0xCD, 0x31, 0x6E, 0x3F, 0x4E, 0x6A, 0x5B, 0x65,
++   0xCA, 0x14, 0x71, 0x53, 0xD9, 0x47, 0x28, 0x7D,
++   0x17, 0x06, 0x5C, 0xFE, 0xBA, 0xB8, 0xAC, 0x15,
++   0xE8, 0xE0, 0x9A, 0xDD, 0x1F, 0xBC, 0x95, 0x42,
++   0xCB, 0x58, 0x00, 0x85, 0xD5, 0x62, 0xC9, 0xB6,
++   0x05, 0x80, 0x4C, 0x3C, 0x1C, 0xF5, 0x03, 0xF8,
++   0x96, 0x77, 0x02, 0x19, 0xF2, 0xFB, 0x5F, 0xC2,
++   0xAE, 0x60, 0x1B, 0xAD, 0x8F, 0xC1, 0x33, 0xA6,
++   0x20, 0xBF, 0xA7, 0xC8, 0x74, 0x18, 0x90, 0xE3,
++   0x68, 0x09, 0x7A, 0x79, 0xB5, 0xDA, 0xF3, 0x0E,
++   0x66, 0x84, 0xB3, 0xBB, 0xE6, 0xF7, 0xB7, 0x7B,
++   0x39, 0x4A, 0x12, 0x4F, 0xC5, 0x41, 0x54, 0xD0,
++   0xFF, 0x87, 0x63, 0x40, 0x99, 0x21, 0x29, 0xD2,
++   0x3D, 0x37, 0x3A, 0x93, 0xFC, 0x25, 0xF1, 0xD1,
++   0x2C, 0x6D, 0x8C, 0x5A, 0x8E, 0x9B, 0xBD, 0xAF,
++   0x10, 0x55, 0xF9, 0x9F, 0x43, 0x0A, 0x50, 0x16,
++   0x57, 0xB1, 0xC0, 0x73, 0x82, 0xEF, 0x88, 0x6F,
++   0xEA, 0x2A, 0xEC, 0x2E, 0x86, 0x45, 0x51, 0x22,
++   0xA9, 0x34, 0x94, 0x3B, 0xB9, 0x9C, 0xA2, 0x13,
++   0x89, 0x46, 0x78, 0xDC, 0x32, 0x8B, 0x67, 0x36 };
++
++unsigned char table_76[256] = {
++   0x3D, 0x66, 0x40, 0xC5, 0x1D, 0xF5, 0xE7, 0xB7,
++   0x2C, 0x23, 0x09, 0xC2, 0x68, 0xE6, 0xD3, 0x8D,
++   0x35, 0x94, 0x93, 0xF0, 0x43, 0x97, 0x2B, 0x4B,
++   0x1A, 0xEB, 0x00, 0x4C, 0x6F, 0xE4, 0x92, 0xEA,
++   0xB8, 0xA3, 0xA6, 0xEC, 0x11, 0x5E, 0x61, 0x81,
++   0xE1, 0x48, 0xC9, 0xCB, 0xDB, 0x2E, 0x3B, 0xED,
++   0x36, 0x52, 0x3A, 0xD2, 0x4F, 0x4E, 0x22, 0x96,
++   0x57, 0x2D, 0x62, 0x53, 0xCF, 0xD9, 0x5B, 0x9F,
++   0x8E, 0x78, 0xC6, 0x07, 0x7D, 0xA1, 0x02, 0xB4,
++   0xF4, 0xB6, 0x34, 0x98, 0xDA, 0xA9, 0xD4, 0x54,
++   0x99, 0x82, 0x0A, 0xD8, 0x88, 0x5D, 0x3C, 0xD0,
++   0xAB, 0x31, 0xFB, 0x03, 0x17, 0x46, 0xE8, 0xE2,
++   0xA4, 0xFF, 0xB0, 0xAA, 0xAD, 0x7C, 0x55, 0x49,
++   0x75, 0x6B, 0x10, 0x24, 0xC0, 0x04, 0xB1, 0xBF,
++   0x6A, 0xF6, 0x15, 0xEF, 0x5C, 0x60, 0x27, 0x3E,
++   0x38, 0x63, 0xC1, 0x76, 0xFD, 0x84, 0xE0, 0xCD,
++   0xFE, 0x30, 0xCE, 0xBB, 0xDC, 0x1E, 0x1B, 0xBC,
++   0xB5, 0xE9, 0x9E, 0x8F, 0x0D, 0x3F, 0x91, 0x19,
++   0x28, 0x37, 0x26, 0x42, 0x08, 0x9A, 0x0C, 0x83,
++   0x90, 0x6D, 0x74, 0x65, 0xF2, 0x4A, 0xDE, 0x8B,
++   0x67, 0x0E, 0x8C, 0x5F, 0xF9, 0x7F, 0x5A, 0x86,
++   0x69, 0x45, 0x44, 0xD5, 0xF7, 0xE5, 0x8A, 0xA8,
++   0xC8, 0x7E, 0x05, 0x64, 0xEE, 0x79, 0xBE, 0x7A,
++   0x14, 0xD6, 0x50, 0x18, 0x25, 0xBD, 0x85, 0xE3,
++   0xA2, 0x70, 0xCC, 0x59, 0x71, 0x77, 0xFA, 0x47,
++   0x9B, 0x1F, 0x9D, 0xBA, 0x29, 0x4D, 0xF8, 0xDF,
++   0xC4, 0x72, 0x2F, 0xAE, 0x06, 0x51, 0x41, 0xAF,
++   0xF3, 0xDD, 0x87, 0xB2, 0x9C, 0xC7, 0x12, 0x16,
++   0x20, 0xA7, 0x21, 0x73, 0xF1, 0x58, 0xD7, 0x7B,
++   0xB9, 0xB3, 0x32, 0x01, 0x80, 0x1C, 0x39, 0x0B,
++   0x13, 0x56, 0x6C, 0x89, 0x33, 0x6E, 0x2A, 0xA5,
++   0xD1, 0x95, 0xC3, 0xA0, 0x0F, 0xCA, 0xAC, 0xFC };
++
++unsigned char table_77[32] = {
++   0x1C, 0x0D, 0x1E, 0x01, 0x06, 0x16, 0x18, 0x17,
++   0x0B, 0x1F, 0x04, 0x0F, 0x00, 0x19, 0x08, 0x0A,
++   0x11, 0x03, 0x05, 0x07, 0x09, 0x0C, 0x15, 0x14,
++   0x1A, 0x12, 0x13, 0x0E, 0x1D, 0x10, 0x02, 0x1B };
++
++unsigned char table_78[32] = {
++   0x0E, 0x02, 0x17, 0x12, 0x1E, 0x09, 0x15, 0x03,
++   0x01, 0x0B, 0x0F, 0x11, 0x10, 0x0A, 0x16, 0x06,
++   0x07, 0x00, 0x1C, 0x1D, 0x1F, 0x0C, 0x18, 0x04,
++   0x13, 0x0D, 0x1B, 0x08, 0x19, 0x14, 0x05, 0x1A };
++
++unsigned char table_79[32] = {
++   0x12, 0x0B, 0x11, 0x01, 0x07, 0x0E, 0x1A, 0x0D,
++   0x1E, 0x18, 0x14, 0x1F, 0x0A, 0x17, 0x19, 0x1B,
++   0x00, 0x10, 0x0C, 0x08, 0x13, 0x02, 0x0F, 0x1D,
++   0x09, 0x06, 0x04, 0x16, 0x15, 0x1C, 0x05, 0x03 };
++
++unsigned char table_80[256] = {
++   0x14, 0xE7, 0x31, 0x0F, 0xD1, 0x5F, 0xED, 0x1E,
++   0xA6, 0x77, 0x20, 0x57, 0x34, 0x64, 0x33, 0x0B,
++   0x5A, 0xB4, 0x83, 0x62, 0xFD, 0x8E, 0xE4, 0xF3,
++   0xBD, 0xA5, 0xC8, 0x6D, 0x3E, 0x4F, 0x01, 0x7A,
++   0xD3, 0x45, 0x3C, 0xF2, 0x68, 0xFF, 0xE6, 0x84,
++   0xC2, 0xC1, 0x53, 0x72, 0x8C, 0xA1, 0xC7, 0x00,
++   0x89, 0x97, 0x69, 0xA4, 0xF8, 0xAA, 0xAD, 0x8F,
++   0x24, 0xC6, 0x9A, 0xAC, 0xE5, 0xAB, 0x6B, 0x79,
++   0x99, 0x60, 0x28, 0x2B, 0x3B, 0xAF, 0x1C, 0x80,
++   0xA3, 0x8A, 0x1A, 0xB5, 0xE1, 0x9F, 0xDA, 0x78,
++   0xD7, 0xC4, 0x87, 0x5D, 0xE9, 0x27, 0xFB, 0x18,
++   0x94, 0x3A, 0xCE, 0x3F, 0xF6, 0x12, 0x75, 0x37,
++   0x6E, 0x9E, 0x29, 0x6C, 0xF7, 0x7D, 0x92, 0x08,
++   0x42, 0xB2, 0xBF, 0x0C, 0xB6, 0x25, 0xE0, 0x49,
++   0x43, 0x91, 0x98, 0xBB, 0xDC, 0x63, 0xEA, 0xA8,
++   0x74, 0x38, 0x35, 0xCD, 0x07, 0x70, 0x81, 0x41,
++   0xC9, 0x51, 0xBC, 0xA9, 0x59, 0xD4, 0xB8, 0x2C,
++   0x7C, 0x2D, 0xB3, 0x6F, 0x11, 0x86, 0x9D, 0x46,
++   0xF0, 0x65, 0x76, 0x04, 0x0E, 0xCA, 0xBE, 0x5C,
++   0xF9, 0x71, 0x9C, 0x21, 0x4C, 0x02, 0xFE, 0x8D,
++   0xD5, 0x26, 0x40, 0xC3, 0x32, 0x9B, 0xB0, 0x5E,
++   0x48, 0xC5, 0x85, 0x4B, 0x0A, 0xCC, 0x58, 0x52,
++   0x61, 0x13, 0xEF, 0x4A, 0xEE, 0x03, 0xD9, 0xDE,
++   0xA7, 0x19, 0x09, 0x7F, 0x5B, 0x96, 0xBA, 0x0D,
++   0xCF, 0xD2, 0x06, 0x1F, 0xD8, 0xDB, 0xEC, 0xA0,
++   0xDD, 0x66, 0x10, 0xA2, 0xDF, 0x30, 0xF4, 0x88,
++   0xCB, 0x36, 0x82, 0xE3, 0x73, 0x17, 0x55, 0x15,
++   0xF5, 0xB7, 0x23, 0xB1, 0xD6, 0xE2, 0x47, 0x7E,
++   0x67, 0xE8, 0x1D, 0x16, 0x8B, 0xEB, 0xD0, 0x3D,
++   0x6A, 0x54, 0x2A, 0x4E, 0x93, 0xFA, 0x44, 0x05,
++   0x2F, 0x50, 0x2E, 0x95, 0xAE, 0x1B, 0x56, 0x7B,
++   0x39, 0xB9, 0xC0, 0x22, 0xF1, 0x4D, 0x90, 0xFC };
++
++unsigned char table_81[32] = {
++   0x03, 0x02, 0x1D, 0x0E, 0x09, 0x1A, 0x0C, 0x11,
++   0x1C, 0x0D, 0x08, 0x12, 0x19, 0x10, 0x04, 0x17,
++   0x15, 0x05, 0x0A, 0x00, 0x13, 0x16, 0x1B, 0x18,
++   0x1E, 0x0B, 0x0F, 0x01, 0x07, 0x14, 0x1F, 0x06 };
++
++unsigned char table_82[256] = {
++   0x53, 0xD3, 0x64, 0x89, 0x7D, 0xA5, 0x66, 0xA4,
++   0x09, 0x46, 0x17, 0x2C, 0xAF, 0x8C, 0x21, 0x5F,
++   0x3B, 0x22, 0xE3, 0x05, 0x07, 0x28, 0x2F, 0xAB,
++   0xF4, 0x8E, 0x51, 0x31, 0x02, 0xC7, 0x48, 0x13,
++   0x24, 0x12, 0xB8, 0xE5, 0xBD, 0xAE, 0x7E, 0xCC,
++   0xC9, 0x98, 0x08, 0xEE, 0xDB, 0x1B, 0xE8, 0x3D,
++   0x8F, 0xF2, 0xFB, 0x36, 0x4D, 0x94, 0x9C, 0x16,
++   0xF7, 0x42, 0x9B, 0x2B, 0xFD, 0x7B, 0x77, 0x3F,
++   0xC3, 0xFC, 0x23, 0x93, 0x50, 0x0C, 0x79, 0x18,
++   0x47, 0xE1, 0xCB, 0xA7, 0xB6, 0x85, 0xE6, 0x61,
++   0x2D, 0xD8, 0x9F, 0x80, 0xE9, 0x14, 0x0B, 0x1C,
++   0x40, 0x76, 0x2A, 0x25, 0x0E, 0x99, 0xAC, 0xC4,
++   0xEB, 0x29, 0x41, 0x8A, 0x73, 0x06, 0x57, 0xC6,
++   0x8D, 0xFA, 0x5A, 0xCD, 0x67, 0xB2, 0xD9, 0x0A,
++   0x1E, 0xEF, 0x3E, 0xA0, 0x45, 0x03, 0x27, 0xF1,
++   0x38, 0x54, 0xC1, 0x7A, 0xFE, 0x52, 0x75, 0xD4,
++   0x74, 0x7C, 0xD2, 0x68, 0xEA, 0x4C, 0x97, 0xF9,
++   0xF5, 0x8B, 0x0F, 0x84, 0xA8, 0x6E, 0x9E, 0x11,
++   0x6B, 0xBC, 0x4B, 0x6C, 0x9A, 0xF0, 0xA3, 0x1F,
++   0x92, 0x19, 0xA2, 0x3A, 0x15, 0x04, 0xC5, 0x62,
++   0xD5, 0x96, 0x90, 0x32, 0xAA, 0xD6, 0xCF, 0x35,
++   0xB4, 0x81, 0x2E, 0x01, 0x10, 0x49, 0x70, 0xDE,
++   0xDD, 0x88, 0xB9, 0x6D, 0x60, 0xBB, 0x44, 0xF8,
++   0x3C, 0xEC, 0x34, 0x82, 0x95, 0x72, 0x58, 0x4E,
++   0xE4, 0x0D, 0xBE, 0xDA, 0x83, 0x4A, 0x00, 0xBF,
++   0xD0, 0xC8, 0x26, 0xB3, 0x65, 0x1A, 0x69, 0xCA,
++   0xF3, 0xD7, 0x6F, 0x55, 0xE2, 0xFF, 0x5D, 0xDC,
++   0x20, 0xF6, 0x63, 0xED, 0xE0, 0x59, 0x9D, 0xB1,
++   0x1D, 0xAD, 0x91, 0xA1, 0xB7, 0xA9, 0xDF, 0xC0,
++   0x39, 0xD1, 0x43, 0xCE, 0x4F, 0x5C, 0xE7, 0x37,
++   0x5E, 0x33, 0x5B, 0xA6, 0xC2, 0xB0, 0xBA, 0x30,
++   0x6A, 0x78, 0xB5, 0x71, 0x56, 0x87, 0x7F, 0x86 };
++
++unsigned char table_83[32] = {
++   0x1B, 0x0A, 0x1F, 0x01, 0x10, 0x08, 0x0E, 0x18,
++   0x06, 0x04, 0x00, 0x1C, 0x0C, 0x19, 0x0D, 0x16,
++   0x02, 0x03, 0x09, 0x07, 0x13, 0x0F, 0x05, 0x12,
++   0x17, 0x1E, 0x1A, 0x1D, 0x0B, 0x11, 0x14, 0x15 };
++
++unsigned char table_84[32] = {
++   0x02, 0x1A, 0x0D, 0x15, 0x01, 0x16, 0x1E, 0x00,
++   0x08, 0x1B, 0x04, 0x10, 0x1C, 0x18, 0x19, 0x14,
++   0x0C, 0x11, 0x0B, 0x0E, 0x03, 0x0A, 0x07, 0x12,
++   0x1D, 0x17, 0x13, 0x06, 0x0F, 0x05, 0x09, 0x1F };
++
++unsigned char table_85[256] = {
++   0xC6, 0x7C, 0xCE, 0xBD, 0x84, 0x3E, 0x0B, 0xD8,
++   0xFE, 0xCC, 0x46, 0x50, 0xD1, 0xFB, 0xA0, 0x6D,
++   0xEA, 0xE2, 0x40, 0x51, 0x13, 0xB0, 0xD6, 0xB1,
++   0xA8, 0xDF, 0x61, 0xA4, 0x80, 0x21, 0xB3, 0x33,
++   0x06, 0x6B, 0xE3, 0x8C, 0xA1, 0x18, 0xBA, 0x03,
++   0xD7, 0x8D, 0x54, 0x12, 0x4C, 0xEE, 0x9E, 0xCF,
++   0x04, 0x2A, 0x08, 0xBB, 0xC2, 0xD4, 0xC3, 0x4A,
++   0xD5, 0xFA, 0x36, 0x2F, 0x14, 0x3F, 0xED, 0x05,
++   0x17, 0x28, 0x75, 0xFC, 0xA2, 0x1F, 0x4B, 0x6F,
++   0x91, 0x7E, 0x4E, 0x96, 0x3B, 0xF3, 0x1D, 0x78,
++   0xEB, 0x68, 0xF1, 0xA7, 0x9F, 0xC7, 0x59, 0x6C,
++   0x92, 0xE6, 0x66, 0x07, 0x8A, 0x25, 0x26, 0x72,
++   0x30, 0x5A, 0x81, 0x2C, 0x58, 0x32, 0xCB, 0xE0,
++   0xF9, 0x48, 0x83, 0x9B, 0xA5, 0xE1, 0xA6, 0x64,
++   0xFF, 0xC9, 0x8F, 0x53, 0x3D, 0x24, 0xC8, 0xDE,
++   0x02, 0x7D, 0x09, 0xB4, 0x0A, 0x95, 0x0F, 0xE4,
++   0xDB, 0xB7, 0x71, 0x4D, 0x1C, 0xAC, 0x35, 0xCD,
++   0x29, 0xDD, 0xC1, 0xF2, 0xF4, 0xC0, 0x5C, 0x74,
++   0xDC, 0x87, 0xFD, 0x4F, 0x11, 0x0E, 0x5D, 0x3C,
++   0x01, 0x73, 0xE9, 0xD9, 0x10, 0x9A, 0x5B, 0xC5,
++   0x98, 0x34, 0x15, 0xAE, 0xF7, 0xAA, 0x67, 0x23,
++   0xBC, 0x8B, 0x7B, 0x65, 0xA9, 0xB6, 0x77, 0x00,
++   0x19, 0x0C, 0x5E, 0x99, 0xF0, 0x55, 0x86, 0x97,
++   0x69, 0xDA, 0x38, 0x9C, 0x16, 0xE8, 0x27, 0xAF,
++   0x2E, 0x47, 0x6A, 0xD0, 0x79, 0x44, 0x45, 0x2B,
++   0x5F, 0x85, 0xF5, 0x62, 0x70, 0x22, 0x7F, 0xF6,
++   0x88, 0x93, 0x60, 0x42, 0x3A, 0x39, 0x49, 0x6E,
++   0x89, 0x52, 0x20, 0xF8, 0xCA, 0xD2, 0x76, 0xB9,
++   0xAB, 0x7A, 0x9D, 0xD3, 0xBE, 0x1A, 0xAD, 0x41,
++   0x56, 0x31, 0x90, 0xB5, 0xB2, 0xEC, 0xA3, 0xE5,
++   0x8E, 0x1B, 0xEF, 0xBF, 0x94, 0xC4, 0x0D, 0xB8,
++   0x2D, 0x57, 0xE7, 0x82, 0x1E, 0x37, 0x63, 0x43 };
++
++unsigned char table_86[32] = {
++   0x11, 0x07, 0x0F, 0x0A, 0x19, 0x1D, 0x0B, 0x09,
++   0x1C, 0x1E, 0x14, 0x06, 0x0C, 0x16, 0x13, 0x04,
++   0x15, 0x18, 0x00, 0x0D, 0x12, 0x05, 0x08, 0x02,
++   0x10, 0x1A, 0x1F, 0x01, 0x17, 0x0E, 0x03, 0x1B };
++
++unsigned char table_87[32] = {
++   0x17, 0x0E, 0x1D, 0x13, 0x0B, 0x19, 0x03, 0x06,
++   0x09, 0x01, 0x0D, 0x15, 0x1C, 0x16, 0x18, 0x1B,
++   0x11, 0x10, 0x00, 0x1E, 0x1F, 0x08, 0x12, 0x0F,
++   0x02, 0x04, 0x07, 0x1A, 0x14, 0x0A, 0x0C, 0x05 };
++
++unsigned char table_88[32] = {
++   0x09, 0x08, 0x17, 0x10, 0x0A, 0x07, 0x1C, 0x1F,
++   0x04, 0x0E, 0x01, 0x0C, 0x0D, 0x1B, 0x03, 0x15,
++   0x02, 0x1E, 0x18, 0x19, 0x0F, 0x06, 0x1A, 0x0B,
++   0x05, 0x11, 0x14, 0x00, 0x16, 0x1D, 0x12, 0x13 };
++
++unsigned char table_89[32] = {
++   0x15, 0x1C, 0x1D, 0x14, 0x0F, 0x1A, 0x05, 0x02,
++   0x07, 0x09, 0x06, 0x08, 0x1F, 0x00, 0x10, 0x13,
++   0x0D, 0x03, 0x0C, 0x18, 0x0E, 0x16, 0x1B, 0x1E,
++   0x12, 0x04, 0x11, 0x0A, 0x01, 0x0B, 0x17, 0x19 };
++
++unsigned char table_90[256] = {
++   0x62, 0x36, 0x64, 0x0E, 0x4C, 0x6C, 0xBE, 0xCF,
++   0x25, 0x5A, 0x3D, 0x12, 0x54, 0x9F, 0xE7, 0xA5,
++   0xDE, 0xD7, 0xB2, 0x60, 0x18, 0x8D, 0x89, 0x70,
++   0x48, 0x66, 0x1C, 0xA6, 0x17, 0x9B, 0xDF, 0x9A,
++   0x82, 0xB9, 0x2E, 0xFA, 0x83, 0x5B, 0x7A, 0x61,
++   0xFC, 0x6B, 0x8B, 0x4E, 0x0F, 0xAD, 0x78, 0xE1,
++   0xE8, 0x15, 0x1A, 0xF7, 0xA3, 0x3A, 0x04, 0xE3,
++   0x30, 0x8C, 0x06, 0xC4, 0x05, 0x32, 0x1F, 0x6A,
++   0xB8, 0x37, 0x58, 0xF5, 0x74, 0x63, 0xD4, 0xAC,
++   0xA4, 0xF3, 0xEC, 0xBB, 0x8E, 0x65, 0xA0, 0xEE,
++   0x6D, 0x11, 0xDD, 0xEA, 0x68, 0x2B, 0xDA, 0x0B,
++   0xEF, 0xC3, 0x8F, 0x03, 0x77, 0x1B, 0xFB, 0x1E,
++   0x5C, 0xD9, 0xCB, 0x33, 0x55, 0xF1, 0xA1, 0xF9,
++   0x7C, 0x38, 0x95, 0x00, 0x6E, 0x85, 0xC2, 0x7F,
++   0xBF, 0x84, 0x2A, 0x13, 0x72, 0x81, 0xE9, 0x59,
++   0x41, 0x69, 0x3B, 0x0C, 0x90, 0xB4, 0x51, 0x2F,
++   0xA2, 0xFE, 0xF8, 0x49, 0x57, 0xE5, 0x96, 0xFF,
++   0xCD, 0xD5, 0xCE, 0xAA, 0x40, 0xB0, 0x4D, 0xBA,
++   0xDB, 0xC7, 0x46, 0x86, 0xD1, 0xCA, 0xC0, 0x67,
++   0x9C, 0x21, 0xAE, 0xB3, 0x7B, 0x87, 0xE2, 0x71,
++   0xE6, 0x39, 0xA8, 0x22, 0x07, 0x2C, 0x44, 0x52,
++   0xA7, 0xF0, 0x4A, 0x92, 0x56, 0x28, 0x43, 0x8A,
++   0x5E, 0x53, 0x93, 0x47, 0x97, 0x88, 0x76, 0x79,
++   0x91, 0x26, 0xC1, 0x3F, 0xB7, 0xF6, 0x3E, 0x80,
++   0xA9, 0xC6, 0x01, 0xD2, 0xEB, 0x9E, 0x4B, 0xBC,
++   0xC8, 0xB5, 0x02, 0x5F, 0x98, 0x9D, 0x5D, 0x35,
++   0xD0, 0x16, 0xB1, 0x23, 0x7D, 0xAF, 0x10, 0x3C,
++   0xAB, 0x14, 0x09, 0x2D, 0x0D, 0xC5, 0x1D, 0xD6,
++   0x42, 0xF2, 0x34, 0x73, 0xF4, 0xFD, 0xE0, 0x24,
++   0x6F, 0xD3, 0x75, 0xD8, 0xCC, 0xB6, 0x99, 0x4F,
++   0x29, 0x0A, 0x08, 0xE4, 0x27, 0x19, 0x31, 0xC9,
++   0x20, 0x94, 0x45, 0xED, 0xDC, 0xBD, 0x7E, 0x50 };
++
++unsigned char table_91[32] = {
++   0x03, 0x04, 0x0C, 0x18, 0x10, 0x0D, 0x13, 0x1B,
++   0x1F, 0x07, 0x11, 0x17, 0x1C, 0x1D, 0x05, 0x06,
++   0x0A, 0x12, 0x02, 0x1A, 0x0B, 0x01, 0x0E, 0x08,
++   0x14, 0x16, 0x00, 0x15, 0x19, 0x09, 0x0F, 0x1E };
++
++unsigned char table_92[32] = {
++   0x1E, 0x10, 0x01, 0x07, 0x11, 0x16, 0x15, 0x17,
++   0x1F, 0x14, 0x0C, 0x1C, 0x06, 0x03, 0x00, 0x18,
++   0x08, 0x0E, 0x02, 0x1B, 0x09, 0x0D, 0x19, 0x05,
++   0x0F, 0x12, 0x0B, 0x13, 0x0A, 0x04, 0x1D, 0x1A };
++
++unsigned char table_93[256] = {
++   0x76, 0x78, 0xA2, 0x94, 0x0E, 0x7F, 0xDF, 0xC1,
++   0xB9, 0xE1, 0x3D, 0x59, 0x6F, 0x1E, 0x53, 0x99,
++   0x80, 0xE3, 0x21, 0xF8, 0x65, 0xB8, 0x08, 0xBC,
++   0x29, 0x17, 0xFD, 0x33, 0x35, 0xF2, 0x70, 0xC7,
++   0x25, 0xD0, 0xCD, 0x7A, 0xB7, 0x9B, 0xA5, 0xC3,
++   0x00, 0x90, 0xDC, 0xB1, 0x0C, 0x20, 0x67, 0x8D,
++   0x43, 0x49, 0xF3, 0x96, 0x14, 0x1A, 0xC8, 0x19,
++   0x72, 0xD7, 0x8A, 0x38, 0x66, 0xDA, 0xDD, 0x2E,
++   0xBE, 0xD5, 0x91, 0x7C, 0x3A, 0x92, 0x8E, 0xE7,
++   0x51, 0xB5, 0xA8, 0xD9, 0x0B, 0x2A, 0xBA, 0x81,
++   0x41, 0x0F, 0xBD, 0x4E, 0x31, 0x23, 0x9C, 0x8B,
++   0x2B, 0x1D, 0x04, 0x3E, 0x8C, 0xF0, 0x45, 0xA0,
++   0x1C, 0x44, 0x55, 0x5E, 0xF1, 0x98, 0x54, 0x5D,
++   0x9D, 0x84, 0xAE, 0x09, 0xA9, 0xC5, 0x83, 0x60,
++   0x86, 0x95, 0xB4, 0xFA, 0x6B, 0xA7, 0x9A, 0xCA,
++   0x8F, 0x4F, 0x0A, 0x7B, 0xB0, 0x02, 0xEA, 0xA4,
++   0x18, 0xDB, 0xD3, 0x64, 0xEB, 0xFC, 0xC4, 0xC9,
++   0xF5, 0xD6, 0xCC, 0x75, 0x0D, 0x5C, 0x93, 0x4A,
++   0x6D, 0xC0, 0x1F, 0x50, 0xE6, 0x16, 0xEE, 0x07,
++   0xFB, 0x74, 0x56, 0x58, 0x52, 0x89, 0x79, 0x68,
++   0xB6, 0xFE, 0x01, 0xD4, 0x7E, 0x06, 0xBF, 0xCB,
++   0x5B, 0xC2, 0xC6, 0x32, 0xAC, 0x26, 0x22, 0xD2,
++   0x82, 0x46, 0x69, 0x15, 0x2C, 0xF7, 0xAD, 0x13,
++   0x4D, 0xA3, 0xF6, 0x2D, 0x48, 0x71, 0x57, 0x11,
++   0x63, 0x05, 0x5F, 0x9E, 0x4B, 0xAB, 0xA6, 0x61,
++   0xBB, 0xA1, 0x3C, 0x97, 0xF9, 0x03, 0x40, 0x12,
++   0xCF, 0x37, 0xE4, 0x10, 0x6A, 0xED, 0xFF, 0x62,
++   0x42, 0x4C, 0xAF, 0x9F, 0xE5, 0xE8, 0xD8, 0xD1,
++   0x28, 0x3F, 0x1B, 0xE9, 0xCE, 0x6C, 0x27, 0x88,
++   0xEF, 0x2F, 0xE0, 0x30, 0x87, 0x5A, 0x73, 0xB3,
++   0x6E, 0x3B, 0x7D, 0x77, 0x36, 0xAA, 0x39, 0xDE,
++   0x24, 0x34, 0xE2, 0xEC, 0x85, 0x47, 0xF4, 0xB2 };
++
++unsigned char table_94[32] = {
++   0x1C, 0x07, 0x05, 0x1A, 0x10, 0x1D, 0x14, 0x12,
++   0x08, 0x0F, 0x0C, 0x01, 0x04, 0x1B, 0x16, 0x0A,
++   0x11, 0x02, 0x1F, 0x13, 0x0D, 0x1E, 0x17, 0x06,
++   0x0E, 0x09, 0x15, 0x19, 0x03, 0x18, 0x00, 0x0B };
++
++unsigned char table_95[32] = {
++   0x12, 0x10, 0x11, 0x15, 0x03, 0x0A, 0x14, 0x05,
++   0x1D, 0x07, 0x17, 0x0D, 0x09, 0x08, 0x1B, 0x1F,
++   0x0B, 0x06, 0x19, 0x0E, 0x18, 0x04, 0x00, 0x02,
++   0x1E, 0x1C, 0x01, 0x0C, 0x1A, 0x0F, 0x13, 0x16 };
++
++unsigned char table_96[256] = {
++   0x1C, 0x6E, 0xCD, 0xB4, 0xB3, 0x93, 0xA8, 0x2E,
++   0x4F, 0x09, 0xE3, 0x72, 0x64, 0x13, 0x21, 0xF5,
++   0x89, 0xB2, 0xD2, 0x22, 0x5D, 0x63, 0x90, 0xC4,
++   0x42, 0x9B, 0x07, 0xCA, 0x16, 0x19, 0x5C, 0x2B,
++   0x3D, 0xA0, 0x69, 0x5F, 0x52, 0x41, 0x66, 0xC0,
++   0x55, 0xDA, 0x82, 0x40, 0x25, 0x02, 0x3C, 0xDD,
++   0xAE, 0xD7, 0xD6, 0xDB, 0x04, 0x78, 0x05, 0x4A,
++   0x4C, 0x81, 0x00, 0xBE, 0x45, 0xC5, 0x30, 0xB0,
++   0x65, 0x5A, 0xA9, 0x38, 0x75, 0x26, 0x85, 0x4E,
++   0xF0, 0xA2, 0x91, 0x8A, 0x54, 0xD0, 0x3E, 0x0D,
++   0xFE, 0xF2, 0x0A, 0x23, 0x24, 0x37, 0x32, 0x0B,
++   0xCB, 0xB5, 0x28, 0x6A, 0x95, 0x49, 0x53, 0x9A,
++   0xEE, 0x2C, 0x9D, 0xD4, 0x1D, 0x46, 0xC9, 0x79,
++   0xCC, 0xDF, 0x17, 0xE8, 0x6D, 0x29, 0x0E, 0x80,
++   0xE0, 0x62, 0xA1, 0xFA, 0x10, 0xF6, 0x03, 0xC1,
++   0x15, 0x14, 0x1F, 0x99, 0x97, 0xD5, 0x9E, 0x3F,
++   0x7B, 0x2F, 0xEF, 0x2A, 0x68, 0x83, 0xE2, 0x1B,
++   0xC8, 0x87, 0x12, 0x70, 0xC7, 0x36, 0xD3, 0x73,
++   0x8B, 0x7D, 0x47, 0x9F, 0xD9, 0xFB, 0x6C, 0x5B,
++   0xFC, 0xAA, 0xB9, 0xB1, 0x0C, 0x31, 0x8E, 0xF3,
++   0x92, 0xA3, 0x4B, 0xF1, 0xC2, 0x3A, 0x67, 0xEA,
++   0x77, 0x11, 0xB6, 0xE4, 0x1A, 0x33, 0xD1, 0xBA,
++   0xF9, 0xAC, 0x43, 0xE5, 0xC3, 0xC6, 0xFD, 0xF4,
++   0x44, 0x6F, 0xB7, 0x88, 0xA7, 0xF8, 0x34, 0x94,
++   0x6B, 0x27, 0xDE, 0x1E, 0xDC, 0x01, 0x61, 0x50,
++   0xAD, 0x74, 0x4D, 0x86, 0xF7, 0x8D, 0x9C, 0x0F,
++   0x5E, 0xBD, 0x08, 0x84, 0x18, 0xED, 0xA5, 0x39,
++   0xAB, 0x98, 0x48, 0xE6, 0x2D, 0x96, 0xCF, 0x7F,
++   0xFF, 0xBB, 0x8F, 0xEC, 0xBF, 0xE7, 0x56, 0xA4,
++   0x35, 0x76, 0xA6, 0xAF, 0xBC, 0x71, 0xE9, 0xB8,
++   0x7E, 0x7C, 0x06, 0x3B, 0xEB, 0x60, 0x7A, 0x8C,
++   0x59, 0xCE, 0xE1, 0x57, 0x20, 0x58, 0x51, 0xD8 };
++
++unsigned char table_97[256] = {
++   0x15, 0x2D, 0xAF, 0x36, 0xCF, 0xD3, 0xD0, 0xED,
++   0xB2, 0x1B, 0xFE, 0x92, 0xBD, 0xAD, 0x58, 0x0F,
++   0x76, 0x3C, 0x47, 0x03, 0x2E, 0x4C, 0x40, 0xF7,
++   0x39, 0xA7, 0x72, 0x22, 0x95, 0xF3, 0x8C, 0xE0,
++   0x79, 0xB6, 0x75, 0x82, 0x94, 0x8F, 0x44, 0xFC,
++   0xB0, 0x05, 0xE9, 0x10, 0x68, 0xE7, 0xF1, 0xA5,
++   0xA8, 0xE2, 0x6F, 0xBE, 0xE5, 0x54, 0xA2, 0xC6,
++   0xDB, 0x1C, 0x9E, 0x6D, 0x14, 0xA1, 0x26, 0x34,
++   0x1E, 0x1A, 0x06, 0x53, 0xEE, 0x67, 0xA9, 0x73,
++   0xD5, 0x59, 0x2F, 0x61, 0xE6, 0x74, 0xD6, 0x97,
++   0xC0, 0x0C, 0xB1, 0x6E, 0x6C, 0x33, 0xC8, 0x77,
++   0x8B, 0x49, 0x43, 0xE3, 0xB5, 0xDE, 0x6A, 0xA0,
++   0x78, 0x2A, 0xC9, 0xF9, 0x9A, 0xDC, 0x90, 0x55,
++   0xF4, 0x16, 0x5E, 0x3F, 0xC5, 0x7C, 0xFA, 0x09,
++   0x8E, 0x87, 0xF2, 0x9D, 0x70, 0x27, 0x9B, 0xC4,
++   0xCD, 0x91, 0x4B, 0xB4, 0x18, 0xE1, 0x3D, 0x5D,
++   0x7A, 0xEA, 0xF0, 0x65, 0xB9, 0xF6, 0xC3, 0x66,
++   0x21, 0x96, 0xD1, 0xB8, 0x56, 0x62, 0x48, 0x28,
++   0x3A, 0x86, 0x63, 0xD4, 0xD7, 0x41, 0x8D, 0x20,
++   0xC2, 0x98, 0x37, 0xD8, 0x85, 0x42, 0x0D, 0x31,
++   0x84, 0x4E, 0x11, 0x46, 0x2B, 0x19, 0xCC, 0xB7,
++   0x69, 0x13, 0x6B, 0x29, 0x38, 0x7E, 0x0E, 0xD2,
++   0x3B, 0x60, 0x89, 0x7F, 0xEF, 0x07, 0x08, 0xCA,
++   0xBF, 0x3E, 0xA3, 0xAA, 0x52, 0x4A, 0x45, 0x00,
++   0xC7, 0xF8, 0x57, 0xEB, 0x93, 0x9C, 0x4D, 0x7B,
++   0x2C, 0xBB, 0xFB, 0xFF, 0x35, 0x4F, 0x32, 0xA6,
++   0x23, 0x8A, 0xDD, 0x12, 0xA4, 0x81, 0x17, 0x1D,
++   0x1F, 0xCB, 0x0A, 0x71, 0x02, 0xAC, 0xDF, 0x24,
++   0xAB, 0x7D, 0x30, 0x5C, 0x01, 0x5A, 0xBA, 0xEC,
++   0x51, 0xF5, 0x0B, 0x64, 0xCE, 0xAE, 0x5B, 0x50,
++   0x80, 0x88, 0xE8, 0x5F, 0x04, 0xDA, 0xE4, 0xBC,
++   0x83, 0x25, 0x9F, 0xD9, 0x99, 0xC1, 0xFD, 0xB3 };
++
++unsigned char table_98[256] = {
++   0xC8, 0xE6, 0x38, 0x93, 0xE5, 0x03, 0x18, 0x1F,
++   0xE9, 0x5A, 0xB6, 0xAF, 0xC3, 0x95, 0x00, 0x51,
++   0xC0, 0xFD, 0x32, 0xE8, 0x96, 0x57, 0xF0, 0xAA,
++   0xDC, 0x71, 0xF8, 0x01, 0x40, 0x0A, 0x4F, 0xB0,
++   0x1B, 0x9D, 0x16, 0x92, 0xF3, 0x5E, 0xA9, 0x3C,
++   0xBE, 0x6A, 0xA7, 0xE3, 0x35, 0x0D, 0xAD, 0xDB,
++   0x48, 0xE0, 0x7E, 0xC6, 0xB4, 0x6D, 0x17, 0x41,
++   0x3E, 0xE2, 0x87, 0x12, 0xE1, 0x53, 0xD9, 0x8A,
++   0xAC, 0xA6, 0xD8, 0xFA, 0x36, 0x0B, 0x06, 0xDF,
++   0x6C, 0x4E, 0xA4, 0xBC, 0xC9, 0xEE, 0x44, 0x26,
++   0xF2, 0xE4, 0x9E, 0x34, 0xEF, 0x05, 0x0F, 0x7F,
++   0xD1, 0xCD, 0x67, 0x28, 0xC1, 0x8E, 0x7D, 0x90,
++   0x8F, 0x60, 0x1E, 0x19, 0xBD, 0x77, 0xB8, 0xD5,
++   0x3D, 0x8C, 0x31, 0x99, 0x08, 0xDD, 0x04, 0x30,
++   0x61, 0xFB, 0xEB, 0x98, 0x15, 0xFC, 0x10, 0xDE,
++   0x20, 0xBA, 0xA1, 0xB3, 0xD4, 0x91, 0x6F, 0x9F,
++   0x94, 0x5B, 0x42, 0xCB, 0x75, 0x1C, 0xBB, 0x5C,
++   0x5D, 0xD6, 0x66, 0x50, 0xB9, 0xF1, 0x82, 0x7B,
++   0x33, 0x23, 0x4A, 0xA5, 0x55, 0x97, 0xEA, 0x37,
++   0xF4, 0x64, 0x6E, 0xBF, 0x8B, 0xB1, 0x07, 0x9A,
++   0x43, 0x11, 0x65, 0xC2, 0x02, 0xDA, 0x9B, 0x25,
++   0xCA, 0x3B, 0x7A, 0xCE, 0xA8, 0xCF, 0xF7, 0x56,
++   0x6B, 0xF9, 0x47, 0x2A, 0x2E, 0x1D, 0x2D, 0xE7,
++   0x46, 0xD0, 0x62, 0x4C, 0x80, 0x4B, 0x2B, 0xF5,
++   0x69, 0x9C, 0x45, 0xED, 0x83, 0xAB, 0x74, 0x39,
++   0xA3, 0x85, 0xD7, 0x5F, 0xB2, 0x86, 0x22, 0x29,
++   0x89, 0x49, 0x1A, 0xC4, 0x52, 0xEC, 0x8D, 0x73,
++   0xD3, 0x7C, 0x79, 0xD2, 0x14, 0x4D, 0x84, 0xA2,
++   0x0E, 0x70, 0x78, 0x72, 0xB7, 0xA0, 0xC5, 0x81,
++   0x58, 0x0C, 0x68, 0x27, 0xFF, 0xF6, 0xAE, 0xCC,
++   0x88, 0xFE, 0x24, 0x2F, 0x76, 0x3F, 0x59, 0x21,
++   0x54, 0x3A, 0x13, 0x09, 0x2C, 0xB5, 0xC7, 0x63 };
++
++unsigned char table_99[32] = {
++   0x19, 0x00, 0x10, 0x18, 0x09, 0x11, 0x13, 0x1D,
++   0x08, 0x1A, 0x02, 0x05, 0x03, 0x17, 0x12, 0x01,
++   0x1F, 0x14, 0x06, 0x07, 0x15, 0x0D, 0x0F, 0x0B,
++   0x0E, 0x16, 0x1E, 0x04, 0x1B, 0x0A, 0x0C, 0x1C };
++
++unsigned char table_100[256] = {
++   0x9B, 0x3A, 0xAE, 0x60, 0x27, 0x67, 0x1E, 0x4E,
++   0x91, 0xDA, 0x85, 0x43, 0x5C, 0xCC, 0x89, 0x55,
++   0x75, 0x56, 0xF2, 0x86, 0xEB, 0xC4, 0x0D, 0xE6,
++   0x63, 0x88, 0x38, 0x59, 0x68, 0xD0, 0x18, 0xF0,
++   0xBA, 0x28, 0xF5, 0x80, 0x02, 0x5B, 0xE1, 0xA4,
++   0x7A, 0x4B, 0x8E, 0xF7, 0x9E, 0x99, 0x70, 0xEF,
++   0x66, 0x50, 0xB1, 0xCD, 0x9A, 0xAF, 0x5F, 0x21,
++   0xE5, 0x5D, 0x14, 0xD4, 0x34, 0x22, 0xC3, 0x0F,
++   0x44, 0xB6, 0x92, 0xCE, 0xB4, 0x6E, 0xB0, 0x00,
++   0xF9, 0xB5, 0x10, 0xEA, 0x45, 0x2F, 0x2B, 0xF4,
++   0xF6, 0xFE, 0xCB, 0x0A, 0x42, 0xF8, 0xE7, 0xFD,
++   0xC8, 0xC2, 0x6C, 0x9C, 0x57, 0xA1, 0x46, 0x04,
++   0xE9, 0x97, 0x40, 0x32, 0x19, 0xFA, 0x51, 0xD1,
++   0x6D, 0x4C, 0x2A, 0xD9, 0x95, 0x26, 0x72, 0x1B,
++   0x83, 0x93, 0x5A, 0x15, 0x33, 0xC5, 0x77, 0x13,
++   0xE0, 0x36, 0x37, 0xDB, 0xA7, 0xC7, 0x81, 0x62,
++   0xC1, 0x47, 0x64, 0x74, 0x1D, 0x84, 0x29, 0x39,
++   0x41, 0x35, 0x09, 0x90, 0x20, 0x9F, 0x8C, 0x7D,
++   0x3E, 0x07, 0xB9, 0x76, 0x06, 0xA3, 0x31, 0x7F,
++   0x49, 0x6F, 0x3D, 0xD5, 0x25, 0xAC, 0xDF, 0x0B,
++   0x3C, 0x79, 0x01, 0x8F, 0x82, 0x2E, 0xFC, 0x98,
++   0xA5, 0x58, 0xA0, 0x4A, 0x7C, 0x24, 0xDD, 0x05,
++   0x4D, 0x12, 0xBC, 0xAA, 0xE2, 0xAB, 0xD3, 0xBF,
++   0x94, 0x2D, 0x54, 0xBB, 0xAD, 0xB7, 0x6A, 0xE3,
++   0xBD, 0x5E, 0x8D, 0x08, 0x3B, 0xB8, 0x73, 0x8A,
++   0x16, 0xD2, 0x69, 0xE8, 0xEE, 0x53, 0xD8, 0xDC,
++   0x48, 0xCF, 0xC6, 0xA9, 0x1A, 0xCA, 0x17, 0x11,
++   0xED, 0xC0, 0xA6, 0x1F, 0x96, 0x8B, 0xFF, 0x78,
++   0x03, 0x61, 0x1C, 0xA8, 0x3F, 0x9D, 0x0E, 0xC9,
++   0xE4, 0xA2, 0x52, 0xEC, 0x4F, 0xD6, 0xF3, 0x6B,
++   0x87, 0xB3, 0x7E, 0xDE, 0xD7, 0x71, 0x65, 0xF1,
++   0x30, 0x0C, 0xB2, 0x7B, 0xBE, 0xFB, 0x23, 0x2C };
++
++unsigned char table_101[32] = {
++   0x18, 0x08, 0x14, 0x17, 0x03, 0x10, 0x19, 0x04,
++   0x0D, 0x1C, 0x06, 0x1D, 0x1E, 0x12, 0x11, 0x0B,
++   0x0F, 0x02, 0x0E, 0x1B, 0x13, 0x05, 0x07, 0x16,
++   0x15, 0x0A, 0x0C, 0x1A, 0x00, 0x01, 0x1F, 0x09 };
++
++unsigned char table_102[32] = {
++   0x17, 0x1F, 0x0E, 0x05, 0x13, 0x0C, 0x14, 0x1A,
++   0x0F, 0x01, 0x12, 0x1C, 0x00, 0x07, 0x0D, 0x02,
++   0x10, 0x16, 0x04, 0x11, 0x1D, 0x03, 0x1E, 0x18,
++   0x06, 0x15, 0x0A, 0x19, 0x09, 0x08, 0x1B, 0x0B };
++
++unsigned char table_103[32] = {
++   0x0F, 0x09, 0x1E, 0x11, 0x0D, 0x08, 0x10, 0x00,
++   0x01, 0x1F, 0x1D, 0x1C, 0x12, 0x04, 0x07, 0x05,
++   0x19, 0x14, 0x1B, 0x02, 0x1A, 0x15, 0x17, 0x16,
++   0x18, 0x0B, 0x0A, 0x13, 0x0C, 0x0E, 0x03, 0x06 };
++
++unsigned char table_104[256] = {
++   0xA4, 0x9F, 0x78, 0x39, 0x3D, 0x81, 0x51, 0x24,
++   0x46, 0x2A, 0x56, 0xE8, 0xDF, 0x73, 0xA8, 0xA2,
++   0x0D, 0xDC, 0xA5, 0x4F, 0xF0, 0x93, 0xC0, 0x76,
++   0x38, 0x70, 0xB0, 0x30, 0x98, 0x13, 0x8B, 0x14,
++   0x26, 0x45, 0x0F, 0x7D, 0x34, 0x72, 0x6B, 0x89,
++   0x43, 0xE2, 0x96, 0x5B, 0xEF, 0x2B, 0xF9, 0xDE,
++   0x82, 0xB5, 0x61, 0x4A, 0x17, 0xC2, 0x5A, 0xCB,
++   0xB2, 0x8D, 0xE4, 0xEC, 0xD9, 0x80, 0xBC, 0x62,
++   0x67, 0x11, 0xA9, 0x3A, 0xE1, 0xC4, 0xEA, 0xD2,
++   0x71, 0xD0, 0xDB, 0xE5, 0x7B, 0x08, 0x77, 0xD6,
++   0x10, 0x19, 0x48, 0xEB, 0xAA, 0x2C, 0x0C, 0x59,
++   0xBE, 0xF6, 0x28, 0x50, 0x90, 0x87, 0xCD, 0x04,
++   0x1F, 0x79, 0x99, 0x5C, 0x49, 0x06, 0x8A, 0x3E,
++   0x5F, 0x5E, 0x15, 0x23, 0x2D, 0xB6, 0xA6, 0x7A,
++   0x03, 0x20, 0xDA, 0xFB, 0x35, 0x75, 0xC7, 0x47,
++   0xB9, 0x7C, 0xA1, 0xCE, 0xC5, 0xDD, 0xFD, 0x6C,
++   0x05, 0xAC, 0x09, 0xB4, 0x95, 0xD1, 0xB1, 0x63,
++   0xFF, 0xAE, 0xD5, 0x25, 0x1E, 0x6E, 0x57, 0x18,
++   0x74, 0xE6, 0x2F, 0x9A, 0xE7, 0x42, 0x65, 0xF5,
++   0x58, 0x27, 0x33, 0x9C, 0xCF, 0xB7, 0xC3, 0xF1,
++   0x12, 0x1D, 0xB8, 0xF4, 0x64, 0x4D, 0xD4, 0xBD,
++   0xE3, 0xAB, 0x44, 0x60, 0xAF, 0xCC, 0x0A, 0xFC,
++   0xD3, 0x21, 0x0B, 0x1A, 0x6D, 0x83, 0xA7, 0x8E,
++   0x3C, 0xC1, 0xED, 0xF3, 0x2E, 0x86, 0xC9, 0x41,
++   0x02, 0xF7, 0xC8, 0x40, 0x1B, 0xF8, 0xF2, 0x07,
++   0x5D, 0x4E, 0xC6, 0x29, 0xD7, 0x4B, 0x7E, 0x31,
++   0x94, 0x32, 0x01, 0x92, 0xE9, 0x36, 0x0E, 0x7F,
++   0x85, 0x16, 0xFA, 0x00, 0x88, 0x3F, 0x68, 0x4C,
++   0x22, 0x55, 0xBF, 0x9D, 0xE0, 0x6A, 0xAD, 0xBA,
++   0x91, 0xCA, 0xA3, 0x1C, 0xEE, 0xD8, 0x3B, 0x66,
++   0x69, 0x9B, 0x84, 0xA0, 0xB3, 0x6F, 0xFE, 0x52,
++   0x97, 0xBB, 0x37, 0x8C, 0x54, 0x53, 0x9E, 0x8F };
++
++unsigned char table_105[256] = {
++   0x7B, 0x35, 0x11, 0x79, 0x07, 0x2F, 0xF6, 0x82,
++   0x8E, 0xB4, 0x6E, 0xD2, 0x6D, 0xC5, 0x8C, 0x1C,
++   0xE0, 0xD6, 0x34, 0xF0, 0x4F, 0x25, 0x59, 0xE8,
++   0xDF, 0x1D, 0xEB, 0x32, 0x86, 0x51, 0xA4, 0xF2,
++   0x5C, 0xD1, 0xC8, 0x41, 0xEC, 0x9D, 0x62, 0xAC,
++   0xDD, 0x3E, 0xB8, 0x65, 0x75, 0x89, 0x12, 0x6C,
++   0x40, 0x4E, 0xC7, 0x27, 0xE1, 0x37, 0xCF, 0x09,
++   0x16, 0x78, 0xAA, 0x58, 0x0D, 0xE6, 0x54, 0xFE,
++   0x8F, 0xFD, 0xF9, 0x61, 0x26, 0x3F, 0x2E, 0xCD,
++   0x2C, 0x04, 0xB2, 0x80, 0x0F, 0x14, 0x6F, 0xC6,
++   0xAB, 0xFB, 0x13, 0xDB, 0x9A, 0x21, 0xB3, 0xC0,
++   0xA9, 0x19, 0x70, 0xF3, 0x2B, 0xAE, 0x9B, 0x49,
++   0xB7, 0xA8, 0x24, 0x1B, 0x48, 0xEA, 0xED, 0xD9,
++   0x47, 0x9E, 0x9C, 0x69, 0x3C, 0x66, 0xBB, 0x06,
++   0x46, 0x38, 0x17, 0xB5, 0xCB, 0x05, 0x4A, 0x5E,
++   0x15, 0x20, 0xB9, 0xB6, 0x33, 0x4C, 0x7D, 0xA3,
++   0xD7, 0xB1, 0x23, 0x72, 0xC3, 0x4B, 0x63, 0xBE,
++   0xF7, 0x5B, 0x74, 0x64, 0x77, 0xCC, 0xD3, 0x85,
++   0xDE, 0x1A, 0x31, 0x97, 0xA2, 0x8B, 0xFC, 0x10,
++   0x5F, 0xDC, 0xD5, 0xB0, 0xBD, 0x55, 0xC1, 0xE7,
++   0x0C, 0x50, 0x43, 0x39, 0x71, 0x52, 0xE5, 0xAF,
++   0x8A, 0x60, 0x92, 0x2D, 0xD8, 0x03, 0xF5, 0x28,
++   0xCA, 0xEF, 0xD0, 0xC2, 0x53, 0x91, 0xA6, 0x73,
++   0x56, 0xA5, 0xF1, 0x57, 0x42, 0xF4, 0xD4, 0x36,
++   0x8D, 0xBC, 0xE9, 0x7E, 0x02, 0x76, 0x18, 0x0B,
++   0x84, 0x5A, 0xE2, 0xBF, 0x68, 0x95, 0x29, 0x98,
++   0xAD, 0x88, 0x1F, 0x81, 0x67, 0xA1, 0x3A, 0xA7,
++   0x22, 0xF8, 0x01, 0xA0, 0xCE, 0x7A, 0xDA, 0x30,
++   0xC4, 0xE4, 0xEE, 0x7C, 0x3B, 0x4D, 0x3D, 0xE3,
++   0xFA, 0x6A, 0x7F, 0x99, 0x00, 0x93, 0x0E, 0xFF,
++   0x90, 0x0A, 0x2A, 0x5D, 0x96, 0x08, 0x6B, 0x83,
++   0xBA, 0x1E, 0x44, 0x87, 0x45, 0x9F, 0xC9, 0x94 };
++
++unsigned char table_106[32] = {
++   0x03, 0x11, 0x07, 0x1B, 0x0F, 0x14, 0x0C, 0x01,
++   0x04, 0x02, 0x09, 0x0A, 0x05, 0x12, 0x06, 0x1F,
++   0x1C, 0x0E, 0x0D, 0x15, 0x18, 0x08, 0x00, 0x10,
++   0x1E, 0x1D, 0x17, 0x19, 0x13, 0x16, 0x0B, 0x1A };
++
++unsigned char table_107[32] = {
++   0x13, 0x1B, 0x06, 0x11, 0x1C, 0x07, 0x08, 0x0E,
++   0x10, 0x05, 0x09, 0x18, 0x04, 0x15, 0x1E, 0x0F,
++   0x1F, 0x12, 0x02, 0x00, 0x17, 0x19, 0x1A, 0x0D,
++   0x03, 0x0C, 0x0A, 0x1D, 0x14, 0x01, 0x16, 0x0B };
++
++unsigned char table_108[256] = {
++   0x99, 0xA3, 0x48, 0xE8, 0x5A, 0x7D, 0x97, 0xCA,
++   0x7F, 0x06, 0x9B, 0x04, 0xE0, 0xF3, 0x18, 0xAE,
++   0x59, 0xA0, 0x2B, 0x15, 0x85, 0x3E, 0x12, 0x93,
++   0x3D, 0x28, 0x32, 0xF5, 0x20, 0x5D, 0x86, 0x00,
++   0x1B, 0x2E, 0x36, 0x10, 0x5E, 0x6C, 0xD8, 0x29,
++   0xB6, 0x3F, 0x05, 0x1C, 0xCE, 0xC2, 0x34, 0x5F,
++   0x5C, 0x79, 0xD1, 0x1F, 0xA2, 0xEE, 0x8A, 0x69,
++   0xB5, 0x87, 0x96, 0x6D, 0x4D, 0xC1, 0x61, 0x2C,
++   0x11, 0xE7, 0x8E, 0xBF, 0x1E, 0x53, 0xD0, 0x58,
++   0x76, 0xA4, 0x60, 0xA9, 0xB0, 0xF9, 0xEA, 0x3C,
++   0x52, 0x9A, 0x24, 0xF1, 0x9F, 0xD3, 0x40, 0x0A,
++   0x63, 0x78, 0x6A, 0x8B, 0x08, 0x22, 0x16, 0x83,
++   0x6B, 0xD2, 0x49, 0x19, 0xBD, 0xFD, 0x62, 0x72,
++   0xA8, 0x55, 0xAB, 0x0C, 0xB9, 0x13, 0xD5, 0xF0,
++   0xF2, 0x84, 0xAF, 0x2F, 0x7B, 0x2A, 0x21, 0x0F,
++   0xDA, 0x30, 0x71, 0xD6, 0x81, 0xE6, 0xEC, 0x41,
++   0x90, 0x50, 0x66, 0x0E, 0xA7, 0xB8, 0xF7, 0x3A,
++   0xB2, 0xCF, 0x3B, 0xFC, 0x56, 0x6F, 0xC3, 0xA6,
++   0xC9, 0xA1, 0x8D, 0xBB, 0x9D, 0x75, 0xF6, 0xAA,
++   0x7E, 0xF8, 0x33, 0xEF, 0xBC, 0x7C, 0x23, 0x1A,
++   0x92, 0x6E, 0x2D, 0x8F, 0xED, 0xB7, 0xB1, 0x1D,
++   0x67, 0x39, 0xAC, 0x0D, 0x74, 0xDB, 0x7A, 0x94,
++   0x07, 0x09, 0xC0, 0xD7, 0xAD, 0xFE, 0x54, 0x91,
++   0xDE, 0x45, 0xA5, 0x77, 0xCB, 0x37, 0xC6, 0x38,
++   0x89, 0x88, 0x17, 0xD9, 0x4F, 0xDF, 0x25, 0xFB,
++   0xFA, 0x4C, 0x80, 0x35, 0x82, 0xF4, 0x95, 0xC8,
++   0xFF, 0xE9, 0x31, 0x01, 0x14, 0xB3, 0x02, 0x9E,
++   0x4E, 0x43, 0x46, 0xC7, 0xEB, 0x51, 0xE5, 0x47,
++   0xB4, 0xE3, 0xDC, 0x57, 0xC4, 0x98, 0x03, 0xE1,
++   0xBA, 0x68, 0xCD, 0x27, 0xC5, 0x0B, 0xD4, 0x64,
++   0x4B, 0x9C, 0x70, 0x65, 0x4A, 0xE4, 0x42, 0xDD,
++   0xCC, 0xE2, 0x44, 0x73, 0xBE, 0x26, 0x8C, 0x5B };
++
++unsigned char table_109[256] = {
++   0xE3, 0x95, 0xDB, 0x09, 0x82, 0x0A, 0x8F, 0x9E,
++   0xC9, 0xDC, 0x28, 0x35, 0x0F, 0x8B, 0xA8, 0xA5,
++   0x7F, 0x3D, 0x8C, 0xD1, 0x93, 0x57, 0x04, 0xAA,
++   0x6A, 0x98, 0x81, 0xDD, 0x16, 0x67, 0x2E, 0xDF,
++   0xED, 0xF7, 0xB2, 0xBD, 0x14, 0xB6, 0x76, 0xC8,
++   0x75, 0x9F, 0x48, 0xAE, 0xBB, 0xB0, 0xF3, 0xE2,
++   0xD4, 0x59, 0xD8, 0x9C, 0x64, 0xC1, 0x73, 0x21,
++   0x6D, 0x96, 0x7B, 0x62, 0x56, 0x55, 0xCC, 0xFD,
++   0xCE, 0x41, 0xA3, 0x43, 0x33, 0xAF, 0x23, 0x9D,
++   0x6F, 0x65, 0x19, 0x52, 0xAD, 0xC6, 0xD3, 0x3F,
++   0x66, 0xFF, 0xD0, 0x30, 0x6C, 0xC0, 0xEB, 0xCF,
++   0x51, 0x88, 0x38, 0x72, 0x69, 0x77, 0x3B, 0xFA,
++   0xBA, 0xB7, 0xA1, 0x91, 0xE0, 0x89, 0xAB, 0x44,
++   0x1B, 0x05, 0x5B, 0xB9, 0x71, 0x47, 0x7E, 0xFB,
++   0x02, 0xC7, 0x99, 0x6E, 0x42, 0x20, 0x90, 0x1F,
++   0x4A, 0x85, 0x1A, 0xEA, 0x0C, 0x0D, 0xB3, 0xDA,
++   0xE7, 0x13, 0xE6, 0xD7, 0x6B, 0x12, 0x46, 0x53,
++   0xB5, 0xF8, 0x1D, 0x83, 0x54, 0x49, 0x8A, 0x26,
++   0x4D, 0xDE, 0xF6, 0x03, 0xA2, 0x7D, 0x0E, 0xA0,
++   0x68, 0x79, 0xCA, 0x0B, 0x5D, 0x40, 0x4F, 0x80,
++   0xC2, 0xD6, 0x87, 0x70, 0xF0, 0xD2, 0x92, 0xEE,
++   0xBE, 0x74, 0x5F, 0xBC, 0xA4, 0x4B, 0xFE, 0x37,
++   0x60, 0xA9, 0x06, 0xA7, 0xE1, 0xF5, 0x2B, 0x10,
++   0xEF, 0x2C, 0x07, 0x86, 0x7A, 0x27, 0xE9, 0xC5,
++   0xAC, 0x32, 0x22, 0xF2, 0xE5, 0x8D, 0x31, 0x01,
++   0x34, 0xA6, 0xB8, 0xC3, 0x3C, 0xE4, 0x08, 0x94,
++   0x15, 0x4E, 0xB4, 0x39, 0x58, 0x00, 0x3E, 0x29,
++   0x45, 0x3A, 0x84, 0x36, 0xF1, 0x2A, 0x50, 0x11,
++   0xC4, 0x5A, 0xFC, 0xBF, 0xD9, 0xF9, 0x17, 0x9B,
++   0x8E, 0x18, 0x63, 0x4C, 0x2F, 0x78, 0x2D, 0x5E,
++   0x9A, 0xCD, 0x24, 0xEC, 0x7C, 0x97, 0x61, 0xCB,
++   0x1E, 0xF4, 0xD5, 0xB1, 0x5C, 0x25, 0xE8, 0x1C };
++
++unsigned char table_110[256] = {
++   0xC3, 0x06, 0x3C, 0xCB, 0xD2, 0x44, 0x9D, 0x48,
++   0x28, 0xAA, 0xA9, 0xD0, 0x64, 0x25, 0x56, 0xCA,
++   0xC2, 0xF8, 0x5C, 0xAE, 0x4E, 0x63, 0xB2, 0xE9,
++   0x35, 0x11, 0xA8, 0x1A, 0x76, 0x15, 0xE0, 0x26,
++   0x97, 0x99, 0xD4, 0x43, 0x80, 0xEE, 0xC1, 0x69,
++   0xA6, 0x1E, 0x7A, 0x42, 0x55, 0x38, 0xBF, 0x75,
++   0x0E, 0x29, 0xF5, 0xF3, 0x36, 0x7D, 0x51, 0xE8,
++   0xE5, 0xEB, 0x68, 0x60, 0x0C, 0x70, 0xFD, 0xCC,
++   0xE3, 0x23, 0x09, 0x6D, 0x2D, 0x6C, 0x5E, 0xB6,
++   0x98, 0x8B, 0x1F, 0x50, 0x34, 0x8D, 0x10, 0x92,
++   0x82, 0x85, 0xD5, 0x79, 0x02, 0xA4, 0x0A, 0xBC,
++   0x40, 0xC6, 0xA3, 0x72, 0x8F, 0xC4, 0xA5, 0xE4,
++   0x49, 0xD6, 0xCE, 0xA1, 0x12, 0x4F, 0x30, 0x31,
++   0xDE, 0x2A, 0xF7, 0x95, 0xB5, 0x96, 0x14, 0x08,
++   0xE6, 0x3D, 0x86, 0xF2, 0x47, 0x74, 0xB8, 0x5D,
++   0x1D, 0x2B, 0x3A, 0x93, 0x7C, 0x6A, 0x01, 0xA0,
++   0x9A, 0x4D, 0xB7, 0x71, 0xA7, 0x41, 0xC5, 0x65,
++   0xC8, 0x89, 0xD1, 0x3E, 0x0D, 0xD8, 0xFF, 0x6F,
++   0x7F, 0xA2, 0xFE, 0xD9, 0xF0, 0x4A, 0x07, 0x1C,
++   0x0F, 0x6E, 0x03, 0x81, 0x1B, 0x05, 0xDF, 0x52,
++   0xF1, 0x8A, 0xF9, 0xDD, 0x91, 0x3B, 0xD7, 0xE1,
++   0x54, 0xAD, 0x90, 0x5A, 0x7B, 0xC7, 0x32, 0x62,
++   0x16, 0x27, 0xB9, 0x66, 0x21, 0x88, 0xBD, 0x18,
++   0x77, 0x8E, 0x94, 0x8C, 0x9B, 0x46, 0x9C, 0xB1,
++   0xD3, 0x53, 0xB0, 0xBE, 0xAC, 0xAF, 0x73, 0x24,
++   0xDA, 0x58, 0xE2, 0xFC, 0x78, 0xEA, 0xCD, 0xFA,
++   0x37, 0xED, 0x13, 0x19, 0xC0, 0x59, 0x83, 0xBA,
++   0x3F, 0x57, 0x00, 0x7E, 0xC9, 0x2E, 0x17, 0x5B,
++   0x84, 0xF6, 0xE7, 0x22, 0xFB, 0x5F, 0x4C, 0x2C,
++   0x61, 0x9F, 0x45, 0x39, 0xB3, 0xEC, 0x04, 0x87,
++   0x67, 0xDC, 0x0B, 0xF4, 0x20, 0xAB, 0x6B, 0x9E,
++   0x4B, 0xCF, 0xB4, 0x2F, 0xBB, 0xEF, 0xDB, 0x33 };
++
++unsigned char table_111[32] = {
++   0x09, 0x0F, 0x00, 0x15, 0x12, 0x17, 0x1A, 0x0D,
++   0x1C, 0x0B, 0x01, 0x0A, 0x05, 0x1E, 0x1D, 0x0C,
++   0x1B, 0x08, 0x19, 0x18, 0x14, 0x07, 0x0E, 0x03,
++   0x10, 0x16, 0x11, 0x1F, 0x04, 0x06, 0x02, 0x13 };
++
++unsigned char table_112[256] = {
++   0xF9, 0x7D, 0xBE, 0xD5, 0x9F, 0xB8, 0x95, 0x43,
++   0xDB, 0xAE, 0x7E, 0xEC, 0x5B, 0x58, 0x18, 0x49,
++   0x4B, 0x9D, 0x1C, 0x3E, 0x61, 0xD1, 0xF6, 0x2F,
++   0x41, 0x82, 0x51, 0x37, 0x72, 0x79, 0x05, 0x2A,
++   0xC2, 0xB0, 0xE2, 0xE7, 0xB2, 0xF3, 0x1B, 0x92,
++   0x86, 0xBB, 0xDC, 0x90, 0x1A, 0x19, 0xD7, 0xBA,
++   0x2C, 0x7B, 0xEF, 0xC7, 0x8A, 0x81, 0xEB, 0xDE,
++   0x73, 0x4E, 0xB7, 0x97, 0xCA, 0x29, 0x85, 0xC1,
++   0xA5, 0x7F, 0xFE, 0x56, 0xE9, 0x9E, 0x21, 0x76,
++   0x3A, 0x88, 0x70, 0xC6, 0xD3, 0x8C, 0x47, 0xC8,
++   0x83, 0x48, 0xC3, 0x6A, 0x9C, 0x80, 0x53, 0xBD,
++   0xFD, 0x54, 0x09, 0x91, 0x94, 0xAA, 0x7A, 0x59,
++   0x71, 0xDD, 0xA8, 0x07, 0xCB, 0x0F, 0xE0, 0x9A,
++   0x36, 0x4C, 0x4D, 0x0D, 0xA4, 0x96, 0x6F, 0x14,
++   0x22, 0x38, 0xAD, 0x02, 0xF4, 0x0B, 0xEA, 0x93,
++   0x20, 0x04, 0xBC, 0xE8, 0x6C, 0xFB, 0x10, 0x6B,
++   0x40, 0xB6, 0x24, 0x17, 0x06, 0x31, 0xD9, 0x33,
++   0xF5, 0x99, 0x57, 0xCD, 0xAB, 0x67, 0x5C, 0x30,
++   0x1E, 0x34, 0xB4, 0x3F, 0x16, 0x42, 0xA2, 0x68,
++   0x27, 0xB3, 0x1D, 0xED, 0x5F, 0x52, 0xF7, 0x3C,
++   0x65, 0x5D, 0xE5, 0x23, 0x0C, 0x6D, 0x84, 0x6E,
++   0xDA, 0x77, 0xF8, 0x15, 0xFA, 0x69, 0xD0, 0xA7,
++   0x11, 0xAC, 0xA6, 0xA3, 0x1F, 0x2E, 0xBF, 0x4A,
++   0x8F, 0xFC, 0xEE, 0xC9, 0x26, 0x12, 0xC0, 0xB1,
++   0x45, 0x0E, 0x3D, 0x7C, 0xCE, 0x13, 0x8E, 0x98,
++   0x46, 0x2B, 0xC5, 0x66, 0x28, 0x32, 0xD2, 0x03,
++   0xE3, 0xC4, 0x9B, 0x89, 0x5E, 0xF0, 0xCF, 0x3B,
++   0x2D, 0x50, 0xB5, 0x00, 0x0A, 0xD6, 0x55, 0xE1,
++   0x62, 0x63, 0x64, 0x87, 0xAF, 0x78, 0xB9, 0xF2,
++   0x25, 0x44, 0xFF, 0x39, 0xF1, 0x08, 0x4F, 0x74,
++   0xA9, 0x8B, 0x75, 0x01, 0xA0, 0xE4, 0x35, 0x8D,
++   0xA1, 0xCC, 0xDF, 0x60, 0xD8, 0x5A, 0xE6, 0xD4 };
++
++unsigned char table_113[256] = {
++   0x46, 0x9D, 0x39, 0xB2, 0x8D, 0x3B, 0x59, 0x5A,
++   0xD0, 0x9C, 0xE4, 0x04, 0x01, 0xE2, 0xB3, 0xD2,
++   0xD7, 0x18, 0x40, 0xD8, 0xF1, 0xEF, 0x3A, 0x1D,
++   0x8E, 0xE5, 0xD9, 0xD3, 0xCB, 0x49, 0x4C, 0xCF,
++   0xC0, 0xD6, 0xB5, 0x73, 0x77, 0x82, 0x54, 0xA2,
++   0xB1, 0xB0, 0x84, 0x5D, 0xC7, 0xDE, 0x31, 0x2F,
++   0x50, 0x78, 0xBE, 0x94, 0x64, 0x44, 0x60, 0x7A,
++   0x1A, 0x6E, 0x09, 0x6F, 0xBF, 0x76, 0x81, 0x38,
++   0x22, 0xC3, 0xEE, 0x8F, 0xFB, 0x32, 0xED, 0x92,
++   0xAE, 0xE6, 0x5F, 0xAA, 0xAC, 0x0D, 0xA3, 0x47,
++   0x1F, 0x11, 0xC1, 0x29, 0xAF, 0xFD, 0x1C, 0xDB,
++   0x00, 0x23, 0xB9, 0xB8, 0x91, 0x41, 0x27, 0x37,
++   0x43, 0x02, 0x26, 0xF6, 0x7D, 0x0A, 0x85, 0x93,
++   0x97, 0x2E, 0x20, 0x55, 0x13, 0x4B, 0x6C, 0xE7,
++   0xFC, 0x25, 0xFA, 0x9E, 0x5B, 0xA1, 0xDF, 0x2C,
++   0x3E, 0xBC, 0xEA, 0x42, 0x7C, 0x36, 0x30, 0xEB,
++   0xBD, 0x8B, 0x87, 0x16, 0x3D, 0x5C, 0x07, 0xBA,
++   0xB4, 0x1B, 0xC2, 0xE3, 0x71, 0x9A, 0x5E, 0x4D,
++   0xF2, 0xCC, 0x0E, 0xE1, 0x34, 0x75, 0x58, 0x89,
++   0x17, 0xD4, 0x68, 0x80, 0x2B, 0x74, 0x70, 0x8A,
++   0x63, 0xE8, 0x56, 0x24, 0xD1, 0x57, 0x35, 0x6D,
++   0x3C, 0xA6, 0xC8, 0x7E, 0xA8, 0x4E, 0xC4, 0x33,
++   0xA9, 0x62, 0x61, 0x7F, 0x21, 0x98, 0x2A, 0xAD,
++   0xB6, 0xA7, 0xF5, 0x3F, 0x15, 0x45, 0xF8, 0xA4,
++   0x95, 0x88, 0xDC, 0x96, 0x90, 0x08, 0x9B, 0xF9,
++   0x06, 0x14, 0x05, 0xF0, 0xF7, 0xA0, 0xE0, 0x65,
++   0xCA, 0xA5, 0x9F, 0x79, 0xCD, 0x4F, 0x72, 0xB7,
++   0x4A, 0x0F, 0x66, 0xC5, 0x0C, 0x52, 0xF3, 0x69,
++   0x83, 0x03, 0x99, 0x1E, 0x2D, 0xDA, 0x8C, 0x53,
++   0x28, 0xDD, 0xE9, 0x0B, 0xC9, 0xF4, 0x48, 0x12,
++   0x6A, 0x19, 0xCE, 0xAB, 0x51, 0xD5, 0x6B, 0xBB,
++   0xFE, 0x7B, 0x67, 0xFF, 0x10, 0xEC, 0xC6, 0x86 };
++
++unsigned char table_114[32] = {
++   0x11, 0x10, 0x04, 0x1D, 0x08, 0x15, 0x1A, 0x1B,
++   0x14, 0x18, 0x0F, 0x17, 0x16, 0x07, 0x1E, 0x0E,
++   0x12, 0x0A, 0x13, 0x0B, 0x0C, 0x00, 0x06, 0x02,
++   0x1F, 0x19, 0x09, 0x1C, 0x01, 0x0D, 0x03, 0x05 };
++
++unsigned char table_115[256] = {
++   0xB7, 0xBB, 0x63, 0x0D, 0xF0, 0x33, 0x5A, 0x05,
++   0xF2, 0x7F, 0x64, 0xDB, 0x51, 0xC9, 0x2C, 0x85,
++   0x4F, 0x41, 0xA4, 0x42, 0xCF, 0xA6, 0x52, 0x2F,
++   0x26, 0xEF, 0xFB, 0x29, 0x40, 0x16, 0xF7, 0xED,
++   0x23, 0x69, 0x8A, 0xDF, 0x77, 0x28, 0x93, 0x14,
++   0x82, 0x0C, 0xBE, 0x3D, 0x20, 0xB4, 0x79, 0x94,
++   0x54, 0xF8, 0x07, 0xB1, 0xE1, 0x66, 0x73, 0xD3,
++   0x19, 0x15, 0xFF, 0x03, 0x6A, 0x9A, 0xDC, 0x1C,
++   0xB3, 0x5D, 0x76, 0x68, 0x47, 0x6C, 0xF9, 0xFD,
++   0xE9, 0xDD, 0x01, 0x65, 0xBD, 0x80, 0x0E, 0x7A,
++   0x8D, 0x99, 0x13, 0x7C, 0xA5, 0xA7, 0x1A, 0xCC,
++   0xB8, 0xE6, 0x2B, 0xB2, 0xB6, 0xD0, 0x62, 0x2D,
++   0x4D, 0xD2, 0xB9, 0x04, 0x46, 0xAE, 0xAA, 0x44,
++   0xDA, 0x92, 0x4B, 0x4E, 0xC4, 0xE2, 0xFE, 0xA2,
++   0x75, 0x7B, 0xC3, 0xFA, 0x9F, 0x37, 0x9D, 0x1E,
++   0x72, 0xD4, 0x1F, 0x4A, 0x9B, 0xE5, 0x6D, 0xEC,
++   0x5C, 0x7D, 0x98, 0xE8, 0xEE, 0x86, 0xD1, 0xC8,
++   0xEA, 0x55, 0xBF, 0xAF, 0xDE, 0x32, 0x09, 0x3A,
++   0x8F, 0x57, 0x83, 0x43, 0x61, 0xC6, 0x8E, 0x96,
++   0x22, 0xA3, 0x97, 0x91, 0x5F, 0x11, 0x3B, 0x5B,
++   0x1B, 0x34, 0x49, 0x95, 0xF1, 0x6F, 0x89, 0xA8,
++   0xC0, 0x36, 0x0A, 0x3F, 0x60, 0x50, 0xE7, 0x08,
++   0xCE, 0x25, 0xC1, 0x71, 0xF6, 0x59, 0x58, 0x56,
++   0x4C, 0xAB, 0x27, 0xAC, 0x06, 0xCB, 0x00, 0x30,
++   0x84, 0x3E, 0xC2, 0x1D, 0x02, 0xE0, 0xC5, 0xD6,
++   0x18, 0x70, 0xA9, 0x88, 0xD9, 0x39, 0x8B, 0x6E,
++   0xF4, 0x24, 0xA0, 0x48, 0x45, 0x21, 0x87, 0x78,
++   0x38, 0x90, 0xE3, 0xCA, 0xF5, 0xD7, 0x2A, 0x53,
++   0x9C, 0xCD, 0x31, 0x35, 0xAD, 0x74, 0xD8, 0x12,
++   0xBC, 0x9E, 0x6B, 0x67, 0xB0, 0xBA, 0xE4, 0x10,
++   0x5E, 0xFC, 0xC7, 0x0F, 0x2E, 0x81, 0x7E, 0xA1,
++   0x8C, 0x17, 0xB5, 0xEB, 0xD5, 0xF3, 0x0B, 0x3C };
++
++unsigned char table_116[32] = {
++   0x00, 0x05, 0x10, 0x1C, 0x0C, 0x1A, 0x04, 0x1B,
++   0x0A, 0x0D, 0x14, 0x0B, 0x07, 0x03, 0x12, 0x1E,
++   0x06, 0x11, 0x01, 0x08, 0x15, 0x09, 0x1F, 0x0F,
++   0x19, 0x18, 0x16, 0x02, 0x13, 0x0E, 0x17, 0x1D };
++
++unsigned char table_117[256] = {
++   0xD0, 0x9A, 0xAB, 0xA8, 0xA7, 0xDF, 0x28, 0xCE,
++   0x3E, 0x51, 0xBF, 0x76, 0x03, 0xA0, 0x53, 0x3F,
++   0x90, 0x93, 0x87, 0x67, 0x98, 0x3D, 0xEA, 0x8B,
++   0x55, 0xCF, 0x10, 0xF3, 0x25, 0xFC, 0x9F, 0x41,
++   0x6B, 0x54, 0x6E, 0x0B, 0x83, 0x35, 0x69, 0x7D,
++   0xE0, 0x88, 0x4B, 0xE9, 0x1E, 0x96, 0x91, 0x57,
++   0xBD, 0x72, 0x21, 0x3C, 0xA6, 0x99, 0x6C, 0xF6,
++   0x13, 0xFA, 0x29, 0xED, 0xDB, 0x16, 0x4D, 0x07,
++   0x45, 0xA5, 0xE3, 0x0E, 0x31, 0xBC, 0x56, 0x5C,
++   0xB2, 0x23, 0xDA, 0x74, 0xFF, 0x02, 0x8F, 0xF4,
++   0x2A, 0xC9, 0x89, 0xAA, 0x05, 0xB1, 0xD1, 0x1F,
++   0x4F, 0xB0, 0x7A, 0x2C, 0x14, 0xD9, 0xE7, 0x66,
++   0x62, 0x1A, 0x4C, 0xC0, 0xC6, 0x63, 0x7F, 0xB4,
++   0xF1, 0x43, 0xFE, 0x61, 0xA3, 0xCC, 0xE8, 0x6D,
++   0xBA, 0x65, 0x42, 0x2B, 0xCA, 0xD5, 0x52, 0x3A,
++   0xCD, 0x1D, 0x24, 0xD7, 0x47, 0xDE, 0x9E, 0x95,
++   0x85, 0x48, 0x86, 0xE1, 0xC5, 0xD2, 0x34, 0xAF,
++   0x40, 0xFB, 0xE6, 0x4E, 0xC8, 0xF5, 0x7B, 0x5A,
++   0xCB, 0xD4, 0x97, 0x6F, 0x0C, 0x79, 0x9C, 0x20,
++   0x59, 0x19, 0x68, 0x2E, 0x09, 0x64, 0x73, 0x50,
++   0xC2, 0x2F, 0x0D, 0xEF, 0x9D, 0x94, 0x00, 0x81,
++   0xE2, 0x46, 0x5F, 0xB8, 0x0A, 0x12, 0x75, 0x1C,
++   0x8C, 0xB6, 0x71, 0xAC, 0x04, 0x60, 0xA9, 0x5B,
++   0xF8, 0x30, 0x49, 0x44, 0x4A, 0xBE, 0x6A, 0xEB,
++   0xD3, 0xD8, 0x36, 0xB3, 0x3B, 0x17, 0x80, 0xA4,
++   0xEC, 0x26, 0x82, 0xB5, 0x37, 0x5D, 0x1B, 0x2D,
++   0xE5, 0xA2, 0x0F, 0xB7, 0xC4, 0xF2, 0x70, 0x39,
++   0xF9, 0xC7, 0xBB, 0x8A, 0x32, 0x78, 0xC3, 0x5E,
++   0xD6, 0xE4, 0x22, 0x9B, 0x18, 0x8E, 0xEE, 0x27,
++   0x8D, 0x33, 0x11, 0x77, 0x01, 0x06, 0x38, 0xF0,
++   0x7E, 0x08, 0x15, 0xB9, 0x7C, 0xAD, 0x84, 0xDD,
++   0xC1, 0xFD, 0x92, 0xA1, 0xF7, 0xAE, 0xDC, 0x58 };
++
++unsigned char table_118[256] = {
++   0x38, 0xA0, 0xA6, 0xFC, 0x7C, 0x5A, 0x97, 0x1D,
++   0xFD, 0x00, 0x20, 0xA2, 0x72, 0x10, 0x1F, 0x48,
++   0x98, 0x7E, 0xDF, 0x2D, 0x80, 0x0A, 0x27, 0xDC,
++   0xCF, 0xBF, 0x92, 0x94, 0x53, 0xCC, 0x0E, 0x74,
++   0xA7, 0x60, 0x08, 0x15, 0x87, 0x6F, 0xB3, 0xA3,
++   0xED, 0x59, 0x09, 0x4F, 0x9E, 0x9A, 0xEE, 0x83,
++   0x56, 0x32, 0x34, 0xC7, 0x24, 0xE7, 0x96, 0x4D,
++   0xAE, 0xE3, 0xBD, 0xE2, 0x36, 0x4A, 0xB6, 0x8B,
++   0xF2, 0xC1, 0xD7, 0x40, 0x31, 0x4B, 0xDA, 0xF1,
++   0xB1, 0x70, 0xA8, 0xC3, 0xC6, 0x8A, 0xE6, 0x77,
++   0x21, 0x7D, 0xD5, 0x0C, 0x43, 0xC4, 0xF0, 0x1B,
++   0x18, 0xA1, 0x85, 0xE1, 0xFF, 0x8D, 0xE5, 0x6E,
++   0x9B, 0x51, 0x1C, 0xA4, 0x5C, 0x8E, 0x69, 0x49,
++   0x23, 0xCD, 0x52, 0xF8, 0x3E, 0x91, 0x5E, 0x1E,
++   0x25, 0xB4, 0x93, 0xCB, 0xE0, 0x47, 0xBC, 0x4E,
++   0x33, 0xB7, 0x75, 0x1A, 0x11, 0x9C, 0x3F, 0xEC,
++   0xD1, 0x46, 0xDD, 0xAA, 0xB8, 0x99, 0x86, 0x67,
++   0x58, 0xF9, 0x16, 0x17, 0x6D, 0x5F, 0x2B, 0xA5,
++   0xD3, 0x8F, 0x55, 0x71, 0xD2, 0xBA, 0x5B, 0x3C,
++   0x82, 0xB5, 0x41, 0xE4, 0x90, 0x45, 0x6C, 0xF6,
++   0xDE, 0xA9, 0x84, 0x62, 0x19, 0x3B, 0xB9, 0xC8,
++   0x2C, 0xB0, 0x76, 0x57, 0xD8, 0x26, 0x9D, 0x89,
++   0xC9, 0x54, 0xFB, 0x07, 0xCE, 0x22, 0x5D, 0x64,
++   0x65, 0xAD, 0x01, 0xDB, 0x14, 0x4C, 0x37, 0x03,
++   0x6B, 0xAF, 0xD0, 0x7F, 0x9F, 0xBB, 0xEB, 0xC0,
++   0x50, 0x66, 0x68, 0x0B, 0x42, 0x2A, 0xD4, 0xF5,
++   0x61, 0x63, 0xF3, 0x39, 0xBE, 0xC5, 0xEF, 0x28,
++   0x3A, 0xAB, 0x79, 0x05, 0xE9, 0x12, 0x73, 0x3D,
++   0xB2, 0x8C, 0xCA, 0x29, 0x0F, 0xF4, 0x7B, 0x13,
++   0x88, 0x44, 0xC2, 0x2E, 0xFA, 0xFE, 0x04, 0x35,
++   0xE8, 0x06, 0x7A, 0x78, 0x0D, 0x81, 0xF7, 0xEA,
++   0xD9, 0x2F, 0x02, 0xAC, 0x30, 0x6A, 0xD6, 0x95 };
++
++unsigned char table_119[32] = {
++   0x14, 0x0A, 0x1C, 0x00, 0x0C, 0x1F, 0x1E, 0x0B,
++   0x12, 0x1D, 0x17, 0x08, 0x07, 0x04, 0x09, 0x10,
++   0x03, 0x1B, 0x0E, 0x1A, 0x05, 0x0D, 0x11, 0x15,
++   0x18, 0x02, 0x06, 0x01, 0x19, 0x16, 0x13, 0x0F };
++
++unsigned char table_120[256] = {
++   0xCE, 0x89, 0xB2, 0x72, 0x04, 0x77, 0x64, 0xAE,
++   0x80, 0x99, 0xB5, 0x00, 0x7B, 0x50, 0x9D, 0xE3,
++   0x87, 0x37, 0x6D, 0x3D, 0x32, 0xBA, 0x20, 0xF0,
++   0xDC, 0xBD, 0x61, 0x26, 0xD4, 0xA6, 0x70, 0x54,
++   0xC1, 0x7D, 0x82, 0xFF, 0x81, 0x83, 0x2F, 0xF5,
++   0x3B, 0x42, 0x08, 0x5C, 0x30, 0x59, 0xBB, 0xC2,
++   0x33, 0x5D, 0xEE, 0xB7, 0xF7, 0x2B, 0x76, 0xD0,
++   0x43, 0x1C, 0x48, 0xFC, 0x01, 0xCD, 0x27, 0x1D,
++   0x5A, 0x96, 0x95, 0x03, 0xC6, 0x1F, 0x09, 0xCB,
++   0xF6, 0x47, 0xA9, 0x93, 0xA7, 0xD2, 0xDB, 0x51,
++   0xB0, 0x7A, 0xE6, 0x62, 0x0F, 0x12, 0x57, 0xF4,
++   0x35, 0xFE, 0xA4, 0xDF, 0x5B, 0xF3, 0x67, 0x85,
++   0x98, 0xE4, 0xAB, 0x75, 0x4C, 0xE2, 0x25, 0x74,
++   0x3A, 0x45, 0xDE, 0xEF, 0x4A, 0x97, 0x86, 0x24,
++   0xE9, 0x8F, 0xD8, 0xD7, 0x60, 0xAD, 0x36, 0x8E,
++   0x1E, 0xB9, 0x4F, 0x6B, 0x8C, 0x06, 0x23, 0x94,
++   0x0E, 0xD3, 0x49, 0x14, 0x90, 0xAF, 0x65, 0xEC,
++   0xF9, 0x0D, 0xED, 0x6C, 0xBE, 0x7F, 0xA5, 0xC5,
++   0xEA, 0x78, 0x2E, 0xBC, 0xD5, 0xDA, 0x18, 0xE1,
++   0x10, 0x2D, 0xB4, 0x16, 0x4B, 0xE8, 0xC4, 0x8D,
++   0x19, 0x1B, 0x02, 0x66, 0xB6, 0xE7, 0x9C, 0x7C,
++   0xC9, 0xA0, 0x2A, 0x53, 0x13, 0xDD, 0xF8, 0xA8,
++   0x0A, 0x6E, 0xCF, 0x6F, 0x7E, 0xE0, 0x3E, 0xE5,
++   0x07, 0xCC, 0x38, 0xD1, 0xF2, 0x2C, 0x9A, 0xAC,
++   0x88, 0x79, 0xB8, 0xC8, 0xBF, 0x63, 0x71, 0x69,
++   0x52, 0x39, 0x9F, 0x22, 0x3F, 0x9E, 0x44, 0xFA,
++   0x73, 0x6A, 0x8B, 0xA2, 0xD6, 0x1A, 0x9B, 0xB1,
++   0x8A, 0x4D, 0x58, 0xA1, 0x46, 0x5F, 0x55, 0x56,
++   0x21, 0x05, 0x15, 0x92, 0xAA, 0xEB, 0x31, 0x68,
++   0xFB, 0x41, 0xC3, 0x4E, 0xB3, 0x40, 0x34, 0x17,
++   0xD9, 0x29, 0x3C, 0x0C, 0xF1, 0x0B, 0x28, 0x84,
++   0x5E, 0xCA, 0xFD, 0x11, 0xA3, 0xC7, 0xC0, 0x91 };
++
++unsigned char table_121[32] = {
++   0x1E, 0x12, 0x06, 0x1D, 0x15, 0x1F, 0x13, 0x0B,
++   0x10, 0x0D, 0x1C, 0x01, 0x0A, 0x0E, 0x02, 0x19,
++   0x04, 0x1A, 0x03, 0x11, 0x00, 0x16, 0x0C, 0x17,
++   0x14, 0x08, 0x18, 0x05, 0x09, 0x0F, 0x1B, 0x07 };
++
++unsigned char table_122[256] = {
++   0x85, 0xDF, 0x7F, 0x7C, 0x56, 0xF0, 0x0C, 0x7D,
++   0x76, 0xA8, 0x58, 0x31, 0x25, 0x8A, 0x0D, 0x23,
++   0x05, 0x0F, 0x12, 0x64, 0x8E, 0x5D, 0xF4, 0x2C,
++   0x18, 0xFA, 0x4B, 0xFE, 0x91, 0xBF, 0x95, 0x0B,
++   0xF1, 0x88, 0x10, 0xD8, 0x3E, 0x53, 0x96, 0xB5,
++   0x75, 0x24, 0x8F, 0xD6, 0x68, 0x5C, 0x93, 0x1F,
++   0x6B, 0xC2, 0xAB, 0xED, 0x1E, 0xC0, 0xBC, 0x47,
++   0xE9, 0xD1, 0xDE, 0xCA, 0xF6, 0x62, 0x43, 0xEB,
++   0xA2, 0xB4, 0x08, 0xE6, 0x74, 0x0E, 0xA1, 0x72,
++   0x66, 0x61, 0x21, 0x2E, 0x32, 0x63, 0x29, 0xD7,
++   0x1C, 0x22, 0xAC, 0xE7, 0x54, 0xF3, 0x65, 0x17,
++   0x9F, 0x78, 0x79, 0x4C, 0xDD, 0x27, 0x90, 0x36,
++   0x19, 0x44, 0x03, 0xD9, 0x4A, 0x5A, 0x34, 0xF9,
++   0x97, 0xA6, 0x70, 0x39, 0x28, 0x77, 0x6E, 0xB7,
++   0x8C, 0x02, 0x5E, 0x9B, 0x8D, 0x59, 0x6F, 0xA5,
++   0x07, 0xE2, 0x41, 0x51, 0xC9, 0x3C, 0xE8, 0xE1,
++   0xB3, 0x16, 0x50, 0x04, 0xE3, 0x1D, 0x3B, 0xD2,
++   0x4D, 0x35, 0x71, 0xDA, 0x9E, 0xA7, 0xE4, 0xE0,
++   0xB6, 0x2B, 0xEA, 0x84, 0x55, 0xF8, 0x57, 0x3D,
++   0x73, 0x42, 0xC6, 0x0A, 0x92, 0x6A, 0xAE, 0xF5,
++   0xFC, 0xD5, 0x15, 0x52, 0x7E, 0x14, 0x81, 0x13,
++   0xE5, 0x49, 0x38, 0x2A, 0x94, 0x5B, 0xA3, 0x11,
++   0x8B, 0x80, 0xBB, 0x01, 0x9C, 0xA4, 0xDB, 0xF7,
++   0xA9, 0x20, 0xF2, 0x1A, 0xDC, 0x33, 0x3A, 0xEF,
++   0xD3, 0xFD, 0x30, 0xB0, 0x1B, 0xC4, 0x06, 0xD4,
++   0x6D, 0x87, 0x2F, 0x60, 0x5F, 0xC5, 0x09, 0x37,
++   0xAF, 0x00, 0xCB, 0x9D, 0xA0, 0xB9, 0x45, 0x86,
++   0x4F, 0x6C, 0x67, 0xFB, 0x40, 0x3F, 0xCC, 0xB8,
++   0xC8, 0x82, 0x98, 0x99, 0x7B, 0xB1, 0xCD, 0xD0,
++   0xBD, 0x48, 0xAD, 0x26, 0x7A, 0x9A, 0x46, 0xFF,
++   0x89, 0xC7, 0xC1, 0xCF, 0xBE, 0xAA, 0xEC, 0xBA,
++   0xCE, 0x2D, 0x4E, 0x83, 0xC3, 0x69, 0xEE, 0xB2 };
++
++unsigned char table_123[256] = {
++   0x9D, 0xFB, 0x3C, 0x81, 0xAA, 0x05, 0xB2, 0xBE,
++   0xD1, 0x5F, 0x4C, 0xE0, 0xA3, 0xF4, 0xDE, 0x35,
++   0xFE, 0x1B, 0x37, 0x99, 0x94, 0x7A, 0x10, 0xAB,
++   0xC0, 0xA4, 0xB5, 0xFF, 0x8F, 0x3B, 0xB4, 0x51,
++   0x04, 0xE9, 0xB9, 0xC1, 0x98, 0xC5, 0x82, 0x38,
++   0x4D, 0x71, 0xFC, 0x33, 0xC4, 0x50, 0x5D, 0x88,
++   0xB8, 0x5C, 0x32, 0xE2, 0xBB, 0xCD, 0x60, 0x2C,
++   0xD4, 0x7E, 0x27, 0x59, 0x2B, 0x1F, 0x53, 0xF6,
++   0x25, 0x86, 0xAE, 0x21, 0xFA, 0x31, 0xD7, 0x0F,
++   0x17, 0xDA, 0x7F, 0xC9, 0x46, 0x19, 0x08, 0xA8,
++   0xCF, 0x13, 0xCC, 0x03, 0x3F, 0x22, 0x6E, 0xEB,
++   0x4A, 0x63, 0x73, 0xBD, 0x36, 0xED, 0x30, 0x57,
++   0x65, 0xF8, 0x41, 0x61, 0x1E, 0xA0, 0xC6, 0x45,
++   0x3E, 0x75, 0x28, 0x87, 0xCB, 0xD6, 0x16, 0xD8,
++   0xDF, 0xEF, 0xEA, 0xA7, 0x58, 0xB0, 0x1D, 0xE6,
++   0x47, 0x76, 0xD9, 0x96, 0xE7, 0xDC, 0x00, 0x80,
++   0xDD, 0xB7, 0x9A, 0xE1, 0xF5, 0x9C, 0x4B, 0xE3,
++   0xBC, 0x8D, 0xF2, 0x2F, 0x9F, 0x6C, 0x93, 0xAF,
++   0xA9, 0xC2, 0x5E, 0x24, 0x15, 0xD2, 0x09, 0x0D,
++   0xDB, 0x4F, 0x91, 0x0E, 0x64, 0x34, 0x4E, 0xAD,
++   0x62, 0x44, 0x23, 0x85, 0xB6, 0xAC, 0xC7, 0xCA,
++   0x84, 0xF9, 0x8C, 0xBF, 0x14, 0x7C, 0x8E, 0x92,
++   0xF0, 0x0B, 0xCE, 0x90, 0x7D, 0x70, 0x9E, 0x54,
++   0x39, 0x5B, 0x6D, 0x52, 0xEE, 0xA2, 0x6F, 0x78,
++   0x2D, 0x95, 0x8B, 0x02, 0x3D, 0x7B, 0x69, 0xC3,
++   0x49, 0xA5, 0x1A, 0x26, 0xD5, 0x6B, 0xE8, 0xFD,
++   0xB3, 0xD3, 0x20, 0x55, 0x18, 0x06, 0xF3, 0xB1,
++   0x0C, 0xC8, 0x07, 0x12, 0xF7, 0x01, 0x2E, 0x72,
++   0x97, 0xA6, 0x11, 0x89, 0x56, 0x5A, 0x29, 0xBA,
++   0x67, 0x42, 0x83, 0x6A, 0x2A, 0xF1, 0xA1, 0x9B,
++   0xE5, 0xE4, 0x74, 0x66, 0x1C, 0x68, 0xEC, 0x40,
++   0x48, 0x77, 0xD0, 0x0A, 0x8A, 0x3A, 0x43, 0x79 };
++
++unsigned char table_124[256] = {
++   0x6C, 0xC3, 0x28, 0x2F, 0x42, 0x4B, 0x7C, 0x3C,
++   0xCE, 0x24, 0xC8, 0x51, 0x25, 0x3F, 0x49, 0x8D,
++   0x1E, 0x5C, 0x89, 0x3A, 0x98, 0x47, 0x0B, 0x12,
++   0xA9, 0xB1, 0xD7, 0xB6, 0x5D, 0xF9, 0x5A, 0xBC,
++   0xFA, 0x06, 0x7D, 0x08, 0xFC, 0x37, 0x54, 0x4F,
++   0xD4, 0xCD, 0xA7, 0x5E, 0xE0, 0x92, 0x82, 0x56,
++   0xF1, 0x2B, 0xC4, 0xE2, 0x29, 0xEA, 0x35, 0x57,
++   0x33, 0x4E, 0x1A, 0x17, 0x8B, 0x85, 0xBF, 0xD5,
++   0x18, 0xB3, 0x0D, 0x71, 0x45, 0x81, 0xB4, 0x27,
++   0xD1, 0xE1, 0xFF, 0x44, 0x9E, 0xA4, 0x15, 0x9A,
++   0x90, 0xC7, 0x79, 0xE3, 0x4C, 0xE9, 0x3D, 0x6B,
++   0xF5, 0xF4, 0xEE, 0xAA, 0xDB, 0x07, 0x09, 0xCF,
++   0x7B, 0x95, 0xA0, 0x53, 0x8F, 0xA1, 0x9D, 0xBE,
++   0x6F, 0xAE, 0x96, 0x46, 0x59, 0x01, 0x84, 0xCC,
++   0x3B, 0x8E, 0xF7, 0x4D, 0x6E, 0xDC, 0xE8, 0x36,
++   0x7A, 0xE5, 0xBD, 0xE7, 0x9F, 0x2C, 0x52, 0xAB,
++   0x55, 0x13, 0x1D, 0xFB, 0x58, 0x9C, 0xDF, 0xC0,
++   0x30, 0x73, 0x67, 0x39, 0x74, 0xD3, 0x11, 0xD2,
++   0x0E, 0x20, 0xB7, 0x02, 0xB9, 0x1C, 0x86, 0x76,
++   0x10, 0x68, 0x9B, 0x63, 0x48, 0x8A, 0xB2, 0xB8,
++   0xAF, 0x26, 0x99, 0x04, 0xB0, 0xE4, 0xEF, 0xEB,
++   0xEC, 0x6D, 0x61, 0xC1, 0xD0, 0x38, 0xC9, 0x19,
++   0x60, 0xA8, 0xA6, 0xF8, 0x80, 0xC5, 0x03, 0x0F,
++   0x22, 0x2D, 0x88, 0x32, 0x77, 0x70, 0xFE, 0x0C,
++   0x31, 0x40, 0x5F, 0xED, 0xA5, 0x93, 0x43, 0xF0,
++   0x8C, 0xE6, 0x34, 0x21, 0xD9, 0xC2, 0xD8, 0xC6,
++   0x6A, 0xD6, 0xCB, 0xAC, 0x75, 0xB5, 0x78, 0x0A,
++   0xA3, 0x69, 0x16, 0xBA, 0x50, 0x2A, 0x41, 0x83,
++   0xF6, 0x64, 0x00, 0x65, 0x7E, 0xDD, 0x5B, 0xDA,
++   0x14, 0xFD, 0x3E, 0x7F, 0xCA, 0x66, 0x4A, 0x1F,
++   0xA2, 0xAD, 0xF2, 0x23, 0xBB, 0x72, 0xF3, 0x94,
++   0x62, 0x1B, 0xDE, 0x91, 0x87, 0x97, 0x05, 0x2E };
++
++unsigned char table_125[32] = {
++   0x1A, 0x18, 0x12, 0x15, 0x00, 0x1C, 0x01, 0x0B,
++   0x19, 0x1B, 0x1F, 0x11, 0x07, 0x10, 0x1E, 0x06,
++   0x17, 0x04, 0x0A, 0x0E, 0x0D, 0x0C, 0x16, 0x08,
++   0x02, 0x03, 0x13, 0x14, 0x09, 0x1D, 0x05, 0x0F };
++
++unsigned char table_126[32] = {
++   0x1C, 0x1D, 0x07, 0x12, 0x18, 0x1A, 0x19, 0x09,
++   0x0F, 0x14, 0x1F, 0x0B, 0x13, 0x04, 0x0E, 0x1E,
++   0x0C, 0x0D, 0x01, 0x17, 0x1B, 0x16, 0x0A, 0x05,
++   0x15, 0x10, 0x11, 0x08, 0x00, 0x03, 0x06, 0x02 };
++
++unsigned char table_127[256] = {
++   0xA0, 0x66, 0xD8, 0x08, 0xEA, 0x39, 0x78, 0xAB,
++   0x61, 0x4E, 0xC7, 0xD1, 0xA3, 0x1C, 0x9F, 0xCB,
++   0x19, 0x51, 0x15, 0x92, 0x23, 0xFD, 0x7D, 0x1D,
++   0x95, 0xAE, 0x0E, 0x8B, 0xE6, 0x7F, 0x86, 0x6D,
++   0x06, 0xBD, 0x20, 0x1F, 0x3A, 0xE4, 0x54, 0x91,
++   0x69, 0xD3, 0xE3, 0x3D, 0x4D, 0x31, 0x49, 0xA4,
++   0x41, 0xF3, 0xE0, 0x11, 0x14, 0x9B, 0x96, 0x5A,
++   0xC4, 0x8E, 0x34, 0xDB, 0xBA, 0x83, 0xD9, 0x81,
++   0xAF, 0x58, 0x8A, 0x79, 0x13, 0xBC, 0x85, 0x37,
++   0x9E, 0x6C, 0x57, 0x71, 0x8D, 0x97, 0x5F, 0x6F,
++   0x1E, 0x74, 0x27, 0xFC, 0x5C, 0x7A, 0x64, 0x87,
++   0xF5, 0xC6, 0xF2, 0x4F, 0xDE, 0x80, 0xAA, 0x84,
++   0x2E, 0xDC, 0xE7, 0x40, 0x75, 0xC5, 0xB3, 0xC8,
++   0xCE, 0x21, 0x02, 0x67, 0xB7, 0x10, 0x47, 0x6A,
++   0xEE, 0x53, 0x2C, 0x16, 0x05, 0xC0, 0x63, 0x4C,
++   0x0D, 0xBB, 0xC3, 0x38, 0x46, 0x68, 0x7E, 0xF9,
++   0xB8, 0xB4, 0x3E, 0x36, 0xD5, 0xEC, 0x0B, 0xF6,
++   0x33, 0x0A, 0x0F, 0x5B, 0xFB, 0x45, 0xEB, 0xA9,
++   0x6E, 0x6B, 0xCF, 0x55, 0x99, 0xAC, 0x22, 0xBE,
++   0xB1, 0xA2, 0x3F, 0x25, 0x77, 0x8F, 0x7C, 0xF1,
++   0xD4, 0x59, 0xA8, 0xE5, 0xD7, 0xCA, 0xA1, 0x93,
++   0xE9, 0xAD, 0xF7, 0x94, 0xEF, 0xED, 0x3C, 0x2A,
++   0x88, 0xB5, 0x35, 0x9D, 0x9C, 0x32, 0x5E, 0xB6,
++   0x48, 0x9A, 0x7B, 0x26, 0x50, 0x90, 0x04, 0xA7,
++   0xDD, 0x09, 0xB9, 0x98, 0xB2, 0xFE, 0xDF, 0x44,
++   0x89, 0x29, 0x5D, 0xE2, 0x72, 0xC9, 0x28, 0x03,
++   0x43, 0x8C, 0x52, 0x18, 0xC1, 0x56, 0x1B, 0x1A,
++   0x01, 0x65, 0xDA, 0xBF, 0x07, 0xFF, 0x76, 0xE8,
++   0x30, 0xA5, 0x4A, 0xA6, 0x12, 0x62, 0x24, 0x60,
++   0x4B, 0x73, 0x0C, 0xF0, 0xFA, 0x42, 0xF4, 0x00,
++   0xD2, 0xD0, 0xD6, 0x3B, 0xC2, 0x2F, 0xE1, 0x2B,
++   0x70, 0xF8, 0x17, 0xCD, 0xB0, 0xCC, 0x82, 0x2D };
++
++unsigned char table_128[32] = {
++   0x1A, 0x1C, 0x09, 0x17, 0x1B, 0x0B, 0x16, 0x1E,
++   0x14, 0x0C, 0x12, 0x0E, 0x05, 0x03, 0x1F, 0x15,
++   0x19, 0x0D, 0x10, 0x13, 0x0A, 0x01, 0x00, 0x11,
++   0x02, 0x08, 0x0F, 0x18, 0x07, 0x04, 0x1D, 0x06 };
++
++unsigned char table_129[256] = {
++   0x9D, 0x5F, 0xE8, 0x99, 0x57, 0x07, 0x16, 0xA6,
++   0x9F, 0xB6, 0xDE, 0xED, 0x2D, 0xB3, 0xC0, 0x8E,
++   0xCC, 0x49, 0xCE, 0xB0, 0x1B, 0xB1, 0x7A, 0xE0,
++   0xEB, 0x28, 0xDB, 0x7D, 0x88, 0xC8, 0x06, 0x6C,
++   0x02, 0xD0, 0x85, 0x7E, 0xDF, 0xF5, 0x78, 0xE5,
++   0xA9, 0x71, 0xD9, 0xDD, 0xDC, 0xEE, 0x8C, 0x54,
++   0xA0, 0x86, 0xFE, 0x0E, 0x55, 0xF7, 0x41, 0x47,
++   0x1D, 0x15, 0xD6, 0xA4, 0xFF, 0x1F, 0x25, 0xF8,
++   0x12, 0xE9, 0x74, 0x7B, 0x04, 0xE6, 0x4C, 0x31,
++   0xA2, 0xBE, 0x0C, 0xB9, 0x17, 0xBD, 0x3D, 0xF0,
++   0x9E, 0x4D, 0x4E, 0xB2, 0xE7, 0x40, 0xC9, 0x8A,
++   0x67, 0x5E, 0x19, 0x0F, 0xB7, 0x22, 0x8D, 0xBA,
++   0xFC, 0x93, 0x14, 0xEA, 0xFD, 0x0D, 0xD5, 0x38,
++   0xA1, 0x84, 0x1C, 0x35, 0x60, 0x37, 0x43, 0x9C,
++   0xCF, 0xEF, 0x3A, 0x72, 0xF2, 0x61, 0x75, 0x6A,
++   0x42, 0xAC, 0xD3, 0x48, 0x77, 0xC5, 0x29, 0xF6,
++   0x58, 0x79, 0xFA, 0x5D, 0xC7, 0x70, 0x53, 0x9A,
++   0x6F, 0xC1, 0x0A, 0x90, 0x8F, 0x3E, 0x3B, 0x8B,
++   0xEC, 0xBC, 0x20, 0x27, 0xC3, 0x66, 0x3F, 0x33,
++   0xA5, 0x44, 0x2E, 0x32, 0x65, 0x18, 0xFB, 0x59,
++   0x52, 0x50, 0xE2, 0x63, 0x2B, 0xCD, 0x64, 0xCB,
++   0xD2, 0x68, 0x10, 0xA7, 0xAE, 0x11, 0xA8, 0x96,
++   0x69, 0xAF, 0xC2, 0x34, 0x5C, 0x56, 0xE3, 0xF9,
++   0xDA, 0x51, 0x81, 0x4A, 0x05, 0x00, 0xB8, 0x7C,
++   0x30, 0x2F, 0x46, 0xB4, 0xC6, 0x87, 0x4B, 0x94,
++   0x80, 0xF4, 0x7F, 0x3C, 0x26, 0xF1, 0x5B, 0xAB,
++   0x91, 0x6E, 0x08, 0x76, 0x98, 0xD1, 0xE1, 0x36,
++   0x21, 0xCA, 0xD8, 0x24, 0x9B, 0x39, 0xBB, 0xAD,
++   0x13, 0x62, 0x97, 0x1A, 0x6D, 0x2C, 0x5A, 0xC4,
++   0xD4, 0xA3, 0x03, 0xBF, 0x1E, 0xE4, 0xF3, 0x95,
++   0x23, 0x73, 0x92, 0xB5, 0x01, 0x83, 0x82, 0xAA,
++   0x09, 0x45, 0x6B, 0xD7, 0x0B, 0x89, 0x4F, 0x2A };
++
++unsigned char table_130[32] = {
++   0x07, 0x03, 0x15, 0x0B, 0x02, 0x11, 0x17, 0x14,
++   0x05, 0x10, 0x0A, 0x0F, 0x01, 0x1C, 0x1D, 0x0E,
++   0x12, 0x06, 0x18, 0x16, 0x1A, 0x09, 0x13, 0x19,
++   0x1B, 0x00, 0x08, 0x0D, 0x0C, 0x1E, 0x04, 0x1F };
++
++unsigned char table_131[32] = {
++   0x1D, 0x13, 0x1B, 0x10, 0x07, 0x03, 0x0A, 0x02,
++   0x00, 0x0C, 0x0E, 0x0B, 0x0D, 0x18, 0x12, 0x1F,
++   0x1A, 0x04, 0x15, 0x11, 0x1E, 0x08, 0x1C, 0x14,
++   0x19, 0x05, 0x0F, 0x17, 0x06, 0x01, 0x09, 0x16 };
++
++unsigned char table_132[256] = {
++   0x33, 0x8D, 0x45, 0x6F, 0xFF, 0xF5, 0xB6, 0x53,
++   0x3B, 0xF3, 0x07, 0xA4, 0x97, 0xEB, 0x6B, 0xA5,
++   0xD3, 0xDC, 0x7B, 0x79, 0x93, 0xE7, 0xF7, 0x67,
++   0x9C, 0x4F, 0x88, 0xF9, 0x3A, 0x2B, 0x27, 0x48,
++   0x47, 0x18, 0xF4, 0xAD, 0xB4, 0x8F, 0x2A, 0x76,
++   0x17, 0xE9, 0x1F, 0x40, 0x0C, 0x59, 0xD1, 0x4C,
++   0x20, 0x31, 0x73, 0x54, 0xCD, 0x68, 0x08, 0x52,
++   0x10, 0x62, 0x3D, 0xD2, 0x77, 0xF2, 0xD7, 0x30,
++   0xCA, 0x16, 0x01, 0x50, 0x9F, 0x3F, 0x75, 0xED,
++   0x90, 0x6A, 0x34, 0xCE, 0x05, 0x78, 0x5E, 0xD6,
++   0x85, 0xCC, 0x29, 0xB8, 0xC1, 0x0D, 0xCB, 0x80,
++   0x2E, 0x04, 0x00, 0x44, 0x32, 0x95, 0xBF, 0xFE,
++   0x6E, 0x7C, 0xFD, 0xA7, 0x3C, 0x5C, 0xF0, 0xEC,
++   0xAC, 0xF8, 0xB9, 0xC0, 0x1B, 0x3E, 0xE8, 0x66,
++   0x5D, 0xDE, 0x49, 0x71, 0xAA, 0xAF, 0x21, 0x64,
++   0x28, 0x8A, 0x4E, 0x98, 0x58, 0xA2, 0x23, 0xCF,
++   0x9E, 0x63, 0x61, 0x91, 0x12, 0xC6, 0x8C, 0x19,
++   0xA8, 0xD4, 0xC7, 0xDD, 0xFC, 0xBD, 0x38, 0xDF,
++   0xEA, 0x2D, 0x7E, 0x7D, 0xE3, 0xE0, 0xC3, 0xD9,
++   0x8B, 0x11, 0xF1, 0x4D, 0xC8, 0xB5, 0x55, 0xAE,
++   0xE1, 0x89, 0xE5, 0xB3, 0xBC, 0x69, 0x9D, 0xA6,
++   0x09, 0x9A, 0x74, 0x35, 0x1A, 0xFB, 0x24, 0xB7,
++   0x13, 0x14, 0x94, 0x0A, 0x86, 0x0F, 0x60, 0x51,
++   0xB0, 0x84, 0x22, 0x5B, 0x87, 0x43, 0x57, 0x0B,
++   0x2F, 0x5F, 0x02, 0xD0, 0xBB, 0xA3, 0xC9, 0x7A,
++   0xBE, 0xC2, 0x26, 0x46, 0xDB, 0x1E, 0x1D, 0x92,
++   0xE2, 0xB2, 0x37, 0x6D, 0xD5, 0x4A, 0x0E, 0x4B,
++   0x8E, 0xC5, 0x42, 0x99, 0xEE, 0xE4, 0xB1, 0x06,
++   0xAB, 0x5A, 0x56, 0x41, 0x65, 0xBA, 0xFA, 0x83,
++   0x15, 0xDA, 0x72, 0xA1, 0x81, 0x1C, 0xA9, 0x36,
++   0x25, 0x96, 0x6C, 0x39, 0x82, 0xE6, 0x2C, 0x9B,
++   0xC4, 0x7F, 0xA0, 0xD8, 0xEF, 0x03, 0x70, 0xF6 };
++
++unsigned char table_133[256] = {
++   0x02, 0xF0, 0xED, 0xC4, 0xE4, 0x67, 0x60, 0x8B,
++   0xF3, 0x77, 0x92, 0xE0, 0x85, 0x93, 0x1E, 0x8E,
++   0x9A, 0x38, 0x61, 0x20, 0xB7, 0x68, 0xE1, 0x5E,
++   0xD5, 0x63, 0xA9, 0xA5, 0xBE, 0x36, 0x12, 0x4D,
++   0x86, 0x16, 0xD6, 0xB1, 0x23, 0x64, 0x4F, 0x62,
++   0xFC, 0xA3, 0xD3, 0x04, 0x7D, 0x8C, 0xE2, 0xFF,
++   0x5D, 0x30, 0xF5, 0x95, 0x1B, 0x5F, 0x73, 0xAA,
++   0xE8, 0x07, 0x87, 0xDC, 0x54, 0x7C, 0xEE, 0x00,
++   0xB8, 0xDE, 0x55, 0xBA, 0xD0, 0x50, 0xBB, 0x89,
++   0x1C, 0xCC, 0x0E, 0xC0, 0x42, 0x11, 0xD8, 0xA2,
++   0x2E, 0x33, 0xFE, 0x26, 0xD4, 0x10, 0xDA, 0xC5,
++   0xFB, 0xAF, 0x98, 0x78, 0xB5, 0xBD, 0xC8, 0x8D,
++   0x46, 0xA0, 0xD1, 0x7B, 0xBC, 0x75, 0xAB, 0x25,
++   0xB2, 0x43, 0x57, 0xB6, 0xEC, 0xF4, 0x66, 0x05,
++   0x9C, 0x08, 0x53, 0x80, 0xEA, 0x21, 0x2C, 0x6C,
++   0x17, 0x71, 0xD2, 0x70, 0x76, 0x9E, 0x6B, 0x7A,
++   0x58, 0xA7, 0xBF, 0x29, 0x03, 0x1F, 0x06, 0xC1,
++   0xDD, 0x2F, 0x5C, 0x0B, 0x0D, 0x8A, 0x0A, 0xCB,
++   0xCA, 0x6F, 0x19, 0x6A, 0xFA, 0xF7, 0xA8, 0xA1,
++   0xEB, 0x88, 0x44, 0xAC, 0x01, 0x4E, 0x59, 0x94,
++   0x72, 0x2B, 0xE9, 0x0F, 0x22, 0x9B, 0x27, 0x37,
++   0x41, 0xF9, 0xF2, 0xE3, 0xEF, 0xB3, 0xD9, 0x2A,
++   0x31, 0xC2, 0x0C, 0x15, 0x90, 0x14, 0xF6, 0x83,
++   0xFD, 0x96, 0x9D, 0x7F, 0xA4, 0x39, 0xE7, 0x3F,
++   0xE6, 0xC7, 0xCD, 0x1A, 0xCF, 0x48, 0x3C, 0x51,
++   0x6D, 0x5B, 0x74, 0xC3, 0xC9, 0x09, 0x3D, 0x9F,
++   0xDB, 0x32, 0x40, 0x18, 0xD7, 0xCE, 0x69, 0x49,
++   0x3A, 0xF1, 0xB9, 0x56, 0x91, 0x99, 0x84, 0x24,
++   0x7E, 0x34, 0x4B, 0xA6, 0x47, 0xB4, 0x6E, 0xDF,
++   0x65, 0x3B, 0xAD, 0x45, 0x13, 0xC6, 0x81, 0xF8,
++   0x4A, 0x2D, 0x8F, 0x4C, 0x97, 0x28, 0x3E, 0xE5,
++   0x5A, 0x35, 0xB0, 0xAE, 0x82, 0x79, 0x1D, 0x52 };
++
++unsigned char table_134[32] = {
++   0x09, 0x0F, 0x10, 0x0C, 0x03, 0x15, 0x07, 0x17,
++   0x0E, 0x0B, 0x1D, 0x08, 0x19, 0x11, 0x00, 0x0A,
++   0x01, 0x06, 0x18, 0x16, 0x0D, 0x13, 0x14, 0x12,
++   0x02, 0x1B, 0x1A, 0x04, 0x05, 0x1F, 0x1C, 0x1E };
++
++unsigned char table_135[256] = {
++   0x14, 0x34, 0xEA, 0x02, 0x2B, 0x5A, 0x10, 0x51,
++   0xF3, 0x8F, 0x28, 0xB2, 0x50, 0x8B, 0x01, 0xCC,
++   0x80, 0x15, 0x29, 0x42, 0xF4, 0x1D, 0xFB, 0xBB,
++   0x1F, 0x43, 0x8C, 0x17, 0x1E, 0x81, 0x04, 0x98,
++   0x46, 0xD8, 0xD5, 0x65, 0x4C, 0x1C, 0xDB, 0x40,
++   0x5F, 0x1A, 0x31, 0x74, 0xF1, 0x64, 0x19, 0x05,
++   0xFC, 0xF0, 0x73, 0xB6, 0x23, 0x77, 0x9C, 0xCE,
++   0x70, 0xEF, 0xDA, 0xE0, 0xA2, 0x78, 0x84, 0xEB,
++   0x9E, 0xC5, 0x95, 0xA3, 0xF6, 0xCA, 0xAD, 0x52,
++   0xD0, 0x3F, 0x54, 0xA7, 0x33, 0xA9, 0x09, 0x6A,
++   0x89, 0x7E, 0x75, 0xA8, 0xD6, 0x79, 0x9F, 0xAB,
++   0x8E, 0x11, 0x0E, 0x3B, 0xAA, 0xE6, 0x85, 0x53,
++   0x0A, 0x59, 0xEC, 0x94, 0xD7, 0x41, 0x86, 0x7D,
++   0x2F, 0xC7, 0xDE, 0x06, 0xCB, 0x13, 0xBA, 0x58,
++   0xC8, 0xC9, 0x07, 0x67, 0x7F, 0xA5, 0xB4, 0x2C,
++   0x48, 0x6C, 0xB8, 0xD1, 0x30, 0xD3, 0x35, 0x4F,
++   0x88, 0x26, 0x93, 0x32, 0x71, 0x3E, 0x3D, 0xF7,
++   0x6D, 0x03, 0xED, 0x8A, 0x36, 0x55, 0x9B, 0x66,
++   0x8D, 0x27, 0x7C, 0xF9, 0xA6, 0xC3, 0x20, 0x69,
++   0x4A, 0xE3, 0x99, 0x5C, 0xBC, 0x45, 0x16, 0x6B,
++   0xB9, 0x49, 0x82, 0xFF, 0xBD, 0xDD, 0xE9, 0x0C,
++   0xD4, 0x44, 0xFD, 0x22, 0xE5, 0xAC, 0x61, 0xC4,
++   0x90, 0x47, 0x37, 0x72, 0xA4, 0x7A, 0x24, 0x4D,
++   0x5B, 0x12, 0x38, 0x92, 0x87, 0x1B, 0xE1, 0xA0,
++   0x91, 0x3C, 0xEE, 0x6F, 0xC1, 0x0F, 0x56, 0xC2,
++   0x9A, 0xF8, 0x18, 0xE8, 0xD2, 0xDC, 0x4B, 0xCF,
++   0x39, 0xF5, 0xFE, 0x2A, 0x2D, 0x9D, 0xA1, 0xFA,
++   0xE7, 0xBF, 0x6E, 0xE4, 0x2E, 0xB3, 0xCD, 0xE2,
++   0xAF, 0x7B, 0xC0, 0x68, 0x97, 0xB5, 0x5D, 0xB7,
++   0x21, 0x57, 0x83, 0x76, 0xB1, 0xAE, 0x5E, 0x0D,
++   0x96, 0x4E, 0x08, 0xC6, 0x0B, 0xDF, 0x3A, 0xB0,
++   0x00, 0x63, 0xD9, 0xBE, 0xF2, 0x60, 0x25, 0x62 };
++
++unsigned char table_136[256] = {
++   0xD3, 0x1A, 0x00, 0xED, 0x59, 0x24, 0xA3, 0xF2,
++   0xBA, 0x58, 0x4C, 0x5C, 0x75, 0x48, 0x98, 0xB0,
++   0xCF, 0xC3, 0xF7, 0x88, 0x70, 0xB3, 0x3D, 0x3E,
++   0x03, 0xF9, 0xC9, 0xFD, 0x80, 0x44, 0x7F, 0x3B,
++   0x95, 0x5F, 0x31, 0x47, 0x15, 0x07, 0xB8, 0x08,
++   0xCE, 0xDA, 0x71, 0x9F, 0x83, 0xB1, 0x55, 0x16,
++   0xE6, 0xB2, 0xC7, 0xBE, 0x54, 0xE7, 0x2E, 0x8D,
++   0x12, 0x21, 0x41, 0x69, 0xFE, 0x28, 0x11, 0x56,
++   0x5A, 0xDD, 0xB6, 0x87, 0x78, 0x82, 0x4D, 0x7B,
++   0x50, 0x9A, 0x9E, 0x62, 0xF8, 0x0A, 0x64, 0xF1,
++   0x4E, 0x33, 0xAD, 0xBB, 0x79, 0x76, 0xD8, 0xCD,
++   0x86, 0x34, 0x29, 0xD5, 0x7D, 0x72, 0xC5, 0xC1,
++   0xDF, 0x09, 0x4A, 0xB4, 0xD2, 0x7A, 0xF0, 0xCC,
++   0x0F, 0xA7, 0xD6, 0x2B, 0x20, 0x26, 0xEF, 0xAB,
++   0x74, 0x1E, 0xE3, 0x77, 0xCB, 0x7C, 0x73, 0x5E,
++   0x6B, 0x0D, 0x65, 0xA6, 0x30, 0xFB, 0xD0, 0xB7,
++   0xAA, 0x94, 0x9D, 0x85, 0x13, 0x18, 0xA8, 0xF3,
++   0xE0, 0xBC, 0x45, 0xCA, 0xC8, 0xDC, 0xE2, 0x3C,
++   0x23, 0xE5, 0xB9, 0x90, 0x49, 0xA5, 0xE4, 0x36,
++   0xFC, 0x53, 0xF6, 0xE8, 0xC6, 0x2C, 0x02, 0x25,
++   0xC0, 0x8F, 0x61, 0xA4, 0x39, 0x8C, 0x5D, 0xAE,
++   0x22, 0x1C, 0x2F, 0xD4, 0x6C, 0xD1, 0x51, 0xEA,
++   0x4F, 0x7E, 0xA0, 0xF5, 0x6A, 0x32, 0xA2, 0x01,
++   0xB5, 0x10, 0x2A, 0xAC, 0xA9, 0x06, 0xC4, 0x91,
++   0x68, 0xE1, 0xBD, 0x14, 0x38, 0xFA, 0x6E, 0x3F,
++   0x37, 0x66, 0xDB, 0x57, 0x43, 0x1B, 0x67, 0xAF,
++   0x1F, 0x0B, 0x6D, 0x2D, 0x89, 0x04, 0x4B, 0x52,
++   0xC2, 0xBF, 0xA1, 0x92, 0x99, 0x6F, 0x63, 0x81,
++   0x27, 0x05, 0x96, 0x3A, 0xEC, 0x0E, 0x97, 0xD9,
++   0xDE, 0x46, 0x35, 0x8B, 0x8E, 0x8A, 0xF4, 0xFF,
++   0x60, 0xD7, 0xE9, 0x17, 0xEB, 0x9C, 0x84, 0x0C,
++   0x93, 0x1D, 0x9B, 0x5B, 0x40, 0xEE, 0x42, 0x19 };
++
++unsigned char table_137[32] = {
++   0x0F, 0x09, 0x02, 0x06, 0x18, 0x0B, 0x1E, 0x05,
++   0x11, 0x1D, 0x16, 0x01, 0x13, 0x10, 0x0E, 0x1A,
++   0x1B, 0x00, 0x0D, 0x08, 0x15, 0x14, 0x19, 0x17,
++   0x03, 0x1F, 0x0A, 0x12, 0x0C, 0x07, 0x04, 0x1C };
++
++unsigned char table_138[32] = {
++   0x0D, 0x1C, 0x1F, 0x15, 0x0F, 0x14, 0x1B, 0x12,
++   0x09, 0x0B, 0x19, 0x07, 0x11, 0x16, 0x0C, 0x04,
++   0x13, 0x05, 0x1D, 0x03, 0x0E, 0x0A, 0x08, 0x1E,
++   0x01, 0x06, 0x18, 0x17, 0x10, 0x1A, 0x02, 0x00 };
++
++unsigned char table_139[32] = {
++   0x05, 0x15, 0x1D, 0x02, 0x0F, 0x03, 0x17, 0x1A,
++   0x0A, 0x00, 0x1F, 0x12, 0x0E, 0x11, 0x1B, 0x13,
++   0x0B, 0x0D, 0x09, 0x18, 0x1E, 0x08, 0x14, 0x07,
++   0x0C, 0x04, 0x16, 0x19, 0x1C, 0x06, 0x10, 0x01 };
++
++unsigned char table_140[32] = {
++   0x06, 0x1E, 0x0C, 0x11, 0x13, 0x08, 0x15, 0x01,
++   0x1D, 0x03, 0x0F, 0x19, 0x18, 0x04, 0x00, 0x14,
++   0x12, 0x1A, 0x0B, 0x0E, 0x02, 0x1B, 0x07, 0x05,
++   0x1F, 0x17, 0x09, 0x0A, 0x0D, 0x16, 0x10, 0x1C };
++
++unsigned char table_141[256] = {
++   0xE1, 0x0A, 0x28, 0xCD, 0x8A, 0x1E, 0x26, 0x10,
++   0xC0, 0x6F, 0x06, 0x2C, 0xF8, 0x51, 0x6C, 0x8F,
++   0xA8, 0x8C, 0x41, 0xF4, 0xED, 0x36, 0xAC, 0x89,
++   0xBD, 0x9D, 0x42, 0x50, 0x95, 0x07, 0x2A, 0x9B,
++   0x7E, 0xA3, 0x6B, 0x30, 0x72, 0x4E, 0xBE, 0xD8,
++   0x8B, 0x5B, 0x1A, 0x56, 0x05, 0xEF, 0xEE, 0x64,
++   0xFF, 0xFD, 0x93, 0xB5, 0xD6, 0x04, 0x57, 0xAE,
++   0x4D, 0x6D, 0x2F, 0xBA, 0x40, 0xE0, 0xDB, 0xF2,
++   0xCC, 0x08, 0x35, 0x02, 0xC4, 0x65, 0x66, 0x76,
++   0xA1, 0x97, 0x9F, 0x6A, 0x90, 0xA7, 0x34, 0x1B,
++   0x18, 0xB9, 0xA2, 0xDE, 0x23, 0x1F, 0xCB, 0xE6,
++   0xAB, 0xCF, 0xAD, 0x4A, 0xF7, 0x24, 0xD0, 0xE8,
++   0x8D, 0x49, 0xEA, 0x0F, 0x94, 0x22, 0xD3, 0x74,
++   0x71, 0x0D, 0x21, 0x14, 0x39, 0x4B, 0x16, 0x25,
++   0x5A, 0xB7, 0x17, 0x67, 0x59, 0x47, 0x27, 0x4F,
++   0x32, 0x3B, 0x63, 0x0C, 0xF0, 0xF3, 0x7B, 0xC7,
++   0xCA, 0x3A, 0x9A, 0xE2, 0xD5, 0xFA, 0x91, 0xFC,
++   0x86, 0x81, 0x99, 0xB4, 0xBC, 0x7C, 0xC5, 0xBF,
++   0xC1, 0xF5, 0x77, 0xA4, 0x79, 0x11, 0x8E, 0x75,
++   0x55, 0x3D, 0x78, 0x20, 0x37, 0x3E, 0x85, 0xE4,
++   0x2E, 0x82, 0xA9, 0x7A, 0x31, 0xC9, 0xB3, 0xFE,
++   0x4C, 0x7D, 0xC3, 0xA0, 0x0E, 0x96, 0x5C, 0xC6,
++   0x1C, 0x5F, 0xD7, 0xDD, 0x83, 0xC8, 0x9E, 0xEC,
++   0x3F, 0xAF, 0x38, 0x9C, 0xD9, 0xB6, 0xDA, 0xD4,
++   0x61, 0x44, 0x43, 0xAA, 0xB1, 0xCE, 0xE7, 0x84,
++   0x00, 0x0B, 0xFB, 0x68, 0xC2, 0x3C, 0x58, 0xB2,
++   0x69, 0x7F, 0x33, 0x2B, 0x80, 0x03, 0xE9, 0x88,
++   0x29, 0x12, 0x01, 0x6E, 0x62, 0xF1, 0xA6, 0xF9,
++   0x5D, 0xD2, 0xE3, 0x53, 0x09, 0x2D, 0xBB, 0x15,
++   0xEB, 0x13, 0xA5, 0xF6, 0x73, 0x19, 0x60, 0xB0,
++   0xD1, 0x48, 0x92, 0x1D, 0x52, 0x5E, 0x45, 0x70,
++   0x98, 0x54, 0xB8, 0xDC, 0x46, 0xDF, 0x87, 0xE5 };
++
++unsigned char table_142[256] = {
++   0x90, 0x94, 0xBE, 0x14, 0x99, 0xEB, 0x45, 0x0F,
++   0x34, 0x4A, 0xE3, 0x79, 0xD2, 0x64, 0x4D, 0x69,
++   0x91, 0xDE, 0xB9, 0x1C, 0x59, 0x20, 0x6C, 0x0B,
++   0x16, 0xC7, 0x1D, 0x18, 0x02, 0x7D, 0x13, 0xB2,
++   0x7B, 0x81, 0xCF, 0x61, 0xA3, 0x33, 0x00, 0x73,
++   0x5A, 0x8A, 0xA1, 0xA8, 0x31, 0xAC, 0xF0, 0x67,
++   0xAE, 0xA5, 0x2A, 0x96, 0x58, 0xF4, 0xB7, 0x0E,
++   0xE1, 0x54, 0x27, 0x83, 0x09, 0x85, 0xF8, 0x84,
++   0xEA, 0xAD, 0x06, 0xED, 0x43, 0xFF, 0xA2, 0x6E,
++   0x68, 0x46, 0x74, 0x47, 0x3C, 0xAA, 0xBC, 0x55,
++   0xA7, 0xC3, 0x82, 0xDC, 0xBF, 0x38, 0x80, 0x15,
++   0xF6, 0xB3, 0x92, 0x7C, 0x93, 0x3F, 0xE9, 0x4C,
++   0x35, 0x30, 0x32, 0xF3, 0x88, 0xC0, 0x49, 0x6D,
++   0xCE, 0x42, 0xDF, 0xFD, 0x78, 0x6A, 0x24, 0xCA,
++   0xB8, 0xFC, 0xA6, 0x5F, 0x29, 0xFE, 0x0C, 0x5C,
++   0x0D, 0x23, 0x8B, 0x9D, 0xD4, 0x03, 0x2C, 0x9C,
++   0x77, 0xD8, 0x39, 0x8C, 0x57, 0xD5, 0xE0, 0x8F,
++   0xC6, 0xB0, 0xCD, 0x48, 0xC9, 0xA0, 0xDA, 0xC8,
++   0xD1, 0x5B, 0xAB, 0x37, 0x5D, 0x63, 0xAF, 0xF9,
++   0x17, 0x1B, 0xE5, 0xF1, 0x36, 0xC1, 0x04, 0x26,
++   0x6F, 0x9E, 0xD9, 0x2F, 0x7F, 0xB5, 0x3A, 0xD6,
++   0xE6, 0x40, 0x07, 0xCB, 0x7E, 0x3E, 0xC5, 0x22,
++   0xEC, 0xE2, 0xD3, 0x4E, 0x65, 0x2D, 0x70, 0xE7,
++   0x10, 0x19, 0xD0, 0xEF, 0xBD, 0xC2, 0x44, 0xB4,
++   0xF7, 0xA4, 0x53, 0x9F, 0x86, 0xFA, 0xE8, 0x4B,
++   0x28, 0x3D, 0x9B, 0x56, 0x89, 0x6B, 0x25, 0x71,
++   0x60, 0x11, 0x9A, 0x5E, 0x1A, 0x52, 0x08, 0x4F,
++   0xB1, 0xDD, 0xBB, 0x98, 0xFB, 0x12, 0x3B, 0x0A,
++   0x2E, 0xDB, 0x62, 0x8D, 0xC4, 0x75, 0xA9, 0x2B,
++   0xE4, 0x97, 0x72, 0xF5, 0xEE, 0xF2, 0xB6, 0x21,
++   0xBA, 0x7A, 0x76, 0x41, 0x50, 0x66, 0x05, 0x8E,
++   0xCC, 0x1E, 0x87, 0xD7, 0x01, 0x1F, 0x51, 0x95 };
++
++unsigned char table_143[32] = {
++   0x0E, 0x16, 0x18, 0x11, 0x0C, 0x01, 0x12, 0x1F,
++   0x08, 0x15, 0x0A, 0x06, 0x1C, 0x1E, 0x02, 0x1A,
++   0x17, 0x03, 0x07, 0x13, 0x05, 0x19, 0x10, 0x0F,
++   0x0D, 0x14, 0x09, 0x0B, 0x1B, 0x00, 0x1D, 0x04 };
++
++unsigned char table_144[32] = {
++   0x00, 0x1B, 0x17, 0x19, 0x1D, 0x11, 0x0D, 0x1A,
++   0x13, 0x03, 0x1E, 0x09, 0x10, 0x0E, 0x15, 0x05,
++   0x0B, 0x1C, 0x1F, 0x08, 0x0A, 0x06, 0x01, 0x0F,
++   0x16, 0x14, 0x02, 0x04, 0x07, 0x18, 0x12, 0x0C };
++
++unsigned char table_145[256] = {
++   0xF9, 0x2C, 0x38, 0x74, 0xDA, 0x65, 0x85, 0x0E,
++   0xBA, 0x64, 0xDB, 0xE3, 0xB6, 0x8B, 0x0B, 0x5E,
++   0x01, 0x0F, 0x12, 0x8C, 0xD4, 0xCC, 0xB1, 0x7B,
++   0xE7, 0xBC, 0x2E, 0x87, 0x84, 0x3B, 0xF8, 0x4C,
++   0x8E, 0x59, 0x2D, 0xAA, 0xCE, 0x28, 0x1B, 0xEE,
++   0x7F, 0x5C, 0xFB, 0x62, 0x05, 0xD9, 0xDD, 0x9D,
++   0x49, 0x66, 0x82, 0x71, 0xD2, 0xC7, 0xEB, 0xCF,
++   0x5B, 0x41, 0x25, 0xC8, 0x6C, 0xFF, 0x78, 0x97,
++   0x0C, 0xA2, 0x50, 0x7A, 0xAF, 0x2F, 0xB0, 0x7E,
++   0xBB, 0x73, 0xA0, 0x9B, 0x09, 0xDE, 0x35, 0xE9,
++   0x5A, 0x70, 0x56, 0xC5, 0x81, 0x19, 0x55, 0xAB,
++   0xC1, 0xB4, 0x2A, 0x30, 0x54, 0x6F, 0x3E, 0x46,
++   0x5D, 0x37, 0xF5, 0x57, 0x6B, 0x7C, 0x43, 0xE1,
++   0x4A, 0x3F, 0xB2, 0x4B, 0x77, 0xB5, 0x44, 0xD6,
++   0x91, 0x11, 0x72, 0xE8, 0xBE, 0xA5, 0xA8, 0xD3,
++   0x9A, 0x17, 0x86, 0x88, 0x16, 0x3C, 0x36, 0xD8,
++   0x6E, 0x07, 0x8D, 0x5F, 0xFA, 0xF1, 0x24, 0x7D,
++   0x20, 0x60, 0x0D, 0x89, 0xC9, 0x29, 0xA7, 0x2B,
++   0x4E, 0x10, 0x9F, 0xE5, 0x61, 0x32, 0x3A, 0xBF,
++   0x93, 0xE6, 0xF3, 0x52, 0x80, 0xC4, 0x02, 0x22,
++   0xA4, 0xBD, 0xF0, 0x48, 0x51, 0xF2, 0xD7, 0x33,
++   0x00, 0x53, 0x98, 0xEC, 0x47, 0x39, 0xB9, 0x90,
++   0x76, 0x4F, 0x68, 0x3D, 0x9C, 0x92, 0xD5, 0xB8,
++   0xAE, 0xD0, 0xF4, 0x67, 0x58, 0xC0, 0x06, 0x08,
++   0x14, 0x31, 0xDC, 0xA1, 0x15, 0xDF, 0xCA, 0xE2,
++   0x23, 0xFE, 0xE4, 0x8F, 0x0A, 0xFC, 0x8A, 0xA3,
++   0xC6, 0xCD, 0x6A, 0x75, 0xFD, 0x42, 0xB7, 0x79,
++   0x96, 0x1D, 0x63, 0x18, 0xA9, 0x1C, 0x83, 0x6D,
++   0xE0, 0x34, 0x04, 0xA6, 0x13, 0xAC, 0xD1, 0xF7,
++   0x26, 0xC3, 0x1F, 0x27, 0x45, 0x95, 0xCB, 0x21,
++   0xED, 0x1A, 0x9E, 0x99, 0xEA, 0x40, 0x94, 0x4D,
++   0x69, 0xF6, 0xEF, 0xC2, 0xAD, 0x03, 0xB3, 0x1E };
++
++unsigned char table_146[256] = {
++   0x1C, 0xF5, 0x16, 0xD2, 0xCC, 0xDC, 0x1E, 0x29,
++   0xE3, 0x17, 0x3B, 0x66, 0x6A, 0xF7, 0x03, 0xB2,
++   0x92, 0x45, 0x4D, 0xD6, 0x0C, 0x5E, 0xE6, 0x01,
++   0xDE, 0xCE, 0x83, 0xFA, 0x35, 0x02, 0x85, 0xC4,
++   0x2E, 0x89, 0x8D, 0xE7, 0x30, 0x93, 0xDD, 0x70,
++   0x80, 0xD9, 0x6D, 0x81, 0x07, 0x8E, 0xA9, 0xA6,
++   0x5F, 0xC9, 0xF3, 0x9D, 0x65, 0xE8, 0x88, 0x0B,
++   0x49, 0xAA, 0xB7, 0x6C, 0x11, 0xFC, 0x6F, 0xA3,
++   0xF8, 0x52, 0x0E, 0xD4, 0x08, 0x25, 0x27, 0x33,
++   0x2F, 0xF0, 0x2B, 0x47, 0xDA, 0x4C, 0x39, 0x54,
++   0xB9, 0xC1, 0xEA, 0x7C, 0x44, 0xEB, 0x06, 0xE1,
++   0x8C, 0x9B, 0x74, 0x42, 0x4F, 0x0A, 0x69, 0x2A,
++   0x2D, 0xA1, 0x19, 0xD5, 0xC3, 0x87, 0x68, 0xFF,
++   0xEC, 0xE4, 0x86, 0xCF, 0xF6, 0x79, 0x34, 0xA8,
++   0x72, 0xF4, 0x8B, 0xAF, 0xA5, 0x00, 0xBA, 0x5C,
++   0x23, 0xB8, 0xC8, 0x59, 0xBF, 0x6E, 0xCB, 0x20,
++   0x1F, 0x53, 0x97, 0x4B, 0xD0, 0x55, 0x5B, 0xDF,
++   0x8A, 0xED, 0x9A, 0x62, 0xC5, 0xD7, 0x18, 0x82,
++   0xC7, 0x12, 0x15, 0x1B, 0xC0, 0x38, 0xCA, 0x26,
++   0xDB, 0xAE, 0xF9, 0x90, 0x1A, 0xF2, 0x56, 0x32,
++   0x21, 0x3C, 0x43, 0xEE, 0xA4, 0x13, 0x94, 0xA2,
++   0x46, 0x77, 0xBC, 0xB6, 0x9C, 0x0D, 0xCD, 0x37,
++   0x63, 0x60, 0x6B, 0x3A, 0x3E, 0xA7, 0xD8, 0xFE,
++   0xFB, 0xEF, 0x67, 0xFD, 0xAD, 0xF1, 0x09, 0x1D,
++   0xE9, 0x51, 0xB4, 0x95, 0x75, 0x0F, 0xB3, 0xD3,
++   0xAB, 0x22, 0xBB, 0x61, 0x7F, 0x5A, 0x58, 0x7B,
++   0x73, 0xC2, 0x05, 0xE0, 0x14, 0xE2, 0xAC, 0x91,
++   0xBE, 0x4E, 0xC6, 0x7A, 0x84, 0x50, 0x28, 0x3F,
++   0xB0, 0x04, 0x7E, 0xD1, 0x40, 0xBD, 0xE5, 0x71,
++   0xB1, 0x78, 0x41, 0x9E, 0x57, 0x64, 0x8F, 0x24,
++   0x4A, 0x9F, 0x3D, 0x31, 0x36, 0x5D, 0xA0, 0x2C,
++   0x7D, 0x96, 0x76, 0x99, 0xB5, 0x48, 0x98, 0x10 };
++
++unsigned char table_147[32] = {
++   0x17, 0x07, 0x0D, 0x16, 0x00, 0x1B, 0x1F, 0x09,
++   0x10, 0x11, 0x14, 0x0A, 0x02, 0x06, 0x13, 0x0C,
++   0x08, 0x1E, 0x0F, 0x12, 0x05, 0x15, 0x19, 0x01,
++   0x1C, 0x1A, 0x03, 0x18, 0x04, 0x0B, 0x1D, 0x0E };
++
++unsigned char table_148[256] = {
++   0xFB, 0x23, 0xBC, 0x5A, 0x8C, 0x02, 0x42, 0x3B,
++   0x95, 0x0C, 0x21, 0x0E, 0x14, 0xDF, 0x11, 0xC0,
++   0xDB, 0x5E, 0xD3, 0xEA, 0xCE, 0xB4, 0x32, 0x12,
++   0x70, 0x68, 0xA3, 0x25, 0x5B, 0x4B, 0x47, 0xA5,
++   0x84, 0x9B, 0xFA, 0xD1, 0xE1, 0x3C, 0x20, 0x93,
++   0x41, 0x26, 0x81, 0x39, 0x17, 0xA4, 0xCF, 0xB9,
++   0xC5, 0x5F, 0x1C, 0xB3, 0x88, 0xC2, 0x92, 0x30,
++   0x0A, 0xB8, 0xA0, 0xE2, 0x50, 0x2B, 0x48, 0x1E,
++   0xD5, 0x13, 0xC7, 0x46, 0x9E, 0x2A, 0xF7, 0x7E,
++   0xE8, 0x82, 0x60, 0x7A, 0x36, 0x97, 0x0F, 0x8F,
++   0x8B, 0x80, 0xE0, 0xEB, 0xB1, 0xC6, 0x6E, 0xAE,
++   0x90, 0x76, 0xA7, 0x31, 0xBE, 0x9C, 0x18, 0x6D,
++   0xAB, 0x6C, 0x7B, 0xFE, 0x62, 0x05, 0xE9, 0x66,
++   0x2E, 0x38, 0xB5, 0xB2, 0xFD, 0xFC, 0x7F, 0xE3,
++   0xA1, 0xF1, 0x99, 0x4D, 0x79, 0x22, 0xD2, 0x37,
++   0x29, 0x01, 0x54, 0x00, 0xBD, 0x51, 0x1B, 0x07,
++   0x0B, 0x4A, 0xEE, 0x57, 0xDA, 0x1A, 0x06, 0xCA,
++   0xCB, 0x9A, 0xC9, 0x7D, 0xE4, 0xDC, 0xE5, 0x8D,
++   0x75, 0x4F, 0xF6, 0xA2, 0x65, 0x7C, 0xD9, 0x9D,
++   0x03, 0x27, 0x2D, 0x4C, 0x49, 0xD4, 0x5D, 0x3E,
++   0xBA, 0x1D, 0xD8, 0x91, 0x74, 0x10, 0xF8, 0xDE,
++   0xEF, 0xF0, 0x6A, 0x04, 0x72, 0x08, 0x78, 0x3A,
++   0x53, 0xC4, 0x34, 0xF2, 0x64, 0xAF, 0x86, 0xC3,
++   0xF3, 0x73, 0x67, 0xCC, 0x58, 0xF4, 0x96, 0xAC,
++   0x3D, 0xE7, 0x15, 0x8E, 0x19, 0x61, 0xF9, 0xB6,
++   0xCD, 0x87, 0xAA, 0xB0, 0x1F, 0x6F, 0xAD, 0x28,
++   0xC8, 0x69, 0x56, 0xC1, 0x71, 0xED, 0xE6, 0x98,
++   0x6B, 0x59, 0xB7, 0xF5, 0x2C, 0xEC, 0xA8, 0x94,
++   0x89, 0xBB, 0xA9, 0xD7, 0x2F, 0x8A, 0x4E, 0xD6,
++   0x33, 0x16, 0x0D, 0x83, 0x5C, 0x52, 0x85, 0xA6,
++   0x40, 0x45, 0x9F, 0x44, 0x63, 0x35, 0x77, 0xFF,
++   0x09, 0x43, 0xBF, 0xD0, 0x55, 0xDD, 0x3F, 0x24 };
++
++unsigned char table_149[32] = {
++   0x1B, 0x0B, 0x0C, 0x06, 0x1F, 0x17, 0x04, 0x1A,
++   0x1E, 0x02, 0x0F, 0x16, 0x0E, 0x09, 0x10, 0x01,
++   0x13, 0x19, 0x11, 0x00, 0x0A, 0x05, 0x03, 0x1C,
++   0x18, 0x1D, 0x14, 0x0D, 0x07, 0x08, 0x15, 0x12 };
++
++unsigned char table_150[256] = {
++   0x57, 0xBC, 0x9D, 0x46, 0x14, 0xD0, 0x94, 0x95,
++   0x1B, 0x12, 0xB8, 0xD4, 0x53, 0x73, 0x83, 0xE6,
++   0x75, 0xE1, 0xD1, 0x0D, 0xDF, 0x23, 0x13, 0x40,
++   0xF1, 0x0C, 0xA0, 0xC1, 0x22, 0xDA, 0xE8, 0xFB,
++   0xE5, 0xC4, 0x16, 0x9C, 0x3F, 0xC3, 0x78, 0x3A,
++   0x06, 0xC7, 0xA8, 0x79, 0xA4, 0xB3, 0x55, 0x88,
++   0xA9, 0x82, 0xE3, 0x68, 0xFC, 0x3B, 0x26, 0x81,
++   0xB4, 0x0A, 0x7D, 0x96, 0xDB, 0x2C, 0xE2, 0xCD,
++   0x92, 0x5C, 0xED, 0x0E, 0x42, 0x98, 0xBE, 0xB7,
++   0x63, 0x25, 0x7B, 0xD9, 0xEF, 0x11, 0xB9, 0xA3,
++   0xFA, 0x00, 0x2A, 0x91, 0x71, 0xBF, 0xB2, 0x3D,
++   0x20, 0x4C, 0xB0, 0x8C, 0x3C, 0x27, 0xAF, 0x09,
++   0x10, 0x5D, 0x2B, 0x1D, 0xBD, 0x4B, 0x54, 0xD3,
++   0xAB, 0x1A, 0xE7, 0xF8, 0x56, 0x65, 0xA5, 0xAD,
++   0xEC, 0x17, 0x45, 0x28, 0xCA, 0xEA, 0x01, 0xF5,
++   0x34, 0x84, 0x43, 0x8B, 0x03, 0x02, 0x90, 0x6B,
++   0x60, 0xCE, 0x19, 0x86, 0x4F, 0x08, 0x35, 0x9A,
++   0xAE, 0x07, 0xE0, 0xB6, 0xD6, 0x2D, 0xD2, 0x89,
++   0x5F, 0xA6, 0x72, 0x05, 0x36, 0xB5, 0xC0, 0x5A,
++   0x4D, 0xD7, 0x30, 0x37, 0x87, 0x50, 0xA2, 0x48,
++   0x29, 0xAC, 0xDE, 0x93, 0x24, 0x6E, 0x1E, 0xF7,
++   0x52, 0x5E, 0x41, 0xC8, 0xEB, 0x31, 0x7E, 0xE9,
++   0x67, 0x7A, 0x47, 0x85, 0x8D, 0x74, 0x9E, 0x64,
++   0x38, 0x9B, 0xBA, 0xCC, 0x9F, 0x8E, 0xEE, 0x0F,
++   0xB1, 0x7C, 0x6A, 0xBB, 0x2E, 0x58, 0x70, 0x7F,
++   0x4E, 0x4A, 0x1C, 0x5B, 0xF0, 0xA1, 0x61, 0xF6,
++   0x15, 0x33, 0xE4, 0xF9, 0x2F, 0x62, 0x1F, 0x76,
++   0x32, 0xCB, 0x49, 0xFE, 0x8F, 0xD5, 0xDC, 0x66,
++   0x0B, 0x3E, 0xC5, 0x21, 0xC6, 0x6C, 0x18, 0xC2,
++   0x6D, 0xFF, 0x51, 0x99, 0xCF, 0xFD, 0x59, 0xA7,
++   0xAA, 0x8A, 0xF2, 0x69, 0x39, 0x6F, 0x77, 0xDD,
++   0x97, 0xC9, 0xF3, 0x04, 0xD8, 0xF4, 0x80, 0x44 };
++
++unsigned char table_151[256] = {
++   0x78, 0x6C, 0xC5, 0x0C, 0x2D, 0xA7, 0x97, 0x9C,
++   0x22, 0x76, 0x3E, 0x81, 0x51, 0x47, 0x59, 0x71,
++   0xB1, 0xA2, 0x4A, 0x3C, 0xB5, 0x16, 0x06, 0x95,
++   0xB9, 0x01, 0xE6, 0x91, 0x96, 0x1C, 0x1B, 0xAD,
++   0x61, 0x64, 0xB2, 0xE7, 0x29, 0x19, 0x52, 0x3B,
++   0xFA, 0xAF, 0x30, 0xDB, 0xD4, 0x0B, 0xFE, 0x75,
++   0x1F, 0xBE, 0xCB, 0xF6, 0xEA, 0x31, 0xF8, 0xD8,
++   0xA3, 0x82, 0x73, 0x1D, 0x99, 0xF0, 0xCC, 0xB6,
++   0x46, 0x26, 0xAA, 0x8C, 0x87, 0x90, 0x24, 0x8F,
++   0x7A, 0x13, 0xEE, 0xD1, 0xA9, 0x05, 0xB3, 0xF7,
++   0x02, 0x7C, 0x4C, 0x1E, 0xFF, 0xE5, 0x77, 0xAB,
++   0xD6, 0x98, 0x20, 0x4D, 0xC4, 0x23, 0xF4, 0xA4,
++   0x85, 0x9A, 0x8E, 0x1A, 0x0E, 0xF5, 0x15, 0x60,
++   0x38, 0x72, 0xE9, 0xF1, 0xC3, 0x68, 0xF2, 0x93,
++   0xD3, 0x2A, 0x48, 0x74, 0xC2, 0x57, 0xA1, 0x7D,
++   0x94, 0x37, 0x92, 0x5C, 0xE1, 0x41, 0x83, 0xD5,
++   0x65, 0x14, 0xA6, 0xDC, 0x44, 0x27, 0xEF, 0xD7,
++   0x25, 0x10, 0x2C, 0x7F, 0x40, 0xA5, 0x55, 0xBD,
++   0x2B, 0x0D, 0xD0, 0xFC, 0xDF, 0xA0, 0x04, 0x00,
++   0x62, 0xB4, 0x5A, 0xEB, 0x6B, 0x84, 0x7E, 0x6A,
++   0xDE, 0xED, 0x66, 0x03, 0xFB, 0x2E, 0x4F, 0x4E,
++   0xBB, 0x36, 0x5B, 0x18, 0xE3, 0x69, 0x3F, 0xEC,
++   0xE4, 0xD2, 0x0A, 0x34, 0x63, 0xCF, 0xA8, 0xF9,
++   0x9B, 0x7B, 0x6F, 0xE8, 0x49, 0xC1, 0x09, 0x54,
++   0xF3, 0x50, 0x67, 0x79, 0xC0, 0x9F, 0x8D, 0x5F,
++   0x17, 0x70, 0x11, 0xC8, 0xBC, 0xC6, 0xE0, 0x35,
++   0x39, 0xC7, 0x6E, 0x21, 0xBF, 0xDA, 0x6D, 0x28,
++   0x0F, 0xDD, 0x33, 0xAC, 0x8A, 0x12, 0xC9, 0xCD,
++   0xB8, 0x45, 0xAE, 0x32, 0xCE, 0xE2, 0x56, 0xFD,
++   0x42, 0x89, 0x86, 0xCA, 0x4B, 0x3D, 0x5E, 0xBA,
++   0x8B, 0x5D, 0xB0, 0xB7, 0xD9, 0x58, 0x2F, 0x08,
++   0x43, 0x3A, 0x53, 0x9E, 0x80, 0x88, 0x07, 0x9D };
++
++unsigned char table_152[32] = {
++   0x02, 0x1A, 0x17, 0x1D, 0x01, 0x03, 0x13, 0x1E,
++   0x05, 0x18, 0x06, 0x0A, 0x0C, 0x04, 0x1B, 0x00,
++   0x1C, 0x09, 0x1F, 0x16, 0x07, 0x0F, 0x0B, 0x0E,
++   0x14, 0x12, 0x0D, 0x10, 0x19, 0x11, 0x08, 0x15 };
++
++unsigned char table_153[32] = {
++   0x0E, 0x14, 0x12, 0x1E, 0x1C, 0x02, 0x06, 0x16,
++   0x18, 0x0D, 0x17, 0x0C, 0x1D, 0x11, 0x08, 0x19,
++   0x07, 0x0F, 0x13, 0x04, 0x03, 0x1B, 0x0B, 0x1F,
++   0x1A, 0x0A, 0x05, 0x10, 0x00, 0x01, 0x15, 0x09 };
++
++unsigned char table_154[256] = {
++   0x27, 0x5A, 0x08, 0x5B, 0xF4, 0x39, 0x13, 0x6F,
++   0x67, 0xEA, 0x22, 0xCA, 0x5C, 0xCF, 0x18, 0x7C,
++   0x05, 0x87, 0x60, 0xCC, 0x40, 0xC6, 0xE8, 0x6D,
++   0xF5, 0x2A, 0x2D, 0xA2, 0x8C, 0x82, 0xE9, 0xDC,
++   0xD6, 0x65, 0x74, 0x8E, 0x42, 0x4F, 0x3E, 0x55,
++   0xFF, 0xC7, 0x9D, 0x0F, 0x81, 0xE2, 0x4C, 0xE6,
++   0xEB, 0x4D, 0x70, 0xD1, 0x49, 0x43, 0x3D, 0x69,
++   0x0C, 0x45, 0x28, 0x00, 0x99, 0xAE, 0xEC, 0xB8,
++   0xC3, 0x17, 0x93, 0x8D, 0x36, 0x3C, 0x46, 0x2B,
++   0x29, 0xC5, 0xB4, 0xB1, 0xD0, 0x0D, 0xAD, 0xFE,
++   0xE5, 0xA8, 0x3B, 0x1A, 0x2C, 0xDF, 0x07, 0x86,
++   0xB0, 0xD3, 0x7A, 0x59, 0x79, 0x8B, 0xC1, 0x9A,
++   0x30, 0xDB, 0x24, 0xF3, 0xD8, 0x04, 0x25, 0xC2,
++   0xA3, 0x98, 0x96, 0x7B, 0x71, 0x4E, 0x5E, 0x58,
++   0xA5, 0x51, 0x88, 0xDA, 0xF8, 0xC0, 0x7D, 0xF6,
++   0x31, 0x5F, 0x09, 0x16, 0x21, 0x62, 0x01, 0x64,
++   0x9B, 0x3A, 0x2F, 0x61, 0x19, 0xA1, 0xB7, 0xE0,
++   0xB9, 0x12, 0xA0, 0xBA, 0x6E, 0x8A, 0xFB, 0xD9,
++   0x38, 0x1B, 0xD5, 0xB3, 0x10, 0xED, 0xE4, 0x6A,
++   0x32, 0xBD, 0x75, 0xD4, 0x1C, 0xFD, 0x73, 0x77,
++   0x54, 0xC8, 0x97, 0x47, 0x35, 0x94, 0xE3, 0xCD,
++   0x6B, 0xBB, 0xF9, 0xAC, 0x11, 0x14, 0xAF, 0x78,
++   0x3F, 0xCE, 0x26, 0x44, 0xEE, 0xFC, 0x15, 0x66,
++   0x4B, 0xA6, 0x20, 0x23, 0xBE, 0x84, 0x1D, 0x7E,
++   0x0B, 0x56, 0x92, 0x0A, 0xFA, 0xF7, 0x48, 0x33,
++   0x9E, 0x8F, 0xAB, 0x5D, 0x41, 0x50, 0xA4, 0x7F,
++   0x80, 0x4A, 0x68, 0x06, 0x2E, 0x6C, 0xC4, 0x02,
++   0x0E, 0x63, 0xF0, 0xC9, 0x91, 0xB2, 0xD2, 0x03,
++   0x37, 0xEF, 0x9C, 0x90, 0x83, 0x76, 0x1E, 0xA9,
++   0x85, 0xB6, 0x57, 0xD7, 0xF2, 0xF1, 0xE7, 0xDE,
++   0xCB, 0xAA, 0xBF, 0x89, 0x1F, 0xA7, 0xBC, 0x9F,
++   0x53, 0xE1, 0xDD, 0x72, 0x95, 0x52, 0x34, 0xB5 };
++
++unsigned char table_155[256] = {
++   0x75, 0x58, 0xC5, 0xA5, 0x83, 0x16, 0xF3, 0x7F,
++   0x94, 0xDE, 0xA0, 0xF6, 0xFD, 0x89, 0xA8, 0x06,
++   0x98, 0x01, 0xD9, 0x69, 0xB7, 0x0F, 0xEA, 0x73,
++   0x32, 0xF0, 0x49, 0xBF, 0x02, 0xE7, 0x22, 0x3F,
++   0xDB, 0x30, 0x5F, 0x20, 0x6A, 0x93, 0x07, 0xBC,
++   0x09, 0x0D, 0x37, 0x24, 0x90, 0x15, 0x80, 0xAF,
++   0x8F, 0x59, 0x28, 0xFF, 0x6D, 0x1E, 0x52, 0x62,
++   0xE2, 0xDD, 0x85, 0x48, 0xB5, 0xAB, 0x68, 0xAC,
++   0x7E, 0x26, 0x2C, 0xF9, 0x2A, 0xBE, 0x5B, 0xCE,
++   0x87, 0x1D, 0x96, 0xBD, 0xEF, 0x29, 0xA9, 0xC3,
++   0x9D, 0x57, 0x79, 0x6B, 0x7A, 0x82, 0x78, 0x0A,
++   0x91, 0xF2, 0x7C, 0xC2, 0x25, 0x88, 0xE3, 0x47,
++   0x64, 0x46, 0x8D, 0x19, 0xF4, 0xE6, 0xF1, 0x53,
++   0x9C, 0x54, 0x23, 0xAD, 0xA3, 0x86, 0x3A, 0x04,
++   0x67, 0x1C, 0xF5, 0x43, 0x05, 0x42, 0xD6, 0x4B,
++   0xFB, 0xD4, 0x2B, 0x08, 0x45, 0xD8, 0xCD, 0xEB,
++   0x31, 0x4A, 0x5A, 0x34, 0x9B, 0xEC, 0x4D, 0xB4,
++   0xC6, 0xFE, 0xD5, 0x5E, 0xC1, 0x39, 0x81, 0xCF,
++   0x03, 0x6E, 0x95, 0x50, 0xA1, 0x3B, 0xB3, 0xE5,
++   0x3D, 0xB1, 0xB2, 0x41, 0x17, 0x2F, 0x2E, 0xE4,
++   0x1F, 0xDC, 0xB0, 0xB6, 0x18, 0x6F, 0x44, 0x12,
++   0x0B, 0xCC, 0x4E, 0xC0, 0x51, 0x14, 0x76, 0x3C,
++   0xB9, 0x9F, 0xA4, 0xD3, 0xA7, 0xE8, 0x13, 0x55,
++   0xC8, 0x8C, 0xD2, 0xEE, 0x65, 0xB8, 0xAA, 0x6C,
++   0x2D, 0x4F, 0x56, 0xFA, 0x61, 0x4C, 0xE0, 0x5C,
++   0xA6, 0x1A, 0xD1, 0x38, 0xD7, 0x72, 0x60, 0x74,
++   0xE1, 0xBA, 0x84, 0x3E, 0x40, 0xF8, 0xC7, 0x36,
++   0x27, 0x0C, 0x70, 0x97, 0x9A, 0x7D, 0x35, 0x71,
++   0xCA, 0x1B, 0x99, 0x8E, 0xAE, 0x66, 0x63, 0xE9,
++   0xC9, 0x11, 0x8A, 0x21, 0x92, 0x5D, 0x77, 0x10,
++   0xD0, 0xC4, 0xF7, 0x7B, 0x9E, 0xCB, 0xED, 0x0E,
++   0x8B, 0x33, 0xFC, 0xBB, 0x00, 0xA2, 0xDF, 0xDA };
++
++unsigned char table_156[256] = {
++   0x31, 0x25, 0xB1, 0xD3, 0xAF, 0xAE, 0x84, 0x2C,
++   0x71, 0x5E, 0xD8, 0x80, 0x6F, 0x3E, 0x48, 0x86,
++   0xED, 0x54, 0x6A, 0xC3, 0xBC, 0xBF, 0x0E, 0xEA,
++   0x10, 0xA2, 0x9D, 0x91, 0x32, 0xE2, 0x7E, 0x1B,
++   0x49, 0x27, 0xFF, 0xDD, 0x8A, 0x2F, 0x8D, 0x38,
++   0xFA, 0x3C, 0x03, 0x14, 0x0F, 0x89, 0xCC, 0x07,
++   0x1A, 0xA0, 0x97, 0x37, 0xA6, 0xD6, 0x63, 0x87,
++   0xA1, 0xC2, 0x4B, 0x39, 0xCB, 0xCF, 0x69, 0x4E,
++   0xC9, 0x28, 0x1C, 0xBB, 0x42, 0x2B, 0xA9, 0x78,
++   0x5B, 0xF6, 0xE0, 0xD0, 0x5F, 0x46, 0x98, 0xCE,
++   0x1F, 0x7A, 0x34, 0x8B, 0xFD, 0x9B, 0xEF, 0x74,
++   0x05, 0xF2, 0x02, 0xC6, 0xDF, 0x73, 0x5C, 0x8E,
++   0xDE, 0x88, 0x57, 0x3B, 0x85, 0xBD, 0xC0, 0x3A,
++   0x45, 0x4D, 0x2D, 0x72, 0x0C, 0x60, 0xCA, 0x5D,
++   0x06, 0x04, 0x3D, 0x51, 0x15, 0xAD, 0xE8, 0x67,
++   0xBA, 0x43, 0x7D, 0xF8, 0xB2, 0xE6, 0xAB, 0xF4,
++   0x23, 0x6E, 0xF0, 0x6B, 0x0B, 0x2E, 0xC8, 0xC4,
++   0x4F, 0xA8, 0x6D, 0x26, 0xE9, 0x9C, 0x22, 0xB7,
++   0x00, 0xB3, 0x0A, 0x7C, 0x44, 0x55, 0x75, 0xD5,
++   0xAA, 0x66, 0x56, 0x24, 0x83, 0x90, 0xA4, 0xF5,
++   0xCD, 0xEC, 0x18, 0xDC, 0xFE, 0x96, 0xA3, 0xF7,
++   0xD2, 0xFB, 0xD1, 0x65, 0xC5, 0x08, 0x7B, 0x70,
++   0x16, 0x9A, 0x20, 0x09, 0x29, 0xDA, 0x52, 0x5A,
++   0x59, 0xB4, 0x77, 0x62, 0x9E, 0x19, 0x7F, 0x82,
++   0x4C, 0xB6, 0x0D, 0x58, 0xEE, 0x1D, 0xB9, 0x93,
++   0x50, 0xD9, 0x30, 0xE4, 0x13, 0x01, 0x36, 0x8F,
++   0x53, 0x3F, 0x64, 0xA5, 0xB5, 0xD7, 0x81, 0x41,
++   0x17, 0xE5, 0x94, 0xE3, 0xF9, 0x61, 0x76, 0xE1,
++   0x9F, 0xFC, 0x1E, 0x12, 0xDB, 0x21, 0x79, 0x2A,
++   0xAC, 0xF3, 0x6C, 0xC1, 0x95, 0x92, 0xEB, 0xA7,
++   0x11, 0xC7, 0xB8, 0x4A, 0x33, 0xB0, 0x99, 0xE7,
++   0xF1, 0x68, 0xBE, 0x35, 0x40, 0x8C, 0xD4, 0x47 };
++
++unsigned char table_157[32] = {
++   0x00, 0x0D, 0x03, 0x02, 0x11, 0x04, 0x18, 0x0B,
++   0x14, 0x1D, 0x1C, 0x13, 0x1B, 0x17, 0x10, 0x15,
++   0x01, 0x19, 0x07, 0x09, 0x1A, 0x16, 0x12, 0x1E,
++   0x08, 0x06, 0x0C, 0x0E, 0x1F, 0x0F, 0x0A, 0x05 };
++
++unsigned char table_158[256] = {
++   0x68, 0x26, 0x80, 0x0B, 0xB8, 0xD5, 0x8C, 0xB7,
++   0x65, 0xEF, 0xBC, 0x94, 0x28, 0xB9, 0xB2, 0xD2,
++   0x92, 0xA4, 0x55, 0x27, 0xE0, 0x40, 0x6C, 0x41,
++   0x25, 0xBD, 0xAF, 0xEA, 0xB1, 0x19, 0xA5, 0xC9,
++   0x0E, 0xED, 0xB4, 0xF9, 0x8B, 0x6A, 0xAE, 0xD8,
++   0x64, 0x83, 0xC1, 0xD3, 0x04, 0xF4, 0xFA, 0xC3,
++   0x46, 0x2C, 0xA8, 0xBB, 0x3A, 0x47, 0x33, 0x8F,
++   0x52, 0x86, 0x08, 0x9D, 0x1D, 0x59, 0x8E, 0x91,
++   0x32, 0xCF, 0x6B, 0x75, 0xB0, 0x7F, 0xC7, 0x24,
++   0x05, 0x6F, 0x00, 0x1C, 0x2D, 0xAC, 0xDA, 0x45,
++   0x73, 0xB3, 0x3E, 0xD6, 0x54, 0x61, 0x03, 0x77,
++   0xF8, 0xD9, 0xE2, 0x4B, 0xFF, 0xF2, 0x0C, 0x4F,
++   0x93, 0x71, 0xA7, 0x3D, 0x66, 0x88, 0x98, 0xF1,
++   0xB6, 0x7A, 0x2B, 0xCD, 0x44, 0x3C, 0x37, 0x5A,
++   0x96, 0x23, 0x9F, 0xBF, 0x7D, 0x5E, 0x2A, 0x35,
++   0x72, 0x79, 0xE1, 0xA3, 0x84, 0x99, 0x38, 0x49,
++   0xC8, 0xDB, 0x30, 0xDC, 0xAD, 0x3F, 0xF6, 0x09,
++   0x69, 0x95, 0xE5, 0x67, 0xA1, 0xFD, 0xF7, 0x1B,
++   0xEC, 0x17, 0xD4, 0xEB, 0x29, 0x36, 0x3B, 0x15,
++   0xDE, 0x2E, 0xC5, 0x70, 0x6D, 0x53, 0x56, 0xAB,
++   0xC0, 0x43, 0xC2, 0xE7, 0x31, 0xE6, 0xA6, 0x78,
++   0x5C, 0x7C, 0x48, 0x10, 0x87, 0xCC, 0x9E, 0x7E,
++   0x5F, 0xE9, 0x07, 0x5B, 0xF5, 0xEE, 0xB5, 0xCA,
++   0x62, 0x18, 0xBE, 0x20, 0x16, 0xDF, 0x13, 0x4E,
++   0x7B, 0x02, 0x11, 0x4C, 0x51, 0x85, 0x0D, 0x22,
++   0xF3, 0x14, 0x63, 0x76, 0xD0, 0x0F, 0xE4, 0xCB,
++   0xCE, 0xA0, 0x82, 0xE3, 0x01, 0xAA, 0x5D, 0x4A,
++   0x4D, 0xFB, 0x39, 0x8A, 0x2F, 0xDD, 0xE8, 0x06,
++   0x1A, 0x90, 0x81, 0x50, 0x8D, 0x89, 0x97, 0x1E,
++   0xFC, 0x60, 0x12, 0x42, 0x9C, 0xF0, 0x34, 0xD7,
++   0xD1, 0x1F, 0x0A, 0x21, 0xA9, 0x6E, 0xC4, 0xBA,
++   0x9A, 0x57, 0xA2, 0x74, 0xC6, 0xFE, 0x9B, 0x58 };
++
++unsigned char table_159[256] = {
++   0xE5, 0xBF, 0x84, 0x56, 0xD6, 0x43, 0x3E, 0xA5,
++   0x64, 0x87, 0x44, 0x63, 0x4A, 0x4C, 0x8D, 0x24,
++   0x1C, 0xDA, 0x89, 0x52, 0x80, 0x4F, 0xE4, 0xBC,
++   0xC5, 0xF4, 0x27, 0x75, 0x9C, 0xF0, 0xE1, 0x06,
++   0x99, 0x48, 0xF2, 0x57, 0x34, 0x9A, 0xA8, 0x62,
++   0xC9, 0xD5, 0x16, 0x6D, 0x55, 0xFA, 0x37, 0x5A,
++   0x2A, 0xC6, 0x45, 0xDD, 0x1B, 0x76, 0x50, 0xE2,
++   0x69, 0x41, 0x6C, 0xC4, 0x3C, 0x47, 0xA9, 0x92,
++   0x00, 0x3D, 0x6F, 0xE7, 0x7A, 0x3A, 0x33, 0x53,
++   0xF7, 0x03, 0xA7, 0xB1, 0x15, 0x78, 0x0B, 0x67,
++   0x2E, 0x21, 0xF1, 0xD4, 0xB3, 0x98, 0x60, 0x58,
++   0xBB, 0x82, 0x1E, 0x70, 0x0A, 0xA2, 0x02, 0x17,
++   0xFF, 0x9F, 0xD2, 0xAF, 0xC7, 0xDC, 0x68, 0x83,
++   0x42, 0xCA, 0x08, 0x39, 0x20, 0xEC, 0x77, 0x96,
++   0x5B, 0xAD, 0x09, 0x6B, 0x40, 0xC2, 0x91, 0x51,
++   0x10, 0xD9, 0xF9, 0xC1, 0xB5, 0xDF, 0xDB, 0xC0,
++   0x7D, 0xAB, 0xAE, 0x54, 0x35, 0xF3, 0xA1, 0xE6,
++   0xEA, 0x14, 0xBA, 0xFC, 0xE8, 0xEB, 0xF6, 0xBD,
++   0x8C, 0x72, 0x1F, 0xE9, 0xFB, 0x7C, 0xCF, 0x49,
++   0xE3, 0xA3, 0x22, 0x9D, 0x46, 0x71, 0x94, 0x31,
++   0x2D, 0x65, 0x2B, 0x32, 0x18, 0xB6, 0x90, 0xF8,
++   0x11, 0x5F, 0xA0, 0xEF, 0xED, 0x1A, 0x25, 0x2C,
++   0x3B, 0xFD, 0x2F, 0x73, 0xB9, 0x7E, 0xDE, 0xB4,
++   0x97, 0x0F, 0x7F, 0x86, 0x93, 0x07, 0x19, 0xCE,
++   0xE0, 0xB7, 0xEE, 0x26, 0xD1, 0x01, 0x59, 0x5C,
++   0xC3, 0x79, 0x8B, 0xD3, 0x4B, 0x04, 0xD0, 0x29,
++   0x0D, 0x3F, 0xB2, 0x30, 0xCC, 0x36, 0xFE, 0xB0,
++   0xF5, 0x8E, 0xA6, 0x8A, 0xC8, 0xD8, 0x05, 0xB8,
++   0x12, 0xBE, 0x81, 0x4D, 0x38, 0xAC, 0x1D, 0x9E,
++   0x66, 0x5E, 0x7B, 0x6E, 0x0C, 0xCD, 0x6A, 0x88,
++   0xAA, 0x0E, 0x61, 0x5D, 0x95, 0x4E, 0xD7, 0x74,
++   0xCB, 0x9B, 0x13, 0x8F, 0xA4, 0x28, 0x23, 0x85 };
++
++unsigned char table_160[256] = {
++   0x35, 0x44, 0x0E, 0x92, 0x75, 0x83, 0x9D, 0x53,
++   0xA5, 0x90, 0xF8, 0xF7, 0x54, 0x74, 0xDF, 0x3D,
++   0x5A, 0xAA, 0xC6, 0x26, 0x7A, 0xFC, 0x79, 0x6C,
++   0x56, 0xB3, 0x32, 0xE3, 0x1C, 0xF9, 0xDC, 0xE6,
++   0xA2, 0x93, 0x71, 0xFF, 0x1D, 0xEB, 0xB2, 0x04,
++   0x96, 0x46, 0x0C, 0x2B, 0x17, 0xEE, 0x28, 0x25,
++   0xD9, 0xAE, 0x11, 0xA7, 0x40, 0x45, 0xFB, 0x80,
++   0x18, 0xF1, 0xCB, 0x2E, 0x24, 0xF3, 0xEC, 0x4F,
++   0xAB, 0xD7, 0xD4, 0xC4, 0xFD, 0x4B, 0xAD, 0xC9,
++   0x4C, 0x08, 0xAC, 0xF4, 0xCD, 0xB7, 0xF2, 0x15,
++   0x02, 0x2F, 0x16, 0x34, 0x65, 0x8A, 0x87, 0xCC,
++   0x50, 0x0F, 0x9B, 0xC2, 0xC8, 0x7B, 0xEA, 0x8E,
++   0xE4, 0xD6, 0x97, 0x30, 0xA8, 0xA0, 0x94, 0xC5,
++   0xE8, 0x12, 0x27, 0xCE, 0x84, 0xDD, 0xB1, 0x47,
++   0x7E, 0xE7, 0xE1, 0x3A, 0x37, 0x21, 0x2D, 0x3B,
++   0x20, 0x60, 0x1E, 0x1B, 0x82, 0xBE, 0xA3, 0x70,
++   0x98, 0xBF, 0xA6, 0x4D, 0x76, 0x86, 0x42, 0x9F,
++   0xCF, 0xE0, 0x14, 0x4A, 0x0B, 0xB4, 0x36, 0xF5,
++   0x85, 0xB8, 0xC0, 0x6A, 0xE9, 0x7D, 0xBD, 0x4E,
++   0x8F, 0x51, 0x0D, 0x5B, 0x6B, 0x58, 0x5F, 0x03,
++   0x6F, 0xBC, 0x5D, 0x1F, 0x7F, 0xDB, 0x00, 0xC1,
++   0x13, 0xF0, 0xD1, 0xFA, 0xDA, 0x05, 0x39, 0xD3,
++   0x38, 0xD2, 0x89, 0xE2, 0x88, 0x5E, 0x5C, 0x6D,
++   0xCA, 0xB0, 0x01, 0x63, 0x8B, 0x59, 0xA4, 0xD0,
++   0x78, 0x19, 0xB5, 0x62, 0x1A, 0x69, 0x8D, 0x9C,
++   0x22, 0x3F, 0x9E, 0x33, 0x72, 0x2A, 0x41, 0x29,
++   0xFE, 0xF6, 0x64, 0x7C, 0x66, 0xB6, 0xAF, 0x23,
++   0x8C, 0x68, 0x6E, 0x49, 0x07, 0x99, 0x77, 0x3E,
++   0x9A, 0x73, 0xD8, 0x55, 0x0A, 0x3C, 0xBA, 0xA9,
++   0x52, 0xED, 0x91, 0x09, 0x95, 0xC7, 0x43, 0xD5,
++   0x57, 0x61, 0x81, 0xEF, 0x06, 0xDE, 0x48, 0x31,
++   0xBB, 0x2C, 0xE5, 0xC3, 0x67, 0xA1, 0x10, 0xB9 };
++
++unsigned char table_161[256] = {
++   0x8F, 0x1A, 0x81, 0xA2, 0x2C, 0x56, 0x6D, 0xCD,
++   0x4A, 0x33, 0x50, 0xE9, 0xE0, 0x12, 0x5A, 0x43,
++   0x2D, 0x4F, 0xEA, 0x95, 0xFD, 0x49, 0xAB, 0xA3,
++   0x79, 0x42, 0x0B, 0xB8, 0x89, 0x40, 0x71, 0x14,
++   0x80, 0x55, 0xAF, 0xCF, 0x3E, 0x64, 0x8B, 0x74,
++   0xBF, 0x9C, 0x24, 0x97, 0xD1, 0xBA, 0x48, 0xD2,
++   0x08, 0x1F, 0xDD, 0xA7, 0xDC, 0x92, 0x30, 0x75,
++   0x31, 0x37, 0x67, 0x06, 0x68, 0x72, 0x6F, 0x05,
++   0x8A, 0x7C, 0x4C, 0x3C, 0x19, 0x28, 0x86, 0x3D,
++   0x93, 0xDA, 0xF4, 0xC7, 0x17, 0x85, 0xAC, 0x02,
++   0x78, 0x04, 0xAD, 0x03, 0x8D, 0x11, 0xC5, 0x9D,
++   0x3A, 0x73, 0x82, 0x59, 0x51, 0x9F, 0x27, 0x47,
++   0xE7, 0xED, 0x1E, 0xFF, 0x34, 0x01, 0x5B, 0x4B,
++   0xCA, 0x6C, 0x69, 0xBB, 0x3B, 0xC4, 0x5F, 0xDF,
++   0x09, 0x6B, 0x7D, 0xC9, 0x88, 0x45, 0x57, 0xD3,
++   0x2A, 0x4E, 0xF1, 0xC2, 0xA9, 0xB6, 0x18, 0xD4,
++   0xA0, 0x1C, 0x4D, 0x0E, 0xE5, 0xE1, 0xD7, 0xB2,
++   0x0C, 0x3F, 0x00, 0x61, 0x16, 0x0D, 0x32, 0x62,
++   0x58, 0x63, 0xEE, 0xEF, 0x2F, 0x5D, 0xB0, 0x20,
++   0x7A, 0x10, 0xE6, 0xA1, 0xF9, 0xD8, 0x6E, 0xCB,
++   0xF0, 0x9B, 0x84, 0x8E, 0xF2, 0xFE, 0xC8, 0x7F,
++   0xBD, 0xF8, 0x07, 0xC6, 0x39, 0xBC, 0xCC, 0x22,
++   0x54, 0x15, 0x9A, 0xA4, 0xC1, 0x2B, 0x1B, 0x25,
++   0xDE, 0x6A, 0xDB, 0x90, 0xEB, 0xB7, 0xD0, 0x44,
++   0xA6, 0xB9, 0xB1, 0x23, 0x9E, 0x65, 0x83, 0xFA,
++   0x96, 0xB5, 0x0F, 0xF6, 0xD6, 0xE8, 0x53, 0x13,
++   0x76, 0xD5, 0x35, 0x87, 0xE3, 0x38, 0xF5, 0xAE,
++   0xB3, 0xCE, 0xE2, 0x70, 0xD9, 0x66, 0x5C, 0x26,
++   0xC3, 0xFC, 0xF7, 0x94, 0xF3, 0xEC, 0xFB, 0x99,
++   0x91, 0x77, 0xB4, 0x46, 0xA5, 0x98, 0x7B, 0x1D,
++   0x52, 0x2E, 0xA8, 0x60, 0x5E, 0x29, 0x21, 0x7E,
++   0xBE, 0x0A, 0x36, 0x41, 0xC0, 0x8C, 0xE4, 0xAA };
++
++unsigned char table_162[256] = {
++   0xF7, 0x1B, 0xC0, 0x31, 0x5A, 0x23, 0xEA, 0xE9,
++   0xFB, 0x14, 0x6A, 0xE8, 0x04, 0x65, 0x5B, 0x2C,
++   0x41, 0xD9, 0xEB, 0xE4, 0x8D, 0x1D, 0xCA, 0x8F,
++   0x5E, 0x43, 0xAF, 0x46, 0x0A, 0x01, 0x0C, 0xB4,
++   0x95, 0x52, 0x92, 0xE0, 0x10, 0x57, 0x0F, 0x71,
++   0xB1, 0x26, 0xD8, 0x05, 0x69, 0x3C, 0x54, 0xDF,
++   0xFF, 0x9D, 0x51, 0xA0, 0xA1, 0x0B, 0xC1, 0x20,
++   0x6D, 0xFA, 0x47, 0x15, 0x09, 0xD3, 0xE1, 0xA9,
++   0x66, 0x12, 0x5C, 0x49, 0x1E, 0x3B, 0xD0, 0x8B,
++   0x62, 0xBD, 0x06, 0xE5, 0x00, 0x98, 0x4E, 0x32,
++   0xB0, 0x2D, 0x2A, 0x7F, 0x03, 0xD5, 0x99, 0x7E,
++   0xAB, 0x22, 0xC6, 0xC3, 0x2F, 0x4C, 0x33, 0x45,
++   0xE3, 0x3F, 0xF9, 0xB2, 0xFE, 0x36, 0xE7, 0xF8,
++   0x55, 0x0D, 0x56, 0x1F, 0x4B, 0xE6, 0x50, 0x81,
++   0xCE, 0x80, 0xCD, 0x67, 0x6B, 0xCF, 0x2E, 0x9B,
++   0xBC, 0xBE, 0x11, 0x75, 0x4D, 0xAC, 0x59, 0x40,
++   0x85, 0x0E, 0xC9, 0x17, 0xA3, 0x60, 0xED, 0x16,
++   0xA4, 0xDD, 0xEE, 0x96, 0x77, 0x83, 0x34, 0xD2,
++   0xCB, 0xFC, 0x6C, 0x08, 0xEC, 0x35, 0xF2, 0x6F,
++   0x3A, 0x7B, 0x21, 0x4A, 0x70, 0xEF, 0xAD, 0xDE,
++   0x90, 0x9E, 0x7D, 0x64, 0x2B, 0x79, 0xF5, 0xF3,
++   0x13, 0x1C, 0x7A, 0x07, 0x4F, 0x78, 0x89, 0xB6,
++   0x97, 0xF1, 0xD7, 0x7C, 0x48, 0xAE, 0x39, 0xA8,
++   0xA6, 0x86, 0x3E, 0x27, 0x87, 0x73, 0x82, 0x24,
++   0x30, 0x74, 0x5F, 0xD1, 0x9F, 0x9C, 0x1A, 0x8C,
++   0x42, 0x6E, 0x28, 0xB9, 0xF0, 0xC4, 0x68, 0x25,
++   0xC5, 0xDC, 0xB8, 0x29, 0xD6, 0x84, 0x3D, 0xBB,
++   0x88, 0x76, 0xFD, 0x61, 0x94, 0x91, 0xDA, 0xB7,
++   0x72, 0xBA, 0xC2, 0xDB, 0xB5, 0xA5, 0xE2, 0x18,
++   0xF6, 0xAA, 0x8A, 0x19, 0x63, 0x9A, 0xA7, 0xC8,
++   0xD4, 0x02, 0x8E, 0x37, 0xF4, 0xB3, 0xA2, 0x53,
++   0x38, 0xCC, 0x58, 0x44, 0xBF, 0x93, 0x5D, 0xC7 };
++
++unsigned char table_163[32] = {
++   0x1B, 0x14, 0x12, 0x15, 0x11, 0x1D, 0x17, 0x19,
++   0x10, 0x09, 0x08, 0x06, 0x1A, 0x16, 0x07, 0x13,
++   0x1F, 0x0B, 0x1C, 0x05, 0x0E, 0x00, 0x18, 0x0A,
++   0x04, 0x01, 0x03, 0x0C, 0x0D, 0x1E, 0x02, 0x0F };
++
++unsigned char table_164[32] = {
++   0x15, 0x00, 0x10, 0x0B, 0x1D, 0x0A, 0x06, 0x1C,
++   0x0D, 0x1F, 0x17, 0x0F, 0x03, 0x14, 0x13, 0x12,
++   0x1B, 0x18, 0x08, 0x1E, 0x16, 0x09, 0x1A, 0x04,
++   0x02, 0x0C, 0x0E, 0x01, 0x07, 0x19, 0x11, 0x05 };
++
++unsigned char table_165[256] = {
++   0x98, 0xF5, 0x1D, 0xFB, 0x13, 0x20, 0x41, 0xA3,
++   0xE3, 0x76, 0x49, 0x7E, 0x60, 0xD8, 0x68, 0x30,
++   0x88, 0x45, 0xD5, 0x77, 0x00, 0xC3, 0x09, 0x31,
++   0x44, 0x18, 0xD4, 0x14, 0xC8, 0x1B, 0x8B, 0x38,
++   0x08, 0x52, 0xD1, 0xF3, 0x69, 0x9F, 0xDA, 0x61,
++   0x16, 0x1C, 0xE4, 0x7D, 0xEE, 0xD9, 0x5E, 0x4C,
++   0xA7, 0xAA, 0xA6, 0xF6, 0xCF, 0xA0, 0xBA, 0x10,
++   0xE2, 0xDE, 0x0F, 0xEA, 0xBC, 0x32, 0x63, 0xC0,
++   0x54, 0xC5, 0xBE, 0x71, 0x80, 0x56, 0x5C, 0xA4,
++   0xAD, 0x15, 0x9D, 0x11, 0x43, 0x67, 0x95, 0xAE,
++   0xC6, 0xC4, 0x91, 0x9C, 0xE5, 0x37, 0xE1, 0x7A,
++   0xDB, 0xEF, 0x03, 0x65, 0x86, 0x66, 0x2A, 0xB5,
++   0xBF, 0xB4, 0x0D, 0xB3, 0xD7, 0x2D, 0x01, 0xEB,
++   0x8C, 0xF2, 0x5A, 0x2E, 0x64, 0x25, 0x02, 0xCB,
++   0x4A, 0xB0, 0xCE, 0x35, 0xA8, 0x47, 0x85, 0x33,
++   0x34, 0x24, 0x23, 0x7B, 0xB6, 0x48, 0x83, 0x40,
++   0x87, 0x57, 0x3C, 0xD6, 0xCD, 0x2C, 0x6D, 0xE7,
++   0xBB, 0xED, 0x81, 0x5D, 0x55, 0x46, 0xDD, 0xD3,
++   0x70, 0xBD, 0xB8, 0x75, 0x53, 0x6E, 0xD0, 0x99,
++   0xCA, 0x58, 0xC7, 0x4B, 0x3D, 0xA5, 0x50, 0x7C,
++   0x93, 0x51, 0xB7, 0xFD, 0x05, 0x3A, 0xE8, 0x8F,
++   0x28, 0x74, 0x39, 0xF0, 0x7F, 0x4F, 0x06, 0x36,
++   0xB2, 0x19, 0x2F, 0x1F, 0x8D, 0x0C, 0xB9, 0xFC,
++   0x89, 0x21, 0x12, 0xF7, 0x3F, 0x94, 0x6F, 0xDC,
++   0x3E, 0x4E, 0x3B, 0xC9, 0x07, 0x9B, 0x17, 0x9A,
++   0x73, 0x6A, 0x5B, 0xA1, 0x1E, 0x8A, 0x04, 0x72,
++   0x6C, 0xA2, 0xEC, 0x96, 0xFE, 0xF8, 0x84, 0xC1,
++   0x79, 0x0E, 0x62, 0x90, 0x8E, 0xF4, 0x42, 0x29,
++   0x92, 0x9E, 0xAC, 0x82, 0x4D, 0xAF, 0x2B, 0x6B,
++   0xA9, 0xFF, 0x0A, 0xAB, 0x22, 0x5F, 0xDF, 0xD2,
++   0x0B, 0x78, 0xF1, 0xE6, 0x59, 0x27, 0xC2, 0xE0,
++   0x1A, 0x26, 0xCC, 0xB1, 0xF9, 0xFA, 0x97, 0xE9 };
++
++unsigned char table_166[256] = {
++   0xCB, 0xEA, 0x2A, 0x36, 0x6D, 0x93, 0x4E, 0xD5,
++   0xBC, 0x6A, 0xD4, 0x68, 0xF7, 0x18, 0xAB, 0x8B,
++   0x66, 0x95, 0x94, 0x64, 0xB7, 0x00, 0x4D, 0x97,
++   0x38, 0xB3, 0xFC, 0xE1, 0xBB, 0x63, 0xF3, 0x1F,
++   0x6B, 0x2C, 0x2F, 0x5E, 0xA4, 0x7E, 0xFB, 0xF4,
++   0xA8, 0x8A, 0x65, 0x53, 0x90, 0x58, 0x40, 0x60,
++   0x28, 0x8E, 0x35, 0x49, 0xED, 0xBD, 0x1B, 0x0B,
++   0xBA, 0xB8, 0x61, 0x50, 0xE9, 0x39, 0xEF, 0xC3,
++   0x74, 0xB6, 0x46, 0x8D, 0xD9, 0x32, 0x92, 0x9A,
++   0x30, 0x01, 0xF2, 0x41, 0xB9, 0xE7, 0x3A, 0xB0,
++   0x80, 0x15, 0xDE, 0x7D, 0x7F, 0x09, 0xC2, 0x76,
++   0xF8, 0x12, 0x59, 0xDD, 0x1D, 0xE6, 0x75, 0xBE,
++   0xA3, 0x04, 0xCA, 0x78, 0x7B, 0xAC, 0xD8, 0x70,
++   0xD3, 0xC1, 0x25, 0x6F, 0x03, 0x6C, 0x14, 0x45,
++   0xE5, 0x2B, 0x87, 0x83, 0xAA, 0x77, 0x5F, 0x4A,
++   0x9C, 0x27, 0x0C, 0x10, 0xAE, 0x56, 0x85, 0x0D,
++   0xE3, 0xFA, 0x71, 0xEE, 0x9F, 0x21, 0xC0, 0xCD,
++   0xFD, 0xDC, 0x5B, 0x11, 0x02, 0x0F, 0x96, 0x3D,
++   0x3C, 0x26, 0xEB, 0x08, 0x7A, 0x82, 0xA7, 0x19,
++   0xD7, 0xC5, 0xF6, 0x52, 0x57, 0x88, 0xFF, 0x47,
++   0x8F, 0xC6, 0x33, 0xB5, 0x2E, 0x8C, 0x81, 0x91,
++   0x44, 0xA6, 0x17, 0xF0, 0x4B, 0x9D, 0x34, 0x73,
++   0x72, 0x67, 0xD2, 0x0E, 0xA0, 0x99, 0xA5, 0xAF,
++   0xFE, 0x9E, 0x6E, 0xDA, 0x3B, 0xE2, 0x23, 0xD6,
++   0xD0, 0x13, 0x89, 0x5A, 0x42, 0x98, 0x5C, 0xD1,
++   0x86, 0x24, 0xDF, 0x37, 0xF9, 0xCC, 0xF5, 0xA9,
++   0x2D, 0xBF, 0x5D, 0xF1, 0x69, 0xE8, 0xA2, 0x06,
++   0x48, 0xC7, 0xDB, 0x29, 0xE4, 0xAD, 0x3E, 0xA1,
++   0xC9, 0x4C, 0x1A, 0xCE, 0x62, 0x4F, 0x7C, 0xC8,
++   0x05, 0xC4, 0xB1, 0x1E, 0x79, 0x55, 0x84, 0xB2,
++   0x20, 0x31, 0x9B, 0xEC, 0xB4, 0xCF, 0x54, 0x22,
++   0x1C, 0xE0, 0x51, 0x16, 0x43, 0x07, 0x0A, 0x3F };
++
++unsigned char table_167[256] = {
++   0x91, 0xEA, 0x4F, 0x6A, 0x6E, 0x2D, 0x27, 0x22,
++   0x44, 0xA5, 0x6D, 0xE3, 0x45, 0x06, 0xE2, 0x87,
++   0x9A, 0xC9, 0x2C, 0x4A, 0x93, 0x6F, 0x00, 0xEB,
++   0x7C, 0x7F, 0xA2, 0xFE, 0x40, 0x3C, 0x3F, 0xC0,
++   0xC7, 0xFB, 0x8B, 0xDF, 0xA3, 0x28, 0x78, 0x48,
++   0x46, 0xD5, 0x70, 0x5C, 0x35, 0x4E, 0xD7, 0x3A,
++   0x42, 0x47, 0x5B, 0x26, 0x8E, 0xE0, 0x21, 0xB1,
++   0x77, 0x1E, 0x53, 0x4B, 0xCC, 0xE5, 0x65, 0xF6,
++   0x66, 0x2A, 0xA0, 0x5E, 0x3E, 0xAD, 0xA8, 0x95,
++   0x1B, 0x0D, 0x8A, 0x05, 0x68, 0x59, 0x0C, 0x38,
++   0x18, 0xC3, 0x81, 0xA4, 0xFD, 0x13, 0x50, 0xCA,
++   0xE8, 0xDD, 0xD9, 0x76, 0x8C, 0xC5, 0xF4, 0x17,
++   0xB4, 0x3D, 0xEC, 0x0B, 0x67, 0xC6, 0x8D, 0xE1,
++   0xBB, 0x7E, 0xCB, 0x10, 0x99, 0xE9, 0x39, 0xF3,
++   0x75, 0xFA, 0xAC, 0x16, 0x54, 0x51, 0xBC, 0x24,
++   0x58, 0x08, 0xA7, 0x0F, 0x5D, 0xBF, 0xBA, 0xE7,
++   0x9D, 0x2B, 0xB5, 0x29, 0xE4, 0xCD, 0x37, 0x30,
++   0x55, 0xAE, 0x1D, 0x4D, 0x94, 0x34, 0x92, 0x1C,
++   0x6B, 0xBE, 0x52, 0x7B, 0x33, 0xB0, 0x0A, 0x5A,
++   0x03, 0x23, 0x41, 0x49, 0x61, 0x64, 0x73, 0x97,
++   0xC2, 0x9F, 0x5F, 0x07, 0x04, 0xF8, 0xC1, 0xFC,
++   0x74, 0x02, 0x0E, 0x60, 0x9E, 0xD4, 0x85, 0x88,
++   0xC4, 0xF5, 0x90, 0x31, 0xF7, 0xEE, 0x9B, 0xB9,
++   0x20, 0xE6, 0xA6, 0x63, 0x79, 0x56, 0x62, 0xF0,
++   0x2F, 0xD8, 0x4C, 0x83, 0xF9, 0x36, 0x3B, 0x84,
++   0xDE, 0x57, 0xB8, 0xB7, 0x11, 0xF2, 0xC8, 0xD3,
++   0xD1, 0x96, 0x19, 0x2E, 0x72, 0x9C, 0xDB, 0xB3,
++   0xA1, 0xAA, 0xCE, 0x09, 0x98, 0xED, 0xA9, 0xDA,
++   0xAF, 0x86, 0xD0, 0x12, 0xFF, 0xDC, 0x1F, 0xD6,
++   0x01, 0xF1, 0xD2, 0x80, 0x43, 0x7A, 0x71, 0x82,
++   0xB6, 0xAB, 0x89, 0xBD, 0x8F, 0xEF, 0x7D, 0xB2,
++   0x14, 0x15, 0x25, 0x32, 0x6C, 0x69, 0x1A, 0xCF };
++
++unsigned char table_168[256] = {
++   0x28, 0xEE, 0xB1, 0xFD, 0xB3, 0xEF, 0x36, 0x8E,
++   0x85, 0x5D, 0x1C, 0x53, 0x1E, 0xDA, 0xBA, 0x3C,
++   0xA8, 0x90, 0x99, 0x49, 0x45, 0xE0, 0x27, 0x8D,
++   0x22, 0xE4, 0x51, 0x3E, 0xAB, 0xE8, 0x70, 0xF5,
++   0x81, 0xE6, 0x34, 0x29, 0xF3, 0x11, 0x46, 0x5F,
++   0x5C, 0xA0, 0xD1, 0xE3, 0x15, 0x68, 0x3A, 0x01,
++   0xE9, 0xD7, 0x24, 0x5A, 0x18, 0x16, 0x88, 0x3B,
++   0x64, 0xA1, 0xDB, 0xBF, 0xAA, 0x43, 0xEA, 0x19,
++   0xA2, 0xD5, 0x7B, 0xBD, 0x2A, 0x0E, 0x4F, 0xB5,
++   0x4B, 0xB7, 0x5B, 0x73, 0xC9, 0xAC, 0x1B, 0x67,
++   0xC7, 0xB4, 0x69, 0x00, 0xBC, 0x6D, 0xC1, 0x04,
++   0xF4, 0x74, 0xD6, 0xD0, 0x60, 0xAE, 0x17, 0xFE,
++   0x63, 0xB6, 0x89, 0x41, 0x7C, 0x44, 0x8B, 0xDC,
++   0x50, 0xE5, 0x79, 0x77, 0x47, 0x9F, 0xA6, 0x3D,
++   0x09, 0x8A, 0x2F, 0xC0, 0x0F, 0xCD, 0x2B, 0x4D,
++   0x0D, 0xC2, 0x5E, 0xB0, 0x57, 0x62, 0xAF, 0x1A,
++   0x21, 0x82, 0x48, 0x9E, 0x38, 0xB9, 0xB8, 0xF2,
++   0x37, 0x07, 0xCA, 0xC5, 0x84, 0xDF, 0xF9, 0xEC,
++   0x42, 0x6B, 0x8F, 0x6C, 0x3F, 0xC4, 0x94, 0xED,
++   0x7A, 0x2D, 0xA3, 0x83, 0xD9, 0x55, 0x02, 0x9A,
++   0xA9, 0x75, 0x10, 0x2C, 0xCB, 0x95, 0xBB, 0x6E,
++   0x23, 0x65, 0x35, 0x97, 0x56, 0xAD, 0xCE, 0xF8,
++   0xF0, 0x0C, 0xE2, 0x52, 0x05, 0x91, 0xCC, 0xC8,
++   0x78, 0x06, 0x96, 0x4E, 0x03, 0xD3, 0x98, 0xA7,
++   0x13, 0x58, 0x93, 0xD4, 0xDD, 0xC6, 0xFC, 0x25,
++   0x9C, 0x86, 0x1F, 0xCF, 0x76, 0xA4, 0x6A, 0xFA,
++   0x0B, 0x4A, 0x54, 0x40, 0x59, 0xD8, 0x61, 0xFF,
++   0x7F, 0x80, 0x6F, 0x7D, 0xF1, 0x8C, 0x92, 0xDE,
++   0x9D, 0xC3, 0xB2, 0xE7, 0xFB, 0x20, 0x31, 0x72,
++   0x12, 0xBE, 0x1D, 0xF6, 0x9B, 0x14, 0x26, 0x0A,
++   0xEB, 0xF7, 0x71, 0x39, 0x30, 0xA5, 0x87, 0xD2,
++   0x66, 0x2E, 0x08, 0x32, 0x4C, 0x33, 0x7E, 0xE1 };
++
++unsigned char table_169[256] = {
++   0xA4, 0x31, 0xA9, 0x3F, 0x13, 0x4D, 0x1B, 0x29,
++   0x73, 0x43, 0xF1, 0xE7, 0x9C, 0xC2, 0xF6, 0xCD,
++   0xA1, 0x94, 0x0D, 0x27, 0xFE, 0x7B, 0x9B, 0x0B,
++   0x89, 0xBA, 0x23, 0xEC, 0x76, 0xC3, 0x6C, 0xD8,
++   0x8D, 0xF8, 0xF9, 0x7D, 0x68, 0x5B, 0x61, 0x87,
++   0x28, 0x14, 0x55, 0x0C, 0xFC, 0xD9, 0x07, 0xE8,
++   0x36, 0x88, 0x67, 0x4C, 0xEA, 0xBD, 0xF5, 0x9D,
++   0xB6, 0xC6, 0x24, 0x32, 0x93, 0x03, 0x79, 0x8C,
++   0x12, 0x84, 0xFF, 0x7E, 0x42, 0xE4, 0x3C, 0xF2,
++   0x50, 0xEB, 0x1F, 0x47, 0xB0, 0xA5, 0xB1, 0x71,
++   0x30, 0x5F, 0x5C, 0x53, 0xF7, 0x10, 0xC5, 0x6E,
++   0xE0, 0xDE, 0xC8, 0x58, 0xB7, 0x90, 0xA6, 0x95,
++   0x70, 0x8F, 0xFD, 0xC1, 0x48, 0xB5, 0x19, 0x92,
++   0xBC, 0x15, 0x4E, 0xE6, 0x11, 0xDD, 0x81, 0x0E,
++   0xBB, 0x75, 0x5D, 0x4A, 0xAB, 0x2D, 0x02, 0x54,
++   0x4B, 0x66, 0xD6, 0x2B, 0x2A, 0xE5, 0x26, 0xE1,
++   0xEE, 0xE9, 0x8B, 0x6A, 0x7A, 0xF4, 0x51, 0x39,
++   0x1C, 0xC9, 0xCF, 0x77, 0x00, 0xF3, 0x25, 0xCC,
++   0x08, 0xFB, 0x0F, 0x3E, 0xCE, 0xED, 0x3D, 0x56,
++   0xEF, 0x1D, 0x85, 0x96, 0x52, 0xA8, 0xD3, 0xCB,
++   0xE3, 0x33, 0x06, 0x7C, 0xAE, 0x72, 0x09, 0x04,
++   0x91, 0xC4, 0x5A, 0x69, 0x98, 0xB4, 0x40, 0xDF,
++   0x7F, 0x9F, 0xAA, 0x83, 0xE2, 0x78, 0x74, 0x20,
++   0xAD, 0x6D, 0xDC, 0xD4, 0xCA, 0x60, 0xF0, 0x35,
++   0x37, 0xD0, 0x18, 0x1A, 0x64, 0x3A, 0x99, 0xDB,
++   0x62, 0x44, 0x2C, 0x82, 0x8E, 0xD7, 0xD1, 0xFA,
++   0x16, 0xD5, 0x46, 0xBF, 0xA7, 0xC0, 0x2E, 0x3B,
++   0x01, 0x63, 0xB2, 0x1E, 0x05, 0x21, 0xB8, 0x17,
++   0x22, 0x97, 0xAF, 0x4F, 0x86, 0x34, 0xDA, 0xC7,
++   0xA3, 0xA0, 0xB3, 0x2F, 0xAC, 0x49, 0xD2, 0x57,
++   0x6F, 0x9A, 0x65, 0xB9, 0x41, 0xBE, 0x8A, 0xA2,
++   0x6B, 0x0A, 0x59, 0x9E, 0x5E, 0x38, 0x45, 0x80 };
++
++unsigned char table_170[256] = {
++   0xE3, 0x00, 0x99, 0x03, 0xF6, 0xDD, 0xD1, 0x41,
++   0x58, 0x7E, 0xD9, 0x46, 0x04, 0xAF, 0x5C, 0x43,
++   0xDE, 0x5E, 0xFC, 0x97, 0x3D, 0x68, 0xC8, 0x37,
++   0x3C, 0xFB, 0x0F, 0x5A, 0xBE, 0xFA, 0x4C, 0x82,
++   0x0C, 0xA0, 0x0A, 0xD4, 0x9D, 0xCE, 0x78, 0xA8,
++   0x55, 0x56, 0x60, 0xAA, 0xC9, 0x96, 0x62, 0xEA,
++   0x0D, 0xB8, 0xE2, 0x84, 0x17, 0xAE, 0x2B, 0x2C,
++   0x91, 0x57, 0x38, 0x01, 0xA9, 0xCD, 0x34, 0xBA,
++   0x8D, 0xC0, 0xD6, 0xFF, 0xF2, 0xD3, 0x5F, 0x26,
++   0xCA, 0x9B, 0x21, 0x75, 0x4E, 0x49, 0x20, 0x59,
++   0x39, 0xBF, 0x90, 0x6C, 0xFE, 0x8F, 0x2F, 0x18,
++   0x36, 0xD7, 0xB4, 0xAC, 0xBD, 0xF3, 0x1D, 0x4F,
++   0xA3, 0x74, 0x5B, 0x44, 0x05, 0x9C, 0x6D, 0x6B,
++   0x1E, 0xE8, 0x25, 0x16, 0x80, 0xCC, 0x29, 0xC7,
++   0x94, 0x4A, 0xF5, 0xF4, 0x27, 0x85, 0xBB, 0x24,
++   0xDA, 0xB5, 0x76, 0x69, 0xA5, 0x54, 0x23, 0x31,
++   0x11, 0xA4, 0x09, 0xE4, 0x64, 0x10, 0xC5, 0xC1,
++   0x7D, 0xE7, 0x92, 0xF8, 0x9E, 0x6A, 0x15, 0x8B,
++   0x98, 0x42, 0x52, 0x66, 0x0B, 0xA1, 0x35, 0x1A,
++   0x14, 0x7C, 0xE1, 0x9F, 0x28, 0xF1, 0x1B, 0xA6,
++   0x71, 0x73, 0x81, 0xAB, 0xE6, 0x95, 0x06, 0x1F,
++   0xC6, 0xB0, 0x51, 0x0E, 0xEE, 0x77, 0xF0, 0xD8,
++   0xC2, 0x89, 0x7B, 0x07, 0xA2, 0xB7, 0x19, 0x67,
++   0x2E, 0x8E, 0x47, 0xA7, 0xEF, 0x32, 0xD2, 0x93,
++   0xDC, 0x9A, 0xB2, 0xED, 0x45, 0xC4, 0x50, 0x3F,
++   0xE5, 0xCF, 0x88, 0x1C, 0x7A, 0x79, 0xEB, 0x70,
++   0x2A, 0x7F, 0xBC, 0xDB, 0xD0, 0xB1, 0xCB, 0x08,
++   0x86, 0x5D, 0x53, 0x72, 0xB6, 0x4B, 0xB3, 0x22,
++   0xC3, 0x6F, 0xB9, 0xD5, 0x3B, 0x13, 0x2D, 0xAD,
++   0x33, 0xFD, 0x02, 0x40, 0x8A, 0x3A, 0xF7, 0xE0,
++   0x8C, 0x3E, 0x61, 0x6E, 0xE9, 0x63, 0xF9, 0xEC,
++   0x48, 0x30, 0x87, 0x83, 0x12, 0x4D, 0x65, 0xDF };
++
++unsigned char table_171[32] = {
++   0x07, 0x06, 0x11, 0x08, 0x0C, 0x1F, 0x19, 0x02,
++   0x14, 0x04, 0x0D, 0x18, 0x1A, 0x05, 0x17, 0x13,
++   0x1C, 0x1B, 0x15, 0x03, 0x01, 0x0F, 0x16, 0x1E,
++   0x1D, 0x10, 0x00, 0x12, 0x0B, 0x0E, 0x09, 0x0A };
++
++unsigned char table_172[32] = {
++   0x11, 0x01, 0x1F, 0x06, 0x1A, 0x04, 0x02, 0x09,
++   0x05, 0x0D, 0x0B, 0x18, 0x0E, 0x12, 0x1B, 0x17,
++   0x07, 0x08, 0x1D, 0x1E, 0x14, 0x19, 0x16, 0x15,
++   0x03, 0x0C, 0x00, 0x10, 0x0A, 0x1C, 0x0F, 0x13 };
++
++unsigned char table_173[32] = {
++   0x1F, 0x0B, 0x13, 0x00, 0x16, 0x15, 0x14, 0x0A,
++   0x1D, 0x05, 0x1E, 0x1A, 0x0F, 0x04, 0x0E, 0x01,
++   0x19, 0x07, 0x02, 0x12, 0x0C, 0x17, 0x08, 0x09,
++   0x03, 0x11, 0x18, 0x10, 0x1C, 0x1B, 0x06, 0x0D };
++
++unsigned char table_174[32] = {
++   0x02, 0x1B, 0x0C, 0x17, 0x1F, 0x05, 0x15, 0x1E,
++   0x16, 0x09, 0x1A, 0x12, 0x0F, 0x1C, 0x18, 0x0A,
++   0x19, 0x10, 0x0D, 0x13, 0x04, 0x11, 0x08, 0x14,
++   0x1D, 0x0E, 0x06, 0x00, 0x01, 0x07, 0x0B, 0x03 };
++
++unsigned char table_175[32] = {
++   0x00, 0x06, 0x0B, 0x08, 0x0C, 0x04, 0x1A, 0x1C,
++   0x05, 0x1E, 0x14, 0x03, 0x0A, 0x18, 0x12, 0x1D,
++   0x16, 0x1F, 0x07, 0x09, 0x0F, 0x0E, 0x17, 0x13,
++   0x11, 0x19, 0x10, 0x0D, 0x1B, 0x02, 0x01, 0x15 };
++
++unsigned char table_176[32] = {
++   0x12, 0x03, 0x1A, 0x15, 0x04, 0x19, 0x0B, 0x1B,
++   0x17, 0x1E, 0x0D, 0x05, 0x11, 0x14, 0x1C, 0x00,
++   0x18, 0x10, 0x0A, 0x06, 0x0E, 0x08, 0x02, 0x07,
++   0x13, 0x09, 0x16, 0x1D, 0x0F, 0x0C, 0x01, 0x1F };
++
++unsigned char table_177[256] = {
++   0x5E, 0x4D, 0x76, 0xFE, 0xB5, 0x50, 0x83, 0x23,
++   0x72, 0xDD, 0x93, 0x08, 0x69, 0xAD, 0xEC, 0x3B,
++   0x0B, 0x9A, 0x36, 0xC9, 0xCA, 0xBE, 0xF7, 0x30,
++   0x19, 0x39, 0x2C, 0xAB, 0xE3, 0x7B, 0xBC, 0x32,
++   0xA0, 0xE4, 0xA6, 0xB6, 0xCB, 0xC8, 0x37, 0x07,
++   0xD2, 0xA1, 0xD9, 0xF6, 0xBF, 0xF5, 0x88, 0x01,
++   0x95, 0x0F, 0x03, 0xFD, 0xE6, 0x68, 0x90, 0x61,
++   0x21, 0x6D, 0x3C, 0x62, 0x34, 0x2B, 0x71, 0x4B,
++   0x44, 0x64, 0x75, 0xA2, 0x6A, 0xFF, 0x29, 0xBD,
++   0x35, 0x15, 0xF9, 0xC1, 0x09, 0x45, 0xB2, 0xF2,
++   0x3F, 0xCE, 0xB0, 0xC0, 0xB8, 0x00, 0x05, 0xD7,
++   0x11, 0xC6, 0x78, 0x53, 0x9E, 0xB3, 0xED, 0x56,
++   0x22, 0x5C, 0x9D, 0x6C, 0x99, 0x43, 0x2F, 0xAE,
++   0xEB, 0x40, 0x8C, 0x1F, 0xC2, 0xDF, 0x92, 0x65,
++   0x6F, 0x79, 0x5D, 0x5B, 0xAA, 0xDB, 0xF1, 0x96,
++   0xD4, 0xF4, 0x8B, 0x51, 0xD5, 0xE2, 0xBB, 0x80,
++   0x17, 0x7C, 0x2A, 0x6E, 0xDE, 0xEA, 0x94, 0x31,
++   0xA4, 0x2D, 0xC3, 0x8D, 0x55, 0x14, 0x9B, 0x0E,
++   0x7D, 0xC4, 0x06, 0x33, 0x73, 0xE9, 0x7A, 0x38,
++   0x5F, 0x89, 0x84, 0xD6, 0xA8, 0x13, 0xE8, 0xCF,
++   0x46, 0xD0, 0x7F, 0x24, 0x8F, 0xF8, 0x87, 0x1B,
++   0x47, 0x02, 0x0C, 0x97, 0x52, 0xFB, 0x8E, 0x20,
++   0x70, 0x3E, 0x7E, 0xD1, 0xE5, 0xEE, 0xCC, 0x91,
++   0x74, 0xCD, 0x42, 0x04, 0x8A, 0xEF, 0xE1, 0x10,
++   0x4F, 0x1C, 0x28, 0x9F, 0xD8, 0x0A, 0x18, 0x49,
++   0x9C, 0x16, 0xF3, 0x82, 0x57, 0x1D, 0x26, 0x66,
++   0x27, 0x86, 0xE7, 0x59, 0xFA, 0x25, 0x54, 0x0D,
++   0x98, 0xDC, 0xF0, 0x3D, 0x63, 0x1E, 0x77, 0x3A,
++   0xDA, 0xB7, 0x6B, 0x2E, 0x48, 0x4C, 0xBA, 0xC7,
++   0x60, 0xAC, 0x1A, 0xB9, 0xFC, 0xA3, 0xA7, 0xA5,
++   0xB4, 0x67, 0xA9, 0x81, 0xB1, 0x12, 0xD3, 0x85,
++   0x5A, 0xC5, 0xE0, 0x58, 0x41, 0x4E, 0x4A, 0xAF };
++
++unsigned char table_178[256] = {
++   0x33, 0xBA, 0x98, 0xDA, 0x07, 0x2C, 0x22, 0x9B,
++   0xE0, 0xED, 0xB7, 0xA1, 0x93, 0xEB, 0xDC, 0x49,
++   0xDF, 0xE1, 0x6C, 0xC2, 0x64, 0x52, 0xD0, 0x8F,
++   0xA2, 0x48, 0x26, 0x21, 0x6E, 0x5E, 0x0B, 0x7C,
++   0x0D, 0x90, 0xA4, 0xCE, 0xF5, 0x5F, 0xF9, 0x1D,
++   0x55, 0x83, 0x8D, 0xFB, 0x38, 0xB3, 0xF2, 0x67,
++   0xDE, 0x0A, 0xBE, 0xEC, 0x5B, 0x35, 0x08, 0x50,
++   0xE7, 0x56, 0x4A, 0x02, 0xBC, 0x5A, 0xBD, 0x43,
++   0x6F, 0x79, 0xB2, 0xF7, 0x60, 0xE9, 0xA0, 0x1B,
++   0xC8, 0xDD, 0x9D, 0xA3, 0x5C, 0x61, 0x77, 0x72,
++   0x9C, 0x31, 0x0E, 0x05, 0x1E, 0x12, 0xF1, 0xC9,
++   0x78, 0x4E, 0x15, 0x7D, 0x54, 0xCB, 0x73, 0xEA,
++   0xC5, 0x2B, 0x0F, 0x7E, 0x42, 0x96, 0xC6, 0x74,
++   0x09, 0x65, 0x34, 0xE6, 0x63, 0xA6, 0x70, 0xD3,
++   0x27, 0x87, 0x3A, 0x16, 0x7B, 0x13, 0x06, 0x40,
++   0x46, 0x69, 0xAD, 0x88, 0x81, 0xC0, 0x37, 0x58,
++   0xD1, 0x8A, 0x8E, 0x9A, 0x5D, 0x6D, 0xC7, 0xC3,
++   0xD2, 0xF4, 0x3F, 0x57, 0x3C, 0x4F, 0xA9, 0x6A,
++   0x92, 0xA5, 0x97, 0x0C, 0x2A, 0x36, 0x47, 0xDB,
++   0x8C, 0xEE, 0x03, 0x89, 0x7F, 0x91, 0x24, 0x80,
++   0x2F, 0x62, 0xE4, 0xAF, 0x17, 0x99, 0xD6, 0xCD,
++   0xFE, 0x76, 0x1C, 0xD4, 0x3E, 0xFF, 0xD8, 0xC4,
++   0x39, 0x32, 0xCF, 0xE2, 0xE3, 0x53, 0xD7, 0xCC,
++   0xD9, 0x11, 0xAA, 0x1F, 0x01, 0x3B, 0x51, 0xB5,
++   0x94, 0x4B, 0x28, 0xF0, 0xAC, 0x44, 0x14, 0x4C,
++   0xB9, 0xA7, 0xB8, 0x1A, 0xD5, 0xCA, 0xE8, 0x82,
++   0x9F, 0x2D, 0xAB, 0x2E, 0x29, 0xFD, 0x68, 0xB1,
++   0x66, 0xC1, 0x7A, 0xFA, 0x71, 0x04, 0xA8, 0xB0,
++   0x59, 0x18, 0xAE, 0x25, 0x3D, 0xE5, 0xF6, 0x41,
++   0x86, 0x75, 0x6B, 0xBB, 0xFC, 0x84, 0x8B, 0x85,
++   0x10, 0x23, 0xB6, 0xF3, 0x19, 0x30, 0x20, 0x4D,
++   0x95, 0x9E, 0xBF, 0xEF, 0xF8, 0x45, 0x00, 0xB4 };
++
++unsigned char table_179[256] = {
++   0x50, 0x3D, 0x41, 0x42, 0x06, 0x5B, 0xD6, 0x34,
++   0x9D, 0x3C, 0x7B, 0x14, 0xE2, 0x9B, 0x80, 0x15,
++   0x51, 0x01, 0x6A, 0x30, 0xD7, 0xFC, 0x61, 0x4B,
++   0x8A, 0xEC, 0x38, 0x71, 0x70, 0x2E, 0x1C, 0x72,
++   0x79, 0x26, 0x4C, 0x48, 0xED, 0xAD, 0x25, 0x53,
++   0x03, 0xD9, 0xB5, 0x0D, 0x8E, 0x19, 0xCC, 0xBE,
++   0xE1, 0x91, 0x64, 0xA6, 0x21, 0xCE, 0x76, 0xAB,
++   0x9F, 0xD1, 0xB6, 0x23, 0x6D, 0xB0, 0x90, 0xBD,
++   0x09, 0x3A, 0x5E, 0xD0, 0x73, 0x10, 0x44, 0x08,
++   0xFF, 0xB8, 0x24, 0x58, 0xDB, 0x65, 0x95, 0xAA,
++   0xE9, 0xC4, 0x32, 0x2B, 0x84, 0xC9, 0xC7, 0xB1,
++   0x4F, 0x0C, 0xCB, 0x11, 0x4E, 0x22, 0x4A, 0x16,
++   0xDE, 0xBC, 0xEE, 0x68, 0x13, 0xFA, 0xC3, 0x98,
++   0xEB, 0x29, 0x43, 0x9A, 0xA1, 0xE0, 0xF0, 0x3F,
++   0x2F, 0x1B, 0xC2, 0x66, 0x35, 0xF5, 0xC8, 0xD8,
++   0x5A, 0xE5, 0x87, 0x47, 0xD3, 0x7A, 0xE6, 0x39,
++   0x77, 0x81, 0xF2, 0x0E, 0x83, 0x7E, 0x17, 0x6C,
++   0xB3, 0x5C, 0xE8, 0xD2, 0xC0, 0xA4, 0xF9, 0x86,
++   0xCD, 0xFB, 0x54, 0x7C, 0xBF, 0x2D, 0x82, 0xDA,
++   0x96, 0x74, 0x97, 0xC5, 0x7D, 0x27, 0x57, 0x56,
++   0xDC, 0xBA, 0x69, 0x8C, 0x9C, 0x88, 0xB4, 0x8D,
++   0x37, 0xEA, 0x3B, 0x33, 0x2C, 0xB2, 0x45, 0xF7,
++   0xC1, 0x1E, 0x46, 0x02, 0x6B, 0x3E, 0xA7, 0xD5,
++   0x05, 0x0A, 0xA9, 0x1D, 0xA3, 0x4D, 0xAE, 0x6F,
++   0x49, 0xDD, 0x8F, 0xEF, 0xBB, 0x67, 0x0B, 0x40,
++   0x9E, 0xF1, 0x78, 0x28, 0xDF, 0x52, 0xF4, 0x92,
++   0x94, 0x0F, 0xB9, 0x93, 0xF6, 0x1F, 0xAF, 0xA8,
++   0xCA, 0xE4, 0x59, 0x7F, 0x85, 0x75, 0xC6, 0xFD,
++   0x00, 0xB7, 0x55, 0xFE, 0x8B, 0x62, 0x5F, 0x12,
++   0xF8, 0xD4, 0x89, 0xA0, 0x20, 0xE7, 0xCF, 0x60,
++   0x5D, 0xAC, 0x1A, 0x36, 0x63, 0x99, 0x31, 0xF3,
++   0x2A, 0x04, 0x18, 0xA5, 0xA2, 0x6E, 0x07, 0xE3 };
++
++unsigned char table_180[256] = {
++   0xDA, 0xCC, 0x72, 0xA6, 0xE7, 0x07, 0xFD, 0x25,
++   0x92, 0x39, 0x49, 0x02, 0xD6, 0x09, 0xA8, 0x65,
++   0x2E, 0x6C, 0xA1, 0x19, 0xBF, 0x21, 0x11, 0xC7,
++   0x3F, 0x9F, 0xF4, 0x51, 0xAF, 0x8C, 0xFE, 0xCD,
++   0x7A, 0xEB, 0x5A, 0xF7, 0x18, 0x69, 0xB9, 0xED,
++   0x37, 0x45, 0x13, 0xB4, 0xAA, 0x75, 0x47, 0x42,
++   0xA3, 0x81, 0x88, 0x70, 0xC1, 0x36, 0x73, 0x1D,
++   0x3B, 0x22, 0xB6, 0x35, 0xE9, 0x31, 0x56, 0x23,
++   0xE1, 0xF5, 0xAD, 0x46, 0x99, 0x32, 0xE4, 0x40,
++   0x00, 0x0F, 0x05, 0xC6, 0x33, 0x84, 0x7B, 0x4D,
++   0x4B, 0x7D, 0x91, 0x3D, 0xCE, 0x64, 0x77, 0x55,
++   0xD7, 0x2B, 0x2F, 0x2C, 0xB8, 0xD3, 0x85, 0xD1,
++   0xB5, 0x6A, 0xF9, 0x41, 0x08, 0xBB, 0x87, 0xEC,
++   0x78, 0xE0, 0xEE, 0x8D, 0x01, 0x58, 0x15, 0x8F,
++   0x06, 0xF0, 0x8B, 0x27, 0x0D, 0x0B, 0x6D, 0xBD,
++   0xCA, 0x2A, 0xA2, 0xE6, 0xDD, 0xBC, 0x4E, 0x5D,
++   0x74, 0x04, 0x3A, 0x96, 0x66, 0x12, 0x1E, 0xF2,
++   0xF6, 0xC4, 0xAE, 0x3C, 0x0C, 0x90, 0x68, 0xD8,
++   0x24, 0x5E, 0x79, 0x10, 0xAC, 0xDF, 0x9B, 0xC5,
++   0x44, 0xC3, 0x50, 0x5C, 0xA5, 0x89, 0x60, 0x5F,
++   0x48, 0x17, 0x34, 0xA7, 0xE2, 0xF3, 0xD9, 0x3E,
++   0x9C, 0xB7, 0x7C, 0x1F, 0xA9, 0xD4, 0xA4, 0x0E,
++   0x8E, 0x4C, 0xDC, 0xF8, 0xF1, 0x98, 0xDE, 0x2D,
++   0x61, 0xCB, 0xD5, 0x43, 0x86, 0x26, 0xB0, 0x7F,
++   0x7E, 0xFF, 0xAB, 0x83, 0x14, 0x9A, 0x80, 0x16,
++   0x30, 0xA0, 0x53, 0x97, 0x52, 0x9E, 0xB1, 0x1B,
++   0xD0, 0x1A, 0xC8, 0x57, 0xBA, 0x6E, 0xFA, 0x94,
++   0xE8, 0x63, 0x5B, 0x29, 0xEF, 0x71, 0x8A, 0x03,
++   0xB3, 0x76, 0xC9, 0xD2, 0xBE, 0xE5, 0x82, 0x1C,
++   0x95, 0x9D, 0x4A, 0x28, 0xEA, 0x0A, 0xC0, 0xE3,
++   0x6F, 0x20, 0x54, 0xFB, 0x93, 0xFC, 0x6B, 0x38,
++   0x62, 0x4F, 0xCF, 0xB2, 0xC2, 0x59, 0xDB, 0x67 };
++
++unsigned char table_181[256] = {
++   0x2B, 0xED, 0x14, 0x05, 0x80, 0xCC, 0x5A, 0xF8,
++   0x43, 0xB7, 0x86, 0xC6, 0xEE, 0xA6, 0xD7, 0xD6,
++   0xA0, 0xC4, 0x21, 0x34, 0xB1, 0x8C, 0xF9, 0xF4,
++   0x7C, 0x53, 0x06, 0xD4, 0x6B, 0x3F, 0xE1, 0x12,
++   0x6A, 0xCE, 0xCF, 0xBF, 0x74, 0x3E, 0xD5, 0xCB,
++   0x97, 0x01, 0xA2, 0x2D, 0xAE, 0xF7, 0x17, 0x29,
++   0x47, 0x03, 0x0E, 0xE9, 0x82, 0x46, 0x94, 0xAF,
++   0x2A, 0x90, 0xFE, 0x4A, 0x7E, 0x0C, 0x71, 0xB6,
++   0xA5, 0xF2, 0x67, 0x41, 0xBA, 0xC2, 0x8A, 0x9D,
++   0x36, 0xFF, 0x50, 0x2E, 0xC3, 0x91, 0x9C, 0x37,
++   0x66, 0xAD, 0xB2, 0x1F, 0xE4, 0xE3, 0x9F, 0xDD,
++   0x87, 0xC0, 0xE6, 0xEF, 0x13, 0x70, 0x5B, 0xDE,
++   0x5C, 0x75, 0x7F, 0x4F, 0x44, 0xCA, 0x55, 0x57,
++   0xF0, 0x26, 0xA7, 0xC7, 0x10, 0x51, 0x00, 0xB3,
++   0x5D, 0x99, 0x81, 0x3B, 0xB9, 0x1C, 0x64, 0x7B,
++   0xFB, 0xD9, 0x8D, 0x4E, 0xAC, 0x25, 0xBB, 0x69,
++   0xDF, 0x02, 0x9E, 0x2C, 0xAB, 0xF3, 0x65, 0x09,
++   0xA3, 0x6C, 0xC1, 0x76, 0x52, 0x30, 0xD8, 0x3A,
++   0x40, 0x18, 0x59, 0xD0, 0xE5, 0xB4, 0x5F, 0x33,
++   0x68, 0x92, 0x2F, 0xB8, 0x93, 0xD1, 0xEB, 0xA4,
++   0xFC, 0x77, 0x19, 0x62, 0xC9, 0x49, 0x84, 0x1A,
++   0x9A, 0xE7, 0x31, 0xE8, 0xE2, 0x58, 0xF1, 0x4B,
++   0x1E, 0x0B, 0x39, 0xFD, 0x42, 0x7A, 0x89, 0x38,
++   0x11, 0x98, 0x63, 0x08, 0xE0, 0xEA, 0xBE, 0xB0,
++   0x45, 0x1B, 0x4C, 0x54, 0xC8, 0x27, 0x3D, 0x73,
++   0x04, 0x8F, 0x79, 0xBC, 0x6F, 0x0D, 0x0F, 0xA1,
++   0x60, 0xDC, 0xC5, 0xFA, 0x8E, 0xDA, 0x15, 0x96,
++   0xD3, 0x07, 0xF5, 0x3C, 0x88, 0x72, 0x1D, 0x4D,
++   0x8B, 0x61, 0x0A, 0xDB, 0xAA, 0x20, 0x23, 0xEC,
++   0x6E, 0x22, 0x48, 0x28, 0xBD, 0xA9, 0x56, 0x5E,
++   0x85, 0xA8, 0x95, 0x6D, 0x16, 0x78, 0xB5, 0xF6,
++   0x32, 0x24, 0x7D, 0x9B, 0xD2, 0x83, 0x35, 0xCD };
++
++unsigned char table_182[256] = {
++   0x06, 0x7F, 0x66, 0xB5, 0xBA, 0x1E, 0xFD, 0x51,
++   0x81, 0x8D, 0x28, 0xA3, 0x15, 0x37, 0xDC, 0x58,
++   0xE6, 0x3D, 0xB4, 0xB9, 0x2E, 0xA0, 0x2F, 0xC4,
++   0xCB, 0xB1, 0x25, 0xBF, 0xC1, 0x4E, 0x5A, 0xE4,
++   0x0F, 0x10, 0x7C, 0x52, 0xA7, 0x29, 0x76, 0x55,
++   0xAA, 0x70, 0x62, 0x54, 0x43, 0x93, 0x3A, 0x7D,
++   0x5B, 0x56, 0x33, 0x64, 0x74, 0x2A, 0xD9, 0x9B,
++   0x88, 0xC0, 0x3C, 0x63, 0xDE, 0xF4, 0x73, 0xDF,
++   0x9E, 0xB2, 0xA8, 0x4F, 0x04, 0x57, 0x47, 0x87,
++   0x14, 0xFC, 0x27, 0x53, 0x83, 0xDB, 0xD7, 0x20,
++   0x96, 0x31, 0xD0, 0xCF, 0x30, 0x19, 0x69, 0x1A,
++   0xAE, 0x3B, 0x11, 0x0C, 0xA6, 0x95, 0x8A, 0xF2,
++   0x1B, 0xCC, 0x78, 0xEF, 0xB3, 0x71, 0x84, 0xA2,
++   0xF1, 0x7A, 0x92, 0x61, 0xCA, 0x90, 0x94, 0x89,
++   0x68, 0xEE, 0x97, 0x38, 0x0D, 0xF9, 0x1F, 0x8E,
++   0xE9, 0x26, 0xBD, 0xC9, 0xFF, 0x4C, 0x44, 0x1D,
++   0x98, 0xE5, 0x86, 0xF3, 0x18, 0xB6, 0x09, 0xD2,
++   0x7E, 0xC5, 0xE7, 0x2B, 0x8C, 0x8B, 0x60, 0x3F,
++   0x2C, 0x6A, 0x08, 0x0E, 0x50, 0x32, 0x9F, 0xF0,
++   0x9A, 0xC2, 0x39, 0xBE, 0xEA, 0x12, 0x16, 0xBB,
++   0x5E, 0x67, 0xE3, 0xB8, 0x79, 0x46, 0xDA, 0x00,
++   0xD3, 0xBC, 0xCE, 0x1C, 0x80, 0xFA, 0xAB, 0x65,
++   0x4A, 0xF8, 0xAC, 0x72, 0x01, 0xC6, 0x35, 0x85,
++   0x3E, 0x5C, 0xA1, 0x05, 0xA5, 0xA9, 0xE1, 0x40,
++   0xEB, 0xE8, 0x5F, 0xF5, 0xC3, 0xD1, 0x34, 0xFB,
++   0xEC, 0xF7, 0x9C, 0xC7, 0xDD, 0x6C, 0x36, 0x9D,
++   0x42, 0x59, 0x99, 0x5D, 0xD8, 0x82, 0x07, 0x24,
++   0x6D, 0xAD, 0x13, 0x48, 0x6B, 0x6E, 0x75, 0x4D,
++   0xD5, 0x02, 0xED, 0xFE, 0x91, 0xCD, 0x77, 0xB0,
++   0xF6, 0xC8, 0x6F, 0x23, 0xAF, 0xB7, 0x2D, 0xD6,
++   0xA4, 0xE2, 0x45, 0x8F, 0x21, 0xE0, 0x49, 0x22,
++   0x7B, 0x17, 0x0B, 0x0A, 0x41, 0x03, 0xD4, 0x4B };
++
++unsigned char table_183[32] = {
++   0x1E, 0x1B, 0x11, 0x07, 0x08, 0x06, 0x18, 0x17,
++   0x0D, 0x0F, 0x12, 0x03, 0x1D, 0x04, 0x0A, 0x1A,
++   0x0C, 0x13, 0x14, 0x1F, 0x0B, 0x19, 0x10, 0x01,
++   0x16, 0x05, 0x1C, 0x0E, 0x02, 0x00, 0x09, 0x15 };
++
++unsigned char table_184[32] = {
++   0x0F, 0x1D, 0x17, 0x16, 0x0D, 0x05, 0x13, 0x1F,
++   0x1B, 0x09, 0x1C, 0x1E, 0x15, 0x01, 0x06, 0x08,
++   0x0C, 0x10, 0x0B, 0x02, 0x04, 0x0A, 0x07, 0x1A,
++   0x18, 0x0E, 0x03, 0x11, 0x12, 0x14, 0x19, 0x00 };
++
++unsigned char table_185[256] = {
++   0xA5, 0xEE, 0x2E, 0x28, 0xA7, 0xAC, 0xD9, 0xB2,
++   0x6E, 0x04, 0xB4, 0x03, 0xE8, 0x92, 0x5F, 0x4D,
++   0x73, 0x20, 0x71, 0xE0, 0x43, 0x53, 0x3F, 0xF8,
++   0x96, 0xA1, 0x24, 0x97, 0xAD, 0x7B, 0xE5, 0xE6,
++   0xF2, 0xCE, 0xE3, 0x76, 0x2F, 0xA2, 0x48, 0x0E,
++   0x4B, 0x4A, 0x8B, 0x5A, 0x81, 0x2C, 0xBF, 0xD7,
++   0xFB, 0x7D, 0x4C, 0x16, 0xF4, 0x00, 0xF5, 0x40,
++   0x64, 0x74, 0xA9, 0x37, 0x86, 0xD3, 0x1B, 0xCD,
++   0xF1, 0x1A, 0x90, 0x9F, 0x54, 0x79, 0x29, 0xC3,
++   0x77, 0x85, 0x02, 0xB1, 0x70, 0xFE, 0x5B, 0xDA,
++   0x6B, 0x01, 0x0C, 0x07, 0xB8, 0x58, 0x47, 0x42,
++   0x09, 0xE4, 0x27, 0xDD, 0xF3, 0x1E, 0x10, 0x9E,
++   0x49, 0x30, 0x05, 0xBE, 0x59, 0xEB, 0xD2, 0xAA,
++   0xC8, 0x9D, 0x8C, 0x5E, 0x14, 0x56, 0x8E, 0xF7,
++   0x38, 0x55, 0x87, 0xA3, 0x5D, 0x41, 0x4F, 0x1F,
++   0xF6, 0x0F, 0x57, 0x91, 0xAE, 0xBA, 0xB3, 0x95,
++   0x9B, 0x69, 0xC1, 0x11, 0xD0, 0x25, 0x7F, 0x3B,
++   0x62, 0xCF, 0xC0, 0xA0, 0xFC, 0xB6, 0x12, 0x6C,
++   0xF0, 0x13, 0x93, 0xAB, 0xC6, 0x78, 0x6D, 0x88,
++   0x22, 0x08, 0x2A, 0xE2, 0xB7, 0x65, 0x31, 0x3A,
++   0xA6, 0x7C, 0xF9, 0xDC, 0xE7, 0xA4, 0xC9, 0x63,
++   0xA8, 0x0B, 0xED, 0x50, 0x36, 0xD8, 0x3E, 0xB0,
++   0x6A, 0x5C, 0x45, 0x4E, 0x23, 0x84, 0x34, 0x9A,
++   0xCC, 0x3D, 0xB5, 0xEA, 0xDE, 0x75, 0xD6, 0xFF,
++   0x6F, 0xC2, 0xDB, 0x8D, 0x7A, 0x1C, 0xE9, 0x61,
++   0x0A, 0x1D, 0x32, 0x52, 0x3C, 0x19, 0xFA, 0xD1,
++   0xD4, 0x68, 0xC7, 0x0D, 0x99, 0x83, 0xEF, 0x80,
++   0x82, 0xBD, 0xD5, 0x7E, 0x39, 0x72, 0x51, 0xAF,
++   0x8A, 0x2D, 0xB9, 0x89, 0xC4, 0x67, 0x35, 0xE1,
++   0x44, 0x06, 0xEC, 0xCB, 0x8F, 0x17, 0xDF, 0x94,
++   0x60, 0xCA, 0x26, 0xFD, 0x33, 0x46, 0x21, 0xBB,
++   0x2B, 0xC5, 0x98, 0x18, 0x66, 0x15, 0x9C, 0xBC };
++
++unsigned char table_186[256] = {
++   0xB7, 0xFA, 0x03, 0x7C, 0x76, 0x43, 0xA7, 0x15,
++   0x4B, 0x4F, 0x04, 0xAA, 0x4E, 0xD2, 0x52, 0xC8,
++   0x79, 0x16, 0xF6, 0x61, 0x01, 0x5D, 0xD6, 0x47,
++   0xDE, 0xC5, 0x4D, 0x2F, 0xF5, 0x29, 0x21, 0xE6,
++   0x97, 0x35, 0xDC, 0x0E, 0x8B, 0xF4, 0x0F, 0xBE,
++   0x30, 0x07, 0x1D, 0x46, 0x75, 0xCE, 0x56, 0x42,
++   0x28, 0x93, 0x84, 0x20, 0xA5, 0xC2, 0x87, 0x45,
++   0x1C, 0x6B, 0x55, 0x06, 0xEB, 0xB0, 0xF9, 0x14,
++   0x23, 0xF1, 0xFC, 0xD7, 0x98, 0xD1, 0xA4, 0xED,
++   0x5B, 0xB1, 0x12, 0x7A, 0xD5, 0x5F, 0x53, 0x88,
++   0x95, 0x71, 0xE7, 0x5C, 0xF8, 0x83, 0xC7, 0x49,
++   0xDD, 0xDA, 0x0B, 0xC1, 0x70, 0xEC, 0x67, 0xE2,
++   0xEA, 0x72, 0x4C, 0x92, 0xA6, 0xE5, 0x59, 0xA9,
++   0x3C, 0xFE, 0x0A, 0x65, 0x6E, 0xF3, 0xA3, 0x22,
++   0x24, 0x81, 0xF2, 0xCC, 0xD3, 0xA0, 0xDF, 0xDB,
++   0xAB, 0x09, 0x13, 0x96, 0x36, 0x9C, 0xEE, 0xD4,
++   0x33, 0x5E, 0x26, 0xAE, 0x48, 0x38, 0xFF, 0x08,
++   0x1F, 0x6D, 0x02, 0xEF, 0x7E, 0x57, 0x2A, 0x8A,
++   0xBA, 0x90, 0xAF, 0xA8, 0x37, 0x8E, 0x9B, 0xC0,
++   0x69, 0x32, 0x86, 0xBD, 0x73, 0x6C, 0xB9, 0x31,
++   0x66, 0xBF, 0x1B, 0x44, 0x9E, 0xB2, 0xD0, 0xE0,
++   0xF0, 0x2C, 0x3F, 0xE1, 0x91, 0x18, 0x19, 0x50,
++   0xCA, 0x8F, 0x54, 0xB5, 0x8D, 0x0C, 0x17, 0x39,
++   0x8C, 0x00, 0x7F, 0x41, 0xE3, 0x2E, 0x1A, 0x9D,
++   0x27, 0xA1, 0x10, 0x34, 0x1E, 0x3A, 0x60, 0x77,
++   0xBB, 0xB6, 0x0D, 0x4A, 0x3E, 0x6A, 0xB4, 0xA2,
++   0xB3, 0xFD, 0xCD, 0x80, 0x51, 0xAD, 0xCF, 0xBC,
++   0x40, 0x74, 0x6F, 0x68, 0x2B, 0xC3, 0xF7, 0x63,
++   0xB8, 0x25, 0xC4, 0x62, 0xE9, 0xFB, 0x58, 0x85,
++   0x78, 0xCB, 0x9A, 0x3D, 0xE4, 0xC9, 0x89, 0x2D,
++   0x64, 0x82, 0xC6, 0x05, 0xD8, 0xAC, 0x99, 0x9F,
++   0x11, 0x3B, 0x94, 0xE8, 0x7D, 0x7B, 0xD9, 0x5A };
++
++unsigned char table_187[32] = {
++   0x0F, 0x04, 0x1D, 0x1B, 0x15, 0x10, 0x01, 0x0B,
++   0x00, 0x17, 0x13, 0x07, 0x1E, 0x1F, 0x08, 0x0A,
++   0x19, 0x09, 0x05, 0x06, 0x0C, 0x1A, 0x14, 0x16,
++   0x0E, 0x18, 0x03, 0x1C, 0x12, 0x11, 0x0D, 0x02 };
++
++struct yahoo_fn yahoo_fntable[5][96] = 
++   {{{ IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 },
++     { IDENT, 0, 0 }},
++    {{ MULADD, 0x36056CD7, 0x4387 },
++     { LOOKUP, (long)table_0, 0 },
++     { LOOKUP, (long)table_1, 0 },
++     { BITFLD, (long)table_2, 0 },
++     { LOOKUP, (long)table_3, 0 },
++     { BITFLD, (long)table_4, 0 },
++     { MULADD, 0x4ABB534D, 0x3769 },
++     { XOR, 0x1D242DA5, 0 },
++     { MULADD, 0x3C23132D, 0x339B },
++     { XOR, 0x0191265C, 0 },
++     { XOR, 0x3DB979DB, 0 },
++     { LOOKUP, (long)table_5, 0 },
++     { XOR, 0x1A550E1E, 0 },
++     { XOR, 0x2F140A2D, 0 },
++     { MULADD, 0x7C466A4B, 0x29BF },
++     { XOR, 0x2D3F30D3, 0 },
++     { MULADD, 0x7E823B21, 0x6BB3 },
++     { BITFLD, (long)table_6, 0 },
++     { LOOKUP, (long)table_7, 0 },
++     { BITFLD, (long)table_8, 0 },
++     { LOOKUP, (long)table_9, 0 },
++     { BITFLD, (long)table_10, 0 },
++     { LOOKUP, (long)table_11, 0 },
++     { BITFLD, (long)table_12, 0 },
++     { LOOKUP, (long)table_13, 0 },
++     { BITFLD, (long)table_14, 0 },
++     { MULADD, 0x5B756AB9, 0x7E9B },
++     { LOOKUP, (long)table_15, 0 },
++     { XOR, 0x1D1C4911, 0 },
++     { LOOKUP, (long)table_16, 0 },
++     { LOOKUP, (long)table_17, 0 },
++     { XOR, 0x46BD7771, 0 },
++     { XOR, 0x51AE2B42, 0 },
++     { MULADD, 0x2417591B, 0x177B },
++     { MULADD, 0x57F27C5F, 0x2433 },
++     { LOOKUP, (long)table_18, 0 },
++     { LOOKUP, (long)table_19, 0 },
++     { XOR, 0x71422261, 0 },
++     { BITFLD, (long)table_20, 0 },
++     { MULADD, 0x58E937F9, 0x1075 },
++     { LOOKUP, (long)table_21, 0 },
++     { BITFLD, (long)table_22, 0 },
++     { LOOKUP, (long)table_23, 0 },
++     { LOOKUP, (long)table_24, 0 },
++     { MULADD, 0x0B4C3D13, 0x1597 },
++     { BITFLD, (long)table_25, 0 },
++     { XOR, 0x0FE07D38, 0 },
++     { MULADD, 0x689B4017, 0x3CFB },
++     { BITFLD, (long)table_26, 0 },
++     { LOOKUP, (long)table_27, 0 },
++     { XOR, 0x35413DF3, 0 },
++     { MULADD, 0x05B611AB, 0x570B },
++     { MULADD, 0x0DA5334F, 0x3AC7 },
++     { XOR, 0x47706008, 0 },
++     { BITFLD, (long)table_28, 0 },
++     { LOOKUP, (long)table_29, 0 },
++     { BITFLD, (long)table_30, 0 },
++     { XOR, 0x57611B36, 0 },
++     { MULADD, 0x314C2CD1, 0x2B5B },
++     { XOR, 0x1EF33946, 0 },
++     { MULADD, 0x28EA041F, 0x638F },
++     { LOOKUP, (long)table_31, 0 },
++     { LOOKUP, (long)table_32, 0 },
++     { LOOKUP, (long)table_33, 0 },
++     { MULADD, 0x511537CB, 0x7135 },
++     { MULADD, 0x1CF71007, 0x5E17 },
++     { XOR, 0x583D4BCF, 0 },
++     { LOOKUP, (long)table_34, 0 },
++     { XOR, 0x373E6856, 0 },
++     { MULADD, 0x4D595519, 0x1A7D },
++     { LOOKUP, (long)table_35, 0 },
++     { LOOKUP, (long)table_36, 0 },
++     { XOR, 0x0E2A36A7, 0 },
++     { LOOKUP, (long)table_37, 0 },
++     { LOOKUP, (long)table_38, 0 },
++     { BITFLD, (long)table_39, 0 },
++     { BITFLD, (long)table_40, 0 },
++     { XOR, 0x53F3604F, 0 },
++     { BITFLD, (long)table_41, 0 },
++     { BITFLD, (long)table_42, 0 },
++     { MULADD, 0x1EDC0BA3, 0x7531 },
++     { LOOKUP, (long)table_43, 0 },
++     { XOR, 0x10DF1038, 0 },
++     { BITFLD, (long)table_44, 0 },
++     { LOOKUP, (long)table_45, 0 },
++     { XOR, 0x4EDE0CAC, 0 },
++     { MULADD, 0x2F076EEB, 0x5BCF },
++     { XOR, 0x6D86030F, 0 },
++     { XOR, 0x3F331713, 0 },
++     { LOOKUP, (long)table_46, 0 },
++     { MULADD, 0x41CD726F, 0x3F79 },
++     { BITFLD, (long)table_47, 0 },
++     { XOR, 0x0ECE0054, 0 },
++     { MULADD, 0x19B32B03, 0x4AD1 },
++     { BITFLD, (long)table_48, 0 },
++     { BITFLD, (long)table_49, 0 }},
++    {{ MULADD, 0x39731111, 0x419B },
++     { XOR, 0x54F7757A, 0 },
++     { BITFLD, (long)table_50, 0 },
++     { BITFLD, (long)table_51, 0 },
++     { LOOKUP, (long)table_52, 0 },
++     { LOOKUP, (long)table_53, 0 },
++     { MULADD, 0x3CC0256B, 0x7CE7 },
++     { XOR, 0x79991847, 0 },
++     { MULADD, 0x228F7FB5, 0x472D },
++     { MULADD, 0x32DA290B, 0x7745 },
++     { XOR, 0x7A28180D, 0 },
++     { BITFLD, (long)table_54, 0 },
++     { BITFLD, (long)table_55, 0 },
++     { MULADD, 0x5C814F8B, 0x227F },
++     { LOOKUP, (long)table_56, 0 },
++     { MULADD, 0x0B496F6D, 0x412D },
++     { XOR, 0x6F4B62DA, 0 },
++     { LOOKUP, (long)table_57, 0 },
++     { XOR, 0x64973977, 0 },
++     { LOOKUP, (long)table_58, 0 },
++     { LOOKUP, (long)table_59, 0 },
++     { BITFLD, (long)table_60, 0 },
++     { LOOKUP, (long)table_61, 0 },
++     { LOOKUP, (long)table_62, 0 },
++     { XOR, 0x6DD14C92, 0 },
++     { LOOKUP, (long)table_63, 0 },
++     { BITFLD, (long)table_64, 0 },
++     { BITFLD, (long)table_65, 0 },
++     { BITFLD, (long)table_66, 0 },
++     { LOOKUP, (long)table_67, 0 },
++     { XOR, 0x5E6324D8, 0 },
++     { LOOKUP, (long)table_68, 0 },
++     { LOOKUP, (long)table_69, 0 },
++     { LOOKUP, (long)table_70, 0 },
++     { BITFLD, (long)table_71, 0 },
++     { XOR, 0x62745ED0, 0 },
++     { MULADD, 0x102C215B, 0x0581 },
++     { LOOKUP, (long)table_72, 0 },
++     { LOOKUP, (long)table_73, 0 },
++     { LOOKUP, (long)table_74, 0 },
++     { MULADD, 0x19511111, 0x12C1 },
++     { LOOKUP, (long)table_75, 0 },
++     { MULADD, 0x2A6E2953, 0x6977 },
++     { LOOKUP, (long)table_76, 0 },
++     { XOR, 0x55CD5445, 0 },
++     { BITFLD, (long)table_77, 0 },
++     { BITFLD, (long)table_78, 0 },
++     { MULADD, 0x646C21EB, 0x43E5 },
++     { XOR, 0x71DC4898, 0 },
++     { XOR, 0x167519CB, 0 },
++     { XOR, 0x6D3158F8, 0 },
++     { XOR, 0x7EA95BEA, 0 },
++     { BITFLD, (long)table_79, 0 },
++     { XOR, 0x47377587, 0 },
++     { XOR, 0x2D8B6E8F, 0 },
++     { MULADD, 0x5E6105DB, 0x1605 },
++     { XOR, 0x65B543C8, 0 },
++     { LOOKUP, (long)table_80, 0 },
++     { BITFLD, (long)table_81, 0 },
++     { MULADD, 0x48AF73CB, 0x0A67 },
++     { XOR, 0x4FB96154, 0 },
++     { LOOKUP, (long)table_82, 0 },
++     { BITFLD, (long)table_83, 0 },
++     { XOR, 0x622C4954, 0 },
++     { BITFLD, (long)table_84, 0 },
++     { XOR, 0x20D220F3, 0 },
++     { XOR, 0x361D4F0D, 0 },
++     { XOR, 0x2B2000D1, 0 },
++     { XOR, 0x6FB8593E, 0 },
++     { LOOKUP, (long)table_85, 0 },
++     { BITFLD, (long)table_86, 0 },
++     { XOR, 0x2B7F7DFC, 0 },
++     { MULADD, 0x5FC41A57, 0x0693 },
++     { MULADD, 0x17154387, 0x2489 },
++     { BITFLD, (long)table_87, 0 },
++     { BITFLD, (long)table_88, 0 },
++     { BITFLD, (long)table_89, 0 },
++     { LOOKUP, (long)table_90, 0 },
++     { XOR, 0x7E221470, 0 },
++     { XOR, 0x7A600061, 0 },
++     { BITFLD, (long)table_91, 0 },
++     { BITFLD, (long)table_92, 0 },
++     { LOOKUP, (long)table_93, 0 },
++     { BITFLD, (long)table_94, 0 },
++     { MULADD, 0x00E813A5, 0x2CE5 },
++     { MULADD, 0x3D707E25, 0x3827 },
++     { MULADD, 0x77A53E07, 0x6A5F },
++     { BITFLD, (long)table_95, 0 },
++     { LOOKUP, (long)table_96, 0 },
++     { LOOKUP, (long)table_97, 0 },
++     { XOR, 0x43A73788, 0 },
++     { LOOKUP, (long)table_98, 0 },
++     { BITFLD, (long)table_99, 0 },
++     { LOOKUP, (long)table_100, 0 },
++     { XOR, 0x55F4606B, 0 },
++     { BITFLD, (long)table_101, 0 }},
++    {{ BITFLD, (long)table_102, 0 },
++     { MULADD, 0x32CA58E3, 0x04F9 },
++     { XOR, 0x11756B30, 0 },
++     { MULADD, 0x218B2569, 0x5DB1 },
++     { XOR, 0x77D64B90, 0 },
++     { BITFLD, (long)table_103, 0 },
++     { LOOKUP, (long)table_104, 0 },
++     { MULADD, 0x7D1428CB, 0x3D },
++     { XOR, 0x6F872C49, 0 },
++     { XOR, 0x2E484655, 0 },
++     { MULADD, 0x1E3349F7, 0x41F5 },
++     { LOOKUP, (long)table_105, 0 },
++     { BITFLD, (long)table_106, 0 },
++     { XOR, 0x61640311, 0 },
++     { BITFLD, (long)table_107, 0 },
++     { LOOKUP, (long)table_108, 0 },
++     { LOOKUP, (long)table_109, 0 },
++     { LOOKUP, (long)table_110, 0 },
++     { XOR, 0x007044D3, 0 },
++     { BITFLD, (long)table_111, 0 },
++     { MULADD, 0x5C221625, 0x576F },
++     { LOOKUP, (long)table_112, 0 },
++     { LOOKUP, (long)table_113, 0 },
++     { XOR, 0x2D406BB1, 0 },
++     { MULADD, 0x680B1F17, 0x12CD },
++     { BITFLD, (long)table_114, 0 },
++     { MULADD, 0x12564D55, 0x32B9 },
++     { MULADD, 0x21A67897, 0x6BAB },
++     { LOOKUP, (long)table_115, 0 },
++     { MULADD, 0x06405119, 0x7143 },
++     { XOR, 0x351D01ED, 0 },
++     { MULADD, 0x46356F6B, 0x0A49 },
++     { MULADD, 0x32C77969, 0x72F3 },
++     { BITFLD, (long)table_116, 0 },
++     { LOOKUP, (long)table_117, 0 },
++     { LOOKUP, (long)table_118, 0 },
++     { BITFLD, (long)table_119, 0 },
++     { LOOKUP, (long)table_120, 0 },
++     { BITFLD, (long)table_121, 0 },
++     { MULADD, 0x74D52C55, 0x5F43 },
++     { XOR, 0x26201CA8, 0 },
++     { XOR, 0x7AEB3255, 0 },
++     { LOOKUP, (long)table_122, 0 },
++     { MULADD, 0x578F1047, 0x640B },
++     { LOOKUP, (long)table_123, 0 },
++     { LOOKUP, (long)table_124, 0 },
++     { BITFLD, (long)table_125, 0 },
++     { BITFLD, (long)table_126, 0 },
++     { XOR, 0x4A1352CF, 0 },
++     { MULADD, 0x4BFB6EF3, 0x704F },
++     { MULADD, 0x1B4C7FE7, 0x5637 },
++     { MULADD, 0x04091A3B, 0x4917 },
++     { XOR, 0x270C2F52, 0 },
++     { LOOKUP, (long)table_127, 0 },
++     { BITFLD, (long)table_128, 0 },
++     { LOOKUP, (long)table_129, 0 },
++     { BITFLD, (long)table_130, 0 },
++     { MULADD, 0x127549D5, 0x579B },
++     { MULADD, 0x0AB54121, 0x7A47 },
++     { BITFLD, (long)table_131, 0 },
++     { XOR, 0x751E6E49, 0 },
++     { LOOKUP, (long)table_132, 0 },
++     { LOOKUP, (long)table_133, 0 },
++     { XOR, 0x670C3F74, 0 },
++     { MULADD, 0x6B080851, 0x7E8B },
++     { XOR, 0x71CD789E, 0 },
++     { XOR, 0x3EB20B7B, 0 },
++     { BITFLD, (long)table_134, 0 },
++     { LOOKUP, (long)table_135, 0 },
++     { MULADD, 0x58A67753, 0x272B },
++     { MULADD, 0x1AB54AD7, 0x4D33 },
++     { MULADD, 0x07D30A45, 0x0569 },
++     { MULADD, 0x737616BF, 0x70C7 },
++     { LOOKUP, (long)table_136, 0 },
++     { MULADD, 0x45C4485D, 0x2063 },
++     { BITFLD, (long)table_137, 0 },
++     { XOR, 0x2598043D, 0 },
++     { MULADD, 0x223A4FE3, 0x49A7 },
++     { XOR, 0x1EED619F, 0 },
++     { BITFLD, (long)table_138, 0 },
++     { XOR, 0x6F477561, 0 },
++     { BITFLD, (long)table_139, 0 },
++     { BITFLD, (long)table_140, 0 },
++     { LOOKUP, (long)table_141, 0 },
++     { MULADD, 0x4BC13C4F, 0x45C1 },
++     { XOR, 0x3B547BFB, 0 },
++     { LOOKUP, (long)table_142, 0 },
++     { MULADD, 0x71406AB3, 0x7A5F },
++     { XOR, 0x2F1467E9, 0 },
++     { MULADD, 0x009366D1, 0x22D1 },
++     { MULADD, 0x587D1B75, 0x2CA5 },
++     { MULADD, 0x213A4BE7, 0x4499 },
++     { MULADD, 0x62653E89, 0x2D5D },
++     { BITFLD, (long)table_143, 0 },
++     { MULADD, 0x4F5F3257, 0x444F },
++     { MULADD, 0x4C0E2B2B, 0x19D3 }},
++    {{ MULADD, 0x3F867B35, 0x7B3B },
++     { MULADD, 0x32D25CB1, 0x3D6D },
++     { BITFLD, (long)table_144, 0 },
++     { MULADD, 0x50FA1C51, 0x5F4F },
++     { LOOKUP, (long)table_145, 0 },
++     { XOR, 0x05FE7AF1, 0 },
++     { MULADD, 0x14067C29, 0x10C5 },
++     { LOOKUP, (long)table_146, 0 },
++     { MULADD, 0x4A5558C5, 0x271F },
++     { XOR, 0x3C0861B1, 0 },
++     { BITFLD, (long)table_147, 0 },
++     { LOOKUP, (long)table_148, 0 },
++     { MULADD, 0x18837C9D, 0x6335 },
++     { BITFLD, (long)table_149, 0 },
++     { XOR, 0x7DAB5033, 0 },
++     { LOOKUP, (long)table_150, 0 },
++     { MULADD, 0x03B87321, 0x7225 },
++     { XOR, 0x7F906745, 0 },
++     { LOOKUP, (long)table_151, 0 },
++     { BITFLD, (long)table_152, 0 },
++     { XOR, 0x21C46C2C, 0 },
++     { MULADD, 0x2B36757D, 0x028D },
++     { BITFLD, (long)table_153, 0 },
++     { LOOKUP, (long)table_154, 0 },
++     { XOR, 0x106B4A85, 0 },
++     { XOR, 0x17640F11, 0 },
++     { LOOKUP, (long)table_155, 0 },
++     { XOR, 0x69E60486, 0 },
++     { LOOKUP, (long)table_156, 0 },
++     { MULADD, 0x3782017D, 0x05BF },
++     { BITFLD, (long)table_157, 0 },
++     { LOOKUP, (long)table_158, 0 },
++     { XOR, 0x6BCA53B0, 0 },
++     { LOOKUP, (long)table_159, 0 },
++     { LOOKUP, (long)table_160, 0 },
++     { LOOKUP, (long)table_161, 0 },
++     { LOOKUP, (long)table_162, 0 },
++     { XOR, 0x0B8236E3, 0 },
++     { BITFLD, (long)table_163, 0 },
++     { MULADD, 0x5EE51C43, 0x4553 },
++     { BITFLD, (long)table_164, 0 },
++     { LOOKUP, (long)table_165, 0 },
++     { LOOKUP, (long)table_166, 0 },
++     { LOOKUP, (long)table_167, 0 },
++     { MULADD, 0x42B14C6F, 0x5531 },
++     { XOR, 0x4A2548E8, 0 },
++     { MULADD, 0x5C071D85, 0x2437 },
++     { LOOKUP, (long)table_168, 0 },
++     { MULADD, 0x29195861, 0x108B },
++     { XOR, 0x24012258, 0 },
++     { LOOKUP, (long)table_169, 0 },
++     { XOR, 0x63CC2377, 0 },
++     { XOR, 0x08D04B59, 0 },
++     { MULADD, 0x3FD30CF5, 0x7027 },
++     { XOR, 0x7C3E0478, 0 },
++     { MULADD, 0x457776B7, 0x24B3 },
++     { XOR, 0x086652BC, 0 },
++     { MULADD, 0x302F5B13, 0x371D },
++     { LOOKUP, (long)table_170, 0 },
++     { MULADD, 0x58692D47, 0x0671 },
++     { XOR, 0x6601178E, 0 },
++     { MULADD, 0x0F195B9B, 0x1369 },
++     { XOR, 0x07BA21D8, 0 },
++     { BITFLD, (long)table_171, 0 },
++     { BITFLD, (long)table_172, 0 },
++     { XOR, 0x13AC3D21, 0 },
++     { MULADD, 0x5BCF3275, 0x6E1B },
++     { MULADD, 0x62725C5B, 0x16B9 },
++     { MULADD, 0x5B950FDF, 0x2D35 },
++     { BITFLD, (long)table_173, 0 },
++     { BITFLD, (long)table_174, 0 },
++     { MULADD, 0x73BA5335, 0x1C13 },
++     { BITFLD, (long)table_175, 0 },
++     { BITFLD, (long)table_176, 0 },
++     { XOR, 0x3E144154, 0 },
++     { MULADD, 0x4EED7B27, 0x38AB },
++     { LOOKUP, (long)table_177, 0 },
++     { MULADD, 0x627C7E0F, 0x7F01 },
++     { MULADD, 0x5D7E1F73, 0x2C0F },
++     { LOOKUP, (long)table_178, 0 },
++     { MULADD, 0x55C9525F, 0x4659 },
++     { XOR, 0x3765334C, 0 },
++     { MULADD, 0x5DF66DDF, 0x7C25 },
++     { LOOKUP, (long)table_179, 0 },
++     { LOOKUP, (long)table_180, 0 },
++     { XOR, 0x16AE5776, 0 },
++     { LOOKUP, (long)table_181, 0 },
++     { LOOKUP, (long)table_182, 0 },
++     { BITFLD, (long)table_183, 0 },
++     { BITFLD, (long)table_184, 0 },
++     { LOOKUP, (long)table_185, 0 },
++     { MULADD, 0x4392327B, 0x7E0D },
++     { LOOKUP, (long)table_186, 0 },
++     { MULADD, 0x3D8B0CB5, 0x640D },
++     { MULADD, 0x32865601, 0x4D43 },
++     { BITFLD, (long)table_187, 0 }}};
++
++#define A( x ) (( x ) & 0xFF )
++#define B( x ) (( x ) >> 8 & 0xFF )
++#define C( x ) (( x ) >> 16 & 0xFF )
++#define D( x ) (( x ) >> 24 & 0xFF )
++
++int yahoo_xfrm( int table, int depth, int seed )
++{
++   struct yahoo_fn *xfrm;
++   int i, j, z;
++   unsigned int n = seed;
++   unsigned char *arg;
++
++   for( i = 0; i < depth; i++ )
++   {
++      xfrm = &yahoo_fntable[table][n % 96];
++      switch( xfrm->type )
++      {
++      case IDENT:
++         return seed;
++      case XOR:
++         seed ^= xfrm->arg1;
++         break;
++      case MULADD:
++         seed = seed * xfrm->arg1 + xfrm->arg2;
++         break;
++      case LOOKUP:
++         arg = (unsigned char *)xfrm->arg1;
++         seed = arg[A( seed )] | arg[B( seed )] << 8 | arg[C( seed )] << 16
++            | arg[D( seed )] << 24;
++         break;
++      case BITFLD:
++         arg = (unsigned char *)xfrm->arg1;
++         for( j = 0, z = 0; j < 32; j++ )
++            z = ((( seed >> j ) & 1 ) << arg[j] ) | ( ~( 1 << arg[j] ) & z );
++         seed = z;
++         break;
++      }
++      if( depth - i == 1 )
++         return seed;
++      z = (((((( A( seed ) * 0x9E3779B1 ) ^ B( seed )) * 0x9E3779B1 )
++         ^ C( seed )) * 0x9E3779B1 ) ^ D( seed )) * 0x9E3779B1;
++      n = (((( z ^ ( z >> 8 )) >> 16 ) ^ z ) ^ ( z >> 8 )) & 0xFF;
++      seed *= 0x00010DCD;
++   }
++   return seed;
++}
+--- kopete/protocols/yahoo/libkyahoo/mailnotifiertask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/mailnotifiertask.cpp	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about new mails
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qstring.h>
++
++#include "mailnotifiertask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++MailNotifierTask::MailNotifierTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++MailNotifierTask::~MailNotifierTask()
++{
++
++}
++
++bool MailNotifierTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = static_cast<YMSGTransfer *>(transfer);
++
++	parseMail( t );
++
++	return true;
++}
++
++bool MailNotifierTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	if ( t->service() == Yahoo::ServiceNewMail )
++		return true;
++	else
++		return false;
++}
++
++void MailNotifierTask::parseMail( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString count = t->firstParam( 9 );
++	QString mail = t->firstParam( 42 );
++	QString from = t->firstParam( 43 );
++	QString subject = t->firstParam( 18 );
++
++	if( !mail.isEmpty() && !from.isEmpty() && !subject.isEmpty() )
++		emit mailNotify( QString::fromLatin1( "%1 <%2>").arg( from, mail ), subject, count.toInt() );
++	else
++		emit mailNotify( QString::null, QString::null, count.toInt());
++}
++
++#include "mailnotifiertask.moc"
+--- kopete/protocols/yahoo/libkyahoo/libyahoo.c	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/libyahoo.c	(revision 586398)
+@@ -0,0 +1,532 @@
++/*
++ * libyahoo2: libyahoo2.c
++ *
++ * Some code copyright (C) 2002, Philip S Tellis <philip . tellis AT gmx . net>
++ *
++ * Much of this code was taken and adapted from the yahoo module for
++ * gaim released under the GNU GPL.  This code is also released under the
++ * GNU GPL.
++ *
++ * This code is derivitive of Gaim <http://gaim.sourceforge.net>
++ * copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
++ *	       1998-1999, Adam Fritzler <afritz at marko.net>
++ *	       1998-2002, Rob Flynn <rob at marko.net>
++ *	       2000-2002, Eric Warmenhoven <eric at warmenhoven.org>
++ *	       2001-2002, Brian Macke <macke at strangelove.net>
++ *		    2001, Anand Biligiri S <abiligiri at users.sf.net>
++ *		    2001, Valdis Kletnieks
++ *		    2002, Sean Egan <bj91704 at binghamton.edu>
++ *		    2002, Toby Gray <toby.gray at ntlworld.com>
++ *
++ * This library also uses code from other libraries, namely:
++ *     Portions from libfaim copyright 1998, 1999 Adam Fritzler
++ *     <afritz at auk.cx>
++ *     Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
++ *     <hiro-y at kcn.ne.jp>
++ *
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#if HAVE_CONFIG_H
++# include <config.h>
++#endif 
++ 
++#include <string.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <stdio.h>
++
++#include "libyahoo.h"
++#include "yahoo_fn.h"
++#include "md5.h"
++#include "sha1.h"
++
++extern char *yahoo_crypt(char *, char *);
++
++void yahooBase64(unsigned char *out, const unsigned char *in, int inlen)
++/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
++{
++	char base64digits[] = 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++				"abcdefghijklmnopqrstuvwxyz"
++				"0123456789._";
++
++	for (; inlen >= 3; inlen -= 3)
++		{
++			*out++ = base64digits[in[0] >> 2];
++			*out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)];
++			*out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)];
++			*out++ = base64digits[in[2] & 0x3f];
++			in += 3;
++		}
++	if (inlen > 0)
++		{
++			unsigned char fragment;
++
++			*out++ = base64digits[in[0] >> 2];
++			fragment = (in[0] << 4) & 0x30;
++			if (inlen > 1)
++				fragment |= in[1] >> 4;
++			*out++ = base64digits[fragment];
++			*out++ = (inlen < 2) ? '-'
++					: base64digits[(in[1] << 2) & 0x3c];
++			*out++ = '-';
++		}
++	*out = '\0';
++}
++
++void authresp_0x0b(const char *seed, const char *sn, const char *password, char *resp_6, char *resp_96 )
++{
++	md5_byte_t         result[16];
++	md5_state_t        ctx;
++
++	SHA1Context            ctx1;
++	SHA1Context            ctx2;
++
++	const char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
++	const char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
++
++	const char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
++	const char *operand_lookup = "+|&%/*^-";
++	const char *delimit_lookup = ",;";
++
++	unsigned char *password_hash = malloc(25);
++	unsigned char *crypt_hash = malloc(25);
++	char *crypt_result = NULL;
++	unsigned char pass_hash_xor1[64];
++	unsigned char pass_hash_xor2[64];
++	unsigned char crypt_hash_xor1[64];
++	unsigned char crypt_hash_xor2[64];
++	char chal[7];
++
++	unsigned char digest1[20];
++	unsigned char digest2[20];
++	unsigned char magic_key_char[4];
++	const unsigned char *magic_ptr;
++
++	unsigned int  magic[64];
++	unsigned int  magic_work = 0;
++	/*unsigned int  value = 0;*/
++
++	char comparison_src[20];
++	int x, i, j;
++	int depth = 0, table = 0;
++	int cnt = 0;
++	int magic_cnt = 0;
++	int magic_len;
++	/*int times = 0;*/
++
++	memset(pass_hash_xor1, 0, 64);
++	memset(pass_hash_xor2, 0, 64);
++	memset(crypt_hash_xor1, 0, 64);
++	memset(crypt_hash_xor2, 0, 64);
++	memset(digest1, 0, 20);
++	memset(digest2, 0, 20);
++	memset(magic, 0, 64);
++	memset(resp_6, 0, 100);
++	memset(resp_96, 0, 100);
++	memset(magic_key_char, 0, 4);
++
++	/*
++	 * Magic: Phase 1.  Generate what seems to be a 30
++	 * byte value (could change if base64
++	 * ends up differently?  I don't remember and I'm
++	 * tired, so use a 64 byte buffer.
++	 */
++
++	magic_ptr = (unsigned char *)seed;
++
++	while (*magic_ptr != (int)NULL) {
++		char *loc;
++
++		/* Ignore parentheses.  */
++
++		if (*magic_ptr == '(' || *magic_ptr == ')') {
++			magic_ptr++;
++			continue;
++		}
++
++		/* Characters and digits verify against
++		   the challenge lookup.
++		*/
++
++		if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
++			loc = strchr(challenge_lookup, *magic_ptr);
++			if (!loc) {
++			        /* This isn't good */
++				continue;
++			}
++
++			/* Get offset into lookup table and lsh 3. */
++
++			magic_work = loc - challenge_lookup;
++			magic_work <<= 3;
++
++			magic_ptr++;
++			continue;
++		} else {
++			unsigned int local_store;
++
++			loc = strchr(operand_lookup, *magic_ptr);
++			if (!loc) {
++			        /* Also not good. */
++				continue;
++			}
++
++			local_store = loc - operand_lookup;
++
++			/* Oops; how did this happen? */
++			if (magic_cnt >= 64)
++			        break;
++
++			magic[magic_cnt++] = magic_work | local_store;
++			magic_ptr++;
++			continue;
++		}
++	}
++
++	magic_len = magic_cnt;
++	magic_cnt = 0;
++
++	/* Magic: Phase 2.  Take generated magic value and
++	 * sprinkle fairy dust on the values. */
++
++	for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
++		unsigned char byte1;
++		unsigned char byte2;
++
++		/* Bad.  Abort.
++		 */
++		if (magic_cnt >= magic_len)
++			break;
++
++		byte1 = magic[magic_cnt];
++		byte2 = magic[magic_cnt+1];
++
++		byte1 *= 0xcd;
++		byte1 ^= byte2;
++
++		magic[magic_cnt+1] = byte1;
++	}
++
++	/* Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic 
++	 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key 
++	 * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets 
++	 * into particular functions we'll later call to potentially alter the magic key. 
++	 * 
++	 * %-) 
++	 */ 
++	
++	magic_cnt = 1; 
++	x = 0; 
++	
++	do { 
++		unsigned int     bl = 0;  
++		unsigned int     cl = magic[magic_cnt++]; 
++		
++		if (magic_cnt >= magic_len) 
++			break; 
++		
++		if (cl > 0x7F) { 
++			if (cl < 0xe0)  
++				bl = cl = (cl & 0x1f) << 6;  
++			else { 
++				bl = magic[magic_cnt++];  
++                              cl = (cl & 0x0f) << 6;  
++                              bl = ((bl & 0x3f) + cl) << 6;  
++			}  
++			
++			cl = magic[magic_cnt++];  
++			bl = (cl & 0x3f) + bl;  
++		} else 
++			bl = cl;  
++		
++		comparison_src[x++] = (bl & 0xff00) >> 8;  
++		comparison_src[x++] = bl & 0xff;  
++	} while (x < 20); 
++
++	/* Dump magic key into a char for SHA1 action. */
++	
++		
++	for(x = 0; x < 4; x++) 
++		magic_key_char[x] = comparison_src[x];
++
++	/* Compute values for recursive function table! */
++	memcpy( chal, magic_key_char, 4 );
++	 x = 1;
++	for( i = 0; i < 0xFFFF && x; i++ )
++	{
++		for( j = 0; j < 5 && x; j++ )
++		{
++			chal[4] = i;
++			chal[5] = i >> 8;
++			chal[6] = j;
++			md5_init( &ctx );
++			md5_append( &ctx, chal, 7 );
++			md5_finish( &ctx, result );
++			if( memcmp( comparison_src + 4, result, 16 ) == 0 )
++			{
++				depth = i;
++				table = j;
++				x = 0;
++			}
++		}
++	}
++
++	/* Transform magic_key_char using transform table */
++	x = magic_key_char[3] << 24  | magic_key_char[2] << 16
++		| magic_key_char[1] << 8 | magic_key_char[0];
++	x = yahoo_xfrm( table, depth, x );
++	x = yahoo_xfrm( table, depth, x );
++	magic_key_char[0] = x & 0xFF;
++	magic_key_char[1] = x >> 8 & 0xFF;
++	magic_key_char[2] = x >> 16 & 0xFF;
++	magic_key_char[3] = x >> 24 & 0xFF;
++
++	/* Get password and crypt hashes as per usual. */
++	md5_init(&ctx);
++	md5_append(&ctx, (md5_byte_t *)password,  strlen(password));
++	md5_finish(&ctx, result);
++	yahooBase64(password_hash, result, 16);
++
++	md5_init(&ctx);
++	crypt_result = yahoo_crypt(password, "$1$_2S43d5f$");
++	md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
++	md5_finish(&ctx, result);
++	yahooBase64(crypt_hash, result, 16);
++
++	/* Our first authentication response is based off
++	 * of the password hash. */
++
++	for (x = 0; x < (int)strlen((char *)password_hash); x++)
++		pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
++
++	if (cnt < 64)
++		memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
++
++	cnt = 0;
++
++	for (x = 0; x < (int)strlen((char *)password_hash); x++)
++		pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
++
++	if (cnt < 64)
++		memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
++
++	SHA1Init(&ctx1);
++	SHA1Init(&ctx2);
++
++	/* The first context gets the password hash XORed
++	 * with 0x36 plus a magic value
++	 * which we previously extrapolated from our
++	 * challenge. */
++
++	SHA1Update(&ctx1, pass_hash_xor1, 64);
++	if (j >= 3 )
++		ctx1.totalLength = 0x1ff;
++	SHA1Update(&ctx1, magic_key_char, 4);
++	SHA1Final(&ctx1, digest1);
++
++	 /* The second context gets the password hash XORed
++	  * with 0x5c plus the SHA-1 digest
++	  * of the first context. */
++
++	SHA1Update(&ctx2, pass_hash_xor2, 64);
++	SHA1Update(&ctx2, digest1, 20);
++	SHA1Final(&ctx2, digest2);
++
++	/* Now that we have digest2, use it to fetch
++	 * characters from an alphabet to construct
++	 * our first authentication response. */
++
++	for (x = 0; x < 20; x += 2) {
++		unsigned int    val = 0;
++		unsigned int    lookup = 0;
++		char            byte[6];
++
++		memset(&byte, 0, 6);
++
++		/* First two bytes of digest stuffed
++		 *  together.
++		 */
++
++		val = digest2[x];
++		val <<= 8;
++		val += digest2[x+1];
++
++		lookup = (val >> 0x0b);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet1))
++			break;
++		sprintf(byte, "%c", alphabet1[lookup]);
++		strcat(resp_6, byte);
++		strcat(resp_6, "=");
++
++		lookup = (val >> 0x06);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet2))
++			break;
++		sprintf(byte, "%c", alphabet2[lookup]);
++		strcat(resp_6, byte);
++
++		lookup = (val >> 0x01);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet2))
++			break;
++		sprintf(byte, "%c", alphabet2[lookup]);
++		strcat(resp_6, byte);
++
++		lookup = (val & 0x01);
++		if (lookup >= strlen(delimit_lookup))
++			break;
++		sprintf(byte, "%c", delimit_lookup[lookup]);
++		strcat(resp_6, byte);
++	}
++
++	/* Our second authentication response is based off
++	 * of the crypto hash. */
++
++	cnt = 0;
++	memset(&digest1, 0, 20);
++	memset(&digest2, 0, 20);
++
++	for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
++		crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
++
++	if (cnt < 64)
++		memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
++
++	cnt = 0;
++
++	for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
++		crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
++
++	if (cnt < 64)
++		memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
++
++	SHA1Init(&ctx1);
++	SHA1Init(&ctx2);
++
++	/* The first context gets the password hash XORed
++	 * with 0x36 plus a magic value
++	 * which we previously extrapolated from our
++	 * challenge. */
++
++	SHA1Update(&ctx1, crypt_hash_xor1, 64);
++	if (j >= 3 )
++		ctx1.totalLength = 0x1ff;
++	SHA1Update(&ctx1, magic_key_char, 4);
++	SHA1Final(&ctx1, digest1);
++
++	/* The second context gets the password hash XORed
++	 * with 0x5c plus the SHA-1 digest
++	 * of the first context. */
++
++	SHA1Update(&ctx2, crypt_hash_xor2, 64);
++	SHA1Update(&ctx2, digest1, 20);
++	SHA1Final(&ctx2, digest2);
++
++	/* Now that we have digest2, use it to fetch
++	 * characters from an alphabet to construct
++	 * our first authentication response.  */
++
++	for (x = 0; x < 20; x += 2) {
++		unsigned int val = 0;
++		unsigned int lookup = 0;
++
++		char byte[6];
++
++		memset(&byte, 0, 6);
++
++		/* First two bytes of digest stuffed
++		 *  together. */
++
++		val = digest2[x];
++		val <<= 8;
++		val += digest2[x+1];
++
++		lookup = (val >> 0x0b);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet1))
++			break;
++		sprintf(byte, "%c", alphabet1[lookup]);
++		strcat(resp_96, byte);
++		strcat(resp_96, "=");
++
++		lookup = (val >> 0x06);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet2))
++			break;
++		sprintf(byte, "%c", alphabet2[lookup]);
++		strcat(resp_96, byte);
++
++		lookup = (val >> 0x01);
++		lookup &= 0x1f;
++		if (lookup >= strlen(alphabet2))
++			break;
++		sprintf(byte, "%c", alphabet2[lookup]);
++		strcat(resp_96, byte);
++
++		lookup = (val & 0x01);
++		if (lookup >= strlen(delimit_lookup))
++			break;
++		sprintf(byte, "%c", delimit_lookup[lookup]);
++		strcat(resp_96, byte);
++	}
++
++	free(password_hash);
++	free(crypt_hash);
++}
++
++char * getcookie(const char *rawcookie)
++{
++	char * cookie=NULL;
++	char * tmpcookie; 
++	char * cookieend;
++
++	if (strlen(rawcookie) < 2) 
++		return NULL;
++
++	tmpcookie = strdup(rawcookie+2);
++	cookieend = strchr(tmpcookie, ';');
++
++	if(cookieend)
++		*cookieend = '\0';
++
++	cookie = strdup(tmpcookie);
++	FREE(tmpcookie);
++	/* cookieend=NULL;  not sure why this was there since the value is not preserved in the stack -dd */
++
++	return cookie;
++}
++
++char * getlcookie(const char *cookie)
++{
++	char *tmp;
++	char *tmpend;
++	char *login_cookie = NULL;
++
++	tmpend = strstr(cookie, "n=");
++	if(tmpend) {
++		tmp = strdup(tmpend+2);
++		tmpend = strchr(tmp, '&');
++		if(tmpend)
++			*tmpend='\0';
++		login_cookie = strdup(tmp);
++		FREE(tmp);
++	}
++
++	return login_cookie;
++}
+--- kopete/protocols/yahoo/libkyahoo/ymsgprotocol.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/ymsgprotocol.h	(revision 586398)
+@@ -0,0 +1,44 @@
++/*
++    Kopete Yahoo Protocol
++
++    Copyright (c) 2004 Duncan Mac-Vicar Prett <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef YAHOO_YMSGPROTOCOL_H
++#define YAHOO_YMSGPROTOCOL_H
++
++#include "inputprotocolbase.h"
++
++
++class YMSGProtocol : public InputProtocolBase
++{
++Q_OBJECT
++public:
++	
++
++	YMSGProtocol( QObject *parent = 0, const char *name = 0 );
++	~YMSGProtocol();
++	
++	/** 
++	 * Attempt to parse the supplied data into an @ref YMSGTransfer object.  
++	 * The exact state of the parse attempt can be read using @ref state. 
++	 * @param rawData The unparsed data.
++	 * @param bytes An integer used to return the number of bytes read.
++	 * @return A pointer to an EventTransfer object if successfull, otherwise 0.  The caller is responsible for deleting this object.
++	 */
++	Transfer * parse( const QByteArray &, uint & bytes );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/filetransfernotifiertask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/filetransfernotifiertask.cpp	(revision 586398)
+@@ -0,0 +1,151 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about incoming filetransfers
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "filetransfernotifiertask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++FileTransferNotifierTask::FileTransferNotifierTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++FileTransferNotifierTask::~FileTransferNotifierTask()
++{
++
++}
++
++bool FileTransferNotifierTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++	
++	YMSGTransfer *t = static_cast<YMSGTransfer*>(transfer);
++
++	if( t->service() == Yahoo::ServiceFileTransfer )
++		parseFileTransfer( t );
++	else if( t->service() == Yahoo::ServiceFileTransfer7 )
++		parseFileTransfer7( t );
++	else if( t->service() == Yahoo::ServicePeerToPeer )
++		acceptFileTransfer( t );
++		
++
++	return true;
++}
++
++bool FileTransferNotifierTask::forMe( Transfer *transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++
++	if( t->service() == Yahoo::ServiceP2PFileXfer ||
++		t->service() == Yahoo::ServicePeerToPeer ||
++		t->service() == Yahoo::ServiceFileTransfer ||
++		t->service() == Yahoo::ServiceFileTransfer7
++	)
++		return true;
++	else
++		return false;
++}
++
++void FileTransferNotifierTask::parseFileTransfer( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString from;		/* key = 4  */
++	QString to;		/* key = 5  */
++	QString url;		/* key = 20  */
++	long expires;		/* key = 38  */
++	QString msg;		/* key = 14  */
++	QString filename;	/* key = 27  */
++	unsigned long size;	/* key = 28  */
++
++	from = t->firstParam( 4 );
++	to = t->firstParam( 5 );
++	url = t->firstParam( 20 );
++	expires = t->firstParam( 38 ).toLong();
++	msg = t->firstParam( 14 );
++	filename = t->firstParam( 27 );
++	size = t->firstParam( 28 ).toULong();
++
++
++
++	if( from.startsWith( "FILE_TRANSFER_SYSTEM" ) )
++	{
++		client()->notifyError( "Fileupload result received.", msg, Client::Notice );
++		return;
++	}	
++	
++	if( url.isEmpty() )
++		return;
++	
++
++	unsigned int left = url.findRev( '/' ) + 1;
++	unsigned int right = url.findRev( '?' );
++	filename = url.mid( left, right - left );
++
++	emit incomingFileTransfer( from, url, expires, msg, filename, size );
++}
++
++void FileTransferNotifierTask::parseFileTransfer7( YMSGTransfer *t )
++{ 
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString from;		/* key = 4  */
++	QString to;		/* key = 5  */
++	QString url;		/* key = 20  */
++	long expires;		/* key = 38  */
++	QString msg;		/* key = 14  */
++	QString filename;	/* key = 27  */
++	unsigned long size;	/* key = 28  */
++	
++	if( t->firstParam( 222 ).toInt() == 2 )
++		return;					// user cancelled the file transfer
++
++	from = t->firstParam( 4 );
++	to = t->firstParam( 5 );
++	url = t->firstParam( 265 );
++	msg = t->firstParam( 14 );
++	filename = t->firstParam( 27 );
++	size = t->firstParam( 28 ).toULong();
++
++	emit incomingFileTransfer( from, url, expires, msg, filename, size );
++}
++
++void FileTransferNotifierTask::acceptFileTransfer( YMSGTransfer *transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePeerToPeer);
++	t->setId( client()->sessionID() );
++	t->setParam( 4, client()->userId().local8Bit() );
++	t->setParam( 5, transfer->firstParam( 4 ) );
++	t->setParam( 11, transfer->firstParam( 11 ) );
++
++	send( t );
++}
++
++#include "filetransfernotifiertask.moc"
+--- kopete/protocols/yahoo/libkyahoo/yahoo_fn.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoo_fn.h	(revision 586398)
+@@ -0,0 +1,33 @@
++/*
++ * gaim
++ *
++ * Copyright (C) 2003
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#define IDENT  1 /* identify function */
++#define XOR    2 /* xor with arg1 */
++#define MULADD 3 /* multipy by arg1 then add arg2 */
++#define LOOKUP 4 /* lookup each byte in the table pointed to by arg1 */
++#define BITFLD 5 /* reorder bits according to table pointed to by arg1 */
++
++struct yahoo_fn
++{
++	int type; 
++	long arg1, arg2;
++};
++
++int yahoo_xfrm( int table, int depth, int seed );
+--- kopete/protocols/yahoo/libkyahoo/yahoobuddyiconloader.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoobuddyiconloader.cpp	(revision 586398)
+@@ -0,0 +1,108 @@
++/*
++    yahoobuddyiconloader.cpp - Fetches YahooBuddyIcons
++
++    Copyright (c) 2005 by André Duffeck <andre at duffeck.de>
++
++    *************************************************************************
++    *                                                                       *
++    * 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 "yahoobuddyiconloader.h"
++
++// QT Includes
++#include <qfile.h>
++
++// KDE Includes
++#include <kdebug.h>
++#include <ktempfile.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++#include <kurl.h>
++#include <kstandarddirs.h>
++#include <klocale.h>
++
++#include "yahootypes.h"
++#include "client.h"
++
++YahooBuddyIconLoader::YahooBuddyIconLoader( Client *c )
++: m_client( c )
++{
++}
++
++YahooBuddyIconLoader::~YahooBuddyIconLoader()
++{
++}
++
++void YahooBuddyIconLoader::fetchBuddyIcon( const QString &who, KURL url, int checksum )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	KIO::TransferJob *transfer;
++	QString Url = url.url();
++	QString ext = Url.left( Url.findRev( "?" ) );
++	ext = ext.right( ext.length() - ext.findRev( "." ) );
++	
++	transfer = KIO::get( url, false, false );
++	connect( transfer, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotComplete( KIO::Job* ) ) );
++	connect( transfer, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
++
++	m_jobs[transfer].url = url;
++	m_jobs[transfer].who = who;
++	m_jobs[transfer].checksum = checksum;
++	m_jobs[transfer].file = new KTempFile( locateLocal( "tmp", "yahoobuddyicon-" ), ext );
++	m_jobs[transfer].file->setAutoDelete( true );
++
++}
++
++void YahooBuddyIconLoader::slotData( KIO::Job *job, const QByteArray& data )
++{
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	KIO::TransferJob *transfer = static_cast< KIO::TransferJob * >(job);
++
++	if( m_jobs[transfer].file )
++		m_jobs[transfer].file->file()->writeBlock( data.data() , data.size() );
++
++}
++
++void YahooBuddyIconLoader::slotComplete( KIO::Job *job )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	KIO::TransferJob *transfer = static_cast< KIO::TransferJob * >(job);
++
++	if ( job->error () || transfer->isErrorPage () )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "An error occured while downloading buddy icon." << endl;
++		if( m_client )
++			m_client->notifyError( i18n( "An error occured while downloading buddy icon (%1)" ).arg(m_jobs[transfer].url.url()), job->errorString(), Client::Info );
++	}
++	else
++	{
++		if ( m_jobs[transfer].file )
++		{
++			m_jobs[transfer].file->close();
++			emit fetchedBuddyIcon( m_jobs[transfer].who, m_jobs[transfer].file, m_jobs[transfer].checksum );
++		}
++		else
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Fatal Error occured. IconLoadJob has an empty KTempFile pointer." << endl;
++			if( m_client )
++				m_client->notifyError( i18n( "Fatal Error occured while downloading buddy icon." ), i18n( "IconLoadJob has an empty KTempFile pointer." ), Client::Info );
++		}
++	}
++
++	m_jobs.remove( transfer );
++}
++
++
++
++#include "yahoobuddyiconloader.moc"
++
+--- kopete/protocols/yahoo/libkyahoo/yahootypes.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahootypes.h	(revision 586398)
+@@ -0,0 +1,182 @@
++/*
++    yahootypes.h - Kopete Yahoo Protocol definitions
++
++    Copyright (c) 2004 Duncan Mac-Vicar Prett <duncan at kde.org>
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef YAHOOTYPESH
++#define YAHOOTYPESH
++
++#include <qglobal.h>
++
++const int YAHOO_RAW_DEBUG = 14181;
++const int YAHOO_GEN_DEBUG = 14180;
++
++namespace Yahoo
++{
++	enum Service 
++	{ 
++		/* these are easier to see in hex */
++		ServiceLogon = 1,
++		ServiceLogoff,
++		ServiceIsAway,
++		ServiceIsBack,
++		ServiceIdle, /* 5 (placemarker) */
++		ServiceMessage,
++		ServiceIdAct,
++		ServiceIddeAct,
++		ServiceMailStat,
++		ServiceUserStat, /* 0xa */
++		ServiceNewMail,
++		ServiceChatInvite,
++		ServiceCalendar,
++		ServiceNewPersonalMail,
++		ServiceNewContact,
++		ServiceAddIdent, /* 0x10 */
++		ServiceAddIgnore,
++		ServicePing,
++		ServiceGotGroupRename, /* < 1, 36(old), 37(new) */
++		ServiceSysMessage = 0x14,
++		ServicePassThrough2 = 0x16,
++		ServiceConfInvite = 0x18,
++		ServiceConfLogon,
++		ServiceConfDecline,
++		ServiceConfLogoff,
++		ServiceConfAddInvite,
++		ServiceConfMsg,
++		ServiceChatLogon,
++		ServiceChatLogoff,
++		ServiceChatMsg = 0x20,
++		ServiceGameLogon = 0x28,
++		ServiceGameLogoff,
++		ServiceGameMsg = 0x2a,
++		ServiceFileTransfer = 0x46,
++		ServiceVoiceChat = 0x4A,
++		ServiceNotify,
++		ServiceVerify = 76,
++		ServiceP2PFileXfer,
++		ServicePeerToPeer = 0x4F,	/* Checks if P2P possible */
++		ServiceWebcam,
++		ServiceAuthResp = 0x54,
++		ServiceList = 85,
++		ServiceAuth = 0x57,
++		ServiceAddBuddy = 0x83,
++		ServiceRemBuddy,
++		ServiceIgnoreContact,	/* > 1, 7, 13 < 1, 66, 13, 0*/
++		ServiceRejectContact,
++		ServiceGroupRename = 0x89, /* > 1, 65(new), 66(0), 67(old) */
++		ServicePing7 = 0x8a,
++		ServiceChatOnline = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
++		ServiceChatGoto,
++		ServiceChatJoin,	/* > 1 104-room 129-1600326591 62-2 */
++		ServiceChatleave,
++		ServiceChatExit = 0x9b,
++		ServiceChatLogout = 0xa0,
++		ServiceChatPing,
++		ServiceComment = 0xa8,
++		ServiceStealthOffline = 0xb9,
++		ServiceStealthOnline = 0xba,
++		ServicePictureChecksum = 0xbd,
++		ServicePicture = 0xbe,
++		ServicePictureUpdate = 0xc1,
++		ServicePictureUpload = 0xc2,
++		ServiceVisibility = 0xc5,	/* YMSG13, key 13: 2 = invisible, 1 = visible */
++		ServiceStatus = 0xc6,		/* YMSG13 */
++		ServicePictureStatus = 0xc7,	/* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */
++		ServiceContactDetails = 0xd3,	/* YMSG13 */
++		ServiceChatSession = 0xd4,	
++		ServiceAuthorization = 0xd6,	/* YMSG13 */
++		ServiceFileTransfer7 = 0xdc,	/* YMSG13 */
++		ServiceFileTransfer7Info,	/* YMSG13 */
++		ServiceFileTransfer7Accept,	/* YMSG13 */
++		ServiceBuddyChangeGroup = 0xe7	/* YMSG13 */
++	};
++	
++	enum Status 
++	{
++		StatusConnecting = -2,
++		StatusDisconnected = -1,
++		StatusAvailable = 0,
++		StatusBRB = 1,
++		StatusBusy,
++		StatusNotAtHome,
++		StatusNotAtDesk,
++		StatusNotInOffice,
++		StatusOnPhone,
++		StatusOnVacation,
++		StatusOutToLunch,
++		StatusSteppedOut,
++		StatusInvisible = 12,
++		StatusCustom = 99,
++		StatusIdle = 999,
++		StatusWebLogin = 0x5a55aa55,
++		StatusOffline = 0x5a55aa56, /* don't ask */
++		StatusNotify = 0x16
++	};
++
++	enum StatusType
++	{
++		StatusTypeAvailable = 0,
++		StatusTypeAway
++	};
++
++	enum LoginStatus {
++	LoginOk = 0,
++	LoginUname = 3,
++	LoginPasswd = 13,
++	LoginLock = 14,
++	LoginVerify = 29,	// FIXME: Find the reason for this response
++	LoginDupl = 99,
++	LoginSock = -1
++	};
++
++	enum StealthMode {
++		StealthOnline,
++		StealthOffline,
++		StealthPermOffline
++	};
++
++	enum StealthStatus {
++		StealthActive = 1,
++		StealthNotActive = 2,
++		StealthClear = 3
++	};
++
++	enum Response {
++		ResponseAccept,
++		ResponseDecline
++	};
++
++	typedef Q_UINT8 BYTE;
++	typedef Q_UINT16 WORD;
++	typedef Q_UINT32 DWORD;
++}
++
++#define yahoo_put16(buf, data) ( \
++		(*(buf) = (unsigned char)((data)>>8)&0xff), \
++		(*((buf)+1) = (unsigned char)(data)&0xff),  \
++		2)
++#define yahoo_get16(buf) ((((*(buf))&0xff)<<8) + ((*((buf)+1)) & 0xff))
++#define yahoo_put32(buf, data) ( \
++		(*((buf)) = (unsigned char)((data)>>24)&0xff), \
++		(*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
++		(*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
++		(*((buf)+3) = (unsigned char)(data)&0xff), \
++		4)
++#define yahoo_get32(buf) ((((*(buf)   )&0xff)<<24) + \
++			 (((*((buf)+1))&0xff)<<16) + \
++			 (((*((buf)+2))&0xff)<< 8) + \
++			 (((*((buf)+3))&0xff)))
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/receivefiletask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/receivefiletask.h	(revision 586398)
+@@ -0,0 +1,83 @@
++/*
++    Kopete Yahoo Protocol
++    Receive a file
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef RECEIVEFILETASK_H
++#define RECEIVEFILETASK_H
++
++#include "task.h"
++#include <qfile.h>
++#include <kurl.h>
++
++class QString;
++class QFile;
++namespace KIO { 
++	class Job;
++	class TransferJob;
++	class MimetypeJob;
++}
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class ReceiveFileTask : public Task
++{
++	Q_OBJECT
++public:
++	enum Type { FileTransferAccept, FileTransfer7Accept, FileTransfer7Reject };
++	ReceiveFileTask(Task *parent);
++	~ReceiveFileTask();
++	
++	virtual void onGo();
++	
++	void setRemoteUrl( KURL url );
++	void setLocalUrl( KURL url );
++	void setFileName( const QString &filename );
++	void setTransferId( unsigned int transferId );
++	void setType( Type type );
++	void setUserId( const QString & userId );
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++
++signals:
++	void bytesProcessed( unsigned int, unsigned int );
++	void complete( unsigned int );
++	void error( unsigned int, int, const QString & );
++
++private slots:
++	void slotData( KIO::Job *job, const QByteArray &data );
++	void slotComplete( KIO::Job *job );
++	void canceled( unsigned int );
++
++private:
++	void parseFileTransfer7Info( YMSGTransfer *transfer );
++
++	KURL m_remoteUrl;
++	KURL m_localUrl;
++	QString m_fileName;
++	QString m_userId;
++	QFile *m_file;
++	KIO::TransferJob *m_transferJob;
++	KIO::MimetypeJob *m_mimetypeJob;
++	unsigned int m_transferId;
++	unsigned int m_transmitted;
++	Type m_type;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/modifyyabtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/modifyyabtask.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++    Kopete Yahoo Protocol
++    modifyyabtask.h - Saves a YAB entry
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef MODIFYYABTASK_H
++#define MODIFYYABTASK_H
++
++#include "task.h"
++#include "yabentry.h"
++
++struct KURL;
++namespace KIO	{ 
++	class Job;
++	class TransferJob;
++}
++namespace KNetwork	{ 
++	class KBufferedSocket;
++}
++class QDomElement;
++
++/**
++ at author André Duffeck
++*/
++class ModifyYABTask : public Task
++{
++	Q_OBJECT
++public:
++	enum Action { AddEntry, EditEntry, DeleteEntry };
++	ModifyYABTask(Task *parent);
++	~ModifyYABTask();
++
++	virtual void onGo();
++	void setAction( Action action );
++	void setEntry( const YABEntry & );
++signals:
++	void gotEntry( YABEntry * );
++	void gotRevision( long rev, bool merged );
++	void error( YABEntry *, const QString &);
++private slots:
++	void connectSucceeded();
++	void connectFailed( int );
++	void slotRead();
++private:
++	KIO::TransferJob *m_transferJob;
++	KNetwork::KBufferedSocket *m_socket;
++	QString m_postData;
++	QString m_data;
++	Action m_action;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/libyahoo.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/libyahoo.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++ * libyahoo2: libyahoo2.c
++ *
++ * Some code copyright (C) 2002, Philip S Tellis <philip . tellis AT gmx . net>
++ *
++ * Much of this code was taken and adapted from the yahoo module for
++ * gaim released under the GNU GPL.  This code is also released under the
++ * GNU GPL.
++ *
++ * This code is derivitive of Gaim <http://gaim.sourceforge.net>
++ * copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
++ *	       1998-1999, Adam Fritzler <afritz at marko.net>
++ *	       1998-2002, Rob Flynn <rob at marko.net>
++ *	       2000-2002, Eric Warmenhoven <eric at warmenhoven.org>
++ *	       2001-2002, Brian Macke <macke at strangelove.net>
++ *		    2001, Anand Biligiri S <abiligiri at users.sf.net>
++ *		    2001, Valdis Kletnieks
++ *		    2002, Sean Egan <bj91704 at binghamton.edu>
++ *		    2002, Toby Gray <toby.gray at ntlworld.com>
++ *
++ * This library also uses code from other libraries, namely:
++ *     Portions from libfaim copyright 1998, 1999 Adam Fritzler
++ *     <afritz at auk.cx>
++ *     Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
++ *     <hiro-y at kcn.ne.jp>
++ *
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++
++#ifndef LIB_YAHOO_UTILS_H
++#define LIB_YAHOO_UTILS_H
++
++#ifndef MIN
++#define MIN(x,y) ((x)<(y)?(x):(y))
++#endif
++
++#ifndef MAX
++#define MAX(x,y) ((x)>(y)?(x):(y))
++#endif
++#define FREE(x)                if(x) {free(x); x=NULL;}
++
++void authresp_0x0b(const char *seed, const char *sn, const char *password, char *resp_6, char *resp_96 );
++void yahooBase64(unsigned char *out, const unsigned char *in, int inlen);
++char * getlcookie(const char *cookie);
++char * getcookie(const char *rawcookie);
++#endif
+--- kopete/protocols/yahoo/libkyahoo/sendfiletask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendfiletask.cpp	(revision 586398)
+@@ -0,0 +1,189 @@
++/*
++    Kopete Yahoo Protocol
++    Send a file
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "sendfiletask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qtimer.h>
++#include <kdebug.h>
++#include <klocale.h>
++#include <kstreamsocket.h>
++#include <kio/global.h>
++
++using namespace KNetwork;
++
++SendFileTask::SendFileTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_transmitted = 0;
++	m_socket = 0;
++}
++
++SendFileTask::~SendFileTask()
++{
++	m_socket->deleteLater();
++	m_socket = 0;
++}
++
++void SendFileTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QTimer::singleShot( 0, this, SLOT(initiateUpload()) );
++}
++
++void SendFileTask::initiateUpload()
++{	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_socket = new KStreamSocket( "filetransfer.msg.yahoo.com", QString::number(80) );
++	m_socket->setBlocking( true );
++	connect( m_socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( connectSucceeded() ) );
++	connect( m_socket, SIGNAL( gotError(int) ), this, SLOT( connectFailed(int) ) );
++
++	m_socket->connect();
++}
++
++void SendFileTask::connectFailed( int i )
++{
++	QString err = m_socket->errorString();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << i << ": " << err << endl;
++	emit error( m_transferId, i, err );
++	setSuccess( false );
++}
++
++void SendFileTask::connectSucceeded()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer t( Yahoo::ServiceFileTransfer );
++
++	m_file.setName( m_url.path() );
++
++	t.setId( client()->sessionID() );
++	t.setParam( 0, client()->userId().local8Bit());
++	t.setParam( 5, m_target.local8Bit());
++	t.setParam( 28, m_file.size() );	
++	t.setParam( 27, m_url.fileName().local8Bit() );
++	t.setParam( 14, "" );
++	QByteArray buffer;
++	QByteArray paket;
++	QDataStream stream( buffer, IO_WriteOnly );
++
++	if ( m_file.open(IO_ReadOnly ) )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "File successfully opened. Reading..." << endl;
++	}
++	else
++	{
++		client()->notifyError( i18n( "An error occured sending the file." ), m_file.errorString(), Client::Error );
++		setSuccess( false );
++		return;
++	}
++
++	paket = t.serialize();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Sizes: File (" << m_url << "): " << m_file.size() << " - paket: " << paket.size() << endl;
++	QString header = QString::fromLatin1("POST http://filetransfer.msg.yahoo.com:80/notifyft HTTP/1.1\r\n"
++			"Cookie: Y=%1; T=%2; C=%3 ;B=fckeert1kk1nl&b=2\r\n"
++			"User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
++			"Host: filetransfer.msg.yahoo.com:80\r\n"
++			"Content-length: %4\r\n"
++			"Cache-Control: no-cache\r\n\r\n").arg(client()->yCookie()).arg(client()->tCookie()).arg(client()->cCookie()).arg(m_file.size()+4+paket.size());
++	stream.writeRawBytes( header.local8Bit(), header.length() );
++	stream.writeRawBytes( paket.data(), paket.size() );
++	stream << (Q_INT8)0x32 << (Q_INT8)0x39 << (Q_INT8)0xc0 << (Q_INT8)0x80;
++
++	if( !m_socket->writeBlock( buffer, buffer.size() ) )
++	{
++		emit error( m_transferId, m_socket->error(), m_socket->errorString() );
++		m_socket->close();
++	}
++	else
++	{
++		connect( m_socket, SIGNAL(readyWrite()), this, SLOT(transmitData()) );
++		m_socket->enableWrite( true );
++	}
++}
++
++void SendFileTask::transmitData()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	int read = 0;
++	int written = 0;	
++	char buf[1024];
++
++	m_socket->enableWrite( false );
++	read = m_file.readBlock( buf, 1024 );
++	written = m_socket->writeBlock( buf, read );
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "read:" << read << " written: " << written << endl;
++
++	m_transmitted += read;
++	emit bytesProcessed( m_transferId, m_transmitted );
++
++	if( written != read )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Upload Failed!" << endl;
++		emit error( m_transferId, m_socket->error(), m_socket->errorString() );
++		setSuccess( false );
++		return;
++	}
++	if( m_transmitted == m_file.size() )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Upload Successful: " << m_transmitted << endl;
++		emit complete( m_transferId );
++		setSuccess( true );
++		m_socket->close();
++	}
++	else
++	{
++		m_socket->enableWrite( true );
++	}
++}
++void SendFileTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void SendFileTask::setMessage( const QString &msg )
++{
++	m_msg = msg;
++}
++
++void SendFileTask::setFileUrl( KURL url )
++{
++	m_url = url;
++
++}
++
++void SendFileTask::setTransferId( unsigned int transferId )
++{
++	m_transferId = transferId;
++}
++
++void SendFileTask::canceled( unsigned int id )
++{
++	if( m_transferId != id )
++		return;
++	
++	if( m_socket )
++		m_socket->close();
++	
++	setSuccess( false );
++}
++
++#include "sendfiletask.moc"
++
+--- kopete/protocols/yahoo/libkyahoo/client.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/client.cpp	(revision 586398)
+@@ -0,0 +1,857 @@
++/*
++    Kopete Yahoo Protocol
++    
++    Copyright (c) 2005-2006 André Duffeck <andre.duffeck at kdemail.net>
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++    Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qtimer.h>
++
++#include <kdebug.h>
++#include <kurl.h>
++#include <ksocketbase.h>
++
++#include "yahooclientstream.h"
++#include "yahooconnector.h"
++#include "task.h"
++#include "logintask.h"
++#include "listtask.h"
++#include "statusnotifiertask.h"
++#include "mailnotifiertask.h"
++#include "messagereceivertask.h"
++#include "sendnotifytask.h"
++#include "sendmessagetask.h"
++#include "logofftask.h"
++#include "changestatustask.h"
++#include "modifybuddytask.h"
++#include "picturenotifiertask.h"
++#include "requestpicturetask.h"
++#include "stealthtask.h"
++#include "sendpicturetask.h"
++#include "webcamtask.h"
++#include "conferencetask.h"
++#include "sendauthresptask.h"
++#include "pingtask.h"
++#include "yabtask.h"
++#include "modifyyabtask.h"
++#include "chatsessiontask.h"
++#include "sendfiletask.h"
++#include "filetransfernotifiertask.h"
++#include "receivefiletask.h"
++#include "client.h"
++#include "yahootypes.h"
++#include "yahoobuddyiconloader.h"
++
++using namespace KNetwork;
++
++class Client::ClientPrivate
++{
++public:
++	ClientPrivate() {}
++
++	ClientStream *stream;
++	int id_seed;
++	Task *root;
++	QString host, user, pass;
++	uint port;
++	bool active;
++	YahooBuddyIconLoader *iconLoader;
++	int error;
++	QString errorString;
++	QString errorInformation;
++	
++	// tasks
++	bool tasksInitialized;
++	LoginTask * loginTask;
++	ListTask *listTask;
++	StatusNotifierTask *statusTask;
++	MailNotifierTask *mailTask;
++	MessageReceiverTask *messageReceiverTask;
++	PictureNotifierTask *pictureNotifierTask;
++	WebcamTask *webcamTask;
++	ConferenceTask *conferenceTask;
++	YABTask *yabTask;
++	FileTransferNotifierTask *fileTransferTask;
++
++	// Connection data
++	uint sessionID;
++	QString yCookie;
++	QString tCookie;
++	QString cCookie;
++	Yahoo::Status status;
++	Yahoo::Status statusOnConnect;
++	QString statusMessageOnConnect;
++	int pictureFlag;
++};
++
++Client::Client(QObject *par) :QObject(par, "yahooclient" )
++{
++	d = new ClientPrivate;
++/*	d->tzoffset = 0;*/
++	d->active = false;
++
++	d->root = new Task(this, true);
++	d->statusOnConnect = Yahoo::StatusAvailable;
++	setStatus( Yahoo::StatusDisconnected );
++	d->tasksInitialized = false;
++	d->stream = 0L;
++	d->iconLoader = 0L;
++	d->loginTask = new LoginTask( d->root );
++	d->listTask = new ListTask( d->root );
++	d->pictureFlag = 0;
++	m_connector = 0L;
++
++	m_pingTimer = new QTimer( this );
++	QObject::connect( m_pingTimer, SIGNAL( timeout() ), this, SLOT( sendPing() ) );
++
++	QObject::connect( d->loginTask, SIGNAL( haveSessionID( uint ) ), SLOT( lt_gotSessionID( uint ) ) );
++	QObject::connect( d->loginTask, SIGNAL( loginResponse( int, const QString& ) ), 
++				SLOT( slotLoginResponse( int, const QString& ) ) );
++	QObject::connect( d->loginTask, SIGNAL( haveCookies() ), SLOT( slotGotCookies() ) );
++	QObject::connect( d->listTask, SIGNAL( gotBuddy(const QString &, const QString &, const QString &) ), 
++					SIGNAL( gotBuddy(const QString &, const QString &, const QString &) ) );
++	QObject::connect( d->listTask, SIGNAL( stealthStatusChanged( const QString&, Yahoo::StealthStatus ) ), 
++					SIGNAL( stealthStatusChanged( const QString&, Yahoo::StealthStatus ) ) );
++}
++
++Client::~Client()
++{
++	close();
++	delete d->iconLoader;
++	delete d->root;
++	delete d;
++}
++
++void Client::connect( const QString &host, const uint port, const QString &userId, const QString &pass )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	d->host = host;
++	d->port = port;
++	d->user = userId;
++	d->pass = pass;
++	setStatus( Yahoo::StatusConnecting );
++
++	m_connector = new KNetworkConnector;
++	m_connector->setOptHostPort( host, port );
++	d->stream = new ClientStream( m_connector, this );
++	QObject::connect( d->stream, SIGNAL( connected() ), this, SLOT( cs_connected() ) );
++	QObject::connect( d->stream, SIGNAL( error(int) ), this, SLOT( streamError(int) ) );
++	QObject::connect( d->stream, SIGNAL( readyRead() ), this, SLOT( streamReadyRead() ) );
++	
++	d->stream->connectToServer( host, false );
++}
++
++void Client::cancelConnect()
++{
++	d->loginTask->reset();
++}
++
++void Client::cs_connected()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	emit connected();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " starting login task ... "<<  endl;
++
++	d->loginTask->setStateOnConnect( (d->statusOnConnect == Yahoo::StatusInvisible) ? Yahoo::StatusInvisible : Yahoo::StatusAvailable );
++	d->loginTask->go();
++	d->active = true;
++}
++
++void Client::close()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_pingTimer->stop();
++	if( d->active )
++	{
++		LogoffTask *lt = new LogoffTask( d->root );
++		lt->go( true );
++	}
++	if( d->tasksInitialized)
++		deleteTasks();	
++	d->loginTask->reset();
++	if( d->stream )
++		d->stream->deleteLater();
++	d->stream = 0L;
++	if( m_connector )
++		m_connector->deleteLater();
++	m_connector = 0L;
++}
++
++int Client::error()
++{
++	return d->error;
++}
++
++QString Client::errorString()
++{
++	return d->errorString;
++}
++
++QString Client::errorInformation()
++{
++	return d->errorInformation;
++}
++
++// SLOTS //
++void Client::streamError( int error )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "CLIENT ERROR (Error " <<  error << ")" << endl;
++	QString msg;
++
++	d->active = false;
++
++	// Examine error
++	if( error == ClientStream::ErrConnection )			// Ask Connector in this case
++	{
++		d->error = m_connector->errorCode();
++		d->errorString = KSocketBase::errorString( (KSocketBase::SocketError)d->error );
++	}
++	else
++	{
++		d->error = error;
++		d->errorString = d->stream->errorText();
++	}
++	close();
++	if( status() == Yahoo::StatusConnecting )
++		emit loginFailed();
++	else
++		emit disconnected();
++}
++
++void Client::streamReadyRead()
++{
++	// take the incoming transfer and distribute it to the task tree
++	Transfer * transfer = d->stream->read();
++	distribute( transfer );
++}
++
++void Client::lt_loginFinished()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	slotLoginResponse( d->loginTask->statusCode(), d->loginTask->statusString() );
++}
++
++void Client::slotLoginResponse( int response, const QString &msg )
++{
++	if( response == Yahoo::LoginOk )
++	{
++		if( !(d->statusOnConnect == Yahoo::StatusAvailable ||
++				d->statusOnConnect == Yahoo::StatusInvisible) ||
++				!d->statusMessageOnConnect.isEmpty() )
++			changeStatus( d->statusOnConnect, d->statusMessageOnConnect, Yahoo::StatusTypeAway );
++		d->statusMessageOnConnect = QString::null;
++		setStatus( d->statusOnConnect );
++		m_pingTimer->start( 60 * 1000 );
++		initTasks();
++	}
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Emitting loggedIn" << endl;
++	emit loggedIn( response, msg );
++}
++
++void Client::lt_gotSessionID( uint id )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Got SessionID: " << id << endl;	
++	d->sessionID = id;
++}
++
++void Client::slotGotCookies()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Y: " << d->loginTask->yCookie()
++					<< " T: " << d->loginTask->tCookie()
++					<< " C: " << d->loginTask->cCookie() << endl;
++	d->yCookie = d->loginTask->yCookie();
++	d->tCookie = d->loginTask->tCookie();
++	d->cCookie = d->loginTask->cCookie();
++}
++
++// INTERNALS //
++
++// ***** Messaging handling *****
++void Client::sendTyping( const QString &who, bool typing )
++{
++	SendNotifyTask *snt = new SendNotifyTask( d->root );
++	snt->setTarget( who );
++	snt->setState( typing ? SendNotifyTask::Active : SendNotifyTask::NotActive );
++	snt->setType( SendNotifyTask::NotifyTyping );
++	snt->go( true );
++}
++
++void Client::sendWebcamInvite( const QString &who )
++{
++	if( !d->webcamTask->transmitting() )
++		d->webcamTask->registerWebcam();
++
++	d->webcamTask->addPendingInvitation( who );
++}
++
++void Client::sendMessage( const QString &to, const QString &msg )
++{
++	SendMessageTask *smt = new SendMessageTask( d->root );
++	smt->setTarget( to );
++	smt->setText( msg );
++	smt->setPicureFlag( pictureFlag() );
++	smt->go( true );
++}
++
++void Client::setChatSessionState( const QString &to, bool close )
++{
++	ChatSessionTask *cst = new ChatSessionTask( d->root );
++	cst->setTarget( to );
++	cst->setType( close ? ChatSessionTask::UnregisterSession : ChatSessionTask::RegisterSession );
++	cst->go( true );
++}
++
++void Client::sendBuzz( const QString &to )
++{
++	SendMessageTask *smt = new SendMessageTask( d->root );
++	smt->setTarget( to );
++	smt->setText( QString::fromLatin1( "<ding>" ) );
++	smt->setPicureFlag( pictureFlag() );
++	smt->go( true );
++}
++
++void Client::sendFile( unsigned int transferId, const QString &to, const QString &msg, KURL url )
++{
++	SendFileTask *sft = new SendFileTask( d->root );
++
++	QObject::connect( sft, SIGNAL(complete(unsigned int)), SIGNAL(fileTransferComplete(unsigned int)) );
++	QObject::connect( sft, SIGNAL(bytesProcessed(unsigned int, unsigned int)), SIGNAL(fileTransferBytesProcessed(unsigned int, unsigned int)) );
++	QObject::connect( sft, SIGNAL(error(unsigned int, int, const QString &)), SIGNAL(fileTransferError(unsigned int, int, const QString &)) );
++
++	QObject::connect( this, SIGNAL(fileTransferCanceled( unsigned int )), sft, SLOT(canceled( unsigned int )) );
++
++	sft->setTarget( to );
++	sft->setMessage( msg );
++	sft->setFileUrl( url );
++	sft->setTransferId( transferId );
++	sft->go( true );
++}
++
++void Client::receiveFile( unsigned int transferId, const QString &userId, KURL remoteURL, KURL localURL )
++{
++	ReceiveFileTask *rft = new ReceiveFileTask( d->root );
++
++	QObject::connect( rft, SIGNAL(complete(unsigned int)), SIGNAL(fileTransferComplete(unsigned int)) );
++	QObject::connect( rft, SIGNAL(bytesProcessed(unsigned int, unsigned int)), SIGNAL(fileTransferBytesProcessed(unsigned int, unsigned int)) );
++	QObject::connect( rft, SIGNAL(error(unsigned int, int, const QString &)), SIGNAL(fileTransferError(unsigned int, int, const QString &)) );
++	QObject::connect( this, SIGNAL(fileTransferCanceled( unsigned int )), rft, SLOT(canceled( unsigned int )) );
++
++	rft->setRemoteUrl( remoteURL );
++	rft->setLocalUrl( localURL );
++	rft->setTransferId( transferId );
++	rft->setUserId( userId );
++	if( remoteURL.url().startsWith( "http://" ) )
++		rft->setType( ReceiveFileTask::FileTransferAccept );
++	else
++		rft->setType( ReceiveFileTask::FileTransfer7Accept );
++	rft->go( true );
++}
++
++void Client::rejectFile( const QString &userId, KURL remoteURL )
++{
++	if( remoteURL.url().startsWith( "http://" ) )
++		return;
++
++	ReceiveFileTask *rft = new ReceiveFileTask( d->root );
++
++	rft->setRemoteUrl( remoteURL );
++	rft->setUserId( userId );
++	rft->setType( ReceiveFileTask::FileTransfer7Reject );
++	rft->go( true );
++}
++
++void Client::cancelFileTransfer( unsigned int transferId )
++{
++	emit fileTransferCanceled( transferId );
++}
++
++void Client::changeStatus( Yahoo::Status status, const QString &message, Yahoo::StatusType type )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "status: " << status
++					<< " message: " << message
++					<< " type: " << type << endl;	
++	ChangeStatusTask *cst = new ChangeStatusTask( d->root );
++	cst->setStatus( status );
++	cst->setMessage( message );
++	cst->setType( type );
++	cst->go( true );
++	
++	if( status == Yahoo::StatusInvisible )
++		stealthContact( QString::null, Yahoo::StealthOnline, Yahoo::StealthClear );
++
++	setStatus( status );
++}
++
++void Client::sendAuthReply( const QString &userId, bool accept, const QString &msg )
++{
++	SendAuthRespTask *sarp = new SendAuthRespTask( d->root );
++	sarp->setGranted( accept );
++	sarp->setTarget( userId );
++	sarp->setMessage( msg );
++	sarp->go( true );
++}
++
++void Client::sendPing()
++{
++	if( !d->active )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Disconnected. NOT sending a PING." << endl;
++		return;
++	}
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Sending a PING." << endl;
++	PingTask *pt = new PingTask( d->root );
++	pt->go( true );
++}
++
++// ***** Contactlist handling *****
++
++void Client::stealthContact(QString const &userId, Yahoo::StealthMode mode, Yahoo::StealthStatus state)
++{
++	StealthTask *st = new StealthTask( d->root );
++	st->setTarget( userId );
++	st->setState( state );
++	st->setMode( mode );
++	st->go( true );
++}
++
++void Client::addBuddy( const QString &userId, const QString &group, const QString &message )
++{
++	ModifyBuddyTask *mbt = new ModifyBuddyTask( d->root );
++	mbt->setType( ModifyBuddyTask::AddBuddy );
++	mbt->setTarget( userId );
++	mbt->setGroup( group );
++	mbt->setMessage( message );
++	mbt->go( true );
++}
++
++void Client::removeBuddy( const QString &userId, const QString &group )
++{
++	ModifyBuddyTask *mbt = new ModifyBuddyTask( d->root );
++	mbt->setType( ModifyBuddyTask::RemoveBuddy );
++	mbt->setTarget( userId );
++	mbt->setGroup( group );
++	mbt->go( true );
++}
++
++void Client::moveBuddy( const QString &userId, const QString &oldGroup, const QString &newGroup )
++{
++	ModifyBuddyTask *mbt = new ModifyBuddyTask( d->root );
++	mbt->setType( ModifyBuddyTask::MoveBuddy );
++	mbt->setTarget( userId );
++	mbt->setOldGroup( oldGroup );
++	mbt->setGroup( newGroup );
++	mbt->go( true );
++}
++
++// ***** Buddyicon handling *****
++
++void Client::requestPicture( const QString &userId )
++{
++	RequestPictureTask *rpt = new RequestPictureTask( d->root );
++	rpt->setTarget( userId );
++	rpt->go( true );
++}
++
++void Client::downloadPicture(  const QString &userId, KURL url, int checksum )
++{
++	if( !d->iconLoader )
++	{
++		d->iconLoader = new YahooBuddyIconLoader( this );
++		QObject::connect( d->iconLoader, SIGNAL(fetchedBuddyIcon(const QString&, KTempFile*, int )),
++				SIGNAL(pictureDownloaded(const QString&, KTempFile*,  int ) ) );
++	}
++
++	d->iconLoader->fetchBuddyIcon( QString(userId), KURL(url), checksum );
++}
++
++void Client::uploadPicture( KURL url )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "URL: " << url.url() << endl;
++	SendPictureTask *spt = new SendPictureTask( d->root );
++	spt->setType( SendPictureTask::UploadPicture );
++	spt->setFilename( url.fileName() );
++	if ( url.isLocalFile() )
++		spt->setPath( url.path() );
++	else
++		spt->setPath( url.url() );
++	d->pictureFlag = 2;
++	spt->go( true );
++}
++
++void Client::sendPictureChecksum( int checksum, const QString &who )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "checksum: " << checksum << endl;
++	SendPictureTask *spt = new SendPictureTask( d->root );
++	spt->setType( SendPictureTask::SendChecksum );
++	spt->setChecksum( checksum );
++	if( !who.isEmpty() )
++		spt->setTarget( who );
++	spt->go( true );	
++}
++
++void Client::sendPictureInformation( const QString &userId, const QString &url, int checksum )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "checksum: " << checksum << endl;
++	SendPictureTask *spt = new SendPictureTask( d->root );
++	spt->setType( SendPictureTask::SendInformation );
++	spt->setChecksum( checksum );
++	spt->setUrl( url );
++	spt->setTarget( userId );
++	spt->go( true );
++}
++
++void Client::sendPictureStatusUpdate( const QString &userId, int type )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Setting PictureStatus to: " << type << endl;
++	SendPictureTask *spt = new SendPictureTask( d->root );
++	spt->setType( SendPictureTask::SendStatus );
++	spt->setStatus( type );
++	spt->setTarget( userId );
++	spt->go( true );
++}
++
++// ***** Webcam handling *****
++
++void Client::requestWebcam( const QString &userId )
++{
++	d->webcamTask->requestWebcam( userId );
++}
++
++void Client::closeWebcam( const QString &userId )
++{
++	d->webcamTask->closeWebcam( userId );
++}
++
++void Client::sendWebcamImage( const QByteArray &ar )
++{
++	d->webcamTask->sendWebcamImage( ar );
++}
++
++void Client::closeOutgoingWebcam()
++{
++	d->webcamTask->closeOutgoingWebcam();
++}
++
++
++void Client::grantWebcamAccess( const QString &userId )
++{
++	d->webcamTask->grantAccess( userId );
++}
++
++// ***** Conferences *****
++void Client::inviteConference( const QString &room, const QStringList &members, const QString &msg )
++{
++	d->conferenceTask->inviteConference( room, members, msg );
++}
++
++void Client::addInviteConference( const QString &room, const QStringList &who, const QStringList &members, const QString &msg )
++{
++	d->conferenceTask->addInvite( room, who, members, msg );
++}
++
++void Client::joinConference( const QString &room, const QStringList &members )
++{
++	d->conferenceTask->joinConference( room, members );
++}
++
++void Client::declineConference( const QString &room, const QStringList &members, const QString &msg )
++{
++	d->conferenceTask->declineConference( room, members, msg );
++}
++
++void Client::leaveConference( const QString &room, const QStringList &members )
++{
++	d->conferenceTask->leaveConference( room, members );
++}
++
++void Client::sendConferenceMessage( const QString &room, const QStringList &members, const QString &msg )
++{
++	d->conferenceTask->sendMessage( room, members, msg );
++}
++
++// ***** YAB *****
++void Client::getYABEntries( long lastMerge, long lastRemoteRevision )
++{
++	d->yabTask->getAllEntries( lastMerge, lastRemoteRevision);
++}
++
++void Client::saveYABEntry( YABEntry &entry )
++{
++	ModifyYABTask *myt = new ModifyYABTask( d->root );
++	myt->setAction( ModifyYABTask::EditEntry );
++	myt->setEntry( entry );
++	QObject::connect( myt, SIGNAL(gotEntry( YABEntry * )), this, SIGNAL( gotYABEntry( YABEntry * ) ) );
++	QObject::connect( myt, SIGNAL(error( YABEntry *, const QString &)), this, SIGNAL(modifyYABEntryError( YABEntry *, const QString & )));
++	myt->go(true);
++}
++
++void Client::addYABEntry(  YABEntry &entry )
++{
++	ModifyYABTask *myt = new ModifyYABTask( d->root );
++	myt->setAction( ModifyYABTask::AddEntry );
++	myt->setEntry( entry );
++	QObject::connect( myt, SIGNAL(gotEntry( YABEntry * )), this, SIGNAL( gotYABEntry( YABEntry * ) ) );
++	QObject::connect( myt, SIGNAL(error( YABEntry *, const QString &)), this, SIGNAL(modifyYABEntryError( YABEntry *, const QString & )));
++	myt->go(true);
++}
++
++void Client::deleteYABEntry(  YABEntry &entry )
++{
++	ModifyYABTask *myt = new ModifyYABTask( d->root );
++	myt->setAction( ModifyYABTask::DeleteEntry );
++	myt->setEntry( entry );
++	myt->go(true);
++}
++
++// ***** other *****
++void Client::notifyError( const QString &info, const QString & errorString, LogLevel level )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << QString::fromLatin1("\nThe following error occured: %1\n    Reason: %2\n    LogLevel: %3")
++		.arg(info).arg(errorString).arg(level) << endl;
++	d->errorString = errorString;
++	d->errorInformation = info;
++	emit error( level );
++}
++
++QString Client::userId()
++{
++	return d->user;
++}
++
++void Client::setUserId( const QString & userId )
++{
++	d->user = userId;
++}
++
++Yahoo::Status Client::status()
++{
++	return d->status;
++}
++
++void Client::setStatus( Yahoo::Status status )
++{
++	d->status = status;
++}
++
++
++void Client::setStatusOnConnect( Yahoo::Status status )
++{
++	d->statusOnConnect = status;
++}
++
++void Client::setStatusMessageOnConnect( const QString &msg )
++{
++	d->statusMessageOnConnect = msg;
++}
++
++void Client::setVerificationWord( const QString &word )
++{
++	d->loginTask->setVerificationWord( word );
++}
++
++QString Client::password()
++{
++	return d->pass;
++}
++
++QCString Client::ipAddress()
++{
++	//TODO determine ip address
++	return "127.0.0.1";
++}
++
++QString Client::host()
++{
++	return d->host;
++}
++
++int Client::port()
++{
++	return d->port;
++}
++
++uint Client::sessionID()
++{
++	return d->sessionID;
++}
++
++int Client::pictureFlag()
++{
++	return d->pictureFlag;
++}
++
++QString Client::yCookie()
++{
++	return d->yCookie;
++}
++
++QString Client::tCookie()
++{
++	return d->tCookie;
++}
++
++QString Client::cCookie()
++{
++	return d->cCookie;
++}
++
++void Client::distribute( Transfer * transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	if( !rootTask()->take( transfer ) )
++		kdDebug(YAHOO_RAW_DEBUG) << "CLIENT: root task refused transfer" << endl;
++	delete transfer;
++}
++
++void Client::send( Transfer* request )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << "CLIENT::send()"<< endl;
++	if( !d->stream )
++	{	
++		kdDebug(YAHOO_RAW_DEBUG) << "CLIENT - NO STREAM TO SEND ON!" << endl;
++		return;
++	}
++
++	d->stream->write( request );
++}
++
++void Client::debug(const QString &str)
++{
++	qDebug( "CLIENT: %s", str.ascii() );
++}
++
++Task * Client::rootTask()
++{
++	return d->root;
++}
++
++void Client::initTasks()
++{
++	if( d->tasksInitialized )
++		return;
++
++	d->statusTask = new StatusNotifierTask( d->root );
++	QObject::connect( d->statusTask, SIGNAL( statusChanged( const QString&, int, const QString&, int, int ) ), 
++				SIGNAL( statusChanged( const QString&, int, const QString&, int, int ) ) );
++	QObject::connect( d->statusTask, SIGNAL( stealthStatusChanged( const QString&, Yahoo::StealthStatus ) ), 
++				SIGNAL( stealthStatusChanged( const QString&, Yahoo::StealthStatus ) ) );
++	QObject::connect( d->statusTask, SIGNAL( loginResponse( int, const QString& ) ), 
++				SIGNAL( loggedIn( int, const QString& ) ) );
++	QObject::connect( d->statusTask, SIGNAL( authorizationRejected( const QString&, const QString& ) ), 
++				SIGNAL( authorizationRejected( const QString&, const QString& ) ) );
++	QObject::connect( d->statusTask, SIGNAL( authorizationAccepted( const QString& ) ), 
++				SIGNAL( authorizationAccepted( const QString& ) ) );
++	QObject::connect( d->statusTask, SIGNAL( gotAuthorizationRequest( const QString &, const QString &, const QString & ) ), 
++				SIGNAL( gotAuthorizationRequest( const QString &, const QString &, const QString & ) ) );
++
++	d->mailTask = new MailNotifierTask( d->root );
++	QObject::connect( d->mailTask, SIGNAL( mailNotify(const QString&, const QString&, int) ), 
++				SIGNAL( mailNotify(const QString&, const QString&, int) ) );
++
++	d->messageReceiverTask = new MessageReceiverTask( d->root );
++	QObject::connect( d->messageReceiverTask, SIGNAL( gotIm(const QString&, const QString&, long, int) ),
++				SIGNAL( gotIm(const QString&, const QString&, long, int) ) );
++	QObject::connect( d->messageReceiverTask, SIGNAL( systemMessage(const QString&) ),
++				SIGNAL( systemMessage(const QString&) ) );
++	QObject::connect( d->messageReceiverTask, SIGNAL( gotTypingNotify(const QString &, int) ),
++				SIGNAL( typingNotify(const QString &, int) ) );
++	QObject::connect( d->messageReceiverTask, SIGNAL( gotBuzz( const QString &, long ) ),
++				SIGNAL( gotBuzz( const QString &, long ) ) );
++	QObject::connect( d->messageReceiverTask, SIGNAL( gotWebcamInvite(const QString &) ),
++				SIGNAL( gotWebcamInvite(const QString &) ) );
++
++	d->pictureNotifierTask = new PictureNotifierTask( d->root );
++	QObject::connect( d->pictureNotifierTask, SIGNAL( pictureStatusNotify( const QString &, int ) ),
++				SIGNAL( pictureStatusNotify( const QString &, int ) ) );
++	QObject::connect( d->pictureNotifierTask, SIGNAL( pictureChecksumNotify( const QString &, int ) ),
++				SIGNAL( pictureChecksumNotify( const QString &, int ) ) );
++	QObject::connect( d->pictureNotifierTask, SIGNAL( pictureInfoNotify( const QString &, KURL, int ) ),
++				SIGNAL( pictureInfoNotify( const QString &, KURL, int ) ) );
++	QObject::connect( d->pictureNotifierTask, SIGNAL( pictureRequest( const QString & ) ),
++				SIGNAL( pictureRequest( const QString & ) ) );
++	QObject::connect( d->pictureNotifierTask, SIGNAL( pictureUploaded( const QString & ) ),
++				SIGNAL( pictureUploaded( const QString & ) ) );
++
++	d->webcamTask = new WebcamTask( d->root );
++	QObject::connect( d->webcamTask, SIGNAL( webcamImageReceived( const QString &, const QPixmap &) ),
++				SIGNAL( webcamImageReceived( const QString &, const QPixmap &) ) );
++	QObject::connect( d->webcamTask, SIGNAL( webcamNotAvailable( const QString & ) ),
++				SIGNAL( webcamNotAvailable( const QString & ) ) );
++	QObject::connect( d->webcamTask, SIGNAL( webcamClosed( const QString &, int ) ),
++				SIGNAL( webcamClosed( const QString &, int ) ) );
++	QObject::connect( d->webcamTask, SIGNAL( webcamPaused(const QString&) ),
++				SIGNAL( webcamPaused(const QString&) ) );
++	QObject::connect( d->webcamTask, SIGNAL( readyForTransmission() ),
++				SIGNAL( webcamReadyForTransmission() ) );
++	QObject::connect( d->webcamTask, SIGNAL( stopTransmission() ),
++				SIGNAL( webcamStopTransmission() ) );
++	QObject::connect( d->webcamTask, SIGNAL( viewerJoined( const QString &) ),
++				SIGNAL( webcamViewerJoined( const QString &) ) );
++	QObject::connect( d->webcamTask, SIGNAL( viewerLeft( const QString &) ),
++				SIGNAL( webcamViewerLeft( const QString &) ) );
++	QObject::connect( d->webcamTask, SIGNAL( viewerRequest( const QString &) ),
++				SIGNAL( webcamViewerRequest( const QString &) ) );
++
++	d->conferenceTask = new ConferenceTask( d->root );
++	QObject::connect( d->conferenceTask, SIGNAL( gotInvite( const QString &, const QString &, const QString &, const QStringList & ) ),
++				SIGNAL( gotConferenceInvite( const QString &, const QString &, const QString &, const QStringList & ) ) );
++	QObject::connect( d->conferenceTask, SIGNAL( gotMessage( const QString &, const QString &, const QString & ) ),
++				SIGNAL( gotConferenceMessage( const QString &, const QString &, const QString & ) ) );
++	QObject::connect( d->conferenceTask, SIGNAL( userJoined( const QString &, const QString & ) ),
++				SIGNAL( confUserJoined( const QString &, const QString & ) ) );
++	QObject::connect( d->conferenceTask, SIGNAL( userLeft( const QString &, const QString & ) ),
++				SIGNAL( confUserLeft( const QString &, const QString & ) ) );
++	QObject::connect( d->conferenceTask, SIGNAL( userDeclined( const QString &, const QString &, const QString & ) ),
++				SIGNAL( confUserDeclined( const QString &, const QString &, const QString & ) ) );
++
++	d->yabTask = new YABTask( d->root );
++	QObject::connect( d->yabTask, SIGNAL( gotEntry( YABEntry * ) ),
++				SIGNAL( gotYABEntry( YABEntry * ) ) );
++	QObject::connect( d->yabTask, SIGNAL( gotRevision( long, bool ) ),
++				SIGNAL( gotYABRevision( long, bool ) ) );
++
++	d->fileTransferTask = new FileTransferNotifierTask( d->root );
++	QObject::connect( d->fileTransferTask, SIGNAL(incomingFileTransfer( const QString &, const QString &, 
++					long, const QString &, const QString &, unsigned long )),
++				SIGNAL(incomingFileTransfer( const QString &, const QString &, 
++					long, const QString &, const QString &, unsigned long )) );
++}
++
++void Client::deleteTasks()
++{
++	d->tasksInitialized = false;
++	d->statusTask->deleteLater();
++	d->statusTask = 0L;
++	d->mailTask->deleteLater();
++	d->mailTask = 0L;
++	d->messageReceiverTask->deleteLater();
++	d->messageReceiverTask = 0L;
++	d->pictureNotifierTask->deleteLater();
++	d->pictureNotifierTask = 0L;
++	d->webcamTask->deleteLater();
++	d->webcamTask = 0L;
++	d->conferenceTask->deleteLater();
++	d->conferenceTask = 0L;
++	d->yabTask->deleteLater();
++	d->yabTask = 0L;
++	d->fileTransferTask->deleteLater();
++	d->fileTransferTask = 0;
++}
++
++#include "client.moc"
+--- kopete/protocols/yahoo/libkyahoo/bytestream.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/bytestream.cpp	(revision 586398)
+@@ -0,0 +1,289 @@
++/*
++ * bytestream.cpp - base class for bytestreams
++ * Copyright (C) 2003  Justin Karneges
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <kdebug.h>
++#include"bytestream.h"
++
++// CS_NAMESPACE_BEGIN
++
++//! \class ByteStream bytestream.h
++//! \brief Base class for "bytestreams"
++//! 
++//! This class provides a basic framework for a "bytestream", here defined
++//! as a bi-directional, asynchronous pipe of data.  It can be used to create
++//! several different kinds of bytestream-applications, such as a console or
++//! TCP connection, or something more abstract like a security layer or tunnel,
++//! all with the same interface.  The provided functions make creating such
++//! classes simpler.  ByteStream is a pure-virtual class, so you do not use it
++//! on its own, but instead through a subclass such as \a BSocket.
++//!
++//! The signals connectionClosed(), delayedCloseFinished(), readyRead(),
++//! bytesWritten(), and error() serve the exact same function as those from
++//! <A HREF="http://doc.trolltech.com/3.1/qsocket.html">QSocket</A>.
++//!
++//! The simplest way to create a ByteStream is to reimplement isOpen(), close(),
++//! and tryWrite().  Call appendRead() whenever you want to make data available for
++//! reading.  ByteStream will take care of the buffers with regards to the caller,
++//! and will call tryWrite() when the write buffer gains data.  It will be your
++//! job to call tryWrite() whenever it is acceptable to write more data to
++//! the underlying system.
++//!
++//! If you need more advanced control, reimplement read(), write(), bytesAvailable(),
++//! and/or bytesToWrite() as necessary.
++//!
++//! Use appendRead(), appendWrite(), takeRead(), and takeWrite() to modify the
++//! buffers.  If you have more advanced requirements, the buffers can be accessed
++//! directly with readBuf() and writeBuf().
++//!
++//! Also available are the static convenience functions ByteStream::appendArray()
++//! and ByteStream::takeArray(), which make dealing with byte queues very easy.
++
++class ByteStream::Private
++{
++public:
++	Private() {}
++
++	QByteArray readBuf, writeBuf;
++};
++
++//!
++//! Constructs a ByteStream object with parent \a parent.
++ByteStream::ByteStream(QObject *parent)
++:QObject(parent)
++{
++// 	kdDebug(14181) << k_funcinfo << endl;
++	d = new Private;
++}
++
++//!
++//! Destroys the object and frees allocated resources.
++ByteStream::~ByteStream()
++{
++	delete d;
++}
++
++//!
++//! Returns TRUE if the stream is open, meaning that you can write to it.
++bool ByteStream::isOpen() const
++{
++	return false;
++}
++
++//!
++//! Closes the stream.  If there is data in the write buffer then it will be
++//! written before actually closing the stream.  Once all data has been written,
++//! the delayedCloseFinished() signal will be emitted.
++//! \sa delayedCloseFinished()
++void ByteStream::close()
++{
++}
++
++//!
++//! Writes array \a a to the stream.
++void ByteStream::write(const QByteArray &a)
++{
++// 	kdDebug(14181) << k_funcinfo << "[data size: " << a.size() << "]" << endl;
++	
++// 	kdDebug(14181) << k_funcinfo << "[Data: " << a << "]" << endl;
++	
++	if(!isOpen())
++		return;
++
++	bool doWrite = bytesToWrite() == 0 ? true: false;
++	appendWrite(a);
++	if(doWrite)
++		tryWrite();
++}
++
++//!
++//! Reads bytes \a bytes of data from the stream and returns them as an array.  If \a bytes is 0, then
++//! \a read will return all available data.
++QByteArray ByteStream::read(int bytes)
++{
++// 	kdDebug(14181) << k_funcinfo << " " << bytes <<" [bytes]"<< endl;
++	return takeRead(bytes);
++}
++
++//!
++//! Returns the number of bytes available for reading.
++int ByteStream::bytesAvailable() const
++{
++	return d->readBuf.size();
++}
++
++//!
++//! Returns the number of bytes that are waiting to be written.
++int ByteStream::bytesToWrite() const
++{
++// 	kdDebug(14181) << k_funcinfo << "[bytes left: " <<  d->writeBuf.size() << " ]" << endl;
++	return d->writeBuf.size();
++}
++
++//!
++//! Writes string \a cs to the stream.
++void ByteStream::write(const QCString &cs)
++{
++// 	kdDebug(14181) << k_funcinfo << "[data size: " << cs.length() << "]" << endl;
++	
++	QByteArray block(cs.length());
++	memcpy(block.data(), cs.data(), block.size());
++	write(block);
++}
++
++//!
++//! Clears the read buffer.
++void ByteStream::clearReadBuffer()
++{
++	d->readBuf.resize(0);
++}
++
++//!
++//! Clears the write buffer.
++void ByteStream::clearWriteBuffer()
++{
++	d->writeBuf.resize(0);
++}
++
++//!
++//! Appends \a block to the end of the read buffer.
++void ByteStream::appendRead(const QByteArray &block)
++{
++// 	kdDebug(14181) << k_funcinfo << endl;
++	appendArray(&d->readBuf, block);
++}
++
++//!
++//! Appends \a block to the end of the write buffer.
++void ByteStream::appendWrite(const QByteArray &block)
++{
++// 	kdDebug(14181) << k_funcinfo << "[data size: " << block.size() << "]" << endl;
++	
++	appendArray(&d->writeBuf, block);
++}
++
++//!
++//! Returns \a size bytes from the start of the read buffer.
++//! If \a size is 0, then all available data will be returned.
++//! If \a del is TRUE, then the bytes are also removed.
++QByteArray ByteStream::takeRead(int size, bool del)
++{
++// 	kdDebug(14181) << k_funcinfo << "[data size: " << size << "][ delete :" << del << " ]" << endl;
++	return takeArray(&d->readBuf, size, del);
++}
++
++//!
++//! Returns \a size bytes from the start of the write buffer.
++//! If \a size is 0, then all available data will be returned.
++//! If \a del is TRUE, then the bytes are also removed.
++QByteArray ByteStream::takeWrite(int size, bool del)
++{
++// 	kdDebug(14181) << k_funcinfo << "[data size: " << size << "][ delete :" << del << " ]" << endl;
++	return takeArray(&d->writeBuf, size, del);
++}
++
++//!
++//! Returns a reference to the read buffer.
++QByteArray & ByteStream::readBuf()
++{
++	return d->readBuf;
++}
++
++//!
++//! Returns a reference to the write buffer.
++QByteArray & ByteStream::writeBuf()
++{
++// 	kdDebug(14181) << k_funcinfo << endl;
++	return d->writeBuf;
++}
++
++//!
++//! Attempts to try and write some bytes from the write buffer, and returns the number
++//! successfully written or -1 on error.  The default implementation returns -1.
++int ByteStream::tryWrite()
++{
++// 	kdDebug(14181) << k_funcinfo << "(THIS RETURNS -1)" << endl;
++	return -1;
++}
++
++//!
++//! Append array \a b to the end of the array pointed to by \a a.
++void ByteStream::appendArray(QByteArray *a, const QByteArray &b)
++{
++// 	kdDebug(14181) << k_funcinfo << endl;
++	int oldsize = a->size();
++	a->resize(oldsize + b.size());
++	memcpy(a->data() + oldsize, b.data(), b.size());
++}
++
++//!
++//! Returns \a size bytes from the start of the array pointed to by \a from.
++//! If \a size is 0, then all available data will be returned.
++//! If \a del is TRUE, then the bytes are also removed.
++QByteArray ByteStream::takeArray(QByteArray *from, int size, bool del)
++{
++// 	kdDebug(14181) << k_funcinfo << "[int size] : " << size << " [bool del] " << del << endl;
++	
++	QByteArray a;
++	if(size == 0) {
++		a = from->copy();
++		if(del)
++			from->resize(0);
++	}
++	else {
++		if(size > (int)from->size())
++			size = from->size();
++		a.resize(size);
++		char *r = from->data();
++		memcpy(a.data(), r, size);
++		if(del) {
++			int newsize = from->size()-size;
++			memmove(r, r+size, newsize);
++			from->resize(newsize);
++		}
++	}
++	return a;
++}
++	void connectionClosed();
++	void delayedCloseFinished();
++	void readyRead();
++	void bytesWritten(int);
++	void error(int);
++
++//! \fn void ByteStream::connectionClosed()
++//! This signal is emitted when the remote end of the stream closes.
++
++//! \fn void ByteStream::delayedCloseFinished()
++//! This signal is emitted when all pending data has been written to the stream
++//! after an attempt to close.
++
++//! \fn void ByteStream::readyRead()
++//! This signal is emitted when data is available to be read.
++
++//! \fn void ByteStream::bytesWritten(int x);
++//! This signal is emitted when data has been successfully written to the stream.
++//! \a x is the number of bytes written.
++
++//! \fn void ByteStream::error(int code)
++//! This signal is emitted when an error occurs in the stream.  The reason for
++//! error is indicated by \a code.
++
++// CS_NAMESPACE_END
++
++#include "bytestream.moc"
+--- kopete/protocols/yahoo/libkyahoo/inputprotocolbase.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/inputprotocolbase.h	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++    Kopete Groupwise Protocol
++    inputprotocolbase.h - Ancestor of all protocols used for reading GroupWise input
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef INPUTPROTOCOLBASE_H
++#define INPUTPROTOCOLBASE_H
++
++#include <qobject.h>
++
++class Transfer;
++/**
++Defines a basic interface for protocols dealing with input from the GroupWise server.
++
++ at author Kopete Developers
++*/
++class InputProtocolBase : public QObject
++{
++Q_OBJECT
++public:
++	enum EventProtocolState { Success, NeedMore, OutOfSync, ProtocolError };
++	InputProtocolBase(QObject *parent = 0, const char *name = 0);
++	~InputProtocolBase();
++	/**
++	 * Returns a value describing the state of the object.  
++	 * If the object is given data to parse that does not begin with a recognised event code, 
++	 * it will become OutOfSync, to indicate that the input data probably contains leftover data not processed during a previous parse.
++	 */
++	uint state() const;
++	/**
++	 * Attempt to parse the supplied data into a Transfer object
++	 * @param bytes this will be set to the number of bytes that were successfully parsed.  It is no indication of the success of the whole procedure
++	 * @return On success, a Transfer object that the caller is responsible for deleting.  It will be either an EventTransfer or a Response, delete as appropriate.  On failure, returns 0.
++	 */
++	virtual Transfer * parse( const QByteArray &, uint & bytes ) = 0 ;
++protected:
++	/**
++	 * Reads an arbitrary string
++	 * updates the bytes parsed counter
++	 */
++	bool readString( QString &message );
++	/**
++	 * Check that there is data to read, and set the protocol's state if there isn't any.
++	 */
++	bool okToProceed();
++	/** 
++	 * read a Q_UINT32 giving the number of following bytes, then a string of that length
++	 * updates the bytes parsed counter
++	 * @return false if the string was broken or there was no data available at all
++	 */
++	bool safeReadBytes( QCString & data, uint & len );
++	
++protected:
++	uint m_state;
++	uint m_bytes;
++	QDataStream * m_din;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/webcamtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/webcamtask.cpp	(revision 586398)
+@@ -0,0 +1,685 @@
++/*
++    Kopete Yahoo Protocol
++    Handles incoming webcam connections
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "webcamtask.h"
++#include "sendnotifytask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qbuffer.h>
++#include <qfile.h>
++#include <qtimer.h>
++#include <ktempfile.h>
++#include <kprocess.h>
++#include <kstreamsocket.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++using namespace KNetwork;
++
++WebcamTask::WebcamTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	transmittingData = false;
++	transmissionPending = false;
++	timestamp = 1;
++}
++
++WebcamTask::~WebcamTask()
++{
++}
++
++bool WebcamTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = static_cast<YMSGTransfer*>(transfer);
++	
++ 	if( t->service() == Yahoo::ServiceWebcam )
++ 		parseWebcamInformation( t );
++// 	else
++// 		parseMessage( transfer );
++
++	return true;
++}
++
++bool WebcamTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	if ( t->service() == Yahoo::ServiceWebcam )	
++		return true;
++	else
++		return false;
++}
++
++void WebcamTask::requestWebcam( const QString &who )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceWebcam);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit());
++	t->setParam( 5, who.local8Bit() );
++	keyPending = who;
++
++	send( t );
++}
++
++void WebcamTask::parseWebcamInformation( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YahooWebcamInformation info;
++	info.sender = keyPending;
++	info.server = t->firstParam( 102 );
++	info.key = t->firstParam( 61 );
++	info.status = InitialStatus;
++	info.dataLength = 0;
++	info.buffer = 0L;
++	info.headerRead = false;
++	if( info.sender == client()->userId() )
++	{
++		transmittingData = true;
++		info.direction = Outgoing;
++	}
++	else
++		info.direction = Incoming;
++	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Got WebcamInformation: Sender: " << info.sender << " Server: " << info.server << " Key: " << info.key << endl;
++
++	KStreamSocket *socket = new KStreamSocket( info.server, QString::number(5100) );
++	socketMap[socket] = info;
++	socket->enableRead( true );
++	connect( socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotConnectionStage1Established() ) );
++	connect( socket, SIGNAL( gotError(int) ), this, SLOT( slotConnectionFailed(int) ) );
++	connect( socket, SIGNAL( readyRead() ), this, SLOT( slotRead() ) );
++	
++	socket->connect();	
++}
++
++void WebcamTask::slotConnectionStage1Established()
++{
++	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
++	if( !socket )
++		return;
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Webcam connection Stage1 to the user " << socketMap[socket].sender << " established." << endl;
++	disconnect( socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotConnectionStage1Established() ) );
++	disconnect( socket, SIGNAL( gotError(int) ), this, SLOT( slotConnectionFailed(int) ) );
++	socketMap[socket].status = ConnectedStage1;
++	
++
++	QByteArray buffer;
++	QDataStream stream( buffer, IO_WriteOnly );
++	QString s;
++	if( socketMap[socket].direction == Incoming )
++	{
++		socket->writeBlock( QCString("<RVWCFG>").data(), 8 );
++		s = QString("g=%1\r\n").arg(socketMap[socket].sender);
++	}
++	else
++	{
++		socket->writeBlock( QCString("<RUPCFG>").data(), 8 );
++		s = QString("f=1\r\n");
++	}
++
++	// Header: 08 00 01 00 00 00 00	
++	stream << (Q_INT8)0x08 << (Q_INT8)0x00 << (Q_INT8)0x01 << (Q_INT8)0x00 << (Q_INT32)s.length();
++	stream.writeRawBytes( s.local8Bit(), s.length() );
++	
++	socket->writeBlock( buffer.data(), buffer.size() );
++}
++
++void WebcamTask::slotConnectionStage2Established()
++{
++	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
++	if( !socket )
++		return;
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Webcam connection Stage2 to the user " << socketMap[socket].sender << " established." << endl;
++	disconnect( socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotConnectionStage2Established() ) );
++	disconnect( socket, SIGNAL( gotError(int) ), this, SLOT( slotConnectionFailed(int) ) );
++	socketMap[socket].status = ConnectedStage2;
++
++	QByteArray buffer;
++	QDataStream stream( buffer, IO_WriteOnly );
++	QString s;
++
++
++	if( socketMap[socket].direction == Incoming )
++	{
++		// Send <REQIMG>-Packet
++		socket->writeBlock( QCString("<REQIMG>").data(), 8 );
++		// Send request information
++		s = QString("a=2\r\nc=us\r\ne=21\r\nu=%1\r\nt=%2\r\ni=\r\ng=%3\r\no=w-2-5-1\r\np=1")
++			.arg(client()->userId()).arg(socketMap[socket].key).arg(socketMap[socket].sender);
++		// Header: 08 00 01 00 00 00 00	
++		stream << (Q_INT8)0x08 << (Q_INT8)0x00 << (Q_INT8)0x01 << (Q_INT8)0x00 << (Q_INT32)s.length();
++	}
++	else
++	{
++		// Send <REQIMG>-Packet
++		socket->writeBlock( QCString("<SNDIMG>").data(), 8 );
++		// Send request information
++		s = QString("a=2\r\nc=us\r\nu=%1\r\nt=%2\r\ni=%3\r\no=w-2-5-1\r\np=2\r\nb=KopeteWebcam\r\nd=\r\n")
++		.arg(client()->userId()).arg(socketMap[socket].key).arg(socket->localAddress().nodeName());
++		// Header: 08 00 05 00 00 00 00	01 00 00 00 01
++		stream << (Q_INT8)0x0d << (Q_INT8)0x00 << (Q_INT8)0x05 << (Q_INT8)0x00 << (Q_INT32)s.length()
++			<< (Q_INT8)0x01 << (Q_INT8)0x00 << (Q_INT8)0x00 << (Q_INT8)0x00 << (Q_INT8)0x01;
++	}
++	socket->writeBlock( buffer.data(), buffer.size() );
++	socket->writeBlock( s.local8Bit(), s.length() );
++}
++
++void WebcamTask::slotConnectionFailed( int error )
++{
++	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
++	client()->notifyError( i18n("Webcam connection to the user %1 could not be established.\n\nPlease relogin and try again.")
++			.arg(socketMap[socket].sender), QString("%1 - %2").arg(error).arg( socket->errorString()), Client::Error );
++	socketMap.remove( socket );
++	socket->deleteLater();
++}
++
++void WebcamTask::slotRead()
++{
++	KStreamSocket* socket = const_cast<KStreamSocket*>( dynamic_cast<const KStreamSocket*>( sender() ) );
++	if( !socket )
++		return;
++	
++	switch( socketMap[socket].status )
++	{
++		case ConnectedStage1:
++			disconnect( socket, SIGNAL( readyRead() ), this, SLOT( slotRead() ) );
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Connected into stage 1" << endl;
++			connectStage2( socket );
++		break;
++		case ConnectedStage2:
++		case Sending:
++		case SendingEmpty:
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Connected into stage 2" << endl;
++			processData( socket );
++		default:
++		break;
++	}
++}
++
++void WebcamTask::connectStage2( KStreamSocket *socket )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	QByteArray data( socket->bytesAvailable() );
++	socket->readBlock ( data.data (), data.size () );
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Magic Byte:" << data[2] << endl;
++
++	socketMap[socket].status = ConnectedStage2;
++
++	QString server;
++	int i = 4;
++	KStreamSocket *newSocket;
++	switch( (const char)data[2] )
++	{
++	case (Q_INT8)0x06:
++		emit webcamNotAvailable(socketMap[socket].sender);
++		break;
++	case (Q_INT8)0x04:
++	case (Q_INT8)0x07:
++		while( (const char)data[i] != (Q_INT8)0x00 )
++			server += data[i++];
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Server:" << server << endl;
++		if( server.isEmpty() )
++		{
++			emit webcamNotAvailable(socketMap[socket].sender);
++			break;
++		}
++		
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Connecting to " << server << endl;
++		newSocket = new KStreamSocket( server, QString::number(5100) );
++		socketMap[newSocket] = socketMap[socket];
++		newSocket->enableRead( true );
++		connect( newSocket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( slotConnectionStage2Established() ) );
++		connect( newSocket, SIGNAL( gotError(int) ), this, SLOT( slotConnectionFailed(int) ) );
++		connect( newSocket, SIGNAL( readyRead() ), this, SLOT( slotRead() ) );
++		if( socketMap[newSocket].direction == Outgoing )
++		{
++			newSocket->enableWrite( true );
++			connect( newSocket, SIGNAL( readyWrite() ), this, SLOT( transmitWebcamImage() ) );
++		}
++		
++		newSocket->connect();	
++		break;
++	default:
++		break;
++	}
++	socketMap.remove( socket );
++	delete socket;
++}
++
++void WebcamTask::processData( KStreamSocket *socket )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	QByteArray data( socket->bytesAvailable() );
++	
++	socket->readBlock ( data.data (), data.size () );
++	if( data.size() <= 0 )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "No data read." << endl;
++		return;
++	}
++	
++	parseData( data, socket );
++}
++
++void WebcamTask::parseData( QByteArray &data, KStreamSocket *socket )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " data " << data.size() << " bytes " << endl;
++	uint headerLength = 0;
++	uint read = 0;
++	YahooWebcamInformation *info = &socketMap[socket];
++	if( !info->headerRead )
++	{
++		headerLength = data[0];	
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "headerLength " << headerLength << endl;
++		if( data.size() < headerLength )
++			return;			
++		if( headerLength >= 8 )
++		{
++			kdDebug() << data[0] << data[1] << data[2] << data[3] << data[4] << data[5] << data[6] << data[7] << endl;
++			info->reason = data[1];
++			info->dataLength = yahoo_get32(data.data() + 4);
++		}
++		if( headerLength == 13 )
++		{
++			kdDebug() << data[8] << data[9] << data[10] << data[11] << data[12] << endl;
++			info->timestamp = yahoo_get32(data.data() + 9);
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "PacketType: " << data[8] << " reason: " << info->reason << " timestamp: " << info->timestamp << endl;
++			QStringList::iterator it;
++			switch( data[8] )
++			{
++				case 0x00:
++					if( info->direction == Incoming )
++					{
++						if( info->timestamp == 0 )
++						{
++							emit webcamClosed( info->sender, 3 );
++							cleanUpConnection( socket );
++						}
++					}
++					else
++					{
++						info->type = UserRequest;
++						info->headerRead = true;
++					}
++				break;
++				case 0x02: 
++					info->type = Image;
++					info->headerRead = true;
++				break;
++				case 0x04:
++					if( info->timestamp == 1 )
++					{
++						emit webcamPaused( info->sender );
++					}
++				break;
++				case 0x05:
++					kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Ready for Transmission" << endl;
++					if( info->timestamp == 1 )
++					{
++						info->status = Sending;
++						emit readyForTransmission();
++					}
++					else
++					{
++						info->status = SendingEmpty;
++						emit stopTransmission();
++						sendEmptyWebcamImage();
++					}
++					
++					// Send Invitation packets
++					for(it = pendingInvitations.begin(); it != pendingInvitations.end(); it++)
++					{
++						SendNotifyTask *snt = new SendNotifyTask( parent() );
++						snt->setTarget( *it );
++						snt->setType( SendNotifyTask::NotifyWebcamInvite );
++						snt->go( true );
++						it = pendingInvitations.remove( it );
++						it--;
++					}
++				break;
++				case 0x07: 
++					
++					info->type = ConnectionClosed;
++					emit webcamClosed( info->sender, info->reason );
++					cleanUpConnection( socket );
++				case 0x0c:
++					info->type = NewWatcher;
++					info->headerRead = true;
++				break;
++				case 0x0d:
++					info->type = WatcherLeft;
++					info->headerRead = true;
++				break;
++			}
++		}
++		if( headerLength > 13 || headerLength <= 0)		//Parse error
++			return;
++		if( !info->headerRead && data.size() > headerLength )
++		{
++			// More headers to read
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "More data to read..." << endl;
++			QByteArray newData( data.size() - headerLength );
++			QDataStream stream( newData, IO_WriteOnly );
++			stream.writeRawBytes( data.data() + headerLength, data.size() - headerLength );
++			parseData( newData, socket );
++			return;
++		}
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Parsed Packet: HeaderLen: " << headerLength << " DataLen: " << info->dataLength << endl;
++	}
++	
++	if( info->dataLength <= 0 )
++		return;
++	if( headerLength >= data.size() )
++		return;		//Nothing to read here...
++	if( !info->buffer )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Buffer created" << endl;
++		info->buffer = new QBuffer();
++		info->buffer->open( IO_WriteOnly );
++	}
++	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "data.size() " << data.size() << " headerLength " << headerLength << " buffersize " << info->buffer->size() << endl;
++	read = headerLength + info->dataLength - info->buffer->size();
++	info->buffer->writeBlock( data.data() + headerLength, data.size() - headerLength );//info->dataLength - info->buffer->size() );
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "read " << data.size() - headerLength << " Bytes, Buffer is now " << info->buffer->size() << endl;
++	if( info->buffer->size() >= static_cast<uint>(info->dataLength) )
++	{	
++		info->buffer->close();
++		QString who;
++		switch( info->type )
++		{
++		case UserRequest:
++			{
++			who.append( info->buffer->buffer() );
++			who = who.mid( 2, who.find('\n') - 3);
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "User wants to view webcam: " << who << " len: " << who.length() << " Index: " << accessGranted.findIndex( who ) << endl;
++			if( accessGranted.findIndex( who ) >= 0 )
++			{
++				grantAccess( who );
++			}
++			else
++				emit viewerRequest( who );
++			}
++		break;
++		case NewWatcher:
++			who.append( info->buffer->buffer() );
++			who = who.left( who.length() - 1 );
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "New Watcher of webcam: " << who << endl;
++			emit viewerJoined( who );
++		break;
++		case WatcherLeft:
++			who.append( info->buffer->buffer() );
++			who = who.left( who.length() - 1 );
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "A Watcher left: " << who << " len: " << who.length() << endl;
++			accessGranted.remove( who );
++			emit viewerLeft( who );
++		break;
++		case Image:
++			{
++			QPixmap webcamImage;
++			//webcamImage.loadFromData( info->buffer->buffer() );
++	
++			KTempFile jpcTmpImageFile;
++			KTempFile bmpTmpImageFile;
++			QFile *file = jpcTmpImageFile.file();
++			file->writeBlock((info->buffer->buffer()).data(), info->buffer->size());
++			file->close();
++			
++			KProcess p;
++			p << "jasper";
++			p << "--input" << jpcTmpImageFile.name() << "--output" << bmpTmpImageFile.name() << "--output-format" << "bmp";
++			
++			p.start( KProcess::Block );
++			if( p.exitStatus() != 0 )
++			{
++				kdDebug(YAHOO_RAW_DEBUG) << " jasper exited with status " << p.exitStatus() << " " << info->sender << endl;
++			}
++			else
++			{
++				webcamImage.load( bmpTmpImageFile.name() );
++				/******* UPTO THIS POINT ******/
++				emit webcamImageReceived( info->sender, webcamImage );
++			}
++			QFile::remove(jpcTmpImageFile.name());
++			QFile::remove(bmpTmpImageFile.name());
++	
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Image Received. Size: " << webcamImage.size() << endl;
++			}
++		break;
++		default:
++		break;
++		}
++		
++		info->headerRead = false;
++		delete info->buffer;
++		info->buffer = 0L;
++	}
++	if( data.size() > read )
++	{
++		// More headers to read
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "More data to read..." << data.size() - read << endl;
++		QByteArray newData( data.size() - read );
++		QDataStream stream( newData, IO_WriteOnly );
++		stream.writeRawBytes( data.data() + read, data.size() - read );
++		parseData( newData, socket );
++	}
++}
++
++void WebcamTask::cleanUpConnection( KStreamSocket *socket )
++{
++	socket->close();
++	YahooWebcamInformation *info = &socketMap[socket];
++	if( info->buffer )
++		delete info->buffer;
++	socketMap.remove( socket );
++	delete socket;	
++}
++
++void WebcamTask::closeWebcam( const QString & who )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << it.data().sender << " - " << who << endl;
++		if( it.data().sender == who )
++		{
++			cleanUpConnection( it.key() );
++			return;
++		}
++	}
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. You tried to close a connection that didn't exist." << endl;
++	client()->notifyError( i18n( "An error occured closing the webcam session. " ), i18n( "You tried to close a connection that didn't exist." ), Client::Debug );
++}
++
++
++// Sending 
++
++void WebcamTask::registerWebcam()
++{	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceWebcam);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit());
++	keyPending  = client()->userId();
++
++	send( t );
++}
++
++void WebcamTask::addPendingInvitation( const QString &userId )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Inviting " << userId << " to watch the webcam." << endl;
++	pendingInvitations.append( userId );
++	accessGranted.append( userId );
++}
++
++void WebcamTask::grantAccess( const QString &userId )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	KStreamSocket *socket = 0L;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		if( it.data().direction == Outgoing )
++		{
++			socket = it.key();
++			break;
++		}
++	}
++	if( !socket )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. No outgoing socket found." << endl;
++		return;
++	}
++	QByteArray ar;
++	QDataStream stream( ar, IO_WriteOnly );
++	QString user = QString("u=%1").arg(userId);
++
++	stream << (Q_INT8)0x0d << (Q_INT8)0x00 << (Q_INT8)0x05 << (Q_INT8)0x00 << (Q_INT32)user.length()
++	<< (Q_INT8)0x00 << (Q_INT8)0x00 << (Q_INT8)0x00 << (Q_INT8)0x00 << (Q_INT8)0x01;
++	socket->writeBlock( ar.data(), ar.size() );
++	socket->writeBlock( user.local8Bit(), user.length() );
++}
++
++void WebcamTask::closeOutgoingWebcam()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	KStreamSocket *socket = 0L;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		if( it.data().direction == Outgoing )
++		{
++			socket = it.key();
++			break;
++		}
++	}
++	if( !socket )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. No outgoing socket found." << endl;
++		return;
++	}
++	
++	cleanUpConnection( socket );
++	transmittingData = false;
++}
++
++void WebcamTask::sendEmptyWebcamImage()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	KStreamSocket *socket = 0L;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		if( it.data().direction == Outgoing )
++		{
++			socket = it.key();
++			break;
++		}
++	}
++	if( !socket )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. No outgoing socket found." << endl;
++		return;
++	}
++	if( socketMap[socket].status != SendingEmpty )
++		return;	
++
++	pictureBuffer.resize( 0 );
++	transmissionPending = true;
++
++	QTimer::singleShot( 1000, this, SLOT(sendEmptyWebcamImage()) );
++
++}
++
++void WebcamTask::sendWebcamImage( const QByteArray &image )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	pictureBuffer.duplicate( image );
++	transmissionPending = true;
++	KStreamSocket *socket = 0L;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		if( it.data().direction == Outgoing )
++		{
++			socket = it.key();
++			break;
++		}
++	}
++	if( !socket )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. No outgoing socket found." << endl;
++		return;
++	}
++
++	socket->enableWrite( true );
++}
++
++void WebcamTask::transmitWebcamImage()
++{
++	if( !transmissionPending )
++		return;
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "arraysize: " << pictureBuffer.size() << endl;
++
++	// Find outgoing socket
++	KStreamSocket *socket = 0L;
++	SocketInfoMap::Iterator it;
++	for( it = socketMap.begin(); it != socketMap.end(); it++ )
++	{
++		if( it.data().direction == Outgoing )
++		{
++			socket = it.key();
++			break;
++		}
++	}
++	if( !socket )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error. No outgoing socket found." << endl;
++		return;
++	}
++
++	socket->enableWrite( false );
++	QByteArray buffer;
++	QDataStream stream( buffer, IO_WriteOnly );
++	stream << (Q_INT8)0x0d << (Q_INT8)0x00 << (Q_INT8)0x05 << (Q_INT8)0x00 << (Q_INT32)pictureBuffer.size()
++			<< (Q_INT8)0x02 << (Q_INT32)timestamp++;
++	socket->writeBlock( buffer.data(), buffer.size() );
++	if( pictureBuffer.size() )
++		socket->writeBlock( pictureBuffer.data(), pictureBuffer.size() );
++	
++	transmissionPending = false;
++}
++#include "webcamtask.moc"
+--- kopete/protocols/yahoo/libkyahoo/transfer.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/transfer.cpp	(revision 586398)
+@@ -0,0 +1,26 @@
++/*
++    transfer.cpp - Kopete Groupwise Protocol
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "transfer.h"
++
++Transfer::Transfer()
++{
++}
++
++Transfer::~Transfer()
++{
++}
+--- kopete/protocols/yahoo/libkyahoo/sendmessagetask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendmessagetask.h	(revision 586398)
+@@ -0,0 +1,44 @@
++/*
++    Kopete Yahoo Protocol
++    Send a message
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SENDMESSAGETASK_H
++#define SENDMESSAGETASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class SendMessageTask : public Task
++{
++public:
++	SendMessageTask(Task *parent);
++	~SendMessageTask();
++	
++	virtual void onGo();
++	
++	void setText( const QString &text );
++	void setTarget( const QString &to );
++	void setPicureFlag( int flag );
++private:
++	QString m_text;
++	QString m_target;
++	int m_pictureFlag;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/sha1.c	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sha1.c	(revision 586398)
+@@ -0,0 +1,628 @@
++/*-
++ * Copyright (c) 2001-2003 Allan Saddi <allan at saddi.com>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ *
++ * $Id$
++ */
++
++/*
++ * Define WORDS_BIGENDIAN if compiling on a big-endian architecture.
++ *
++ * Define SHA1_TEST to test the implementation using the NIST's
++ * sample messages. The output should be:
++ *
++ *   a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
++ *   84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1
++ *   34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif /* HAVE_CONFIG_H */
++
++#if HAVE_INTTYPES_H
++# include <inttypes.h>
++#else
++# if HAVE_STDINT_H
++#  include <stdint.h>
++# endif
++#endif
++
++#include <string.h>
++
++#include "sha1.h"
++
++#ifndef lint
++static const char rcsid[] =
++	"$Id$";
++#endif /* !lint */
++
++#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
++#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
++
++#define F_0_19(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
++#define F_20_39(x, y, z) ((x) ^ (y) ^ (z))
++#define F_40_59(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
++#define F_60_79(x, y, z) ((x) ^ (y) ^ (z))
++
++#define DO_ROUND(F, K) { \
++  temp = ROTL(a, 5) + F(b, c, d) + e + *(W++) + K; \
++  e = d; \
++  d = c; \
++  c = ROTL(b, 30); \
++  b = a; \
++  a = temp; \
++}
++
++#define K_0_19 0x5a827999L
++#define K_20_39 0x6ed9eba1L
++#define K_40_59 0x8f1bbcdcL
++#define K_60_79 0xca62c1d6L
++
++#ifndef RUNTIME_ENDIAN
++
++#ifdef WORDS_BIGENDIAN
++
++#define BYTESWAP(x) (x)
++#define BYTESWAP64(x) (x)
++
++#else /* WORDS_BIGENDIAN */
++
++#define BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | (ROTL((x), 8) & 0x00ff00ffL))
++
++static uint64_t _byteswap64(uint64_t x)
++{
++	uint32_t a = x >> 32;
++	uint32_t b = (uint32_t) x;
++	return ((uint64_t) BYTESWAP(b) << 32) | (uint64_t) BYTESWAP(a);
++}
++
++#define BYTESWAP64(x) _byteswap64(x)
++
++
++
++#endif /* WORDS_BIGENDIAN */
++
++#else /* !RUNTIME_ENDIAN */
++
++#define BYTESWAP(x) _byteswap(sc->littleEndian, x)
++#define BYTESWAP64(x) _byteswap64(sc->littleEndian, x)
++
++#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \
++		      (ROTL((x), 8) & 0x00ff00ffL))
++#define _BYTESWAP64(x) __byteswap64(x)
++
++static uint64_t __byteswap64(uint64_t x)
++{
++  uint32_t a = x >> 32;
++  uint32_t b = (uint32_t) x;
++  return ((uint64_t) _BYTESWAP(b) << 32) | (uint64_t) _BYTESWAP(a);
++}
++
++static uint32_t _byteswap(int littleEndian, uint32_t x)
++{
++  if (!littleEndian)
++    return x;
++  else
++    return _BYTESWAP(x);
++}
++
++static uint64_t _byteswap64(int littleEndian, uint64_t x)
++{
++  if (!littleEndian)
++    return x;
++  else
++    return _BYTESWAP64(x);
++}
++
++static void setEndian(int *littleEndianp)
++{
++  union {
++    uint32_t w;
++    uint8_t b[4];
++  } endian;
++
++  endian.w = 1L;
++  *littleEndianp = endian.b[0] != 0;
++}
++
++#endif /* !RUNTIME_ENDIAN */
++
++static const uint8_t padding[64] = {
++  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++void
++SHA1Init (SHA1Context *sc)
++{
++#ifdef RUNTIME_ENDIAN
++  setEndian (&sc->littleEndian);
++#endif /* RUNTIME_ENDIAN */
++
++  sc->totalLength = 0LL;
++  sc->hash[0] = 0x67452301L;
++  sc->hash[1] = 0xefcdab89L;
++  sc->hash[2] = 0x98badcfeL;
++  sc->hash[3] = 0x10325476L;
++  sc->hash[4] = 0xc3d2e1f0L;
++  sc->bufferLength = 0L;
++}
++
++static void
++burnStack (int size)
++{
++  char buf[128];
++
++  memset (buf, 0, sizeof (buf));
++  size -= sizeof (buf);
++  if (size > 0)
++    burnStack (size);
++}
++
++static void
++SHA1Guts (SHA1Context *sc, const uint32_t *cbuf)
++{
++  uint32_t buf[80];
++  uint32_t *W, *W3, *W8, *W14, *W16;
++  uint32_t a, b, c, d, e, temp;
++  int i;
++
++  W = buf;
++
++  for (i = 15; i >= 0; i--) {
++    *(W++) = BYTESWAP(*cbuf);
++    cbuf++;
++  }
++
++  W16 = &buf[0];
++  W14 = &buf[2];
++  W8 = &buf[8];
++  W3 = &buf[13];
++
++  for (i = 63; i >= 0; i--) {
++    *W = *(W3++) ^ *(W8++) ^ *(W14++) ^ *(W16++);
++    *W = ROTL(*W, 1);
++    W++;
++  }
++
++  a = sc->hash[0];
++  b = sc->hash[1];
++  c = sc->hash[2];
++  d = sc->hash[3];
++  e = sc->hash[4];
++
++  W = buf;
++
++#ifndef SHA1_UNROLL
++#define SHA1_UNROLL 20
++#endif /* !SHA1_UNROLL */
++
++#if SHA1_UNROLL == 1
++  for (i = 19; i >= 0; i--)
++    DO_ROUND(F_0_19, K_0_19);
++
++  for (i = 19; i >= 0; i--)
++    DO_ROUND(F_20_39, K_20_39);
++
++  for (i = 19; i >= 0; i--)
++    DO_ROUND(F_40_59, K_40_59);
++
++  for (i = 19; i >= 0; i--)
++    DO_ROUND(F_60_79, K_60_79);
++#elif SHA1_UNROLL == 2
++  for (i = 9; i >= 0; i--) {
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++  }
++
++  for (i = 9; i >= 0; i--) {
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++  }
++
++  for (i = 9; i >= 0; i--) {
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++  }
++
++  for (i = 9; i >= 0; i--) {
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++  }
++#elif SHA1_UNROLL == 4
++  for (i = 4; i >= 0; i--) {
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++  }
++
++  for (i = 4; i >= 0; i--) {
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++  }
++
++  for (i = 4; i >= 0; i--) {
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++  }
++
++  for (i = 4; i >= 0; i--) {
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++  }
++#elif SHA1_UNROLL == 5
++  for (i = 3; i >= 0; i--) {
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++  }
++
++  for (i = 3; i >= 0; i--) {
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++  }
++
++  for (i = 3; i >= 0; i--) {
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++  }
++
++  for (i = 3; i >= 0; i--) {
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++  }
++#elif SHA1_UNROLL == 10
++  for (i = 1; i >= 0; i--) {
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++    DO_ROUND(F_0_19, K_0_19);
++  }
++
++  for (i = 1; i >= 0; i--) {
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++    DO_ROUND(F_20_39, K_20_39);
++  }
++
++  for (i = 1; i >= 0; i--) {
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++    DO_ROUND(F_40_59, K_40_59);
++  }
++
++  for (i = 1; i >= 0; i--) {
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++    DO_ROUND(F_60_79, K_60_79);
++  }
++#elif SHA1_UNROLL == 20
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++  DO_ROUND(F_0_19, K_0_19);
++
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++  DO_ROUND(F_20_39, K_20_39);
++
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++  DO_ROUND(F_40_59, K_40_59);
++
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++  DO_ROUND(F_60_79, K_60_79);
++#else /* SHA1_UNROLL */
++#error SHA1_UNROLL must be 1, 2, 4, 5, 10 or 20!
++#endif
++
++  sc->hash[0] += a;
++  sc->hash[1] += b;
++  sc->hash[2] += c;
++  sc->hash[3] += d;
++  sc->hash[4] += e;
++}
++
++void
++SHA1Update (SHA1Context *sc, const void *vdata, uint32_t len)
++{
++  const uint8_t *data = vdata;
++  uint32_t bufferBytesLeft;
++  uint32_t bytesToCopy;
++  int needBurn = 0;
++
++#ifdef SHA1_FAST_COPY
++  if (sc->bufferLength) {
++    bufferBytesLeft = 64L - sc->bufferLength;
++
++    bytesToCopy = bufferBytesLeft;
++    if (bytesToCopy > len)
++      bytesToCopy = len;
++
++    memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
++
++    sc->totalLength += bytesToCopy * 8L;
++
++    sc->bufferLength += bytesToCopy;
++    data += bytesToCopy;
++    len -= bytesToCopy;
++
++    if (sc->bufferLength == 64L) {
++      SHA1Guts (sc, sc->buffer.words);
++      needBurn = 1;
++      sc->bufferLength = 0L;
++    }
++  }
++
++  while (len > 63) {
++    sc->totalLength += 512L;
++
++    SHA1Guts (sc, data);
++    needBurn = 1;
++
++    data += 64L;
++    len -= 64L;
++  }
++
++  if (len) {
++    memcpy (&sc->buffer.bytes[sc->bufferLength], data, len);
++
++    sc->totalLength += len * 8L;
++
++    sc->bufferLength += len;
++  }
++#else /* SHA1_FAST_COPY */
++  while (len) {
++    bufferBytesLeft = 64L - sc->bufferLength;
++
++    bytesToCopy = bufferBytesLeft;
++    if (bytesToCopy > len)
++      bytesToCopy = len;
++
++    memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
++
++    sc->totalLength += bytesToCopy * 8L;
++
++    sc->bufferLength += bytesToCopy;
++    data += bytesToCopy;
++    len -= bytesToCopy;
++
++    if (sc->bufferLength == 64L) {
++      SHA1Guts (sc, sc->buffer.words);
++      needBurn = 1;
++      sc->bufferLength = 0L;
++    }
++  }
++#endif /* SHA1_FAST_COPY */
++
++  if (needBurn)
++    burnStack (sizeof (uint32_t[86]) + sizeof (uint32_t *[5]) + sizeof (int));
++}
++
++void
++SHA1Final (SHA1Context *sc, uint8_t hash[SHA1_HASH_SIZE])
++{
++  uint32_t bytesToPad;
++  uint64_t lengthPad;
++  int i;
++
++  bytesToPad = 120L - sc->bufferLength;
++  if (bytesToPad > 64L)
++    bytesToPad -= 64L;
++
++  lengthPad = BYTESWAP64(sc->totalLength);
++
++  SHA1Update (sc, padding, bytesToPad);
++  SHA1Update (sc, &lengthPad, 8L);
++
++  if (hash) {
++    for (i = 0; i < SHA1_HASH_WORDS; i++) {
++#ifdef SHA1_FAST_COPY
++      *((uint32_t *) hash) = BYTESWAP(sc->hash[i]);
++#else /* SHA1_FAST_COPY */
++      hash[0] = (uint8_t) (sc->hash[i] >> 24);
++      hash[1] = (uint8_t) (sc->hash[i] >> 16);
++      hash[2] = (uint8_t) (sc->hash[i] >> 8);
++      hash[3] = (uint8_t) sc->hash[i];
++#endif /* SHA1_FAST_COPY */
++      hash += 4;
++    }
++  }
++}
++
++#ifdef SHA1_TEST
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++int
++main (int argc, char *argv[])
++{
++  SHA1Context foo;
++  uint8_t hash[SHA1_HASH_SIZE];
++  char buf[1000];
++  int i;
++
++  SHA1Init (&foo);
++  SHA1Update (&foo, "abc", 3);
++  SHA1Final (&foo, hash);
++
++  for (i = 0; i < SHA1_HASH_SIZE;) {
++    printf ("%02x", hash[i++]);
++    if (!(i % 4))
++      printf (" ");
++  }
++  printf ("\n");
++
++  SHA1Init (&foo);
++  SHA1Update (&foo,
++		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++		56);
++  SHA1Final (&foo, hash);
++
++  for (i = 0; i < SHA1_HASH_SIZE;) {
++    printf ("%02x", hash[i++]);
++    if (!(i % 4))
++      printf (" ");
++  }
++  printf ("\n");
++
++  SHA1Init (&foo);
++  memset (buf, 'a', sizeof (buf));
++  for (i = 0; i < 1000; i++)
++    SHA1Update (&foo, buf, sizeof (buf));
++  SHA1Final (&foo, hash);
++
++  for (i = 0; i < SHA1_HASH_SIZE;) {
++    printf ("%02x", hash[i++]);
++    if (!(i % 4))
++      printf (" ");
++  }
++  printf ("\n");
++
++  exit (0);
++}
++
++#endif /* SHA1_TEST */
+--- kopete/protocols/yahoo/libkyahoo/stealthtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/stealthtask.h	(revision 586398)
+@@ -0,0 +1,46 @@
++/*
++    Kopete Yahoo Protocol
++    Stealth/Unstealth a buddy
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef STEALTHTASK_H
++#define STEALTHTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++#include <kdebug.h>
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class StealthTask : public Task
++{
++public:
++	StealthTask(Task *parent);
++	~StealthTask();
++	
++	virtual void onGo();
++
++	void setTarget( const QString &to );
++	void setState( Yahoo::StealthStatus state );
++	void setMode( Yahoo::StealthMode mode );
++private:
++	QString m_target;
++	Yahoo::StealthMode m_mode;
++	Yahoo::StealthStatus m_state;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yabentry.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yabentry.cpp	(revision 586398)
+@@ -0,0 +1,201 @@
++/*
++    yabcpp - Encapsulate Yahoo Adressbook information
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "yabentry.h"
++
++void YABEntry::fromQDomElement( const QDomElement &e )
++{
++	yahooId = e.attribute("yi");
++	YABId = e.attribute("id", "-1").toInt();
++	firstName = e.attribute("fn");
++	secondName = e.attribute("mn");
++	lastName = e.attribute("ln");
++	nickName = e.attribute("nn");
++	email = e.attribute("e0");
++	privatePhone = e.attribute("hp");
++	workPhone = e.attribute("wp");
++	pager = e.attribute("pa");
++	fax = e.attribute("fa");
++	phoneMobile = e.attribute("mo");
++	additionalNumber = e.attribute("ot");
++	altEmail1 = e.attribute("e1");
++	altEmail2 = e.attribute("e2");
++	privateURL = e.attribute("pu");
++	title = e.attribute("ti");
++	corporation = e.attribute("co");
++	workAdress = e.attribute("wa").replace( "&#xd;&#xa;", "\n" );
++	workCity = e.attribute("wc");
++	workState = e.attribute("ws");
++	workZIP = e.attribute("wz");
++	workCountry = e.attribute("wn");
++	workURL = e.attribute("wu");
++	privateAdress = e.attribute("ha").replace( "&#xd;&#xa;", "\n" );
++	privateCity = e.attribute("hc");
++	privateState = e.attribute("hs");
++	privateZIP = e.attribute("hz");
++	privateCountry = e.attribute("hn");
++	QString birtday = e.attribute("bi");
++	birthday = QDate( birtday.section("/",2,2).toInt(), birtday.section("/",1,1).toInt(), birtday.section("/",0,0).toInt() );
++	QString an = e.attribute("an");
++	anniversary = QDate( an.section("/",2,2).toInt(), an.section("/",1,1).toInt(), an.section("/",0,0).toInt() );
++	additional1 = e.attribute("c1");
++	additional2 = e.attribute("c2");
++	additional3 = e.attribute("c3");
++	additional4 = e.attribute("c4");
++	notes = e.attribute("cm").replace( "&#xd;&#xa;", "\n" );
++	imAIM = e.attribute("ima");
++	imGoogleTalk = e.attribute("img");
++	imICQ = e.attribute("imq");
++	imIRC = e.attribute("imc");
++	imMSN = e.attribute("imm");
++	imQQ = e.attribute("imqq");
++	imSkype = e.attribute("imk");
++}
++
++void YABEntry::fromQDomDocument( const QDomDocument &d )
++{
++	kdDebug() << d.toString() << 
++		d.elementsByTagName("yi").item(0).toElement().text();
++	yahooId = d.elementsByTagName("yi").item(0).toElement().text();
++	firstName = d.elementsByTagName("fn").item(0).toElement().text();
++	secondName = d.elementsByTagName("mn").item(0).toElement().text();
++	lastName = d.elementsByTagName("ln").item(0).toElement().text();
++	nickName = d.elementsByTagName("nn").item(0).toElement().text();
++	email = d.elementsByTagName("e0").item(0).toElement().text();
++	privatePhone = d.elementsByTagName("hp").item(0).toElement().text();
++	workPhone = d.elementsByTagName("wp").item(0).toElement().text();
++	pager = d.elementsByTagName("pa").item(0).toElement().text();
++	fax = d.elementsByTagName("fa").item(0).toElement().text();
++	phoneMobile = d.elementsByTagName("mo").item(0).toElement().text();
++	additionalNumber = d.elementsByTagName("ot").item(0).toElement().text();
++	altEmail1 = d.elementsByTagName("e1").item(0).toElement().text();
++	altEmail2 = d.elementsByTagName("e2").item(0).toElement().text();
++	privateURL = d.elementsByTagName("pu").item(0).toElement().text();
++	title = d.elementsByTagName("ti").item(0).toElement().text();
++	corporation = d.elementsByTagName("co").item(0).toElement().text();
++	workAdress = d.elementsByTagName("wa").item(0).toElement().text().replace( "&#xd;&#xa;", "\n" );
++	workCity = d.elementsByTagName("wc").item(0).toElement().text();
++	workState = d.elementsByTagName("ws").item(0).toElement().text();
++	workZIP = d.elementsByTagName("wz").item(0).toElement().text();
++	workCountry = d.elementsByTagName("wn").item(0).toElement().text();
++	workURL = d.elementsByTagName("wu").item(0).toElement().text();
++	privateAdress = d.elementsByTagName("ha").item(0).toElement().text().replace( "&#xd;&#xa;", "\n" );
++	privateCity = d.elementsByTagName("hc").item(0).toElement().text();
++	privateState = d.elementsByTagName("hs").item(0).toElement().text();
++	privateZIP = d.elementsByTagName("hz").item(0).toElement().text();
++	privateCountry = d.elementsByTagName("hn").item(0).toElement().text();
++	QString birtday = d.elementsByTagName("bi").item(0).toElement().text();
++	birthday = QDate( birtday.section("/",2,2).toInt(), birtday.section("/",1,1).toInt(), birtday.section("/",0,0).toInt() );
++	QString an = d.elementsByTagName("an").item(0).toElement().text();
++	anniversary = QDate( an.section("/",2,2).toInt(), an.section("/",1,1).toInt(), an.section("/",0,0).toInt() );
++	additional1 = d.elementsByTagName("c1").item(0).toElement().text();
++	additional2 = d.elementsByTagName("c2").item(0).toElement().text();
++	additional3 = d.elementsByTagName("c3").item(0).toElement().text();
++	additional4 = d.elementsByTagName("c4").item(0).toElement().text();
++	notes = d.elementsByTagName("cm").item(0).toElement().text().replace( "&#xd;&#xa;", "\n" );
++	imAIM = d.elementsByTagName("ima").item(0).toElement().text();
++	imGoogleTalk = d.elementsByTagName("img").item(0).toElement().text();
++	imICQ = d.elementsByTagName("imq").item(0).toElement().text();
++	imIRC = d.elementsByTagName("imc").item(0).toElement().text();
++	imMSN = d.elementsByTagName("imm").item(0).toElement().text();
++	imQQ = d.elementsByTagName("imqq").item(0).toElement().text();
++	imSkype = d.elementsByTagName("imk").item(0).toElement().text();
++}
++
++void YABEntry::fillQDomElement( QDomElement &e ) const
++{
++	e.setAttribute( "yi", yahooId );
++	e.setAttribute( "id", YABId );
++	e.setAttribute( "fn", firstName );
++	e.setAttribute( "mn", secondName );
++	e.setAttribute( "ln", lastName );
++	e.setAttribute( "nn", nickName );
++	e.setAttribute( "e0", email );
++	e.setAttribute( "hp", privatePhone );
++	e.setAttribute( "wp", workPhone );
++	e.setAttribute( "pa", pager );
++	e.setAttribute( "fa", fax );
++	e.setAttribute( "mo", phoneMobile );
++	e.setAttribute( "ot", additionalNumber );
++	e.setAttribute( "e1", altEmail1 );
++	e.setAttribute( "e2", altEmail2 );
++	e.setAttribute( "pu", privateURL );
++	e.setAttribute( "ti", title );
++	e.setAttribute( "co", corporation );
++	e.setAttribute( "wa", QString( workAdress ).replace( "\n", "&#xd;&#xa;" ) );
++	e.setAttribute( "wc", workCity );
++	e.setAttribute( "ws", workState );
++	e.setAttribute( "wz", workZIP );
++	e.setAttribute( "wn", workCountry );
++	e.setAttribute( "wu", workURL );
++	e.setAttribute( "ha", QString( privateAdress ).replace( "\n", "&#xd;&#xa;" ) );
++	e.setAttribute( "hc", privateCity );
++	e.setAttribute( "hs", privateState );
++	e.setAttribute( "hz", privateZIP );
++	e.setAttribute( "hn", privateCountry );
++	e.setAttribute( "bi", QString("%1/%2/%3").arg( birthday.day() ).arg( birthday.month() ).arg( birthday.year() ) );
++	e.setAttribute( "an", QString("%1/%2/%3").arg( anniversary.day() ).arg( anniversary.month() ).arg( anniversary.year() ) );
++	e.setAttribute( "c1", additional1 );
++	e.setAttribute( "c2", additional2 );
++	e.setAttribute( "c3", additional3 );
++	e.setAttribute( "c4", additional4 );
++	e.setAttribute( "cm", QString( notes ).replace( "\n", "&#xd;&#xa;" ) );
++	e.setAttribute( "ima", imAIM );
++	e.setAttribute( "img", imGoogleTalk );
++	e.setAttribute( "imq", imICQ );
++	e.setAttribute( "imc", imIRC );
++	e.setAttribute( "imm", imMSN );
++	e.setAttribute( "imqq", imQQ );
++	e.setAttribute( "imk", imSkype );
++}
++
++void YABEntry::dump() const
++{
++	kdDebug() << "firstName: " << firstName << endl << 
++		"secondName: " << secondName << endl << 
++		"lastName: " << lastName << endl << 
++		"nickName: " << nickName << endl << 
++		"title: " << title << endl << 
++		"phoneMobile: " << phoneMobile << endl << 
++		"email: " << email << endl << 
++		"yahooId: " << yahooId << endl << 
++		"pager: " << pager << endl << 
++		"fax: " << fax << endl << 
++		"additionalNumber: " << additionalNumber << endl << 
++		"altEmail1: " << altEmail1 << endl << 
++		"altEmail2: " << altEmail2 << endl << 
++		"privateAdress: " << privateAdress << endl << 
++		"privateCity: " << privateCity << endl << 
++		"privateState: " << privateState << endl << 
++		"privateZIP: " << privateZIP << endl << 
++		"privateCountry: " << privateCountry << endl << 
++		"privatePhone: " << privatePhone << endl << 
++		"privateURL: " << privateURL << endl << 
++		"corporation: " << corporation << endl << 
++		"workAdress: " << workAdress << endl << 
++		"workCity: " << workCity << endl << 
++		"workState: " << workState << endl << 
++		"workZIP: " << workZIP << endl << 
++		"workCountry: " << workCountry << endl << 
++		"workURL: " << workURL << endl << 
++		"birthday: " << birthday.toString() << endl << 
++		"anniversary: " << anniversary.toString() << endl << 
++		"notes: " << notes << endl << 
++		"additional1: " << additional1 << endl << 
++		"additional2: " << additional2 << endl << 
++		"additional3: " << additional3 << endl << 
++		"additional4: " << additional4 << endl;
++}
+--- kopete/protocols/yahoo/libkyahoo/connector.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/connector.h	(revision 586398)
+@@ -0,0 +1,59 @@
++/*
++    Kopete Oscar Protocol
++    connector.h - the Oscar socket connector
++
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++    Based on code Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef LIBKYAHOO_CONNECTOR_H
++#define LIBKYAHOO_CONNECTOR_H
++
++
++#include <qobject.h>
++#include "qhostaddress.h"
++
++class ByteStream;
++
++class Connector : public QObject
++{
++	Q_OBJECT
++public:
++	Connector(QObject *parent=0);
++	virtual ~Connector();
++
++	virtual void connectToServer(const QString &server)=0;
++	virtual ByteStream *stream() const=0;
++	virtual void done()=0;
++
++	bool havePeerAddress() const;
++	QHostAddress peerAddress() const;
++	Q_UINT16 peerPort() const;
++
++signals:
++	void connected();
++	void error();
++
++protected:
++	void setPeerAddressNone();
++	void setPeerAddress(const QHostAddress &addr, Q_UINT16 port);
++
++private:
++	bool haveaddr;
++	QHostAddress addr;
++	Q_UINT16 port;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/logintask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/logintask.h	(revision 586398)
+@@ -0,0 +1,75 @@
++/*
++    Kopete Yahoo Protocol
++    Handles logging into to the Yahoo service
++
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef LOGINTASK_H
++#define LOGINTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++
++class QString;
++class YMSGTransfer;
++
++/**
++ at author Duncan Mac-Vicar
++*/
++class LoginTask : public Task
++{
++Q_OBJECT
++public:
++	LoginTask(Task *parent);
++	~LoginTask();
++	
++	bool take(Transfer* transfer);
++	virtual void onGo();
++
++	void reset();
++	void setStateOnConnect( Yahoo::Status status );
++	void setVerificationWord( const QString &word );
++
++	const QString &yCookie();
++	const QString &cCookie();
++	const QString &tCookie();
++	const QString &loginCookie();
++protected:
++	bool forMe( Transfer* transfer ) const;
++	enum State { InitialState, SentVerify, GotVerifyACK, SentAuth, GotAuthACK, SentAuthResp };
++	void sendVerify();
++	void sendAuth(YMSGTransfer* transfer);
++	void sendAuthResp(YMSGTransfer* transfer);
++	void sendAuthResp_0x0b(const QString &sn, const QString &seed, uint sessionID);
++	void sendAuthResp_pre_0x0b(const QString &sn, const QString &seed);
++	void handleAuthResp(YMSGTransfer *transfer);
++	void parseCookies( YMSGTransfer *transfer );
++signals:
++	void haveSessionID( uint );
++	void haveCookies();
++	void loginResponse( int, const QString& );
++private:
++	State mState;
++	Yahoo::Status m_stateOnConnect;
++	QString m_yCookie;
++	QString m_tCookie;
++	QString m_cCookie;
++	QString m_loginCookie;
++	QString m_verificationWord;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/sha1.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sha1.h	(revision 586398)
+@@ -0,0 +1,72 @@
++/*-
++ * Copyright (c) 2001-2003 Allan Saddi <allan at saddi.com>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ *
++ * $Id$
++ */
++
++#ifndef _SHA1_H
++#define _SHA1_H
++
++#if HAVE_INTTYPES_H
++# include <inttypes.h>
++#else
++# if HAVE_STDINT_H
++#  include <stdint.h>
++# endif
++#endif
++
++#define SHA1_HASH_SIZE 20
++
++/* Hash size in 32-bit words */
++#define SHA1_HASH_WORDS 5
++
++struct _SHA1Context {
++  uint64_t totalLength;
++  uint32_t hash[SHA1_HASH_WORDS];
++  uint32_t bufferLength;
++  union {
++    uint32_t words[16];
++    uint8_t bytes[64];
++  } buffer;
++#ifdef RUNTIME_ENDIAN
++  int littleEndian;
++#endif /* RUNTIME_ENDIAN */
++};
++
++typedef struct _SHA1Context SHA1Context;
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++void SHA1Init (SHA1Context *sc);
++void SHA1Update (SHA1Context *sc, const void *data, uint32_t len);
++void SHA1Final (SHA1Context *sc, uint8_t hash[SHA1_HASH_SIZE]);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _SHA1_H */
+--- kopete/protocols/yahoo/libkyahoo/ymsgprotocol.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/ymsgprotocol.cpp	(revision 586398)
+@@ -0,0 +1,388 @@
++/*
++    Kopete Yahoo Protocol
++
++    Copyright (c) 2004 Duncan Mac-Vicar Prett <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <stdlib.h>
++
++#include <qcstring.h>
++#include <qdatastream.h>
++#include <qmap.h>
++#include <qobject.h>
++
++#include <kdebug.h>
++
++#include "ymsgprotocol.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++
++using namespace Yahoo;
++
++YMSGProtocol::YMSGProtocol(QObject *parent, const char *name)
++ : InputProtocolBase(parent, name)
++{
++}
++
++YMSGProtocol::~YMSGProtocol()
++{
++}
++
++Transfer* YMSGProtocol::parse( const QByteArray & packet, uint& bytes )
++{
++	/*
++	<------- 4B -------><------- 4B -------><---2B--->
++	+-------------------+-------------------+---------+
++	|   Y   M   S   G   |      version      | pkt_len |
++	+---------+---------+---------+---------+---------+
++	| service |      status       |    session_id     |
++	+---------+-------------------+-------------------+
++	|                                                 |
++	:                    D A T A                      :
++	/                   0 - 65535*                   |
++	+-------------------------------------------------+
++	*/
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << packet << endl;
++	
++	int pos = 0;
++	int len = 0;
++	
++	Yahoo::Status status = Yahoo::StatusAvailable;
++	Yahoo::Service service = Yahoo::ServiceAuth;
++	int statusnum = 0;
++	int sessionid = 0;
++	int servicenum;
++	int version1, version2;
++	
++	QMap<QString, QString> params;
++	
++	// Skip the YMSG header
++	pos += 4;
++	
++	// Skip the version
++	version1 = yahoo_get16(packet.data() + pos);
++	pos += 2;
++	version2 = yahoo_get16(packet.data() + pos);
++	pos += 2;
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - parsed packet version " << version1 << " " << version2 << endl;
++	
++	len = yahoo_get16(packet.data() + pos);
++	pos += 2;
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - parsed packet len " << len << endl;
++	
++	servicenum = yahoo_get16(packet.data() + pos);
++	pos += 2;
++	
++	switch (servicenum)
++	{
++		// TODO add remamining services
++		case (Yahoo::ServiceAuth) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceAuth " << servicenum << endl;
++			service = Yahoo::ServiceAuth;
++		break;
++		case (Yahoo::ServiceAuthResp) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceAuthResp " << servicenum << endl;
++			service = Yahoo::ServiceAuthResp;
++		break;
++		case (Yahoo::ServiceVerify) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceVerify " << servicenum << endl;
++			service = Yahoo::ServiceVerify;
++		break;
++		case (Yahoo::ServiceList) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceList " << servicenum << endl;
++			service = Yahoo::ServiceList;
++		break;
++		case (Yahoo::ServiceLogon) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceLogon " << servicenum << endl;
++			service = Yahoo::ServiceLogon;
++		break;
++		case (Yahoo::ServicePing) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePing " << servicenum << endl;
++			service = Yahoo::ServicePing;
++		break;
++		case (Yahoo::ServiceNewMail) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceNewMail " << servicenum << endl;
++			service = Yahoo::ServiceNewMail;
++		break;
++		case (Yahoo::ServiceLogoff) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceLogoff " << servicenum << endl;
++			service = Yahoo::ServiceLogoff;
++		break;
++		case (Yahoo::ServiceIsAway) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceIsAway " << servicenum << endl;
++			service = Yahoo::ServiceIsAway;
++		break;
++		case (Yahoo::ServiceIsBack) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceIsBack " << servicenum << endl;
++			service = Yahoo::ServiceIsBack;
++		break;
++		case (Yahoo::ServiceGameLogon) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceGameLogon " << servicenum << endl;
++			service = Yahoo::ServiceGameLogon;
++		break;
++		case (Yahoo::ServiceGameLogoff) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceGameLogoff " << servicenum << endl;
++			service = Yahoo::ServiceGameLogoff;
++		break;
++		case (Yahoo::ServiceIdAct) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceIdAct " << servicenum << endl;
++			service = Yahoo::ServiceIdAct;
++		break;
++		case (Yahoo::ServiceIddeAct) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceIddeAct " << servicenum << endl;
++			service = Yahoo::ServiceIddeAct;
++		break;
++		case (Yahoo::ServiceStatus) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceStatus " << servicenum << endl;
++			service = Yahoo::ServiceStatus;
++		break;
++		case (Yahoo::ServiceMessage) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceMessage " << servicenum << endl;
++			service = Yahoo::ServiceMessage;
++		break;
++		case (Yahoo::ServiceNotify) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceNotify " << servicenum << endl;
++			service = Yahoo::ServiceNotify;
++		break;
++		case (Yahoo::ServiceAddBuddy) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceAddBuddy " << servicenum << endl;
++			service = Yahoo::ServiceAddBuddy;
++		break;
++		case (Yahoo::ServicePictureChecksum) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePictureChecksum " << servicenum << endl;
++			service = Yahoo::ServicePictureChecksum;
++		break;
++		case (Yahoo::ServicePictureStatus) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePictureStatus " << servicenum << endl;
++			service = Yahoo::ServicePictureStatus;
++		break;
++		case (Yahoo::ServicePicture) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePicture " << servicenum << endl;
++			service = Yahoo::ServicePicture;
++		break;
++		case (Yahoo::ServiceStealthOnline) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceStealthOnline " << servicenum << endl;
++			service = Yahoo::ServiceStealthOnline;
++		break;
++		case (Yahoo::ServiceStealthOffline) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceStealthOffline " << servicenum << endl;
++			service = Yahoo::ServiceStealthOffline;
++		break;
++		case (Yahoo::ServicePictureUpload) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePictureUpload " << servicenum << endl;
++			service = Yahoo::ServicePictureUpload;
++		break;
++		case (Yahoo::ServiceWebcam) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceWebcam " << servicenum << endl;
++			service = Yahoo::ServiceWebcam;
++		break;
++		case (Yahoo::ServiceConfInvite) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfInvite " << servicenum << endl;
++			service = Yahoo::ServiceConfInvite;
++		break;
++		case (Yahoo::ServiceConfLogon) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfLogon " << servicenum << endl;
++			service = Yahoo::ServiceConfLogon;
++		break;
++		case (Yahoo::ServiceConfDecline) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfDecline " << servicenum << endl;
++			service = Yahoo::ServiceConfDecline;
++		break;
++		case (Yahoo::ServiceConfLogoff) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfLogoff " << servicenum << endl;
++			service = Yahoo::ServiceConfLogoff;
++		break;
++		case (Yahoo::ServiceConfAddInvite) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfAddInvite " << servicenum << endl;
++			service = Yahoo::ServiceConfAddInvite;
++		break;
++		case (Yahoo::ServiceConfMsg) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceConfMsg " << servicenum << endl;
++			service = Yahoo::ServiceConfMsg;
++		break;
++		case (Yahoo::ServiceAuthorization) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceAuthorization " << servicenum << endl;
++			service = Yahoo::ServiceAuthorization;
++		break;
++		case (Yahoo::ServiceContactDetails) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceContactDetails " << servicenum << endl;
++			service = Yahoo::ServiceContactDetails;
++		break;
++		case (Yahoo::ServiceFileTransfer) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceFileTransfer " << servicenum << endl;
++			service = Yahoo::ServiceFileTransfer;
++		break;
++		case (Yahoo::ServiceFileTransfer7) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceFileTransfer7 " << servicenum << endl;
++			service = Yahoo::ServiceFileTransfer7;
++		break;
++		case (Yahoo::ServiceFileTransfer7Info) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServiceFileTransfer7Info " << servicenum << endl;
++			service = Yahoo::ServiceFileTransfer7Info;
++		break;
++		case (Yahoo::ServicePeerToPeer) :
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Parsed packet service -  This means ServicePeerToPeer " << servicenum << endl;
++			service = Yahoo::ServicePeerToPeer;
++		break;
++		/*
++		ServiceIdle, // 5 (placemarker)
++		ServiceMailStat,
++		ServiceUserStat, // 0xa
++		ServiceChatInvite,
++		ServiceCalendar,
++		ServiceNewPersonalMail,
++		ServiceNewContact,
++		ServiceAddIdent, // 0x10
++		ServiceAddIgnore,
++		ServiceGotGroupRename, // < 1, 36(old), 37(new)
++		ServiceSysMessage = 0x14,
++		ServicePassThrough2 = 0x16,
++		ServiceChatLogon,
++		ServiceChatLogoff,
++		ServiceChatMsg = 0x20,
++		ServiceGameMsg = 0x2a,
++		ServiceFileTransfer = 0x46,
++		ServiceVoiceChat = 0x4A,
++		ServiceVerify = 76,
++		ServiceP2PFileXfer,
++		ServiceRemBuddy,
++		ServiceIgnoreContact,	// > 1, 7, 13 < 1, 66, 13, 0
++		ServiceRejectContact,
++		ServiceGroupRename = 0x89, // > 1, 65(new), 66(0), 67(old) 
++		ServiceChatOnline = 0x96, // > 109(id), 1, 6(abcde) < 0,1
++		ServiceChatGoto,
++		ServiceChatJoin,	// > 1 104-room 129-1600326591 62-2
++		ServiceChatleave,
++		ServiceChatExit = 0x9b,
++		ServiceChatLogout = 0xa0,
++		ServiceChatPing,
++		ServiceComment = 0xa8
++		ServicePictureUpdate = 0xc1,
++		ServiceVisibility = 0xc5,	// YMSG13, key 13: 2 = invisible, 1 = visible 
++		ServiceStatus = 0xc6,		// YMSG13 
++		*/
++
++		default:
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "  Parsed packet service -  This means an unknown service " << servicenum << endl;
++		break;
++	}
++	
++	statusnum = yahoo_get32(packet.data() + pos);
++	pos += 4;
++	
++	switch (statusnum)
++	{
++		// TODO add remaining status
++		case (Yahoo::StatusAvailable) :
++			status = Yahoo::StatusAvailable;
++		break;
++		case (Yahoo::StatusBRB) :
++			status = Yahoo::StatusBRB;
++		break;
++		case (Yahoo::StatusDisconnected) :
++			status = Yahoo::StatusDisconnected;
++		break;
++		/*StatusBusy
++		StatusNotAtHome
++		StatusNotAtDesk
++		StatusNotInOffice
++		StatusOnPhone
++		StatusOnVacation
++		StatusOutToLunch
++		StatusSteppedOut
++		StatusInvisible
++		StatusCustom
++		StatusIdle
++		StatusOffline
++		StatusNotify*/
++		default:
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - unknown status " << statusnum << endl;
++		break;
++	}
++	
++	sessionid = yahoo_get32(packet.data() + pos);
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "  Parsed session id: " << (void *)sessionid << endl;
++	pos += 4;
++	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Setting incoming transfer basic information." << endl;
++	YMSGTransfer *t = new YMSGTransfer();
++	t->setService(service);
++	t->setId(sessionid);
++	t->setStatus(status);
++	
++	// taken almost as is from libyahoo ;-)
++	
++	char *data = packet.data();
++	while (pos + 1 < len + 20 /*header*/)
++	{
++		if( (BYTE) data[pos] == (BYTE)0x00  )
++			break;
++	
++		char *key = 0L, *value = 0L;
++		int accept;
++		int x;
++		key = (char *) malloc(len + 1);
++		x = 0;
++		while (pos + 1 < len +20) {
++			if ( ((BYTE) data[pos] == (BYTE)0xc0 && (BYTE) data[pos + 1] == (BYTE)0x80) )
++				break;
++			key[x++] = data[pos++];
++		}
++		key[x] = 0;
++		pos += 2;
++
++		accept = x;
++		
++		/* if x is 0 there was no key, so don't accept it */
++		if (accept)
++			value = (char *) malloc(len - pos + 20 + 1);
++		
++		x = 0;
++		while (pos + 1 < len + 20 /* header */)
++		{
++			if ((BYTE) data[pos] == (BYTE) 0xc0 && (BYTE) data[pos + 1] == (BYTE) 0x80)
++				break;
++			if (accept)
++				value[x++] = data[pos++];
++		}
++		if (accept)
++			value[x] = 0;
++		pos += 2;
++
++		if (accept) 
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " setting packet key [" << QString(key) << "] to " << QString(value) << endl;
++			t->setParam(QString(key).toInt(), value);
++			free(value);
++		}
++		else
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " key not accepted" << endl;
++		}
++		free(key);
++	}
++
++	// Packets consisting of several YMSG-packets sometimes contain padding chars (0x00) -> filter out
++ 	while( (BYTE)data[pos] == (BYTE) 0x00 && pos <= len + 20)
++ 		pos++;
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Returning transfer" << endl;
++	// tell them we have parsed offset bytes
++	
++	bytes = pos;
++	return t;
++}
++
++#include "ymsgprotocol.moc"
+--- kopete/protocols/yahoo/libkyahoo/task.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/task.cpp	(revision 586398)
+@@ -0,0 +1,265 @@
++/*
++    task.cpp - Kopete Groupwise Protocol
++   
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++  
++#include <qtimer.h>
++
++#include "client.h"
++#include "transfer.h"
++#include "safedelete.h"
++
++#include "task.h"
++
++class Task::TaskPrivate
++{
++public:
++	TaskPrivate() {}
++
++	QString id;
++	bool success;
++	int statusCode;
++	QString statusString;
++	Client *client;
++	bool insignificant, deleteme, autoDelete;
++	bool done;
++	Transfer * transfer;
++};
++
++Task::Task(Task *parent)
++:QObject(parent)
++{
++	init();
++	d->transfer = 0;
++	d->client = parent->client();
++	//d->id = client()->genUniqueId();
++	connect(d->client, SIGNAL(disconnected()), SLOT(clientDisconnected()));
++}
++
++Task::Task(Client *parent, bool)
++:QObject(0)
++{
++	init();
++
++	d->client = parent;
++	connect(d->client, SIGNAL(disconnected()), SLOT(clientDisconnected()));
++}
++
++Task::~Task()
++{
++	delete d;
++}
++
++void Task::init()
++{
++	d = new TaskPrivate;
++	d->success = false;
++	d->insignificant = false;
++	d->deleteme = false;
++	d->autoDelete = false;
++	d->done = false;
++	d->transfer = 0;
++}
++
++Task *Task::parent() const
++{
++	return (Task *)QObject::parent();
++}
++
++Client *Task::client() const
++{
++	return d->client;
++}
++
++Transfer * Task::transfer() const
++{
++	return d->transfer;
++}
++
++void Task::setTransfer( Transfer * transfer )
++{
++	d->transfer = transfer;
++}
++
++QString Task::id() const
++{
++	return d->id;
++}
++
++bool Task::success() const
++{
++	return d->success;
++}
++
++int Task::statusCode() const
++{
++	return d->statusCode;
++}
++
++const QString & Task::statusString() const
++{
++	return d->statusString;
++}
++
++void Task::go(bool autoDelete)
++{
++	d->autoDelete = autoDelete;
++
++	onGo();
++}
++
++bool Task::take( Transfer * transfer)
++{
++	const QObjectList *p = children();
++	if(!p)
++		return false;
++
++	// pass along the transfer to our children
++	QObjectListIt it(*p);
++	Task *t;
++	for(; it.current(); ++it) {
++		QObject *obj = it.current();
++		if(!obj->inherits("Task"))
++			continue;
++
++		t = static_cast<Task*>(obj);
++		
++		if(t->take( transfer ))
++		{
++			qDebug( "Transfer ACCEPTED by: %s", t->className() );
++			return true;
++		}
++/*		else
++			qDebug( "Transfer refused by: %s", t->className() );*/
++	}
++
++	return false;
++}
++
++void Task::safeDelete()
++{
++	if(d->deleteme)
++		return;
++
++	d->deleteme = true;
++	if(!d->insignificant)
++		SafeDelete::deleteSingle(this);
++}
++
++void Task::onGo()
++{
++	qDebug( "ERROR: calling default NULL onGo() for this task, you should reimplement this!");
++}
++
++void Task::onDisconnect()
++{
++	if(!d->done) {
++		d->success = false;
++		d->statusCode = ErrDisc;
++		d->statusString = tr("Disconnected");
++
++		// delay this so that tasks that react don't block the shutdown
++		QTimer::singleShot(0, this, SLOT(done()));
++	}
++}
++
++void Task::send( Transfer * request )
++{
++	client()->send( request );
++}
++
++void Task::setSuccess(int code, const QString &str)
++{
++	if(!d->done) {
++		d->success = true;
++		d->statusCode = code;
++		d->statusString = str;
++		done();
++	}
++}
++
++void Task::setError(int code, const QString &str)
++{
++	if(!d->done) {
++		d->success = false;
++		d->statusCode = code;
++		d->statusString = str;
++		done();
++	}
++}
++
++void Task::done()
++{
++	debug("Task::done()");
++	if(d->done || d->insignificant)
++		return;
++	d->done = true;
++
++	if(d->deleteme || d->autoDelete)
++		d->deleteme = true;
++
++	d->insignificant = true;
++	debug("emitting finished");
++	finished();
++	d->insignificant = false;
++
++	if(d->deleteme)
++		SafeDelete::deleteSingle(this);
++}
++
++void Task::clientDisconnected()
++{
++	onDisconnect();
++}
++
++// void Task::debug(const char *fmt, ...)
++// {
++// 	char *buf;
++// 	QString str;
++// 	int size = 1024;
++// 	int r;
++// 
++// 	do {
++// 		buf = new char[size];
++// 		va_list ap;
++// 		va_start(ap, fmt);
++// 		r = vsnprintf(buf, size, fmt, ap);
++// 		va_end(ap);
++// 
++// 		if(r != -1)
++// 			str = QString(buf);
++// 
++// 		delete [] buf;
++// 
++// 		size *= 2;
++// 	} while(r == -1);
++// 
++// 	debug(str);
++// }
++
++void Task::debug(const QString &str)
++{
++	client()->debug(QString("%1: ").arg(className()) + str);
++}
++
++bool Task::forMe( const Transfer * transfer ) const
++{
++	Q_UNUSED( transfer );
++	return false;
++}
++
++#include "task.moc"
+--- kopete/protocols/yahoo/libkyahoo/listtask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/listtask.h	(revision 586398)
+@@ -0,0 +1,46 @@
++/*
++    Kopete Yahoo Protocol
++    Handles several lists such as buddylist, ignorelist and so on
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef LISTTASK_H
++#define LISTTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++
++class QString;
++class YMSGTransfer;
++/**
++ at author André Duffeck
++*/
++class ListTask : public Task
++{
++Q_OBJECT
++public:
++	ListTask(Task *parent);
++	~ListTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++	void parseBuddyList( YMSGTransfer *transfer );
++	void parseStealthList( YMSGTransfer *transfer );	
++signals:
++	void gotBuddy(const QString&, const QString&, const QString&);
++	void stealthStatusChanged( const QString&, Yahoo::StealthStatus );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/logofftask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/logofftask.h	(revision 586398)
+@@ -0,0 +1,36 @@
++/*
++    Kopete Yahoo Protocol
++    Log off the Yahoo server
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef LOGOFFTASK_H
++#define LOGOFFTASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class LogoffTask : public Task
++{
++public:
++	LogoffTask(Task *parent);
++	~LogoffTask();
++	
++	virtual void onGo();
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/receivefiletask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/receivefiletask.cpp	(revision 586398)
+@@ -0,0 +1,243 @@
++/*
++    Kopete Yahoo Protocol
++    Receive a file
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "receivefiletask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qtimer.h>
++#include <kdebug.h>
++#include <klocale.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++
++ReceiveFileTask::ReceiveFileTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_transmitted = 0;
++	m_file = 0;
++	m_transferJob = 0;
++}
++
++ReceiveFileTask::~ReceiveFileTask()
++{
++	delete m_file;
++	m_file = 0;
++}
++
++void ReceiveFileTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceFileTransfer7);
++	switch( m_type )
++	{
++	case FileTransferAccept:
++		m_file = new QFile( m_localUrl.path() );
++		if( !m_file->open( IO_WriteOnly ) )
++		{
++			emit error( m_transferId, KIO::ERR_CANNOT_OPEN_FOR_WRITING, i18n("Could not open file for writing.") );
++			setSuccess( false );
++			return;
++		}
++		m_transferJob = KIO::get( m_remoteUrl, false, false );
++		QObject::connect( m_transferJob, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotComplete( KIO::Job* ) ) );
++		QObject::connect( m_transferJob, SIGNAL( data( KIO::Job*, const QByteArray & ) ), this, SLOT( slotData( KIO::Job*, const QByteArray & ) ) );
++		delete t;
++		break;
++	case FileTransfer7Accept:
++		t->setId( client()->sessionID() );
++		t->setParam( 1, client()->userId().local8Bit() );
++		t->setParam( 5, m_userId.local8Bit() );
++		t->setParam( 265, m_remoteUrl.url().local8Bit() );
++		t->setParam( 222, 3 );
++	
++		send( t );
++		break;
++	case FileTransfer7Reject:
++		t->setId( client()->sessionID() );
++		t->setParam( 1, client()->userId().local8Bit() );
++		t->setParam( 5, m_userId.local8Bit() );
++		t->setParam( 265, m_remoteUrl.url().local8Bit() );
++		t->setParam( 222, 4 );
++	
++		send( t );
++		break;
++	default:
++		delete t;
++	}
++}
++
++bool ReceiveFileTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++	
++	YMSGTransfer *t = static_cast<YMSGTransfer*>(transfer);
++
++	parseFileTransfer7Info( t );
++	
++	return true;
++}
++
++bool ReceiveFileTask::forMe( Transfer *transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++
++	if( t->service() == Yahoo::ServiceFileTransfer7Info )
++	{
++		// Only take this transfer if we are the corresponding task (in case of simultaneous file transfers)
++		if( t->firstParam( 265 ) == m_remoteUrl.url().local8Bit() )
++			return true;
++		else
++			return false;
++	}	
++	else
++		return false;
++}
++
++void ReceiveFileTask::slotData( KIO::Job *job, const QByteArray& data )
++{
++	Q_UNUSED( job );
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	m_transmitted += data.size();
++	emit bytesProcessed( m_transferId, m_transmitted );
++	m_file->writeBlock( data.data() , data.size() );
++	
++}
++
++void ReceiveFileTask::slotComplete( KIO::Job *job )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	KIO::TransferJob *transfer = static_cast< KIO::TransferJob * >(job);
++
++	if( m_file )
++		m_file->close();
++	if ( job->error () || transfer->isErrorPage () )
++	{
++		emit error( m_transferId, KIO::ERR_ABORTED, i18n("An error occured while downloading the file.") );
++		setSuccess( false );
++	}
++	else
++	{
++		emit complete( m_transferId );
++		setSuccess( true );
++	}
++}
++
++void ReceiveFileTask::parseFileTransfer7Info( YMSGTransfer *transfer )
++{	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	if( transfer->firstParam( 249 ).toInt() == 1 )
++	{
++		// Reject P2P Transfer offer
++		YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceFileTransfer7Accept);
++		t->setId( client()->sessionID() );
++		t->setParam( 1, client()->userId().local8Bit() );
++		t->setParam( 5, transfer->firstParam( 4 ) );
++		t->setParam( 265, transfer->firstParam( 265 ) );
++		t->setParam( 66, -3 );
++	
++		send( t );
++	}
++	else if( transfer->firstParam( 249 ).toInt() == 3 )
++	{
++		m_file = new QFile( m_localUrl.path() );
++		if( !m_file->open( IO_WriteOnly ) )
++		{
++			emit error( m_transferId, KIO::ERR_CANNOT_OPEN_FOR_WRITING, i18n("Could not open file for writing.") );
++			setSuccess( false );
++			return;
++		}
++
++		YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceFileTransfer7Accept);
++		t->setId( client()->sessionID() );
++		t->setParam( 1, client()->userId().local8Bit() );
++		t->setParam( 5, transfer->firstParam( 4 ) );
++		t->setParam( 265, transfer->firstParam( 265 ) );
++		t->setParam( 27, transfer->firstParam( 27 ) );
++		t->setParam( 249, 3 );			// Use Reflection server
++		t->setParam( 251, transfer->firstParam( 251 ) );
++	
++		send( t );
++		// The server expects a HTTP HEAD command prior to the GET
++		m_mimetypeJob = KIO::mimetype(QString::fromLatin1("http://%1/relay?token=%2&sender=%3&recver=%4")
++				.arg(transfer->firstParam( 250 )).arg(transfer->firstParam( 251 )).arg(m_userId).arg(client()->userId()), false);
++		m_mimetypeJob->addMetaData("cookies", "manual");
++		m_mimetypeJob->addMetaData("setcookies", QString::fromLatin1("Cookie: T=%1; path=/; domain=.yahoo.com; Y=%2; C=%3;")
++				.arg(client()->tCookie()).arg(client()->yCookie()).arg(client()->cCookie()) );
++
++
++		m_transferJob = KIO::get( QString::fromLatin1("http://%1/relay?token=%2&sender=%3&recver=%4")
++				.arg(transfer->firstParam( 250 )).arg(transfer->firstParam( 251 )).arg(m_userId).arg(client()->userId()), false, false );
++		QObject::connect( m_transferJob, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotComplete( KIO::Job* ) ) );
++		QObject::connect( m_transferJob, SIGNAL( data( KIO::Job*, const QByteArray & ) ), this, SLOT( slotData( KIO::Job*, const QByteArray & ) ) );
++		m_transferJob->addMetaData("cookies", "manual");
++		m_transferJob->addMetaData("setcookies", QString::fromLatin1("Cookie: T=%1; path=/; domain=.yahoo.com; Y=%2; C=%3;")
++				.arg(client()->tCookie()).arg(client()->yCookie()).arg(client()->cCookie()) );
++	}
++}
++
++void ReceiveFileTask::setRemoteUrl( KURL url )
++{
++	m_remoteUrl = url;
++}
++
++void ReceiveFileTask::setLocalUrl( KURL url )
++{
++	m_localUrl = url;
++}
++
++void ReceiveFileTask::setTransferId( unsigned int transferId )
++{
++	m_transferId = transferId;
++}
++
++void ReceiveFileTask::setType( Type type )
++{
++	m_type = type;
++}
++
++void ReceiveFileTask::setUserId( const QString &userId )
++{
++	m_userId = userId;
++}
++
++void ReceiveFileTask::canceled( unsigned int id )
++{
++	if( m_transferId != id )
++		return;
++	
++	if( m_transferJob )
++		m_transferJob->kill();
++	
++	setSuccess( false );
++}
++
++#include "receivefiletask.moc"
++
+--- kopete/protocols/yahoo/libkyahoo/statusnotifiertask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/statusnotifiertask.cpp	(revision 586398)
+@@ -0,0 +1,179 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about status changes of buddies
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "statusnotifiertask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qstringlist.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++StatusNotifierTask::StatusNotifierTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++StatusNotifierTask::~StatusNotifierTask()
++{
++
++}
++
++bool StatusNotifierTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++	
++	YMSGTransfer *t = static_cast<YMSGTransfer*>(transfer);
++
++	if( t->service() == Yahoo::ServiceStealthOffline )
++		parseStealthStatus( t );
++	else if( t->service() == Yahoo::ServiceAuthorization )
++		parseAuthorization( t );
++	else
++		parseStatus( t );	
++
++	return true;
++}
++
++bool StatusNotifierTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++
++	if ( t->service() == Yahoo::ServiceLogon ||
++		t->service() == Yahoo::ServiceLogoff ||
++		t->service() == Yahoo::ServiceIsAway ||
++		t->service() == Yahoo::ServiceIsBack ||
++		t->service() == Yahoo::ServiceGameLogon ||
++		t->service() == Yahoo::ServiceGameLogoff ||
++		t->service() == Yahoo::ServiceIdAct ||
++		t->service() == Yahoo::ServiceIddeAct ||
++		t->service() == Yahoo::ServiceStatus ||
++		t->service() == Yahoo::ServiceStealthOffline ||
++		t->service() == Yahoo::ServiceAuthorization
++	)
++		return true;
++	else
++		return false;
++}
++
++void StatusNotifierTask::parseStatus( YMSGTransfer* t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	if( t->status() == Yahoo::StatusDisconnected && 
++		t->service() == Yahoo::ServiceLogoff )
++	{
++		emit loginResponse( Yahoo::LoginDupl, QString::null );
++	}
++
++	QString	myNick;		/* key = 1 */
++	QString customError;	/* key = 16  */
++	QString nick;		/* key = 7  */
++	int state;		/* key = 10  */
++	QString message;	/* key = 19  */
++	int flags;		/* key = 13  */
++	int away;		/* key = 47  */
++	int idle;		/* key = 137 */
++	bool utf;		/* key = 97 */
++
++	customError = t->firstParam( 16 );
++	if( !customError.isEmpty() )
++		client()->notifyError( i18n("An unknown error has occured."), customError, Client::Warning );
++
++	myNick = t->firstParam( 1 );
++	
++	for( int i = 0; i < t->paramCount( 7 ); ++i)
++	{
++		nick = t->nthParam( 7, i );
++		state = t->nthParamSeparated( 10, i, 7 ).toInt();
++		flags = t->nthParamSeparated( 13, i, 7 ).toInt();
++		away = t->nthParamSeparated( 47, i, 7 ).toInt();
++		idle = t->nthParamSeparated( 137, i, 7 ).toInt();
++		utf = t->nthParamSeparated( 97, i, 7 ).toInt() == 1;
++		if( utf )
++			message = QString::fromUtf8( t->nthParamSeparated( 19, i, 7 ) );
++		else
++			message = t->nthParamSeparated( 19, i, 7 );
++
++		if( t->service() == Yahoo::ServiceLogoff || ( state != 0 && flags == 0 ) )
++			emit statusChanged( nick, Yahoo::StatusOffline, QString::null, 0, 0 );
++		else
++			emit statusChanged( nick, state, message, away, idle );
++	}
++}
++
++void StatusNotifierTask::parseAuthorization( YMSGTransfer* t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString nick;		/* key = 4  */	
++	QString msg;		/* key = 14  */
++	int state;		/* key = 13  */
++	bool utf;		/* key = 97 */
++
++	utf = t->firstParam( 97 ).toInt() == 1;
++	nick = t->firstParam( 4 );
++	if( utf )
++		msg = QString::fromUtf8( t->firstParam( 14 ) );
++	else
++		msg = t->firstParam( 14 );
++	state = t->firstParam( 13 ).toInt();
++
++	if( state == 1 )
++	{
++		emit( authorizationAccepted( nick ) );
++	}
++	else if( state == 2 )
++	{
++		emit( authorizationRejected( nick, msg ) );
++	}
++	else	// This is a request
++	{
++		QString fname = t->firstParam( 216 );
++		QString lname = t->firstParam( 254 );
++		QString name;
++		if( !fname.isEmpty() || !lname.isEmpty() )
++			name = QString("%1 %2").arg(fname).arg(lname);
++
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Emitting gotAuthorizationRequest( " << nick<< ", " << msg << ", " << name << " )" << endl;
++		emit gotAuthorizationRequest( nick, msg, name );
++	}
++}
++
++void StatusNotifierTask::parseStealthStatus( YMSGTransfer* t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString nick;		/* key = 7  */
++	int state;		/* key = 31  */
++
++	nick = t->firstParam( 7 );
++	state = t->firstParam( 31 ).toInt();
++
++	emit stealthStatusChanged( nick, ( state == 1 ) ? Yahoo::StealthActive : Yahoo::StealthNotActive );
++}
++
++#include "statusnotifiertask.moc"
+--- kopete/protocols/yahoo/libkyahoo/chatsessiontask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/chatsessiontask.cpp	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++    Kopete Yahoo Protocol
++    chatsessiontask.cpp - Register / Unregister a chatsession
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "chatsessiontask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++ChatSessionTask::ChatSessionTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++ChatSessionTask::~ChatSessionTask()
++{
++}
++
++void ChatSessionTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer( Yahoo::ServiceChatSession );
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	t->setParam( 5, m_target.local8Bit() );
++	if( m_type == RegisterSession )
++	{
++		t->setParam( 13, 1 );
++	}
++	else
++	{
++		t->setParam( 13, 2 );
++		t->setParam( 34, 1 );
++	}
++	send( t );
++	
++	setSuccess( true );
++}
++
++void ChatSessionTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void ChatSessionTask::setType( Type type )
++{
++	m_type = type;
++}
+--- kopete/protocols/yahoo/libkyahoo/sendnotifytask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendnotifytask.h	(revision 586398)
+@@ -0,0 +1,48 @@
++/*
++    Kopete Yahoo Protocol
++    Send a notification
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SENDNOTIFYTASK_H
++#define SENDNOTIFYTASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class SendNotifyTask : public Task
++{
++Q_OBJECT
++public:
++	enum Type { NotifyTyping, NotifyWebcamInvite, NotifyGame };
++	enum State { Active = 1, NotActive = 0 };
++
++	SendNotifyTask(Task *parent);
++	~SendNotifyTask();
++	
++	virtual void onGo();
++
++	void setType( Type type );
++	void setTarget( const QString &to );
++	void setState( State );
++private:
++	QString m_target;
++	Type m_type;
++	State m_state;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/coreprotocol.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/coreprotocol.cpp	(revision 586398)
+@@ -0,0 +1,228 @@
++/*
++    Kopete Yahoo Protocol
++    
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    
++    Based on code 
++    Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <string.h>
++#include <iostream>
++
++#include <qdatastream.h>
++#include <qdatetime.h>
++#include <qtextstream.h>
++
++
++#include <kdebug.h>
++#include <kurl.h>
++
++#include "coreprotocol.h"
++#include "ymsgprotocol.h"
++#include "ymsgtransfer.h"
++
++CoreProtocol::CoreProtocol() : QObject()
++{
++	m_YMSGProtocol = new YMSGProtocol( this, "ymsgprotocol" );
++}
++
++CoreProtocol::~CoreProtocol() 
++{
++}
++
++int CoreProtocol::state()
++{
++	return m_state;
++}
++
++void CoreProtocol::addIncomingData( const QByteArray & incomingBytes )
++{
++	// store locally
++	int oldsize = m_in.size();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << incomingBytes.size() << " bytes. already had " << oldsize << " bytes" << endl;
++	
++	m_in.resize( oldsize + incomingBytes.size() );
++	memcpy( m_in.data() + oldsize, incomingBytes.data(), incomingBytes.size() );
++	
++	m_state = Available;
++	// convert every event in the chunk to a Transfer, signalling it back to the clientstream
++	
++	int parsedBytes = 0;
++	int transferCount = 0;
++	// while there is data left in the input buffer, and we are able to parse something out of it
++	
++	while ( m_in.size() && ( parsedBytes = wireToTransfer(m_in) ) )
++	{
++		transferCount++;
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " parsed transfer " <<  transferCount << " in chunk of "<< parsedBytes << " bytes" << endl; 
++		int size =  m_in.size();
++		if ( parsedBytes < size )
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " more data in chunk! ( I have parsed " << parsedBytes << " and total data of " << size << ")" << endl;
++			// copy the unparsed bytes into a new qbytearray and replace m_in with that
++			QByteArray remainder( size - parsedBytes );
++			memcpy( remainder.data(), m_in.data() + parsedBytes, remainder.size() );
++			m_in = remainder;
++		}
++		else
++			m_in.truncate( 0 );
++	}
++	if ( m_state == NeedMore )
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " message was incomplete, waiting for more..." << endl;
++	/*
++	if ( m_eventProtocol->state() == EventProtocol::OutOfSync )
++	{	
++		qDebug( " - protocol thinks it's out of sync, discarding the rest of the buffer and hoping the server regains sync soon..." );
++		m_in.truncate( 0 );
++	}
++	*/
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " done processing chunk" << endl;
++	
++}
++
++Transfer* CoreProtocol::incomingTransfer()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;	
++	if ( m_state == Available )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - got a transfer" << endl;
++		m_state = NoData;
++		return m_inTransfer;
++		m_inTransfer = 0;
++	}
++	else
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " no milk today" << endl;
++		return 0;
++	}
++}
++
++void cp_dump( const QByteArray &bytes )
++{
++#ifdef YAHOO_COREPROTOCOL_DEBUG
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " contains " << bytes.count() << " bytes" << endl;
++	for ( uint i = 0; i < bytes.count(); ++i )
++	{
++		printf( "%02x ", bytes[ i ] );
++	}
++	printf( "\n" );
++#else
++	Q_UNUSED( bytes );
++#endif
++}
++
++void CoreProtocol::outgoingTransfer( Transfer* outgoing )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	if ( outgoing->type() == Transfer::YMSGTransfer )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " got YMSGTransfer" << endl;
++		YMSGTransfer *yt = (YMSGTransfer *) outgoing;
++		QByteArray bytesOut = yt->serialize();
++		
++		//QTextStream dout( bytesOut, IO_WriteOnly );
++		//dout.setEncoding( QTextStream::Latin1 );
++		//dout.setByteOrder( QDataStream::LittleEndian );
++		//dout << bytesOut;
++		//kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " " << bytesOut << endl;
++		emit outgoingData( bytesOut );
++		// now convert 
++		//fieldsToWire( fields );
++	}
++	delete outgoing;
++}
++
++
++
++int CoreProtocol::wireToTransfer( const QByteArray& wire )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	// processing incoming data and reassembling it into transfers
++	// may be an event or a response
++	
++	uint bytesParsed = 0;
++			
++	if ( wire.size() < 20 ) // minimal value of a YMSG header
++	{
++		m_state = NeedMore;
++		return bytesParsed;
++	}
++	
++	QDataStream din( wire, IO_ReadOnly );
++	
++	// look at first four bytes and decide what to do with the chunk
++	if ( okToProceed( din ) )
++	{
++		if ( (wire[0] == 'Y') && (wire[1] == 'M') && (wire[2] == 'S') && (wire[3] == 'G'))
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - looks like a valid YMSG packet" << endl;
++			Transfer *t = m_YMSGProtocol->parse( wire, bytesParsed );
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - YMSG Protocol parsed " << bytesParsed << " bytes" << endl;
++			if ( t )
++			{
++				m_inTransfer = t;
++				kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - got a valid packet " << endl;
++				
++				m_state = Available;
++				emit incomingData();
++			}
++			else
++				bytesParsed = 0;
++		}
++		else 
++		{ 
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - not a valid YMSG packet. Trying to recover." << endl;
++			QTextStream s( wire, IO_ReadOnly );
++			QString remaining = s.read();
++			int pos = remaining.find( "YMSG", bytesParsed );
++			if( pos >= 0 )
++			{
++				kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Recover successful." << endl;
++				bytesParsed += pos;
++			}
++			else
++			{
++				kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Recover failed. Dump it!" << endl;
++				bytesParsed = wire.size();
++			}
++		}
++	}
++	return bytesParsed;
++}
++
++void CoreProtocol::reset()
++{
++	m_in.resize( 0 );
++}
++
++void CoreProtocol::slotOutgoingData( const QCString &out )
++{
++	qDebug( "%s", out.data() );
++}
++
++bool CoreProtocol::okToProceed( QDataStream &din)
++{
++	if ( din.atEnd() )
++	{
++		m_state = NeedMore;
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " saved message prematurely" << endl;
++		return false;
++	}
++	else
++		return true;
++}
++
++#include "coreprotocol.moc"
+--- kopete/protocols/yahoo/libkyahoo/requestpicturetask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/requestpicturetask.h	(revision 586398)
+@@ -0,0 +1,41 @@
++/*
++    Kopete Yahoo Protocol
++    Request a Picture of a Buddy
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef REQUESTPICTURETASK_H
++#define REQUESTPICTURETASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class RequestPictureTask : public Task
++{
++Q_OBJECT
++public:
++	RequestPictureTask(Task *parent);
++	~RequestPictureTask();
++	
++	virtual void onGo();
++	
++	void setTarget( const QString &target );
++private:
++	QString m_target;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/changestatustask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/changestatustask.cpp	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++    Kopete Yahoo Protocol
++    Change our Status
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "changestatustask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++ChangeStatusTask::ChangeStatusTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++ChangeStatusTask::~ChangeStatusTask()
++{
++}
++
++void ChangeStatusTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	if( m_status == Yahoo::StatusInvisible )			// status --> Invisible
++	{
++		sendVisibility( Invisible );
++	}
++	else
++	{
++		YMSGTransfer *t = new YMSGTransfer( Yahoo::ServiceStatus );
++		t->setId( client()->sessionID() );
++
++		if( !m_message.isEmpty() )
++		{
++			m_status = Yahoo::StatusCustom;
++			t->setParam( 19, m_message.utf8() );
++		}
++		t->setParam( 10, m_status );
++		t->setParam( 47, m_type );
++		t->setParam( 97, 1 );	// it's utf8
++			
++		send( t );
++
++		if( client()->status() == Yahoo::StatusInvisible )	// Invisible --> Status
++			sendVisibility( Visible );
++	}
++	setSuccess( true );
++}
++
++void ChangeStatusTask::sendVisibility( Visibility visible )
++{
++	YMSGTransfer *t = new YMSGTransfer( Yahoo::ServiceVisibility );
++	t->setId( client()->sessionID() );
++	t->setParam( 13, visible );
++	send( t );
++}
++
++void ChangeStatusTask::setMessage( const QString &msg )
++{
++	m_message = msg;
++}
++
++void ChangeStatusTask::setStatus( Yahoo::Status status )
++{
++	m_status = status;
++}
++
++void ChangeStatusTask::setType( Yahoo::StatusType type )
++{
++	m_type = type;
++}
+--- kopete/protocols/yahoo/libkyahoo/sendmessagetask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendmessagetask.cpp	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++    Kopete Yahoo Protocol
++    Send a message
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "sendmessagetask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++SendMessageTask::SendMessageTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++SendMessageTask::~SendMessageTask()
++{
++}
++
++void SendMessageTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	if( m_text.isEmpty() )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Text to send is empty." << endl;
++		client()->notifyError( i18n( "An error occured sending the message" ), i18n( "The message is empty." ), Client::Debug );
++		return;
++	}	
++	uint pos=0;
++	
++	// split messages that are longer than 800 chars. they get dropped otherwise
++	while( pos < m_text.length() )
++	{
++		YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceMessage, Yahoo::StatusOffline);
++		t->setId( client()->sessionID() );
++		t->setParam( 1, client()->userId().local8Bit() );
++		t->setParam( 5, m_target.local8Bit() );
++		t->setParam( 14, m_text.mid( pos, 700).utf8() );
++		t->setParam( 63, ";0" );
++		t->setParam( 64, "0"  );	
++		t->setParam( 97, 1 );	// UTF-8
++		t->setParam( 206, client()->pictureFlag() );	
++		send( t );
++
++		pos += 700;
++	}
++	
++	setSuccess( true );
++}
++
++void SendMessageTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void SendMessageTask::setText( const QString &text )
++{
++	m_text = text;
++}
++
++void SendMessageTask::setPicureFlag( int flag )
++{
++	m_pictureFlag = flag;
++}
+--- kopete/protocols/yahoo/libkyahoo/sendfiletask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendfiletask.h	(revision 586398)
+@@ -0,0 +1,68 @@
++/*
++    Kopete Yahoo Protocol
++    Send a file
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SENDFILETASK_H
++#define SENDFILETASK_H
++
++#include "task.h"
++#include <kurl.h>
++#include <qfile.h>
++
++class QString;
++namespace KNetwork{
++	class KStreamSocket;
++}
++
++/**
++ at author André Duffeck
++*/
++class SendFileTask : public Task
++{
++	Q_OBJECT
++public:
++	SendFileTask(Task *parent);
++	~SendFileTask();
++	
++	virtual void onGo();
++	
++	void setTarget( const QString &to );
++	void setMessage( const QString &msg );
++	void setFileUrl( KURL url );
++	void setTransferId( unsigned int transferId );
++
++signals:
++	void bytesProcessed( unsigned int, unsigned int );
++	void complete( unsigned int );
++	void error( unsigned int, int, const QString & );
++
++private slots:
++	void initiateUpload();
++	void connectSucceeded();
++	void connectFailed( int );
++	void transmitData();
++	void canceled( unsigned int );
++
++private:
++	QString m_msg;
++	QString m_target;
++	KURL m_url;
++	QFile m_file;
++	unsigned int m_transferId;
++	unsigned int m_transmitted;
++	KNetwork::KStreamSocket *m_socket;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/tests/clientstream_test.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/tests/clientstream_test.h	(revision 586398)
+@@ -0,0 +1,49 @@
++//
++// C++ Implementation: clientstream_test
++//
++// Description: 
++//
++//
++// Author: Kopete Developers <kopete-devel at kde.org>, (C) 2004
++// Licensed under the GNU General Public License
++
++#ifndef clientstream_test_h
++#define clientstream_test_h
++
++#include <qglobal.h>
++#include <qapplication.h>
++#include <qtimer.h>
++
++#include "yahooclientstream.h"
++#include "yahooconnector.h"
++
++#include "coreprotocol.h"
++
++#define QT_FATAL_ASSERT 1
++
++class ClientStreamTest : public QApplication
++{
++Q_OBJECT
++public:
++	ClientStreamTest(int argc, char ** argv);
++	
++	~ClientStreamTest();
++	
++	bool isConnected();
++
++public slots:
++	void slotDoTest();
++	
++	void slotConnected();
++	
++	//void slotWarning(int warning);
++
++	//void slotsend(int layer);
++
++private:
++	KNetworkConnector *myConnector;
++	ClientStream *myTestObject;
++	bool connected;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/tests/Makefile.am	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/tests/Makefile.am	(revision 586398)
+@@ -0,0 +1,9 @@
++INCLUDES = -I$(top_srcdir)/kopete/protocols/yahoo/libkyahoo -I../ $(all_includes)
++METASOURCES = AUTO
++check_PROGRAMS = clientstream_test
++
++clientstream_test_SOURCES = clientstream_test.cpp
++clientstream_test_LDADD = $(LIB_QT) $(LIB_KDECORE) ../libkyahoo.la
++
++#login_test_SOURCES = logintest.cpp
++#login_test_LDADD = $(LIB_QT) $(LIB_KDECORE) ../libkyahoo.la
+--- kopete/protocols/yahoo/libkyahoo/tests/logintest.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/tests/logintest.cpp	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++    Kopete Yahoo Protocol Tests
++    
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    
++    Based on code 
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "logintest.h"
++#include <kdebug.h>
++#include "../ymsgtransfer.h"
++#include "../yahootypes.h"
++
++LoginTest::LoginTest(int argc, char ** argv) : QApplication( argc, argv )
++{
++	// set up client stream
++	myConnector = new KNetworkConnector( 0 );
++	//myConnector->setOptHostPort( "localhost", 8300 );
++	myConnector->setOptHostPort( "scs.msg.yahoo.com", 5050 );
++	myClientStream = new ClientStream( myConnector, myConnector);
++	// notify when the transport layer is connected
++	myClient = new Client();
++	// do test once the event loop is running
++	QTimer::singleShot( 0, this, SLOT( slotDoTest() ) );
++	connected = false;
++}
++
++LoginTest::~LoginTest()
++{
++	delete myClientStream;
++	delete myConnector;
++	delete myClient;
++}
++
++void LoginTest::slotDoTest()
++{
++	QString server = QString::fromLatin1("scs.msg.yahoo.com");
++	// connect to server
++	kdDebug(14180) << k_funcinfo << " connecting to server" << endl;
++	
++	connect( myClient, SIGNAL( connected() ), SLOT( slotConnected() ) );
++	myClient->start( server, 5050, "duncanmacvicar", "**********" );
++	myClient->connectToServer( myClientStream, server, true );
++}
++
++void LoginTest::slotConnected()
++{	
++	kdDebug(14180) << k_funcinfo << " connection is up" << endl;
++	connected = true;
++}
++
++int main(int argc, char ** argv)
++{
++	LoginTest a( argc, argv );
++	a.exec();
++	if ( !a.isConnected() )
++		return 0;
++}
++
++#include "logintest.moc"
+--- kopete/protocols/yahoo/libkyahoo/tests/clientstream_test.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/tests/clientstream_test.cpp	(revision 586398)
+@@ -0,0 +1,57 @@
++//Licensed under the GNU General Public License
++
++#include "clientstream_test.h"
++#include <kdebug.h>
++#include "../ymsgtransfer.h"
++#include "../yahootypes.h"
++
++ClientStreamTest::ClientStreamTest(int argc, char ** argv) : QApplication( argc, argv )
++{
++	// set up client stream
++	myConnector = new KNetworkConnector( 0 );
++	//myConnector->setOptHostPort( "localhost", 8300 );
++	myConnector->setOptHostPort( "scs.msg.yahoo.com", 5050 );
++	myTestObject = new ClientStream( myConnector, myConnector);
++	// notify when the transport layer is connected
++	connect( myTestObject, SIGNAL( connected() ), SLOT( slotConnected() ) );
++	// notify and start sending
++	//connect( myTestObject, SIGNAL( warning(int) ), SLOT( slotWarning(int) ) );
++
++	// do test once the event loop is running
++	QTimer::singleShot( 0, this, SLOT( slotDoTest() ) );
++	connected = false;
++}
++
++ClientStreamTest::~ClientStreamTest()
++{
++	delete myTestObject;
++	delete myConnector;
++}
++
++void ClientStreamTest::slotDoTest()
++{
++	QString server = QString::fromLatin1("scs.msg.yahoo.com");
++	// connect to server
++	kdDebug(14180) << k_funcinfo << " connecting to server" << endl;
++	myTestObject->connectToServer( server, true ); // fine up to here...
++}
++
++void ClientStreamTest::slotConnected()
++{
++	kdDebug(14180) << k_funcinfo << " connection is up" << endl;
++	connected = true;
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceLogon);
++	t->setParam( 1, "kopetetest");
++	
++	myTestObject->write(t);
++	while(1);
++}
++
++int main(int argc, char ** argv)
++{
++	ClientStreamTest a( argc, argv );
++	a.exec();
++	return 0;
++}
++
++#include "clientstream_test.moc"
+--- kopete/protocols/yahoo/libkyahoo/tests/logintest.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/tests/logintest.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++    Kopete Yahoo Protocol
++    
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    
++    Based on code 
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef logintest_h
++#define logintest_h
++
++#include <qglobal.h>
++#include <qapplication.h>
++#include <qtimer.h>
++
++#include "client.h"
++#include "coreprotocol.h"
++#include "yahooclientstream.h"
++#include "yahooconnector.h"
++
++#include "coreprotocol.h"
++
++#define QT_FATAL_ASSERT 1
++
++class LoginTest : public QApplication
++{
++Q_OBJECT
++public:
++	LoginTest(int argc, char ** argv);
++	
++	~LoginTest();
++	
++	bool isConnected() { return connected; }
++
++public slots:
++	void slotDoTest();
++	
++	void slotConnected();
++	
++	//void slotWarning(int warning);
++
++	//void slotsend(int layer);
++
++private:
++	KNetworkConnector *myConnector;
++	ClientStream *myClientStream;
++	Client* myClient;
++
++	bool connected;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/client.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/client.h	(revision 586398)
+@@ -0,0 +1,613 @@
++/*
++    Kopete Yahoo Protocol
++    
++    Copyright (c) 2005-2006 André Duffeck <andre.duffeck at kdemail.net>
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++    Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef LIBYAHOO_CLIENT_H
++#define LIBYAHOO_CLIENT_H
++
++#include <qobject.h>
++
++#include "transfer.h"
++#include "yahootypes.h"
++
++#define YMSG_PROGRAM_VERSION_STRING "7,5,0,33"
++
++class QString;
++class QTimer;
++class ClientStream;
++class KNetworkConnector;
++class Task;
++class KURL;
++class KTempFile;
++class YABEntry;
++class SendFileTask;
++
++class Client : public QObject
++{
++Q_OBJECT
++
++	public:
++	
++		/*************
++		  EXTERNAL API 
++		 *************/
++
++		enum LogLevel { Debug, Info, Notice, Warning, Error, Critical }; 
++		  
++		Client(QObject *parent=0);
++		~Client();
++		void setUserId( const QString& userName );
++
++		/**
++		 * Start a connection to the server using the supplied @ref ClientStream.
++		 * This is only a transport layer connection.
++		 * Needed for protocol action P1.
++		 * @param s initialised client stream to use for the connection.
++		 * @param server the server to connect to - but this is also set on the connector used to construct the clientstream??
++		 * @param auth indicate whether we're connecting to the authorizer or the bos server
++		 */
++		void connect( const QString &host, const uint port, const QString &userId, const QString &pass );
++
++		/**
++		 * Cancel active login attemps
++		 */
++		void cancelConnect();
++
++		/**
++		 * Logout and disconnect
++		 */
++		void close();
++
++		/**
++		 * Returns the errorcode
++		 */
++		int error();
++
++		/**
++		 * Returns a description of the error
++		 */
++		QString errorString();
++
++		/**
++		 * Returns information about what went wrong
++		 */
++		QString errorInformation();
++
++		/**
++		 * Specifies the status we connect with. 
++		 * The Yahoo protocol supports connecting into Online and Invisible state.
++		 * If status is any other status the Client connects into Online state and changes into the specified state after the login. 
++		 * @param status the status to connect with
++		 */
++		void setStatusOnConnect( Yahoo::Status status );
++
++		/**
++		 * Specifies the status message we connect with.
++		 * The Yahoo protocol does not support connecting with a status message. If msg is not empty the Client
++		 * will change the status message after the login.
++		 * @param msg the status message to connect with
++		 */
++		void setStatusMessageOnConnect( const QString &msg );
++
++		/**
++		 * Accessors needed for login
++		 */
++		QString host();
++		int port();
++
++		/**
++		 * Send a Typing notification
++		 * @param to the buddy that should be notified
++		 * @param typing true if there is typing activity, false if not
++		 */
++		void sendTyping( const QString &to, bool typing );
++		
++		/**
++		 * Send a Message
++		 * @param to the buddy that should receive the message
++		 * @param msg the message
++		 */
++		void sendMessage( const QString &to, const QString &msg );
++
++		/**
++		 * Register / Unregister a chatsession
++		 * @param to the buddy, the chatsession belongs to 
++		 * @param close if true, the chatsession will be closed, if false, it will be opened
++		 */
++		void setChatSessionState( const QString &to, bool close );
++
++		/**
++		 * Send a Buzz
++		 * @param to the buddy that should receive the buzz
++		 */
++		void sendBuzz( const QString &to );
++
++		/**
++		 * Change our status
++		 * @param status the status that will be set
++		 * @param message the status message that will be set
++		 * @param type Yahoo::StatusTypeAvailable means that the user is available, Yahoo::StatusTypeAway means that the user is away from the keyboard
++		 */	
++		void changeStatus(Yahoo::Status status, const QString &message, Yahoo::StatusType type);
++
++		/**
++		 * Set the verification word that is needed for a account verification after
++		 * too many wrong login attempts.
++		 * @param word the verification word
++		 */
++		void setVerificationWord( const QString &word );
++
++		/**
++		 * Add a buddy to the contact list
++		 * @param userId the yahoo ID of the buddy that should be added
++		 * @param group the group where the buddy will be placed
++		 * @param message the message that will be sent to the buddy along the authorization request
++		 */
++		void addBuddy( const QString &userId, const QString &group, const QString &message = QString::fromLatin1("Please add me")  );
++
++		/**
++		 * Remove a buddy from the contact list
++		 */
++		void removeBuddy( const QString &userId, const QString &group );
++
++		/**
++		 * Move a buddy into another group
++		 */
++		void moveBuddy( const QString &userId, const QString &oldGroup, const QString &newGroup );
++
++		/**
++		 * Change the stealth status of a buddy
++		 */
++		void stealthContact( QString const &userId, Yahoo::StealthMode mode, Yahoo::StealthStatus state );
++
++		/**
++		 * Request the buddy's picture
++		 */
++		void requestPicture( const QString &userId );
++
++		/**
++		 * Download the buddy's picture
++		 */
++		void downloadPicture( const QString &userId, KURL url, int checksum );
++
++		/**
++		 * Send our picture
++		 */
++		void uploadPicture( KURL url );
++
++		/**
++		 * Send checksum of our picture
++		 */
++		void sendPictureChecksum( int checksum, const QString & );
++
++		/**
++		 * Send information about our picture
++		 */
++		void sendPictureInformation( const QString &userId, const QString &url, int checksum );
++
++		/**
++		 * Notify the buddies about our new status
++		 */
++		void sendPictureStatusUpdate( const QString &userId, int type );
++
++		/**
++		 * Send a response to the webcam invite ( Accept / Decline )
++		 */
++		void requestWebcam( const QString &userId );
++
++		/**
++		 * Stop receiving of webcam
++		 */
++		void closeWebcam( const QString &userId );
++
++		/**
++		 * Invite the user to view your Webcam
++		 */
++		void sendWebcamInvite( const QString &userId );
++
++		/**
++		 * transmit a new image to the watchers
++		 */
++		void sendWebcamImage( const QByteArray &image );
++
++		/**
++		 * Stop transmission
++		 */
++		void closeOutgoingWebcam();
++
++		/**
++		 * Allow a buddy to watch the cam
++		 */
++		void grantWebcamAccess( const QString &userId );
++
++		/**
++		 * Invite buddies to a conference
++		 */
++		void inviteConference( const QString &room, const QStringList &members, const QString &msg );
++
++		/**
++		 * Invite buddies to a already existing conference
++		 */
++		void addInviteConference( const QString &room, const QStringList &who, const QStringList &members, const QString &msg );
++
++		/**
++		 * Join a conference
++		 */
++		void joinConference( const QString &room, const QStringList &members );
++
++		/**
++		 * Decline to join a conference
++		 */
++		void declineConference( const QString &room, const QStringList &members, const QString &msg );
++
++		/**
++		 * Leave the conference
++		 */
++		void leaveConference( const QString &room, const QStringList &members );
++
++		/**
++		 * Send a message to the conference
++		 */
++		void sendConferenceMessage( const QString &room, const QStringList &members, const QString &msg );
++
++		/**
++		 * Send a authorization request response
++		 */
++		void sendAuthReply( const QString &userId, bool accept, const QString &msg );
++
++		/**
++		 * Fetches all entries of the YAB
++		 */
++		void getYABEntries( long lastMerge, long lastRemoteRevision );
++
++		/**
++		 * Saves a modified YAB entry
++		 */
++		void saveYABEntry( YABEntry &entry );
++
++		/**
++		 * Creates a new YAB entry
++		 */
++		void addYABEntry( YABEntry &entry );
++
++		/**
++		 * Deletes a YAB entry
++		 */
++		void deleteYABEntry( YABEntry &entry );
++
++		/**
++		 * Send a file to a buddy
++		 */
++		void sendFile( unsigned int transferId, const QString &userId, const QString &msg, KURL url );
++
++		/**
++		 * Receive a file from a buddy
++		 */
++		void receiveFile( unsigned int transferId, const QString &userId, KURL remoteURL, KURL localURL );
++
++		/**
++		 * Reject a file offered by a buddy
++		 */
++		void rejectFile( const QString &userId, KURL remoteURL );
++
++		/**
++		 * The user canceled the filetransfer
++		 */
++		void cancelFileTransfer( unsigned int transferId );	
++
++		/*************
++		  INTERNAL (FOR USE BY TASKS) METHODS 
++		 *************/
++		/**
++		 * Send an outgoing request to the server
++		 */
++		void send( Transfer *request );
++		
++		/**
++		 * Print a debug statement
++		 */
++		void debug( const QString &str );
++		
++		/**
++		 * The current user's user ID
++		 */
++		QString userId();
++		
++		/**
++		 * The current user's password
++		 */
++		QString password();
++		
++		/**
++		 * Host's IP address
++		 */
++		QCString ipAddress();
++		
++		/**
++		 * current Session ID
++		 */
++		uint sessionID();
++		
++		/**
++		 * return the pictureFlag describing the status of our buddy icon
++		 * 0 = no icon, 2 = icon, 1 = avatar (?)
++		 */
++		int pictureFlag();
++
++		/**
++		 * Get our status
++		 */
++		Yahoo::Status status();
++
++		/**
++		 * Set our status
++		 */
++		void setStatus( Yahoo::Status );
++
++		/**
++		 * Access the root Task for this client, so tasks may be added to it.
++		 */
++		Task* rootTask();
++
++		/**
++		 * Accessors to the cookies
++		 */
++		QString yCookie();
++		QString tCookie();
++		QString cCookie();
++
++		/**
++		 * Error
++		 */
++		void notifyError( const QString &info, const QString &errorString, LogLevel level );
++	signals:
++		/** CONNECTION EVENTS */
++		/**
++		 * Notifies that the login process has succeeded.
++		 */
++		void loggedIn( int, const QString& );
++
++		/** 
++		 * Notifies that the login process has failed 
++		 */
++		void loginFailed();
++		
++		/**
++		 * Notifies tasks and account so they can react properly
++		 */
++		void connected();
++		/**
++		 * Notifies tasks and account so they can react properly
++		 */
++		void disconnected();
++		/**
++		 * We were disconnected because we connected elsewhere
++		 */
++		void connectedElsewhere();
++
++		void error( int level );
++		/**
++		 * Notifies about our buddies and groups
++		 */
++		void gotBuddy( const QString &, const QString &, const QString & );
++		/**
++		 * Notifies about the status of online buddies
++		 */
++		void statusChanged( const QString&, int, const QString&, int, int );
++		/**
++		 * Notifies about the stealth status of buddies
++		 */
++		void stealthStatusChanged( const QString &, Yahoo::StealthStatus );
++		/**
++		 * Notifies about mails
++		 */
++		void mailNotify( const QString&, const QString&, int );
++		/**
++		 * We got a new message
++		 */
++		void gotIm( const QString&, const QString&, long, int );
++		/**
++		 * We got a new system message
++		 */
++		void systemMessage( const QString& );
++		/**
++		 * The buddy is typing a message
++		 */
++		void typingNotify( const QString &, int );
++		/**
++		 * The buddy has invited us to view his webcam
++		 */
++		void gotWebcamInvite(const QString &);
++		/**
++		 * Notifies about a BUZZ notification
++		 */
++		void gotBuzz( const QString &, long );
++		/**
++		 * Notifies about a changed picture status
++		 */
++		void pictureStatusNotify( const QString &, int );
++		/**
++		 * Notifies about a picture checksum
++		 */
++		void pictureChecksumNotify( const QString &, int );
++		/**
++		 * Notifies about a picture
++		 */
++		void pictureInfoNotify( const QString &, KURL, int );
++		/**
++		 * The iconLoader has successfully downloaded a picutre
++		 */
++		void pictureDownloaded( const QString &, KTempFile *, int );
++		/**
++		 * A Buddy asks for our picture
++		 */
++		void pictureRequest( const QString & );
++		/**
++		 * Information about the picture upload
++		 */
++		void pictureUploaded( const QString & );
++		/**
++		 * We've received a webcam image from a buddy
++		 */
++		void webcamImageReceived( const QString &, const QPixmap &);
++		/**
++		 * The requested Webcam is not available
++		 */
++		void webcamNotAvailable( const QString & );
++		/**
++		 * The connection to the webcam was closed
++		 */
++		void webcamClosed( const QString &, int );
++		/**
++		 * The webcamtransmission is paused
++		 */
++		void webcamPaused(const QString&);
++		/**
++		 * The webcam connection is ready for transmission
++		 */
++		void webcamReadyForTransmission();
++		/**
++		 * The webcam should stop sending images
++		 */
++		void webcamStopTransmission();
++		/**
++		 * A new buddy watches the cam
++		 */
++		void webcamViewerJoined( const QString & );
++		/**
++		 * A buddy no longer watches the cam
++		 */
++		void webcamViewerLeft( const QString & );
++		/**
++		 * A buddy wants to watch the cam
++		 */
++		void webcamViewerRequest( const QString & );
++		/**
++		 * A buddy invited us to a conference
++		 */
++		void gotConferenceInvite( const QString &, const QString &, const QString &, const QStringList & );
++		/**
++		 * A conference message was received
++		 */
++		void gotConferenceMessage( const QString &, const QString &, const QString & );
++		/**
++		 * A buddy joined the conference
++		 */
++		void confUserJoined( const QString &, const QString & );
++		/**
++		 * A buddy left the conference
++		 */
++		void confUserLeft( const QString &, const QString & );
++		/**
++		 * A buddy declined to join the conference
++		 */
++		void confUserDeclined( const QString &, const QString &, const QString & );
++		/**
++		 * A buddy accepted our authorization request
++		 */
++		void authorizationAccepted( const QString & );
++		/**
++		 * A buddy rejected our authorization request
++		 */
++		void authorizationRejected( const QString &, const QString & );
++		/**
++		 * A buddy requests authorization
++		 */
++		void gotAuthorizationRequest( const QString &, const QString &, const QString & );
++		/**
++		 * A revision of the Yahoo Addressbook was received
++		 */
++		void gotYABRevision( long rev, bool merged );
++		/**
++		 * A entry from the Yahoo Addressbook was retrieved
++		 */
++		void gotYABEntry( YABEntry * );
++		/**
++		 * An error occured while saving a Yahoo Addressbook entry
++		 */
++		void modifyYABEntryError( YABEntry *, const QString & );
++		/**
++		 * number of Bytes transferred for FileTransfer id
++		 */
++		void fileTransferBytesProcessed( unsigned int, unsigned int );
++		/**
++		 * filetransfer completed
++		 */
++		void fileTransferComplete( unsigned int );
++		/**
++		 * An error occured during the filetransfer
++		 */
++		void fileTransferError( unsigned int, int, const QString & );
++		/**
++		 * filetransfer canceled
++		 */
++		void fileTransferCanceled( unsigned int );
++		/**
++		 * A buddy is trying to send us a file
++		 */
++		void incomingFileTransfer( const QString &, const QString &, long, const QString &,
++			const QString &, unsigned long );
++	protected slots:
++		// INTERNAL, FOR USE BY TASKS' finished() SIGNALS //
++		void lt_loginFinished();
++		void lt_gotSessionID( uint );
++		void cs_connected();
++		void slotGotCookies();
++		
++		/**
++		 * Used by tasks to identify a response to a login attempt
++		 */
++		void slotLoginResponse( int, const QString& );
++
++		/**
++		 * Used by the client stream to notify errors to upper layers.
++		 */
++		void streamError( int error );
++		
++		/**
++		 * The client stream has data ready to read.
++		 */
++		void streamReadyRead();
++
++		/**
++		 * Send a Yahoo Ping packet to the server
++		 */
++		void sendPing();
++	private:
++		void distribute( Transfer *transfer );
++		
++		/**
++		 * create static tasks and connect their signals
++		 */
++		void initTasks();
++
++		/**
++		 * remove static tasks and their singal connections
++		 */
++		void deleteTasks();
++
++		class ClientPrivate;
++		ClientPrivate* d;
++		KNetworkConnector *m_connector;
++
++		QTimer *m_pingTimer;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/stealthtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/stealthtask.cpp	(revision 586398)
+@@ -0,0 +1,76 @@
++/*
++    Kopete Yahoo Protocol
++    Stealth/Unstealth a buddy
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "stealthtask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++
++StealthTask::StealthTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++StealthTask::~StealthTask()
++{
++}
++
++void StealthTask::onGo()
++{
++	YMSGTransfer *t = new YMSGTransfer();
++	if( m_mode == Yahoo::StealthOnline )
++	{
++		t->setService( Yahoo::ServiceStealthOnline );
++		t->setParam( 13, "1" );
++		t->setParam( 31, m_state );	
++	}
++	else if( m_mode == Yahoo::StealthOffline )
++	{
++		t->setService( Yahoo::ServiceStealthOffline );
++		t->setParam( 13, "1" );
++		t->setParam( 31, m_state );
++	}
++	else if( m_mode == Yahoo::StealthPermOffline )
++	{
++		t->setService( Yahoo::ServiceStealthOffline );
++		t->setParam( 13, "2" );
++		t->setParam( 31, m_state );
++	}
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit());
++	if( !m_target.isEmpty() )
++		t->setParam( 7, m_target.local8Bit() );
++	send( t );
++	
++	setSuccess( true );
++}
++
++void StealthTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void StealthTask::setState( Yahoo::StealthStatus state)
++{
++	m_state = state;
++}
++
++void StealthTask::setMode( Yahoo::StealthMode mode )
++{
++	m_mode = mode;
++}
+--- kopete/protocols/yahoo/libkyahoo/transfer.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/transfer.h	(revision 586398)
+@@ -0,0 +1,35 @@
++/*
++    transfer.h - Kopete Groupwise Protocol
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef TRANSFER_H
++#define TRANSFER_H
++
++/*class Buffer;*/
++
++class Transfer
++{
++public:
++        enum TransferType { YMSGTransfer };
++        Transfer();
++        virtual ~Transfer();
++
++        virtual TransferType type() = 0;
++
++};
++
++#endif
++
+--- kopete/protocols/yahoo/libkyahoo/conferencetask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/conferencetask.cpp	(revision 586398)
+@@ -0,0 +1,259 @@
++/*
++    Kopete Yahoo Protocol
++    Handles conferences
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "conferencetask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qstringlist.h>
++#include <kdebug.h>
++
++ConferenceTask::ConferenceTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++ConferenceTask::~ConferenceTask()
++{
++}
++
++bool ConferenceTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = 0L;
++	t = static_cast<YMSGTransfer*>(transfer);
++	
++ 	if( t->service() == Yahoo::ServiceConfInvite ||
++		t->service() == Yahoo::ServiceConfAddInvite)
++ 		parseInvitation( t );
++	else if( t->service() == Yahoo::ServiceConfMsg )
++		parseMessage( t );
++	else if( t->service() == Yahoo::ServiceConfLogon )
++		parseUserJoined( t );
++	else if( t->service() == Yahoo::ServiceConfLogoff )
++		parseUserLeft( t );
++	else if( t->service() == Yahoo::ServiceConfDecline )
++		parseUserDeclined( t );
++
++	return true;
++}
++
++bool ConferenceTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	if ( t->service() == Yahoo::ServiceConfInvite ||
++		t->service() == Yahoo::ServiceConfLogon ||
++		t->service() == Yahoo::ServiceConfDecline ||
++		t->service() == Yahoo::ServiceConfLogoff ||
++		t->service() == Yahoo::ServiceConfAddInvite ||
++		t->service() == Yahoo::ServiceConfMsg )	
++		return true;
++	else
++		return false;
++}
++
++void ConferenceTask::parseInvitation( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	int i = 0;
++	QString who = t->firstParam( 50 );
++	QString room = t->firstParam( 57 );
++	bool utf = QString( t->firstParam( 97 ) ).toInt() == 1;
++	QString msg;
++	if( utf )
++		msg = QString::fromUtf8( t->firstParam( 58 ) );
++	else
++		msg = t->firstParam( 58 );
++
++	QStringList members;
++	for( i = 0; i < t->paramCount( 52 ); i++ )
++		members.append( t->nthParam( 52, i ) );
++	for( i = 0; i < t->paramCount( 53 ); i++ )
++		members.append( t->nthParam( 53, i ) );
++	if( who == client()->userId() )
++		return;
++
++	if( !who.isEmpty() && !room.isEmpty() )
++		emit gotInvite( who, room, msg, members );
++}
++
++void ConferenceTask::parseMessage( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString room = t->firstParam( 57 );
++	QString from = t->firstParam( 3 );
++	bool utf = QString( t->firstParam( 97 ) ).toInt() == 1;
++	QString msg;
++	if( utf )
++		msg = QString::fromUtf8( t->firstParam( 14 ) );
++	else
++		msg = t->firstParam( 14 );
++
++	if( !msg.isEmpty() )
++		emit gotMessage( from, room, msg ); 
++}
++
++void ConferenceTask::parseUserJoined( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString room = t->firstParam( 57 );
++	QString who = t->firstParam( 53 );
++
++	if( !who.isEmpty() && !room.isEmpty() )
++		emit userJoined( who, room );
++}
++
++void ConferenceTask::parseUserLeft( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString room = t->firstParam( 57 );
++	QString who = t->firstParam( 56 );
++
++	if( !who.isEmpty() && !room.isEmpty() )
++		emit userLeft( who, room );
++}
++
++void ConferenceTask::parseUserDeclined( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString room = t->firstParam( 57 );
++	QString who = t->firstParam( 54 );
++	QString msg = t->firstParam( 14 );
++
++	if( !who.isEmpty() && !room.isEmpty() )
++		emit userDeclined( who, room, msg );
++}
++
++void ConferenceTask::inviteConference( const QString &room, const QStringList &members, const QString &msg )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfInvite);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	t->setParam( 50, client()->userId().local8Bit() );
++	t->setParam( 57, room.local8Bit() );
++	t->setParam( 58, msg.local8Bit() );
++	t->setParam( 97, 1 );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++		t->setParam( 52, (*it).local8Bit() );
++	t->setParam( 13, "0" );
++
++	send( t );
++}
++
++void ConferenceTask::addInvite( const QString &room, const QStringList &who, const QStringList &members, const QString &msg )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfAddInvite);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++
++	QString whoList = who.first();
++	for( uint i = 1; i < who.size(); i++ )
++		whoList += QString(",%1").arg( who[i] );
++	t->setParam( 51, whoList.local8Bit() );
++
++	t->setParam( 57, room.local8Bit() );
++	t->setParam( 58, msg.local8Bit() );
++	t->setParam( 97, 1 );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++	{
++		t->setParam( 52, (*it).local8Bit() );
++		t->setParam( 53, (*it).local8Bit() );	// Note: this field should only be set if the buddy has already joined the conference, but no harm is done this way
++	}
++	t->setParam( 13, "0" );
++
++	send( t );
++}
++
++void ConferenceTask::joinConference( const QString &room, const QStringList &members )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfLogon);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++		t->setParam( 3, (*it).local8Bit() );
++	t->setParam( 57, room.local8Bit() );
++
++	send( t );
++}
++
++void ConferenceTask::declineConference( const QString &room, const QStringList &members, const QString &msg )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfDecline);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++		t->setParam( 3, (*it).local8Bit() );
++	t->setParam( 57, room.local8Bit() );	
++	t->setParam( 14, msg.utf8() );
++	t->setParam( 97, 1 );
++
++	send( t );
++}
++void ConferenceTask::leaveConference( const QString &room, const QStringList &members )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfLogoff);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++		t->setParam( 3, (*it).local8Bit() );
++	t->setParam( 57, room.local8Bit() );
++
++	send( t );
++}
++
++void ConferenceTask::sendMessage( const QString &room, const QStringList &members, const QString &msg )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceConfMsg);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	for( QStringList::const_iterator it = members.begin(); it != members.end(); it++ )
++		t->setParam( 53, (*it).local8Bit() );
++	t->setParam( 57, room.local8Bit() );
++	t->setParam( 14, msg.utf8() );
++	t->setParam( 97, 1 );
++
++	send( t );
++}
++#include "conferencetask.moc"
+--- kopete/protocols/yahoo/libkyahoo/yahooclientstream.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahooclientstream.cpp	(revision 586398)
+@@ -0,0 +1,418 @@
++/*
++	oscarclientstream.cpp - Kopete Oscar Protocol
++	
++	Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++	
++	Based on code Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++	Based on Iris, Copyright (C) 2003  Justin Karneges
++	
++	Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++	
++	*************************************************************************
++	*                                                                       *
++	* This library is free software; you can redistribute it and/or         *
++	* modify it under the terms of the GNU Lesser General Public            *
++	* License as published by the Free Software Foundation; either          *
++	* version 2 of the License, or (at your option) any later version.      *
++	*                                                                       *
++	*************************************************************************
++*/
++
++
++
++#include <qapplication.h>  // for qdebug
++#include <qguardedptr.h> 
++#include <qobject.h>
++#include <qptrqueue.h>
++#include <qtimer.h>
++
++#include <kdebug.h>
++
++#include "bytestream.h"
++#include "connector.h"
++#include "coreprotocol.h"
++#include "transfer.h"
++
++#include "yahooclientstream.h"
++#include "yahootypes.h"
++
++void cs_dump( const QByteArray &bytes );
++
++enum {
++	Idle,
++	Connecting,
++	Active,
++	Closing
++};
++
++enum {
++	Client,
++	Server
++};
++
++class ClientStream::Private
++{
++public:
++	Private()
++	{
++		conn = 0;
++		bs = 0;
++		
++		username = QString::null;
++		password = QString::null;
++		server = QString::null;
++		haveLocalAddr = false;
++		doBinding = true;
++
++		reset();
++	}
++	void reset()
++	{
++		state = Idle;
++		notify = 0;
++		newTransfers = false;
++	}
++	
++	QString username;
++	QString password;
++	QString server;
++	bool doAuth; //send the initial login sequences to get the cookie
++	bool haveLocalAddr;
++	QHostAddress localAddr;
++	Q_UINT16 localPort;
++	bool doBinding;
++
++	Connector *conn;
++	ByteStream *bs;
++	CoreProtocol client;
++
++	QString defRealm;
++
++	int mode;
++	int state;
++	int notify;
++	bool newTransfers;
++	
++	int errCond;
++	QString errText;
++
++	QPtrQueue<Transfer> in;
++
++	QTimer noopTimer; // used to send icq keepalive
++	int noop_time;
++};
++
++ClientStream::ClientStream(Connector *conn, QObject *parent)
++:Stream(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	d = new Private;
++	d->mode = Client;
++	d->conn = conn;
++	connect( d->conn, SIGNAL(connected()), SLOT(cr_connected()) );
++	connect( d->conn, SIGNAL(error()), SLOT(cr_error()) );
++	connect( &d->client, SIGNAL( outgoingData( const QByteArray& ) ), SLOT ( cp_outgoingData( const QByteArray & ) ) );
++	connect( &d->client, SIGNAL( incomingData() ), SLOT ( cp_incomingData() ) );
++
++	d->noop_time = 0;
++	connect(&d->noopTimer, SIGNAL(timeout()), SLOT(doNoop()));
++}
++
++ClientStream::~ClientStream()
++{
++	reset();
++	delete d;
++}
++
++void ClientStream::reset(bool all)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	d->reset();
++	d->noopTimer.stop();
++
++	// client
++	if(d->mode == Client) {
++		
++		// reset connector
++		if(d->bs) {
++			d->bs->close();
++			d->bs = 0;
++		}
++		d->conn->done();
++
++		// reset state machine
++		d->client.reset();
++	}
++	if(all)
++		d->in.clear();
++}
++
++void ClientStream::connectToServer(const QString& server, bool auth)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	reset(true);
++	d->state = Connecting;
++	d->doAuth = auth;
++	d->server = server;
++
++	d->conn->connectToServer( d->server );
++}
++
++void ClientStream::continueAfterWarning()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++/* unneeded?
++	if(d->state == WaitVersion) {
++		d->state = Connecting;
++		processNext();
++	}
++	else if(d->state == WaitTLS) {
++		d->state = Connecting;
++		processNext();
++	}
++*/
++}
++
++void ClientStream::accept()
++{
++
++}
++
++bool ClientStream::isActive() const
++{
++	return (d->state != Idle);
++}
++
++bool ClientStream::isAuthenticated() const
++{
++	return (d->state == Active);
++}
++
++void ClientStream::setNoopTime(int mills)
++{
++	d->noop_time = mills;
++
++	if(d->state != Active)
++		return;
++
++	if(d->noop_time == 0) {
++		d->noopTimer.stop();
++		return;
++	}
++	d->noopTimer.start(d->noop_time);
++}
++
++void ClientStream::setLocalAddr(const QHostAddress &addr, Q_UINT16 port)
++{
++	d->haveLocalAddr = true;
++	d->localAddr = addr;
++	d->localPort = port;
++}
++
++int ClientStream::errorCondition() const
++{
++	return d->errCond;
++}
++
++QString ClientStream::errorText() const
++{
++	return d->errText;
++}
++
++void ClientStream::close()
++{
++	if(d->state == Active) {
++		d->state = Closing;
++//		d->client.shutdown();
++		processNext();
++	}
++	else if(d->state != Idle && d->state != Closing) {
++		reset();
++	}
++}
++
++bool ClientStream::transfersAvailable() const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	return ( !d->in.isEmpty() );
++}
++
++Transfer* ClientStream::read()
++{
++	if(d->in.isEmpty())
++		return 0; //first from queue...
++	else 
++		return d->in.dequeue();
++}
++
++void ClientStream::write( Transfer *request )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	// pass to CoreProtocol for transformation into wire format
++	d->client.outgoingTransfer( request );
++}
++	
++void cs_dump( const QByteArray &bytes )
++{
++#if 0
++	qDebug( "contains: %i bytes ", bytes.count() );
++	uint count = 0;
++	while ( count < bytes.count() )
++	{
++		int dword = 0;
++		for ( int i = 0; i < 8; ++i )
++		{
++			if ( count + i < bytes.count() )
++				printf( "%02x ", bytes[ count + i ] );
++			else
++				printf( "   " );
++			if ( i == 3 )
++				printf( " " );
++		}
++		printf(" | ");
++		dword = 0;
++		for ( int i = 0; i < 8; ++i )
++		{
++			if ( count + i < bytes.count() )
++			{
++				int j = bytes [ count + i ];
++				if ( j >= 0x20 && j <= 0x7e ) 
++					printf( "%2c ", j );
++				else
++					printf( "%2c ", '.' );
++			}
++			else
++				printf( "   " );
++			if ( i == 3 )
++				printf( " " );
++		}
++		printf( "\n" );
++		count += 8;
++	}
++	printf( "\n" );
++#endif
++	Q_UNUSED( bytes );
++}
++
++void ClientStream::cp_outgoingData( const QByteArray& outgoingBytes )
++{
++	// take formatted bytes from CoreProtocol and put them on the wire
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "[data size: " << outgoingBytes.size() << "]" << endl;
++	//cs_dump( outgoingBytes );
++	d->bs->write( outgoingBytes );
++}
++
++void ClientStream::cp_incomingData()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	Transfer * incoming = d->client.incomingTransfer();
++	if ( incoming )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - got a new transfer" << endl;
++		d->in.enqueue( incoming );
++		d->newTransfers = true;
++		emit doReadyRead();
++	}
++	else
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " - client signalled incomingData but none was available, state is: "<< d->client.state() << endl;
++}
++
++/* Connector connected */
++void ClientStream::cr_connected()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	d->bs = d->conn->stream();
++	connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed()));
++	connect(d->bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished()));
++	connect(d->bs, SIGNAL(readyRead()), SLOT(bs_readyRead()));
++	connect(d->bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int)));
++	connect(d->bs, SIGNAL(error(int)), SLOT(bs_error(int)));
++
++	QByteArray spare = d->bs->read();
++
++	QGuardedPtr<QObject> self = this;
++	emit connected();
++	if(!self)
++		return;
++}
++
++void ClientStream::cr_error()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	reset();
++	emit error(ErrConnection);
++}
++
++void ClientStream::bs_connectionClosed()	
++{
++	reset();
++	emit connectionClosed();
++}
++
++void ClientStream::bs_delayedCloseFinished()
++{
++	// we don't care about this (we track all important data ourself)
++}
++
++void ClientStream::bs_error(int)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	// TODO
++}
++
++void ClientStream::bs_readyRead()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	QByteArray a;
++	//qDebug( "size of storage for incoming data is %i bytes.", a.size() );
++	a = d->bs->read();
++
++	//QCString cs(a.data(), a.size()+1);
++	//qDebug("ClientStream: recv: %d [%s]\n", a.size(), cs.data());
++	//kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " recv: " << a.size()  <<" bytes" <<endl;
++	//cs_dump( a );
++
++	d->client.addIncomingData(a);
++}
++
++void ClientStream::bs_bytesWritten(int bytes)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " written: " << bytes  <<" bytes" <<endl;
++}
++
++void ClientStream::srvProcessNext()
++{
++}
++
++void ClientStream::doReadyRead()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	emit readyRead();
++}
++
++void ClientStream::processNext()
++{
++	if( !d->in.isEmpty() ) 
++	{
++		QTimer::singleShot(0, this, SLOT(doReadyRead()));
++	}
++}
++
++bool ClientStream::handleNeed()
++{
++	return false;
++}
++
++
++void ClientStream::doNoop()
++{
++}
++
++void ClientStream::handleError()
++{
++}
++
++#include "yahooclientstream.moc"
+--- kopete/protocols/yahoo/libkyahoo/logintask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/logintask.cpp	(revision 586398)
+@@ -0,0 +1,303 @@
++/*
++    Kopete Yahoo Protocol
++    Handles logging into to the Yahoo service
++
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qstring.h>
++
++#include "logintask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++#include <stdlib.h>
++extern "C"
++{
++#include "libyahoo.h"
++}
++
++LoginTask::LoginTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	mState = InitialState;
++}
++
++LoginTask::~LoginTask()
++{
++
++}
++
++bool LoginTask::take(Transfer* transfer)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	/*
++	  Yahoo login task has various stages
++	  
++	  1 .- Initial State
++	      1.1 .- OnGo is called
++	      1.2 .- SendVerify() - send a service verify ack
++	  2.- SentVerify
++	      2.1 - take(), get a useless transfer, sendAuth is called
++	  3.- SentAuth
++	      2.2 - take(), get a transfer with login and challenge string
++	            sendAuthResp is called.
++              2.3 - Need to decode and send a transfer back
++	  4.- SentAuthResp
++	*/
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = static_cast<YMSGTransfer *>(transfer);
++
++	switch (mState)
++	{
++		case (InitialState):
++			client()->notifyError( "Error in login procedure.", "take called while in initial state", Client::Debug );
++			return false;
++		break;
++		case (SentVerify):
++			sendAuth( t );
++			return true;
++		break;
++		case (SentAuth):
++			sendAuthResp( t );
++			return true;
++		break;
++		case (SentAuthResp):
++			parseCookies( t );
++			handleAuthResp( t );
++			// Throw transfer to the next task as it contains further data
++			return false;
++		break;
++		default:
++		return false;
++		break;
++	}
++}
++
++bool LoginTask::forMe(Transfer* transfer) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	switch (mState)
++	{
++		case (InitialState):
++			//there shouldn't be a incoming transfer for this task at this state
++			return false;
++		break;
++		case (SentVerify):
++			if ( t->service() == Yahoo::ServiceVerify )
++			return true;
++		break;
++		case (SentAuth):
++			if ( t->service() == Yahoo::ServiceAuth )
++			return true;
++		break;
++		case (SentAuthResp ):
++			if ( t->service() == Yahoo::ServiceList ||
++				t->service() == Yahoo::ServiceAuthResp )
++			return true;
++		default:
++			return false;
++		break;
++	}
++	return false;
++}
++
++void LoginTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	/* initial state, we have to send a ServiceVerify */
++	if (mState == InitialState)
++		sendVerify();
++	else
++			client()->notifyError( "Error in login procedure.", "take called while not in initial state", Client::Debug );
++}
++
++void LoginTask::reset()
++{
++	mState = InitialState;
++}
++
++void LoginTask::sendVerify()
++{
++	/* send a ServiceVerify */
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceVerify);
++	send( t );
++	mState = SentVerify;	
++}
++
++void LoginTask::sendAuth(YMSGTransfer* transfer)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	// transfer is the verify ack transfer, no useful data in it.
++	Q_UNUSED(transfer);
++	
++	/* got ServiceVerify ACK, send a ServiceAuth with username */
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = new YMSGTransfer( Yahoo::ServiceAuth );
++	t->setParam( 1 , client()->userId().local8Bit() );
++	send(t);
++	mState = SentAuth;
++}
++
++void LoginTask::sendAuthResp(YMSGTransfer* t)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	QString sn = t->firstParam( 1 );
++	QString seed = t->firstParam( 94 );
++	QString version_s = t->firstParam( 13 );
++	uint sessionID = t->id();
++	int version = version_s.toInt();
++	
++	switch (version)
++	{
++		case 0:
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Version pre 0x0b "<< version_s << endl;	
++		break;
++		default:
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Version 0x0b "<< version_s << endl;
++		sendAuthResp_0x0b(sn, seed, sessionID);
++		break;
++	}	
++	mState = SentAuthResp;
++
++	emit haveSessionID( sessionID );
++}
++
++void LoginTask::sendAuthResp_0x0b(const QString &sn, const QString &seed, uint sessionID)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " with seed " << seed << endl;
++	char *resp_6 = (char *) malloc(100);
++	char *resp_96 = (char *) malloc(100);
++	authresp_0x0b(seed.latin1(), sn.latin1(), (client()->password()).latin1(), resp_6, resp_96);
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "resp_6: " << resp_6 << " resp_69: " << resp_96 << endl;
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceAuthResp, m_stateOnConnect);
++	t->setId( sessionID );
++	t->setParam( 0 , sn.local8Bit());
++	t->setParam( 6 , resp_6);
++	t->setParam( 96 , resp_96);
++	t->setParam( 59 , "B\\tfckeert1kk1nl&b=2" );	// ???
++	t->setParam( 135 , "7,0,0,437" );	// Client version
++	t->setParam( 148 , -60 );
++	t->setParam( 244 , 524223 );
++	t->setParam( 1 , sn.local8Bit());
++
++	if( !m_verificationWord.isEmpty() )
++	{
++		t->setParam( 227 , m_verificationWord.local8Bit() );
++		m_verificationWord = QString::null;
++	}
++
++	free(resp_6);
++	free(resp_96);
++	send(t);
++
++}
++
++void LoginTask::sendAuthResp_pre_0x0b(const QString &/*sn*/, const QString &/*seed*/)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++void LoginTask::handleAuthResp(YMSGTransfer *t)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	switch( t->service() )
++	{
++		case( Yahoo::ServiceList ):
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Emitting Signal" << endl;
++			emit loginResponse( Yahoo::LoginOk, QString::null );
++		break;
++		case( Yahoo::ServiceAuthResp ):
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Emitting Signal" << endl;
++			emit loginResponse( t->firstParam( 66 ).toInt(), t->firstParam( 20 ) );
++		break;
++		default:
++		break;
++	}
++	mState = InitialState;
++}
++
++void LoginTask::setStateOnConnect( Yahoo::Status status )
++{
++	m_stateOnConnect = status;
++}
++
++void LoginTask::parseCookies( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	for( int i = 0; i < t->paramCount( 59 ); ++i)
++	{	
++		QString cookie;
++		cookie = t->nthParam( 59, i );
++        	if( cookie.startsWith( "Y" ) )
++		{
++			m_yCookie = getcookie( cookie.latin1() );
++			m_loginCookie = getlcookie( cookie.latin1() );
++		}
++		else if( cookie.startsWith( "T" ) )
++		{
++			m_tCookie = getcookie( cookie.latin1() );
++		}
++		else if( cookie.startsWith( "C" ) )
++		{
++			m_cCookie = getcookie( cookie.latin1() );
++		}
++    	}
++	if( !m_yCookie.isEmpty() && !m_tCookie.isEmpty() &&
++		!m_cCookie.isEmpty() )
++		emit haveCookies();
++}
++
++void LoginTask::setVerificationWord( const QString &word )
++{
++	m_verificationWord = word;
++}
++
++const QString& LoginTask::yCookie()
++{
++	return m_yCookie;
++}
++
++const QString& LoginTask::tCookie()
++{
++	return m_tCookie;
++}
++
++const QString& LoginTask::cCookie()
++{
++	return m_cCookie;
++}
++
++const QString& LoginTask::loginCookie()
++{
++	return m_loginCookie;
++}
++#include "logintask.moc"
+--- kopete/protocols/yahoo/libkyahoo/picturenotifiertask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/picturenotifiertask.cpp	(revision 586398)
+@@ -0,0 +1,157 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about buddy icons
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "picturenotifiertask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qstringlist.h>
++#include <kurl.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++PictureNotifierTask::PictureNotifierTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++PictureNotifierTask::~PictureNotifierTask()
++{
++
++}
++
++bool PictureNotifierTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++	
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	switch( t->service() )
++	{	
++		case Yahoo::ServicePictureStatus:
++			parsePictureStatus( t );
++		break;
++		case Yahoo::ServicePictureChecksum:
++			parsePictureChecksum( t );
++		break;
++		case Yahoo::ServicePicture:
++			parsePicture( t );
++		break;
++		case Yahoo::ServicePictureUpload:
++			parsePictureUploadResponse( t );
++		break;
++		default:
++		break;
++	}	
++
++	return true;
++}
++
++bool PictureNotifierTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++
++	if ( t->service() == Yahoo::ServicePictureChecksum ||
++		t->service() == Yahoo::ServicePicture ||
++		t->service() == Yahoo::ServicePictureUpdate ||
++		t->service() == Yahoo::ServicePictureUpload ||
++		t->service() == Yahoo::ServicePictureStatus )
++		return true;
++	else
++		return false;
++}
++
++void PictureNotifierTask::parsePictureStatus( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString	nick;		/* key = 4 */
++	int state;		/* key = 213  */
++
++	nick = t->firstParam( 4 );
++	state = t->firstParam( 213 ).toInt();
++	
++	emit pictureStatusNotify( nick, state );
++}
++
++void PictureNotifierTask::parsePictureChecksum( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString	nick;		/* key = 4 */
++	int checksum;		/* key = 192  */
++
++	nick = t->firstParam( 4 );
++	checksum = t->firstParam( 192 ).toInt();
++	
++	if( nick != client()->userId() )
++		emit pictureChecksumNotify( nick, checksum );
++}
++
++void PictureNotifierTask::parsePicture( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString	nick;		/* key = 4 */
++	int type;		/* key = 13: 1 = request, 2 = notification */
++	QString url;		/* key = 20 */
++	int checksum;		/* key = 192  */
++
++	nick = t->firstParam( 4 );
++	url = t->firstParam( 20 );
++	checksum = t->firstParam( 192 ).toInt();
++	type = t->firstParam( 13 ).toInt();
++	
++	if( type == 1 )
++		emit pictureRequest( nick );
++	else if( type == 2 )
++		emit pictureInfoNotify( nick, KURL( url ), checksum );
++}
++
++void PictureNotifierTask::parsePictureUploadResponse( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString url;
++	QString error;
++
++	url = t->firstParam( 20 );
++	error = t->firstParam( 16 );
++	
++	if( !error.isEmpty() )
++		client()->notifyError(i18n("The picture was not successfully uploaded"), error, Client::Error );
++
++	if( !url.isEmpty() )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Emitting url: " << url << endl;
++		emit pictureUploaded( url );
++	}
++}
++
++#include "picturenotifiertask.moc"
+--- kopete/protocols/yahoo/libkyahoo/yabtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yabtask.cpp	(revision 586398)
+@@ -0,0 +1,160 @@
++/*
++    Kopete Yahoo Protocol
++    yabtask.h - Handles the Yahoo Address Book
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "yabtask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qdatastream.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++#include <klocale.h>
++
++YABTask::YABTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++YABTask::~YABTask()
++{
++}
++
++bool YABTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = static_cast<YMSGTransfer*>(transfer);
++	
++	if( t->service() == Yahoo::ServiceContactDetails )
++		parseContactDetails( t );
++	
++	return true;
++}
++
++bool YABTask::forMe( Transfer* transfer ) const
++{
++// 	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	if ( t->service() == Yahoo::ServiceContactDetails )	
++		return true;
++	else
++		return false;
++}
++
++void YABTask::parseContactDetails( YMSGTransfer* t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString from;		/* key = 7  */
++	int count;
++
++	from = t->firstParam( 4 );
++	count = t->paramCount( 5 );
++	
++	for( int i = 0; i < count; i++ )
++	{
++		QString who = t->nthParam( 5, i );
++		QString s = t->nthParamSeparated( 280, i, 5 );
++		if( s.isEmpty() )
++			continue;
++
++		QDomDocument doc;
++		doc.setContent( s );
++		YABEntry *entry = new YABEntry;
++		entry->fromQDomDocument( doc );
++		entry->source = YABEntry::SourceContact;
++		entry->dump();
++		emit gotEntry( entry );
++	}
++}
++
++
++void YABTask::getAllEntries( long lastMerge, long lastRemoteRevision )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "LastMerge: " << lastMerge << " LastRemoteRevision: " << lastRemoteRevision << endl;
++	m_data = QString::null;
++	QString url = QString::fromLatin1("http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us&diffs=1&t=%1&tags=short&rt=%2&prog-ver=%3")
++		.arg( lastMerge ).arg( lastRemoteRevision ).arg( YMSG_PROGRAM_VERSION_STRING );
++
++	m_transferJob = KIO::get( url , false, false );
++	m_transferJob->addMetaData("cookies", "manual");
++	m_transferJob->addMetaData("setcookies", QString::fromLatin1("Cookie: Y=%1; T=%2; C=%3;")
++				.arg(client()->yCookie()).arg(client()->tCookie()).arg(client()->cCookie()) );
++	connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotData( KIO::Job*, const QByteArray & ) ) );
++	connect( m_transferJob, SIGNAL( result( KIO::Job *) ), this, SLOT( slotResult( KIO::Job* ) ) );
++}
++
++void YABTask::slotData( KIO::Job* /*job*/, const QByteArray &info  )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_data += info;
++}
++
++void YABTask::slotResult( KIO::Job* job )
++{
++	if( job->error () || m_transferJob->isErrorPage () )
++		client()->notifyError( i18n( "Could not retrieve server side addressbook for user info." ), job->errorString(), Client::Info );
++	else 
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Server side addressbook retrieved." << endl;
++		QDomDocument doc;
++		QDomNodeList list;
++		QDomElement e;
++		uint it = 0;
++
++		kdDebug(YAHOO_RAW_DEBUG) << m_data << endl;
++		doc.setContent( m_data );
++		
++		list = doc.elementsByTagName( "ab" );			// Get the Addressbook
++		for( it = 0; it < list.count(); it++ )	{
++			if( !list.item( it ).isElement() )
++				continue;
++			e = list.item( it ).toElement();
++			
++			if( !e.attribute( "lm" ).isEmpty() )
++				emit gotRevision( e.attribute( "lm" ).toLong(), true );
++
++			if( !e.attribute( "rt" ).isEmpty() )
++				emit gotRevision( e.attribute( "rt" ).toLong(), false );
++		}
++		
++		list = doc.elementsByTagName( "ct" );			// Get records
++		for( it = 0; it < list.count(); it++ )	{
++			if( !list.item( it ).isElement() )
++				continue;
++			e = list.item( it ).toElement();
++			
++			YABEntry *entry = new YABEntry;
++			entry->fromQDomElement( e );
++			entry->source = YABEntry::SourceYAB;
++			emit gotEntry( entry );
++		}
++	}
++}
++
++#include "yabtask.moc"
+--- kopete/protocols/yahoo/libkyahoo/logofftask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/logofftask.cpp	(revision 586398)
+@@ -0,0 +1,43 @@
++/*
++    Kopete Yahoo Protocol
++    Log off the Yahoo server
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "logofftask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++LogoffTask::LogoffTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++LogoffTask::~LogoffTask()
++{
++}
++
++void LogoffTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceLogoff);
++	t->setId( client()->sessionID() );
++	send( t );
++	
++	setSuccess( true );
++}
+--- kopete/protocols/yahoo/libkyahoo/stream.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/stream.h	(revision 586398)
+@@ -0,0 +1,76 @@
++/*
++    stream.h - Kopete Groupwise Protocol
++
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++
++    Based on code copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qobject.h>
++
++#ifndef YAHOO_STREAM_H
++#define YAHOO_STREAM_H
++
++class Transfer;
++
++class Stream : public QObject
++{
++	Q_OBJECT
++public:
++	enum Error { ErrParse, ErrProtocol, ErrStream, ErrCustom = 10 };
++	enum StreamCond
++	{
++		GenericStreamError,
++		Conflict,
++		ConnectionTimeout,
++		InternalServerError,
++		InvalidFrom,
++/*#		InvalidXml,  // not required*/
++		PolicyViolation,
++		ResourceConstraint,
++		SystemShutdown
++	};
++
++	Stream(QObject *parent=0);
++	virtual ~Stream();
++
++	virtual void close()=0;
++	virtual int errorCondition() const=0;
++	virtual QString errorText() const=0;
++
++	/**
++	 * Are there any messages waiting to be read
++	 */
++	virtual bool transfersAvailable() const = 0;	// adapt to messages
++	/**
++	 * Read a message received from the server
++	 */
++	virtual Transfer* read() = 0;
++
++	/**
++	 * Send a message to the server
++	 */
++	virtual void write( Transfer *request) = 0;
++	
++
++signals:
++	void connectionClosed();
++	void delayedCloseFinished();
++	void readyRead();
++//	void stanzaWritten();
++	void error(int);
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/oscartypes.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/oscartypes.h	(revision 586398)
+@@ -0,0 +1,31 @@
++/*
++    Kopete Oscar Protocol
++    oscartypes.h - Oscar Type Definitions
++
++    Copyright (c) 2004 Matt Rogers <matt.rogers at kdemail.net>
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef _YAHOOTYPES_H_
++#define _YAHOOTYPES_H_
++
++#include <qglobal.h>
++
++namespace Yahoo
++{
++	typedef Q_UINT8 BYTE;
++	typedef Q_UINT16 WORD;
++	typedef Q_UINT32 DWORD;
++}
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/modifybuddytask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/modifybuddytask.cpp	(revision 586398)
+@@ -0,0 +1,116 @@
++/*
++    Kopete Yahoo Protocol
++    Add a buddy to the Contactlist
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "modifybuddytask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++ModifyBuddyTask::ModifyBuddyTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++ModifyBuddyTask::~ModifyBuddyTask()
++{
++}
++
++void ModifyBuddyTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	switch( m_type )
++	{
++		case AddBuddy:
++			addBuddy();
++		break;
++		case RemoveBuddy:
++			removeBuddy();
++		break;
++		case MoveBuddy:
++			moveBuddy();
++		break;
++	}
++
++
++	
++	setSuccess( true );
++}
++
++void ModifyBuddyTask::addBuddy()
++{
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceAddBuddy);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	t->setParam( 7, m_target.local8Bit() );
++	t->setParam( 14, m_message.utf8() );
++	t->setParam( 65, m_group.local8Bit() );	
++	t->setParam( 97, 1 );	// UTF-8
++	send( t );
++}
++
++void ModifyBuddyTask::removeBuddy()
++{
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceRemBuddy);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	t->setParam( 7, m_target.local8Bit() );
++	t->setParam( 65, m_group.local8Bit() );	
++	send( t );
++}
++
++void ModifyBuddyTask::moveBuddy()
++{
++	YMSGTransfer *mov = new YMSGTransfer( Yahoo::ServiceBuddyChangeGroup );
++	mov->setId( client()->sessionID() );
++	mov->setParam( 1, client()->userId().local8Bit() );
++	mov->setParam( 302, 240 );
++	mov->setParam( 300, 240 );
++	mov->setParam( 7, m_target.local8Bit() );
++	mov->setParam( 224, m_oldGroup.local8Bit() );
++	mov->setParam( 264, m_group.local8Bit() );
++	mov->setParam( 301, 240 );
++	mov->setParam( 303, 240 );
++	send( mov );
++}
++
++void ModifyBuddyTask::setTarget( const QString &target )
++{
++	m_target = target;
++}
++
++void ModifyBuddyTask::setMessage( const QString &text )
++{
++	m_message = text;
++}
++
++void ModifyBuddyTask::setGroup( const QString &group )
++{
++	m_group = group;
++}
++
++void ModifyBuddyTask::setOldGroup( const QString &old )
++{
++	m_oldGroup = old;
++}
++
++void ModifyBuddyTask::setType( Type type )
++{
++	m_type = type;
++}
+--- kopete/protocols/yahoo/libkyahoo/sendnotifytask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendnotifytask.cpp	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++    Kopete Yahoo Protocol
++    Send a notification
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "sendnotifytask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++SendNotifyTask::SendNotifyTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++SendNotifyTask::~SendNotifyTask()
++{
++}
++
++void SendNotifyTask::onGo()
++{
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceNotify);
++	t->setId( client()->sessionID() );
++	t->setStatus( Yahoo::StatusNotify );
++	t->setParam( 4, client()->userId().local8Bit() );
++	t->setParam( 5, m_target.local8Bit() );
++	t->setParam( 14, " " );	
++	switch( m_type )
++	{
++	case NotifyTyping:
++		t->setParam( 13, m_state );
++		t->setParam( 49, "TYPING" );
++	break;
++	case NotifyWebcamInvite:
++		t->setParam( 13, 0 );
++		t->setParam( 49, "WEBCAMINVITE" );		
++	break;
++	case NotifyGame:
++	default:
++		setSuccess( false );
++		delete t;
++		return;
++	break;
++	}
++	send( t );
++	
++	setSuccess( true );
++}
++
++void SendNotifyTask::setType( Type type )
++{
++	m_type = type;
++}
++
++void SendNotifyTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void SendNotifyTask::setState( State state)
++{
++	m_state = state;
++}
++
++
++#include "sendnotifytask.moc"
+--- kopete/protocols/yahoo/libkyahoo/requestpicturetask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/requestpicturetask.cpp	(revision 586398)
+@@ -0,0 +1,52 @@
++/*
++    Kopete Yahoo Protocol
++    Request a Picture of a Buddy
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "requestpicturetask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++RequestPictureTask::RequestPictureTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++RequestPictureTask::~RequestPictureTask()
++{
++}
++
++void RequestPictureTask::onGo()
++{
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePicture);
++	t->setId( client()->sessionID() );
++	t->setParam( 4, client()->userId().local8Bit());
++	t->setParam( 5, m_target.local8Bit() );
++	t->setParam( 13, "1" );
++	send( t );
++	
++	setSuccess( true );
++}
++
++void RequestPictureTask::setTarget( const QString &target )
++{
++	m_target = target;
++}
++
++#include "requestpicturetask.moc"
++
+--- kopete/protocols/yahoo/libkyahoo/task.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/task.h	(revision 586398)
+@@ -0,0 +1,93 @@
++/*
++    task.h - Kopete Groupwise Protocol
++      
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++  
++#ifndef YAHOO_TASK_H
++#define YAHOO_TASK_H
++
++#include <qobject.h>
++
++class QString;
++
++class Client;
++class Request;
++class Transfer;
++
++class Task : public QObject
++{
++	Q_OBJECT
++public:
++	enum { ErrDisc };
++	Task(Task *parent);
++	Task( Client *, bool isRoot );
++	virtual ~Task();
++
++	Task *parent() const;
++	Client *client() const;
++	Transfer *transfer() const;
++	
++	QString id() const;
++
++	bool success() const;
++	int statusCode() const;
++	const QString & statusString() const;
++
++	void go( bool autoDelete=false  );
++	/** 
++	 * Allows a task to examine an incoming Transfer and decide whether to 'take' it
++	 * for further processing.
++	 */
++	virtual bool take( Transfer* transfer );
++	void safeDelete();
++
++signals:
++	void finished();
++
++protected:
++	virtual void onGo();
++	virtual void onDisconnect();
++	void send( Transfer * request );
++	void setSuccess( int code=0, const QString &str="" );
++	void setError( int code=0, const QString &str="" );
++// 	void debug( const char *, ... );
++	void debug( const QString & );
++	/**
++	 * Used in take() to check if the offered transfer is for this Task
++	 * @return true if this Task should take the Transfer.  Default impl always returns false.
++	 */
++	virtual bool forMe( const Transfer * transfer ) const;
++	/**
++	 * Creates a transfer with the given command and field list
++	 */
++	//void createTransfer( const QString & command, const Field::FieldList fields );
++	/**
++	 * Direct setter for Tasks which don't have any fields
++	 */
++	void setTransfer( Transfer * transfer );
++private slots:
++	void clientDisconnected();
++	void done();
++
++private:
++	void init();
++
++	class TaskPrivate;
++	TaskPrivate *d;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/sendpicturetask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendpicturetask.cpp	(revision 586398)
+@@ -0,0 +1,247 @@
++/*
++    Kopete Yahoo Protocol
++    sendpicturetask.cpp - Send our picture or information about it
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "sendpicturetask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <qfile.h>
++#include <qcstring.h>
++#include <qdatastream.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++#include <kbufferedsocket.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++using namespace KNetwork;
++
++SendPictureTask::SendPictureTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_socket = 0;
++}
++
++SendPictureTask::~SendPictureTask()
++{
++	delete m_socket;
++}
++
++void SendPictureTask::onGo()
++{
++	switch( m_type )
++	{
++		case UploadPicture:
++			initiateUpload();
++		break;
++		case SendChecksum:
++			sendChecksum();
++		break;
++		case SendInformation:
++			sendInformation();
++		case SendStatus:
++			sendStatus();
++		break;
++	}
++}
++
++void SendPictureTask::initiateUpload()
++{	
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	m_socket = new KBufferedSocket( "filetransfer.msg.yahoo.com", QString::number(80) );
++	connect( m_socket, SIGNAL( connected( const KResolverEntry& ) ), this, SLOT( connectSucceeded() ) );
++	connect( m_socket, SIGNAL( gotError(int) ), this, SLOT( connectFailed(int) ) );
++
++	m_socket->connect();
++}
++
++void SendPictureTask::connectFailed( int i)
++{
++	m_socket->close();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << i << ": " << static_cast<const KBufferedSocket*>( sender() )->errorString() << endl;
++	client()->notifyError(i18n("The picture was not successfully uploaded"), QString("%1 - %2").arg(i).arg(static_cast<const KBufferedSocket*>( sender() )->errorString()), Client::Error );
++	setSuccess( false );
++}
++
++void SendPictureTask::connectSucceeded()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	YMSGTransfer t(Yahoo::ServicePictureUpload);
++
++	QFile file( m_path );
++
++	t.setId( client()->sessionID() );
++	t.setParam( 1, client()->userId().local8Bit());
++	t.setParam( 38, 604800);
++	t.setParam( 0, client()->userId().local8Bit());
++	t.setParam( 28, file.size() );	
++	t.setParam( 27, m_fileName.local8Bit() );
++	t.setParam( 14, "" );
++	QByteArray buffer;
++	QByteArray paket;
++	QDataStream stream( buffer, IO_WriteOnly );
++
++	if ( file.open(IO_ReadOnly ) )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "File successfully opened. Reading..." << endl;
++	}
++	else
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Error opening file: " << file.errorString() << endl;
++		client()->notifyError(i18n("Error opening file: %1").arg(m_path), file.errorString(), Client::Error );
++		return;
++	}
++
++	paket = t.serialize();
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Sizes: File (" << m_path << "): " << file.size() << " - paket: " << paket.size() << endl;
++	QString header = QString::fromLatin1("POST /notifyft HTTP/1.1\r\n"
++			"Cookie: Y=%1; T=%2; C=%3 ;\r\n"
++			"User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
++			"Host: filetransfer.msg.yahoo.com\r\n"
++			"Content-length: %4\r\n"
++			"Cache-Control: no-cache\r\n\r\n").arg(client()->yCookie()).arg(client()->tCookie()).arg(client()->cCookie()).arg(file.size()+4+paket.size());
++	stream.writeRawBytes( header.local8Bit(), header.length() );
++	stream.writeRawBytes( paket.data(), paket.size() );
++	stream << (Q_INT8)0x32 << (Q_INT8)0x39 << (Q_INT8)0xc0 << (Q_INT8)0x80;
++	stream.writeRawBytes( file.readAll(), file.size() );
++
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Buffersize: " << buffer.size() << endl;
++	if( m_socket->writeBlock( buffer, buffer.size() ) )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Upload Successful." << endl;
++		connect( m_socket, SIGNAL( readyRead() ), this, SLOT( readResult() ) );
++	}
++	else
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Upload Failed." << endl;
++		m_socket->close();
++		setSuccess( false );
++	}
++}
++
++void SendPictureTask::readResult()
++{
++	QByteArray ar( m_socket->bytesAvailable() );
++	m_socket->readBlock ( ar.data (), ar.size () );
++	QString buf( ar );
++
++	m_socket->close();
++	if( buf.find( "error", 0, false ) >= 0 )
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Picture upload failed" << endl;
++		setSuccess( false );
++	}
++	else
++	{
++		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Picture upload acknowledged." << endl;
++		setSuccess( true );
++	}
++
++}
++
++void SendPictureTask::sendChecksum()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePictureChecksum);
++	t->setId( client()->sessionID() );
++	t->setParam(1, client()->userId().local8Bit());
++	if( !m_target.isEmpty() )
++		t->setParam( 5, m_target.local8Bit() );
++	t->setParam(192, m_checksum);
++	t->setParam(212, 1);
++	send( t );
++	
++	setSuccess( true );
++}
++
++void SendPictureTask::sendInformation()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePicture);
++	t->setId( client()->sessionID() );
++	t->setParam(1, client()->userId().local8Bit());
++	t->setParam(4, client()->userId().local8Bit());
++	t->setParam(13, 2 );
++	t->setParam(5, m_target.local8Bit() );
++	t->setParam(20, m_url.local8Bit() );
++	t->setParam(192, m_checksum);
++
++	send( t );
++	
++	setSuccess( true );
++}
++
++void SendPictureTask::sendStatus()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePictureUpdate);
++	t->setId( client()->sessionID() );
++	t->setParam(1, client()->userId().local8Bit());
++	t->setParam(5, m_target.local8Bit() );
++	t->setParam(206, m_status );
++
++	send( t );
++	
++	setSuccess( true );
++}
++
++void SendPictureTask::setType( Type type )
++{
++	m_type = type;
++}
++
++void SendPictureTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void SendPictureTask::setFilename( const QString &filename )
++{
++	m_fileName = filename;
++}
++
++void SendPictureTask::setFilesize( int filesize )
++{
++	m_fileSize = filesize;
++}
++
++void SendPictureTask::setPath( const QString &path )
++{
++	m_path = path;
++}
++
++void SendPictureTask::setChecksum( int checksum )
++{
++	m_checksum = checksum;
++}
++
++void SendPictureTask::setStatus( int status )
++{
++	m_status = status;
++}
++
++void SendPictureTask::setUrl( const QString &url )
++{
++	m_url = url;
++}
++
++#include "sendpicturetask.moc"
+--- kopete/protocols/yahoo/libkyahoo/configure.in.in	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/configure.in.in	(revision 586398)
+@@ -0,0 +1,38 @@
++YAHOO2_VERSION=""
++AC_SUBST(YAHOO2_VERSION)
++
++# Checks for typedefs, structures, and compiler characteristics.
++AC_C_BIGENDIAN
++AC_C_CONST
++AC_C_INLINE
++AC_TYPE_SIZE_T
++AC_STRUCT_TM
++
++AC_CHECK_TYPE([uint8_t],,
++[AC_DEFINE([uint8_t], [unsigned char],
++[Define to `unsigned char' if not defined.])])
++AC_CHECK_TYPE([uint32_t],,
++[AC_DEFINE([uint32_t], [unsigned int],
++[Define to `unsigned int' if not defined.])])
++AC_CHECK_TYPE([uint64_t],,
++[AC_DEFINE([uint64_t], [unsigned long long],
++[Define to `unsigned long long' if not defined.])])
++
++dnl Checks for library functions.
++AC_CHECK_FUNCS(strerror)
++
++# Checks for library functions.
++
++AC_ARG_WITH([struct-callbacks], [AC_HELP_STRING([--with-struct-callbacks],
++[use a callback structure instead of callback functions])])
++if test "$with_struct_callbacks" = "yes"; then
++	AC_DEFINE(USE_STRUCT_CALLBACKS, 1, 
++	[Define if you want to use a callback structure instead of callback functions])
++fi
++
++enable_sample_client="no"
++AM_CONDITIONAL(SAMPLE_CLIENT, test "$enable_sample_client" != "no")
++
++YAHOOPKGREQ=""
++AC_SUBST(YAHOOPKGREQ)
++
+--- kopete/protocols/yahoo/libkyahoo/statusnotifiertask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/statusnotifiertask.h	(revision 586398)
+@@ -0,0 +1,52 @@
++/*
++    Kopete Yahoo Protocol
++    Notifies about status changes of buddies
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef STATUSNOTIFIERTASK_H
++#define STATUSNOTIFIERTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++
++class QString;
++class YMSGTransfer;
++
++/**
++ at author André Duffeck
++*/
++class StatusNotifierTask : public Task
++{
++Q_OBJECT
++public:
++	StatusNotifierTask(Task *parent);
++	~StatusNotifierTask();
++	
++	bool take(Transfer *transfer);
++
++protected:
++	bool forMe( Transfer *transfer ) const;
++	void parseStatus( YMSGTransfer *transfer );
++	void parseStealthStatus( YMSGTransfer *transfer );
++	void parseAuthorization( YMSGTransfer *transfer );
++signals:
++	void statusChanged( const QString&, int, const QString&, int, int );
++	void stealthStatusChanged( const QString&, Yahoo::StealthStatus );
++	void loginResponse( int, const QString& );
++	void authorizationAccepted( const QString & );
++	void authorizationRejected( const QString &, const QString & );
++	void gotAuthorizationRequest( const QString &, const QString &, const QString & );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/chatsessiontask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/chatsessiontask.h	(revision 586398)
+@@ -0,0 +1,45 @@
++/*
++    Kopete Yahoo Protocol
++    chatsessiontask.h - Register / Unregister a chatsession
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHATSESSIONTASK_H
++#define CHATSESSIONTASK_H
++
++#include "task.h"
++
++class QString;
++
++/**
++ at author André Duffeck
++*/
++class ChatSessionTask : public Task
++{
++public:
++	enum Type { RegisterSession, UnregisterSession };
++	ChatSessionTask(Task *parent);
++	~ChatSessionTask();
++	
++	virtual void onGo();
++	
++	void setTarget( const QString &to );
++	void setType( Type type );
++private:
++	QString m_target;
++	Type m_type;
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/coreprotocol.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/coreprotocol.h	(revision 586398)
+@@ -0,0 +1,107 @@
++/*
++    Kopete Yahoo Protocol
++    
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++    
++    Based on code 
++    Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
++    Copyright (C) 2003  Justin Karneges
++    
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef YAHOO_CORE_PROTOCOL_H
++#define YAHOO_CORE_PROTOCOL_H
++
++#include <qcstring.h>
++#include <qobject.h>
++#include <qptrlist.h>
++
++class Transfer;
++class YMSGProtocol;
++
++class CoreProtocol : public QObject
++{
++Q_OBJECT
++public:
++	enum State { NeedMore, Available, NoData, OutOfSync };
++
++	CoreProtocol();
++	
++	virtual ~CoreProtocol();
++	
++	/**
++	 * Reset the protocol, clear buffers
++	 */
++	void reset();
++	
++	/**
++	 * Accept data from the network, and buffer it into a useful message
++	 * This requires parsing out each FLAP, etc. from the incoming data
++	 * @param incomingBytes Raw data in wire format.
++	 */
++	void addIncomingData( const QByteArray& incomingBytes );
++	
++	/**
++	 * @return the incoming transfer or 0 if none is available.
++	 */
++	Transfer* incomingTransfer();
++	
++	/** 
++	 * Convert a request into an outgoing transfer
++	 * emits @ref outgoingData() with each part of the transfer
++	 */
++	void outgoingTransfer( Transfer* outgoing );
++	
++	/**
++	 * Get the state of the protocol 
++	 */
++	int state();
++	
++signals:
++	/** 
++	 * Emitted as the core protocol converts fields to wire ready data
++	 */
++	void outgoingData( const QByteArray& );
++	
++	/**
++	 * Emitted when there is incoming data, parsed into a Transfer
++	 */
++	void incomingData();
++protected slots:
++	/**
++	 * Just a debug method to test emitting to the socket, atm - should go to the ClientStream
++	 */
++	void slotOutgoingData( const QCString & );
++	
++protected:
++	/**
++	 * Check that there is data to read, and set the protocol's state if there isn't any.
++	 */
++	bool okToProceed( QDataStream & );
++	/**
++	 * Convert incoming wire data into a Transfer object and queue it
++	 * @return number of bytes from the input that were parsed into a Transfer
++	 */ 
++	int wireToTransfer( const QByteArray& wire );
++
++private:
++	QByteArray m_in;	// buffer containing unprocessed bytes we received
++	int m_error;
++	Transfer* m_inTransfer; // the transfer that is being received
++	int m_state;		// represents the protocol's overall state
++	YMSGProtocol* m_YMSGProtocol;
++
++};
++
++#endif
++
+--- kopete/protocols/yahoo/libkyahoo/pingtask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/pingtask.cpp	(revision 586398)
+@@ -0,0 +1,46 @@
++/*
++    pingtask.cpp
++    Send a ping to the server
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "pingtask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++PingTask::PingTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++PingTask::~PingTask()
++{
++}
++
++void PingTask::onGo()
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServicePing7);
++	t->setParam( 0, client()->userId().local8Bit() );
++	t->setId( client()->sessionID() );
++	send( t );
++	
++	setSuccess( true );
++}
+--- kopete/protocols/yahoo/libkyahoo/changestatustask.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/changestatustask.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++    Kopete Yahoo Protocol
++    Change our Status
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHANGESTATUSTASK_H
++#define CHANGESTATUSTASK_H
++
++#include "task.h"
++#include "yahootypes.h"
++
++class QString;
++
++
++/**
++ at author André Duffeck
++*/
++class ChangeStatusTask : public Task
++{
++public:
++	enum Type { Available, Away };
++	ChangeStatusTask(Task *parent);
++	~ChangeStatusTask();
++	
++	virtual void onGo();
++
++	void setMessage( const QString &msg );
++	void setStatus( Yahoo::Status status );
++	void setType( Yahoo::StatusType type );
++private:
++	enum Visibility { Visible = 1, Invisible = 2 };
++	QString m_message;
++	Yahoo::Status m_status;
++	Yahoo::StatusType m_type;
++
++	void sendVisibility( Visibility visible );
++};
++
++#endif
+--- kopete/protocols/yahoo/libkyahoo/yahoobytestream.h	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahoobytestream.h	(revision 586398)
+@@ -0,0 +1,69 @@
++/*
++    YMSG - Yahoo Protocol Knetwork Bytestream
++
++    Copyright (C) 2004 by Till Gerken <till at tantalo.net>
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library 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 KNETWORKBYTESTREAM_H
++#define KNETWORKBYTESTREAM_H
++
++#include <kbufferedsocket.h>
++
++#include "bytestream.h"
++
++
++/**
++ * Low level socket class, using KDE's KNetwork socket classes
++ * @author Till Gerken
++ */
++ 
++class KNetworkByteStream : public ByteStream
++{
++
++Q_OBJECT
++
++public:
++	KNetworkByteStream ( QObject *parent = 0, const char *name = 0 );
++
++	~KNetworkByteStream ();
++
++	bool connect ( QString host, QString service );
++	virtual bool isOpen () const;
++	virtual void close ();
++
++	KNetwork::KBufferedSocket *socket () const;
++
++signals:
++	void connected ();
++
++protected:
++	virtual int tryWrite ();
++
++private slots:
++	void slotConnected ();
++	void slotConnectionClosed ();
++	void slotReadyRead ();
++	void slotBytesWritten ( int );
++	void slotError ( int );
++
++private:
++	KNetwork::KBufferedSocket *mSocket;
++	bool mClosing;
++
++};
++
++#endif
++
++// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
++
+--- kopete/protocols/yahoo/libkyahoo/ymsgtransfer.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/ymsgtransfer.cpp	(revision 586398)
+@@ -0,0 +1,239 @@
++/*
++    Kopete Yahoo Protocol
++    Handles logging into to the Yahoo service
++
++    Copyright (c) 2004 Duncan Mac-Vicar P. <duncan at kde.org>
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <string>
++
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "kdebug.h"
++#include <qdatastream.h>
++#include <qmap.h>
++#include <qstring.h>
++#include <qstringlist.h>
++
++
++using namespace Yahoo;
++
++class YMSGTransferPrivate
++{
++public:
++	int yflag;
++	int version;
++	int packetLength;
++	Yahoo::Service service;
++	Yahoo::Status status;
++	unsigned int id;	
++	ParamList data;
++	bool valid;
++};
++
++YMSGTransfer::YMSGTransfer()
++{
++	d = new YMSGTransferPrivate;
++	d->valid = true;
++	d->id = 0;
++	d-> status = Yahoo::StatusAvailable;
++}
++
++YMSGTransfer::YMSGTransfer(Yahoo::Service service)
++{
++	d = new YMSGTransferPrivate;
++	d->valid = true;
++	d->service = service;
++	d->id = 0;
++	d->status = Yahoo::StatusAvailable;
++}
++
++YMSGTransfer::YMSGTransfer(Yahoo::Service service, Yahoo::Status status)
++{
++	d = new YMSGTransferPrivate;
++	d->valid = true;
++	d->service = service;
++	d->id = 0;
++	d->status = status;
++}
++
++YMSGTransfer::~YMSGTransfer()
++{
++	delete d;
++}
++
++Transfer::TransferType YMSGTransfer::type()
++{
++	return Transfer::YMSGTransfer;
++}
++
++bool YMSGTransfer::isValid()
++{
++	return d->valid;
++}
++
++Yahoo::Service YMSGTransfer::service()
++{
++	return d->service;
++}
++
++void YMSGTransfer::setService(Yahoo::Service service)
++{
++	d->service = service;
++}
++
++Yahoo::Status YMSGTransfer::status()
++{
++	return d->status;
++}
++
++void YMSGTransfer::setStatus(Yahoo::Status status)
++{
++	d->status = status;
++}
++
++unsigned int YMSGTransfer::id()
++{
++	return d->id;
++}
++
++void YMSGTransfer::setId(unsigned int id)
++{
++	d->id = id;
++}
++
++ParamList YMSGTransfer::paramList()
++{
++	return d->data;
++}
++
++int YMSGTransfer::paramCount( int index )
++{
++	int cnt = 0;
++	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++		if( (*it).first == index )
++			cnt++;
++	}
++	return cnt;
++}
++
++
++QCString YMSGTransfer::nthParam( int index, int occurence )
++{
++	int cnt = 0;
++	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++		if( (*it).first == index && cnt++ == occurence)
++			return (*it).second;
++	}
++	return QCString();
++}
++
++QCString YMSGTransfer::nthParamSeparated( int index, int occurence, int separator )
++{
++
++	int cnt = -1;
++	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++		if( (*it).first == separator )
++			cnt++;
++		if( (*it).first == index && cnt == occurence)
++			return (*it).second;
++	}
++	return QCString();
++}
++
++QCString YMSGTransfer::firstParam( int index )
++{
++	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++		if( (*it).first == index )
++			return (*it).second;
++	}
++	return QCString();
++}
++
++void YMSGTransfer::setParam(int index, const QCString &data)
++{
++	d->data.append( Param( index, data ) );
++}
++
++void YMSGTransfer::setParam( int index, int data )
++{
++	d->data.append( Param( index, QString::number( data ).local8Bit() ) );
++}
++
++int YMSGTransfer::length()
++{
++	int len = 0;
++	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++		len += QString::number( (*it).first ).length();
++		len += 2;
++		len += (*it).second.length();
++		len += 2;
++	}
++	return len;
++}
++
++
++QByteArray YMSGTransfer::serialize()
++{
++	/*
++	<------- 4B -------><------- 4B -------><---2B--->
++	+-------------------+-------------------+---------+
++	|   Y   M   S   G   |      version      | pkt_len |
++	+---------+---------+---------+---------+---------+
++	| service |      status       |    session_id     |
++	+---------+-------------------+-------------------+
++	|                                                 |
++	:                    D A T A                      :
++	/                   0 - 65535*                   |
++	+-------------------------------------------------+
++	*/
++	
++	int pos = 0;
++	QStringList::ConstIterator listIt = 0;
++	QByteArray buffer;
++	QDataStream stream( buffer, IO_WriteOnly );
++	
++	stream << (Q_INT8)'Y' << (Q_INT8)'M' << (Q_INT8)'S' << (Q_INT8)'G';
++	if( d->service == Yahoo::ServicePictureUpload )
++		stream << (Q_INT16)0x0e00;
++	else
++		stream << (Q_INT16)0x000e;
++	stream << (Q_INT16)0x0000;
++	if( d->service == Yahoo::ServicePictureUpload ||
++		d->service == Yahoo::ServiceFileTransfer )
++		stream << (Q_INT16)(length()+4);
++	else
++		stream << (Q_INT16)length();
++	stream << (Q_INT16)d->service;
++	stream << (Q_INT32)d->status;
++	stream << (Q_INT32)d->id;
++ 	for (ParamList::ConstIterator it = d->data.begin(); it !=  d->data.end(); ++it) 
++	{
++ 		kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " Serializing key " << (*it).first << " value " << (*it).second << endl;
++		stream.writeRawBytes ( QString::number( (*it).first ).local8Bit(), QString::number( (*it).first ).length() );
++		stream << (Q_INT8)0xc0 << (Q_INT8)0x80;
++		stream.writeRawBytes( (*it).second, (*it).second.length() );
++		stream << (Q_INT8)0xc0 << (Q_INT8)0x80;
++	}
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << " pos=" << pos << " (packet size)" << buffer << endl;
++	return buffer;
++}
++
+--- kopete/protocols/yahoo/libkyahoo/sendauthresptask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/sendauthresptask.cpp	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++    Kopete Yahoo Protocol
++    Send a authorization request response
++
++    Copyright (c) 2006 André Duffeck <andre.duffeck at kdemail.net>
++    Kopete    (c) 2003-2006 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "sendauthresptask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++SendAuthRespTask::SendAuthRespTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++SendAuthRespTask::~SendAuthRespTask()
++{
++}
++
++void SendAuthRespTask::onGo()
++{
++	YMSGTransfer *t = new YMSGTransfer(Yahoo::ServiceAuthorization);
++	t->setId( client()->sessionID() );
++	t->setParam( 1, client()->userId().local8Bit() );
++	t->setParam( 5, m_target.local8Bit() );
++	if( m_granted )
++	{
++		t->setParam( 13, 1 );
++	}
++	else
++	{
++		t->setParam( 13, 2 );
++		t->setParam( 97, 1 );	// UTF
++		t->setParam( 14, m_msg.utf8() );
++		
++	}
++	send( t );
++	
++	setSuccess( true );
++}
++
++void SendAuthRespTask::setGranted( bool granted )
++{
++	m_granted = granted;
++}
++
++void SendAuthRespTask::setTarget( const QString &to )
++{
++	m_target = to;
++}
++
++void SendAuthRespTask::setMessage( const QString &msg )
++{
++	m_msg = msg;
++}
++
++
++#include "sendauthresptask.moc"
+--- kopete/protocols/yahoo/libkyahoo/Makefile.am	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/Makefile.am	(revision 586398)
+@@ -0,0 +1,23 @@
++SUBDIRS = . tests
++METASOURCES = AUTO
++noinst_LTLIBRARIES = libkyahoo.la
++
++AM_CPPFLAGS = $(all_includes)
++
++
++libkyahoo_la_SOURCES = client.cpp task.cpp connector.cpp inputprotocolbase.cpp \
++		ymsgprotocol.cpp ymsgtransfer.cpp transfer.cpp yahoobytestream.cpp bytestream.cpp \
++		yahooclientstream.cpp yahooconnector.cpp safedelete.cpp stream.cpp sha1.c md5.c crypt.c \
++		coreprotocol.cpp logintask.cpp libyahoo.c yahoo_fn.c listtask.cpp statusnotifiertask.cpp \
++		mailnotifiertask.cpp messagereceivertask.cpp sendnotifytask.cpp sendmessagetask.cpp \
++		logofftask.cpp changestatustask.cpp modifybuddytask.cpp picturenotifiertask.cpp \
++		requestpicturetask.cpp yahoobuddyiconloader.cpp stealthtask.cpp sendpicturetask.cpp \
++		webcamtask.cpp conferencetask.cpp sendauthresptask.cpp pingtask.cpp yabtask.cpp \
++		yabentry.cpp modifyyabtask.cpp chatsessiontask.cpp sendfiletask.cpp filetransfernotifiertask.cpp \
++		receivefiletask.cpp
++libkyahoo_la_LDFLAGS = -no-undefined $(all_libraries)
++libkyahoo_la_LIBADD = $(LIB_QT)
++
++noinst_HEADERS = logintask.h yabentry.h yabtask.h modifyyabtask.h \
++	chatsessiontask.h
++KDE_OPTIONS = nofinal
+--- kopete/protocols/yahoo/libkyahoo/yahooconnector.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/yahooconnector.cpp	(revision 586398)
+@@ -0,0 +1,111 @@
++
++/***************************************************************************
++                   gwconnector.cpp  -  Socket Connector for KNetwork
++                             -------------------
++    begin                : Wed Jul 7 2004
++    copyright            : (C) 2004 by Till Gerken <till at tantalo.net>
++ 
++			Kopete (C) 2004 Kopete developers <kopete-devel at kde.org>
++ ***************************************************************************/
++
++/***************************************************************************
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU Lesser General Public License as        *
++ *   published by the Free Software Foundation; either version 2.1 of the  *
++ *   License, or (at your option) any later version.                       *
++ *                                                                         *
++ ***************************************************************************/
++
++#include <kbufferedsocket.h>
++#include <kdebug.h>
++#include <kresolver.h>
++
++#include "yahooconnector.h"
++#include "yahoobytestream.h"
++#include "yahootypes.h"
++
++KNetworkConnector::KNetworkConnector( QObject *parent, const char */*name*/ )
++		: Connector( parent )
++{
++	kdDebug( YAHOO_RAW_DEBUG ) << k_funcinfo << "New KNetwork connector." << endl;
++
++	mErrorCode = KNetwork::KSocketBase::NoError;
++
++	mByteStream = new KNetworkByteStream( this );
++
++	connect( mByteStream, SIGNAL ( connected () ), this, SLOT ( slotConnected () ) );
++	connect( mByteStream, SIGNAL ( error ( int ) ), this, SLOT ( slotError ( int ) ) );
++	mPort = 5510;
++}
++
++KNetworkConnector::~KNetworkConnector()
++{
++	delete mByteStream;
++}
++
++void KNetworkConnector::connectToServer( const QString &server )
++{
++	Q_UNUSED( server );
++	kdDebug( YAHOO_RAW_DEBUG ) << k_funcinfo << "Initiating connection to " << mHost << endl;
++	Q_ASSERT( !mHost.isNull() );
++	Q_ASSERT( mPort );
++
++	mErrorCode = KNetwork::KSocketBase::NoError;
++
++	if ( !mByteStream->connect( mHost, QString::number (mPort) ) )
++	{
++		// Houston, we have a problem
++		mErrorCode = mByteStream->socket()->error();
++		emit error();
++	}
++}
++
++void KNetworkConnector::slotConnected()
++{
++	kdDebug( YAHOO_RAW_DEBUG ) << k_funcinfo << "We are connected." << endl;
++
++	// FIXME: setPeerAddress() is something different, find out correct usage later
++	//KInetSocketAddress inetAddress = mStreamSocket->address().asInet().makeIPv6 ();
++	//setPeerAddress ( QHostAddress ( inetAddress.ipAddress().addr () ), inetAddress.port () );
++
++	emit connected ();
++}
++
++void KNetworkConnector::slotError( int code )
++{
++	kdDebug( YAHOO_RAW_DEBUG ) << k_funcinfo << "Error detected: " << code << endl;
++
++	mErrorCode = code;
++	emit error ();
++}
++
++int KNetworkConnector::errorCode()
++{
++	return mErrorCode;
++}
++
++ByteStream *KNetworkConnector::stream() const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	return mByteStream;
++}
++
++void KNetworkConnector::done()
++{
++	kdDebug ( YAHOO_RAW_DEBUG ) << k_funcinfo << endl;
++	mByteStream->close ();
++}
++
++void KNetworkConnector::setOptHostPort( const QString &host, Q_UINT16 port )
++{
++	kdDebug ( YAHOO_RAW_DEBUG ) << k_funcinfo << "Manually specifying host " << host << " and port " << port << endl;
++
++	mHost = host;
++	mPort = port;
++
++}
++
++#include "yahooconnector.moc"
++
++// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
+--- kopete/protocols/yahoo/libkyahoo/stream.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/stream.cpp	(revision 586398)
+@@ -0,0 +1,31 @@
++/*
++    stream.cpp - Kopete Groupwise Protocol
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "stream.h"
++
++Stream::Stream(QObject *parent)
++:QObject(parent)
++{
++}
++
++Stream::~Stream()
++{
++}
++
++#include "stream.moc"
+--- kopete/protocols/yahoo/libkyahoo/messagereceivertask.cpp	(revision 0)
++++ kopete/protocols/yahoo/libkyahoo/messagereceivertask.cpp	(revision 586398)
+@@ -0,0 +1,148 @@
++/*
++    Kopete Yahoo Protocol
++    Receive Messages
++
++    Copyright (c) 2005 André Duffeck <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qstring.h>
++
++#include "messagereceivertask.h"
++#include "transfer.h"
++#include "ymsgtransfer.h"
++#include "yahootypes.h"
++#include "client.h"
++#include <qstring.h>
++#include <kdebug.h>
++
++MessageReceiverTask::MessageReceiverTask(Task* parent) : Task(parent)
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++}
++
++MessageReceiverTask::~MessageReceiverTask()
++{
++}
++
++bool MessageReceiverTask::take( Transfer* transfer )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	if ( !forMe( transfer ) )
++		return false;
++
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++	
++	if( t->service() == Yahoo::ServiceNotify )
++		parseNotify( t );
++	else
++		parseMessage( t );
++
++	return true;
++}
++
++bool MessageReceiverTask::forMe( Transfer* transfer ) const
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++	
++	YMSGTransfer *t = 0L;
++	t = dynamic_cast<YMSGTransfer*>(transfer);
++	if (!t)
++		return false;
++
++	if ( t->service() == Yahoo::ServiceMessage ||
++		t->service() == Yahoo::ServiceGameMsg ||
++		t->service() == Yahoo::ServiceSysMessage ||
++		t->service() == Yahoo::ServiceNotify )	
++		return true;
++	else
++		return false;
++}
++
++void MessageReceiverTask::parseMessage( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	int cnt = t->paramCount( 5 );
++	for( int i = 0; i < cnt; ++i )
++	{
++		QString to = t->nthParam( 5, i );
++		QString timestamp = t->nthParamSeparated( 15, i, 5 );
++		QString utf8 = t->nthParamSeparated( 97, i, 5 );
++		QString from = t->nthParamSeparated( 1, i, 5 ).isEmpty() ? t->nthParamSeparated( 4, i, 5 ) : t->nthParamSeparated( 1, i, 5 );
++		QString msg = t->nthParamSeparated( 14, i, 5 );
++		QString sysmsg = t->nthParamSeparated( 16, i, 5 );
++
++		// The arrangement of the key->value pairs is different when there is only one message in the packet.
++		// Separating by key "5" (sender) doesn't work in that case, because the "1" and "4" keys are sent before the "5" key
++		if( cnt == 1 )
++			from = t->firstParam( 1 ).isEmpty() ? t->firstParam( 4 ) : t->firstParam( 1 );
++	
++		if( !sysmsg.isEmpty() )
++		{
++			client()->notifyError( "Server message received: ", sysmsg, Client::Error );
++			continue;
++		}
++	
++		if( msg.isEmpty() )
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Got a empty message. Dropped." << endl;
++			continue;
++		}
++	
++		if( utf8.startsWith( "1" ) )
++			msg = QString::fromUtf8( msg.latin1() );
++	
++		if( t->service() == Yahoo::ServiceSysMessage )
++			emit systemMessage( sysmsg );
++		else
++		{	
++			if( msg.startsWith( "<ding>" ) )
++				emit gotBuzz( from, timestamp.toLong() );
++			else
++				emit gotIm( from, msg, timestamp.toLong(), 0);
++		}
++	}
++}
++
++void MessageReceiverTask::parseNotify( YMSGTransfer *t )
++{
++	kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << endl;
++
++	QString from = t->firstParam( 4 );
++	//QString to = t->firstParam( 5 );
++	QString type = t->firstParam( 49 );
++	QString stat = t->firstParam( 13 );
++	QString ind = t->firstParam( 14 );
++
++	if( type.startsWith( "TYPING" ) )
++		emit gotTypingNotify( from, stat.toInt() );
++	else if( type.startsWith( "GAME" ) )
++		;
++	else if( type.startsWith( "WEBCAMINVITE" ) )
++	{
++		if( ind.startsWith(" ") )
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Got a WebcamInvitation." << endl;
++			emit gotWebcamInvite( from );
++		}
++		else
++		{
++			kdDebug(YAHOO_RAW_DEBUG) << k_funcinfo << "Got a WebcamRequest-Response: " << ind.toInt() << endl;
++		}
++	}
++}
++
++#include "messagereceivertask.moc"
+--- kopete/protocols/yahoo/yahoocontact.h	(revision 568672)
++++ kopete/protocols/yahoo/yahoocontact.h	(revision 586398)
+@@ -35,6 +35,7 @@
+ class YahooAccount;
+ class YahooWebcamDialog;
+ class YahooChatSession;
++class YABEntry;
+ struct KURL;
+ 
+ class YahooContact : public Kopete::Contact
+@@ -53,27 +54,40 @@
+ 
+ 	void setOnlineStatus(const Kopete::OnlineStatus &status);
+ 	void setYahooStatus( const Kopete::OnlineStatus& );
++	void setStealthed( bool );
++	bool stealthed();
+ 
++
+ 	/** The group name getter and setter methods**/
+ 	QString group() const;
+ 	void setGroup( const QString& );
+ 
+-	void gotWebcamInvite();
++	/** The userId getter method**/
++	QString userId() const;
++
+ 	void receivedWebcamImage( const QPixmap& );
+ 	void webcamClosed( int );
++	void webcamPaused();
++	
++	const YABEntry *yabEntry();
+ 
++	static QString prepareMessage( const QString &messageText );
++
+ public slots:
+ 	virtual void slotUserInfo();
+-	virtual void slotSendFile();
++	virtual void slotSendFile( const KURL &file );
+ 	virtual void deleteContact();
+ 	virtual void sendFile( const KURL &sourceURL = KURL(), const QString &fileName = QString::null, uint fileSize = 0L );
++	void slotUserProfile();
+ 	void stealthContact();
+ 	void requestWebcam();
++	void inviteWebcam();
+ 	void buzzContact();
+ 	void setDisplayPicture(KTempFile *f, int checksum);
+ 	void sendBuddyIconInfo( const QString &url, int checksum );
+ 	void sendBuddyIconUpdate( int type );
+ 	void sendBuddyIconChecksum( int checksum );
++	void setYABEntry( YABEntry *, bool show = false );
+ 
+ 	/**
+ 	 * Must be called after the contact list has been received
+@@ -84,10 +98,9 @@
+ 	void sync(unsigned int flags);
+ 
+ signals:
+-	void signalReceivedWebcamInvite();
+ 	void signalReceivedWebcamImage( const QPixmap &pic );
+ 	void signalWebcamClosed( int reason );
+-	void signalWebcamInviteAccepted();
++	void signalWebcamPaused();
+ 	void displayPictureChanged();
+ 
+ private slots:
+@@ -97,23 +110,29 @@
+ 	void slotEmitDisplayPictureChanged();
+ 
+ 	void closeWebcamDialog();
+-	//void webcamClosed( const QString& contact, int reason );
++	void initWebcamViewer();
++	void inviteConference();
+ 
++	void writeYABEntry();
++	void readYABEntry();
++
+ private:
+ 	QString m_userId; 
+ 	QString m_groupName;
++	YABEntry *m_YABEntry;
+ 	YahooChatSession *m_manager;
++	YahooWebcamDialog* m_webcamDialog;
+ 	YahooAccount* m_account;
+-
+-	//stealth
++	bool m_stealthed;
++	bool m_receivingWebcam;
++	bool m_sessionActive;
++	
+ 	KAction* m_stealthAction;
+-	
+-	//webcam handling
++	KAction* m_profileAction;
+ 	KAction* m_webcamAction;
+-	YahooWebcamDialog* m_webcamDialog;
+-	
+-	//buzz
++	KAction* m_inviteWebcamAction;
+ 	KAction* m_buzzAction;	
++	KAction* m_inviteConferenceAction;
+ };
+ 
+ #endif
+--- kopete/protocols/yahoo/yahooaccount.h	(revision 568672)
++++ kopete/protocols/yahoo/yahooaccount.h	(revision 586398)
+@@ -29,8 +29,8 @@
+ #include "kopeteawaydialog.h"
+ 
+ // Local
+-#include "yahooconferencemessagemanager.h"
+ #include "yahooprotocol.h"
++#include "yahootypes.h"
+ 
+ class QColor;
+ class KAction;
+@@ -38,10 +38,20 @@
+ class YahooContact;
+ class YahooAccount;
+ class YahooProtocol;
++class YahooWebcam;
++class YahooConferenceChatSession;
+ class KTempFile;
+-class QTimer;
+ struct KURL;
+-
++namespace Kopete{
++class Transfer;
++class ChatSession;
++class FileTransferInfo;
++}
++class Client;
++class YABEntry;
++namespace KIO{
++	class Job;
++}
+ class YahooAwayDialog : public KopeteAwayDialog
+ {
+ public:
+@@ -78,7 +88,7 @@
+ 	/**
+ 	 * The session
+ 	 */
+-	YahooSession *yahooSession();
++	Client *yahooSession();
+ 
+ 	/**
+ 	 * Returns true if contact @p id is on the server-side contact list
+@@ -114,6 +124,12 @@
+ 	 * 0 = no image, 2 = buddy icon, 1 = avatar?
+ 	 */
+ 	int pictureFlag();
++
++	void verifyAccount( const QString &word );
++
++	void sendConfMessage( YahooConferenceChatSession *s, Kopete::Message &message );
++	void prepareConference( const QString &who );
++	void sendFile( YahooContact *to, const KURL &url );
+ public slots:
+ 	/**
+ 	 * Connect to the Yahoo service
+@@ -160,14 +176,21 @@
+ 	void slotGoOffline();
+ 	void slotOpenInbox();			// Open Yahoo Mailbox in browser
+ 	void slotOpenYAB();			// Open Yahoo Addressbook in browser
++	void slotEditOwnYABEntry();		// Show own Yahoo Addressbook entry
+ 
+ 	void slotGoStatus(int status, const QString &awayMessage = QString::null);
+ 	void slotLoginResponse(int succ, const QString &url);
+-	void slotGotBuddies(const YList * buds);
++	void slotDisconnected();
++	void slotLoginFailed();
+ 	void slotGotBuddy(const QString &userid, const QString &alias, const QString &group);
++	void slotAuthorizationAccepted( const QString &who );
++	void slotAuthorizationRejected( const QString &who, const QString &msg );
++	void slotgotAuthorizationRequest( const QString &, const QString &, const QString & );
++	void slotContactAddedNotifyDialogClosed( const QString & );
+ 	void slotGotIgnore(const QStringList &);
+ 	void slotGotIdentities(const QStringList &);
+-	void slotStatusChanged(const QString &who, int stat, const QString &msg, int away);
++	void slotStatusChanged(const QString &who, int stat, const QString &msg, int away, int idle);
++	void slotStealthStatusChanged(const QString &who, Yahoo::StealthStatus state);
+ 	void slotGotIm(const QString &who, const QString &msg, long tm, int stat);
+ 	void slotGotBuzz(const QString &who, long tm);
+ 	void slotGotConfInvite(const QString &who, const QString &room, const QString &msg, const QStringList &members);
+@@ -175,6 +198,9 @@
+ 	void slotConfUserJoin(const QString &who, const QString &room);
+ 	void slotConfUserLeave(const QString &who, const QString &room);
+ 	void slotConfMessage(const QString &who, const QString &room, const QString &msg);
++	void slotConfLeave( YahooConferenceChatSession *s );
++	void slotInviteConference( const QString &room, const QStringList &who, const QStringList &members, const QString &msg );
++	void slotAddInviteConference( const QString &room, const QStringList &who, const QStringList &members, const QString &msg );
+ 	void slotGotFile(const QString &who, const QString &url, long expires, const QString &msg, const QString &fname, unsigned long fesize);
+ 	void slotContactAdded(const QString &myid, const QString &who, const QString &msg);
+ 	void slotRejected(const QString &, const QString &);
+@@ -182,28 +208,43 @@
+ 	void slotGameNotify(const QString &, int);
+ 	void slotMailNotify(const QString &, const QString &, int);
+ 	void slotSystemMessage(const QString &);
+-	void slotError(const QString &, int);
+ 	void slotRemoveHandler(int fd);
+ 	//void slotHostConnect(const QString &host, int port);
+ 	void slotGotWebcamInvite(const QString &);
++	void slotWebcamNotAvailable( const QString &who );
+ 	void slotGotWebcamImage(const QString&, const QPixmap&);
++	void slotWebcamReadyForTransmission();
++	void slotWebcamStopTransmission();
++	void slotOutgoingWebcamClosing();
+ 	void slotWebcamClosed(const QString&, int);
++	void slotWebcamPaused(const QString&);
++	void slotWebcamViewerJoined( const QString & );
++	void slotWebcamViewerLeft( const QString & );
++	void slotWebcamViewerRequest( const QString & );
++	void slotPictureStatusNotiy( const QString&, int);
+ 	void slotGotBuddyIcon(const QString&, KTempFile*, int);
+ 	void slotGotBuddyIconInfo(const QString&, KURL, int);
+ 	void slotGotBuddyIconChecksum(const QString&, int);
+ 	void slotGotBuddyIconRequest(const QString &);
+ 	void slotBuddyIconChanged(const QString&);
++	void slotGotYABEntry( YABEntry *entry );
++	void slotGotYABRevision( long revision, bool merged );
++	void slotSaveYABEntry( YABEntry &entry );
++	void slotModifyYABEntryError( YABEntry *entry, const QString & );
+ 
+-	void slotBuddyListFetched( int numBuddies );
+-
+ 	void slotReceiveFileAccepted( Kopete::Transfer *trans, const QString& fileName );
++	void slotReceiveFileRefused( const Kopete::FileTransferInfo& info );
++	void slotFileTransferComplete( unsigned int id );
++	void slotFileTransferError( unsigned int id, int error, const QString &desc );
++	void slotFileTransferBytesProcessed( unsigned int id, unsigned int bytes );
++	void slotFileTransferResult( KIO::Job * );
++	void slotError( int level );
+ 
+ private slots:
+ 	/**
+ 	 * When a global identity key get changed.
+ 	 */
+ 	void slotGlobalIdentityChanged( const QString &key, const QVariant &value );
+-	void slotKeepalive();
+ private:
+ 
+ 	/**
+@@ -211,6 +252,8 @@
+ 	 */
+ 	void initConnectionSignals( enum SignalConnectionType sct );
+ 
++	QString prepareIncomingMessage( const QString &msg );
++
+ 	/**
+ 	 * internal (to the plugin) controls/flags
+ 	 * This should be kept in sync with server - if a buddy is removed, this should be changed accordingly.
+@@ -221,13 +264,16 @@
+ 	 * Conferences list, maped by room name (id)
+ 	 */
+ 	QMap<QString, YahooConferenceChatSession *> m_conferences;
++	QStringList m_pendingConfInvites;
++	QStringList m_pendingWebcamInvites;
++	QStringList m_pendingFileTransfers;
+ 
++	QMap<unsigned int, Kopete::Transfer *> m_fileTransfers;
++
+ 	void setPictureFlag( int flag );
+ 
+ 	bool theHaveContactList;	// Do we have the full server-side contact list yet?
+ 	int stateOnConnection;		// The state to change to on connection
+-	QTimer* m_keepaliveTimer;
+-	bool m_waitingForResponse;
+ 
+ 	/**
+ 	 * External Settings and Descriptors
+@@ -238,14 +284,19 @@
+ 	int m_lastDisconnectCode;	// The last disconnect code.
+ 	int m_currentMailCount;
+ 	int m_pictureFlag;			// Describes if we send a buddy icon or not
+-	YahooSession *m_session;	// Connection Object
++	long m_YABLastMerge;		// The YAB Revision on which the last merge was done
++	long m_YABLastRemoteRevision;	// The last remote YAB Revision on which a sync was done
+ 	YahooProtocol *m_protocol;	// The Protocol Object
+ 
++	YahooWebcam *m_webcam;
+ 
+ 	YahooAwayDialog *theAwayDialog;	// Our away message dialog
+ 
+ 	KAction *m_openInboxAction;	// Menu item openInbox
+ 	KAction *m_openYABAction;	// Menu item openYahooAddressbook
++	KAction *m_editOwnYABEntry;	// Menu item editOwnYABEntry
++	
++	Client *m_session;		// The Connection object
+ };
+ 
+ 
+--- kopete/protocols/yahoo/yahooprotocol.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahooprotocol.cpp	(revision 586398)
+@@ -57,10 +57,51 @@
+ 	awayMessage(Kopete::Global::Properties::self()->awayMessage()),
+ 	iconCheckSum("iconCheckSum", i18n("Buddy Icon Checksum"), QString::null, true, false, true),
+ 	iconExpire("iconExpire", i18n("Buddy Icon Expire"), QString::null, true, false, true),
+-	iconRemoteUrl("iconRemoteUrl", i18n("Buddy Icon Remote Url"), QString::null, true, false, true)
+-
++	iconRemoteUrl("iconRemoteUrl", i18n("Buddy Icon Remote Url"), QString::null, true, false, true),
++	propfirstName(Kopete::Global::Properties::self()->firstName()),
++	propSecondName(),
++	propLastName(Kopete::Global::Properties::self()->lastName()),
++	propNickName(Kopete::Global::Properties::self()->nickName()),
++	propTitle("YABTitle", i18n("Title"), QString::null, true, false),
++	propPhoneMobile(Kopete::Global::Properties::self()->privateMobilePhone()),
++	propEmail(Kopete::Global::Properties::self()->emailAddress()),
++	propYABId("YABId", i18n("YAB Id"), QString::null, true, false, true),
++	propPager("YABPager", i18n("Pager number"), QString::null, true, false),
++	propFax("YABFax", i18n("Fax number"), QString::null, true, false),
++	propAdditionalNumber("YABAdditionalNumber", i18n("Additional number"), QString::null, true, false),
++	propAltEmail1("YABAlternativeEmail1", i18n("Alternative email 1"), QString::null, true, false),
++	propAltEmail2("YABAlternativeEmail2", i18n("Alternative email 1"), QString::null, true, false),
++	propImAIM("YABIMAIM", i18n("AIM"), QString::null, true, false),
++	propImICQ("YABIMICQ", i18n("ICQ"), QString::null, true, false),
++	propImMSN("YABIMMSN", i18n("MSN"), QString::null, true, false),
++	propImGoogleTalk("YABIMGoogleTalk", i18n("GoogleTalk"), QString::null, true, false),
++	propImSkype("YABIMSkype", i18n("Skype"), QString::null, true, false),
++	propImIRC("YABIMIRC", i18n("IRC"), QString::null, true, false),
++	propImQQ("YABIMQQ", i18n("QQ"), QString::null, true, false),
++	propPrivateAddress("YABPrivateAddress", i18n("Private Address"), QString::null, true, false),
++	propPrivateCity("YABPrivateCity", i18n("Private City"), QString::null, true, false),
++	propPrivateState("YABPrivateState", i18n("Private State"), QString::null, true, false),
++	propPrivateZIP("YABPrivateZIP", i18n("Private ZIP"), QString::null, true, false),
++	propPrivateCountry("YABPrivateCountry", i18n("Private Country"), QString::null, true, false),
++	propPrivatePhone(Kopete::Global::Properties::self()->privatePhone()),
++	propPrivateURL("YABPrivateURL", i18n("Private URL"), QString::null, true, false),
++	propCorporation("YABCorporation", i18n("Corporation"), QString::null, true, false),
++	propWorkAddress("YABWorkAddress", i18n("Work Address"), QString::null, true, false),
++	propWorkCity("YABWorkCity", i18n("Work City"), QString::null, true, false),
++	propWorkState("YABWorkState", i18n("Work State"), QString::null, true, false),
++	propWorkZIP("YABWorkZIP", i18n("Work ZIP"), QString::null, true, false),
++	propWorkCountry("YABWorkCountry", i18n("Work Country"), QString::null, true, false),
++	propWorkPhone(Kopete::Global::Properties::self()->workPhone()),
++	propWorkURL("YABWorkURL", i18n("Work URL"), QString::null, true, false),
++	propBirthday("YABBirthday", i18n("Birthday"), QString::null, true, false),
++	propAnniversary("YABAnniversary", i18n("Anniversary"), QString::null, true, false),
++	propNotes("YABNotes", i18n("Notes"), QString::null, true, false),
++	propAdditional1("YABAdditional1", i18n("Additional 1"), QString::null, true, false),
++	propAdditional2("YABAdditional2", i18n("Additional 2"), QString::null, true, false),
++	propAdditional3("YABAdditional3", i18n("Additional 3"), QString::null, true, false),
++	propAdditional4("YABAdditional4", i18n("Additional 4"), QString::null, true, false)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	s_protocolStatic_ = this;
+ 	setCapabilities( RichFgColor | RichFormatting | RichFont );
+@@ -70,7 +111,7 @@
+ 
+ YahooProtocol::~YahooProtocol()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	s_protocolStatic_ = 0L;
+ }
+ 
+@@ -133,12 +174,12 @@
+ 	YahooAccount *theAccount = static_cast<YahooAccount*>(Kopete::AccountManager::self()->findAccount(protocol()->pluginId(), accountId));
+ 
+ 	if(!theAccount)
+-	{	kdDebug( 14180 ) << k_funcinfo << "Account " << accountId << " not found" << endl;
++	{	kdDebug( YAHOO_GEN_DEBUG ) << k_funcinfo << "Account " << accountId << " not found" << endl;
+ 		return 0;
+ 	}
+ 
+ 	if(theAccount->contact(contactId))
+-	{	kdDebug( 14180 ) << k_funcinfo << "User " << contactId << " already in contacts map" << endl;
++	{	kdDebug( YAHOO_GEN_DEBUG ) << k_funcinfo << "User " << contactId << " already in contacts map" << endl;
+ 		return 0;
+ 	}
+ 
+@@ -148,7 +189,7 @@
+ 
+ AddContactPage *YahooProtocol::createAddContactWidget( QWidget * parent , Kopete::Account* )
+ {
+-	kdDebug(14180) << "YahooProtocol::createAddContactWidget(<parent>)" << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << "YahooProtocol::createAddContactWidget(<parent>)" << endl;
+ 	return new YahooAddContact(this, parent);
+ }
+ 
+--- kopete/protocols/yahoo/yahooeditaccount.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahooeditaccount.cpp	(revision 586398)
+@@ -49,7 +49,7 @@
+ // Yahoo Add Contact page
+ YahooEditAccount::YahooEditAccount(YahooProtocol *protocol, Kopete::Account *theAccount, QWidget *parent, const char* /*name*/): YahooEditAccountBase(parent), KopeteEditAccountWidget(theAccount)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	theProtocol = protocol;
+ 
+@@ -81,6 +81,9 @@
+ 		if( !iconUrl.isEmpty() )
+ 			m_Picture->setPixmap( KURL( iconUrl ).path() );
+ 		editPictureUrl->setEnabled( sendPicture );
++
++		// Global Identity
++		mGlobalIdentity->setChecked( account()->configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) );
+ 	}
+ 
+ 	QObject::connect(buttonRegister, SIGNAL(clicked()), this, SLOT(slotOpenRegister()));
+@@ -98,7 +101,7 @@
+ 
+ bool YahooEditAccount::validateData()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	if(mScreenName->text().isEmpty())
+ 	{	KMessageBox::queuedMessageBox(this, KMessageBox::Sorry,
+@@ -115,7 +118,7 @@
+ 
+ Kopete::Account *YahooEditAccount::apply()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	if ( !account() )
+ 		setAccount( new YahooAccount( theProtocol, mScreenName->text().lower() ) );
+@@ -148,6 +151,9 @@
+ 		yahooAccount->setBuddyIcon( KURL( QString::null ) );
+ 	}
+ 	
++	// Global Identity
++	account()->configGroup()->writeEntry("ExcludeGlobalIdentity", mGlobalIdentity->isChecked() );
++
+ 	return yahooAccount;
+ }
+ 
+--- kopete/protocols/yahoo/yahoowebcam.h	(revision 0)
++++ kopete/protocols/yahoo/yahoowebcam.h	(revision 586398)
+@@ -0,0 +1,62 @@
++/*
++    yahoowebcam.h - Send webcam images
++
++    Copyright (c) 2005 by André Duffec <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * 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 YAHOOWEBCAM_H
++#define YAHOOWEBCAM_H
++
++#include <qobject.h>
++#include <qstringlist.h>
++
++class YahooAccount;
++class YahooWebcamDialog;
++class QTimer;
++class QImage;
++class KTempFile;
++
++namespace Kopete { 
++	namespace AV	{
++		class VideoDevicePool;
++	}
++}
++
++class YahooWebcam : public QObject
++{	
++	Q_OBJECT
++public:
++	YahooWebcam( YahooAccount *account );
++	~YahooWebcam();
++public slots:
++	void startTransmission();
++	void stopTransmission();
++	void sendImage();
++	void updateImage();
++	void webcamDialogClosing();
++	void addViewer( const QString & );
++	void removeViewer( const QString & );
++signals:
++	void webcamClosing();
++private:
++	YahooAccount *theAccount;
++	YahooWebcamDialog *theDialog;
++	QTimer *m_sendTimer;
++	QTimer *m_updateTimer;
++	QStringList m_viewer;
++	QImage *m_img;
++	KTempFile *origImg;
++	KTempFile *convertedImg;
++	Kopete::AV::VideoDevicePool *m_devicePool;
++};
++
++#endif
+--- kopete/protocols/yahoo/yahooaddcontact.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahooaddcontact.cpp	(revision 586398)
+@@ -35,7 +35,7 @@
+ // Yahoo Add Contact page
+ YahooAddContact::YahooAddContact(YahooProtocol *owner, QWidget *parent, const char *name): AddContactPage(parent, name)
+ {
+-	kdDebug(14180) << "YahooAddContact::YahooAddContact(<owner>, <parent>, " << name << ")" << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << "YahooAddContact::YahooAddContact(<owner>, <parent>, " << name << ")" << endl;
+ 
+ 	(new QVBoxLayout(this))->setAutoAdd(true);
+ 	theDialog = new YahooAddContactBase(this);
+@@ -46,19 +46,19 @@
+ // Destructor
+ YahooAddContact::~YahooAddContact()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+ bool YahooAddContact::validateData()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	return !theDialog->contactID->text().isEmpty();
+ }
+ 
+ bool YahooAddContact::apply(Kopete::Account *theAccount, Kopete::MetaContact *theMetaContact)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	QString displayName = theDialog->contactID->text();
+ 	YahooAccount* myAccount = static_cast<YahooAccount*>(theAccount);
+--- kopete/protocols/yahoo/yahooprotocol.h	(revision 568672)
++++ kopete/protocols/yahoo/yahooprotocol.h	(revision 586398)
+@@ -19,12 +19,6 @@
+ #ifndef YAHOOPROTOCOL_H
+ #define YAHOOPROTOCOL_H
+ 
+-#include "libyahoo2/yahoo2.h"
+-#include "libyahoo2/yahoo2_callbacks.h"
+-
+-// Local Includes
+-#include "kyahoo.h"
+-
+ // Kopete Includes
+ #include "kopeteonlinestatus.h"
+ 
+@@ -69,11 +63,65 @@
+ 	const Kopete::OnlineStatus Idle;
+ 	const Kopete::OnlineStatus Connecting;
+ 
+-	const Kopete::ContactPropertyTmpl awayMessage;
+-	const Kopete::ContactPropertyTmpl iconCheckSum;
+-	const Kopete::ContactPropertyTmpl iconExpire;
+-	const Kopete::ContactPropertyTmpl iconRemoteUrl;
++	const Kopete::ContactPropertyTmpl 	awayMessage;
++	const Kopete::ContactPropertyTmpl 	iconCheckSum;
++	const Kopete::ContactPropertyTmpl 	iconExpire;
++	const Kopete::ContactPropertyTmpl 	iconRemoteUrl;
+ 
++	// Personal
++	const Kopete::ContactPropertyTmpl	propfirstName;
++	const Kopete::ContactPropertyTmpl	propSecondName;
++	const Kopete::ContactPropertyTmpl	propLastName;
++	const Kopete::ContactPropertyTmpl	propNickName;
++	const Kopete::ContactPropertyTmpl	propTitle;
++
++	// Primary Information	
++	const Kopete::ContactPropertyTmpl	propPhoneMobile;
++	const Kopete::ContactPropertyTmpl	propEmail;
++	const Kopete::ContactPropertyTmpl	propYABId;
++
++	// Additional Information
++	const Kopete::ContactPropertyTmpl	propPager;
++	const Kopete::ContactPropertyTmpl	propFax;
++	const Kopete::ContactPropertyTmpl	propAdditionalNumber;
++	const Kopete::ContactPropertyTmpl	propAltEmail1;
++	const Kopete::ContactPropertyTmpl	propAltEmail2;
++	const Kopete::ContactPropertyTmpl	propImAIM;
++	const Kopete::ContactPropertyTmpl	propImICQ;
++	const Kopete::ContactPropertyTmpl	propImMSN;
++	const Kopete::ContactPropertyTmpl	propImGoogleTalk;
++	const Kopete::ContactPropertyTmpl	propImSkype;
++	const Kopete::ContactPropertyTmpl	propImIRC;
++	const Kopete::ContactPropertyTmpl	propImQQ;
++
++	// Private Information
++	const Kopete::ContactPropertyTmpl	propPrivateAddress;
++	const Kopete::ContactPropertyTmpl	propPrivateCity;
++	const Kopete::ContactPropertyTmpl	propPrivateState;
++	const Kopete::ContactPropertyTmpl	propPrivateZIP;
++	const Kopete::ContactPropertyTmpl	propPrivateCountry;
++	const Kopete::ContactPropertyTmpl	propPrivatePhone;
++	const Kopete::ContactPropertyTmpl	propPrivateURL;
++		
++	// Work Information
++	const Kopete::ContactPropertyTmpl	propCorporation;
++	const Kopete::ContactPropertyTmpl	propWorkAddress;
++	const Kopete::ContactPropertyTmpl	propWorkCity;
++	const Kopete::ContactPropertyTmpl	propWorkState;
++	const Kopete::ContactPropertyTmpl	propWorkZIP;
++	const Kopete::ContactPropertyTmpl	propWorkCountry;
++	const Kopete::ContactPropertyTmpl	propWorkPhone;
++	const Kopete::ContactPropertyTmpl	propWorkURL;
++
++	// Miscellanous
++	const Kopete::ContactPropertyTmpl	propBirthday;
++	const Kopete::ContactPropertyTmpl	propAnniversary;
++	const Kopete::ContactPropertyTmpl	propNotes;
++	const Kopete::ContactPropertyTmpl	propAdditional1;
++	const Kopete::ContactPropertyTmpl	propAdditional2;
++	const Kopete::ContactPropertyTmpl	propAdditional3;
++	const Kopete::ContactPropertyTmpl	propAdditional4;
++
+ 	/** Protocol Accessor **/
+ 	static YahooProtocol *protocol();
+ 
+--- kopete/protocols/yahoo/yahooconferencemessagemanager.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahooconferencemessagemanager.cpp	(revision 586398)
+@@ -2,8 +2,9 @@
+     yahooconferencemessagemanager.h - Yahoo Conference Message Manager
+ 
+     Copyright (c) 2003 by Duncan Mac-Vicar <duncan at kde.org>
++    Copyright (c) 2005 by André Duffeck        <andre at duffeck.de>
+ 
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -15,7 +16,6 @@
+     *************************************************************************
+ */
+ 
+-
+ #include <kdebug.h>
+ #include <klineeditdlg.h>
+ #include <klocale.h>
+@@ -23,26 +23,92 @@
+ #include <kpopupmenu.h>
+ #include <kconfig.h>
+ 
+-#include "kopetecontactaction.h"
+-#include "kopetecontactlist.h"
+-#include "kopetecontact.h"
+-#include "kopetechatsessionmanager.h"
++#include <kopetecontactaction.h>
++#include <kopetecontactlist.h>
++#include <kopetecontact.h>
++#include <kopetechatsessionmanager.h>
++#include <kopeteuiglobal.h>
+ 
+ #include "yahooconferencemessagemanager.h"
++#include "yahoocontact.h"
++#include "yahooaccount.h"
++#include "yahooinvitelistimpl.h"
+ 
+-YahooConferenceChatSession::YahooConferenceChatSession( const QString & /* yahooRoom */, Kopete::Protocol *protocol, const Kopete::Contact *user,
++YahooConferenceChatSession::YahooConferenceChatSession( const QString & yahooRoom, Kopete::Protocol *protocol, const Kopete::Contact *user,
+ 	Kopete::ContactPtrList others, const char *name )
+ : Kopete::ChatSession( user, others, protocol,  name )
+ {
++
+ 	Kopete::ChatSessionManager::self()->registerChatSession( this );
++	setInstance(protocol->instance());
++
++	connect ( this, SIGNAL( messageSent ( Kopete::Message &, Kopete::ChatSession * ) ),
++			  SLOT( slotMessageSent ( Kopete::Message &, Kopete::ChatSession * ) ) );
++
++	m_yahooRoom = yahooRoom;
++
++	m_actionInvite = new KAction( i18n( "&Invite others" ), "kontact_contacts", this, SLOT( slotInviteOthers() ), actionCollection(), "yahooInvite");
++
++	setXMLFile("yahooconferenceui.rc");
+ }
+ 
+ YahooConferenceChatSession::~YahooConferenceChatSession()
+ {
++	emit leavingConference( this );
+ }
+ 
++YahooAccount *YahooConferenceChatSession::account()
++{
++	return static_cast< YahooAccount *>( Kopete::ChatSession::account() );
++}	
+ 
++const QString &YahooConferenceChatSession::room()
++{
++	return m_yahooRoom;
++}
+ 
++void YahooConferenceChatSession::joined( YahooContact *c )
++{
++	addContact( c );
++}
++
++void YahooConferenceChatSession::left( YahooContact *c )
++{
++	removeContact( c );
++}
++
++void YahooConferenceChatSession::slotMessageSent( Kopete::Message & message, Kopete::ChatSession * )
++{
++	kdDebug ( YAHOO_GEN_DEBUG ) << k_funcinfo << endl;
++
++	YahooAccount *acc = dynamic_cast< YahooAccount *>( account() );
++	if( acc )
++		acc->sendConfMessage( this, message );
++	appendMessage( message );
++	messageSucceeded();
++}
++
++void YahooConferenceChatSession::slotInviteOthers()
++{
++	QStringList buddies;
++	QDictIterator<Kopete::Contact> it( account()->contacts() );
++	Kopete::Contact *myself = account()->myself();
++	for( ; it.current(); ++it )
++	{
++		if( (*it) != myself && !members().contains( *it ) )
++			buddies.push_back( (*it)->contactId() );
++	}
++
++	YahooInviteListImpl *dlg = new YahooInviteListImpl( Kopete::UI::Global::mainWidget() );
++	QObject::connect( dlg, SIGNAL( readyToInvite( const QString &, const QStringList &, const QStringList &, const QString & ) ), 
++				account(), SLOT( slotAddInviteConference( const QString &, const QStringList &, const QStringList &, const QString & ) ) );
++	dlg->setRoom( m_yahooRoom );
++	dlg->fillFriendList( buddies );
++	for( QPtrList<Kopete::Contact>::ConstIterator it = members().begin(); it != members().end(); it++ )
++		dlg->addParticipant( (*it)->contactId() );
++	dlg->show();
++}
++
+ #include "yahooconferencemessagemanager.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/yahoo/yahooconferencemessagemanager.h	(revision 568672)
++++ kopete/protocols/yahoo/yahooconferencemessagemanager.h	(revision 586398)
+@@ -2,8 +2,9 @@
+     yahooconferencemessagemanager.h - Yahoo Conference Message Manager
+ 
+     Copyright (c) 2003 by Duncan Mac-Vicar Prett <duncan at kde.org>
++    Copyright (c) 2005 by André Duffeck        <andre at duffeck.de>
+ 
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -22,9 +23,9 @@
+ 
+ class KActionCollection;
+ class YahooContact;
++class YahooAccount;
+ class KActionMenu;
+ 
+-
+ /**
+  * @author Duncan Mac-Vicar Prett
+  */
+@@ -35,8 +36,20 @@
+ public:
+ 	YahooConferenceChatSession( const QString &m_yahooRoom, Kopete::Protocol *protocol, const Kopete::Contact *user, Kopete::ContactPtrList others, const char *name = 0 );
+ 	~YahooConferenceChatSession();
++
++	void joined( YahooContact *c );
++	void left( YahooContact *c );
++	const QString &room();
++	YahooAccount *account();
++signals:
++	void leavingConference( YahooConferenceChatSession *s );
++protected slots:
++	void slotMessageSent( Kopete::Message &message, Kopete::ChatSession * );
++	void slotInviteOthers();
+ private:
+ 	QString m_yahooRoom;
++
++	KAction *m_actionInvite;
+ };
+ 
+ #endif
+--- kopete/protocols/yahoo/yahooverifyaccount.cpp	(revision 0)
++++ kopete/protocols/yahoo/yahooverifyaccount.cpp	(revision 586398)
+@@ -0,0 +1,107 @@
++/*
++    yahooverifyaccount.cpp - UI Page for Verifying a locked account
++
++    Copyright (c) 2005 by André Duffeck          <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * 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.                                   *
++    *                                                                       *
++    *************************************************************************
++*/
++
++// QT Includes
++#include <qlayout.h>
++#include <qfile.h>
++#include <qlabel.h>
++
++// KDE Includes
++#include <kdebug.h>
++#include <klineedit.h>
++#include <ktempfile.h>
++#include <klocale.h>
++#include <kio/global.h>
++#include <kio/job.h>
++#include <kio/jobclasses.h>
++#include <kstandarddirs.h>
++
++// Kopete Includes
++#include <yahooverifyaccountbase.h>
++#include <kopeteaccount.h>
++
++// Local Includes
++#include "yahooverifyaccountbase.h"
++#include "yahooverifyaccount.h"
++#include "yahooaccount.h"
++
++YahooVerifyAccount::YahooVerifyAccount(Kopete::Account *account, QWidget *parent, const char *name)
++: KDialogBase(parent, name, true, i18n("Account Verification - Yahoo"), Cancel|Apply,
++              Apply, true )
++{
++	mTheAccount = account;	
++	mTheDialog = new YahooVerifyAccountBase( this );
++	mTheDialog->mPicture->hide();
++	setMainWidget( mTheDialog );
++	setEscapeButton( Cancel );
++}
++
++// Destructor
++YahooVerifyAccount::~YahooVerifyAccount()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++}
++
++void YahooVerifyAccount::setUrl( KURL url )
++{
++	mFile = new KTempFile( locateLocal( "tmp", url.fileName() ) );
++	mFile->setAutoDelete( true );
++	KIO::TransferJob *transfer = KIO::get( url, false, false );
++	connect( transfer, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotComplete( KIO::Job* ) ) );
++	connect( transfer, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
++}
++
++void YahooVerifyAccount::slotData( KIO::Job */*job*/, const QByteArray& data )
++{
++
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++
++	mFile->file()->writeBlock( data.data() , data.size() );
++}
++
++void YahooVerifyAccount::slotComplete( KIO::Job */*job*/ )
++{
++
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	mFile->file()->close();
++	mTheDialog->mPicture->setPixmap( mFile->file()->name() );
++	mTheDialog->mPicture->show();
++}
++
++bool YahooVerifyAccount::validateData()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++
++	return ( !mTheDialog->mWord->text().isEmpty() );
++}
++
++void YahooVerifyAccount::slotClose()
++{
++	QDialog::done(0);
++}
++
++void YahooVerifyAccount::slotApply()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++
++	YahooAccount* myAccount = static_cast<YahooAccount*>(mTheAccount);
++	myAccount->verifyAccount( mTheDialog->mWord->text() );
++	QDialog::done(0);
++}
++
++#include "yahooverifyaccount.moc"
++
++// vim: set noet ts=4 sts=4 sw=4:
++
+--- kopete/protocols/yahoo/yahoochatsession.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahoochatsession.cpp	(revision 586398)
+@@ -1,7 +1,7 @@
+ /*
+     yahoochatsession.cpp - Yahoo! Message Manager
+ 
+-    Copyright (c) 2005 by André Duffeck        <andre at duffeck.de>
++    Copyright (c) 2005 by André Duffeck        <andre at duffeck.de>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -48,16 +48,17 @@
+ 	Kopete::ContactPtrList others, const char *name )
+ : Kopete::ChatSession( user, others, protocol,  name )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	Kopete::ChatSessionManager::self()->registerChatSession( this );
+ 	setInstance(protocol->instance());
+ 
+ 	// Add Actions
+ 	new KAction( i18n( "Buzz Contact" ), QIconSet(BarIcon("bell")), "Ctrl+G", this, SLOT( slotBuzzContact() ), actionCollection(), "yahooBuzz" ) ;
+ 	new KAction( i18n( "Show User Info" ), QIconSet(BarIcon("idea")), 0, this, SLOT( slotUserInfo() ), actionCollection(), "yahooShowInfo" ) ;
+-	new KAction( i18n( "Request Webcam" ), QIconSet(BarIcon("image")), 0, this, SLOT( slotRequestWebcam() ), actionCollection(), "yahooRequestWebcam" ) ;
++	new KAction( i18n( "Request Webcam" ), QIconSet(BarIcon("webcamreceive")), 0, this, SLOT( slotRequestWebcam() ), actionCollection(), "yahooRequestWebcam" ) ;
++	new KAction( i18n( "Invite to view your Webcam" ), QIconSet(BarIcon("webcamsend")), 0, this, SLOT( slotInviteWebcam() ), actionCollection(), "yahooSendWebcam" ) ;
++	new KAction( i18n( "Send File" ), QIconSet(BarIcon("attach")), 0, this, SLOT( slotSendFile() ), actionCollection(), "yahooSendFile" );
+ 
+-
+ 	YahooContact *c = static_cast<YahooContact*>( others.first() );
+ 	connect( c, SIGNAL( displayPictureChanged() ), this, SLOT( slotDisplayPictureChanged() ) );
+ 	m_image = new QLabel( 0L, "kde toolbar widget" );
+@@ -81,28 +82,42 @@
+ 
+ void YahooChatSession::slotBuzzContact()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QPtrList<Kopete::Contact>contacts = members();
+ 	static_cast<YahooContact *>(contacts.first())->buzzContact();
+ }
+ 
+ void YahooChatSession::slotUserInfo()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QPtrList<Kopete::Contact>contacts = members();
+ 	static_cast<YahooContact *>(contacts.first())->slotUserInfo();
+ }
+ 
+ void YahooChatSession::slotRequestWebcam()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QPtrList<Kopete::Contact>contacts = members();
+ 	static_cast<YahooContact *>(contacts.first())->requestWebcam();
+ }
+ 
++void YahooChatSession::slotInviteWebcam()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	QPtrList<Kopete::Contact>contacts = members();
++	static_cast<YahooContact *>(contacts.first())->inviteWebcam();
++}
++
++void YahooChatSession::slotSendFile()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	QPtrList<Kopete::Contact>contacts = members();
++	static_cast<YahooContact *>(contacts.first())->sendFile();
++}
++
+ void YahooChatSession::slotDisplayPictureChanged()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QPtrList<Kopete::Contact> mb=members();
+ 	YahooContact *c = static_cast<YahooContact *>( mb.first() );
+ 	if ( c && m_image )
+--- kopete/protocols/yahoo/yahooverifyaccount.h	(revision 0)
++++ kopete/protocols/yahoo/yahooverifyaccount.h	(revision 586398)
+@@ -0,0 +1,57 @@
++/*
++    yahooverifyaccount.h - UI Page for Verifying a locked account
++
++    Copyright (c) 2005 by André Duffeck          <andre.duffeck at kdemail.net>
++
++    *************************************************************************
++    *                                                                       *
++    * 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 __YAHOOVERIFYACCOUNT_H
++#define __YAHOOVERIFYACCOUNT_H
++
++// Local Includes
++
++// Kopete Includes
++// QT Includes
++
++// KDE Includes
++#include <kdialogbase.h>
++
++namespace Kopete { class Account; }
++class YahooVerifyAccountBase;
++class KTempFile;
++
++class YahooVerifyAccount : public KDialogBase
++{
++	Q_OBJECT
++private:
++	Kopete::Account *mTheAccount;
++	KTempFile *mFile;
++	YahooVerifyAccountBase *mTheDialog;
++public:
++	YahooVerifyAccount(Kopete::Account *account, QWidget *parent = 0, const char *name = 0);
++	~YahooVerifyAccount();
++
++	virtual bool validateData();
++
++	void setUrl( KURL url );
++
++protected slots:
++	virtual void slotClose();
++	virtual void slotApply();
++public slots:
++	void slotData( KIO::Job *job, const QByteArray& data );
++	void slotComplete( KIO::Job *job );
++};
++
++#endif
++
++// vim: set noet ts=4 sts=4 sw=4:
++
+--- kopete/protocols/yahoo/yahooconferenceui.rc	(revision 0)
++++ kopete/protocols/yahoo/yahooconferenceui.rc	(revision 586398)
+@@ -0,0 +1,11 @@
++<!DOCTYPE kpartgui>
++<kpartgui version="4" name="kopete_yahoo_conference">
++	<MenuBar>
++		<Menu noMerge="1" name="file">
++                        <text>&amp;Chat</text>
++			<Action name="yahooInvite" />
++		</Menu>
++	</MenuBar>
++
++</kpartgui>
++
+--- kopete/protocols/yahoo/yahoochatsession.h	(revision 568672)
++++ kopete/protocols/yahoo/yahoochatsession.h	(revision 586398)
+@@ -41,6 +41,8 @@
+ 	void slotBuzzContact();
+ 	void slotUserInfo();
+ 	void slotRequestWebcam();
++	void slotInviteWebcam();
++	void slotSendFile();
+ 
+ private:
+ 	QLabel *m_image;
+--- kopete/protocols/yahoo/Makefile.am	(revision 568672)
++++ kopete/protocols/yahoo/Makefile.am	(revision 586398)
+@@ -1,23 +1,26 @@
+-SUBDIRS = libyahoo2 ui icons
++SUBDIRS = libkyahoo ui icons
+ METASOURCES = AUTO
+ 
+ AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+ 	-I$(srcdir)/ui \
+ 	-Iui \
++	-I$(srcdir)/libkyahoo \
+ 	$(all_includes)
+ 
+ kde_module_LTLIBRARIES = kopete_yahoo.la
+ 
+-kopete_yahoo_la_SOURCES = yahooprotocol.cpp kyahoo.cpp yahoocontact.cpp \
++kopete_yahoo_la_SOURCES = yahooprotocol.cpp yahoocontact.cpp \
+ 	yahooaddcontact.cpp yahooaccount.cpp yahooeditaccount.cpp yahooconferencemessagemanager.cpp \
+-	yahoouserinfo.cpp yahoobuddyiconloader.cpp yahoochatsession.cpp yahoochatsession.h
+-kopete_yahoo_la_LDFLAGS     = -module $(KDE_PLUGIN) $(all_libraries)
+-kopete_yahoo_la_LIBADD      = $(top_builddir)/kopete/libkopete/libkopete.la  ui/libkopeteyahooui.la libyahoo2/libyahoo2.la
++	yahoochatsession.cpp yahooverifyaccount.cpp yahoowebcam.cpp
++kopete_yahoo_la_LDFLAGS     = -module $(KDE_PLUGIN)
++kopete_yahoo_la_LIBADD = ../../libkopete/avdevice/libkopete_videodevice.la \
++	$(top_builddir)/kopete/libkopete/libkopete.la ui/libkopeteyahooui.la libkyahoo/libkyahoo.la
+ 
+ service_DATA = kopete_yahoo.desktop
+ servicedir = $(kde_servicesdir)
+ 
+-noinst_HEADERS = yahoouserinfo.h yahoobuddyiconloader.h
+ 
+ mydatadir = $(kde_datadir)/kopete_yahoo
+-mydata_DATA = yahoochatui.rc
++mydata_DATA = yahooconferenceui.rc yahoochatui.rc
++
++
+--- kopete/protocols/yahoo/yahoocontact.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahoocontact.cpp	(revision 586398)
+@@ -25,13 +25,18 @@
+ #include "kopetemetacontact.h"
+ #include "kopeteuiglobal.h"
+ #include "kopeteview.h"
++#include "kopetetransfermanager.h"
+ 
+ // Local Includes
+ #include "yahoocontact.h"
+ #include "yahooaccount.h"
++#include "client.h"
+ #include "yahoowebcamdialog.h"
+ #include "yahoostealthsetting.h"
+ #include "yahoochatsession.h"
++#include "yabentry.h"
++#include "yahoouserinfodialog.h"
++#include "sendfiletask.h"
+ 
+ // QT Includes
+ #include <qregexp.h>
+@@ -51,20 +56,24 @@
+ #include <kio/job.h>
+ #include <kurl.h>
+ #include <kio/jobclasses.h>
+-//#include <kimageio.h>
++#include <kimageio.h>
+ #include <kstandarddirs.h>
+ #include <kfiledialog.h>
+ 
+ YahooContact::YahooContact( YahooAccount *account, const QString &userId, const QString &fullName, Kopete::MetaContact *metaContact )
+ 	: Kopete::Contact( account, userId, metaContact )
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	m_userId = userId;
+ 	if ( metaContact )
+ 		m_groupName = metaContact->groups().getFirst()->displayName();
+ 	m_manager = 0L;
+ 	m_account = account;
++	m_YABEntry = 0L;
++	m_stealthed = false;
++	m_receivingWebcam = false;
++	m_sessionActive = false;
+ 
+ 	// Update ContactList
+ 	setNickName( fullName );
+@@ -77,35 +86,70 @@
+ 	m_webcamDialog = 0L;
+ 	m_webcamAction = 0L;
+ 	m_stealthAction = 0L;
++	m_inviteWebcamAction = 0L;
++	m_inviteConferenceAction = 0L;
++	m_profileAction = 0L;
+ 
+ 	m_buzzAction = 0L;
+ }
+ 
+ YahooContact::~YahooContact()
+ {
++	delete m_YABEntry;
++	m_YABEntry = 0L;
+ }
+ 
++QString YahooContact::userId() const
++{
++	return m_userId;
++}
++
+ void YahooContact::setOnlineStatus(const Kopete::OnlineStatus &status)
+ {
+-	Contact::setOnlineStatus( status );
++	if( m_stealthed && status.internalStatus() <= 999)	// Not Stealted -> Stealthed
++	{
++		Contact::setOnlineStatus( 
++			Kopete::OnlineStatus(status.status() ,
++			(status.weight()==0) ? 0 : (status.weight() -1)  ,
++			protocol() ,
++			status.internalStatus()+1000 ,
++			status.overlayIcons() + QStringList("yahoo_stealthed") ,
++			i18n("%1|Stealthed").arg( status.description() ) ) );
++	}
++	else if( !m_stealthed && status.internalStatus() > 999 )// Stealthed -> Not Stealthed
++		Contact::setOnlineStatus( static_cast< YahooProtocol *>( protocol() )->statusFromYahoo( status.internalStatus() - 1000 ) );
++	else
++		Contact::setOnlineStatus( status );
++	
+ 	if( status.status() == Kopete::OnlineStatus::Offline ) 
+ 		removeProperty( ((YahooProtocol*)(m_account->protocol()))->awayMessage);
+ }
+ 
++void YahooContact::setStealthed( bool stealthed )
++{
++	m_stealthed = stealthed;
++	setOnlineStatus( onlineStatus() );
++}
++
++bool YahooContact::stealthed()
++{
++	return m_stealthed;
++}
++
+ void YahooContact::serialize(QMap<QString, QString> &serializedData, QMap<QString, QString> &addressBookData)
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	Kopete::Contact::serialize(serializedData, addressBookData);
+ }
+ 
+ void YahooContact::syncToServer()
+ {
+-	kdDebug(14180) << k_funcinfo  << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo  << endl;
+ 	if(!m_account->isConnected()) return;
+ 
+ 	if ( !m_account->isOnServer(m_userId) && !metaContact()->isTemporary() )
+-	{	kdDebug(14180) << "Contact " << m_userId << " doesn't exist on server-side. Adding..." << endl;
++	{	kdDebug(YAHOO_GEN_DEBUG) << "Contact " << m_userId << " doesn't exist on server-side. Adding..." << endl;
+ 
+ 		Kopete::GroupList groupList = metaContact()->groups();
+ 		for( Kopete::Group *g = groupList.first(); g; g = groupList.next() )
+@@ -115,13 +159,14 @@
+ 
+ void YahooContact::sync(unsigned int flags)
+ {
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo  << endl;
+ 	if ( !m_account->isConnected() )
+ 		return;
+ 
+ 	if ( !m_account->isOnServer( contactId() ) )
+ 	{
+ 		//TODO: Share this code with the above function
+-		kdDebug(14180) << k_funcinfo << "Contact isn't on the server. Adding..." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Contact isn't on the server. Adding..." << endl;
+ 		Kopete::GroupList groupList = metaContact()->groups();
+ 		for ( Kopete::Group *g = groupList.first(); g; g = groupList.next() )
+ 			m_account->yahooSession()->addBuddy(m_userId, g->displayName() );
+@@ -131,8 +176,8 @@
+ 		QString newGroup = metaContact()->groups().first()->displayName();
+ 		if ( flags & Kopete::Contact::MovedBetweenGroup )
+ 		{
+-			kdDebug(14180) << k_funcinfo << "contact changed groups. moving on server" << endl;
+-			m_account->yahooSession()->changeBuddyGroup( contactId(), m_groupName, newGroup );
++			kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact changed groups. moving on server" << endl;
++			m_account->yahooSession()->moveBuddy( contactId(), m_groupName, newGroup );
+ 			m_groupName = newGroup;
+ 		}
+ 	}
+@@ -141,13 +186,13 @@
+ 
+ bool YahooContact::isOnline() const
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	return onlineStatus().status() != Kopete::OnlineStatus::Offline && onlineStatus().status() != Kopete::OnlineStatus::Unknown;
+ }
+ 
+ bool YahooContact::isReachable()
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	if ( m_account->isConnected() )
+ 		return true;
+ 	else
+@@ -165,26 +210,21 @@
+ 		connect( m_manager, SIGNAL( messageSent ( Kopete::Message&, Kopete::ChatSession* ) ), this, SLOT( slotSendMessage( Kopete::Message& ) ) );
+ 		connect( m_manager, SIGNAL( myselfTyping( bool) ), this, SLOT( slotTyping( bool ) ) );
+ 		connect( m_account, SIGNAL( receivedTypingMsg( const QString &, bool ) ), m_manager, SLOT( receivedTypingMsg( const QString&, bool ) ) );
+-		connect( this, SIGNAL( signalWebcamInviteAccepted() ), this, SLOT( requestWebcam() ) );
+ 		connect( this, SIGNAL(displayPictureChanged()), m_manager, SLOT(slotDisplayPictureChanged()));
+ 	}
+ 
+ 	return m_manager;
+ }
+ 
+-void YahooContact::slotSendMessage( Kopete::Message &message )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-	
++QString YahooContact::prepareMessage( const QString &messageText )
++{	
+ 	// Yahoo does not understand XML/HTML message data, so send plain text
+ 	// instead.  (Yahoo has its own format for "rich text".)
++	QString newMsg( messageText );
+ 	QRegExp regExp;
+ 	int pos = 0;
+ 	regExp.setMinimal( true );
+ 	
+-	QString messageText = message.escapedBody();
+-	kdDebug(14180) << "Original message: " << messageText << endl;
+-
+ 	// find and replace Bold-formattings
+ 	regExp.setPattern( "<span([^>]*)font-weight:600([^>]*)>(.*)</span>" );
+ 	pos = 0;
+@@ -192,7 +232,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-		messageText.replace( regExp, QString::fromLatin1("<span\\1font-weight:600\\2>\033[1m\\3\033[x1m</span>" ) );
++		newMsg.replace( regExp, QString::fromLatin1("<span\\1font-weight:600\\2>\033[1m\\3\033[x1m</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -203,7 +243,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("<span\\1text-decoration:underline\\2>\033[4m\\3\033[x4m</span>" ) );
++		newMsg.replace( regExp, QString::fromLatin1("<span\\1text-decoration:underline\\2>\033[4m\\3\033[x4m</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -214,7 +254,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("<span\\1font-style:italic\\2>\033[2m\\3\033[x2m</span>" ) );
++		newMsg.replace( regExp, QString::fromLatin1("<span\\1font-style:italic\\2>\033[2m\\3\033[x2m</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -225,7 +265,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("<span\\1\\3>\033[#\\2m\\4\033[#000000m</span>" ) );
++			newMsg.replace( regExp, QString::fromLatin1("<span\\1\\3>\033[#\\2m\\4\033[#000000m</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -236,7 +276,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("<span\\1\\3><font face=\"\\2\">\\4</span>" ) );
++			newMsg.replace( regExp, QString::fromLatin1("<span\\1\\3><font face=\"\\2\">\\4</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -247,7 +287,7 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("<span\\1\\3><font size=\"\\2\">\\4</span>" ) );
++			newMsg.replace( regExp, QString::fromLatin1("<span\\1\\3><font size=\"\\2\">\\4</span>" ) );
+ 		}
+ 	}
+ 	
+@@ -258,61 +298,50 @@
+ 		pos = regExp.search( messageText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			messageText.replace( regExp, QString::fromLatin1("\\2") );
++			newMsg.replace( regExp, QString::fromLatin1("\\2") );
+ 		}
+ 	}
+ 	
+ 	// convert escaped chars
+-	messageText.replace( QString::fromLatin1( "&gt;" ), QString::fromLatin1( ">" ) );
+-	messageText.replace( QString::fromLatin1( "&lt;" ), QString::fromLatin1( "<" ) );
+-	messageText.replace( QString::fromLatin1( "&quot;" ), QString::fromLatin1( "\"" ) );
+-	messageText.replace( QString::fromLatin1( "&nbsp;" ), QString::fromLatin1( " " ) );
+-	messageText.replace( QString::fromLatin1( "&amp;" ), QString::fromLatin1( "&" ) );
+-	messageText.replace( QString::fromLatin1( "<br/>" ), QString::fromLatin1( "\r" ) );
++	newMsg.replace( QString::fromLatin1( "&gt;" ), QString::fromLatin1( ">" ) );
++	newMsg.replace( QString::fromLatin1( "&lt;" ), QString::fromLatin1( "<" ) );
++	newMsg.replace( QString::fromLatin1( "&quot;" ), QString::fromLatin1( "\"" ) );
++	newMsg.replace( QString::fromLatin1( "&nbsp;" ), QString::fromLatin1( " " ) );
++	newMsg.replace( QString::fromLatin1( "&amp;" ), QString::fromLatin1( "&" ) );
++	newMsg.replace( QString::fromLatin1( "<br/>" ), QString::fromLatin1( "\r" ) );
+ 	
+-	kdDebug(14180) << "Converted message: " << messageText << endl;
++	return newMsg;
++}
++
++void YahooContact::slotSendMessage( Kopete::Message &message )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	
++	QString messageText = message.escapedBody();
++	kdDebug(YAHOO_GEN_DEBUG) << "Original message: " << messageText << endl;
++	messageText = prepareMessage( messageText );
++	kdDebug(YAHOO_GEN_DEBUG) << "Converted message: " << messageText << endl;
++	
+ 	Kopete::ContactPtrList m_them = manager(Kopete::Contact::CanCreate)->members();
+ 	Kopete::Contact *target = m_them.first();
+ 
+-	//TODO: move the message-length limit to chatwindow-level
+-	if( messageText.length() > 800 )
++	if( !m_sessionActive )			// Register a new chatsession
+ 	{
+-		kdDebug(14180) << "Message exceeds max. length of 800 chars. The message gets split." << endl;
+-		uint i = 0;
+-		while( i < messageText.length() )
+-		{
+-			m_account->yahooSession()->sendIm( static_cast<YahooContact*>(m_account->myself())->m_userId,
+-					static_cast<YahooContact *>(target)->m_userId, messageText.mid( i, 800 ), m_account->pictureFlag());
+-			i += 800;
+-		}		
++		m_account->yahooSession()->setChatSessionState( m_userId, false );
++		m_sessionActive = true;
+ 	}
+-	else
+-		m_account->yahooSession()->sendIm( static_cast<YahooContact*>(m_account->myself())->m_userId,
+-							static_cast<YahooContact *>(target)->m_userId, messageText, m_account->pictureFlag());
+-
++	
++	m_account->yahooSession()->sendMessage( static_cast<YahooContact *>(target)->m_userId, messageText );
++	
+ 	// append message to window
+ 	manager(Kopete::Contact::CanCreate)->appendMessage(message);
+ 	manager(Kopete::Contact::CanCreate)->messageSucceeded();
+ }
+ 
+-void YahooContact::sendFile( const KURL &sourceURL, const QString &/*fileName*/, uint fileSize )
++void YahooContact::sendFile( const KURL &sourceURL, const QString &fileName, uint fileSize )
+ {
+-	QString file;
+-	if( sourceURL.isValid() )
+-		file = sourceURL.path();
+-	else
+-	{
+-		file = KFileDialog::getOpenFileName( QString::null, "*", 0, i18n("Kopete File Transfer") );
+-		if( !file.isEmpty() )
+-		{
+-			fileSize = QFile( file ).size();
+-		}
+-		else
+-			return;
+-	}
+-	
+-	m_account->yahooSession()->sendFile( m_userId, QString(), file, fileSize );
++	Kopete::TransferManager::transferManager()->sendFile( sourceURL, fileName, fileSize, 
++			false, this, SLOT(slotSendFile( const KURL & )) );
+ }
+ 
+ void YahooContact::slotTyping(bool isTyping_ )
+@@ -321,13 +350,14 @@
+ 	Kopete::Contact *target = m_them.first();
+ 
+ 
+-	m_account->yahooSession()->sendTyping( static_cast<YahooContact*>(m_account->myself())->m_userId,
+-		static_cast<YahooContact*>(target)->m_userId, isTyping_ );
++	m_account->yahooSession()->sendTyping( static_cast<YahooContact*>(target)->m_userId, isTyping_ );
+ }
+ 
+ void YahooContact::slotChatSessionDestroyed()
+ {
+ 	m_manager = 0L;
++	m_account->yahooSession()->setChatSessionState( m_userId, true );	// Unregister chatsession
++	m_sessionActive = false;
+ }
+ 
+ QPtrList<KAction> *YahooContact::customContextMenuActions()
+@@ -335,7 +365,7 @@
+ 	QPtrList<KAction> *actionCollection = new QPtrList<KAction>();
+ 	if ( !m_webcamAction )
+ 	{
+-		m_webcamAction = new KAction( i18n( "View &Webcam" ), "camera_unmount", KShortcut(),
++		m_webcamAction = new KAction( i18n( "View &Webcam" ), "webcamreceive", KShortcut(),
+ 		                              this, SLOT( requestWebcam() ), this, "view_webcam" );
+ 	}
+ 	if ( isReachable() )
+@@ -344,9 +374,20 @@
+ 		m_webcamAction->setEnabled( false );
+ 	actionCollection->append( m_webcamAction );
+ 	
++	if( !m_inviteWebcamAction )
++	{
++		m_inviteWebcamAction = new KAction( i18n( "Invite to view your Webcam" ), "webcamsend", KShortcut(),
++		                                    this, SLOT( inviteWebcam() ), this, "invite_webcam" );
++	}
++	if ( isReachable() )
++		m_inviteWebcamAction->setEnabled( true );
++	else
++		m_inviteWebcamAction->setEnabled( false );
++	actionCollection->append( m_inviteWebcamAction );
++	
+ 	if ( !m_buzzAction )
+ 	{
+-		m_buzzAction = new KAction( i18n( "&Buzz Contact" ), KShortcut(), this, SLOT( buzzContact() ), this, "buzz_contact");
++		m_buzzAction = new KAction( i18n( "&Buzz Contact" ), "bell", KShortcut(), this, SLOT( buzzContact() ), this, "buzz_contact");
+ 	}
+ 	if ( isReachable() )
+ 		m_buzzAction->setEnabled( true );
+@@ -356,7 +397,7 @@
+ 
+ 	if ( !m_stealthAction )
+ 	{
+-		m_stealthAction = new KAction( i18n( "&Stealth Setting" ), KShortcut(), this, SLOT( stealthContact() ), this, "stealth_contact");
++		m_stealthAction = new KAction( i18n( "&Stealth Setting" ), "yahoo_stealthed", KShortcut(), this, SLOT( stealthContact() ), this, "stealth_contact");
+ 	}
+ 	if ( isReachable() )
+ 		m_stealthAction->setEnabled( true );
+@@ -364,6 +405,23 @@
+ 		m_stealthAction->setEnabled( false );
+ 	actionCollection->append( m_stealthAction );
+ 	
++	if ( !m_inviteConferenceAction )
++	{
++		m_inviteConferenceAction = new KAction( i18n( "&Invite to Conference" ), "kontact_contacts", KShortcut(), this, SLOT( inviteConference() ), this, "invite_conference");
++	}
++	if ( isReachable() )
++		m_inviteConferenceAction->setEnabled( true );
++	else
++		m_inviteConferenceAction->setEnabled( false );
++	actionCollection->append( m_inviteConferenceAction );
++	
++	if ( !m_profileAction )
++	{
++		m_profileAction = new KAction( i18n( "&View Yahoo Profile" ), "kontact_notes", KShortcut(), this, SLOT( slotUserProfile() ), this, "profile_contact");
++	}
++	m_profileAction->setEnabled( true );
++	actionCollection->append( m_profileAction );
++	
+ 	return actionCollection;
+ 	
+ 	//return 0L;
+@@ -371,35 +429,77 @@
+ 
+ void YahooContact::slotUserInfo()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
+-	if( m_account->yahooSession() )
+-		m_account->yahooSession()->getUserInfo( m_userId );
+-	else
+-		KMessageBox::information( Kopete::UI::Global::mainWidget(), i18n("You need to connect to the service in order to use this feature."),
+-		                         i18n("Not connected") );
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	if( !m_YABEntry )
++	{
++		readYABEntry();	// No YABEntry was set, so read the one from contactlist.xml
++	}
++	
++	YahooUserInfoDialog *dlg = new YahooUserInfoDialog( this, Kopete::UI::Global::mainWidget(), "yahoo userinfo" );
++	dlg->setData( *m_YABEntry );
++	dlg->setAccountConnected( m_account->isConnected() );
++	dlg->show();
++	QObject::connect( dlg, SIGNAL(saveYABEntry( YABEntry & )), m_account, SLOT(slotSaveYABEntry( YABEntry & )));
+ }
+ 
+-void YahooContact::slotSendFile()
++void YahooContact::slotUserProfile()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	QString profileSiteString = QString::fromLatin1("http://profiles.yahoo.com/") + userId();
++	KRun::runURL( KURL( profileSiteString ) , "text/html" );
+ }
+ 
++void YahooContact::slotSendFile( const KURL &url)
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	m_account->sendFile( this, url );
++}
++
+ void YahooContact::stealthContact()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	KDialogBase *stealthSettingDialog = new KDialogBase( Kopete::UI::Global::mainWidget(), "stealthSettingDialog", "true",
+ 				i18n("Stealth Setting"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, true );
+ 	YahooStealthSetting *stealthWidget = new YahooStealthSetting( stealthSettingDialog, "stealthSettingWidget" );
+ 	stealthSettingDialog->setMainWidget( stealthWidget );
+ 
++	// Prepare dialog
++	if( m_account->myself()->onlineStatus() == YahooProtocol::protocol()->Invisible )
++	{
++		stealthWidget->radioOffline->setEnabled( true );
++		stealthWidget->radioOffline->setChecked( true );
++	}
++	if( stealthed() )
++		stealthWidget->radioPermOffline->setChecked( true );
++		
++	
++	// Show dialog
+ 	if ( stealthSettingDialog->exec() == QDialog::Rejected )
++	{	
++		stealthSettingDialog->delayedDestruct();
+ 		return;
++	}
+ 	
+-	if ( stealthWidget->radioOnline->isChecked() )
+-		m_account->yahooSession()->stealthContact( m_userId, 1 );
+-	else
+-		m_account->yahooSession()->stealthContact( m_userId, 0 );
++	// Apply permanent setting
++	if( stealthed() && !stealthWidget->radioPermOffline->isChecked() )
++		m_account->yahooSession()->stealthContact( m_userId, Yahoo::StealthPermOffline, Yahoo::StealthNotActive );
++	else if( !stealthed() && stealthWidget->radioPermOffline->isChecked() )
++		m_account->yahooSession()->stealthContact( m_userId, Yahoo::StealthPermOffline, Yahoo::StealthActive );
++	
++	// Apply temporary setting
++	if( m_account->myself()->onlineStatus() == YahooProtocol::protocol()->Invisible )
++	{
++		if( stealthWidget->radioOnline->isChecked() )
++		{
++			m_account->yahooSession()->stealthContact( m_userId, Yahoo::StealthOnline, Yahoo::StealthActive );
++		}
++		else if( stealthWidget->radioOffline->isChecked() )
++		{
++			m_account->yahooSession()->stealthContact( m_userId, Yahoo::StealthOffline, Yahoo::StealthActive );
++		}
++	}
+ 
+ 	stealthSettingDialog->delayedDestruct();
+ }
+@@ -409,56 +509,41 @@
+ 	Kopete::ContactPtrList m_them = manager(Kopete::Contact::CanCreate)->members();
+ 	Kopete::Contact *target = m_them.first();
+ 	
+-	m_account->yahooSession()->buzzContact(	static_cast<YahooContact*>(m_account->myself())->m_userId, static_cast<YahooContact*>(target)->m_userId, m_account->pictureFlag() );
++	m_account->yahooSession()->sendBuzz( static_cast<YahooContact*>(target)->m_userId );
+ 
+ 	KopeteView *view = manager(Kopete::Contact::CannotCreate)->view(false);
+ 	if ( view )
+ 	{
+ 		Kopete::Message msg = Kopete::Message( manager(Kopete::Contact::CannotCreate)->myself() ,
+-									manager(Kopete::Contact::CannotCreate)->members(), i18n("Buzzz!!!"),
+-									Kopete::Message::Internal, Kopete::Message::PlainText );
++					manager(Kopete::Contact::CannotCreate)->members(), i18n("Buzzz!!!"),
++					Kopete::Message::Outbound, Kopete::Message::PlainText,
++					QString::null , Kopete::Message::TypeAction);
+ 		view->appendMessage( msg );
+ 	}
+ }
+ 
+-void YahooContact::gotWebcamInvite()
+-{
+-	// emit signalReceivedWebcamInvite();
+-	
+-	if( KMessageBox::Yes == KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(), i18n("%1 has invited you to view his/her webcam. Accept?").arg(nickName()), QString::null, i18n("Accept"), i18n("Ignore") ) )
+-		
+-	{
+-		emit signalWebcamInviteAccepted ( );
+-	}
+-	else
+-	{
+-		// libyahoo2 doesn't do anything for rejecting invites
+-	}
+-	
+-}
+-
+ void YahooContact::sendBuddyIconChecksum( int checksum )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
+-	m_account->yahooSession()->sendBuddyIconChecksum( checksum, m_userId );
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	m_account->yahooSession()->sendPictureChecksum( checksum, m_userId );
+ 	
+ }
+ 
+ void YahooContact::sendBuddyIconInfo( const QString &url, int checksum )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
+-	m_account->yahooSession()->sendBuddyIconInfo( m_userId, url, checksum );
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	m_account->yahooSession()->sendPictureInformation( m_userId, url, checksum );
+ }
+ 
+ void YahooContact::sendBuddyIconUpdate( int type )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
+-	m_account->yahooSession()->sendBuddyIconUpdate( m_userId, type );
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	m_account->yahooSession()->sendPictureStatusUpdate( m_userId, type );
+ }
+ 
+ void YahooContact::setDisplayPicture(KTempFile *f, int checksum)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	if( !f )
+ 		return;
+ 	// stolen from msncontact.cpp ;)
+@@ -474,56 +559,107 @@
+ 	connect(j, SIGNAL(result(KIO::Job *)) , this, SLOT(slotEmitDisplayPictureChanged() ));
+ }
+ 
++
++void YahooContact::setYABEntry( YABEntry *entry, bool show )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << userId() << endl;
++	if( m_YABEntry )
++		delete m_YABEntry;
++	
++	m_YABEntry = entry;
++	writeYABEntry();	// Store data in Contact
++	
++	if( show )
++		slotUserInfo();
++}
++const YABEntry *YahooContact::yabEntry()
++{
++	if( !m_YABEntry )
++		readYABEntry();
++	return m_YABEntry;
++}
++
+ void YahooContact::slotEmitDisplayPictureChanged()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QString newlocation=locateLocal( "appdata", "yahoopictures/"+ contactId().lower().replace(QRegExp("[./~]"),"-")  +".png"  ) ;
+ 	setProperty( Kopete::Global::Properties::self()->photo(), QString::null );
+ 	setProperty( Kopete::Global::Properties::self()->photo() , newlocation );
+ 	emit displayPictureChanged();
+ }
+ 
++void YahooContact::inviteConference()
++{
++	m_account->prepareConference( m_userId );
++}
++
++void YahooContact::inviteWebcam()
++{
++	if ( !KStandardDirs::findExe("jasper") )
++	{
++		KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error, 
++			i18n("I cannot find the jasper image convert program.\njasper is required to render the yahoo webcam images."
++			"\nPlease see %1 for further information.").arg("http://wiki.kde.org/tiki-index.php?page=Kopete%20Webcam%20Support") );
++		return;
++	}
++	m_account->yahooSession()->sendWebcamInvite( m_userId );
++}
++
+ void YahooContact::receivedWebcamImage( const QPixmap& image )
+ {
++	if( !m_webcamDialog )
++		initWebcamViewer();
++	m_receivingWebcam = true;
+ 	emit signalReceivedWebcamImage( image );
+ }
+ 
+ void YahooContact::webcamClosed( int reason )
+ {
++	m_receivingWebcam = false;
+ 	emit signalWebcamClosed( reason );
+ }
+ 
+-void YahooContact::requestWebcam()
++void YahooContact::webcamPaused()
+ {
+-	if ( !KStandardDirs::findExe("jasper") )
+-	{
+-		KMessageBox::queuedMessageBox(
+-			Kopete::UI::Global::mainWidget(), KMessageBox::Error,
+-			i18n("Jasper image conversion program not found.\njasper is required to render the Yahoo webcam images.\nPlease go to %1").arg( "http://www.ece.uvic.ca/~mdadams/jasper/")
+-                );
+-		return;
+-	}
++	emit signalWebcamPaused();
++}
+ 
+-	// uncomment this when kdelibs supports jpc
+-	// KImageIO::registerFormats();
++void YahooContact::initWebcamViewer()
++{
++	//KImageIO::registerFormats();
+ 	
+-	delete m_webcamDialog;
+-	m_webcamDialog = NULL;
+ 	if ( !m_webcamDialog )
+ 	{
+-		m_webcamDialog = new YahooWebcamDialog( this, Kopete::UI::Global::mainWidget() );
+-		QObject::connect( m_webcamDialog, SIGNAL( closeClicked() ), this, SLOT( closeWebcamDialog() ) );
++		m_webcamDialog = new YahooWebcamDialog( userId(), Kopete::UI::Global::mainWidget() );
++// 		QObject::connect( m_webcamDialog, SIGNAL( closeClicked() ), this, SLOT( closeWebcamDialog() ) );
++	
++		QObject::connect( this, SIGNAL( signalWebcamClosed( int ) ),
++		                  m_webcamDialog, SLOT( webcamClosed( int ) ) );
++		
++		QObject::connect( this, SIGNAL( signalWebcamPaused() ),
++		                  m_webcamDialog, SLOT( webcamPaused() ) );
++		
++		QObject::connect( this, SIGNAL ( signalReceivedWebcamImage( const QPixmap& ) ),
++				m_webcamDialog, SLOT( newImage( const QPixmap& ) ) );
++		
++		QObject::connect( m_webcamDialog, SIGNAL ( closingWebcamDialog ( ) ),
++				this, SLOT ( closeWebcamDialog ( ) ) );
+ 	}
+-	
+-	QObject::connect( this, SIGNAL( signalWebcamClosed( int ) ),
+-	                  m_webcamDialog, SLOT( webcamClosed( int ) ) );
+-	
+-	QObject::connect( this, SIGNAL ( signalReceivedWebcamImage( const QPixmap& ) ),
+-	                  m_webcamDialog, SLOT( newImage( const QPixmap& ) ) );
++	m_webcamDialog->show();
++}
+ 
+-	QObject::connect( m_webcamDialog, SIGNAL ( closingWebcamDialog ( ) ),
+-	                  this, SLOT ( closeWebcamDialog ( ) ) );
++void YahooContact::requestWebcam()
++{
++	if ( !KStandardDirs::findExe("jasper") )
++	{
++		KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error, 
++			i18n("I cannot find the jasper image convert program.\njasper is required to render the yahoo webcam images."
++			"\nPlease see %1 for further information.").arg("http://wiki.kde.org/tiki-index.php?page=Kopete%20Webcam%20Support") );
++		return;
++	}
+ 	
++	if( !m_webcamDialog )
++		initWebcamViewer();
+ 	m_account->yahooSession()->requestWebcam( contactId() );
+ }
+ 
+@@ -532,25 +668,165 @@
+ 	QObject::disconnect( this, SIGNAL( signalWebcamClosed( int ) ),
+ 	                  m_webcamDialog, SLOT( webcamClosed( int ) ) );
+ 	
++	QObject::disconnect( this, SIGNAL( signalWebcamPaused() ),
++	                  m_webcamDialog, SLOT( webcamPaused( ) ) );
++	
+ 	QObject::disconnect( this, SIGNAL ( signalReceivedWebcamImage( const QPixmap& ) ),
+ 	                  m_webcamDialog, SLOT( newImage( const QPixmap& ) ) );
+ 	
+ 	QObject::disconnect( m_webcamDialog, SIGNAL ( closingWebcamDialog ( ) ),
+ 	                  this, SLOT ( closeWebcamDialog ( ) ) );
+-	
+-	m_account->yahooSession()->closeWebcam( contactId() );
+-	//m_webcamDialog->delayedDestruct();
++	if( m_receivingWebcam )
++		m_account->yahooSession()->closeWebcam( contactId() );
++	m_webcamDialog->delayedDestruct();
++	m_webcamDialog = 0L;
+ }
+ 
+ void YahooContact::deleteContact()
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
+-	//my ugliest hack yet. how many levels of indirection do I want? ;)
+-	if ( m_account->isConnected() )
+-		m_account->yahooSession()->removeBuddy(m_userId, m_groupName);
+-
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	if( !m_account->isOnServer( contactId() ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Contact does not exist on server-side. Not removing..." << endl;		
++	}
++	else
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Contact is getting remove from server side contactlist...." << endl;
++		// Delete from YAB first
++		if( !m_YABEntry )
++			readYABEntry();
++		if( m_YABEntry->YABId )
++			m_account->yahooSession()->deleteYABEntry( *m_YABEntry );
++		
++		// Now remove from the contactlist
++		m_account->yahooSession()->removeBuddy( contactId(), m_groupName );
++	}
+ 	Kopete::Contact::deleteContact();
+ }
++
++void YahooContact::writeYABEntry()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	// Personal
++	setProperty( YahooProtocol::protocol()->propfirstName, m_YABEntry->firstName );
++	setProperty( YahooProtocol::protocol()->propSecondName, m_YABEntry->secondName );
++	setProperty( YahooProtocol::protocol()->propLastName, m_YABEntry->lastName );
++	setProperty( YahooProtocol::protocol()->propNickName, m_YABEntry->nickName );
++	setProperty( YahooProtocol::protocol()->propTitle, m_YABEntry->title );
++	
++	// Primary Information	
++	setProperty( YahooProtocol::protocol()->propPhoneMobile, m_YABEntry->phoneMobile );
++	setProperty( YahooProtocol::protocol()->propEmail, m_YABEntry->email );
++	setProperty( YahooProtocol::protocol()->propYABId, m_YABEntry->YABId );
++	
++		// Additional Information
++	setProperty( YahooProtocol::protocol()->propPager, m_YABEntry->pager );
++	setProperty( YahooProtocol::protocol()->propFax, m_YABEntry->fax );
++	setProperty( YahooProtocol::protocol()->propAdditionalNumber, m_YABEntry->additionalNumber );
++	setProperty( YahooProtocol::protocol()->propAltEmail1, m_YABEntry->altEmail1 );
++	setProperty( YahooProtocol::protocol()->propAltEmail2, m_YABEntry->altEmail2 );
++	setProperty( YahooProtocol::protocol()->propImAIM, m_YABEntry->imAIM );
++	setProperty( YahooProtocol::protocol()->propImICQ, m_YABEntry->imICQ );
++	setProperty( YahooProtocol::protocol()->propImMSN, m_YABEntry->imMSN );
++	setProperty( YahooProtocol::protocol()->propImGoogleTalk, m_YABEntry->imGoogleTalk );
++	setProperty( YahooProtocol::protocol()->propImSkype, m_YABEntry->imSkype );
++	setProperty( YahooProtocol::protocol()->propImIRC, m_YABEntry->imIRC );
++	setProperty( YahooProtocol::protocol()->propImQQ, m_YABEntry->imQQ );
++	
++		// Private Information
++	setProperty( YahooProtocol::protocol()->propPrivateAddress, m_YABEntry->privateAdress );
++	setProperty( YahooProtocol::protocol()->propPrivateCity, m_YABEntry->privateCity );
++	setProperty( YahooProtocol::protocol()->propPrivateState, m_YABEntry->privateState );
++	setProperty( YahooProtocol::protocol()->propPrivateZIP, m_YABEntry->privateZIP );
++	setProperty( YahooProtocol::protocol()->propPrivateCountry, m_YABEntry->privateCountry );
++	setProperty( YahooProtocol::protocol()->propPrivatePhone, m_YABEntry->privatePhone );
++	setProperty( YahooProtocol::protocol()->propPrivateURL, m_YABEntry->privateURL );
++	
++		// Work Information
++	setProperty( YahooProtocol::protocol()->propCorporation, m_YABEntry->corporation );
++	setProperty( YahooProtocol::protocol()->propWorkAddress, m_YABEntry->workAdress );
++	setProperty( YahooProtocol::protocol()->propWorkCity, m_YABEntry->workCity );
++	setProperty( YahooProtocol::protocol()->propWorkState, m_YABEntry->workState );
++	setProperty( YahooProtocol::protocol()->propWorkZIP, m_YABEntry->workZIP );
++	setProperty( YahooProtocol::protocol()->propWorkCountry, m_YABEntry->workCountry );
++	setProperty( YahooProtocol::protocol()->propWorkPhone, m_YABEntry->workPhone );
++	setProperty( YahooProtocol::protocol()->propWorkURL, m_YABEntry->workURL );
++	
++		// Miscellanous
++	setProperty( YahooProtocol::protocol()->propBirthday, m_YABEntry->birthday.toString( Qt::ISODate ) );
++	setProperty( YahooProtocol::protocol()->propAnniversary, m_YABEntry->anniversary.toString( Qt::ISODate ) );
++	setProperty( YahooProtocol::protocol()->propNotes, m_YABEntry->notes );
++	setProperty( YahooProtocol::protocol()->propAdditional1, m_YABEntry->additional1 );
++	setProperty( YahooProtocol::protocol()->propAdditional2, m_YABEntry->additional2 );
++	setProperty( YahooProtocol::protocol()->propAdditional3, m_YABEntry->additional3 );
++	setProperty( YahooProtocol::protocol()->propAdditional4, m_YABEntry->additional4 );
++}
++
++void YahooContact::readYABEntry()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	if( m_YABEntry )
++		delete m_YABEntry;
++	
++	m_YABEntry = new YABEntry;
++	m_YABEntry->yahooId = userId();
++	// Personal
++	m_YABEntry->firstName = property( YahooProtocol::protocol()->propfirstName ).value().toString();
++	m_YABEntry->secondName = property( YahooProtocol::protocol()->propSecondName ).value().toString();
++	m_YABEntry->lastName = property( YahooProtocol::protocol()->propLastName ).value().toString();
++	m_YABEntry->nickName = property( YahooProtocol::protocol()->propNickName ).value().toString();
++	m_YABEntry->title = property( YahooProtocol::protocol()->propTitle ).value().toString();
++	
++	// Primary Information	
++	m_YABEntry->phoneMobile = property( YahooProtocol::protocol()->propPhoneMobile ).value().toString();
++	m_YABEntry->email = property( YahooProtocol::protocol()->propEmail ).value().toString();
++	m_YABEntry->YABId = property( YahooProtocol::protocol()->propYABId ).value().toInt();
++	
++	// Additional Information
++	m_YABEntry->pager = property( YahooProtocol::protocol()->propPager ).value().toString();
++	m_YABEntry->fax = property( YahooProtocol::protocol()->propFax ).value().toString();
++	m_YABEntry->additionalNumber = property( YahooProtocol::protocol()->propAdditionalNumber ).value().toString();
++	m_YABEntry->altEmail1 = property( YahooProtocol::protocol()->propAltEmail1 ).value().toString();
++	m_YABEntry->altEmail2 = property( YahooProtocol::protocol()->propAltEmail2 ).value().toString();
++	m_YABEntry->imAIM = property( YahooProtocol::protocol()->propImAIM ).value().toString();
++	m_YABEntry->imICQ = property( YahooProtocol::protocol()->propImICQ ).value().toString();
++	m_YABEntry->imMSN = property( YahooProtocol::protocol()->propImMSN ).value().toString();
++	m_YABEntry->imGoogleTalk = property( YahooProtocol::protocol()->propImGoogleTalk ).value().toString();
++	m_YABEntry->imSkype = property( YahooProtocol::protocol()->propImSkype ).value().toString();
++	m_YABEntry->imIRC = property( YahooProtocol::protocol()->propImIRC ).value().toString();
++	m_YABEntry->imQQ = property( YahooProtocol::protocol()->propImQQ ).value().toString();
++	
++	// Private Information
++	m_YABEntry->privateAdress = property( YahooProtocol::protocol()->propPrivateAddress ).value().toString();
++	m_YABEntry->privateCity = property( YahooProtocol::protocol()->propPrivateCity ).value().toString();
++	m_YABEntry->privateState = property( YahooProtocol::protocol()->propPrivateState ).value().toString();
++	m_YABEntry->privateZIP = property( YahooProtocol::protocol()->propPrivateZIP ).value().toString();
++	m_YABEntry->privateCountry = property( YahooProtocol::protocol()->propPrivateCountry ).value().toString();
++	m_YABEntry->privatePhone = property( YahooProtocol::protocol()->propPrivatePhone ).value().toString();
++	m_YABEntry->privateURL = property( YahooProtocol::protocol()->propPrivateURL ).value().toString();
++	
++	// Work Information 
++	m_YABEntry->corporation = property( YahooProtocol::protocol()->propCorporation ).value().toString();
++	m_YABEntry->workAdress = property( YahooProtocol::protocol()->propWorkAddress ).value().toString();
++	m_YABEntry->workCity = property( YahooProtocol::protocol()->propWorkCity ).value().toString();
++	m_YABEntry->workState = property( YahooProtocol::protocol()->propWorkState ).value().toString();
++	m_YABEntry->workZIP = property( YahooProtocol::protocol()->propWorkZIP ).value().toString();
++	m_YABEntry->workCountry = property( YahooProtocol::protocol()->propWorkCountry ).value().toString();
++	m_YABEntry->workPhone = property( YahooProtocol::protocol()->propWorkPhone ).value().toString();
++	m_YABEntry->workURL = property( YahooProtocol::protocol()->propWorkURL ).value().toString();
++
++	// Miscellanous
++	m_YABEntry->birthday = QDate::fromString( property( YahooProtocol::protocol()->propBirthday ).value().toString(), Qt::ISODate );
++	m_YABEntry->anniversary = QDate::fromString( property( YahooProtocol::protocol()->propAnniversary ).value().toString(), Qt::ISODate );
++	m_YABEntry->notes = property( YahooProtocol::protocol()->propNotes ).value().toString();
++	m_YABEntry->additional1 = property( YahooProtocol::protocol()->propAdditional1 ).value().toString();
++	m_YABEntry->additional2 = property( YahooProtocol::protocol()->propAdditional2 ).value().toString();
++	m_YABEntry->additional3 = property( YahooProtocol::protocol()->propAdditional3 ).value().toString();
++	m_YABEntry->additional4 = property( YahooProtocol::protocol()->propAdditional4 ).value().toString();
++}
++
+ #include "yahoocontact.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/yahoo/yahooaccount.cpp	(revision 568672)
++++ kopete/protocols/yahoo/yahooaccount.cpp	(revision 586398)
+@@ -17,6 +17,7 @@
+ */
+ //Standard Header
+ #include <ctime>
++#include <stdlib.h>
+ 
+ //QT
+ #include <qfont.h>
+@@ -24,7 +25,9 @@
+ #include <qcolor.h>
+ #include <qregexp.h>
+ #include <qimage.h>
+-#include <qtimer.h>
++#include <qfile.h>
++#include <qdir.h>
++#include <qfileinfo.h>
+ 
+ // KDE
+ #include <klocale.h>
+@@ -48,10 +51,21 @@
+ #include <kopetemetacontact.h>
+ #include <kopetecontactlist.h>
+ #include <kopetetransfermanager.h>
++#include <kopeteview.h>
++#include <contactaddednotifydialog.h>
+ 
+ // Yahoo
+ #include "yahooaccount.h"
+ #include "yahoocontact.h"
++#include "yahooconnector.h"
++#include "yahooclientstream.h"
++#include "client.h"
++#include "yahooverifyaccount.h"
++#include "yahoowebcam.h"
++#include "yahooconferencemessagemanager.h"
++#include "yahooinvitelistimpl.h"
++#include "yabentry.h"
++#include "yahoouserinfodialog.h"
+ 
+ YahooAwayDialog::YahooAwayDialog(YahooAccount* account, QWidget *parent, const char *name) :
+ 	KopeteAwayDialog(parent, name)
+@@ -71,19 +85,20 @@
+ {
+ 
+ 	// first things first - initialise internals
+-	theHaveContactList = false;
+ 	stateOnConnection = 0;
+ 	theAwayDialog = new YahooAwayDialog( this );
+ 	m_protocol = parent;
+-	m_session = 0;
++	m_session = new Client( this );
+ 	m_lastDisconnectCode = 0;
+ 	m_currentMailCount = 0;
+ 	m_pictureFlag = 0;
+-	m_waitingForResponse = false;
+-	m_keepaliveTimer = new QTimer( this, "keepaliveTimer" );
++	m_webcam = 0L;
+ 	
++	m_session->setUserId( accountId.lower() );
++	
+ 	m_openInboxAction = new KAction( i18n( "Open Inbo&x..." ), "mail_generic", 0, this, SLOT( slotOpenInbox() ), this, "m_openInboxAction" );
+ 	m_openYABAction = new KAction( i18n( "Open &Addressbook..." ), "contents", 0, this, SLOT( slotOpenYAB() ), this, "m_openYABAction" );
++	m_editOwnYABEntry = new KAction( i18n( "&Edit my contact details..."), "contents", 0, this, SLOT( slotEditOwnYABEntry() ), this, "m_editOwnYABEntry" );
+ 
+ 	YahooContact* _myself=new YahooContact( this, accountId.lower(), accountId, Kopete::ContactList::self()->myself() );
+ 	setMyself( _myself );
+@@ -94,11 +109,14 @@
+ 	myself()->setProperty( YahooProtocol::protocol()->iconExpire, configGroup()->readNumEntry( "iconExpire", 0 ) );
+ 	
+ 	QObject::connect( Kopete::ContactList::self(), SIGNAL( globalIdentityChanged(const QString&, const QVariant& ) ), SLOT( slotGlobalIdentityChanged(const QString&, const QVariant& ) ));
+-	QObject::connect( m_keepaliveTimer, SIGNAL( timeout() ), this, SLOT( slotKeepalive() ) );
+-
++// 	initConnectionSignals( MakeConnections );
++	
+ 	QString displayName = configGroup()->readEntry(QString::fromLatin1("displayName"));
+ 	if(!displayName.isEmpty())
+ 		_myself->setNickName(displayName);
++	
++	m_YABLastMerge = configGroup()->readNumEntry( "YABLastMerge", 0 );
++	m_YABLastRemoteRevision = configGroup()->readNumEntry( "YABLastRemoteRevision", 0 );
+ }
+ 
+ YahooAccount::~YahooAccount()
+@@ -118,6 +136,7 @@
+ 
+ void YahooAccount::slotGoStatus( int status, const QString &awayMessage)
+ {
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "GoStatus: " << status << " msg: " << awayMessage <<endl;
+ 	if( !isConnected() )
+ 	{
+ 		connect( m_protocol->statusFromYahoo( status ) );
+@@ -125,7 +144,8 @@
+ 	}
+ 	else
+ 	{
+-		m_session->setAway( yahoo_status( status ), awayMessage, status? 1 : 0 );
++		m_session->changeStatus( Yahoo::Status( status ), awayMessage, 
++			(status == Yahoo::StatusAvailable)? Yahoo::StatusTypeAvailable : Yahoo::StatusTypeAway );
+ 		
+ 		//sets the awayMessage property for the owner of the account. shows up in the statusbar icon's tooltip. the property is unset when awayMessage is null
+ 		myself()->setProperty( m_protocol->awayMessage, awayMessage );
+@@ -134,7 +154,7 @@
+ 	}
+ }
+ 
+-YahooSession *YahooAccount::yahooSession()
++Client *YahooAccount::yahooSession()
+ {
+ 	return m_session ? m_session : 0L;
+ }
+@@ -170,7 +190,7 @@
+ 	/* Yahoo sends a message either with color or without color
+ 	 * so we have to use this really hacky method to get colors
+ 	 */
+-	//kdDebug(14180) << k_funcinfo << "msg is " << msg << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "msg is " << msg << endl;
+ 	//Please note that some of the colors are hard-coded to
+ 	//match the yahoo colors
+ 	if ( msg.find("\033[38m") != -1 )
+@@ -191,7 +211,7 @@
+ 		return QColor("#FFD8D8");
+ 	if ( msg.find("\033[#") != -1 )
+ 	{
+-		kdDebug(14180) << "Custom color is " << msg.mid(msg.find("\033[#")+2,7) << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << "Custom color is " << msg.mid(msg.find("\033[#")+2,7) << endl;
+ 		return QColor(msg.mid(msg.find("\033[#")+2,7));
+ 	}
+ 
+@@ -206,59 +226,80 @@
+ 
+ 	if ( sct == MakeConnections )
+ 	{
+-		QObject::connect(m_session, SIGNAL(loginResponse(int, const QString &)),
++		QObject::connect(m_session, SIGNAL(loggedIn( int, const QString &)),
+ 		                 this, SLOT(slotLoginResponse(int, const QString &)) );
+ 		
++		QObject::connect(m_session, SIGNAL(disconnected()),
++		                 this, SLOT(slotDisconnected()) );
++		
++		QObject::connect(m_session, SIGNAL(loginFailed()),
++		                 this, SLOT(slotLoginFailed()) );
++		
++		QObject::connect(m_session, SIGNAL(error(int)),
++		                 this, SLOT(slotError(int)));
++		
+ 		QObject::connect(m_session, SIGNAL(gotBuddy(const QString &, const QString &, const QString &)),
+ 		                 this, SLOT(slotGotBuddy(const QString &, const QString &, const QString &)));
+ 		
+-		QObject::connect(m_session, SIGNAL( buddyListFetched( int ) ),
+-		                 this, SLOT(slotBuddyListFetched( int ) ) );
++		QObject::connect(m_session, SIGNAL(authorizationAccepted( const QString & )),
++		                 this, SLOT(slotAuthorizationAccepted( const QString & )) );
+ 		
+-		QObject::connect(m_session, SIGNAL(statusChanged(const QString&, int, const QString&, int)),
+-		                 this, SLOT(slotStatusChanged(const QString&, int, const QString&, int)));
++		QObject::connect(m_session, SIGNAL(authorizationRejected( const QString &, const QString & )),
++		                 this, SLOT(slotAuthorizationRejected( const QString &, const QString & )) );
+ 		
++		QObject::connect(m_session, SIGNAL(gotAuthorizationRequest( const QString &, const QString &, const QString & )),
++		                 this, SLOT(slotgotAuthorizationRequest( const QString &, const QString &, const QString & )) );
++		
++		QObject::connect(m_session, SIGNAL(statusChanged(const QString&, int, const QString&, int, int)),
++		                 this, SLOT(slotStatusChanged(const QString&, int, const QString&, int, int)));
++		
++		QObject::connect(m_session, SIGNAL(stealthStatusChanged(const QString &, Yahoo::StealthStatus)), 
++		                 this, SLOT(slotStealthStatusChanged( const QString &, Yahoo::StealthStatus)) );
++		
+ 		QObject::connect(m_session, SIGNAL(gotIm(const QString&, const QString&, long, int)),
+ 		                 this, SLOT(slotGotIm(const QString &, const QString&, long, int)));
+ 		
+ 		QObject::connect(m_session, SIGNAL(gotBuzz(const QString&, long)),
+ 		                 this, SLOT(slotGotBuzz(const QString &, long)));
+ 
+-		QObject::connect(m_session, SIGNAL( gotConfInvite( const QString&, const QString&,
++		QObject::connect(m_session, SIGNAL( gotConferenceInvite( const QString&, const QString&,
+ 		                                                   const QString&, const QStringList&) ),
+ 		                 this,
+ 		                 SLOT( slotGotConfInvite( const QString&, const QString&,
+ 		                                          const QString&, const QStringList& ) ) );
+ 		
+-		QObject::connect(m_session, SIGNAL(confUserDecline(const QString&, const QString &, const QString &)),
++		QObject::connect(m_session, SIGNAL(confUserDeclined(const QString&, const QString &, const QString &)),
+ 		                 this,
+ 		                 SLOT(slotConfUserDecline( const QString &, const QString &, const QString &)) );
+ 		
+-		QObject::connect(m_session , SIGNAL(confUserJoin( const QString &, const QString &)), this,
++		QObject::connect(m_session , SIGNAL(confUserJoined( const QString &, const QString &)), this,
+ 		                 SLOT(slotConfUserJoin( const QString &, const QString &)) );
+ 		
+-		QObject::connect(m_session , SIGNAL(confUserLeave( const QString &, const QString &)), this,
++		QObject::connect(m_session , SIGNAL(confUserLeft( const QString &, const QString &)), this,
+ 		                 SLOT(slotConfUserLeave( const QString &, const QString &)) );
+ 		
+-		QObject::connect(m_session , SIGNAL(confMessage( const QString &, const QString &, const QString &)), this,
++		QObject::connect(m_session , SIGNAL(gotConferenceMessage( const QString &, const QString &, const QString &)), this,
+ 		                 SLOT(slotConfMessage( const QString &, const QString &, const QString &)) );
+ 		
+ 		QObject::connect(m_session,
+-		                 SIGNAL(gotFile(const QString &, const QString &, long, const QString &, const QString &, unsigned long)),
++		                 SIGNAL(incomingFileTransfer(const QString &, const QString &, long, const QString &, const QString &, unsigned long)),
+ 		                 this,
+ 		                 SLOT(slotGotFile(const QString&, const QString&, long, const QString&, const QString&, unsigned long)));
+ 		
+-		QObject::connect(m_session , SIGNAL(contactAdded(const QString &, const QString &, const QString &)), this,
+-		                 SLOT(slotContactAdded(const QString &, const QString &, const QString &)));
++		QObject::connect(m_session, SIGNAL(fileTransferComplete(unsigned int)), this,
++		                 SLOT(slotFileTransferComplete(unsigned int)) );
+ 		
+-		QObject::connect(m_session , SIGNAL(rejected(const QString &, const QString &)), this,
+-		                 SLOT(slotRejected(const QString&, const QString&)));
++		QObject::connect(m_session, SIGNAL(fileTransferBytesProcessed(unsigned int,unsigned int)), this,
++		                 SLOT(slotFileTransferBytesProcessed(unsigned int,unsigned int)) );
+ 		
++		QObject::connect(m_session, SIGNAL(fileTransferError(unsigned int,int,const QString &)), this,
++		                 SLOT(slotFileTransferError(unsigned int,int,const QString &)) );
++		
+ 		QObject::connect(m_session, SIGNAL(typingNotify(const QString &, int)), this ,
+ 		                 SLOT(slotTypingNotify(const QString &, int)));
+ 		
+-		QObject::connect(m_session, SIGNAL(gameNotify(const QString &, int)), this,
+-		                 SLOT(slotGameNotify( const QString &, int)));
++// 		QObject::connect(m_session, SIGNAL(gameNotify(const QString &, int)), this,
++// 		                 SLOT(slotGameNotify( const QString &, int)));
+ 		
+ 		QObject::connect(m_session, SIGNAL(mailNotify(const QString&, const QString&, int)), this,
+ 		                 SLOT(slotMailNotify(const QString &, const QString&, int)));
+@@ -266,43 +307,80 @@
+ 		QObject::connect(m_session, SIGNAL(systemMessage(const QString&)), this,
+ 		                 SLOT(slotSystemMessage(const QString &)));
+ 		
+-		QObject::connect(m_session, SIGNAL(error(const QString&, int)), this,
+-		                 SLOT(slotError(const QString &, int )));
++// 		QObject::connect(m_session, SIGNAL(gotIdentities(const QStringList &)), this,
++// 		                 SLOT(slotGotIdentities( const QStringList&)));
+ 		
+-		QObject::connect(m_session, SIGNAL(gotIdentities(const QStringList &)), this,
+-		                 SLOT(slotGotIdentities( const QStringList&)));
++		QObject::connect(m_session, SIGNAL(gotWebcamInvite(const QString&)), this, SLOT(slotGotWebcamInvite(const QString&)));
+ 		
+-		QObject::connect(m_session, SIGNAL(gotWebcamInvite(const QString&)), this, SLOT(slotGotWebcamInvite(const QString&)));
+-				
++		QObject::connect(m_session, SIGNAL(webcamNotAvailable(const QString&)), this, SLOT(slotWebcamNotAvailable(const QString&)));
++		
+ 		QObject::connect(m_session, SIGNAL(webcamImageReceived(const QString&, const QPixmap& )), this, SLOT(slotGotWebcamImage(const QString&, const QPixmap& )));
+ 		
+-		QObject::connect(m_session, SIGNAL(remoteWebcamClosed(const QString&, int )), this, SLOT(slotWebcamClosed(const QString&, int )));
++		QObject::connect(m_session, SIGNAL(webcamClosed(const QString&, int )), this, SLOT(slotWebcamClosed(const QString&, int )));
++		
++		QObject::connect(m_session, SIGNAL(webcamPaused(const QString&)), this, SLOT(slotWebcamPaused(const QString&)));
++		
++		QObject::connect(m_session, SIGNAL(webcamReadyForTransmission()), this, SLOT(slotWebcamReadyForTransmission()));
++		
++		QObject::connect(m_session, SIGNAL(webcamStopTransmission()), this, SLOT(slotWebcamStopTransmission()));
++		
++		QObject::connect(m_session, SIGNAL(webcamViewerJoined(const QString&)), this, SLOT(slotWebcamViewerJoined(const QString&)));
++		
++		QObject::connect(m_session, SIGNAL(webcamViewerLeft(const QString&)), this, SLOT(slotWebcamViewerLeft(const QString&)));
++		
++		QObject::connect(m_session, SIGNAL(webcamViewerRequest(const QString&)), this, SLOT(slotWebcamViewerRequest( const QString&)));
++		
++		QObject::connect(m_session, SIGNAL(pictureStatusNotify( const QString&, int )), SLOT(slotPictureStatusNotiy( const QString&, int)));
++		
++		QObject::connect(m_session, SIGNAL(pictureDownloaded(const QString&, KTempFile*, int)), this, SLOT(slotGotBuddyIcon(const QString&, KTempFile*, int)) );
+ 
+-		QObject::connect(m_session, SIGNAL(gotBuddyIcon(const QString&, KTempFile*, int)), this, SLOT(slotGotBuddyIcon(const QString&, KTempFile*, int)) );
++		QObject::connect(m_session, SIGNAL(pictureInfoNotify(const QString&, KURL, int)), this, SLOT(slotGotBuddyIconInfo(const QString&, KURL, int )));
+ 
+-		QObject::connect(m_session, SIGNAL(gotBuddyIconInfo(const QString&, KURL, int)), this, SLOT(slotGotBuddyIconInfo(const QString&, KURL, int )));
++		QObject::connect(m_session, SIGNAL(pictureChecksumNotify(const QString&, int)), this, SLOT(slotGotBuddyIconChecksum(const QString&, int )));
++		
++		QObject::connect(m_session, SIGNAL(pictureRequest(const QString&)), this, SLOT(slotGotBuddyIconRequest(const QString&)) );
+ 
+-		QObject::connect(m_session, SIGNAL(gotBuddyIconChecksum(const QString&, int)), this, SLOT(slotGotBuddyIconChecksum(const QString&, int )));
+-		QObject::connect(m_session, SIGNAL(gotBuddyIconRequest(const QString&)), this, SLOT(slotGotBuddyIconRequest(const QString&)) );
+-
+-		QObject::connect(m_session, SIGNAL(buddyIconUploaded( const QString &)), this, SLOT(slotBuddyIconChanged(const QString&)));
++		QObject::connect(m_session, SIGNAL(pictureUploaded( const QString &)), this, SLOT(slotBuddyIconChanged(const QString&)));
+ 		
++		QObject::connect(m_session, SIGNAL(gotYABEntry( YABEntry * )), this, SLOT(slotGotYABEntry( YABEntry * )));
++		
++		QObject::connect(m_session, SIGNAL(modifyYABEntryError( YABEntry *, const QString & )), this, SLOT(slotModifyYABEntryError( YABEntry *, const QString & )));
++		
++		QObject::connect(m_session, SIGNAL(gotYABRevision( long, bool )), this, SLOT(slotGotYABRevision( long , bool )) );
+ 	}
+ 
+ 	if ( sct == DeleteConnections )
+ 	{
+-		QObject::disconnect(m_session, SIGNAL(loginResponse(int, const QString &)),
++		QObject::disconnect(m_session, SIGNAL(loggedIn(int, const QString &)),
+ 		                    this, SLOT(slotLoginResponse(int, const QString &)) );
+ 		
++		QObject::disconnect(m_session, SIGNAL(disconnected()),
++		                    this, SLOT(slotDisconnected()) );
++		
++		QObject::disconnect(m_session, SIGNAL(loginFailed()),
++		                    this, SLOT(slotLoginFailed()) );
++		
++		QObject::disconnect(m_session, SIGNAL(error(int)),
++		                 this, SLOT(slotError(int)));
++		
+ 		QObject::disconnect(m_session, SIGNAL(gotBuddy(const QString &, const QString &, const QString &)),
+ 		                    this, SLOT(slotGotBuddy(const QString &, const QString &, const QString &)));
+ 		
+-		QObject::disconnect(m_session, SIGNAL( buddyListFetched( int ) ),
+-		                    this, SLOT(slotBuddyListFetched( int ) ) );
++		QObject::disconnect(m_session, SIGNAL(authorizationAccepted( const QString &)),
++		                 this, SLOT(slotAuthorizationAccepted( const QString &)) );
+ 		
+-		QObject::disconnect(m_session, SIGNAL(statusChanged(const QString&, int, const QString&, int)),
+-		                    this, SLOT(slotStatusChanged(const QString&, int, const QString&, int)));
++		QObject::disconnect(m_session, SIGNAL(authorizationRejected( const QString &, const QString &)),
++		                    this, SLOT(slotAuthorizationRejected( const QString &, const QString & )) );
+ 		
++		QObject::disconnect(m_session, SIGNAL(gotAuthorizationRequest( const QString &, const QString &, const QString & )),
++		                 this, SLOT(slotgotAuthorizationRequest( const QString &, const QString &, const QString & )) );
++		
++		QObject::disconnect(m_session, SIGNAL(statusChanged(const QString&, int, const QString&, int, int)),
++		                    this, SLOT(slotStatusChanged(const QString&, int, const QString&, int, int)));
++		
++		QObject::disconnect(m_session, SIGNAL(stealthStatusChanged(const QString &, Yahoo::StealthStatus)), 
++		                 this, SLOT(slotStealthStatusChanged( const QString &, Yahoo::StealthStatus)) );
++		
+ 		QObject::disconnect(m_session, SIGNAL(gotIm(const QString&, const QString&, long, int)),
+ 		                    this, SLOT(slotGotIm(const QString &, const QString&, long, int)));
+ 
+@@ -310,44 +388,47 @@
+ 		                    this, SLOT(slotGotBuzz(const QString &, long)));
+ 		
+ 		QObject::disconnect(m_session,
+-		                    SIGNAL( gotConfInvite( const QString&, const QString&,
++		                    SIGNAL( gotConferenceInvite( const QString&, const QString&,
+ 		                                           const QString&, const QStringList&) ),
+ 		                    this, 
+ 		                    SLOT( slotGotConfInvite( const QString&, const QString&,
+ 		                                             const QString&, const QStringList&) ) );
+ 		
+ 		QObject::disconnect(m_session,
+-		                    SIGNAL(confUserDecline(const QString&, const QString &, const QString &)),
++		                    SIGNAL(confUserDeclined(const QString&, const QString &, const QString &)),
+ 		                    this,
+ 		                    SLOT(slotConfUserDecline( const QString &, const QString &, const QString& ) ) );
+ 		
+-		QObject::disconnect(m_session , SIGNAL(confUserJoin( const QString &, const QString &)),
++		QObject::disconnect(m_session , SIGNAL(confUserJoined( const QString &, const QString &)),
+ 		                    this, SLOT(slotConfUserJoin( const QString &, const QString &)) );
+ 		
+-		QObject::disconnect(m_session , SIGNAL(confUserLeave( const QString &, const QString &)),
++		QObject::disconnect(m_session , SIGNAL(confUserLeft( const QString &, const QString &)),
+ 		                    this, SLOT(slotConfUserLeave( const QString &, const QString &)) );
+ 		
+-		QObject::disconnect(m_session , SIGNAL(confMessage( const QString &, const QString &, const QString &)), this,
++		QObject::disconnect(m_session , SIGNAL(gotConferenceMessage( const QString &, const QString &, const QString &)), this,
+ 		                    SLOT(slotConfMessage( const QString &, const QString &, const QString &)) );
+ 		
+ 		QObject::disconnect(m_session,
+-		                    SIGNAL(gotFile(const QString &, const QString &,
++		                    SIGNAL(incomingFileTransfer(const QString &, const QString &,
+ 		                                   long, const QString &, const QString &, unsigned long)),
+ 		                    this,
+ 		                    SLOT(slotGotFile(const QString&, const QString&,
+ 		                                     long, const QString&, const QString&, unsigned long)));
+ 		
+-		QObject::disconnect(m_session , SIGNAL(contactAdded(const QString &, const QString &, const QString &)), this,
+-		                    SLOT(slotContactAdded(const QString &, const QString &, const QString &)));
++		QObject::disconnect(m_session, SIGNAL(fileTransferComplete(unsigned int)), this,
++		                 SLOT(slotFileTransferComplete(unsigned int)) );
+ 		
+-		QObject::disconnect(m_session , SIGNAL(rejected(const QString &, const QString &)), this,
+-		                    SLOT(slotRejected(const QString&, const QString&)));
++		QObject::disconnect(m_session, SIGNAL(fileTransferBytesProcessed(unsigned int,unsigned int)), this,
++		                 SLOT(slotFileTransferBytesProcessed(unsigned int,unsigned int)) );
+ 		
++		QObject::disconnect(m_session, SIGNAL(fileTransferError(unsigned int,int,const QString &)), this,
++		                 SLOT(slotFileTransferError(unsigned int,int,const QString &)) );
++		
+ 		QObject::disconnect(m_session, SIGNAL(typingNotify(const QString &, int)), this ,
+ 		                    SLOT(slotTypingNotify(const QString &, int)));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(gameNotify(const QString &, int)), this,
+-		                    SLOT(slotGameNotify( const QString &, int)));
++// 		QObject::disconnect(m_session, SIGNAL(gameNotify(const QString &, int)), this,
++// 		                    SLOT(slotGameNotify( const QString &, int)));
+ 		
+ 		QObject::disconnect(m_session, SIGNAL(mailNotify(const QString&, const QString&, int)), this,
+ 		                    SLOT(slotMailNotify(const QString &, const QString&, int)));
+@@ -355,34 +436,52 @@
+ 		QObject::disconnect(m_session, SIGNAL(systemMessage(const QString&)), this,
+ 		                    SLOT(slotSystemMessage(const QString &)));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(error(const QString&, int)), this,
+-		                    SLOT(slotError(const QString &, int )));
++// 		QObject::disconnect(m_session, SIGNAL(gotIdentities(const QStringList &)), this,
++// 		                    SLOT(slotGotIdentities( const QStringList&)));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(gotIdentities(const QStringList &)), this,
+-		                    SLOT(slotGotIdentities( const QStringList&)));
+-		
+ 		QObject::disconnect(m_session, SIGNAL(gotWebcamInvite(const QString&)), this, SLOT(slotGotWebcamInvite(const QString&)));
+ 		
++		QObject::disconnect(m_session, SIGNAL(webcamNotAvailable(const QString&)), this, SLOT(slotWebcamNotAvailable(const QString&)));
++		
+ 		QObject::disconnect(m_session, SIGNAL(webcamImageReceived(const QString&, const QPixmap& )), this, SLOT(slotGotWebcamImage(const QString&, const QPixmap& )));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(remoteWebcamClosed(const QString&, int )), this, SLOT(slotWebcamClosed(const QString&, int )));
++		QObject::disconnect(m_session, SIGNAL(webcamClosed(const QString&, int )), this, SLOT(slotWebcamClosed(const QString&, int )));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(gotBuddyIcon(const QString&, KTempFile*, int )), this, SLOT(slotGotBuddyIcon(const QString&, KTempFile*,int )));
+-
+-		QObject::disconnect(m_session, SIGNAL(gotBuddyIconInfo(const QString&, KURL, int)), this, SLOT(slotGotBuddyIconInfo(const QString&, KURL, int )));
++		QObject::disconnect(m_session, SIGNAL(webcamPaused(const QString&)), this, SLOT(slotWebcamPaused(const QString&)));
+ 		
++		QObject::disconnect(m_session, SIGNAL(webcamReadyForTransmission()), this, SLOT(slotWebcamReadyForTransmission()));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(gotBuddyIconRequest(const QString&)), this, SLOT(slotGotBuddyIconRequest(const QString&)) );
++		QObject::disconnect(m_session, SIGNAL(webcamStopTransmission()), this, SLOT(slotWebcamStopTransmission()));
+ 		
+-		QObject::disconnect(m_session, SIGNAL(buddyIconUploaded( const QString & )), this, SLOT(slotBuddyIconChanged(const QString&)));
++		QObject::disconnect(m_session, SIGNAL(webcamViewerJoined(const QString&)), this, SLOT(slotWebcamViewerJoined(const QString&)));
++		
++		QObject::disconnect(m_session, SIGNAL(webcamViewerLeft(const QString&)), this, SLOT(slotWebcamViewerLeft(const QString&)));
++		
++		QObject::disconnect(m_session, SIGNAL(webcamViewerRequest(const QString&)), this, SLOT(slotWebcamViewerRequest( const QString&)));
++		
++		QObject::disconnect(m_session, SIGNAL(pictureDownloaded(const QString&, KTempFile*, int )), this, SLOT(slotGotBuddyIcon(const QString&, KTempFile*,int )));
+ 
++		QObject::disconnect(m_session, SIGNAL(pictureInfoNotify(const QString&, KURL, int)), this, SLOT(slotGotBuddyIconInfo(const QString&, KURL, int )));
++	
++		QObject::disconnect(m_session, SIGNAL(gotBuddyIconRequest(const QString&)), this, SLOT(slotGotBuddyIconRequest(const QString&)) );
+ 		
+-		QObject::disconnect(m_session, SIGNAL(gotBuddyIconChecksum(const QString&, int)), this, SLOT(slotGotBuddyIconChecksum(const QString&, int )));
++		QObject::disconnect(m_session, SIGNAL(pictureUploaded( const QString & )), this, SLOT(slotBuddyIconChanged(const QString&)));
++	
++		QObject::disconnect(m_session, SIGNAL(pictureStatusNotify( const QString&, int )), this, SLOT(slotPictureStatusNotiy( const QString&, int)));
++		
++		QObject::disconnect(m_session, SIGNAL(pictureChecksumNotify(const QString&, int)), this, SLOT(slotGotBuddyIconChecksum(const QString&, int )));
++		
++		QObject::disconnect(m_session, SIGNAL(gotYABEntry( YABEntry * )), this, SLOT(slotGotYABEntry( YABEntry * )));
++		
++		QObject::disconnect(m_session, SIGNAL(modifyYABEntryError( YABEntry *, const QString & )), this, SLOT(slotModifyYABEntryError( YABEntry *, const QString & )));
++		
++		QObject::disconnect(m_session, SIGNAL(gotYABRevision( long, bool )), this, SLOT(slotGotYABRevision( long , bool )) );
+ 	}
+ }
+ 
+ void YahooAccount::connectWithPassword( const QString &passwd )
+ {
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	if ( isAway() )
+ 	{
+ 		slotGoOnline();
+@@ -392,7 +491,7 @@
+ 	if ( isConnected() || 
+ 	     myself()->onlineStatus() == m_protocol->Connecting )
+ 	{
+-		kdDebug(14180) << "Yahoo plugin: Ignoring connect request (already connected)." <<endl;
++		kdDebug(YAHOO_GEN_DEBUG) << "Yahoo plugin: Ignoring connect request (already connected)." <<endl;
+ 		return;
+ 	
+ 	}
+@@ -405,38 +504,28 @@
+ 	
+ 	QString server = configGroup()->readEntry( "Server", "scs.msg.yahoo.com" );
+ 	int port = configGroup()->readNumEntry( "Port", 5050 );
++	
++	initConnectionSignals( MakeConnections );
+ 
+-	YahooSessionManager::manager()->setPager( server, port );
+-	m_session = YahooSessionManager::manager()->createSession( accountId(), passwd );
+-	kdDebug(14180) << "Attempting to connect to Yahoo on <" << server << ":" 
+-		<< port << ">. user <" << accountId() << ">" << endl;
+-	
+-	static_cast<YahooContact*>( myself() )->setOnlineStatus( m_protocol->Connecting );
+-	if ( m_session && m_session->sessionId() > 0 )
+-	{
+-		initConnectionSignals( MakeConnections );
+-		kdDebug(14180) << "Starting the login connection" << endl;
+-		m_session->login( initialStatus().internalStatus() );
+-	}
+-	else
+-	{
+-		kdDebug(14180) << "Couldn't connect!" << endl;
+-			// TODO: message box saying can't connect?
+-	}
+-	
++	//YahooSessionManager::manager()->setPager( server, port );
++	//m_session = YahooSessionManager::manager()->createSession( accountId(), passwd );
++	kdDebug(YAHOO_GEN_DEBUG) << "Attempting to connect to Yahoo on <" << server << ":" 
++		<< port << ">. user <" << accountId() << ">"  << endl;
++	static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Connecting );	
++	m_session->setStatusOnConnect( Yahoo::Status( initialStatus().internalStatus() ) );
++	m_session->connect( server, port, accountId().lower(), passwd );
+ }
+ 
+ void YahooAccount::disconnect()
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	m_currentMailCount = 0;
+ 	if ( isConnected() )
+ 	{
+-		kdDebug(14180) <<  "Attempting to disconnect from Yahoo server " << endl;
++		kdDebug(YAHOO_GEN_DEBUG) <<  "Attempting to disconnect from Yahoo server " << endl;
+ 
+-		m_keepaliveTimer->stop();
+-		m_session->logOff();
++		m_session->close();
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 
+ 		for ( QDictIterator<Kopete::Contact> i( contacts() ); i.current(); ++i )
+@@ -446,7 +535,8 @@
+ 	}
+ 	else
+ 	{       //make sure we set everybody else offline explicitly, just for cleanup
+-		kdDebug(14180) << "Ignoring disconnect request (not fully connected)." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << "Cancelling active login attempts (not fully connected)." << endl;
++		m_session->cancelConnect();
+ 
+ 		for ( QDictIterator<Kopete::Contact> i(contacts()); i.current(); ++i )
+ 			static_cast<YahooContact*>( i.current() )->setOnlineStatus( m_protocol->Offline );
+@@ -456,26 +546,16 @@
+ 	theHaveContactList = false;
+ }
+ 
+-void YahooAccount::slotKeepalive()
++void YahooAccount::verifyAccount( const QString &word )
+ {
+-	if( m_waitingForResponse )
+-	{
+-		m_waitingForResponse = false;
+-		slotError( QString::null, 1 );
+-		return;
+-	}
+-	if( isConnected() && m_session )
+-	{	
+-		m_session->keepalive();
+-		m_session->sendIm( accountId(), accountId(), QString("<ping>"), pictureFlag() );
+-		kdDebug(14180) << "Ping packet sent." << endl;
+-	}
+-	m_waitingForResponse = true;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Word: s" << word << endl;
++	m_session->setVerificationWord( word );
++	disconnected( BadPassword );
+ }
+ 
+ void YahooAccount::setAway(bool status, const QString &awayMessage)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 
+ 	if( awayMessage.isEmpty() )
+ 		slotGoStatus( status ? 2 : 0 );
+@@ -485,11 +565,12 @@
+ 
+ void YahooAccount::slotConnected()
+ {
+-	kdDebug(14180) << k_funcinfo << "Moved to slotLoginResponse for the moment" << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Moved to slotLoginResponse for the moment" << endl;
+ }
+ 
+ void YahooAccount::slotGoOnline()
+ {
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	if( !isConnected() )
+ 		connect( m_protocol->Online );
+ 	else
+@@ -504,30 +585,20 @@
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ }
+ 
+-void YahooAccount::slotBuddyListFetched( int numBuddies )
+-{
+-	kdDebug(14180) << "Number of buddies: " << numBuddies << endl;
+-	theHaveContactList = true;
+-}
+-
+ KActionMenu *YahooAccount::actionMenu()
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	
+ 	KActionMenu *theActionMenu = Kopete::Account::actionMenu();
+ 	
+ 	theActionMenu->popupMenu()->insertSeparator();
++	theActionMenu->insert( m_editOwnYABEntry );
+ 	theActionMenu->insert( m_openInboxAction );
+ 	theActionMenu->insert( m_openYABAction );
+ 	
+ 	return theActionMenu;
+ }
+ 
+-void YahooAccount::slotGotBuddies( const YList */*theList*/ )
+-{
+-	kdDebug(14180) << k_funcinfo << endl;
+-}
+-
+ YahooContact *YahooAccount::contact( const QString &id )
+ {
+ 	return static_cast<YahooContact *>(contacts()[id]);
+@@ -535,7 +606,7 @@
+ 
+ bool YahooAccount::createContact(const QString &contactId, Kopete::MetaContact *parentContact )
+ {
+-//	kdDebug(14180) << k_funcinfo << " contactId: " << contactId << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << " contactId: " << contactId << endl;
+ 
+ 	if(!contact(contactId))
+ 	{
+@@ -548,22 +619,25 @@
+ 		return newContact != 0;
+ 	}
+ 	else
+-		kdDebug(14180) << k_funcinfo << "Contact already exists" << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Contact already exists" << endl;
+ 
+ 	return false;
+ }
+ 
+ void YahooAccount::slotGlobalIdentityChanged( const QString &key, const QVariant &value )
+ {
+-	if ( key == Kopete::Global::Properties::self()->photo().key() )
++	if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
+ 	{
+-		setBuddyIcon( KURL( value.toString() ) );
++		if ( key == Kopete::Global::Properties::self()->photo().key() )
++		{
++			setBuddyIcon( KURL( value.toString() ) );
++		}
+ 	}
+ }
+ 
+ void YahooAccount::setPictureFlag( int flag )
+ {
+-	kdDebug(14180) << k_funcinfo << " PictureFlag: " << flag << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << " PictureFlag: " << flag << endl;
+ 	m_pictureFlag = flag;
+ }
+ 
+@@ -572,6 +646,19 @@
+ 	return m_pictureFlag;
+ }
+ 
++void YahooAccount::sendFile( YahooContact *to, const KURL &url )
++{	
++	QFile file( url.path() );
++	
++	Kopete::Transfer *transfer = Kopete::TransferManager::transferManager()->addTransfer ( to,
++		url.fileName(), file.size(), to->userId(), Kopete::FileTransferInfo::Outgoing );
++	m_session->sendFile( transfer->info().transferId(), to->userId(), QString(), url );
++	
++	QObject::connect( transfer, SIGNAL(result( KIO::Job * )), this, SLOT(slotFileTransferResult( KIO::Job * )) );
++	
++	m_fileTransfers.insert( transfer->info().transferId(), transfer );	
++}
++
+ /***************************************************************************
+  *                                                                         *
+  *   Slot for KYahoo signals                                               *
+@@ -580,163 +667,263 @@
+ 
+ void YahooAccount::slotLoginResponse( int succ , const QString &url )
+ {
+-	kdDebug(14180) << k_funcinfo << succ << ", " << url << ")]" << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << succ << ", " << url << ")]" << endl;
+ 	QString errorMsg;
+-	if ( succ == YAHOO_LOGIN_OK || (succ == YAHOO_LOGIN_DUPL && m_lastDisconnectCode == 2) )
++	if ( succ == Yahoo::LoginOk || (succ == Yahoo::LoginDupl && m_lastDisconnectCode == 2) )
+ 	{
+-		slotGotBuddies(yahooSession()->getLegacyBuddyList());
+-
+-		//Yahoo only supports connecting as invisible and online, nothing else
+-		if ( initialStatus() == m_protocol->Invisible )
++		if ( initialStatus().internalStatus() )
++		{
+ 			static_cast<YahooContact *>( myself() )->setOnlineStatus( initialStatus() );
++		}
+ 		else
++		{
+ 			static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Online );
++		}
+ 
+ 		 
+ 		setBuddyIcon( myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString() );
++		m_session->getYABEntries( m_YABLastMerge, m_YABLastRemoteRevision );
+ 		m_lastDisconnectCode = 0;
+-		m_keepaliveTimer->start( 60 * 1000 );
+ 		return;
+ 	}
+-	else if(succ == YAHOO_LOGIN_PASSWD)
++	else if(succ == Yahoo::LoginPasswd)
+ 	{
++		initConnectionSignals( DeleteConnections );
+ 		password().setWrong();
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 		disconnected( BadPassword );
+ 		return;
+ 	}
+-	else if(succ == YAHOO_LOGIN_LOCK)
++	else if(succ == Yahoo::LoginLock)
+ 	{
++		initConnectionSignals( DeleteConnections );
+ 		errorMsg = i18n("Could not log into Yahoo service: your account has been locked.\nVisit %1 to reactivate it.").arg(url);
+ 		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Error, errorMsg);
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 		disconnected( BadUserName ); // FIXME: add a more appropriate disconnect reason
+ 		return;
+ 	}
+-	else if ( succ == YAHOO_LOGIN_UNAME )
++	else if( succ == Yahoo::LoginUname )
+ 	{
++		initConnectionSignals( DeleteConnections );
+ 		errorMsg = i18n("Could not log into the Yahoo service: the username specified was invalid.");
+ 		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Error, errorMsg);
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 		disconnected( BadUserName );
++		return;
+ 	}
+-	else if ( succ == YAHOO_LOGIN_DUPL && m_lastDisconnectCode != 2 )
++	else if( succ == Yahoo::LoginDupl && m_lastDisconnectCode != 2 )
+ 	{
++		initConnectionSignals( DeleteConnections );
+ 		errorMsg = i18n("You have been logged out of the Yahoo service, possibly due to a duplicate login.");
+ 		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(), KMessageBox::Error, errorMsg);
+ 		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 		disconnected( Manual ); // cannot use ConnectionReset since that will auto-reconnect
+ 		return;
+ 	}
++	else if( succ == Yahoo::LoginVerify )
++	{
++		initConnectionSignals( DeleteConnections );
++		static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
++		YahooVerifyAccount *verifyDialog = new YahooVerifyAccount( this );
++		verifyDialog->setUrl( KURL(url) );
++		verifyDialog->show();
++		return;
++	}
+ 
+ 	//If we get here, something went wrong, so set ourselves to offline
+ 	static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
+ 	disconnected( Unknown );
++}
+ 
++void YahooAccount::slotDisconnected()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	initConnectionSignals( DeleteConnections );
++	if( !isConnected() )
++		return;
++	static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
++	disconnected( ConnectionReset );	// may reconnect
++	
++	QString message;
++	message = i18n( "%1 has been disconnected.\nError message:\n%2 - %3" )
++		.arg( accountId() ).arg( m_session->error() ).arg( m_session->errorString() );
++	KNotification::event( "connection_lost", message, myself()->onlineStatus().protocolIcon() );
+ }
+ 
++void YahooAccount::slotLoginFailed()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	initConnectionSignals( DeleteConnections );
++	static_cast<YahooContact *>( myself() )->setOnlineStatus( m_protocol->Offline );
++	disconnected( Manual );			// don't reconnect
++	
++	QString message;
++	message = i18n( "There was an error while connecting %1 to the Yahoo server.\nError message:\n%2 - %3" )
++		.arg( accountId() ).arg( m_session->error() ).arg( m_session->errorString() );
++	KNotification::event( "cannot_connect", message, myself()->onlineStatus().protocolIcon() );
++}
++
++void YahooAccount::slotError( int level )
++{
++	// enum LogLevel { Debug, Info, Notice, Warning, Error, Critical }; 
++	if( level <= Client::Notice )
++		return;
++	else if( level <= Client::Warning )
++		KMessageBox::information( Kopete::UI::Global::mainWidget(), i18n( "%1\n\nReason: %2 - %3" ).arg(m_session->errorInformation())
++		                          .arg(m_session->error()).arg(m_session->errorString()), i18n( "Yahoo Plugin" ) );
++	else 
++		KMessageBox::error( Kopete::UI::Global::mainWidget(), i18n( "%1\n\nReason: %2 - %3" ).arg(m_session->errorInformation())
++		                    .arg(m_session->error()).arg(m_session->errorString()), i18n( "Yahoo Plugin" ) );
++}
++
+ void YahooAccount::slotGotBuddy( const QString &userid, const QString &alias, const QString &group )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	IDs[userid] = QPair<QString, QString>(group, alias);
+ 
+ 	// Serverside -> local
+ 	if ( !contact( userid ) )
+ 	{
+-		kdDebug(14180) << "SS Contact " << userid << " is not in the contact list. Adding..." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << "SS Contact " << userid << " is not in the contact list. Adding..." << endl;
+ 		Kopete::Group *g=Kopete::ContactList::self()->findGroup(group);
+ 		addContact(userid, alias.isEmpty() ? userid : alias, g, Kopete::Account::ChangeKABC);
+ 	}
+ }
+ 
++void YahooAccount::slotAuthorizationAccepted( const QString &who )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	QString message;
++	message = i18n( "User %1 has granted your authorization request." )
++		.arg( who );
++	KNotification::event( "kopete_authorization", message, 0 , 0 , 0 );
++	
++	if( contact( who ) )
++		contact( who )->setOnlineStatus( m_protocol->Online );
++}
++
++void YahooAccount::slotAuthorizationRejected( const QString &who, const QString &msg )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	QString message;
++	message = i18n( "User %1 has granted your authorization request.\n%2" )
++		.arg( who ).arg( msg );
++	KNotification::event( "kopete_authorization", message, 0 , 0 , 0 );
++}
++
++void YahooAccount::slotgotAuthorizationRequest( const QString &user, const QString &msg, const QString &name )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	Q_UNUSED( msg );
++	Q_UNUSED( name );
++	YahooContact *kc = contact( user );
++	Kopete::MetaContact *metaContact=0L;
++	if(kc)
++		metaContact=kc->metaContact();
++	
++	int hideFlags=Kopete::UI::ContactAddedNotifyDialog::InfoButton;
++	if( metaContact && !metaContact->isTemporary() )
++		hideFlags |= Kopete::UI::ContactAddedNotifyDialog::AddCheckBox | Kopete::UI::ContactAddedNotifyDialog::AddGroupBox ;
++	
++	Kopete::UI::ContactAddedNotifyDialog *dialog=
++		new Kopete::UI::ContactAddedNotifyDialog( user,QString::null,this, hideFlags );
++	QObject::connect(dialog,SIGNAL(applyClicked(const QString&)),
++	                 this,SLOT(slotContactAddedNotifyDialogClosed(const QString& )));
++	dialog->show();
++}
++
++void YahooAccount::slotContactAddedNotifyDialogClosed( const QString &user )
++{
++	const Kopete::UI::ContactAddedNotifyDialog *dialog =
++		dynamic_cast<const Kopete::UI::ContactAddedNotifyDialog *>(sender());
++	if(!dialog || !isConnected())
++		return;
++	
++	m_session->sendAuthReply( user, dialog->authorized(), QString::null );
++	
++	if(dialog->added())
++	{
++		dialog->addContact();
++	}
++}
++
+ void YahooAccount::slotGotIgnore( const QStringList & /* igns */ )
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+ void YahooAccount::slotGotIdentities( const QStringList & /* ids */ )
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+-void YahooAccount::slotStatusChanged( const QString &who, int stat, const QString &msg, int  away )
++void YahooAccount::slotStatusChanged( const QString &who, int stat, const QString &msg, int away, int idle )
+ {
+-	//kdDebug(14180) << k_funcinfo << endl;
+-	Kopete::Contact *kc = contact( who );
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << who << " status: " << stat << " msg: " << msg << " away: " << away << " idle: " << idle <<endl;
++	YahooContact *kc = contact( who );
+ 	
+ 	if( contact( who ) == myself() )
+ 		return;
+ 	
+ 	if ( kc )
+ 	{
+-		Kopete::OnlineStatus newStatus = static_cast<YahooProtocol*>( m_protocol )->statusFromYahoo( stat );
++		Kopete::OnlineStatus newStatus = m_protocol->statusFromYahoo( stat );
+ 		Kopete::OnlineStatus oldStatus = kc->onlineStatus();
+ 
+-		if( newStatus == static_cast<YahooProtocol*>( m_protocol )->Custom ) {
++		if( newStatus == m_protocol->Custom ) {
+ 			if( away == 0 )
+-				newStatus = static_cast<YahooProtocol*>( m_protocol )->Online;
++				newStatus =m_protocol->Online;
+ 			kc->setProperty( m_protocol->awayMessage, msg);
+ 		}
+ 		else
+ 			kc->removeProperty( m_protocol->awayMessage );
+ 
+-		if( newStatus != static_cast<YahooProtocol*>( m_protocol )->Offline &&
+-		    oldStatus == static_cast<YahooProtocol*>( m_protocol )->Offline && contact(who) != myself() &&
+-		    myself()->onlineStatus() != m_protocol->Invisible )
++		if( newStatus != m_protocol->Offline &&
++		    oldStatus == m_protocol->Offline && contact(who) != myself() )
+ 		{
+-			m_session->requestBuddyIcon( who );		// Try to get Buddy Icon
++			//m_session->requestBuddyIcon( who );		// Try to get Buddy Icon
+ 
+-			if ( !myself()->property( Kopete::Global::Properties::self()->photo() ).isNull() )
++			if ( !myself()->property( Kopete::Global::Properties::self()->photo() ).isNull() &&
++					myself()->onlineStatus() != m_protocol->Invisible && 
++					!kc->stealthed() )
+ 			{
+-				static_cast< YahooContact* >( contact( who ) )->sendBuddyIconUpdate( pictureFlag() );
+-				static_cast< YahooContact* >( contact( who ) )->sendBuddyIconChecksum(
+-					myself()->property( YahooProtocol::protocol()->iconCheckSum ).value().toInt() );
++				kc->sendBuddyIconUpdate( pictureFlag() );
++				kc->sendBuddyIconChecksum( myself()->property( YahooProtocol::protocol()->iconCheckSum ).value().toInt() );
+ 			}
+ 		}
+ 		
+-		if( newStatus == static_cast<YahooProtocol*>( m_protocol )->Idle ) {
+-			// TODO: Use the argument 'away' to set the idleTime
+-		}
++		//if( newStatus == static_cast<YahooProtocol*>( m_protocol )->Idle ) {
++		if( newStatus == m_protocol->Idle )
++			kc->setIdleTime( idle ? idle : 1 );
++		else
++			kc->setIdleTime( 0 );
+ 		
+ 		kc->setOnlineStatus( newStatus );
+ 	}
+ }
+ 
+-void YahooAccount::slotGotIm( const QString &who, const QString &msg, long tm, int /*stat*/)
++void YahooAccount::slotStealthStatusChanged( const QString &who, Yahoo::StealthStatus state )
+ {
+-	QFont msgFont;
+-	QDateTime msgDT;
+-	Kopete::ContactPtrList justMe;
+-	QRegExp regExp;
+-	int pos = 0;
++	//kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Stealth Status of " << who << "changed to " << state << endl;
+ 	
+-	// Check for ping-messages
+-	if( contact( who ) == myself() && msg.startsWith("<ping>") )
+-	{
+-		kdDebug(14180) << "Ping packet received." << endl;
+-		m_waitingForResponse = false;
++	YahooContact* kc = contact( who );
++	if ( kc == NULL ) {
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
++	kc->setStealthed( state == Yahoo::StealthActive );
++}
++
++QString YahooAccount::prepareIncomingMessage( const QString &messageText )
++{
++	QString newMsgText( messageText );
++	QRegExp regExp;
++	int pos = 0;
++	newMsgText = stripMsgColorCodes( newMsgText );
+ 	
+-	if( !contact( who ) )
+-	{
+-		kdDebug(14180) << "Adding contact " << who << endl;
+-		addContact( who,who,  0L, Kopete::Account::Temporary );
+-	}
++	kdDebug(YAHOO_GEN_DEBUG) << "Message after stripping color codes '" << newMsgText << "'" << endl;
+ 	
+-	//Parse the message for it's properties
+-	kdDebug(14180) << "Original message is '" << msg << "'" << endl;
+-	//kdDebug(14180) << "Message color is " << getMsgColor(msg) << endl;
+-	QColor fgColor = getMsgColor( msg );
+-	if (tm == 0)
+-		msgDT.setTime_t(time(0L));
+-	else
+-		msgDT.setTime_t(tm, Qt::LocalTime);
+-	
+-	QString newMsgText = stripMsgColorCodes( msg );
+-	
+-	kdDebug(14180) << "Message after stripping color codes '" << newMsgText << "'" << endl;
+-
+ 	newMsgText.replace( QString::fromLatin1( "&" ), QString::fromLatin1( "&amp;" ) );
+ 	
+ 	// Replace Font tags
+@@ -747,18 +934,19 @@
+ 		pos = regExp.search( newMsgText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+-			newMsgText.replace( regExp, QString::fromLatin1("<font\\1style=\"font-size:\\2pt\">" ) );
++		newMsgText.replace( regExp, QString::fromLatin1("<font\\1style=\"font-size:\\2pt\">" ) );
+ 		}
+ 	}
+ 	
+ 	// Remove FADE and ALT tags
+-    regExp.setPattern( "<[/]*FADE([^>]*)>" );
+-    pos = 0;
++	regExp.setPattern( "<[/]*FADE([^>]*)>" );
++	pos = 0;
+ 	while ( pos >= 0 ) {
+ 		pos = regExp.search( newMsgText, pos );
+ 		if ( pos >= 0 ) {
+ 			pos += regExp.matchedLength();
+ 			newMsgText.replace( regExp, QString::fromLatin1("" ) );
++		
+ 		}
+ 	}
+ 	regExp.setPattern( "<[/]*ALT([^>]*)>" );
+@@ -770,7 +958,7 @@
+ 			newMsgText.replace( regExp, QString::fromLatin1("" ) );
+ 		}
+ 	}
+-				
++	
+ 	// Replace < and > in text
+ 	regExp.setPattern( "<(?!(/*(font.*|[\"fbui])>))" );
+ 	pos = 0;
+@@ -804,8 +992,34 @@
+ 	
+ 	newMsgText.replace( QString::fromLatin1( "\r" ), QString::fromLatin1( "<br/>" ) );
+ 	
+-	kdDebug(14180) << "Message after fixing font tags '" << newMsgText << "'" << endl;
++	return newMsgText;
++}
++
++void YahooAccount::slotGotIm( const QString &who, const QString &msg, long tm, int /*stat*/)
++{
++	QFont msgFont;
++	QDateTime msgDT;
++	Kopete::ContactPtrList justMe;
+ 	
++	if( !contact( who ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << "Adding contact " << who << endl;
++		addContact( who,who,  0L, Kopete::Account::Temporary );
++	}
++	
++	//Parse the message for it's properties
++	kdDebug(YAHOO_GEN_DEBUG) << "Original message is '" << msg << "'" << endl;
++	//kdDebug(YAHOO_GEN_DEBUG) << "Message color is " << getMsgColor(msg) << endl;
++	QColor fgColor = getMsgColor( msg );
++	if (tm == 0)
++		msgDT.setTime_t(time(0L));
++	else
++		msgDT.setTime_t(tm, Qt::LocalTime);
++	
++	QString newMsgText = prepareIncomingMessage( msg );
++	
++	kdDebug(YAHOO_GEN_DEBUG) << "Message after fixing font tags '" << newMsgText << "'" << endl;
++	
+ 	Kopete::ChatSession *mm = contact(who)->manager(Kopete::Contact::CanCreate);
+ 	
+ 	// Tell the message manager that the buddy is done typing
+@@ -828,7 +1042,7 @@
+ 	
+ 	if( !contact( who ) )
+ 	{
+-		kdDebug(14180) << "Adding contact " << who << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << "Adding contact " << who << endl;
+ 		addContact( who,who,  0L, Kopete::Account::Temporary );
+ 	}
+ 	
+@@ -841,8 +1055,8 @@
+ 	
+ 	QString buzzMsgText = i18n("This string is shown when the user is buzzed by a contact", "Buzz!!");
+ 	
+-	Kopete::Message kmsg(msgDT, contact(who), justMe, buzzMsgText,
+-	                     Kopete::Message::Inbound , Kopete::Message::PlainText);
++	Kopete::Message kmsg(msgDT, contact(who), justMe, buzzMsgText, Kopete::Message::Inbound,
++	                     Kopete::Message::PlainText, QString::null, Kopete::Message::TypeAction);
+ 	QColor fgColor( "gold" );
+ 	kmsg.setFg( fgColor );
+ 	
+@@ -852,57 +1066,417 @@
+ 	mm->emitNudgeNotification();
+ }
+ 
+-void YahooAccount::slotGotConfInvite( const QString & /* who */, const QString & /* room */, const QString & /* msg */, const QStringList & /* members */ )
++void YahooAccount::slotGotConfInvite( const QString & who, const QString & room, const QString &msg, const QStringList &members )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << who << " has invited you to join the conference \"" << room << "\" : " << msg << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Members: " << members << endl;
++	
++	if( !m_pendingConfInvites.contains( room ) )	// We have to keep track of the invites as the server will send the same invite twice if it gets canceled by the host
++		m_pendingConfInvites.push_back( room );
++	else
++	{
++		return;
++	}
++	
++	QString m = who;
++	QStringList myMembers;
++	myMembers.push_back( who );
++	for( QStringList::const_iterator it = ++members.begin(); it != members.end(); it++ )
++	{
++		if( *it != m_session->userId() )
++		{
++			m.append( QString(", %1").arg( *it ) );
++			myMembers.push_back( *it );
++		}
++	}
++	if( KMessageBox::Yes == KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(), 
++				i18n("%1 has invited you to join a conference with %2.\n\nHis message: %3\n\n Accept?")
++				.arg(who).arg(m).arg(msg), QString::null, i18n("Accept"), i18n("Ignore") ) )
++	{
++		m_session->joinConference( room, myMembers );
++		if( !m_conferences[room] )
++		{
++			Kopete::ContactPtrList others;
++			YahooConferenceChatSession *session = new YahooConferenceChatSession( room, protocol(), myself(), others );
++			m_conferences[room] = session;
++			
++			QObject::connect( session, SIGNAL(leavingConference( YahooConferenceChatSession * ) ), this, SLOT( slotConfLeave( YahooConferenceChatSession * ) ) );
++			
++			for ( QValueList<QString>::ConstIterator it = myMembers.begin(); it != myMembers.end(); ++it )
++			{
++				YahooContact * c = contact( *it );
++				if ( !c )
++				{
++					kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Adding contact " << *it << " to conference." << endl;
++					addContact( *it,*it,  0L, Kopete::Account::Temporary );
++					c = contact( *it );
++				}
++				session->joined( c );	
++			}
++			session->view( true )->raise( false );
++		}
++	}
++	else
++		m_session->declineConference( room, myMembers, QString::null );
++	
++	m_pendingConfInvites.remove( room );
+ }
+ 
+-void YahooAccount::slotConfUserDecline( const QString & /* who */, const QString & /* room */, const QString & /* msg */ )
++void YahooAccount::prepareConference( const QString &who )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	QString room;
++	for( int i = 0; i < 22; i++ )
++	{
++		char c = rand()%52;
++		room += (c > 25)  ? c + 71 : c + 65;
++	}
++	room = QString("%1-%2--").arg(accountId()).arg(room);
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "The generated roomname is: " << room << endl;
++	
++	QStringList buddies;
++	QDictIterator<Kopete::Contact> it( contacts() );
++	for( ; it.current(); ++it )
++	{
++		if( (*it) != myself() )
++			buddies.push_back( (*it)->contactId() );
++	}
++	
++	YahooInviteListImpl *dlg = new YahooInviteListImpl( Kopete::UI::Global::mainWidget() );
++	QObject::connect( dlg, SIGNAL( readyToInvite( const QString &, const QStringList &, const QStringList &, const QString & ) ), 
++			this, SLOT( slotInviteConference( const QString &, const QStringList &, const QStringList &, const QString & ) ) );
++	dlg->setRoom( room );
++	dlg->fillFriendList( buddies );
++	dlg->addInvitees( QStringList( who ) );
++	dlg->show();
+ }
+ 
+-void YahooAccount::slotConfUserJoin( const QString & /* who */, const QString & /* room */ )
++void YahooAccount::slotInviteConference( const QString &room, const QStringList &members, const QStringList &participants, const QString &msg )
++{	
++	Q_UNUSED( participants );
++kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Inviting " << members << " to the conference " << room << ". Message: " << msg << endl;
++	m_session->inviteConference( room, members, msg );
++	
++	Kopete::ContactPtrList others;
++	YahooConferenceChatSession *session = new YahooConferenceChatSession( room, protocol(), myself(), others );
++	m_conferences[room] = session;
++	
++	QObject::connect( session, SIGNAL(leavingConference( YahooConferenceChatSession * ) ), this, SLOT( slotConfLeave( YahooConferenceChatSession * ) ) );
++	
++	session->joined( static_cast< YahooContact *>(myself()) );
++	session->view( true )->raise( false );
++}
++
++void YahooAccount::slotAddInviteConference( const QString &room, const QStringList &who, const QStringList &members, const QString &msg )
++{	
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Inviting " << who << " to the conference " << room << ". Message: " << msg << endl;
++	m_session->addInviteConference( room, who, members, msg );
++}
++
++void YahooAccount::slotConfUserDecline( const QString &who, const QString &room, const QString &msg)
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	if( !m_conferences.contains( room ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Error. No chatsession for this conference found." << endl;
++		return;
++	}
++	
++	YahooConferenceChatSession *session = m_conferences[room];
++	
++	QString body = i18n( "%1 declined to join the conference: \"%2\"" ).arg( who ).arg( msg );
++	Kopete::Message message = Kopete::Message( contact( who ), myself(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
++	
++	session->appendMessage( message );
+ }
+ 
+-void YahooAccount::slotConfUserLeave( const QString & /* who */, const QString & /* room */ )
++void YahooAccount::slotConfUserJoin( const QString &who, const QString &room )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;	
++	if( !m_conferences.contains( room ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Error. No chatsession for this conference found." << endl;
++		return;
++	}
++	
++	YahooConferenceChatSession *session = m_conferences[room];
++	if( !contact( who ) )
++	{
++		addContact( who, who,  0L, Kopete::Account::Temporary );
++	}
++	session->joined( contact( who ) );
+ }
+ 
+-void YahooAccount::slotConfMessage( const QString & /* who */, const QString & /* room */, const QString & /* msg */ )
++void YahooAccount::slotConfUserLeave( const QString & who, const QString &room )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;	
++	if( !m_conferences.contains( room ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Error. No chatsession for this conference found." << endl;
++		return;
++	}
++	
++	YahooConferenceChatSession *session = m_conferences[room];
++	if( !contact( who ) )
++	{
++		addContact( who, who,  0L, Kopete::Account::Temporary );
++	}
++	session->left( contact( who ) );
+ }
+ 
++void YahooAccount::slotConfLeave( YahooConferenceChatSession *s )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	if( !s )
++		return;
++	QStringList members;
++	for( Kopete::ContactPtrList::iterator it = s->members().begin(); it != s->members().end(); ++it )
++	{
++		if( (*it) == myself() )
++			continue;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Member: " << (*it)->contactId() << endl;
++		members.append( (*it)->contactId() );
++	}
++	m_session->leaveConference( s->room(), members );
++	m_conferences.remove( s->room() );
++}
++
++void YahooAccount::slotConfMessage( const QString &who, const QString &room, const QString &msg )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	if( !m_conferences.contains( room ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Error. No chatsession for this conference found." << endl;
++		return;
++	}
++	
++	YahooConferenceChatSession *session = m_conferences[room];
++
++	QFont msgFont;
++	QDateTime msgDT;
++	Kopete::ContactPtrList justMe;
++	
++	if( !contact( who ) )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << "Adding contact " << who << endl;
++		addContact( who,who,  0L, Kopete::Account::Temporary );
++	}
++	kdDebug(YAHOO_GEN_DEBUG) << "Original message is '" << msg << "'" << endl;
++	
++	QColor fgColor = getMsgColor( msg );
++	msgDT.setTime_t(time(0L));	
++	
++	QString newMsgText = prepareIncomingMessage( msg );
++	
++	kdDebug(YAHOO_GEN_DEBUG) << "Message after fixing font tags '" << newMsgText << "'" << endl;
++	session->receivedTypingMsg(contact(who), false);
++	
++	justMe.append(myself());
++	
++	Kopete::Message kmsg(msgDT, contact(who), justMe, newMsgText,
++	                     Kopete::Message::Inbound , Kopete::Message::RichText);
++	
++	kmsg.setFg( fgColor );
++	session->appendMessage(kmsg);
++}
++
++void YahooAccount::sendConfMessage( YahooConferenceChatSession *s, Kopete::Message &message )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	QStringList members;
++	for( Kopete::ContactPtrList::iterator it = s->members().begin(); it != s->members().end(); ++it )
++	{
++		if( (*it) == myself() )
++			continue;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Member: " << (*it)->contactId() << endl;
++		members.append( (*it)->contactId() );
++	}
++	m_session->sendConferenceMessage( s->room(), members, YahooContact::prepareMessage( message.escapedBody() ) );
++}
++
++void YahooAccount::slotGotYABRevision( long rev, bool merged )
++{
++	if( merged )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Merge Revision received: " << rev << endl;
++		configGroup()->writeEntry( "YABLastMerge", rev );
++		m_YABLastMerge = rev;
++	}
++	else
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Remote Revision received: " << rev << endl;
++		configGroup()->writeEntry( "YABLastRemoteRevision", rev );
++		m_YABLastRemoteRevision = rev;
++	}
++}
++
++void YahooAccount::slotGotYABEntry( YABEntry *entry )
++{
++	YahooContact* kc = contact( entry->yahooId );
++	if( !kc )
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "YAB entry received for a contact not on our buddylist: " << entry->yahooId << endl;
++		delete entry;
++	}
++	else
++	{
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "YAB entry received for: " << entry->yahooId << endl;
++		if( entry->source == YABEntry::SourceYAB )
++		{
++			kc->setYABEntry( entry );
++		}
++		else if( entry->source == YABEntry::SourceContact )
++		{
++			entry->YABId = kc->yabEntry()->YABId;
++			YahooUserInfoDialog *dlg = new YahooUserInfoDialog( kc, Kopete::UI::Global::mainWidget(), "yahoo userinfo" );
++			dlg->setData( *entry );
++			dlg->setAccountConnected( isConnected() );
++			dlg->show();
++			QObject::connect( dlg, SIGNAL(saveYABEntry( YABEntry & )), this, SLOT(slotSaveYABEntry( YABEntry & )));
++			delete entry;
++		}
++	}
++}
++
++void YahooAccount::slotSaveYABEntry( YABEntry &entry )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "YABId: " << entry.YABId << endl;
++	if( entry.YABId > 0 )
++		m_session->saveYABEntry( entry );
++	else
++		m_session->addYABEntry( entry );
++}
++
++void YahooAccount::slotModifyYABEntryError( YABEntry *entry, const QString &msg )
++{
++	YahooContact* kc = contact( entry->yahooId );
++	if( kc )
++		kc->setYABEntry( entry, true );
++	KMessageBox::sorry( Kopete::UI::Global::mainWidget(), msg, i18n( "Yahoo Plugin" ) );
++}
++
+ void YahooAccount::slotGotFile( const QString &  who, const QString &  url , long /* expires */, const QString &  msg ,
+ 	const QString &  fname, unsigned long  fesize  )
+ {
+-	kdDebug(14180) << k_funcinfo << "Received File from " << who << ": " << msg << endl;
+-	kdDebug(14180) << k_funcinfo << "Filename :" << fname << " size:" << fesize << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Received File from " << who << ": " << msg << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Filename :" << fname << " size:" << fesize << endl;
+ 	
+ 	Kopete::TransferManager::transferManager()->askIncomingTransfer( contact( who ) , fname, fesize, msg, url );	
+-	QObject::connect( Kopete::TransferManager::transferManager(), SIGNAL( accepted( Kopete::Transfer *, const QString& ) ),
+-					this, SLOT( slotReceiveFileAccepted( Kopete::Transfer *, const QString& ) ) );
++	
++	if( m_pendingFileTransfers.empty() )
++	{
++		QObject::connect( Kopete::TransferManager::transferManager(), SIGNAL( accepted( Kopete::Transfer *, const QString& ) ),
++						this, SLOT( slotReceiveFileAccepted( Kopete::Transfer *, const QString& ) ) );
++		QObject::connect( Kopete::TransferManager::transferManager(), SIGNAL( refused(const Kopete::FileTransferInfo& ) ),
++						this, SLOT( slotReceiveFileRefused( const Kopete::FileTransferInfo& ) ) );
++	}
++	m_pendingFileTransfers.append( url );
+ }
+ 
+-void YahooAccount::slotReceiveFileAccepted(Kopete::Transfer *trans, const QString& /*fileName*/)
++void YahooAccount::slotReceiveFileAccepted(Kopete::Transfer *transfer, const QString& fileName)
+ {	
+-	m_session->getUrlHandle( trans );
+-	QObject::disconnect( Kopete::TransferManager::transferManager(), SIGNAL( accepted( Kopete::Transfer *, const QString& ) ),
+-					this, SLOT( slotReceiveFileAccepted( Kopete::Transfer *, const QString& ) ) );
++	if( !m_pendingFileTransfers.contains( transfer->info().internalId() ) )
++		return;
++	
++	m_pendingFileTransfers.remove( transfer->info().internalId() );
++	
++	//Create directory if it doesn't already exist
++	QDir dir;
++	QString path = QFileInfo( fileName ).dirPath();
++	for( int i = 1; i <= path.contains('/'); ++i )
++	{
++		if( !dir.exists( path.section( '/', 0, i ) ) )
++		{
++			dir.mkdir( path.section( '/', 0, i) );
++		}		
++	}
++	
++	m_session->receiveFile( transfer->info().transferId(), transfer->info().contact()->contactId(), transfer->info().internalId(), fileName );	
++	m_fileTransfers.insert( transfer->info().transferId(), transfer );
++	QObject::connect( transfer, SIGNAL(result( KIO::Job * )), this, SLOT(slotFileTransferResult( KIO::Job * )) );
++	
++	if( m_pendingFileTransfers.empty() )
++	{
++		QObject::disconnect( Kopete::TransferManager::transferManager(), SIGNAL( accepted( Kopete::Transfer *, const QString& ) ),
++							this, SLOT( slotReceiveFileAccepted( Kopete::Transfer *, const QString& ) ) );
++		QObject::disconnect( Kopete::TransferManager::transferManager(), SIGNAL( refused(const Kopete::FileTransferInfo& ) ),
++						this, SLOT( slotReceiveFileRefused( const Kopete::FileTransferInfo& ) ) );
++	}	
+ }
+ 
++void YahooAccount::slotReceiveFileRefused( const Kopete::FileTransferInfo& info )
++{		
++	if( !m_pendingFileTransfers.contains( info.internalId() ) )
++		return;
++	
++	m_pendingFileTransfers.remove( info.internalId() );
++	m_session->rejectFile( info.contact()->contactId(), info.internalId() );
++	
++	if( m_pendingFileTransfers.empty() )
++	{
++		QObject::disconnect( Kopete::TransferManager::transferManager(), SIGNAL( accepted( Kopete::Transfer *, const QString& ) ),
++							this, SLOT( slotReceiveFileAccepted( Kopete::Transfer *, const QString& ) ) );
++		QObject::disconnect( Kopete::TransferManager::transferManager(), SIGNAL( refused(const Kopete::FileTransferInfo& ) ),
++						this, SLOT( slotReceiveFileRefused( const Kopete::FileTransferInfo& ) ) );
++	}
++}
++
++void YahooAccount::slotFileTransferBytesProcessed( unsigned int transferId, unsigned int bytes )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Transfer: " << transferId << " Bytes:" << bytes << endl;
++	Kopete::Transfer *t = m_fileTransfers[transferId];
++	if( !t )
++		return;
++	
++	t->slotProcessed( bytes );
++}
++
++void YahooAccount::slotFileTransferComplete( unsigned int transferId )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	Kopete::Transfer *t = m_fileTransfers[transferId];
++	if( !t )
++		return;
++	
++	t->slotComplete();
++	m_fileTransfers.remove( transferId );
++}
++
++void YahooAccount::slotFileTransferError( unsigned int transferId, int error, const QString &desc )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	Kopete::Transfer *t = m_fileTransfers[transferId];
++	if( !t )
++		return;
++	
++	t->slotError( error, desc );
++	m_fileTransfers.remove( transferId );
++}
++
++void YahooAccount::slotFileTransferResult( KIO::Job *job )
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	const Kopete::Transfer *t = dynamic_cast< const Kopete::Transfer * >( job );
++	
++	if( !t )
++		return;
++	
++	if( t->error() == KIO::ERR_USER_CANCELED )
++	{
++		m_session->cancelFileTransfer( t->info().transferId() );
++		m_fileTransfers.remove( t->info().transferId() );
++	}
++}
++
+ void YahooAccount::slotContactAdded( const QString & /* myid */, const QString & /* who */, const QString & /* msg */ )
+ {
+-//	kdDebug(14180) << k_funcinfo << myid << " " << who << " " << msg << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << myid << " " << who << " " << msg << endl;
+ }
+ 
+ void YahooAccount::slotRejected( const QString & /* who */, const QString & /* msg */ )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+ void YahooAccount::slotTypingNotify( const QString &who, int what )
+@@ -912,12 +1486,12 @@
+ 
+ void YahooAccount::slotGameNotify( const QString & /* who */, int /* stat */ )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+ void YahooAccount::slotMailNotify( const QString& from, const QString& /* subject */, int cnt )
+ {
+-//	kdDebug(14180) << k_funcinfo << "Mail count: " << cnt << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Mail count: " << cnt << endl;
+ 
+ 	if ( cnt > m_currentMailCount && from.isEmpty() )
+ 	{
+@@ -927,7 +1501,7 @@
+ 		m_currentMailCount = cnt;
+ 	}
+ 	else if ( cnt > m_currentMailCount )
+-	{	kdDebug(14180) << k_funcinfo << "attempting to trigger event" << endl;
++	{	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "attempting to trigger event" << endl;
+ 		QObject::connect(KNotification::event( "yahoo_mail", i18n( "You have a message from %1 in your Yahoo inbox.").arg(from) 
+ 			, 0 , 0 , i18n( "Open Inbox..." ) ), SIGNAL(activated(unsigned int ) ) , this, SLOT( slotOpenInbox() ) );
+ 		m_currentMailCount = cnt;
+@@ -936,99 +1510,111 @@
+ 
+ void YahooAccount::slotSystemMessage( const QString & /* msg */ )
+ {
+-//	kdDebug(14180) << k_funcinfo << msg << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << msg << endl;
+ }
+ 
+-void YahooAccount::slotError( const QString &err, int fatal )
+-{
+-	kdDebug(14180) << k_funcinfo << fatal << ": " << err << endl;
+-	m_lastDisconnectCode = fatal;
+-	m_keepaliveTimer->stop();
+-	if(isConnected()) { // If we are already disconnected we don't need this MessageBox (<heiko at rangun.de>)
+-		KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error, i18n( "<qt>The connection with the Yahoo server was lost.</qt>" ), 
+-							i18n( "Connection Lost - Yahoo Plugin" ) );
+-	
+-		if ( fatal == 1 || fatal == 2 || fatal == -1 )
+-			disconnect();
+-	}
+-}
+-
+ void YahooAccount::slotRemoveHandler( int /* fd */ )
+ {
+-//	kdDebug(14180) << k_funcinfo << endl;
++//	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ }
+ 
+ void YahooAccount::slotGotWebcamInvite( const QString& who )
+ {
+ 	YahooContact* kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+-	kc->gotWebcamInvite();
++	
++	if( m_pendingWebcamInvites.contains( who ) )
++		return;
++	
++	m_pendingWebcamInvites.append( who );
++	
++	if( KMessageBox::Yes == KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(), i18n("%1 has invited you to view his/her webcam. Accept?")
++							.arg(who), QString::null, i18n("Accept"), i18n("Ignore") ) )
++	{
++		m_pendingWebcamInvites.remove( who );
++		m_session->requestWebcam( who );
++	}
+ }
++void YahooAccount::slotWebcamNotAvailable( const QString &who )
++{
++	KMessageBox::sorry( Kopete::UI::Global::mainWidget(), i18n("Webcam for %1 is not available.").arg(who), i18n( "Yahoo Plugin" ) );
++}
+ 
+ void YahooAccount::slotGotWebcamImage( const QString& who, const QPixmap& image )
+ {
+ 	YahooContact* kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+ 	kc->receivedWebcamImage( image );
+ }
+ 
++void YahooAccount::slotPictureStatusNotiy( const QString &who, int status)
++{
++	YahooContact *kc = contact( who );
++	if ( kc == NULL ) {
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		return;
++	}
++	
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " changed picture status to" << status << endl;
++}
++
+ void YahooAccount::slotGotBuddyIconChecksum(const QString &who, int checksum)
+ {
+ 	YahooContact *kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+ 
+ 	if ( checksum == kc->property( YahooProtocol::protocol()->iconCheckSum ).value().toInt() &&
+ 	     QFile::exists( locateLocal( "appdata", "yahoopictures/"+ who.lower().replace(QRegExp("[./~]"),"-")  +".png" ) ) )
+ 	{
+-		kdDebug(14180) << k_funcinfo << "Icon already exists. I will not request it again." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Icon already exists. I will not request it again." << endl;
+ 		return;
+ 	} else
+-		m_session->requestBuddyIcon( who );
++		m_session->requestPicture( who );
+ }
+ 
+ void YahooAccount::slotGotBuddyIconInfo(const QString &who, KURL url, int checksum)
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	YahooContact *kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+ 
+ 	if ( checksum == kc->property( YahooProtocol::protocol()->iconCheckSum ).value().toInt()  &&
+ 	     QFile::exists( locateLocal( "appdata", "yahoopictures/"+ who.lower().replace(QRegExp("[./~]"),"-")  +".png" ) ))
+ 	{
+-		kdDebug(14180) << k_funcinfo << "Icon already exists. I will not download it again." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Icon already exists. I will not download it again." << endl;
+ 		return;
+ 	} else
+-		m_session->downloadBuddyIcon( who, url, checksum );
++		m_session->downloadPicture( who, url, checksum );
+ }
+ 
+ void YahooAccount::slotGotBuddyIcon( const QString &who, KTempFile *file, int checksum )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	YahooContact *kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+-	kc->setDisplayPicture( file, checksum );	
++	kc->setDisplayPicture( file, checksum );
+ }
+ void YahooAccount::slotGotBuddyIconRequest( const QString & who )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	YahooContact *kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+ 	kc->sendBuddyIconInfo( myself()->property( YahooProtocol::protocol()->iconRemoteUrl ).value().toString(),
+@@ -1037,8 +1623,7 @@
+ 
+ void YahooAccount::setBuddyIcon( KURL url )
+ {
+-	
+-	kdDebug(14180) << k_funcinfo << "Url: " << url.path() << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "Url: " << url.path() << endl;
+ 	QString s = url.path();
+ 	if ( url.path().isEmpty() )
+ 	{
+@@ -1061,12 +1646,14 @@
+ 			KMessageBox::sorry( Kopete::UI::Global::mainWidget(), i18n( "<qt>The selected buddy icon could not be opened. <br>Please set a new buddy icon.</qt>" ), i18n( "Yahoo Plugin" ) );
+ 			return;
+ 		}
+-		image = image.smoothScale( 96, 96, QImage::ScaleMax );
+-		if(image.width() > image.height()) {
+-			image = image.copy((image.width()-image.height())/2, 0, image.height(), image.height());
++		image = image.smoothScale( 96, 96, QImage::ScaleMin );
++		if(image.width() < image.height())
++		{
++			image = image.copy((image.width()-image.height())/2, 0, 96, 96);
+ 		}
+-		else if(image.height() > image.width()) {
+-			image = image.copy(0, (image.height()-image.width())/2, image.width(), image.width());
++		else if(image.height() < image.width())
++		{
++			image = image.copy(0, (image.height()-image.width())/2, 96, 96);
+ 		}
+ 
+ 		if( !image.save( newlocation, "PNG" ) || !iconFile.open(IO_ReadOnly) )
+@@ -1104,14 +1691,14 @@
+ 			configGroup()->writeEntry( "iconCheckSum", checksum );
+ 			configGroup()->writeEntry( "iconExpire", myself()->property( YahooProtocol::protocol()->iconExpire ).value().toInt() );
+ 			if ( m_session != 0 )
+-				m_session->uploadBuddyIcon( newlocation, data.size() );
++				m_session->uploadPicture( newlocation );
+ 		}
+ 	}
+ }
+ 
+ void YahooAccount::slotBuddyIconChanged( const QString &url )
+ {
+-	kdDebug(14180) << k_funcinfo << endl;
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
+ 	QDictIterator<Kopete::Contact> it( contacts() );
+ 	int checksum = myself()->property( YahooProtocol::protocol()->iconCheckSum ).value().toInt();
+ 
+@@ -1125,32 +1712,98 @@
+ 		myself()->setProperty( YahooProtocol::protocol()->iconRemoteUrl, url );
+ 		configGroup()->writeEntry( "iconRemoteUrl", url );
+ 		setPictureFlag( 2 );
++		m_session->sendPictureChecksum( checksum, QString::null );
+ 	}
+ 	
+-	for ( ; it.current(); ++it )
++// 	for ( ; it.current(); ++it )
++// 	{
++// 		if ( it.current() == myself() || !it.current()->isReachable() )
++// 			continue;
++// 		static_cast< YahooContact* >( it.current() )->sendBuddyIconChecksum( checksum );
++// 		static_cast< YahooContact* >( it.current() )->sendBuddyIconUpdate( pictureFlag() );
++// 	}
++}
++
++void YahooAccount::slotWebcamReadyForTransmission()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	if( !m_webcam )
+ 	{
+-		if ( it.current() == myself() || !it.current()->isReachable() )
+-			continue;
+-		static_cast< YahooContact* >( it.current() )->sendBuddyIconChecksum( checksum );
+-		static_cast< YahooContact* >( it.current() )->sendBuddyIconUpdate( pictureFlag() );
++		m_webcam = new YahooWebcam( this );
++		QObject::connect( m_webcam, SIGNAL(webcamClosing()), this, SLOT(slotOutgoingWebcamClosing()) );
+ 	}
++	
++	m_webcam->startTransmission();
+ }
+ 
++void YahooAccount::slotWebcamStopTransmission()
++{
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	
++	if( m_webcam )
++	{
++		m_webcam->stopTransmission();
++	}
++}
++
++void YahooAccount::slotOutgoingWebcamClosing()
++{
++	m_session->closeOutgoingWebcam();
++	m_webcam->deleteLater();
++	m_webcam = 0L;
++}
++
++void YahooAccount::slotWebcamViewerJoined( const QString &viewer )
++{
++	if( m_webcam )
++	{
++		m_webcam->addViewer( viewer );
++	}
++}
++
++void YahooAccount::slotWebcamViewerRequest( const QString &viewer )
++{
++	if( KMessageBox::Yes == KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(), i18n("%1 wants to view your webcam. Grant access?")
++		.arg(viewer), QString::null, i18n("Accept"), i18n("Ignore") ) )	
++		m_session->grantWebcamAccess( viewer );
++}
++
++void YahooAccount::slotWebcamViewerLeft( const QString &viewer )
++{
++	if( m_webcam )
++	{
++		m_webcam->removeViewer( viewer );
++	}
++}
++
+ void YahooAccount::slotWebcamClosed( const QString& who, int reason )
+ {
+ 	YahooContact* kc = contact( who );
+ 	if ( kc == NULL ) {
+-		kdDebug(14180) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
+ 		return;
+ 	}
+ 	kc->webcamClosed( reason );
+ }
+ 
++void YahooAccount::slotWebcamPaused( const QString &who )
++{
++	YahooContact* kc = contact( who );
++	if ( kc == NULL ) {
++		kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << "contact " << who << " doesn't exist." << endl;
++		return;
++	}
++	kc->webcamPaused();
++}
++
+ void YahooAccount::setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason)
+ {
+-	if ( myself()->onlineStatus().status() == Kopete::OnlineStatus::Offline &&
+-	     ( status.status() == Kopete::OnlineStatus::Online || status.status() == Kopete::OnlineStatus::Invisible ) )
++	kdDebug(YAHOO_GEN_DEBUG) << k_funcinfo << endl;
++	if ( myself()->onlineStatus().status() == Kopete::OnlineStatus::Offline && 
++	     status.status() != Kopete::OnlineStatus::Offline )
+ 	{
++		if( !reason.isEmpty() )
++			m_session->setStatusMessageOnConnect( reason );
+ 		connect( status );
+ 	}
+ 	else if ( myself()->onlineStatus().status() != Kopete::OnlineStatus::Offline &&
+@@ -1184,6 +1837,11 @@
+ 	KRun::runURL( KURL( QString::fromLatin1("http://address.yahoo.com/") ) , "text/html" );
+ }
+ 
++void YahooAccount::slotEditOwnYABEntry()
++{
++	myself()->slotUserInfo();
++}
++
+ #include "yahooaccount.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/yahoo/ui/yahoouserinfobase.ui	(revision 568672)
++++ kopete/protocols/yahoo/ui/yahoouserinfobase.ui	(revision 586398)
+@@ -1,189 +0,0 @@
+-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+-<class>YahooUserInfoWidget</class>
+-<widget class="QWidget">
+-    <property name="name">
+-        <cstring>YahooUserInfoWidget</cstring>
+-    </property>
+-    <property name="geometry">
+-        <rect>
+-            <x>0</x>
+-            <y>0</y>
+-            <width>270</width>
+-            <height>240</height>
+-        </rect>
+-    </property>
+-    <property name="sizePolicy">
+-        <sizepolicy>
+-            <hsizetype>1</hsizetype>
+-            <vsizetype>1</vsizetype>
+-            <horstretch>0</horstretch>
+-            <verstretch>0</verstretch>
+-        </sizepolicy>
+-    </property>
+-    <property name="minimumSize">
+-        <size>
+-            <width>270</width>
+-            <height>240</height>
+-        </size>
+-    </property>
+-    <grid>
+-        <property name="name">
+-            <cstring>unnamed</cstring>
+-        </property>
+-        <widget class="QLayoutWidget" row="0" column="0">
+-            <property name="name">
+-                <cstring>layout7</cstring>
+-            </property>
+-            <grid>
+-                <property name="name">
+-                    <cstring>unnamed</cstring>
+-                </property>
+-                <widget class="QLabel" row="3" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1_2_3</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Nickname:</string>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="4" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1_2_4</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Email address:</string>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="1" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1_2</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>First name:</string>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="0" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Yahoo ID:</string>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="0" column="1">
+-                    <property name="name">
+-                        <cstring>m_userID</cstring>
+-                    </property>
+-                    <property name="enabled">
+-                        <bool>false</bool>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="1" column="1">
+-                    <property name="name">
+-                        <cstring>m_fname</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="3" column="1">
+-                    <property name="name">
+-                        <cstring>m_nname</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="2" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1_2_2</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Last name:</string>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="4" column="1">
+-                    <property name="name">
+-                        <cstring>m_email</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="2" column="1">
+-                    <property name="name">
+-                        <cstring>m_lname</cstring>
+-                    </property>
+-                </widget>
+-            </grid>
+-        </widget>
+-        <widget class="QGroupBox" row="1" column="0">
+-            <property name="name">
+-                <cstring>groupBox8</cstring>
+-            </property>
+-            <property name="title">
+-                <string>Phone Numbers</string>
+-            </property>
+-            <grid>
+-                <property name="name">
+-                    <cstring>unnamed</cstring>
+-                </property>
+-                <widget class="QLayoutWidget" row="0" column="0">
+-                    <property name="name">
+-                        <cstring>layout15</cstring>
+-                    </property>
+-                    <grid>
+-                        <property name="name">
+-                            <cstring>unnamed</cstring>
+-                        </property>
+-                        <widget class="QLineEdit" row="0" column="1">
+-                            <property name="name">
+-                                <cstring>m_hphone</cstring>
+-                            </property>
+-                        </widget>
+-                        <widget class="QLabel" row="1" column="0">
+-                            <property name="name">
+-                                <cstring>textLabel1_2_5_2</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>Work:</string>
+-                            </property>
+-                        </widget>
+-                        <widget class="QLineEdit" row="1" column="1">
+-                            <property name="name">
+-                                <cstring>m_wphone</cstring>
+-                            </property>
+-                        </widget>
+-                        <widget class="QLabel" row="0" column="0">
+-                            <property name="name">
+-                                <cstring>textLabel1_2_5</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>Home:</string>
+-                            </property>
+-                        </widget>
+-                    </grid>
+-                </widget>
+-            </grid>
+-        </widget>
+-        <spacer row="2" column="0">
+-            <property name="name">
+-                <cstring>spacer7</cstring>
+-            </property>
+-            <property name="orientation">
+-                <enum>Vertical</enum>
+-            </property>
+-            <property name="sizeType">
+-                <enum>Expanding</enum>
+-            </property>
+-            <property name="sizeHint">
+-                <size>
+-                    <width>20</width>
+-                    <height>40</height>
+-                </size>
+-            </property>
+-        </spacer>
+-    </grid>
+-</widget>
+-<tabstops>
+-    <tabstop>m_fname</tabstop>
+-    <tabstop>m_lname</tabstop>
+-    <tabstop>m_nname</tabstop>
+-    <tabstop>m_email</tabstop>
+-    <tabstop>m_hphone</tabstop>
+-    <tabstop>m_wphone</tabstop>
+-    <tabstop>m_userID</tabstop>
+-</tabstops>
+-<layoutdefaults spacing="6" margin="11"/>
+-</UI>
+--- kopete/protocols/yahoo/ui/yahooverifyaccountbase.ui	(revision 0)
++++ kopete/protocols/yahoo/ui/yahooverifyaccountbase.ui	(revision 586398)
+@@ -0,0 +1,159 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>YahooVerifyAccountBase</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>YahooVerifyAccountBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>450</width>
++            <height>200</height>
++        </rect>
++    </property>
++    <property name="minimumSize">
++        <size>
++            <width>450</width>
++            <height>200</height>
++        </size>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel1</cstring>
++            </property>
++            <property name="text">
++                <string>Your Account has to be verified because of too many false login attempts.&lt;br&gt;</string>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout0</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>textLabel2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Please enter the chars shown in the picture:</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit">
++                    <property name="name">
++                        <cstring>mWord</cstring>
++                    </property>
++                </widget>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer15</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>110</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++            </hbox>
++        </widget>
++        <spacer>
++            <property name="name">
++                <cstring>spacer4</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>20</width>
++                    <height>16</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout16</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer14</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>72</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>mPicture</cstring>
++                    </property>
++                    <property name="minimumSize">
++                        <size>
++                            <width>240</width>
++                            <height>75</height>
++                        </size>
++                    </property>
++                    <property name="pixmap">
++                        <pixmap>image0</pixmap>
++                    </property>
++                    <property name="scaledContents">
++                        <bool>true</bool>
++                    </property>
++                </widget>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer13</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>72</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++            </hbox>
++        </widget>
++    </vbox>
++</widget>
++<images>
++    <image name="image0">
++        <data format="XPM.GZ" length="4833">789c8597596f23470e80dfe75718c3b7c182e9eabb11ec834fc9873cbeaf601fc86ec9966df994cfc5fef794483633934d10c836fcb9582cde55fee5dbd2d9de68e9db2f5f9ee7349fb64bed153d2d7deb5e66b38fdffef3efff7ef99aa64b8baf2c5b4abffeebcb57dc5c6a9720499290640b8613e110ff22eb941b07657e7256f90be742e4a7c6a9ed076791c7a1732efbd784d3f817615a71167db0e55c0a17ce95c88f8ced3c7e74d6f306cea29fd159f583b3e8a75367d18f5bce8df0b63389be67e3ccfcd97716fd78e22cfaf1d459edefedcbedbc63e75af4cf85b33edeb8616cfef1b5b39eb7e72cf6c28b7166fb53678df7b5b3fadf388b3d503a8b3d40c6b9eaa35767d9cf37c6a5e53f73d6f3769d55bedf5f2789ac6bfcf2de1fda33ce4cdfbb716eeb6fce1acf1de3c2f2bbe7acf573605cdafe2b67f5efd359f20bb97165febe38b3c453fd2bfa7cd0a67165fea97c9db416ff1de3b1e9d77a6d12567bf8c159ed9d1ab7969fc2b8d378e2ba304579c93769bd719457fd524f2184cae221f51bd250a8fd3c35ae4cfec1b8b6fa06e3c6eaffc859d651f215b2d0c7efdab8327b969d459e9e8d7bfd57c68df587c43be4c1e20b685c1b9f0b17c1e283cfce927f96f911ca40d63fcbce7afebd31eb3a91b3fa37376ead9e64dea5759606a94f546eb23499883d9bc69932bef4acf22cf594725c1f8bfca9b3c8d3aa711e82c82bb73de3817111a4fe2171d67e1a1b97ba8e87ce5a8f12bfb48b2cfae8ceb85206894f9666135bff2e5c45d6fae894a3393a3f5be13aaeb7729eca4ff2d6ce3f5b701ef2b1c95f0aa7715dfb4de657519675d0fc8d8c9ba0f527f12faab234fd8fc695f1ab716dfa3f84ebb2089dec5f779678d381711d74beae398b7f540b3751bfd6e39ab1c9033b6bbd07e326687dcb3c2da8ecf47cfa301e9bbe37e389c94b3c0a2edba0f5f361dc194b3c8b36eed77acf9c453fab7f6d95587e6e8d83c957c25dc9668fdc5fc538b2c6e3a6e754e7adcc836252b6a9d69bccffb2ad535d67e98fb2ab538befaab3e8439947e5b84e82f6ffa17165f1bd7096fcc1ccb8b67a981b375a0f20f92d2775b078493dd54c75aaef0de9dfba75167fea2eb2f683dc5771388d753fbe396b7fca7c6b52ea2c5e57ce621fcbfdd26464f1812767ed8f63e3ced665de34c464fe9e1bb3d5b3f45bc3dca67a7fc9fba7697b46a9bf66cc13cb8fcc8b66c2960f3832b6f3988dad1e2828b799c53371d6f9766b9c5b7f4afe286983f5c3aeb3be177ace6c1ecc9cb51f6a678def8a7169f351fca710f5a93d9db3d64febacf9981aa76a2f5e3b6b7d5d1af7f6df3aebfb67e4acf93f72d6f972675cd83c7d77d67cac3bebfdfce9acf7eb87b3c66b665cdabc5feed9f44bfd51caade59395dbc4fc3f33cecc9f9b9e35bf786fdccfffc459e7ffc059eb7fe2acefcfd459df13dbceda5f4367bddffed8affdf0665c243a6f769c351f6367f51f7ad6fcefcf9dd57e72567fd959e3dd3a6bbc3b677daf34ce6affadb3dadbdb57263a5f46ce7adf8e9dd5dededfbe5e2f9cb5de5b678df7bb71a5fa59f767dccf77cd57d6f7136c185b7e79d359f3159cf53df7e8acf19e19f7f57ee5acef9b0d67f5b733b6fa844b63f38f07ceea9fcc3fca5b9bef58199b3dbce5acefa53567bd6fee8c73d54f95b3fa3b34b6fcc3b3b3f6dba1b3f6afe6a788fb6bad9f1f3f08f19b90b18ddff0f3dafefc2fe4bb284948f1b7f1e2e73fca4ff012af708ad77883b77f2f8f33bc8b9aeff1011ff1099f718e2ff88a6ff88e1ff8196da33fc92fe30aaee21aaee3060e70889bb885dbb88323dc8d7a407df941be8dd2dfa3ec5e94dac7033cc4233cc6133cc5333cc78bffb327c18029669863812556d1ef1a9ba8168080a1850ec608daaf30814bb882296ec035dc486426700b33b8837b78c0213cc2133ce367af3f7a93c01c5e700b5ee10d6fe11d093ee01396610556f104d6601d36a2d77abf0da2f41036610bb6b1841d18c12e7c873dd887033884233886133885b318297d3fc558e114cee1021208d1e01432c8a180122aa8e3c5190f2322c63bb507995aea62bc37698c9f34a14bba822d9ad235ddd02dcde80e87744f0f7fc823d1233de1363d634d737aa1577aa3ebf8047ba70ffaa4655aa1555aa375b37f0c298e6923ca0fb0a1212cd3266dd136edd08876e93bedd13e1dd0211d997e88f6031dd3099d624e67744e17f15f8b40296594cb273ef61632aa5ff34515d5d43032707c19449fd6e993db283b8217ee62fc0630fa31bf1cdf037c493bb1724ef98a162d30e56bcae185467cc3b731dfa0f935f919dff13daef1033ff2133fc77d039e73d41da55ff90d268b8afba17ea27d30a18edff9833f7999577895d7a88421aff31b6fc0e04ff5c6314acc031ef2266cc4c7ce036ff12ca66a10ff75d95eacfd2ccf3b0bfd38e651ac93f7d83b77f84e47d1e6f1222e0bf9c5ef3ff7a3f690766f4ffd0490aa85affffbf5cbef985d44a8</data>
++    </image>
++</images>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/yahoo/ui/yahoouserinfodialog.cpp	(revision 0)
++++ kopete/protocols/yahoo/ui/yahoouserinfodialog.cpp	(revision 586398)
+@@ -0,0 +1,260 @@
++/*
++ Kopete Yahoo Protocol
++ yahoouserinfodialog.h - Display Yahoo user info
++
++ Copyright (c) 2005 Matt Rogers <mattr at kde.org>
++ Copyright (c) 2006 Andre Duffeck <andre at duffeck.de>
++
++ Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++ *************************************************************************
++ *                                                                       *
++ * This library is free software; you can redistribute it and/or         *
++ * modify it under the terms of the GNU Lesser General Public            *
++ * License as published by the Free Software Foundation; either          *
++ * version 2 of the License, or (at your option) any later version.      *
++ *                                                                       *
++ *************************************************************************
++*/
++
++#include "yahoouserinfodialog.h"
++
++#include <qlayout.h>
++#include <qlineedit.h>
++#include <qspinbox.h>
++#include <qcombobox.h>
++#include <qtextedit.h>
++#include <qobject.h>
++#include <qtextcodec.h>
++
++#include <kdatewidget.h>
++#include <kdebug.h>
++#include <kglobal.h>
++#include <kiconloader.h>
++#include <kjanuswidget.h>
++#include <klocale.h>
++
++#include "yahooworkinfowidget.h"
++#include "yahoogeneralinfowidget.h"
++#include "yahoootherinfowidget.h"
++#include "yahoocontact.h"
++
++YahooUserInfoDialog::YahooUserInfoDialog( YahooContact *c, QWidget * parent, const char * name )
++: KDialogBase( KDialogBase::IconList, 0,  parent, name, false, i18n( "Yahoo User Information" ), User2|User1|Cancel, Cancel, false, i18n("Save and Close"), i18n("Merge with existing entry") )
++{
++	kdDebug(14180) << k_funcinfo << "Creating new yahoo user info widget" << endl;
++	m_contact = c;
++	showButton( User2, false );
++	QFrame* genInfo = addPage( i18n( "General Info" ),
++	                                         i18n( "General Yahoo Information" ),
++	                                         KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "identity" ), KIcon::Desktop ) );
++	QVBoxLayout* genLayout = new QVBoxLayout( genInfo );
++	m_genInfoWidget = new YahooGeneralInfoWidget( genInfo, "Basic Information" );
++	genLayout->addWidget( m_genInfoWidget );
++	
++	QFrame* workInfo = addPage( i18n( "Work Info" ),
++	                                          i18n( "Work Information" ),
++	                                          KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "attach" ), KIcon::Desktop ) );
++	QVBoxLayout* workLayout = new QVBoxLayout( workInfo );
++	m_workInfoWidget = new YahooWorkInfoWidget( workInfo, "Work Information" );
++	workLayout->addWidget( m_workInfoWidget );
++	
++	QFrame* otherInfo = addPage( i18n( "Other Info" ),
++	                                           i18n( "Other Yahoo Information" ),
++	                                           KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "email" ), KIcon::Desktop ) );
++	QVBoxLayout* otherLayout = new QVBoxLayout( otherInfo );
++	m_otherInfoWidget = new YahooOtherInfoWidget( otherInfo, "Other Information"  );
++	otherLayout->addWidget( m_otherInfoWidget );
++	
++	QObject::connect(this, SIGNAL(user1Clicked()), this, SLOT(slotSaveAndCloseClicked()));
++}
++
++void YahooUserInfoDialog::setAccountConnected( bool isOnline )
++{
++	enableButton( User1, isOnline );
++	enableButton( User2, isOnline );
++}
++
++void YahooUserInfoDialog::slotSaveAndCloseClicked()
++{
++	YABEntry entry;
++	entry.yahooId = m_yab.yahooId;
++	entry.YABId = m_yab.YABId;
++	entry.firstName = m_genInfoWidget->firstNameEdit->text();
++	entry.secondName = m_genInfoWidget->secondNameEdit->text();
++	entry.lastName = m_genInfoWidget->lastNameEdit->text();
++	entry.nickName = m_genInfoWidget->nickNameEdit->text();
++	entry.email = m_genInfoWidget->emailEdit->text();
++	entry.privatePhone = m_genInfoWidget->phoneEdit->text();
++	entry.workPhone = m_workInfoWidget->phoneEdit->text();
++	entry.pager = m_genInfoWidget->pagerEdit->text();
++	entry.fax = m_genInfoWidget->faxEdit->text();
++	entry.phoneMobile = m_genInfoWidget->cellEdit->text();
++	entry.additionalNumber = m_genInfoWidget->additionalEdit->text();
++	entry.altEmail1 = m_genInfoWidget->emailEdit_2->text();
++	entry.altEmail2 = m_genInfoWidget->emailEdit_3->text();
++	entry.privateURL = m_genInfoWidget->homepageEdit->text();
++	entry.title = m_genInfoWidget->titleEdit->text();
++	entry.corporation = m_workInfoWidget->companyEdit->text();
++	entry.workAdress = m_workInfoWidget->addressEdit->text();
++	entry.workCity = m_workInfoWidget->cityEdit->text();
++	entry.workState = m_workInfoWidget->stateEdit->text();
++	entry.workZIP = m_workInfoWidget->zipEdit->text();
++	entry.workCountry = m_workInfoWidget->countryEdit->text();
++	entry.workURL = m_workInfoWidget->homepageEdit->text();
++	entry.privateAdress = m_genInfoWidget->addressEdit->text();
++	entry.privateCity = m_genInfoWidget->cityEdit->text();
++	entry.privateState = m_genInfoWidget->stateEdit->text();
++	entry.privateZIP = m_genInfoWidget->zipEdit->text();
++	entry.privateCountry = m_genInfoWidget->countryEdit->text();
++	QString bi = m_genInfoWidget->birthdayEdit->text();
++	entry.birthday = QDate( bi.section("/",2,2).toInt(), bi.section("/",1,1).toInt(), bi.section("/",0,0).toInt() );
++	QString an = m_genInfoWidget->anniversaryEdit->text();
++	entry.anniversary = QDate( an.section("/",2,2).toInt(), an.section("/",1,1).toInt(), an.section("/",0,0).toInt() );
++	entry.additional1 = m_otherInfoWidget->note1Edit->text();
++	entry.additional2 = m_otherInfoWidget->note2Edit->text();
++	entry.additional3 = m_otherInfoWidget->note3Edit->text();
++	entry.additional4 = m_otherInfoWidget->note4Edit->text();
++	entry.notes = m_otherInfoWidget->commentsEdit->text();
++// 	entry.imAIM = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imGoogleTalk = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imICQ = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imIRC = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imMSN = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imQQ = m_genInfoWidget->firstNameEdit->text();
++// 	entry.imSkype = m_genInfoWidget->firstNameEdit->text();
++		
++	emit saveYABEntry( entry );
++	
++	QDialog::accept();
++}
++
++void YahooUserInfoDialog::slotUser2()
++{
++	if( m_contact )
++	{
++		YABEntry entry;
++		const YABEntry *oldEntry = m_contact->yabEntry();
++
++		entry.yahooId = m_yab.yahooId;
++		entry.YABId = m_yab.YABId;
++		entry.firstName = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->firstName : m_genInfoWidget->firstNameEdit->text();
++		entry.secondName = m_genInfoWidget->secondNameEdit->text().isEmpty() ? oldEntry->secondName : m_genInfoWidget->secondNameEdit->text();
++		entry.lastName = m_genInfoWidget->lastNameEdit->text().isEmpty() ? oldEntry->lastName : m_genInfoWidget->lastNameEdit->text();
++		entry.nickName = m_genInfoWidget->nickNameEdit->text().isEmpty() ? oldEntry->nickName : m_genInfoWidget->nickNameEdit->text();
++		entry.email = m_genInfoWidget->emailEdit->text().isEmpty() ? oldEntry->email : m_genInfoWidget->emailEdit->text();
++		entry.privatePhone = m_genInfoWidget->phoneEdit->text().isEmpty() ? oldEntry->privatePhone : m_genInfoWidget->phoneEdit->text();
++		entry.workPhone = m_workInfoWidget->phoneEdit->text().isEmpty() ? oldEntry->workPhone : m_workInfoWidget->phoneEdit->text();
++		entry.pager = m_genInfoWidget->pagerEdit->text().isEmpty() ? oldEntry->pager : m_genInfoWidget->pagerEdit->text();
++		entry.fax = m_genInfoWidget->faxEdit->text().isEmpty() ? oldEntry->fax : m_genInfoWidget->faxEdit->text();
++		entry.phoneMobile = m_genInfoWidget->cellEdit->text().isEmpty() ? oldEntry->phoneMobile : m_genInfoWidget->cellEdit->text();
++		entry.additionalNumber = m_genInfoWidget->additionalEdit->text().isEmpty() ? oldEntry->additionalNumber : m_genInfoWidget->additionalEdit->text();
++		entry.altEmail1 = m_genInfoWidget->emailEdit_2->text().isEmpty() ? oldEntry->altEmail1 : m_genInfoWidget->emailEdit_2->text();
++		entry.altEmail2 = m_genInfoWidget->emailEdit_3->text().isEmpty() ? oldEntry->altEmail2 : m_genInfoWidget->emailEdit_3->text();
++		entry.privateURL = m_genInfoWidget->homepageEdit->text().isEmpty() ? oldEntry->privateURL : m_genInfoWidget->homepageEdit->text();
++		entry.title = m_genInfoWidget->titleEdit->text().isEmpty() ? oldEntry->title : m_genInfoWidget->titleEdit->text();
++		entry.corporation = m_workInfoWidget->companyEdit->text().isEmpty() ? oldEntry->corporation : m_workInfoWidget->companyEdit->text();
++		entry.workAdress = m_workInfoWidget->addressEdit->text().isEmpty() ? oldEntry->workAdress : m_workInfoWidget->addressEdit->text();
++		entry.workCity = m_workInfoWidget->cityEdit->text().isEmpty() ? oldEntry->workCity : m_workInfoWidget->cityEdit->text();
++		entry.workState = m_workInfoWidget->stateEdit->text().isEmpty() ? oldEntry->workState : m_workInfoWidget->stateEdit->text();
++		entry.workZIP = m_workInfoWidget->zipEdit->text().isEmpty() ? oldEntry->workZIP : m_workInfoWidget->zipEdit->text();
++		entry.workCountry = m_workInfoWidget->countryEdit->text().isEmpty() ? oldEntry->workCountry : m_workInfoWidget->countryEdit->text();
++		entry.workURL = m_workInfoWidget->homepageEdit->text().isEmpty() ? oldEntry->workURL : m_workInfoWidget->homepageEdit->text();
++		entry.privateAdress = m_genInfoWidget->addressEdit->text().isEmpty() ? oldEntry->privateAdress : m_genInfoWidget->addressEdit->text();
++		entry.privateCity = m_genInfoWidget->cityEdit->text().isEmpty() ? oldEntry->privateCity : m_genInfoWidget->cityEdit->text();
++		entry.privateState = m_genInfoWidget->stateEdit->text().isEmpty() ? oldEntry->privateState : m_genInfoWidget->stateEdit->text();
++		entry.privateZIP = m_genInfoWidget->zipEdit->text().isEmpty() ? oldEntry->privateZIP : m_genInfoWidget->zipEdit->text();
++		entry.privateCountry = m_genInfoWidget->countryEdit->text().isEmpty() ? oldEntry->privateCountry : m_genInfoWidget->countryEdit->text();
++		
++		if( m_genInfoWidget->birthdayEdit->text().isEmpty() )
++			entry.birthday = oldEntry->birthday;
++		else
++		{
++			QString bi = m_genInfoWidget->birthdayEdit->text();
++			entry.birthday = QDate( bi.section("/",2,2).toInt(), bi.section("/",1,1).toInt(), bi.section("/",0,0).toInt() );
++		}
++		
++		if( m_genInfoWidget->anniversaryEdit->text().isEmpty() )
++			entry.anniversary = oldEntry->anniversary;
++		else
++		{
++			QString an = m_genInfoWidget->anniversaryEdit->text();
++			entry.anniversary = QDate( an.section("/",2,2).toInt(), an.section("/",1,1).toInt(), an.section("/",0,0).toInt() );
++		}
++		
++		entry.additional1 = m_otherInfoWidget->note1Edit->text().isEmpty() ? oldEntry->additional1 : m_otherInfoWidget->note1Edit->text();
++		entry.additional2 = m_otherInfoWidget->note2Edit->text().isEmpty() ? oldEntry->additional2 : m_otherInfoWidget->note2Edit->text();
++		entry.additional3 = m_otherInfoWidget->note3Edit->text().isEmpty() ? oldEntry->additional3 : m_otherInfoWidget->note3Edit->text();
++		entry.additional4 = m_otherInfoWidget->note4Edit->text().isEmpty() ? oldEntry->additional4 : m_otherInfoWidget->note4Edit->text();
++		entry.notes = m_otherInfoWidget->commentsEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imAIM = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imGoogleTalk = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imICQ = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imIRC = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imMSN = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imQQ = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++	// 	entry.imSkype = m_genInfoWidget->firstNameEdit->text().isEmpty() ? oldEntry->notes : m_otherInfoWidget->commentsEdit->text();
++		
++		emit saveYABEntry( entry );
++	}
++	
++	QDialog::accept();
++}
++
++void YahooUserInfoDialog::setData( const YABEntry &yab )
++{	
++	m_yab = yab;
++	
++	if( m_yab.source == YABEntry::SourceContact )
++	{
++		showButton( User2, true );
++		setButtonText( User1, i18n("Replace existing entry") );
++	}
++	
++	m_genInfoWidget->firstNameEdit->setText( yab.firstName );
++	m_genInfoWidget->secondNameEdit->setText( yab.secondName );
++	m_genInfoWidget->lastNameEdit->setText( yab.lastName );
++	m_genInfoWidget->nickNameEdit->setText( yab.nickName );
++	m_genInfoWidget->yahooIdEdit->setText( yab.yahooId );
++	m_genInfoWidget->titleEdit->setText( yab.title );
++	
++	if( yab.birthday.isValid() )
++		m_genInfoWidget->birthdayEdit->setText( QString("%1/%2/%3").arg( yab.birthday.day() ).arg( yab.birthday.month() ).arg( yab.birthday.year() ));
++	if( yab.anniversary.isValid() )
++	m_genInfoWidget->anniversaryEdit->setText( QString("%1/%2/%3").arg( yab.anniversary.day() ).arg( yab.anniversary.month() ).arg( yab.anniversary.year() ));
++	
++	m_genInfoWidget->addressEdit->setText( yab.privateAdress );
++	m_genInfoWidget->cityEdit->setText( yab.privateCity );
++	m_genInfoWidget->stateEdit->setText( yab.privateState );
++	m_genInfoWidget->zipEdit->setText( yab.privateZIP );
++	m_genInfoWidget->countryEdit->setText( yab.privateCountry );
++	m_genInfoWidget->phoneEdit->setText( yab.privatePhone );
++	m_genInfoWidget->cellEdit->setText( yab.phoneMobile );
++	m_genInfoWidget->faxEdit->setText( yab.fax );
++	m_genInfoWidget->pagerEdit->setText( yab.pager );
++	m_genInfoWidget->emailEdit->setText( yab.email );
++	m_genInfoWidget->emailEdit_2->setText( yab.altEmail1 );
++	m_genInfoWidget->emailEdit_3->setText( yab.altEmail2 );
++	m_genInfoWidget->homepageEdit->setText( yab.privateURL );
++	m_genInfoWidget->additionalEdit->setText( yab.additionalNumber );
++	
++	m_workInfoWidget->phoneEdit->setText( yab.workPhone );
++	m_workInfoWidget->addressEdit->setText( yab.workAdress );
++	m_workInfoWidget->cityEdit->setText( yab.workCity );
++	m_workInfoWidget->stateEdit->setText( yab.workState );
++	m_workInfoWidget->zipEdit->setText( yab.workZIP );
++	m_workInfoWidget->countryEdit->setText( yab.workCountry );
++	m_workInfoWidget->companyEdit->setText( yab.corporation );
++	m_workInfoWidget->homepageEdit->setText( yab.workURL );
++	
++	m_otherInfoWidget->commentsEdit->setText( yab.notes );
++	m_otherInfoWidget->note1Edit->setText( yab.additional1 );
++	m_otherInfoWidget->note2Edit->setText( yab.additional2 );
++	m_otherInfoWidget->note3Edit->setText( yab.additional3 );
++	m_otherInfoWidget->note4Edit->setText( yab.additional4 );
++}
++
++#include "yahoouserinfodialog.moc"
++
++//kate: indent-mode csands; tab-width 4; space-indent off; replace-tabs off;
++
+--- kopete/protocols/yahoo/ui/yahooinvitelistimpl.cpp	(revision 0)
++++ kopete/protocols/yahoo/ui/yahooinvitelistimpl.cpp	(revision 586398)
+@@ -0,0 +1,165 @@
++/*
++    YahooInviteListImpl - conference invitation dialog
++    
++    Copyright (c) 2004 by Duncan Mac-Vicar P.    <duncan at kde.org>
++    
++    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel at 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 "yahooinvitelistimpl.h"
++
++#include <kdebug.h>
++
++#include <qlistbox.h>
++#include <qlineedit.h>
++
++YahooInviteListImpl::YahooInviteListImpl(QWidget *parent, const char *name) : YahooInviteListBase(parent,name)
++{
++	listFriends->setSelectionMode( QListBox::Extended );
++	listInvited->setSelectionMode( QListBox::Extended );
++}
++
++YahooInviteListImpl::~YahooInviteListImpl()
++{
++}
++
++void YahooInviteListImpl::setRoom( const QString &room )
++{
++	kdDebug(14180) << k_funcinfo << "Setting roomname to: " << room << endl;
++
++	m_room = room;
++}
++
++void YahooInviteListImpl::fillFriendList( const QStringList &buddies )
++{	
++	kdDebug(14180) << k_funcinfo << "Adding friends: " << buddies << endl;
++
++	m_buddyList = buddies;
++	updateListBoxes();
++}
++
++void YahooInviteListImpl::updateListBoxes()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	listFriends->clear();
++	listInvited->clear();
++	listFriends->insertStringList( m_buddyList );
++	listFriends->sort();
++	listInvited->insertStringList( m_inviteeList );
++	listInvited->sort();
++}
++
++void YahooInviteListImpl::addInvitees( const QStringList &invitees )
++{
++	kdDebug(14180) << k_funcinfo << "Adding invitees: " << invitees << endl;
++
++	for( QStringList::const_iterator it = invitees.begin(); it != invitees.end(); it++ )
++	{
++		if( m_inviteeList.find( *it ) == m_inviteeList.end() )
++			m_inviteeList.push_back( *it );
++		if( m_buddyList.find( *it ) != m_buddyList.end() )
++			m_buddyList.remove( *it );
++	}
++
++	updateListBoxes();
++}
++
++void YahooInviteListImpl::removeInvitees( const QStringList &invitees )
++{
++	kdDebug(14180) << k_funcinfo << "Removing invitees: " << invitees << endl;
++
++	for( QStringList::const_iterator it = invitees.begin(); it != invitees.end(); it++ )
++	{
++		if( m_buddyList.find( *it ) == m_buddyList.end() )
++			m_buddyList.push_back( *it );
++		if( m_inviteeList.find( *it ) != m_inviteeList.end() )
++			m_inviteeList.remove( *it );
++	}
++
++	updateListBoxes();
++}
++
++void YahooInviteListImpl::addParticipant( const QString &p )
++{
++	m_participants.push_back( p );
++}
++
++void YahooInviteListImpl::btnInvite_clicked()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	if( m_inviteeList.count() )
++		emit readyToInvite( m_room, m_inviteeList,m_participants, editMessage->text() );
++	QDialog::accept();
++}
++
++
++void YahooInviteListImpl::btnCancel_clicked()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	QDialog::reject();
++}
++
++
++void YahooInviteListImpl::btnAddCustom_clicked()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	QString userId;
++	userId = editBuddyAdd->text();
++	if( userId.isEmpty() )
++		return;
++	
++	addInvitees( QStringList(userId) );
++	editBuddyAdd->clear();
++}
++
++
++void YahooInviteListImpl::btnRemove_clicked()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	QStringList buddies;
++	for( uint i=0; i<listInvited->count(); i++ )
++	{
++		if (listInvited->isSelected(i))
++		{
++			buddies.push_back( listInvited->text(i) );
++		}
++	}
++	removeInvitees( buddies );
++}
++
++
++void YahooInviteListImpl::btnAdd_clicked()
++{
++	kdDebug(14180) << k_funcinfo << endl;
++
++	QStringList buddies;
++	for( uint i=0; i<listFriends->count(); i++ )
++	{
++		if (listFriends->isSelected(i))
++		{
++			buddies.push_back( listFriends->text(i) );
++		}
++	}
++	addInvitees( buddies );
++}
++
++
++#include "yahooinvitelistimpl.moc"
++
++
++
++
+--- kopete/protocols/yahoo/ui/yahoowebcamdialog.cpp	(revision 568672)
++++ kopete/protocols/yahoo/ui/yahoowebcamdialog.cpp	(revision 586398)
+@@ -19,38 +19,39 @@
+ #include <qframe.h>
+ #include <qobject.h>
+ #include <qwidget.h>
++#include <qlabel.h>
++#include <qlayout.h>
++#include <qvbox.h>
+ #include <kdebug.h>
+ #include <klocale.h>
+-#include "yahoocontact.h"
+ 
++#include <webcamwidget.h>
+ 
+-
+-YahooWebcamDialog::YahooWebcamDialog( YahooContact* contact, QWidget * parent, const char * name )
+-	: KDialogBase( KDialogBase::Plain, i18n( "Webcam for %1" ).arg( contact->nickName() ),
+-                   KDialogBase::Close, KDialogBase::Close, parent, name, false, true /*seperator*/ ),
+-	m_imageContainer( this )
++YahooWebcamDialog::YahooWebcamDialog( const QString &contactId, QWidget * parent, const char * name )
++: KDialogBase( KDialogBase::Plain, i18n( "Webcam for %1" ).arg( contactId ),
++                   KDialogBase::Close, KDialogBase::Close, parent, name, false, true /*seperator*/ )
+ {
+ 	setInitialSize( QSize(320,290), false );
+ 	
+ 	setEscapeButton( KDialogBase::Close );
+-	/*
+-	QObject::connect( contact, SIGNAL( signalReceivedWebcamImage( const QPixmap&  ) ),
+-	                  this, SLOT( newImage( const QPixmap& ) ) );
+-	*/
+ 	QObject::connect( this, SIGNAL( closeClicked() ), this, SIGNAL( closingWebcamDialog() ) );
+-	/*
+-	QObject::connect( contact, SIGNAL( webcamClosed( int ) ), this, SLOT( webcamClosed( int ) ) );
+-	*/
+-	contactName = contact->contactId();
++
++	contactName = contactId;
++	QWidget *page = plainPage();
++	setMainWidget(page);
++
++	QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );	
++	m_imageContainer = new Kopete::WebcamWidget( page );
++	m_imageContainer->setText( i18n( "No webcam image received" ) );
++	m_imageContainer->setMinimumSize(320,240);
++	m_imageContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
++	topLayout->add( m_imageContainer );
+ 	
+-	QFrame* page = plainPage();
+-	if ( page )
+-	{
+-		kdDebug(14180) << k_funcinfo << "Adding webcam image container" << endl;
+-		m_imageContainer.setText( i18n( "No webcam image received" ) );
+-		m_imageContainer.setAlignment( Qt::AlignCenter );
+-		m_imageContainer.setMinimumSize(320,240);
+-	}
++	m_Viewer = new QLabel( page );
++	m_Viewer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
++	m_Viewer->hide();
++	topLayout->add( m_Viewer );
++
+ 	show();
+ }
+ 
+@@ -59,15 +60,16 @@
+ 
+ }
+ 
+-void YahooWebcamDialog::newImage( const QPixmap & image )
++void YahooWebcamDialog::newImage( const QPixmap &image )
+ {
+-	kdDebug(14180) << k_funcinfo << "New image received" << endl;
+-	kdDebug(14180) << image << endl;
+-	m_imageContainer.clear();
+-	m_imageContainer.setPixmap( image );
+-	show();
++	m_imageContainer->updatePixmap( image );
+ }
+ 
++void YahooWebcamDialog::webcamPaused()
++{
++	m_imageContainer->setText( QString::fromLatin1("*** Webcam paused ***") );
++}
++
+ void YahooWebcamDialog::webcamClosed( int reason  )
+ {
+ 	kdDebug(14180) << k_funcinfo << "webcam closed with reason?? " <<  reason <<endl;
+@@ -77,7 +79,7 @@
+ 	case 1:
+ 		closeReason = i18n( "%1 has stopped broadcasting" ).arg( contactName ); break;
+ 	case 2:
+-		closeReason = i18n( "%1 has canceled viewing permission" ).arg( contactName ); break;
++		closeReason = i18n( "%1 has cancelled viewing permission" ).arg( contactName ); break;
+ 	case 3:
+ 		closeReason = i18n( "%1 has declined permission to view webcam" ).arg( contactName ); break;
+ 	case 4:
+@@ -85,15 +87,27 @@
+ 	default:
+ 		closeReason = i18n( "Unable to view the webcam of %1 for an unknown reason" ).arg( contactName);
+ 	}
+-	m_imageContainer.clear();
++	m_imageContainer->clear();
+ 
+-	m_imageContainer.setText( closeReason );
+-	m_imageContainer.adjustSize();
+-	m_imageContainer.setAlignment( Qt::AlignCenter );
+-	adjustSize();
+-	show();
++	m_imageContainer->setText( closeReason );
+ }
+ 
++void YahooWebcamDialog::setViewer( const QStringList &viewer )
++{
++	QString s = i18n( "%1 viewer(s)" ).arg( viewer.size() );
++	if( viewer.size() )
++	{
++		s += ": ";
++		for ( QStringList::ConstIterator it = viewer.begin(); it != viewer.end(); ++it ) {
++			if( it != viewer.begin() )
++				s += ", ";
++			s += *it;
++		}
++	}
++	m_Viewer->setText( s );
++	m_Viewer->show();
++}
++
+ // kate: indent-mode csands; tab-width 4;
+ 
+ #include "yahoowebcamdialog.moc"
+--- kopete/protocols/yahoo/ui/yahoouserinfodialog.h	(revision 0)
++++ kopete/protocols/yahoo/ui/yahoouserinfodialog.h	(revision 586398)
+@@ -0,0 +1,56 @@
++/*
++ Kopete Yahoo Protocol
++ yahoouserinfodialog.h - Display Yahoo user info
++
++ Copyright (c) 2005 Matt Rogers <mattr at kde.org>
++ Copyright (c) 2006 Andre Duffeck <mattr at kde.org>
++
++ Kopete (c) 2002-2006 by the Kopete developers <kopete-devel at kde.org>
++
++ *************************************************************************
++ *                                                                       *
++ * This library is free software; you can redistribute it and/or         *
++ * modify it under the terms of the GNU Lesser General Public            *
++ * License as published by the Free Software Foundation; either          *
++ * version 2 of the License, or (at your option) any later version.      *
++ *                                                                       *
++ *************************************************************************
++*/
++
++#ifndef YAHOOUSERINFODIALOG_H_
++#define YAHOOUSERINFODIALOG_H_
++
++#include <kdialogbase.h>
++#include "../libkyahoo/yabentry.h"
++
++class KJanusWidget;
++class YahooWorkInfoWidget;
++class YahooGeneralInfoWidget;
++class YahooOtherInfoWidget;
++class YahooContact;
++
++class YahooUserInfoDialog : public KDialogBase
++{
++Q_OBJECT
++public:
++	YahooUserInfoDialog( YahooContact *c, QWidget* parent = 0, const char* name = 0 );
++	void setAccountConnected( bool isOnline );
++signals:
++	void saveYABEntry( YABEntry & );
++public slots:
++	void setData( const YABEntry &yab );
++private slots:
++	void slotSaveAndCloseClicked();
++	void slotUser2();
++private:
++	YahooGeneralInfoWidget* m_genInfoWidget;
++	YahooWorkInfoWidget* m_workInfoWidget;
++	YahooOtherInfoWidget* m_otherInfoWidget;
++	
++	YABEntry m_yab;
++	YahooContact *m_contact;
++};
++
++#endif
++
++//kate: indent-mode csands; tab-width 4; space-indent off; replace-tabs off;
+--- kopete/protocols/yahoo/ui/yahooinvitelistbase.ui	(revision 0)
++++ kopete/protocols/yahoo/ui/yahooinvitelistbase.ui	(revision 586398)
+@@ -0,0 +1,337 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>YahooInviteListBase</class>
++<widget class="QDialog">
++    <property name="name">
++        <cstring>YahooInviteListBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>529</width>
++            <height>418</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>Invite Friends to Conference</string>
++    </property>
++    <grid>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLayoutWidget" row="0" column="0">
++            <property name="name">
++                <cstring>layout19</cstring>
++            </property>
++            <vbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QGroupBox">
++                    <property name="name">
++                        <cstring>groupBox3</cstring>
++                    </property>
++                    <property name="title">
++                        <string>Conference Members</string>
++                    </property>
++                    <grid>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <widget class="QLayoutWidget" row="0" column="0">
++                            <property name="name">
++                                <cstring>layout5</cstring>
++                            </property>
++                            <vbox>
++                                <property name="name">
++                                    <cstring>unnamed</cstring>
++                                </property>
++                                <widget class="QLabel">
++                                    <property name="name">
++                                        <cstring>textLabel2</cstring>
++                                    </property>
++                                    <property name="text">
++                                        <string>Friend List</string>
++                                    </property>
++                                </widget>
++                                <widget class="QListBox">
++                                    <item>
++                                        <property name="text">
++                                            <string>New Item</string>
++                                        </property>
++                                    </item>
++                                    <property name="name">
++                                        <cstring>listFriends</cstring>
++                                    </property>
++                                    <property name="minimumSize">
++                                        <size>
++                                            <width>0</width>
++                                            <height>180</height>
++                                        </size>
++                                    </property>
++                                </widget>
++                            </vbox>
++                        </widget>
++                        <widget class="QLayoutWidget" row="0" column="2">
++                            <property name="name">
++                                <cstring>layout4</cstring>
++                            </property>
++                            <vbox>
++                                <property name="name">
++                                    <cstring>unnamed</cstring>
++                                </property>
++                                <widget class="QLabel">
++                                    <property name="name">
++                                        <cstring>textLabel2_2</cstring>
++                                    </property>
++                                    <property name="text">
++                                        <string>Chat Invitation List</string>
++                                    </property>
++                                </widget>
++                                <widget class="QListBox">
++                                    <item>
++                                        <property name="text">
++                                            <string>New Item</string>
++                                        </property>
++                                    </item>
++                                    <property name="name">
++                                        <cstring>listInvited</cstring>
++                                    </property>
++                                    <property name="minimumSize">
++                                        <size>
++                                            <width>0</width>
++                                            <height>150</height>
++                                        </size>
++                                    </property>
++                                </widget>
++                                <widget class="QLayoutWidget">
++                                    <property name="name">
++                                        <cstring>layout2</cstring>
++                                    </property>
++                                    <hbox>
++                                        <property name="name">
++                                            <cstring>unnamed</cstring>
++                                        </property>
++                                        <widget class="QLineEdit">
++                                            <property name="name">
++                                                <cstring>editBuddyAdd</cstring>
++                                            </property>
++                                        </widget>
++                                        <widget class="QPushButton">
++                                            <property name="name">
++                                                <cstring>btnCustomAdd</cstring>
++                                            </property>
++                                            <property name="text">
++                                                <string>Add</string>
++                                            </property>
++                                        </widget>
++                                    </hbox>
++                                </widget>
++                            </vbox>
++                        </widget>
++                        <widget class="QLayoutWidget" row="0" column="1">
++                            <property name="name">
++                                <cstring>layout10</cstring>
++                            </property>
++                            <vbox>
++                                <property name="name">
++                                    <cstring>unnamed</cstring>
++                                </property>
++                                <spacer>
++                                    <property name="name">
++                                        <cstring>spacer1_2</cstring>
++                                    </property>
++                                    <property name="orientation">
++                                        <enum>Vertical</enum>
++                                    </property>
++                                    <property name="sizeType">
++                                        <enum>Expanding</enum>
++                                    </property>
++                                    <property name="sizeHint">
++                                        <size>
++                                            <width>20</width>
++                                            <height>20</height>
++                                        </size>
++                                    </property>
++                                </spacer>
++                                <widget class="QPushButton">
++                                    <property name="name">
++                                        <cstring>btn_Add</cstring>
++                                    </property>
++                                    <property name="text">
++                                        <string>Add &gt;&gt;</string>
++                                    </property>
++                                </widget>
++                                <widget class="QPushButton">
++                                    <property name="name">
++                                        <cstring>btn_Remove</cstring>
++                                    </property>
++                                    <property name="text">
++                                        <string>&lt;&lt; Remove</string>
++                                    </property>
++                                </widget>
++                                <spacer>
++                                    <property name="name">
++                                        <cstring>spacer1</cstring>
++                                    </property>
++                                    <property name="orientation">
++                                        <enum>Vertical</enum>
++                                    </property>
++                                    <property name="sizeType">
++                                        <enum>Expanding</enum>
++                                    </property>
++                                    <property name="sizeHint">
++                                        <size>
++                                            <width>20</width>
++                                            <height>90</height>
++                                        </size>
++                                    </property>
++                                </spacer>
++                            </vbox>
++                        </widget>
++                    </grid>
++                </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout14</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>txtInvMsg</cstring>
++                            </property>
++                            <property name="text">
++                                <string>Invitation Message</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer4</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Fixed</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>20</width>
++                                    <height>21</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QLineEdit">
++                            <property name="name">
++                                <cstring>editMessage</cstring>
++                            </property>
++                        </widget>
++                    </hbox>
++                </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout18</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <widget class="QPushButton">
++                            <property name="name">
++                                <cstring>btnCancel</cstring>
++                            </property>
++                            <property name="sizePolicy">
++                                <sizepolicy>
++                                    <hsizetype>5</hsizetype>
++                                    <vsizetype>0</vsizetype>
++                                    <horstretch>0</horstretch>
++                                    <verstretch>0</verstretch>
++                                </sizepolicy>
++                            </property>
++                            <property name="text">
++                                <string>Cancel</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer5</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Maximum</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>350</width>
++                                    <height>31</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QPushButton">
++                            <property name="name">
++                                <cstring>btnInvite</cstring>
++                            </property>
++                            <property name="sizePolicy">
++                                <sizepolicy>
++                                    <hsizetype>0</hsizetype>
++                                    <vsizetype>0</vsizetype>
++                                    <horstretch>0</horstretch>
++                                    <verstretch>0</verstretch>
++                                </sizepolicy>
++                            </property>
++                            <property name="text">
++                                <string>Invite</string>
++                            </property>
++                        </widget>
++                    </hbox>
++                </widget>
++            </vbox>
++        </widget>
++    </grid>
++</widget>
++<connections>
++    <connection>
++        <sender>btnCancel</sender>
++        <signal>clicked()</signal>
++        <receiver>YahooInviteListBase</receiver>
++        <slot>btnCancel_clicked()</slot>
++    </connection>
++    <connection>
++        <sender>btnCustomAdd</sender>
++        <signal>clicked()</signal>
++        <receiver>YahooInviteListBase</receiver>
++        <slot>btnAddCustom_clicked()</slot>
++    </connection>
++    <connection>
++        <sender>btnInvite</sender>
++        <signal>clicked()</signal>
++        <receiver>YahooInviteListBase</receiver>
++        <slot>btnInvite_clicked()</slot>
++    </connection>
++    <connection>
++        <sender>btn_Add</sender>
++        <signal>clicked()</signal>
++        <receiver>YahooInviteListBase</receiver>
++        <slot>btnAdd_clicked()</slot>
++    </connection>
++    <connection>
++        <sender>btn_Remove</sender>
++        <signal>clicked()</signal>
++        <receiver>YahooInviteListBase</receiver>
++        <slot>btnRemove_clicked()</slot>
++    </connection>
++</connections>
++<slots>
++    <slot>btnAdd_clicked()</slot>
++    <slot>btnRemove_clicked()</slot>
++    <slot>btnAddCustom_clicked()</slot>
++    <slot>btnCancel_clicked()</slot>
++    <slot>btnInvite_clicked()</slot>
++</slots>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/yahoo/ui/yahooinvitelistimpl.h	(revision 0)
++++ kopete/protocols/yahoo/ui/yahooinvitelistimpl.h	(revision 586398)
+@@ -0,0 +1,59 @@
++/*
++    YahooInviteListImpl - conference invitation dialog
++    
++    Copyright (c) 2004 by Duncan Mac-Vicar P.    <duncan at kde.org>
++    
++    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel at 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 YAHOO_INVITE_LIST_IMPL
++#define YAHOO_INVITE_LIST_IMPL
++
++#include <qwidget.h>
++
++#include "yahooinvitelistbase.h"
++
++class YahooInviteListImpl : public YahooInviteListBase
++{
++	Q_OBJECT
++public: 
++	YahooInviteListImpl(QWidget *parent=0, const char *name=0);
++	~YahooInviteListImpl();
++	
++	void fillFriendList( const QStringList &buddies );
++	void addInvitees( const QStringList &buddies );
++	void removeInvitees( const QStringList &buddies );
++	void setRoom( const QString &room );
++	void addParticipant( const QString &participant );
++private:
++	
++signals:
++	void readyToInvite( const QString &room, const QStringList &buddies, const QStringList &participants, const QString &msg );
++protected slots:
++
++public slots:
++    virtual void btnInvite_clicked();
++    virtual void btnCancel_clicked();
++    virtual void btnAddCustom_clicked();
++    virtual void btnRemove_clicked();
++    virtual void btnAdd_clicked();
++private:
++	void updateListBoxes();
++
++	QStringList m_buddyList;
++	QStringList m_inviteeList;
++	QStringList m_participants;
++	QString m_room;
++};
++
++#endif
++
+--- kopete/protocols/yahoo/ui/yahoowebcamdialog.h	(revision 568672)
++++ kopete/protocols/yahoo/ui/yahoowebcamdialog.h	(revision 586398)
+@@ -17,7 +17,7 @@
+ #ifndef YAHOOWEBCAMDIALOG_H_
+ #define YAHOOWEBCAMDIALOG_H_
+ 
+-#include <qlabel.h>
++#include <qstring.h>
+ #include <kdialogbase.h>
+ 
+ 
+@@ -25,22 +25,29 @@
+ class QWidget;
+ class YahooContact;
+ 
++namespace Kopete
++{
++	class WebcamWidget;
++}
++
+ class YahooWebcamDialog : public KDialogBase
+ {
+ Q_OBJECT
+ public:
+-	YahooWebcamDialog( YahooContact*, QWidget* parent = 0, const char* name = 0 );
++	YahooWebcamDialog( const QString &, QWidget* parent = 0, const char* name = 0 );
+ 	~YahooWebcamDialog();
+ 	
++	void setViewer( const QStringList & );
+ public slots:
+-	void newImage( const QPixmap& image );
++	void newImage( const QPixmap &image );
+ 	void webcamClosed( int );
+-
++	void webcamPaused();
+ signals:
+ 	void closingWebcamDialog();
+ 	
+ private:
+-	QLabel m_imageContainer;
++	Kopete::WebcamWidget *m_imageContainer;
++	QLabel *m_Viewer;
+ 	QString contactName;
+ 	
+ };
+--- kopete/protocols/yahoo/ui/yahoogeneralinfowidget.ui	(revision 0)
++++ kopete/protocols/yahoo/ui/yahoogeneralinfowidget.ui	(revision 586398)
+@@ -0,0 +1,647 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>YahooGeneralInfoWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>YahooGeneralInfoWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>596</width>
++            <height>506</height>
++        </rect>
++    </property>
++    <grid>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QGroupBox" row="0" column="0">
++            <property name="name">
++                <cstring>groupBox4</cstring>
++            </property>
++            <property name="title">
++                <string>Personal Information</string>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>fullNameLabel_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>First name:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>fullNameEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>fullNameLabel_2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Second name:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>fullNameEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>LastNameLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Last name:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>fullNameEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="1">
++                    <property name="name">
++                        <cstring>lastNameEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="1">
++                    <property name="name">
++                        <cstring>nickNameEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>2</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="0">
++                    <property name="name">
++                        <cstring>nickNameLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Nickname:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>nickNameEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="1">
++                    <property name="name">
++                        <cstring>firstNameEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="1">
++                    <property name="name">
++                        <cstring>secondNameEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="0" column="2">
++                    <property name="name">
++                        <cstring>yahooIdLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Yahoo ID:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>uinEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="2">
++                    <property name="name">
++                        <cstring>yahooIdLabel_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Title:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>uinEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="2">
++                    <property name="name">
++                        <cstring>birthdayLabel_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Anniversary:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>birthday</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="3">
++                    <property name="name">
++                        <cstring>yahooIdEdit</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>false</bool>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>5</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>1</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="3">
++                    <property name="name">
++                        <cstring>titleEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>5</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="3">
++                    <property name="name">
++                        <cstring>birthdayEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="3">
++                    <property name="name">
++                        <cstring>anniversaryEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="2">
++                    <property name="name">
++                        <cstring>birthdayLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Birthday:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>birthday</cstring>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <spacer row="3" column="0">
++            <property name="name">
++                <cstring>spacer4</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>21</width>
++                    <height>30</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QGroupBox" row="2" column="0">
++            <property name="name">
++                <cstring>groupBox5</cstring>
++            </property>
++            <property name="title">
++                <string>Contact Information</string>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="1" column="2">
++                    <property name="name">
++                        <cstring>textLabel6_2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Pager:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>cellEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="6" column="0">
++                    <property name="name">
++                        <cstring>textLabel10_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Homepage:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>homepageEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="5" column="1" rowspan="1" colspan="3">
++                    <property name="name">
++                        <cstring>emailEdit_3</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>3</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="0">
++                    <property name="name">
++                        <cstring>textLabel9</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Email:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>emailEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="5" column="0">
++                    <property name="name">
++                        <cstring>textLabel9_3</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Email &amp;3:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>emailEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="4" column="0">
++                    <property name="name">
++                        <cstring>textLabel9_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Email &amp;2:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>emailEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="4" column="1" rowspan="1" colspan="3">
++                    <property name="name">
++                        <cstring>emailEdit_2</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>3</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="6" column="1" rowspan="1" colspan="3">
++                    <property name="name">
++                        <cstring>homepageEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>3</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="1" rowspan="1" colspan="3">
++                    <property name="name">
++                        <cstring>emailEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>3</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="1">
++                    <property name="name">
++                        <cstring>faxEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>textLabel7_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Fa&amp;x:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>faxEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>textLabel6_2_2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Additional:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>cellEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="3">
++                    <property name="name">
++                        <cstring>pagerEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="1">
++                    <property name="name">
++                        <cstring>additionalEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>textLabel5</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Phone:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>phoneEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="3">
++                    <property name="name">
++                        <cstring>cellEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="0" column="2">
++                    <property name="name">
++                        <cstring>textLabel6_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Ce&amp;ll:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>cellEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="1">
++                    <property name="name">
++                        <cstring>phoneEdit</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <widget class="QGroupBox" row="1" column="0">
++            <property name="name">
++                <cstring>groupBox2</cstring>
++            </property>
++            <property name="title">
++                <string>Location Information</string>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Address:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>addressEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="2">
++                    <property name="name">
++                        <cstring>textLabel8</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Countr&amp;y:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>countryEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QTextEdit" row="0" column="1" rowspan="2" colspan="3">
++                    <property name="name">
++                        <cstring>addressEdit</cstring>
++                    </property>
++                </widget>
++                <spacer row="1" column="0">
++                    <property name="name">
++                        <cstring>spacer7</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Vertical</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>20</width>
++                            <height>78</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="QLabel" row="3" column="0">
++                    <property name="name">
++                        <cstring>textLabel4</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;State:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>stateEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="1">
++                    <property name="name">
++                        <cstring>stateEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>1</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="2">
++                    <property name="name">
++                        <cstring>textLabel2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;City:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>cityEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="3">
++                    <property name="name">
++                        <cstring>cityEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>1</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="3">
++                    <property name="name">
++                        <cstring>countryEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>textLabel3</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Zip:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>zipEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="1">
++                    <property name="name">
++                        <cstring>zipEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++    </grid>
++</widget>
++<tabstops>
++    <tabstop>firstNameEdit</tabstop>
++    <tabstop>secondNameEdit</tabstop>
++    <tabstop>lastNameEdit</tabstop>
++    <tabstop>nickNameEdit</tabstop>
++    <tabstop>titleEdit</tabstop>
++    <tabstop>birthdayEdit</tabstop>
++    <tabstop>anniversaryEdit</tabstop>
++    <tabstop>addressEdit</tabstop>
++    <tabstop>zipEdit</tabstop>
++    <tabstop>cityEdit</tabstop>
++    <tabstop>stateEdit</tabstop>
++    <tabstop>countryEdit</tabstop>
++    <tabstop>phoneEdit</tabstop>
++    <tabstop>faxEdit</tabstop>
++    <tabstop>additionalEdit</tabstop>
++    <tabstop>cellEdit</tabstop>
++    <tabstop>pagerEdit</tabstop>
++    <tabstop>emailEdit</tabstop>
++    <tabstop>emailEdit_2</tabstop>
++    <tabstop>emailEdit_3</tabstop>
++    <tabstop>homepageEdit</tabstop>
++    <tabstop>yahooIdEdit</tabstop>
++</tabstops>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/yahoo/ui/yahooeditaccountbase.ui	(revision 568672)
++++ kopete/protocols/yahoo/ui/yahooeditaccountbase.ui	(revision 586398)
+@@ -70,7 +70,7 @@
+                                             <cstring>label1</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>Yahoo &amp;username:</string>
++                                            <string>&amp;Yahoo username:</string>
+                                         </property>
+                                         <property name="buddy" stdset="0">
+                                             <cstring>mScreenName</cstring>
+@@ -106,6 +106,14 @@
+                                     <string>Check to disable automatic connection.  If checked, you may connect to this account manually using the icon in the bottom of the main Kopete window</string>
+                                 </property>
+                             </widget>
++                            <widget class="QCheckBox">
++                                <property name="name">
++                                    <cstring>mGlobalIdentity</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Exclude from &amp;Global Identity</string>
++                                </property>
++                            </widget>
+                         </vbox>
+                     </widget>
+                     <widget class="QGroupBox">
+@@ -195,7 +203,7 @@
+                     <cstring>TabPage</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>&amp;Account Preferences</string>
++                    <string>Accoun&amp;t Preferences</string>
+                 </attribute>
+                 <grid>
+                     <property name="name">
+--- kopete/protocols/yahoo/ui/Makefile.am	(revision 568672)
++++ kopete/protocols/yahoo/ui/Makefile.am	(revision 586398)
+@@ -6,7 +6,9 @@
+ 		$(all_includes)
+ 
+ 
+-libkopeteyahooui_la_SOURCES = yahooadd.ui yahooeditaccountbase.ui empty.cpp \
+-		yahoowebcamdialog.cpp yahoouserinfobase.ui yahoostealthsetting.ui
++libkopeteyahooui_la_SOURCES = yahooadd.ui yahooeditaccountbase.ui \
++	yahooinvitelistbase.ui yahooinvitelistimpl.cpp empty.cpp yahooverifyaccountbase.ui \
++	yahoostealthsetting.ui yahoowebcamdialog.cpp yahoogeneralinfowidget.ui yahoouserinfodialog.cpp \
++	yahooworkinfowidget.ui yahoootherinfowidget.ui
+ EXTRA_DIST = dlgrename.ui
+-noinst_HEADERS = yahoowebcamdialog.h
++noinst_HEADERS = yahoouserinfodialog.h
+--- kopete/protocols/yahoo/ui/yahoootherinfowidget.ui	(revision 0)
++++ kopete/protocols/yahoo/ui/yahoootherinfowidget.ui	(revision 586398)
+@@ -0,0 +1,119 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>YahooOtherInfoWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>YahooOtherInfoWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>289</width>
++            <height>439</height>
++        </rect>
++    </property>
++    <grid>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
++            <property name="name">
++                <cstring>textLabel13</cstring>
++            </property>
++            <property name="text">
++                <string>Contact comments:</string>
++            </property>
++        </widget>
++        <widget class="QTextEdit" row="1" column="0" rowspan="1" colspan="2">
++            <property name="name">
++                <cstring>commentsEdit</cstring>
++            </property>
++            <property name="readOnly">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLabel" row="2" column="0">
++            <property name="name">
++                <cstring>textLabel2</cstring>
++            </property>
++            <property name="text">
++                <string>Note 1:</string>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="2" column="1">
++            <property name="name">
++                <cstring>note1Edit</cstring>
++            </property>
++            <property name="readOnly">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLabel" row="3" column="0">
++            <property name="name">
++                <cstring>textLabel3</cstring>
++            </property>
++            <property name="text">
++                <string>Note 2:</string>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="3" column="1">
++            <property name="name">
++                <cstring>note2Edit</cstring>
++            </property>
++            <property name="readOnly">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="4" column="1">
++            <property name="name">
++                <cstring>note3Edit</cstring>
++            </property>
++            <property name="readOnly">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLabel" row="4" column="0">
++            <property name="name">
++                <cstring>textLabel4</cstring>
++            </property>
++            <property name="text">
++                <string>Note 3:</string>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="5" column="1">
++            <property name="name">
++                <cstring>note4Edit</cstring>
++            </property>
++            <property name="readOnly">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLabel" row="5" column="0">
++            <property name="name">
++                <cstring>textLabel5</cstring>
++            </property>
++            <property name="text">
++                <string>Note 4:</string>
++            </property>
++        </widget>
++        <spacer row="7" column="1">
++            <property name="name">
++                <cstring>spacer8</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>20</width>
++                    <height>130</height>
++                </size>
++            </property>
++        </spacer>
++    </grid>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/yahoo/ui/yahooworkinfowidget.ui	(revision 0)
++++ kopete/protocols/yahoo/ui/yahooworkinfowidget.ui	(revision 586398)
+@@ -0,0 +1,233 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>YahooWorkInfoWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>YahooWorkInfoWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>328</width>
++            <height>681</height>
++        </rect>
++    </property>
++    <grid>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QGroupBox" row="0" column="0">
++            <property name="name">
++                <cstring>groupBox2</cstring>
++            </property>
++            <property name="title">
++                <string>Personal Work Information</string>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>textLabel10</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Phone:</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="1">
++                    <property name="name">
++                        <cstring>phoneEdit</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>0</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <widget class="QButtonGroup" row="1" column="0">
++            <property name="name">
++                <cstring>buttonGroup1</cstring>
++            </property>
++            <property name="title">
++                <string>Company Location Information</string>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Name:</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>textLabel8</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Homepage:</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="1">
++                    <property name="name">
++                        <cstring>companyEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="1">
++                    <property name="name">
++                        <cstring>homepageEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="7" column="0">
++                    <property name="name">
++                        <cstring>textLabel9</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>5</hsizetype>
++                            <vsizetype>5</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="text">
++                        <string>Country:</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="7" column="1">
++                    <property name="name">
++                        <cstring>countryEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QTextEdit" row="2" column="1" rowspan="2" colspan="1">
++                    <property name="name">
++                        <cstring>addressEdit</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>textLabel2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Address:</string>
++                    </property>
++                </widget>
++                <spacer row="3" column="0">
++                    <property name="name">
++                        <cstring>spacer9</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Vertical</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>20</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="QLineEdit" row="5" column="1">
++                    <property name="name">
++                        <cstring>cityEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="6" column="1">
++                    <property name="name">
++                        <cstring>stateEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="6" column="0">
++                    <property name="name">
++                        <cstring>textLabel5</cstring>
++                    </property>
++                    <property name="text">
++                        <string>State:</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="5" column="0">
++                    <property name="name">
++                        <cstring>textLabel3</cstring>
++                    </property>
++                    <property name="text">
++                        <string>City:</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="4" column="0">
++                    <property name="name">
++                        <cstring>textLabel4</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Zip:</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="4" column="1">
++                    <property name="name">
++                        <cstring>zipEdit</cstring>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <spacer row="2" column="0">
++            <property name="name">
++                <cstring>spacer2</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>20</width>
++                    <height>150</height>
++                </size>
++            </property>
++        </spacer>
++    </grid>
++</widget>
++<tabstops>
++    <tabstop>phoneEdit</tabstop>
++    <tabstop>companyEdit</tabstop>
++    <tabstop>homepageEdit</tabstop>
++    <tabstop>addressEdit</tabstop>
++    <tabstop>zipEdit</tabstop>
++    <tabstop>cityEdit</tabstop>
++    <tabstop>stateEdit</tabstop>
++    <tabstop>countryEdit</tabstop>
++</tabstops>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/yahoo/ui/yahoostealthsetting.ui	(revision 568672)
++++ kopete/protocols/yahoo/ui/yahoostealthsetting.ui	(revision 586398)
+@@ -9,7 +9,7 @@
+             <x>0</x>
+             <y>0</y>
+             <width>195</width>
+-            <height>77</height>
++            <height>114</height>
+         </rect>
+     </property>
+     <property name="minimumSize">
+@@ -18,43 +18,76 @@
+             <height>75</height>
+         </size>
+     </property>
+-    <vbox>
++    <grid>
+         <property name="name">
+             <cstring>unnamed</cstring>
+         </property>
+-        <widget class="QButtonGroup">
++        <widget class="QButtonGroup" row="0" column="0">
+             <property name="name">
+                 <cstring>buttonGroup1</cstring>
+             </property>
+             <property name="title">
+                 <string>Show Me As</string>
+             </property>
+-            <vbox>
++            <widget class="QRadioButton">
+                 <property name="name">
+-                    <cstring>unnamed</cstring>
++                    <cstring>radioPermOffline</cstring>
+                 </property>
+-                <widget class="QRadioButton">
+-                    <property name="name">
+-                        <cstring>radioOnline</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Online</string>
+-                    </property>
+-                    <property name="checked">
+-                        <bool>true</bool>
+-                    </property>
+-                </widget>
+-                <widget class="QRadioButton">
+-                    <property name="name">
+-                        <cstring>radioOffline</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Per&amp;manently offline</string>
+-                    </property>
+-                </widget>
+-            </vbox>
++                <property name="geometry">
++                    <rect>
++                        <x>10</x>
++                        <y>60</y>
++                        <width>151</width>
++                        <height>17</height>
++                    </rect>
++                </property>
++                <property name="text">
++                    <string>Perma&amp;nently offline</string>
++                </property>
++            </widget>
++            <widget class="QRadioButton">
++                <property name="name">
++                    <cstring>radioOnline</cstring>
++                </property>
++                <property name="geometry">
++                    <rect>
++                        <x>10</x>
++                        <y>20</y>
++                        <width>151</width>
++                        <height>17</height>
++                    </rect>
++                </property>
++                <property name="text">
++                    <string>&amp;Online</string>
++                </property>
++                <property name="checked">
++                    <bool>true</bool>
++                </property>
++            </widget>
++            <widget class="QRadioButton">
++                <property name="name">
++                    <cstring>radioOffline</cstring>
++                </property>
++                <property name="enabled">
++                    <bool>false</bool>
++                </property>
++                <property name="geometry">
++                    <rect>
++                        <x>10</x>
++                        <y>40</y>
++                        <width>151</width>
++                        <height>17</height>
++                    </rect>
++                </property>
++                <property name="text">
++                    <string>Off&amp;line</string>
++                </property>
++                <property name="checked">
++                    <bool>false</bool>
++                </property>
++            </widget>
+         </widget>
+-    </vbox>
++    </grid>
+ </widget>
+ <tabstops>
+     <tabstop>radioOnline</tabstop>
+--- kopete/protocols/gadu/libgadu/events.c	(revision 568672)
++++ kopete/protocols/gadu/libgadu/events.c	(revision 586398)
+@@ -1,9 +1,10 @@
+ /* $Id$ */
+ 
+ /*
+- *  (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka at irc.pl>
++ *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka at irc.pl>
+  *                          Robert J. Wo¼ny <speedy at ziew.org>
+  *                          Arkadiusz Mi¶kiewicz <arekm at pld-linux.org>
++ *                          Adam Wysocki <gophi at ekg.chmurka.net>
+  *
+  *  This program is free software; you can redistribute it and/or modify
+  *  it under the terms of the GNU Lesser General Public License Version
+@@ -1092,6 +1093,12 @@
+ 				port = atoi(tmp + 1);
+ 			}
+ 
++			if (!strcmp(host, "notoperating")) {
++				gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno));
++				sess->fd = -1;
++				goto fail_unavailable;
++			}
++
+ 			addr.s_addr = inet_addr(host);
+ 			sess->server_addr = addr.s_addr;
+ 
+@@ -1204,6 +1211,8 @@
+ 				 * write() zawiedzie, sta³o siê co¶ z³ego. */
+ 				if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
+ 					gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
++					if (auth)
++						free(auth);
+ 					goto fail_connecting;
+ 				}
+ 
+@@ -1211,6 +1220,7 @@
+ 					gg_debug(GG_DEBUG_MISC, "//   %s", auth);
+ 					if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) {
+ 						gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
++						free(auth);
+ 						goto fail_connecting;
+ 					}
+ 
+@@ -1485,6 +1495,10 @@
+ 				gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login failed\n");
+ 				e->event.failure = GG_FAILURE_PASSWORD;
+ 				errno = EACCES;
++			} else if (h->type == GG_DISCONNECTING) {
++				gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n");
++				e->event.failure = GG_FAILURE_INTRUDER;
++				errno = EACCES;
+ 			} else {
+ 				gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n");
+ 				e->event.failure = GG_FAILURE_INVALID;
+@@ -1547,6 +1561,12 @@
+ 	e->event.failure = GG_FAILURE_RESOLVING;
+ 	sess->state = GG_STATE_IDLE;
+ 	goto done;
++
++fail_unavailable:
++	e->type = GG_EVENT_CONN_FAILED;
++	e->event.failure = GG_FAILURE_UNAVAILABLE;
++	sess->state = GG_STATE_IDLE;
++	goto done;
+ }
+ 
+ /*
+--- kopete/protocols/gadu/libgadu/pubdir.c	(revision 568672)
++++ kopete/protocols/gadu/libgadu/pubdir.c	(revision 586398)
+@@ -1,8 +1,9 @@
+ /* $Id$ */
+ 
+ /*
+- *  (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka at irc.pl>
++ *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka at irc.pl>
+  *                          Dawid Jarosz <dawjar at poczta.onet.pl>
++ *                          Adam Wysocki <gophi at ekg.chmurka.net>
+  *
+  *  This program is free software; you can redistribute it and/or modify
+  *  it under the terms of the GNU Lesser General Public License Version
+@@ -447,8 +448,12 @@
+ 	
+ 	gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
+ 
+-	if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
++	if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) {
+ 		p->success = 1;
++		p->uin = strtol(tmp + sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL, 0);
++		gg_debug(GG_DEBUG_MISC, "=> pubdir, success (okregisterreply, uin=%d)\n", p->uin);
++	} else if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
++		p->success = 1;
+ 		if (tmp[7] == ':')
+ 			p->uin = strtol(tmp + 8, NULL, 0);
+ 		gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin);
+--- kopete/protocols/gadu/libgadu/libgadu.c	(revision 568672)
++++ kopete/protocols/gadu/libgadu/libgadu.c	(revision 586398)
+@@ -1,10 +1,11 @@
+ /* $Id$ */
+ 
+ /*
+- *  (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka at irc.pl>
++ *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka at irc.pl>
+  *                          Robert J. Wo¼ny <speedy at ziew.org>
+  *                          Arkadiusz Mi¶kiewicz <arekm at pld-linux.org>
+  *                          Tomasz Chiliñski <chilek at chilan.com>
++ *                          Adam Wysocki <gophi at ekg.chmurka.net>
+  *
+  *  This program is free software; you can redistribute it and/or modify
+  *  it under the terms of the GNU Lesser General Public License Version
+@@ -41,6 +42,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <signal.h>
+ #include <unistd.h>
+ #ifdef __GG_LIBGADU_HAVE_OPENSSL
+ #  include <openssl/err.h>
+@@ -208,6 +210,8 @@
+ 	}
+ 
+ 	if (!res) {
++		close(pipes[0]);
++
+ 		if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
+ 			struct in_addr *hn;
+ 		
+@@ -951,8 +955,10 @@
+ 		sess->resolver = NULL;
+ 	}
+ #else
+-	if (sess->pid != -1)
++	if (sess->pid != -1) {
++		kill(sess->pid, SIGTERM);
+ 		waitpid(sess->pid, NULL, WNOHANG);
++	}
+ #endif
+ 
+ 	if (sess->fd != -1)
+@@ -1099,6 +1105,7 @@
+ 	}
+ #else
+ 	if (sess->pid != -1) {
++		kill(sess->pid, SIGTERM);
+ 		waitpid(sess->pid, NULL, WNOHANG);
+ 		sess->pid = -1;
+ 	}
+--- kopete/protocols/gadu/libgadu/Makefile.am	(revision 568672)
++++ kopete/protocols/gadu/libgadu/Makefile.am	(revision 586398)
+@@ -1,7 +1,7 @@
+ METASOURCES = AUTO
+ noinst_LTLIBRARIES = libgadu_copy.la
+-INCLUDES = $(SSL_INCLUDES) 
+-libgadu_copy_la_LDFLAGS = $(SSL_LDFLAGS)
++INCLUDES = $(SSL_INCLUDES) $(all_includes)
++libgadu_copy_la_LDFLAGS = $(SSL_LDFLAGS) $(all_libraries)
+ libgadu_copy_la_LIBADD =  $(LIBSSL) $(LIBPTHREAD) 
+ libgadu_copy_la_SOURCES = common.c \
+ 			  dcc.c \
+--- kopete/protocols/gadu/libgadu/dcc.c	(revision 568672)
++++ kopete/protocols/gadu/libgadu/dcc.c	(revision 586398)
+@@ -1,8 +1,9 @@
+ /* $Id$ */
+ 
+ /*
+- *  (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka at irc.pl>
++ *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka at irc.pl>
+  *                          Tomasz Chiliñski <chilek at chilan.com>
++ *                          Adam Wysocki <gophi at ekg.chmurka.net>
+  *
+  *  This program is free software; you can redistribute it and/or modify
+  *  it under the terms of the GNU Lesser General Public License Version
+@@ -92,7 +93,7 @@
+  *  - unix - czas w postaci unixowej
+  *  - filetime - czas w postaci windowsowej
+  */
+-void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft)
++static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft)
+ {
+ #ifdef __GG_LIBGADU_HAVE_LONG_LONG
+ 	unsigned long long tmp;
+@@ -874,6 +875,7 @@
+ 
+ 				if (!(h->voice_buf = malloc(h->chunk_size))) {
+ 					gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n");
++					free(e);
+ 					return NULL;
+ 				}
+ 
+--- kopete/protocols/gadu/libgadu/pubdir50.c	(revision 568672)
++++ kopete/protocols/gadu/libgadu/pubdir50.c	(revision 586398)
+@@ -62,7 +62,7 @@
+  *
+  * 0/-1
+  */
+-int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value)
++static int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value)
+ {
+ 	struct gg_pubdir50_entry *tmp = NULL, *entry;
+ 	char *dupfield, *dupvalue;
+--- kopete/protocols/gadu/libgadu/libgadu.h	(revision 568672)
++++ kopete/protocols/gadu/libgadu/libgadu.h	(revision 586398)
+@@ -437,7 +437,9 @@
+ 	GG_FAILURE_PASSWORD,		/* nieprawid³owe has³o */
+ 	GG_FAILURE_404, 		/* XXX nieu¿ywane */
+ 	GG_FAILURE_TLS,			/* b³±d negocjacji TLS */
+-	GG_FAILURE_NEED_EMAIL 		/* serwer roz³±czy³ nas z pro¶b± o zmianê emaila */
++	GG_FAILURE_NEED_EMAIL, 		/* serwer roz³±czy³ nas z pro¶b± o zmianê emaila */
++	GG_FAILURE_INTRUDER,		/* za du¿o prób po³±czenia siê z nieprawid³owym has³em */
++	GG_FAILURE_UNAVAILABLE		/* serwery s± wy³±czone */
+ };
+ 
+ /*
+--- kopete/protocols/gadu/gadudcctransaction.cpp	(revision 568672)
++++ kopete/protocols/gadu/gadudcctransaction.cpp	(revision 586398)
+@@ -118,6 +118,7 @@
+ 
+ 	if ( !peerContact ) {
+ 		kdDebug( 14100 ) << "setupIncoming called with peerContact == NULL " << endl;
++		return false;
+ 	}
+ 
+ 	QString aaa =  peerContact->contactIp().toString();
+--- kopete/protocols/gadu/gaduaccount.h	(revision 568672)
++++ kopete/protocols/gadu/gaduaccount.h	(revision 586398)
+@@ -113,6 +113,14 @@
+ 	bool dccEnabled();
+ 	bool setDcc( bool );
+ 
++	// anons
++	bool ignoreAnons();
++	void setIgnoreAnons( bool );
++
++	// forFriends
++	bool loadFriendsMode();
++	void saveFriendsMode( bool );
++
+ signals:
+ 	void pubDirSearchResult( const SearchResult&, unsigned int );
+ 
+--- kopete/protocols/gadu/gadueditaccount.cpp	(revision 568672)
++++ kopete/protocols/gadu/gadueditaccount.cpp	(revision 586398)
+@@ -80,6 +80,7 @@
+ 		autoLoginCheck_->setChecked( account_->excludeConnect() );
+ 		dccCheck_->setChecked( account_->dccEnabled() );
+ 		useTls_->setCurrentItem( isSsl ? ( account_->useTls() ) : 2 );
++		ignoreCheck_->setChecked( account_->ignoreAnons() );
+ 
+ 		connect( account(), SIGNAL( pubDirSearchResult( const SearchResult&, unsigned int ) ),
+ 					SLOT( slotSearchResult( const SearchResult&, unsigned int ) ) );
+@@ -249,7 +250,8 @@
+ 
+ 	account_->setExcludeConnect( autoLoginCheck_->isChecked() );
+ 	account_->setUseTls( (GaduAccount::tlsConnection) useTls_->currentItem() );
+-
++	account_->setIgnoreAnons( ignoreCheck_->isChecked() );
++	
+ 	if ( account_->setDcc( dccCheck_->isChecked() ) == false ) {
+ 		KMessageBox::sorry( this, i18n( "<b>Starting DCC listening socket failed; dcc is not working now.</b>" ), i18n( "Gadu-Gadu" ) );
+ 	}
+--- kopete/protocols/gadu/gaducontact.cpp	(revision 568672)
++++ kopete/protocols/gadu/gaducontact.cpp	(revision 586398)
+@@ -53,6 +53,9 @@
+ 	remote_port	= 0;
+ 	version		= 0;
+ 	image_size	= 0;
++	// let us not ignore the contact by default right? causes ugly bug if 
++	// setContactDetails is not run on a contact right after it is added
++	ignored_	= false;
+ 
+ 	thisContact_.append( this );
+ 
+--- kopete/protocols/gadu/ui/gaduawayui.ui	(revision 568672)
++++ kopete/protocols/gadu/ui/gaduawayui.ui	(revision 586398)
+@@ -111,7 +111,7 @@
+                                         <string>Set status to invisible, which will hide your presence from other users.</string>
+                                     </property>
+                                     <property name="whatsThis" stdset="0">
+-                                        <string>Set status to invisible, which will hide your presence from other users (who will see you as offline).  However you may still chat, and see the online presence others.</string>
++                                        <string>Set status to invisible, which will hide your presence from other users (who will see you as offline).  However you may still chat, and see the online presence of others.</string>
+                                     </property>
+                                 </widget>
+                                 <widget class="QRadioButton">
+--- kopete/protocols/gadu/ui/gadueditaccountui.ui	(revision 568672)
++++ kopete/protocols/gadu/ui/gadueditaccountui.ui	(revision 586398)
+@@ -8,7 +8,7 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>545</width>
++            <width>580</width>
+             <height>390</height>
+         </rect>
+     </property>
+@@ -217,12 +217,29 @@
+                 <attribute name="title">
+                     <string>A&amp;ccount Preferences</string>
+                 </attribute>
+-                <vbox>
++                <grid>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QGroupBox">
++                    <spacer row="1" column="0">
+                         <property name="name">
++                            <cstring>spacer16</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Expanding</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>20</width>
++                                <height>160</height>
++                            </size>
++                        </property>
++                    </spacer>
++                    <widget class="QGroupBox" row="0" column="0">
++                        <property name="name">
+                             <cstring>groupBox64</cstring>
+                         </property>
+                         <property name="title">
+@@ -234,26 +251,6 @@
+                             </property>
+                             <widget class="QCheckBox" row="1" column="0">
+                                 <property name="name">
+-                                    <cstring>cacheServersCheck__</cstring>
+-                                </property>
+-                                <property name="enabled">
+-                                    <bool>false</bool>
+-                                </property>
+-                                <property name="text">
+-                                    <string>C&amp;ache server information</string>
+-                                </property>
+-                                <property name="checked">
+-                                    <bool>true</bool>
+-                                </property>
+-                                <property name="toolTip" stdset="0">
+-                                    <string>Cache connection information for each server connected to in case the main load-balancing server fails.</string>
+-                                </property>
+-                                <property name="whatsThis" stdset="0">
+-                                    <string>This option is used whenever the primary Gadu-Gadu load-balancing server fails.  If this is checked, Kopete will try to connect to the actual servers directly using cached information about them.  This prevents connection errors when the main load-balancing server does not answer. In practice it only helps very rarely.</string>
+-                                </property>
+-                            </widget>
+-                            <widget class="QCheckBox" row="2" column="0">
+-                                <property name="name">
+                                     <cstring>dccCheck_</cstring>
+                                 </property>
+                                 <property name="enabled">
+@@ -325,26 +322,46 @@
+                                     </widget>
+                                 </hbox>
+                             </widget>
++                            <widget class="QCheckBox" row="0" column="0">
++                                <property name="name">
++                                    <cstring>cacheServersCheck__</cstring>
++                                </property>
++                                <property name="enabled">
++                                    <bool>false</bool>
++                                </property>
++                                <property name="text">
++                                    <string>C&amp;ache server information</string>
++                                </property>
++                                <property name="checked">
++                                    <bool>true</bool>
++                                </property>
++                                <property name="toolTip" stdset="0">
++                                    <string>Cache connection information for each server connected to in case the main load-balancing server fails.</string>
++                                </property>
++                                <property name="whatsThis" stdset="0">
++                                    <string>This option is used whenever the primary Gadu-Gadu load-balancing server fails.  If this is checked, Kopete will try to connect to the actual servers directly using cached information about them.  This prevents connection errors when the main load-balancing server does not answer. In practice it only helps very rarely.</string>
++                                </property>
++                            </widget>
++                            <widget class="QCheckBox" row="2" column="0">
++                                <property name="name">
++                                    <cstring>ignoreCheck_</cstring>
++                                </property>
++                                <property name="enabled">
++                                    <bool>true</bool>
++                                </property>
++                                <property name="text">
++                                    <string>Ignore people off your contact list</string>
++                                </property>
++                                <property name="accel">
++                                    <string></string>
++                                </property>
++                                <property name="checked">
++                                    <bool>false</bool>
++                                </property>
++                            </widget>
+                         </grid>
+                     </widget>
+-                    <spacer>
+-                        <property name="name">
+-                            <cstring>spacer16</cstring>
+-                        </property>
+-                        <property name="orientation">
+-                            <enum>Vertical</enum>
+-                        </property>
+-                        <property name="sizeType">
+-                            <enum>Expanding</enum>
+-                        </property>
+-                        <property name="sizeHint">
+-                            <size>
+-                                <width>20</width>
+-                                <height>160</height>
+-                            </size>
+-                        </property>
+-                    </spacer>
+-                </vbox>
++                </grid>
+             </widget>
+             <widget class="QWidget">
+                 <property name="name">
+--- kopete/protocols/gadu/gaduaccount.cpp	(revision 568672)
++++ kopete/protocols/gadu/gaduaccount.cpp	(revision 586398)
+@@ -83,6 +83,7 @@
+ 
+ 	QString		lastDescription;
+ 	bool		forFriends;
++	bool		ignoreAnons;
+         
+ 	QTimer*         exportTimer_;
+ 	bool		exportUserlist;
+@@ -98,15 +99,18 @@
+ 
+ // FIXME: use dynamic cache please, i consider this as broken resolution of this problem
+ static const char* const servers_ip[] = {
++	"217.17.41.82",
++	"217.17.41.83",
++	"217.17.41.84",
++	"217.17.41.85",
++	"217.17.41.86",
++	"217.17.41.87",
+ 	"217.17.41.88",
+ 	"217.17.41.92",
+ 	"217.17.41.93",
+- 	"217.17.41.85",
+-	"217.17.41.87",
+-	"217.17.41.86",
+-	"217.17.41.84",
+-	"217.17.41.83",
+-	"217.17.41.82"
++	"217.17.45.133",
++	"217.17.45.143",
++	"217.17.45.144"
+ };
+ 
+ #define NUM_SERVERS (sizeof(servers_ip)/sizeof(char*))
+@@ -145,7 +149,6 @@
+ 	p->loginInfo.useTls		= false;
+ 	p->loginInfo.status		= GG_STATUS_AVAIL;
+ 	p->loginInfo.server		= 0;
+-	p->loginInfo.forFriends		= false;
+ 	p->loginInfo.client_port	= 0;
+ 	p->loginInfo.client_addr	= 0;
+ 
+@@ -157,6 +160,9 @@
+ 
+ 	p->config = configGroup();
+ 
++	p->ignoreAnons = ignoreAnons();
++	p->forFriends = loadFriendsMode();
++
+ 	initConnections();
+ 	initActions();
+ 
+@@ -189,6 +195,8 @@
+ 	p->friendsModeAction	= new KToggleAction( i18n( "Only for Friends" ), "", 0,
+ 							this, SLOT( slotFriendsMode() ), this,
+ 							"actionFriendsMode" );
++
++	static_cast<KToggleAction*>(p->friendsModeAction)->setChecked( p->forFriends );
+ }
+ 
+ void
+@@ -586,7 +594,6 @@
+ 	QPtrList<Kopete::Contact> contactsListTmp;
+ 
+ 	// FIXME:check for ignored users list
+-	// FIXME:anonymous (those not on the list) users should be ignored, as an option
+ 
+ 	if ( gaduMessage->sender_id == 0 ) {
+ 		//system message, display them or not?
+@@ -597,6 +604,10 @@
+ 	contact = static_cast<GaduContact*> ( contacts()[ QString::number( gaduMessage->sender_id ) ] );
+ 
+ 	if ( !contact ) {
++		if ( p->ignoreAnons == true ) {
++			return;
++		}
++
+ 		Kopete::MetaContact* metaContact = new Kopete::MetaContact ();
+ 		metaContact->setTemporary ( true );
+ 		contact = new GaduContact( gaduMessage->sender_id,
+@@ -895,6 +906,8 @@
+ 	// now change status, it will changing it with p->forFriends flag
+ 	changeStatus( p->status, p->lastDescription );
+ 
++	saveFriendsMode( p->forFriends );
++
+ }
+ 
+ // FIXME: make loading and saving nonblocking (at the moment KFileDialog stops plugin/kopete)
+@@ -1109,7 +1122,7 @@
+ GaduAccount::dccEnabled()
+ {
+ 	QString s = p->config->readEntry( QString::fromAscii( "useDcc" ) );
+-	kdDebug( 14100 ) << "dccEnabled: "<<s<<endl;
++	kdDebug( 14100 ) << "dccEnabled: "<< s << endl;
+ 	if ( s == QString::fromAscii( "enabled" ) ) {
+ 		return true;
+ 	}
+@@ -1132,14 +1145,67 @@
+ 
+ 	p->config->writeEntry( QString::fromAscii( "useDcc" ), s );
+ 
+-	if ( p->session_->isConnected() & d ) {
++	if ( p->session_->isConnected() && d ) {
+ 		dccOn();
+ 	}
++
+ 	kdDebug( 14100 ) << "s: "<<s<<endl;
+ 
+ 	return f;
+ }
+ 
++void
++GaduAccount::saveFriendsMode( bool i )
++{
++	p->config->writeEntry( QString::fromAscii( "forFriends" ), 
++			i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
++}
++
++bool
++GaduAccount::loadFriendsMode()
++{
++	QString s;
++	bool r;
++	int n;
++
++	s = p->config->readEntry( QString::fromAscii( "forFriends" ) );
++	n = s.toInt( &r );
++
++	if ( n ) {
++		return true;
++	}
++
++	return false;
++
++}
++
++// might be bit inconsistent with what I used in DCC, but hell, it is so much easier to parse :-)
++bool
++GaduAccount::ignoreAnons()
++{
++	QString s;
++	bool r;
++	int n;
++	
++	s = p->config->readEntry( QString::fromAscii( "ignoreAnons" ) );
++	n = s.toInt( &r );
++	
++	if ( n ) {
++		return true;
++	}
++
++	return false;
++	
++}
++
++void 
++GaduAccount::setIgnoreAnons( bool i )
++{
++	p->ignoreAnons = i;
++	p->config->writeEntry( QString::fromAscii( "ignoreAnons" ), 
++			i == true ? QString::fromAscii( "1" ) : QString::fromAscii( "0" ) );
++}
++
+ GaduAccount::tlsConnection
+ GaduAccount::useTls()
+ {
+--- kopete/protocols/winpopup/wpdebug.h	(revision 568672)
++++ kopete/protocols/winpopup/wpdebug.h	(revision 586398)
+@@ -1,18 +0,0 @@
+-/***************************************************************************
+-     wpdebug.h  -  Debugging header file for WinPopup protocol
+-                             -------------------
+-    begin                : Fri Apr 26 2002
+-    copyright            : (C) 2002 by Bruno Rodrigues
+-    email                : bruno.rodrigues at litux.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.                                   *
+- *                                                                         *
+- ***************************************************************************/
+-
+-// Remove this file.
+\ No newline at end of file
+--- kopete/protocols/winpopup/winpopup-send.sh	(revision 568672)
++++ kopete/protocols/winpopup/winpopup-send.sh	(revision 586398)
+@@ -1,5 +1,5 @@
+ #!/bin/sh
+-PATH=/bin
++PATH=/bin:/usr/bin/:/usr/local/bin
+ 
+ # Check input
+ [ -z "$1" -o -z "$2" ] && exit 1
+@@ -7,29 +7,38 @@
+ # Check if file is indeed a file and readable
+ [ ! -f "$1" -o ! -r "$1" ] && exit 1
+ 
+-# Create a unique filename
+-filename="/var/lib/winpopup/`date +%s_%N`"
++KOPETE_RUNNING=x`ps -A|grep -e "kopete$"`
+ 
+-# Put the remote host name into the file
+-echo "$2" > $filename
++if [ "$KOPETE_RUNNING" = "x" ]; then
+ 
+-# And the time...
+-echo `date --iso-8601=seconds` >> $filename
++    if [ -z "$3" ]; then
++        THIS_SERVER=`uname -n`
++    else
++        THIS_SERVER="$3"
++    fi
+ 
+-# Finally the message
+-#cat "$1" | tr "\000" "\012" >> $filename
+-# This tr eats the messages? GF
+-cat "$1" >> $filename
++    if [ "$2" != "$THIS_SERVER" ]; then
++        echo -e "Kopete is currently not running.\nYour message was not delivered!" \
++            | smbclient -N -M $2
++    fi
+ 
+-# Make sure the file is owned by nobody and is readable
+-#chown nobody:nogroup $filename
+-# Just to be sure
+-#chmod 666 $filename
++else
+ 
+-# Move the new message file into the pickup place
+-# Doesn't this overwrite short before received messages? GF
+-#mv -f $filename /var/lib/winpopup/message
++    # Create a unique filename
++    filename="/var/lib/winpopup/`date +%s_%N`"
+ 
++    # the time...
++    TIME=`date --iso-8601=seconds`
++
++    # the message
++    MESSAGE=`cat "$1"`
++
++    # Put it into the file
++    echo -e "$2\n$TIME\n$MESSAGE" > $filename
++
++
++fi
++
+ # Remove the message from samba
+ rm -f "$1"
+ 
+--- kopete/protocols/winpopup/wpuserinfo.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpuserinfo.cpp	(revision 586398)
+@@ -110,4 +110,5 @@
+ 
+ #include "wpuserinfo.moc"
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpcontact.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpcontact.cpp	(revision 586398)
+@@ -31,7 +31,7 @@
+ 	: Kopete::Contact(account, newHostName, metaContact)
+ {
+ //	kdDebug(14170) << "WPContact::WPContact(<account>, " << newHostName << ", " << nickName << ", <parent>)" << endl;
+-	kdDebug(14170) << "I am " << this << "!" << endl;
++	kdDebug(14170) << "WPContact::WPContact: " << this << endl;
+ 
+ 	QString theNickName = nickName;
+ 
+@@ -44,15 +44,15 @@
+ 	setNickName(theNickName);
+ 	myWasConnected = false;
+ 
++
++	m_manager = 0;
++	m_infoDialog = 0;
++
+ 	// Initialise and start the periodical checking for contact's status
+ 	setOnlineStatus(static_cast<WPProtocol *>(protocol())->WPOffline);
+ 
+-	//TODO: makes checking more often than hostcheck cycle sense? GF
+ 	connect(&checkStatus, SIGNAL(timeout()), this, SLOT(slotCheckStatus()));
+ 	checkStatus.start(1000, false);
+-
+-	m_manager = 0;
+-	m_infoDialog = 0;
+ }
+ 
+ QPtrList<KAction> * WPContact::customContextMenuActions()
+@@ -141,16 +141,10 @@
+ 	if (acct) newIsOnline = acct->checkHost(contactId());
+ 
+ 	if(newIsOnline != isOnline() || myWasConnected != oldWasConnected) {
+-		Kopete::OnlineStatus tmpStatus;
+-		if (myWasConnected) {
+-			if (newIsOnline)
++		Kopete::OnlineStatus tmpStatus = WPProtocol::protocol()->WPOffline;
++		if (myWasConnected && newIsOnline) {
+ 				tmpStatus = WPProtocol::protocol()->WPOnline;
+-			else
+-				WPProtocol::protocol()->WPOffline;
+-		} else {
+-			WPProtocol::protocol()->WPOffline;
+ 		}
+-
+ 		setOnlineStatus(tmpStatus);
+ 	}
+ }
+@@ -191,4 +185,5 @@
+ 
+ #include "wpcontact.moc"
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpaccount.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpaccount.cpp	(revision 586398)
+@@ -34,19 +34,18 @@
+ 
+ class KPopupMenu;
+ 
+-WPAccount::WPAccount(WPProtocol *parent, const QString &accountID, const char *name) : Kopete::Account(parent, accountID, name)
++WPAccount::WPAccount(WPProtocol *parent, const QString &accountID, const char *name)
++	: Kopete::Account(parent, accountID, name)
+ {
+ //	kdDebug(14170) <<  "WPAccount::WPAccount()" << endl;
+ 
+-	// setup internals
+-	QString theHostName = accountID;
++	mProtocol = WPProtocol::protocol();
+ 
+ 	// we need this before initActions
+-	setMyself( new WPContact(this, theHostName, theHostName, 0) );
++	Kopete::MetaContact *myself = Kopete::ContactList::self()->myself();
++	setMyself( new WPContact(this, accountID, myself->displayName(), myself) );
+ 
+ //	if (excludeConnect()) connect(Kopete::OnlineStatus::Online); // ??
+-
+-	QObject::connect(this, SIGNAL(settingsChanged()), parent, SLOT(slotSettingsChanged()));
+ }
+ 
+ // Destructor
+@@ -56,29 +55,23 @@
+ 
+ const QStringList WPAccount::getGroups()
+ {
+-	return static_cast<WPProtocol *>(protocol())->getGroups();
++	return mProtocol->getGroups();
+ }
+ 
+ const QStringList WPAccount::getHosts(const QString &Group)
+ {
+-	return static_cast<WPProtocol *>(protocol())->getHosts(Group);
++	return mProtocol->getHosts(Group);
+ }
+ 
+-void WPAccount::slotSettingsChanged()
+-{
+-//	kdDebug(14170) <<  "WPAccount::slotSettingsChanged()" << endl;
+-	emit(settingsChanged());
+-}
+-
+ bool WPAccount::checkHost(const QString &Name)
+ {
+ //	kdDebug() << "WPAccount::checkHost: " << Name << endl;
+-	if (Name.upper() == "LOCALHOST") {
++	if (Name.upper() == QString::fromLatin1("LOCALHOST")) {
+ 		// Assume localhost is always there, but it will not appear in the samba output.
+ 		// Should never happen as localhost is now forbidden as contact, just for safety. GF
+ 		return true;
+ 	} else {
+-		return static_cast<WPProtocol *>(protocol())->checkHost(Name);
++		return mProtocol->checkHost(Name);
+ 	}
+ }
+ 
+@@ -104,11 +97,11 @@
+ 	// IPs can not be matched to an account anyway.
+ 	// This should happen rarely but they make kopete crash.
+ 	// The reason for this seems to be in ChatSessionManager? GF
+-	QRegExp ip("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
++	QRegExp ip("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
+ 
+ //	kdDebug(14170) << "ip.search: " << From << " match: " << ip.search(From) << endl;
+ 
+-	if (From == accountId() || ip.search(From) > -1) {
++	if (From == accountId() || ip.exactMatch(From)) {
+ 		kdDebug(14170) << "Ignoring message from own host/account or IP." << endl;
+ 		return;
+ 	}
+@@ -121,24 +114,24 @@
+ 			static_cast<WPContact *>(contacts()[From])->slotNewMessage(Body, Arrival);
+ 		}
+ 		else {
+-			static_cast<WPProtocol *>(protocol())->sendMessage(theAwayMessage, From);
++			if (!theAwayMessage.isEmpty()) mProtocol->sendMessage(theAwayMessage, From);
+ 		}
+ 	 } else {
+ 		// What to do with offline received messages?
+-		kdDebug(14170) << "WinPopup: That's strange - we got a message while offline! Ignoring." << endl;
++		kdDebug(14170) << "That's strange - we got a message while offline! Ignoring." << endl;
+ 	}
+ }
+ 
+ void WPAccount::connect(const Kopete::OnlineStatus &)
+ {
+ //	kdDebug(14170) <<  "WPAccount::Connect()" << endl;
+-	myself()->setOnlineStatus(static_cast<WPProtocol *>(protocol())->WPOnline);
++	myself()->setOnlineStatus(mProtocol->WPOnline);
+ }
+ 
+ void WPAccount::disconnect()
+ {
+ //	kdDebug(14170) <<  "WPAccount::Disconnect()" << endl;
+-	myself()->setOnlineStatus(static_cast<WPProtocol *>(protocol())->WPOffline);
++	myself()->setOnlineStatus(mProtocol->WPOffline);
+ }
+ 
+ /* I commented this code because deleting myself may have *dangerous* side effect, for example, for the status tracking.
+@@ -153,30 +146,40 @@
+ {
+ //	kdDebug(14170) <<  "WPAccount::setAway()" << endl;
+ 
+-	theAwayMessage = awayMessage.isNull() ? i18n("I'm away at the moment.") : awayMessage;
++	theAwayMessage = awayMessage;
+ 
+ //	if(!isConnected())
+ //		theInterface->goOnline();
+-	myself()->setOnlineStatus(status ? static_cast<WPProtocol *>(protocol())->WPAway : static_cast<WPProtocol *>(protocol())->WPOnline);
++	myself()->setOnlineStatus(status ? mProtocol->WPAway : mProtocol->WPOnline);
+ }
+ 
+ KActionMenu* WPAccount::actionMenu()
+ {
+ 	kdDebug(14170) <<  "WPAccount::actionMenu()" << endl;
+ 
+-	WPProtocol *theProtocol = static_cast<WPProtocol *>(protocol());
++	/// How to remove an action from Kopete::Account::actionMenu()? GF
++
+ 	KActionMenu *theActionMenu = new KActionMenu(accountId() , myself()->onlineStatus().iconFor(this), this);
+-	theActionMenu->popupMenu()->insertTitle(myself()->icon(), i18n("WinPopup (%1)").arg(accountId()));
++	theActionMenu->popupMenu()->insertTitle(myself()->onlineStatus().iconFor(this), i18n("WinPopup (%1)").arg(accountId()));
+ 
+-	if (theProtocol)
++	if (mProtocol)
+ 	{
+-		theActionMenu->insert(new KAction("Online", QIconSet(theProtocol->WPOnline.iconFor(this)), 0,
+-			this, SLOT(connect()), theActionMenu, "actionGoAvailable"));
+-		theActionMenu->insert(new KAction("Away", QIconSet(theProtocol->WPAway.iconFor(this)), 0,
+-			this, SLOT(goAway()), theActionMenu, "actionGoAway"));
+-		// One can not really go offline manually - appears online as long as samba server is running. GF
+-//		theActionMenu->insert(new KAction("Offline", QIconSet(theProtocol->WPOffline.iconFor(this)), 0,
+-//			this, SLOT(disconnect()), theActionMenu, "actionGoOffline"));
++		KAction *goOnline = new KAction("Online", QIconSet(mProtocol->WPOnline.iconFor(this)), 0,
++										 this, SLOT(connect()), theActionMenu, "actionGoAvailable");
++		goOnline->setEnabled(isConnected() && isAway());
++		theActionMenu->insert(goOnline);
++
++		KAction *goAway = new KAction("Away", QIconSet(mProtocol->WPAway.iconFor(this)), 0,
++									  this, SLOT(goAway()), theActionMenu, "actionGoAway");
++		goAway->setEnabled(isConnected() && !isAway());
++		theActionMenu->insert(goAway);
++
++		/// One can not really go offline manually - appears online as long as samba server is running. GF
++
++		theActionMenu->popupMenu()->insertSeparator();
++		theActionMenu->insert(new KAction(i18n("Properties"),  0,
++							  this, SLOT(editAccount()), theActionMenu, "actionAccountProperties"));
++
+ 	}
+ 
+ 	return theActionMenu;
+@@ -186,7 +189,8 @@
+ {
+ 	kdDebug(14170) << "WPAccount::slotSendMessage(" << Body << ", " << Destination << ")" << endl;
+ 
+-	static_cast<WPProtocol *>(protocol())->sendMessage(Body, Destination);
++	if (myself()->onlineStatus().status() == Kopete::OnlineStatus::Away) myself()->setOnlineStatus(mProtocol->WPOnline);
++	mProtocol->sendMessage(Body, Destination);
+ }
+ 
+ void WPAccount::setOnlineStatus(const Kopete::OnlineStatus &status, const QString &reason)
+--- kopete/protocols/winpopup/wpuserinfo.h	(revision 568672)
++++ kopete/protocols/winpopup/wpuserinfo.h	(revision 586398)
+@@ -57,4 +57,5 @@
+ 
+ #endif
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpcontact.h	(revision 568672)
++++ kopete/protocols/winpopup/wpcontact.h	(revision 586398)
+@@ -22,7 +22,7 @@
+ #include <kaction.h>
+ 
+ // Qt Includes
+-#include <qvaluestack.h>
++//#include <qvaluestack.h>
+ #include <qdatetime.h>
+ #include <qptrlist.h>
+ #include <qtimer.h>
+@@ -73,7 +73,7 @@
+ 	bool myWasConnected;	// true if protocol connected at last check
+ 
+ 	QTimer checkStatus;		// checks the status of this contact every second or so
+-	KActionCollection *myActionCollection;
++//	KActionCollection *myActionCollection;
+ 							// holds all the protocol specific actions (not many!)
+ 	Kopete::ChatSession *m_manager;
+ 							// holds the two message managers - one for email and one for chat
+@@ -82,4 +82,5 @@
+ 
+ #endif
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpprotocol.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpprotocol.cpp	(revision 586398)
+@@ -64,12 +64,9 @@
+ 
+ 	addAddressBookField( "messaging/winpopup", Kopete::Plugin::MakeIndexField );
+ 
+-	KGlobal::config()->setGroup("WinPopup");
+-	QString smbClientBin = KGlobal::config()->readEntry("SmbcPath", "/usr/bin/smbclient");
+-	int groupCheckFreq = KGlobal::config()->readNumEntry("HostCheckFreq", 60);
+-	int messageCheckFreq = KGlobal::config()->readNumEntry("MessageCheckFreq", 5);
++	readConfig();
+ 
+-	popupClient = new WinPopupLib(smbClientBin, groupCheckFreq, messageCheckFreq);
++	popupClient = new WinPopupLib(smbClientBin, groupCheckFreq);
+ 	QObject::connect(popupClient, SIGNAL(signalNewMessage(const QString &, const QDateTime &, const QString &)),
+ 		this, SLOT(slotReceivedMessage(const QString &, const QDateTime &, const QString &)));
+ }
+@@ -86,7 +83,7 @@
+ {
+ //	kdDebug(14170) << "WPProtocol::createAddContactWidget(<parent>, " << theAccount << ")" << endl;
+ 
+-	return new WPAddContact(this, dynamic_cast<WPAccount *>(theAccount), parent);
++	return new WPAddContact(parent, dynamic_cast<WPAccount *>(theAccount));
+ }
+ 
+ Kopete::Contact *WPProtocol::deserializeContact( Kopete::MetaContact *metaContact,
+@@ -113,7 +110,7 @@
+ 
+ KopeteEditAccountWidget *WPProtocol::createEditAccountWidget(Kopete::Account *account, QWidget *parent)
+ {
+-	return new WPEditAccount(this, account, parent);
++	return new WPEditAccount(parent, account);
+ }
+ 
+ Kopete::Account *WPProtocol::createNewAccount(const QString &accountId)
+@@ -121,16 +118,19 @@
+ 	return new WPAccount(this, accountId);
+ }
+ 
+-void WPProtocol::slotSettingsChanged()
++void WPProtocol::settingsChanged()
+ {
+ 	kdDebug(14170) <<  "WPProtocol::slotSettingsChanged()" << endl;
+ 
++	readConfig();
++	popupClient->settingsChanged(smbClientBin, groupCheckFreq);
++}
++
++void WPProtocol::readConfig()
++{
+ 	KGlobal::config()->setGroup("WinPopup");
+-	QString smbClientBin = KGlobal::config()->readEntry("SmbcPath", "/usr/bin/smbclient");
+-	int groupCheckFreq = KGlobal::config()->readNumEntry("HostCheckFreq", 60);
+-	int messageCheckFreq = KGlobal::config()->readNumEntry("MessageCheckFreq", 5);
+-
+-	popupClient->settingsChanged(smbClientBin, groupCheckFreq, messageCheckFreq);
++	smbClientBin = KGlobal::config()->readEntry("SmbcPath", "/usr/bin/smbclient");
++	groupCheckFreq = KGlobal::config()->readNumEntry("HostCheckFreq", 60);
+ }
+ 
+ void WPProtocol::installSamba()
+--- kopete/protocols/winpopup/wpaccount.h	(revision 568672)
++++ kopete/protocols/winpopup/wpaccount.h	(revision 586398)
+@@ -90,8 +90,6 @@
+ 	/* Reimplemented from Kopete::Account */
+ 	void setOnlineStatus( const Kopete::OnlineStatus &status , const QString &reason = QString::null);
+ 
+-	void slotSettingsChanged();
+-
+ protected:
+ 	virtual bool createContact(const QString &contactId, Kopete::MetaContact *parentContact);
+ 
+@@ -99,12 +97,11 @@
+ //	void updateAccountId();
+ 
+ private:
++	WPProtocol *mProtocol;
+ 	QString theAwayMessage;			// The message to give when the user is away
+-
+-signals:
+-	void settingsChanged();
+ };
+ 
+ #endif
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpeditaccount.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpeditaccount.cpp	(revision 586398)
+@@ -34,27 +34,33 @@
+ #include <kmessagebox.h>
+ #include <kconfig.h>
+ #include <kapplication.h>
++#include <kstandarddirs.h>
+ 
++
+ // Kopete Includes
+ #include <addcontactpage.h>
+ 
+ // Local Includes
+ #include "wpaccount.h"
+ #include "wpeditaccount.h"
++#include "wpprotocol.h"
+ 
+-WPEditAccount::WPEditAccount(WPProtocol *protocol, Kopete::Account *theAccount, QWidget *parent, const char *name)
+-	: WPEditAccountBase(parent), KopeteEditAccountWidget(theAccount), mProtocol(protocol)
++WPEditAccount::WPEditAccount(QWidget *parent, Kopete::Account *theAccount)
++	: WPEditAccountBase(parent), KopeteEditAccountWidget(theAccount)
+ {
+-	kdDebug(14170) << "WPEditAccount::WPEditAccount(<protocol>, <theAccount>, <parent>, " << name << ")";
++	kdDebug(14170) << "WPEditAccount::WPEditAccount(<parent>, <theAccount>)";
+ 
++	mProtocol = WPProtocol::protocol();
++
++	QString tmpSmbcPath = KStandardDirs::findExe("smbclient");
++
+ 	if(account()) {
+ 		mHostName->setText(account()->accountId());
+-		mAutoConnect->setChecked(account()->excludeConnect());
++//		mAutoConnect->setChecked(account()->excludeConnect());
+ 		mHostName->setReadOnly(true);
+ 		KGlobal::config()->setGroup("WinPopup");
+-		mMessageCheckFreq->setValue(KGlobal::config()->readNumEntry("MessageCheckFreq", 5));
+ 		mHostCheckFreq->setValue(KGlobal::config()->readNumEntry("HostCheckFreq", 60));
+-		mSmbcPath->setURL(KGlobal::config()->readEntry("SmbcPath", "/usr/bin/smbclient"));
++		mSmbcPath->setURL(KGlobal::config()->readEntry("SmbcPath", tmpSmbcPath));
+ 
+ 	}
+ 	else {
+@@ -74,9 +80,8 @@
+ 		else
+ 			mHostName->setText("LOCALHOST");
+ 
+-		mMessageCheckFreq->setValue(5);
+ 		mHostCheckFreq->setValue(60);
+-		mSmbcPath->setURL("/usr/bin/smbclient");
++		mSmbcPath->setURL(tmpSmbcPath);
+ 	}
+ 
+ 	show();
+@@ -102,11 +107,6 @@
+ 		return false;
+ 	}
+ 
+-	if (!mProtocol->checkMessageDir()) {
+-		KMessageBox::sorry(this, i18n("<qt>There is a serious problem with your working directory.</qt>"), i18n("WinPopup"));
+-		return false;
+-	}
+-
+ 	return true;
+ }
+ 
+@@ -115,7 +115,6 @@
+ 	KGlobal::config()->setGroup("WinPopup");
+ 	KGlobal::config()->writeEntry("SmbcPath", mSmbcPath->url());
+ 	KGlobal::config()->writeEntry("HostCheckFreq", mHostCheckFreq->text());
+-	KGlobal::config()->writeEntry("MessageCheckFreq", mMessageCheckFreq->text());
+ }
+ 
+ Kopete::Account *WPEditAccount::apply()
+@@ -125,11 +124,10 @@
+ 	if(!account())
+ 		setAccount(new WPAccount(mProtocol, mHostName->text()));
+ 
+-	account()->setExcludeConnect(mAutoConnect->isChecked());
++//	account()->setExcludeConnect(mAutoConnect->isChecked());
+ 	writeConfig();
+ 
+-	//is there already an API function or signal? GF
+-	dynamic_cast<WPAccount *>(account())->slotSettingsChanged();
++	mProtocol->settingsChanged();
+ 
+ 	return account();
+ }
+--- kopete/protocols/winpopup/wpaddcontact.cpp	(revision 568672)
++++ kopete/protocols/winpopup/wpaddcontact.cpp	(revision 586398)
+@@ -36,7 +36,7 @@
+ #include "wpaccount.h"
+ #include "wpaddcontact.h"
+ 
+-WPAddContact::WPAddContact(WPProtocol *owner, WPAccount *newAccount, QWidget *parent, const char *name): AddContactPage(parent, name)
++WPAddContact::WPAddContact(QWidget *parent, WPAccount *newAccount, const char *name) : AddContactPage(parent, name)
+ {
+ //	kdDebug(14170) << "WPAddContact::WPAddContact(<owner>, " << newAccount << ", <parent>, " << name << ")" << endl;
+ 
+@@ -45,7 +45,7 @@
+ 	connect(theDialog->mHostGroup, SIGNAL(activated(const QString &)), this, SLOT(slotSelected(const QString &)));
+ 	connect(theDialog->mRefresh, SIGNAL(clicked()), this, SLOT(slotUpdateGroups()));
+ 	theDialog->show();
+-	theProtocol = owner;
++
+ 	theAccount = newAccount;
+ 
+ 	slotUpdateGroups();
+@@ -74,9 +74,10 @@
+ 
+ 	theDialog->mHostName->clear();
+ 	QStringList Hosts = theAccount->getHosts(Group);
++	QString ownHost = theAccount->myself()->contactId();
+ 	QStringList::ConstIterator end = Hosts.end();
+ 	for (QStringList::ConstIterator i = Hosts.begin(); i != end; i++)
+-		theDialog->mHostName->insertItem(SmallIcon("personal"), *i);
++		if (*i != ownHost) theDialog->mHostName->insertItem(SmallIcon("personal"), *i);
+ }
+ 
+ bool WPAddContact::validateData()
+@@ -92,7 +93,7 @@
+ 
+ 	// If our own host is not allowed as contact localhost should be forbidden as well,
+ 	// additionally somehow localhost as contact crashes when receiving a message from it?? GF
+-	if (tmpHostName.upper() == "LOCALHOST") {
++	if (tmpHostName.upper() == QString::fromLatin1("LOCALHOST")) {
+ 		KMessageBox::sorry(this, i18n("<qt>LOCALHOST is not allowed as contact.</qt>"), i18n("WinPopup"));
+ 		return false;
+ 	}
+@@ -105,8 +106,7 @@
+ 	kdDebug(14170) << "WPAddContact::apply(" << theAccount << ", " << theMetaContact << ")" << endl;
+ 
+ 	// TODO: make the nickname an option
+-	theAccount->addContact(theDialog->mHostName->currentText(), theMetaContact, Kopete::Account::ChangeKABC );
+-	return true;
++	return theAccount->addContact(theDialog->mHostName->currentText(), theMetaContact, Kopete::Account::ChangeKABC );
+ }
+ 
+ #include "wpaddcontact.moc"
+--- kopete/protocols/winpopup/winpopup-install.sh	(revision 568672)
++++ kopete/protocols/winpopup/winpopup-install.sh	(revision 586398)
+@@ -7,7 +7,7 @@
+ 
+ # Create new smb.conf file with updated message command line
+ echo "[global]" > ~/smb.conf.new
+-echo "   message command = $1 %s %m &" >> ~/smb.conf.new
++echo "   message command = $1 %s %m %t &" >> ~/smb.conf.new
+ cat $i | grep -v "message command = " | grep -v "\[global\]" >> ~/smb.conf.new
+ 
+ # Backup the old file
+--- kopete/protocols/winpopup/wpprotocol.h	(revision 568672)
++++ kopete/protocols/winpopup/wpprotocol.h	(revision 586398)
+@@ -61,7 +61,6 @@
+ 	const QStringList getGroups() {return popupClient->getGroups(); }
+ 	const QStringList getHosts(const QString &Group) { return popupClient->getHosts(Group); }
+ 	bool checkHost(const QString &Name) { return popupClient->checkHost(Name); }
+-	bool checkMessageDir() { return popupClient->checkMessageDir(); }
+ 
+ // Kopete::Plugin overloading
+ public:
+@@ -75,17 +74,21 @@
+ 	const Kopete::OnlineStatus WPAway;
+ 	const Kopete::OnlineStatus WPOffline;
+ 	void sendMessage(const QString &Body, const QString &Destination);
++	void settingsChanged(void);			// Callback when settings changed
+ 
+ public slots:
+-	void slotSettingsChanged(void);			// Callback when settings changed
+ 	void installSamba();				// Modify smb.conf to use winpopup-send.sh script
+ 	void slotReceivedMessage(const QString &Body, const QDateTime &Time, const QString &From);
+ 
+ private:
++	QString smbClientBin;
++	int groupCheckFreq;
++	void readConfig();
+ 	WinPopupLib *popupClient;
+ 	static WPProtocol *sProtocol;			// Singleton
+ };
+ 
+ #endif
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/wpeditaccount.h	(revision 568672)
++++ kopete/protocols/winpopup/wpeditaccount.h	(revision 586398)
+@@ -41,7 +41,7 @@
+ 	WPAccount *mAccount;
+ 
+ public:
+-	WPEditAccount(WPProtocol *protocol, Kopete::Account *theAccount, QWidget *parent = 0, const char *name = 0);
++	WPEditAccount(QWidget *parent, Kopete::Account *theAccount);
+ 
+ 	virtual bool validateData();
+ 	void writeConfig();
+--- kopete/protocols/winpopup/wpaddcontact.h	(revision 568672)
++++ kopete/protocols/winpopup/wpaddcontact.h	(revision 586398)
+@@ -18,8 +18,6 @@
+ #ifndef WPADDCONTACT_H
+ #define WPADDCONTACT_H
+ 
+-// Local Includes
+-
+ // Kopete Includes
+ #include <addcontactpage.h>
+ 
+@@ -27,7 +25,8 @@
+ 
+ // KDE Includes
+ 
+-class WPProtocol;
++// Local Includes
++
+ class WPAccount;
+ class WPAddContactBase;
+ namespace Kopete { class MetaContact; }
+@@ -37,12 +36,11 @@
+ 	Q_OBJECT
+ 
+ private:
+-	WPProtocol *theProtocol;
+ 	WPAccount *theAccount;
+ 	WPAddContactBase *theDialog;
+ 
+ public:
+-	WPAddContact(WPProtocol *owner, WPAccount *newAccount, QWidget *parent = 0, const char *name = 0);
++	WPAddContact(QWidget *parent, WPAccount *newAccount, const char *name = 0);
+ 	~WPAddContact();
+ 
+ 	virtual bool validateData();
+--- kopete/protocols/winpopup/libwinpopup/libwinpopup.cpp	(revision 568672)
++++ kopete/protocols/winpopup/libwinpopup/libwinpopup.cpp	(revision 586398)
+@@ -25,7 +25,7 @@
+ #include <kdebug.h>
+ #include <kmessagebox.h>
+ #include <klocale.h>
+-#include <kfileitem.h>
++#include <kdirlister.h>
+ 
+ // Kopete Includes
+ #include "kopeteuiglobal.h"
+@@ -33,32 +33,39 @@
+ // Local Includes
+ #include "libwinpopup.h"
+ 
+-WinPopupLib::WinPopupLib(const QString &smbClient,int groupFreq,int messageCheck)
+-	: smbClientBin(smbClient), groupCheckFreq(groupFreq), messageCheckFreq(messageCheck)
++WinPopupLib::WinPopupLib(const QString &smbClient,int groupFreq)
++	: smbClientBin(smbClient), groupCheckFreq(groupFreq)
+ {
+ 	connect(&updateGroupDataTimer, SIGNAL(timeout()), this, SLOT(slotUpdateGroupData()));
+-	connect(&messageCheckTimer, SIGNAL(timeout()), this, SLOT(slotCheckForNewMessages()));
+ 
+ 	updateGroupDataTimer.start(1, true);
+-	messageCheckTimer.start(1, true);
++	QTimer::singleShot(1, this, SLOT(slotStartDirLister()));
+ }
+ 
+ WinPopupLib::~WinPopupLib()
+ {
+ }
+ 
++void WinPopupLib::slotStartDirLister()
++{
++	if (checkMessageDir()) {
++		dirLister = new KDirLister();
++		dirLister->setAutoUpdate(true);
++		connect(dirLister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(slotNewMessages(const KFileItemList &)));
++		connect(dirLister, SIGNAL(completed()), this, SLOT(slotListCompleted()));
++		dirLister->openURL(KURL::fromPathOrURL(WP_POPUP_DIR));
++	}
++}
++
+ /**
+  * return the group list
+  */
+ const QStringList WinPopupLib::getGroups()
+ {
+ 	QStringList ret;
+-	// Do we need a mutex or semaphore here? GF
+-	groupMutex.lock();
+ 	QMap<QString, WorkGroup>::ConstIterator end = theGroups.end();
+ 	for(QMap<QString, WorkGroup>::ConstIterator i = theGroups.begin(); i != end; i++)
+ 		ret += i.key();
+-	groupMutex.unlock();
+ 
+ 	return ret;
+ }
+@@ -79,16 +86,13 @@
+ //	kdDebug() << "WP checkHost: " << Name << endl;
+ 	bool ret = false;
+ 
+-	// Do we need a mutex or semaphore here? GF
+-	groupMutex.lock();
+ 	QMap<QString, WorkGroup>::Iterator end = theGroups.end();
+ 	for(QMap<QString, WorkGroup>::Iterator i = theGroups.begin(); i != end && !ret; i++) {
+ 		if ((*i).Hosts().contains(Name.upper())) {
+ 			ret = true;
+-			break; //keep the mutex locked as short as possible
++			break;
+ 		}
+ 	}
+-	groupMutex.unlock();
+ 
+ 	return ret;
+ }
+@@ -98,27 +102,34 @@
+ {
+ 	QDir dir(WP_POPUP_DIR);
+ 	if (! dir.exists()) {
+-		int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(), i18n("Working directory /var/lib/winpopup/ does not exist.\n"
+-								     "If you have not configured anything yet (samba) it may be better to call\n"
+-								     "Install Into Samba (Configure... -> Account -> Edit)\n"
+-								     "Should the directory be created? (May need root password)"), QString::null, i18n("Create Directory"), i18n("Do Not Create"));
++		int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(),
++												  i18n("Working directory %1 does not exist.\n"
++													   "If you have not configured anything yet (samba) please see\n"
++													   "Install Into Samba (Configure... -> Account -> Edit) information\n"
++													   "on how to do this.\n"
++													   "Should the directory be created? (May need root password)").arg(WP_POPUP_DIR),
++												  QString::fromLatin1("Winpopup"), i18n("Create Directory"), i18n("Do Not Create"));
+ 		if (tmpYesNo == KMessageBox::Yes) {
+-			QString kdesuArgs = "mkdir -p -m 0777 /var/lib/winpopup";
++			QStringList kdesuArgs = QStringList(QString("-c mkdir -p -m 0777 " + WP_POPUP_DIR));
+ 			if (KApplication::kdeinitExecWait("kdesu", kdesuArgs) == 0) return true;
+ 		}
+ 	} else {
+-		KFileItem tmpFileItem = KFileItem(KFileItem::Unknown, KFileItem::Unknown, "/var/lib/winpopup/");
+-		QString tmpPerms = tmpFileItem.permissionsString();
++		KFileItem tmpFileItem = KFileItem(KFileItem::Unknown, KFileItem::Unknown, KURL::fromPathOrURL(WP_POPUP_DIR));
++		mode_t tmpPerms = tmpFileItem.permissions();
+ 
+-		if (tmpPerms != "drwxrwxrwx") {
++		if (tmpPerms != 0777) {
+ 
+ 			kdDebug(14170) << "Perms not ok!" << endl;
+ 
+-			int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(), i18n("Permissions of the working directory "
+-									     "/var/lib/winpopup/ are wrong!\n"
+-									     "Fix? (May need root password)"), QString::null, i18n("Fix"), i18n("Do Not Fix"));
++			int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(),
++													  i18n("Permissions of the working directory "
++														   "%1 are wrong!\n"
++														   "You will not receive messages if you say no.\n"
++														   "You can also correct it manually (chmod 0777 %1) and restart kopete.\n"
++														   "Fix? (May need root password)").arg(WP_POPUP_DIR),
++													  QString::fromLatin1("Winpopup"), i18n("Fix"), i18n("Do Not Fix"));
+ 			if (tmpYesNo == KMessageBox::Yes) {
+-				QString kdesuArgs = "chmod 0777 /var/lib/winpopup";
++				QStringList kdesuArgs = QStringList(QString("-c chmod 0777 " + WP_POPUP_DIR));
+ 				if (KApplication::kdeinitExecWait("kdesu", kdesuArgs) == 0) return true;
+ 			}
+ 		} else {
+@@ -128,19 +139,25 @@
+ 
+ 	return false;
+ }
++
+ /**
+  * read the groups and their hosts
+  */
+ void WinPopupLib::slotUpdateGroupData()
+ {
+ 	passedInitialHost = false;
++	todo.clear();
+ 	currentGroupsMap.clear();
+-	currentHost = "LOCALHOST";
++	currentHost = QString::fromLatin1("LOCALHOST");
+ 	startReadProcess(currentHost);
+ }
+ 
+ void WinPopupLib::startReadProcess(const QString &Host)
+ {
++	currentHosts.clear();
++	currentGroups.clear();
++	currentGroup = QString();
++
+ 	// for Samba 3
+ 	KProcIO *reader = new KProcIO;
+ 	*reader << smbClientBin << "-N" << "-E" << "-g" << "-L" << Host << "-";
+@@ -158,12 +175,17 @@
+ {
+ 	QString tmpLine = QString::null;
+ 	QRegExp group("^Workgroup\\|(.*)\\|(.*)$"), host("^Server\\|(.*)\\|(.*)$"),
+-		info("^Domain=\\[([^\\]]+)\\] OS=\\[([^\\]]+)\\] Server=\\[([^\\]]+)\\]");
++			info("^Domain=\\[([^\\]]+)\\] OS=\\[([^\\]]+)\\] Server=\\[([^\\]]+)\\]"),
++			error("Connection.*failed");
+ 
+ 	while (r->readln(tmpLine) > -1) {
+ 		if (info.search(tmpLine) != -1) currentGroup = info.cap(1);
+ 		if (host.search(tmpLine) != -1) currentHosts += host.cap(1);
+ 		if (group.search(tmpLine) != -1) currentGroups[group.cap(1)] = group.cap(2);
++		if (error.search(tmpLine) != -1) {
++			kdDebug(14170) << "Connection to " << currentHost << " failed!" << endl;
++			if (currentHost == QString::fromLatin1("LOCALHOST")) currentHost = QString::fromLatin1("failed"); // to be sure
++		}
+ 	}
+ }
+ 
+@@ -180,116 +202,124 @@
+ 		todo.remove(currentHost);
+ 		done += currentHost;
+ 
+-		QMap<QString, WorkGroup> newGroups;
+-		//loop through the read groups and check for new ones
+-		QMap<QString, QString>::ConstIterator end = currentGroups.end();
+-		for (QMap<QString, QString>::ConstIterator i = currentGroups.begin(); i != end; i++) {
+-			QString groupMaster = i.data();
+-			if (!done.contains(groupMaster)) todo += groupMaster;
++		if (!currentGroups.isEmpty()) {
++			QMap<QString, WorkGroup> newGroups;
++			//loop through the read groups and check for new ones
++			QMap<QString, QString>::ConstIterator end = currentGroups.end();
++			for (QMap<QString, QString>::ConstIterator i = currentGroups.begin(); i != end; i++) {
++				QString groupMaster = i.data();
++				if (!done.contains(groupMaster)) todo += groupMaster;
++			}
+ 		}
+ 
+-		// create a workgroup object and put the hosts in
+-		WorkGroup nWG;
+-		nWG.addHosts(currentHosts);
++		if (!currentGroup.isEmpty() && !currentHosts.isEmpty()) {
++			// create a workgroup object and put the hosts in
++			WorkGroup nWG;
++			nWG.addHosts(currentHosts);
+ 
+-		currentGroupsMap.insert(currentGroup, nWG, true);
++			currentGroupsMap.insert(currentGroup, nWG, true);
++		}
+ 
+ 	} else {
+ 		passedInitialHost = true;
+-		QMap<QString, QString>::ConstIterator end = currentGroups.end();
+-		for (QMap<QString, QString>::ConstIterator i = currentGroups.begin(); i != end; i++) {
+-			QString groupMaster = i.data();
+-			todo += groupMaster;
++		if (!currentGroups.isEmpty()) {
++			QMap<QString, QString>::ConstIterator end = currentGroups.end();
++			for (QMap<QString, QString>::ConstIterator i = currentGroups.begin(); i != end; i++) {
++				QString groupMaster = i.data();
++				todo += groupMaster;
++			}
++		} else {
++			if (currentHost == QString::fromLatin1("failed"))
++				KMessageBox::error(Kopete::UI::Global::mainWidget(),
++								   i18n("Connection to localhost failed!\n"
++									    "Is your samba server running?"),
++								   QString::fromLatin1("Winpopup"));
+ 		}
+ 	}
+ 
+ 	// maybe restart cycle
+-	currentHosts.clear();
+-	currentGroups.clear();
+ 	if (todo.count()) {
+ 		currentHost = todo[0];
+ 		startReadProcess(currentHost);
+ 	} else {
+-		groupMutex.lock();
+ 		theGroups = currentGroupsMap;
+-		groupMutex.unlock();
+ 		updateGroupDataTimer.start(groupCheckFreq * 1000, true);
+ 	}
+ }
+ 
++void WinPopupLib::slotListCompleted()
++{
++	/// only to check received messages during start up, then we use newItems. GF
++	disconnect(dirLister, SIGNAL(completed()), this, SLOT(slotListCompleted()));
++	readMessages(dirLister->items());
++}
++
++void WinPopupLib::slotNewMessages(const KFileItemList &items)
++{
++	readMessages(items);
++}
++
+ /**
+- * check for new arrived messages
++ * read new arrived messages
+  */
+-void WinPopupLib::slotCheckForNewMessages()
++void WinPopupLib::readMessages(const KFileItemList &items)
+ {
+-//	kdDebug(14170) << "check for new Messages: " << this << endl;
++	QPtrListIterator<KFileItem> it(items);
++	KFileItem *tmpItem;
++	while ((tmpItem = it.current()) != 0) {
++		if (tmpItem->isFile()) {
++			QFile messageFile(tmpItem->url().path());
+ 
+-	if (!checkMessageDir()) return; // Restart timer if false? GF
++			if (messageFile.open(IO_ReadOnly)) {
++				QTextStream stream(&messageFile);
++				QString sender;
++				QDateTime time;
++				QString text;
+ 
+-	QDir dir(WP_POPUP_DIR);
+-	const QFileInfoList *messageFiles = dir.entryInfoList(QDir::Files, QDir::Name);
+-	if (messageFiles) {
+-		QFileInfoListIterator it(*messageFiles);
+-		QFileInfo *messageFileInfo;
+-		while((messageFileInfo = it.current()) != 0) {
+-			++it;
+-			if (messageFileInfo->isFile()) {
+-				QString messageFileName(messageFileInfo->fileName());
+-				QString messageFilePath(WP_POPUP_DIR);
+-//				messageFilePath.append("/");
+-				messageFilePath.append(messageFileName);
+-				QFile messageFile(messageFilePath);
++				// first line is sender, can this really be empty? GF
++				sender = stream.readLine();
++				sender = sender.upper();
+ 
+-				if (messageFile.open(IO_ReadOnly)) {
+-					QTextStream stream(&messageFile);
+-					QString sender;
+-					QDateTime time;
+-					QString text;
++				// second line is time
++				QString tmpTime = stream.readLine();
++				time = QDateTime::fromString(tmpTime, Qt::ISODate);
+ 
+-					// first line is sender, can this really be empty? GF
+-					sender = stream.readLine();
+-					sender = sender.upper();
++				while (!stream.atEnd()) {
++					text.append(stream.readLine());
++					text.append('\n');
++				}
+ 
+-					// second line is time
+-					QString tmpTime = stream.readLine();
+-					time = QDateTime::fromString(tmpTime, Qt::ISODate);
++				// remove trailing CR
++				text = text.stripWhiteSpace();
+ 
+-					while (!stream.atEnd()) {
+-						text.append(stream.readLine());
+-						text.append('\n');
+-					}
++				messageFile.close();
+ 
+-					// remove trailing CR
+-					text = text.stripWhiteSpace();
+-
+-					messageFile.close();
+-
+-					// delete file
+-					if (!messageFile.remove()) {
+-						// QFile::remove() seems to be very persistent, it removes even files with 0444 owned by root
+-						// if the directory permissions are 0777 - so this is just for safety. GF
+-						kdDebug(14170) << "Message file not removed - how that?" << endl;
+-						int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(), i18n("A message file could not be removed; "
+-											"maybe the permissions are wrong.\n"
+-											"Fix? (May need root password)"), QString::null, i18n("Fix"), i18n("Do Not Fix"));
+-						if (tmpYesNo == KMessageBox::Yes) {
+-							QFileInfo messageFileInfo(messageFile);
+-							QString kdesuArgs = "chmod 0666 /var/lib/winpopup/" + messageFileInfo.fileName();
+-							if (KApplication::kdeinitExecWait("kdesu", kdesuArgs) == 0) {
+-								if (!messageFile.remove())
+-									KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("Still cannot remove it; please fix manually."));
+-							}
++				// delete file
++				if (!messageFile.remove()) {
++					// QFile::remove() seems to be very persistent, it removes even files with 0444 owned by root
++					// if the directory permissions are 0777 - so this is just for safety. GF
++					kdDebug(14170) << "Message file not removed - how that?" << endl;
++					int tmpYesNo =  KMessageBox::warningYesNo(Kopete::UI::Global::mainWidget(),
++															  i18n("A message file could not be removed; "
++																   "maybe the permissions are wrong.\n"
++																   "Fix? (May need root password)"),
++															  QString::fromLatin1("Winpopup"), i18n("Fix"), i18n("Do Not Fix"));
++					if (tmpYesNo == KMessageBox::Yes) {
++						QStringList kdesuArgs = QStringList(QString("-c chmod 0666 " + tmpItem->url().path()));
++						if (KApplication::kdeinitExecWait("kdesu", kdesuArgs) == 0) {
++							if (!messageFile.remove())
++								KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("Still cannot remove it; please fix manually."));
+ 						}
+ 					}
+-					if (!sender.isEmpty() && time.isValid())
+-						emit signalNewMessage(text, time, sender);
+-					else
+-						kdDebug(14170) << "Received invalid message!" << endl;
+ 				}
++				if (!sender.isEmpty() && time.isValid())
++					emit signalNewMessage(text, time, sender);
++				else
++					kdDebug(14170) << "Received invalid message!" << endl;
+ 			}
+-		} // while
+-	} // if messageFiles
+-	messageCheckTimer.start(messageCheckFreq *1000, true);
++		} // isFile
++		++it;
++	} // while
+ }
+ 
+ /**
+@@ -319,16 +349,15 @@
+ 	delete p;
+ }
+ 
+-void WinPopupLib::settingsChanged(const QString &smbClient, int groupFreq, int messageCheck)
++void WinPopupLib::settingsChanged(const QString &smbClient, int groupFreq)
+ {
+ 	smbClientBin = smbClient;
+ 	groupCheckFreq = groupFreq;
+-	messageCheckFreq = messageCheck;
+ 
+ 	if (updateGroupDataTimer.isActive()) updateGroupDataTimer.changeInterval(groupCheckFreq * 1000);
+-	if (messageCheckTimer.isActive()) messageCheckTimer.changeInterval(messageCheckFreq * 1000);
+ }
+ 
+ #include "libwinpopup.moc"
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/libwinpopup/libwinpopup.h	(revision 568672)
++++ kopete/protocols/winpopup/libwinpopup/libwinpopup.h	(revision 586398)
+@@ -18,11 +18,8 @@
+ #ifndef LIBWINPOPUP_H
+ #define LIBWINPOPUP_H
+ 
+-#define WP_POPUP_DIR "/var/lib/winpopup/"
+-
+ //QT includes
+ #include <qobject.h>
+-#include <qmutex.h>
+ #include <qmap.h>
+ #include <qstringlist.h>
+ #include <qtimer.h>
+@@ -30,7 +27,12 @@
+ 
+ // KDE Includes
+ #include <kprocio.h>
++#include <kfileitem.h>
+ 
++const QString WP_POPUP_DIR = QString::fromLatin1("/var/lib/winpopup");
++
++class KDirLister;
++
+ typedef QMap<QString, QString> stringMap;
+ 
+ class WorkGroup
+@@ -47,14 +49,13 @@
+ 	Q_OBJECT
+ 
+ public:
+-	WinPopupLib(const QString &smbClient,int groupFreq,int messageCheck);
++	WinPopupLib(const QString &smbClient,int groupFreq);
+ 	~WinPopupLib();
+ 
+ 	const QStringList getGroups();
+ 	const QStringList getHosts(const QString &Group);
+ 	bool checkHost(const QString &Name);
+-	bool checkMessageDir();
+-	void settingsChanged(const QString &smbClient, int groupFreq, int messageCheck);
++	void settingsChanged(const QString &smbClient, int groupFreq);
+ 	void sendMessage(const QString &Body, const QString &Destination);
+ 
+ private:
+@@ -63,18 +64,23 @@
+ 	QString currentGroup, currentHost;
+ 	QStringList todo, done, currentHosts;
+ 	stringMap currentGroups;
+-	QMutex groupMutex;
+-	QTimer updateGroupDataTimer, messageCheckTimer;
++	QTimer updateGroupDataTimer;
+ 	QString smbClientBin;
+-	int groupCheckFreq, messageCheckFreq;
++	int groupCheckFreq;
++	KDirLister *dirLister;
+ 
+-public slots:
++	void readMessages(const KFileItemList &items);
++	bool checkMessageDir();
++
++private slots:
+ 	void slotUpdateGroupData();
+ 	void startReadProcess(const QString &Host);
+ 	void slotReadProcessReady(KProcIO *r);
+ 	void slotReadProcessExited(KProcess *r);
+-	void slotCheckForNewMessages();
+ 	void slotSendProcessExited(KProcess *p);
++	void slotStartDirLister();
++	void slotListCompleted();
++	void slotNewMessages(const KFileItemList &items);
+ 
+ signals:
+ 	void signalNewMessage(const QString &, const QDateTime &, const QString &);
+@@ -82,4 +88,5 @@
+ 
+ #endif
+ 
++// vim: set noet ts=4 sts=4 sw=4:
+ // kate: tab-width 4; indent-width 4; replace-trailing-space-save on;
+--- kopete/protocols/winpopup/Makefile.am	(revision 568672)
++++ kopete/protocols/winpopup/Makefile.am	(revision 586398)
+@@ -8,7 +8,7 @@
+ 
+ kde_module_LTLIBRARIES = kopete_wp.la
+ 
+-noinst_HEADERS = wpdebug.h wpprotocol.h wpeditaccount.h wpaccount.h wpuserinfo.h wpcontact.h wpaddcontact.h
++noinst_HEADERS = wpprotocol.h wpeditaccount.h wpaccount.h wpuserinfo.h wpcontact.h wpaddcontact.h
+ 
+ kopete_wp_la_SOURCES = wpprotocol.cpp wpcontact.cpp  wpaddcontact.cpp wpeditaccount.cpp  wpaccount.cpp wpuserinfo.cpp
+ kopete_wp_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries)
+--- kopete/protocols/winpopup/ui/wpeditaccountbase.ui	(revision 568672)
++++ kopete/protocols/winpopup/ui/wpeditaccountbase.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>519</width>
+-            <height>403</height>
++            <width>398</width>
++            <height>445</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -45,13 +45,13 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>Basic &amp;Setup</string>
++                    <string>Basi&amp;c Setup</string>
+                 </attribute>
+-                <grid>
++                <vbox>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QGroupBox" row="0" column="0">
++                    <widget class="QGroupBox">
+                         <property name="name">
+                             <cstring>groupBox51</cstring>
+                         </property>
+@@ -114,31 +114,20 @@
+                                     </widget>
+                                 </hbox>
+                             </widget>
+-                            <widget class="QCheckBox">
+-                                <property name="name">
+-                                    <cstring>mAutoConnect</cstring>
+-                                </property>
+-                                <property name="text">
+-                                    <string>Excl&amp;ude from connection</string>
+-                                </property>
+-                                <property name="whatsThis" stdset="0">
+-                                    <string>Check to disable automatic connection.  If checked, you may connect to this account manually using the icon in the bottom of the main Kopete window</string>
+-                                </property>
+-                            </widget>
+                         </vbox>
+                     </widget>
+-                    <widget class="QGroupBox" row="1" column="0">
++                    <widget class="QGroupBox">
+                         <property name="name">
+                             <cstring>groupBox22</cstring>
+                         </property>
+                         <property name="title">
+                             <string>Information</string>
+                         </property>
+-                        <grid>
++                        <vbox>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLabel" row="0" column="0">
++                            <widget class="QLabel">
+                                 <property name="name">
+                                     <cstring>textLabel12</cstring>
+                                 </property>
+@@ -157,11 +146,32 @@
+                                     <set>WordBreak|AlignTop</set>
+                                 </property>
+                             </widget>
+-                        </grid>
++                            <widget class="QLabel">
++                                <property name="name">
++                                    <cstring>textLabel1_3</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>The samba server must be configured and running.</string>
++                                </property>
++                            </widget>
++                            <widget class="QLabel">
++                                <property name="name">
++                                    <cstring>textLabel1_2</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>"Install into Samba" is a simple method to create the directory for the temporary message files and configure your samba server.&lt;br&gt;
++However, the recommended way is to ask your administrator to create this directory ('mkdir -p -m 0777 /var/lib/winpopup') and add
++'message command = _PATH_TO_/winpopup-send.sh %s %m %t &amp;' (substitute _PATH_TO_ by the real path) to your smb.conf [global]-section.</string>
++                                </property>
++                                <property name="alignment">
++                                    <set>WordBreak|AlignTop</set>
++                                </property>
++                            </widget>
++                        </vbox>
+                     </widget>
+-                    <spacer row="2" column="0">
++                    <spacer>
+                         <property name="name">
+-                            <cstring>spacer30</cstring>
++                            <cstring>spacer7</cstring>
+                         </property>
+                         <property name="orientation">
+                             <enum>Vertical</enum>
+@@ -171,12 +181,12 @@
+                         </property>
+                         <property name="sizeHint">
+                             <size>
+-                                <width>20</width>
+-                                <height>140</height>
++                                <width>21</width>
++                                <height>16</height>
+                             </size>
+                         </property>
+                     </spacer>
+-                </grid>
++                </vbox>
+             </widget>
+             <widget class="QWidget">
+                 <property name="name">
+@@ -238,7 +248,7 @@
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLabel" row="1" column="0">
++                            <widget class="QLabel" row="0" column="0">
+                                 <property name="name">
+                                     <cstring>textLabel4</cstring>
+                                 </property>
+@@ -246,23 +256,15 @@
+                                     <string>Host check frequency:</string>
+                                 </property>
+                             </widget>
+-                            <widget class="QLabel" row="0" column="0">
++                            <widget class="QLabel" row="1" column="0">
+                                 <property name="name">
+-                                    <cstring>textLabel3</cstring>
+-                                </property>
+-                                <property name="text">
+-                                    <string>Message check frequency:</string>
+-                                </property>
+-                            </widget>
+-                            <widget class="QLabel" row="2" column="0">
+-                                <property name="name">
+                                     <cstring>textLabel1</cstring>
+                                 </property>
+                                 <property name="text">
+                                     <string>Path to 'smbclient' executable:</string>
+                                 </property>
+                             </widget>
+-                            <widget class="QLayoutWidget" row="0" column="1" rowspan="3" colspan="1">
++                            <widget class="QLayoutWidget" row="0" column="1" rowspan="2" colspan="1">
+                                 <property name="name">
+                                     <cstring>layout6</cstring>
+                                 </property>
+@@ -272,51 +274,6 @@
+                                     </property>
+                                     <widget class="QLayoutWidget">
+                                         <property name="name">
+-                                            <cstring>layout4</cstring>
+-                                        </property>
+-                                        <hbox>
+-                                            <property name="name">
+-                                                <cstring>unnamed</cstring>
+-                                            </property>
+-                                            <widget class="KIntSpinBox">
+-                                                <property name="name">
+-                                                    <cstring>mMessageCheckFreq</cstring>
+-                                                </property>
+-                                                <property name="sizePolicy">
+-                                                    <sizepolicy>
+-                                                        <hsizetype>7</hsizetype>
+-                                                        <vsizetype>0</vsizetype>
+-                                                        <horstretch>0</horstretch>
+-                                                        <verstretch>0</verstretch>
+-                                                    </sizepolicy>
+-                                                </property>
+-                                                <property name="maxValue">
+-                                                    <number>3600</number>
+-                                                </property>
+-                                                <property name="minValue">
+-                                                    <number>1</number>
+-                                                </property>
+-                                            </widget>
+-                                            <widget class="QLabel">
+-                                                <property name="name">
+-                                                    <cstring>textLabel5</cstring>
+-                                                </property>
+-                                                <property name="sizePolicy">
+-                                                    <sizepolicy>
+-                                                        <hsizetype>3</hsizetype>
+-                                                        <vsizetype>5</vsizetype>
+-                                                        <horstretch>0</horstretch>
+-                                                        <verstretch>0</verstretch>
+-                                                    </sizepolicy>
+-                                                </property>
+-                                                <property name="text">
+-                                                    <string>second(s)</string>
+-                                                </property>
+-                                            </widget>
+-                                        </hbox>
+-                                    </widget>
+-                                    <widget class="QLayoutWidget">
+-                                        <property name="name">
+                                             <cstring>layout5</cstring>
+                                         </property>
+                                         <hbox>
+@@ -386,7 +343,6 @@
+     <tabstop>tabWidget10</tabstop>
+     <tabstop>mHostName</tabstop>
+     <tabstop>doInstallSamba</tabstop>
+-    <tabstop>mAutoConnect</tabstop>
+ </tabstops>
+ <slots>
+     <slot>installSamba()</slot>
+@@ -395,7 +351,6 @@
+ <includehints>
+     <includehint>kpushbutton.h</includehint>
+     <includehint>knuminput.h</includehint>
+-    <includehint>knuminput.h</includehint>
+     <includehint>kurlrequester.h</includehint>
+     <includehint>klineedit.h</includehint>
+     <includehint>kpushbutton.h</includehint>
+--- kopete/protocols/sms/services/kopete_unix_serial.h	(revision 0)
++++ kopete/protocols/sms/services/kopete_unix_serial.h	(revision 586398)
+@@ -0,0 +1,70 @@
++// *************************************************************************
++// * Taken from the GSM TA/ME library
++// *
++// * File:    gsm_unix_port.h
++// *
++// * Purpose: UNIX serial port implementation with extras
++// *
++// * Original Author:  Peter Hofmann (software at pxh.de)
++// * Modified by: Justin Huff (jjhuff at mspin.net)
++// *
++// * Created: 4.5.1999
++// *************************************************************************
++
++#ifndef GSM_UNIX_SERIAL_KOPETE_H
++#define GSM_UNIX_SERIAL_KOPETE_H
++
++#include "config.h"
++#ifdef INCLUDE_SMSGSM
++
++#include <string>
++#include <gsmlib/gsm_error.h>
++#include <gsmlib/gsm_port.h>
++#include <gsmlib/gsm_util.h>
++#include <sys/types.h>
++#include <termios.h>
++
++#include <qobject.h>
++
++class QSocketNotifier;
++namespace gsmlib
++{
++	
++class KopeteUnixSerialPort : public QObject, public Port
++{
++	Q_OBJECT;
++	
++protected:
++	int _fd;                    // file descriptor for device
++	int _oldChar;               // character set by putBack() (-1 == none)
++	long int _timeoutVal;       // timeout for getLine/readByte
++
++	QSocketNotifier* _readNotifier;
++	
++	// throw GsmException include UNIX errno
++	void throwModemException(std::string message) throw(GsmException);
++
++public:
++	// create Port given the UNIX device name
++	KopeteUnixSerialPort(std::string device, speed_t lineSpeed = DEFAULT_BAUD_RATE,
++				   std::string initString = DEFAULT_INIT_STRING,
++				   bool swHandshake = false)
++	  throw(GsmException);
++	virtual ~KopeteUnixSerialPort();
++
++	// inherited from Port
++	void putBack(unsigned char c);
++	int readByte() throw(GsmException);
++	std::string getLine() throw(GsmException);
++	void putLine(std::string line,
++						 bool carriageReturn = true) throw(GsmException);
++	bool wait(GsmTime timeout) throw(GsmException);
++	void setTimeOut(unsigned int timeout);
++
++signals:
++	void activated();
++};
++
++}
++#endif
++#endif // GSM_UNIX_SERIAL_KOPETE_H
+--- kopete/protocols/sms/services/smsclient.cpp	(revision 568672)
++++ kopete/protocols/sms/services/smsclient.cpp	(revision 586398)
+@@ -80,9 +80,9 @@
+ 	*p << provider + ":" + nr;
+ 	*p << message;
+ 
+-	connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(slotSendFinished(KProcess*)));
+-	connect(p, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
+-	connect(p, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
++	QObject::connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(slotSendFinished(KProcess*)));
++	QObject::connect(p, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
++	QObject::connect(p, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
+ 
+ 	p->start(KProcess::Block, KProcess::AllOutput);
+ }
+--- kopete/protocols/sms/services/gsmlib.h	(revision 0)
++++ kopete/protocols/sms/services/gsmlib.h	(revision 586398)
+@@ -0,0 +1,151 @@
++/*  *************************************************************************
++    *   copyright: (C) 2005 Justin Huff <jjhuff at mspin.net>                  *
++    *************************************************************************
++*/
++
++/*  *************************************************************************
++    *                                                                       *
++    * 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 GSMLIB_H_039562406
++#define GSMLIB_H_039562406
++
++#include "config.h"
++#ifdef INCLUDE_SMSGSM
++
++#include <unistd.h>
++
++#include <gsmlib/gsm_unix_serial.h>
++#include <gsmlib/gsm_sms.h>
++#include <gsmlib/gsm_me_ta.h>
++#include <gsmlib/gsm_util.h>
++#include <gsmlib/gsm_event.h>
++
++#include "smsservice.h"
++#include "kopetemessage.h"
++
++#include <qobject.h>
++#include <qevent.h>
++#include <qthread.h>
++#include <qmutex.h>
++#include <qvaluelist.h>
++#include <qstringlist.h>
++
++class GSMLibPrefsUI;
++class SMSContact;
++class QListViewItem;
++class KProcess;
++class GSMLibThread;
++
++class GSMLib : public SMSService
++{
++    Q_OBJECT
++public:
++    GSMLib(Kopete::Account* account);
++    ~GSMLib();
++
++    void send(const Kopete::Message& msg);
++    void setWidgetContainer(QWidget* parent, QGridLayout* container);
++
++    int maxSize();
++    const QString& description();
++
++public slots:
++    void savePreferences();
++	virtual void connect();
++	virtual void disconnect();
++
++//signals:
++//	void messageSent(const Kopete::Message &);
++protected:
++	virtual void customEvent(QCustomEvent* e);
++	
++    QWidget* configureWidget(QWidget* parent);
++	void saveConfig(); 
++	void loadConfig(); 
++
++    GSMLibPrefsUI* prefWidget;
++    QStringList output;
++
++	QString m_device;
++	
++    QString m_description;
++
++	GSMLibThread* m_thread;
++	
++} ;
++
++
++/// Custom event for async-events
++class GSMLibEvent : public QCustomEvent
++{
++public:
++	enum SubType { CONNECTED, DISCONNECTED, NEW_MESSAGE, MSG_SENT, MSG_NOT_SENT };
++	
++	GSMLibEvent(SubType t);
++
++	SubType subType();
++	void setSubType(SubType t);
++
++	QString Text;
++	QString Number;
++	
++	QString Reason;
++	
++	Kopete::Message Message;
++protected:
++	SubType m_subType;
++};
++
++/// Thread to deal with GsmLib's blocking 
++class GSMLibThread : public QThread, gsmlib::GsmEvent
++{
++public:
++	GSMLibThread(QString dev, GSMLib* parent);
++	virtual ~GSMLibThread();
++	
++	virtual void run();
++	void stop();
++	void send(const Kopete::Message& msg);
++protected:
++	bool doConnect();
++	void pollForMessages();
++	void sendMessageQueue();
++	void sendMessage(const Kopete::Message& msg);
++    void SMSReception(gsmlib::SMSMessageRef newMessage, SMSMessageType messageType);
++    void SMSReceptionIndication(std::string storeName, unsigned int index, SMSMessageType messageType);
++	
++	GSMLib* m_parent;
++	QString m_device;
++	
++    gsmlib::MeTa* m_MeTa;
++	
++	bool m_run;
++	
++    struct IncomingMessage
++    {
++        int Index;
++        QString StoreName;
++        gsmlib::SMSMessageRef Message;
++        GsmEvent::SMSMessageType Type; 
++
++        IncomingMessage() :   Index(-1)
++        {}
++    };
++
++    typedef QValueList<IncomingMessage> MessageList;
++    MessageList m_newMessages;
++
++	typedef QValueList<Kopete::Message> KopeteMessageList;
++	KopeteMessageList m_outMessages;
++	QMutex m_outMessagesMutex;
++};
++
++#endif
++#endif //GSMLIB_H_039562406
+--- kopete/protocols/sms/services/Makefile.am	(revision 568672)
++++ kopete/protocols/sms/services/Makefile.am	(revision 586398)
+@@ -4,8 +4,15 @@
+     -I.. \
+     $(all_includes)
+ 
++KDE_CXXFLAGS = $(USE_EXCEPTIONS)
++
+ noinst_LTLIBRARIES = libkopetesmsservices.la
+ 
++
+ libkopetesmsservices_la_SOURCES = smssend.cpp smssendprefs.ui smssendprovider.cpp \
+-	smsclient.cpp smsclientprefs.ui
++	smsclient.cpp smsclientprefs.ui gsmlib.cpp gsmlibprefs.ui kopete_unix_serial.cpp
+ 
++if include_smsgsm
++libkopetesmsservices_la_LIBADD = -lgsmme
++endif
++
+--- kopete/protocols/sms/services/gsmlibprefs.ui	(revision 0)
++++ kopete/protocols/sms/services/gsmlibprefs.ui	(revision 586398)
+@@ -0,0 +1,100 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>GSMLibPrefsUI</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>GSMLibPrefsUI</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>375</width>
++            <height>168</height>
++        </rect>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <property name="margin">
++            <number>0</number>
++        </property>
++        <spacer>
++            <property name="name">
++                <cstring>spacer16</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Horizontal</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>321</width>
++                    <height>16</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel8</cstring>
++            </property>
++            <property name="font">
++                <font>
++                    <bold>1</bold>
++                </font>
++            </property>
++            <property name="text">
++                <string>GSMLib Settings</string>
++            </property>
++        </widget>
++        <widget class="Line">
++            <property name="name">
++                <cstring>line14</cstring>
++            </property>
++            <property name="frameShape">
++                <enum>HLine</enum>
++            </property>
++            <property name="frameShadow">
++                <enum>Sunken</enum>
++            </property>
++            <property name="orientation">
++                <enum>Horizontal</enum>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout13</cstring>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Device:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>program</cstring>
++                    </property>
++                </widget>
++                <widget class="KURLRequester" row="0" column="1">
++                    <property name="name">
++                        <cstring>device</cstring>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kurlrequester.h</includehint>
++    <includehint>klineedit.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/protocols/sms/services/kopete_unix_serial.cpp	(revision 0)
++++ kopete/protocols/sms/services/kopete_unix_serial.cpp	(revision 586398)
+@@ -0,0 +1,445 @@
++// *************************************************************************
++// * Taken from the GSM TA/ME library
++// *
++// * File:	  gsm_unix_port.cc
++// *
++// * Purpose: UNIX serial port implementation with extras
++// *
++// * Original Author:  Peter Hofmann (software at pxh.de)
++// * Modified by: Justin Huff (jjhuff at mspin.net)
++// *
++// * Created: 10.5.1999
++// *************************************************************************
++#include "config.h"
++#ifdef INCLUDE_SMSGSM
++
++#include <gsmlib/gsm_util.h>
++#include <termios.h>
++#include <fcntl.h>
++#include <iostream>
++#include <sstream>
++#include <errno.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <signal.h>
++#include <pthread.h>
++#include <cassert>
++#include <assert.h>
++
++#include <qsocketnotifier.h>
++
++#include "kopete_unix_serial.h"
++
++using namespace std;
++using namespace gsmlib;
++
++static const int holdoff[] = {2000000, 1000000, 400000};
++static const int holdoffArraySize = sizeof(holdoff)/sizeof(int);
++  
++// alarm handling for socket read/write
++// the timerMtx is necessary since several threads cannot use the
++// timer indepently of each other
++
++static pthread_mutex_t timerMtx = PTHREAD_MUTEX_INITIALIZER;
++#define pthread_mutex_lock(x) 
++#define pthread_mutex_unlock(x) 
++
++// for non-GNU systems, define alarm()
++#ifndef HAVE_ALARM
++unsigned int alarm(unsigned int seconds)
++{
++  struct itimerval old, newt;
++  newt.it_interval.tv_usec = 0;
++  newt.it_interval.tv_sec = 0;
++  newt.it_value.tv_usec = 0;
++  newt.it_value.tv_sec = (long int)seconds;
++  if (setitimer(ITIMER_REAL, &newt, &old) < 0)
++	return 0;
++  else
++	return old.it_value.tv_sec;
++}
++#endif
++
++// this routine is called in case of a timeout
++static void catchAlarm(int)
++{
++  // do nothing
++}
++
++// start timer
++static void startTimer()
++{
++  pthread_mutex_lock(&timerMtx);
++  struct sigaction newAction;
++  newAction.sa_handler = catchAlarm;
++  newAction.sa_flags = 0;
++  sigaction(SIGALRM, &newAction, NULL);
++  alarm(1);
++}
++
++// reset timer
++static void stopTimer()
++{
++  alarm(0);
++  sigaction(SIGALRM, NULL, NULL);
++  pthread_mutex_unlock(&timerMtx);
++}
++
++// KopeteUnixSerialPort members
++
++void KopeteUnixSerialPort::throwModemException(string message) throw(GsmException)
++{
++  ostringstream os;
++  os << message << " (errno: " << errno << "/" << strerror(errno) << ")";
++  throw GsmException(os.str(), OSError, errno);
++}
++
++void KopeteUnixSerialPort::putBack(unsigned char c)
++{
++  assert(_oldChar == -1);
++  _oldChar = c;
++}
++
++int KopeteUnixSerialPort::readByte() throw(GsmException)
++{
++  if (_oldChar != -1)
++  {
++	int result = _oldChar;
++	_oldChar = -1;
++	return result;
++  }
++
++  unsigned char c;
++  int timeElapsed = 0;
++  struct timeval oneSecond;
++  bool readDone = false;
++
++  while (! readDone && timeElapsed < _timeoutVal)
++  {
++	if (interrupted())
++	  throwModemException("interrupted when reading from TA");
++
++	// setup fd_set data structure for select()
++	fd_set fdSet;
++	oneSecond.tv_sec = 1;
++	oneSecond.tv_usec = 0;
++	FD_ZERO(&fdSet);
++	FD_SET(_fd, &fdSet);
++
++	switch (select(FD_SETSIZE, &fdSet, NULL, NULL, &oneSecond))
++	{
++	case 1:
++	{
++	  int res = read(_fd, &c, 1);
++	  if (res != 1)
++		throwModemException("end of file when reading from TA");
++	  else
++		readDone = true;
++	  break;
++	}
++	case 0:
++	  ++timeElapsed;
++	  break;
++	default:
++	  if (errno != EINTR)
++		throwModemException("reading from TA");
++	  break;
++	}
++  }
++  if (! readDone)
++	throwModemException("timeout when reading from TA");
++
++#ifndef NDEBUG
++  if (debugLevel() >= 2)
++  {
++	// some useful debugging code
++	if (c == LF)
++	  cerr << "<LF>";
++	else if (c == CR)
++	  cerr << "<CR>";
++	else cerr << "<'" << (char) c << "'>";
++	cerr.flush();
++  }
++#endif
++  return c;
++}
++
++KopeteUnixSerialPort::KopeteUnixSerialPort(string device, speed_t lineSpeed,
++							   string initString, bool swHandshake)
++  throw(GsmException) :
++  _oldChar(-1), _timeoutVal(TIMEOUT_SECS)
++{
++	_readNotifier = NULL;
++	
++  struct termios t;
++
++  // open device
++  _fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
++  if (_fd == -1)
++	throwModemException("opening device");
++
++  // switch off non-blocking mode
++  int fdFlags;
++  if ((fdFlags = fcntl(_fd, F_GETFL)) == -1)
++  {
++	close(_fd);
++	throwModemException("getting file status flags failed");
++  }
++  fdFlags &= ~O_NONBLOCK;
++  if (fcntl(_fd, F_SETFL, fdFlags) == -1)
++  {
++	close(_fd);
++	throwModemException("switching of non-blocking mode failed");
++  }
++
++	// Set the close on exec flag
++	if ((fdFlags = fcntl(_fd, F_GETFD)) == -1)
++	{
++		close(_fd);
++		throwModemException("getting file status flags failed");
++	}
++	fdFlags |= FD_CLOEXEC;
++	if (fcntl(_fd, F_SETFD, fdFlags) == -1)
++	{
++		close(_fd);
++		throwModemException("switching of non-blocking mode failed");
++	}
++
++  long int saveTimeoutVal = _timeoutVal;
++  _timeoutVal = 3;
++  int initTries = holdoffArraySize;
++  while (initTries-- > 0)
++  {
++	// flush all pending output
++	tcflush(_fd, TCOFLUSH);
++
++	// toggle DTR to reset modem
++	int mctl = TIOCM_DTR;
++	if (ioctl(_fd, TIOCMBIC, &mctl) < 0 && errno != ENOTTY)
++	{
++	  close(_fd);
++	  throwModemException("clearing DTR failed");
++	}
++	// the waiting time for DTR toggling is increased with each loop
++	usleep(holdoff[initTries]);
++	if (ioctl(_fd, TIOCMBIS, &mctl) < 0 && errno != ENOTTY)
++	{
++	  close(_fd);
++	  throwModemException("setting DTR failed");
++	}
++	// get line modes
++	if (tcgetattr(_fd, &t) < 0)
++	{
++	  close(_fd);
++	  throwModemException("tcgetattr device");
++	}
++
++	// set line speed
++	cfsetispeed(&t, lineSpeed);
++	cfsetospeed(&t, lineSpeed);
++
++	// set the device to a sane state
++	t.c_iflag |= IGNPAR | (swHandshake ? IXON | IXOFF : 0);
++	t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL |
++				   (swHandshake ? 0 : IXON |  IXOFF)
++				   | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK);
++	t.c_oflag &= ~(OPOST);
++	// be careful, only touch "known" flags
++	t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD |
++				  (swHandshake ? CRTSCTS : 0 ));
++	t.c_cflag |= CS8 | CREAD | HUPCL | (swHandshake ? 0 : CRTSCTS) | CLOCAL;
++	t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
++				   ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
++	t.c_lflag |= NOFLSH;
++	t.c_cc[VMIN] = 1;
++	t.c_cc[VTIME] = 0;
++
++	t.c_cc[VSUSP] = 0;
++
++	// write back
++	if(tcsetattr (_fd, TCSANOW, &t) < 0)
++	{
++	  close(_fd);
++	  throwModemException("tcsetattr device");
++	}
++	// the waiting time for writing to the ME/TA is increased with each loop
++	usleep(holdoff[initTries]);
++
++	// flush all pending input
++	tcflush(_fd, TCIFLUSH);
++
++	try
++	{
++	  // reset modem
++	  putLine("ATZ");
++	  bool foundOK = false;
++	  int readTries = 5;
++	  while (readTries-- > 0)
++	  {
++		// for the first call getLine() waits only 3 seconds
++		// because of _timeoutVal = 3
++		string s = getLine();
++		if (s.find("OK") != string::npos ||
++			s.find("CABLE: GSM") != string::npos)
++		{
++		  foundOK = true;
++		  readTries = 0;		// found OK, exit loop
++		}
++		else if (s.find("ERROR") != string::npos)
++		  readTries = 0;		// error, exit loop
++	  }
++
++	  // set getLine/putLine timeout back to old value
++	  _timeoutVal = saveTimeoutVal;
++
++	  if (foundOK)
++	  {
++		// init modem
++		readTries = 5;
++		putLine("AT" + initString);
++		while (readTries-- > 0)
++		{
++		  string s = getLine();
++		  if (s.find("OK") != string::npos ||
++			  s.find("CABLE: GSM") != string::npos)
++		  {
++				_readNotifier = new QSocketNotifier(_fd, QSocketNotifier::Read);
++					connect( _readNotifier, SIGNAL(activated(int)), this, SIGNAL(activated()));
++				return;					// found OK, return
++		  }
++		}
++	  }
++	}
++	catch (GsmException &e)
++	{
++	  _timeoutVal = saveTimeoutVal;
++	  if (initTries == 0)
++	  {
++		close(_fd);
++		throw e;
++	  }
++	}
++  }
++  // no response after 3 tries
++  close(_fd);
++  throwModemException("reset modem failed");
++}
++
++string KopeteUnixSerialPort::getLine() throw(GsmException)
++{
++  string result;
++  int c;
++  while ((c = readByte()) >= 0)
++  {
++	while (c == CR)
++	{
++	  c = readByte();
++	}
++	if (c == LF)
++	  break;
++	result += c;
++  }
++
++#ifndef NDEBUG
++  if (debugLevel() >= 1)
++	cerr << "<-- " << result << endl;
++#endif
++
++  return result;
++}
++
++void KopeteUnixSerialPort::putLine(string line,
++							 bool carriageReturn) throw(GsmException)
++{
++#ifndef NDEBUG
++  if (debugLevel() >= 1)
++	cerr << "--> " << line << endl;
++#endif
++
++  if (carriageReturn) line += CR;
++  const char *l = line.c_str();
++  
++  int timeElapsed = 0;
++  struct timeval oneSecond;
++
++  ssize_t bytesWritten = 0;
++  while (bytesWritten < (ssize_t)line.length() && timeElapsed < _timeoutVal)
++  {
++	if (interrupted())
++	  throwModemException("interrupted when writing to TA");
++
++	// setup fd_set data structure for select()
++	fd_set fdSet;
++	oneSecond.tv_sec = 1;
++	oneSecond.tv_usec = 0;
++	FD_ZERO(&fdSet);
++	FD_SET(_fd, &fdSet);
++
++	switch (select(FD_SETSIZE, NULL, &fdSet, NULL, &oneSecond))
++	{
++	case 1:
++	{
++	  ssize_t bw = write(_fd, l + bytesWritten, line.length() - bytesWritten);
++	  if (bw < 0)
++		throwModemException("writing to TA");
++	  bytesWritten += bw;
++	  break;
++	}
++	case 0:
++	  ++timeElapsed;
++	  break;
++	default:
++	  if (errno != EINTR)
++		throwModemException("writing to TA");
++	  break;
++	}
++  }
++  
++  while (timeElapsed < _timeoutVal)
++  {
++	if (interrupted())
++	  throwModemException("interrupted when writing to TA");
++	::startTimer();
++	int res = tcdrain(_fd);		// wait for output to be read by TA
++	::stopTimer();
++	if (res == 0)
++	  break;
++	else
++	{
++	  assert(errno == EINTR);
++	  ++timeElapsed;
++	}
++  }
++  if (timeElapsed >= _timeoutVal)
++	throwModemException("timeout when writing to TA");
++
++  // echo CR LF must be removed by higher layer functions in gsm_at because
++  // in order to properly handle unsolicited result codes from the ME/TA
++}
++
++bool KopeteUnixSerialPort::wait(GsmTime timeout) throw(GsmException)
++{
++  fd_set fds;
++  FD_ZERO(&fds);
++  FD_SET(_fd, &fds);
++  return select(FD_SETSIZE, &fds, NULL, NULL, timeout) != 0;
++}
++
++// set timeout for read or write in seconds.
++void KopeteUnixSerialPort::setTimeOut(unsigned int timeout)
++{
++  _timeoutVal = timeout;
++}
++
++KopeteUnixSerialPort::~KopeteUnixSerialPort()
++{
++	delete _readNotifier;
++	_readNotifier = NULL;
++	if (_fd != -1)
++		close(_fd);
++}
++
++#include "kopete_unix_serial.moc"
++
++#endif
+--- kopete/protocols/sms/services/smssend.cpp	(revision 568672)
++++ kopete/protocols/sms/services/smssend.cpp	(revision 586398)
+@@ -67,8 +67,8 @@
+ 
+ 	m_provider = new SMSSendProvider(provider, prefix, m_account, this);
+ 
+-	connect( m_provider, SIGNAL(messageSent(const Kopete::Message &)), this, SIGNAL(messageSent(const Kopete::Message &)));
+-	connect( m_provider, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)), this, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)));
++	QObject::connect( m_provider, SIGNAL(messageSent(const Kopete::Message &)), this, SIGNAL(messageSent(const Kopete::Message &)));
++	QObject::connect( m_provider, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)), this, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)));
+ 
+ 	m_provider->send(msg);
+ }
+@@ -108,12 +108,12 @@
+ 		}
+ 	}
+ 
+-	connect (prefWidget->program, SIGNAL(textChanged(const QString &)),
++	QObject::connect (prefWidget->program, SIGNAL(textChanged(const QString &)),
+ 		this, SLOT(loadProviders(const QString&)));
+ 
+ 	prefWidget->program->setURL(prefix);
+ 
+-	connect(prefWidget->provider, SIGNAL(activated(const QString &)),
++	QObject::connect(prefWidget->provider, SIGNAL(activated(const QString &)),
+ 		this, SLOT(setOptions(const QString &)));
+ 
+ 	prefWidget->show();
+--- kopete/protocols/sms/services/gsmlib.cpp	(revision 0)
++++ kopete/protocols/sms/services/gsmlib.cpp	(revision 586398)
+@@ -0,0 +1,462 @@
++/*  *************************************************************************
++	*   copyright: (C) 2005 Justin Huff <jjhuff at mspin.net>                  *
++    *************************************************************************
++*/
++
++/*  *************************************************************************
++    *                                                                       *
++    * 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 "config.h"
++#ifdef INCLUDE_SMSGSM
++
++#include <qcombobox.h>
++#include <qlayout.h>
++#include <qapplication.h>
++#include <qevent.h>
++#include <qmutex.h>
++#include <qthread.h>
++#include <qcheckbox.h>
++
++#include <klocale.h>
++#include <kurlrequester.h>
++#include <kmessagebox.h>
++#include <kprocess.h>
++#include <kdebug.h>
++#include <kconfigbase.h>
++
++#include <unistd.h>
++#include <gsmlib/gsm_me_ta.h>
++#include <gsmlib/gsm_sms.h>
++#include <gsmlib/gsm_util.h>
++#include <gsmlib/gsm_error.h>
++
++#include "kopeteaccount.h"
++#include "kopeteuiglobal.h"
++#include "kopetemetacontact.h"
++#include "kopetecontactlist.h"
++#include "kopetechatsessionmanager.h"
++
++#include "gsmlib.h"
++#include "gsmlibprefs.h"
++#include "smsprotocol.h"
++#include "smscontact.h"
++
++#include "kopete_unix_serial.h"
++
++/////////////////////////////////////////////////////////////////////
++#define GSMLIB_EVENT_ID 245
++GSMLibEvent::GSMLibEvent(SubType t) : QCustomEvent(QEvent::User+GSMLIB_EVENT_ID)
++{
++	setSubType(t);
++}
++
++GSMLibEvent::SubType GSMLibEvent::subType()
++{
++	return m_subType;
++}
++
++void GSMLibEvent::setSubType(GSMLibEvent::SubType t)
++{
++	m_subType = t;
++}
++
++/////////////////////////////////////////////////////////////////////
++GSMLibThread::GSMLibThread(QString dev, GSMLib* parent)
++{
++	m_device = dev;
++	m_parent = parent;
++	m_run = true;
++	m_MeTa = NULL;
++}
++
++GSMLibThread::~GSMLibThread()
++{
++	m_run = false;
++}
++
++void GSMLibThread::stop()
++{
++	m_run = false;
++	kdDebug( 14160 ) << "Waiting from GSMLibThread to die"<<endl;
++	if( wait(4000) == false )
++		kdWarning( 14160 ) << "GSMLibThread didn't exit!"<<endl;
++}
++void GSMLibThread::run()
++{
++	if( doConnect() )
++	{
++		while( m_run )
++		{
++			pollForMessages();
++			sendMessageQueue();	
++		}
++	}
++
++	delete m_MeTa;
++	m_MeTa = NULL;
++	QApplication::postEvent(m_parent, new GSMLibEvent(GSMLibEvent::DISCONNECTED));
++	kdDebug( 14160 ) << "GSMLibThread exited"<<endl;
++}
++
++void GSMLibThread::send(const Kopete::Message& msg)
++{
++	if( m_MeTa )
++	{
++		m_outMessagesMutex.lock();
++		m_outMessages.push_back(msg);
++		m_outMessagesMutex.unlock();
++	}
++	else
++	{
++		GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT );
++		e->Reason = QString("GSMLib: Not Connected");
++		e->Message = msg;
++		QApplication::postEvent(m_parent, e);
++	}
++}
++
++
++bool GSMLibThread::doConnect()
++{
++	// open the port and ME/TA
++	try
++	{
++		kdDebug( 14160 ) << "Connecting to: '"<<m_device<<"'"<<endl;
++		
++		gsmlib::Ref<gsmlib::Port> port = new gsmlib::KopeteUnixSerialPort(m_device.latin1(), 9600, gsmlib::DEFAULT_INIT_STRING, false);
++		
++		kdDebug( 14160 ) << "Port created"<<endl;
++				
++		m_MeTa = new gsmlib::MeTa(port);
++		std::string dummy1, dummy2, receiveStoreName;
++		m_MeTa->getSMSStore(dummy1, dummy2, receiveStoreName );
++		m_MeTa->setSMSStore(receiveStoreName, 3);
++
++		m_MeTa->setMessageService(1);
++
++		// switch on SMS routing
++		m_MeTa->setSMSRoutingToTA(true, false, false, true);
++
++		m_MeTa->setEventHandler(this);
++		QApplication::postEvent(m_parent, new GSMLibEvent(GSMLibEvent::CONNECTED));
++		return true;
++	}
++	catch(gsmlib::GsmException &e)
++	{
++		kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl;
++		m_run = false;
++		return false;
++	}
++}
++
++void GSMLibThread::SMSReception(gsmlib::SMSMessageRef newMessage, SMSMessageType messageType)
++{
++	try
++	{
++		IncomingMessage m;
++		m.Type = messageType;
++		m.Message = newMessage;
++		
++		m_newMessages.push_back(m);
++	}
++	catch(gsmlib::GsmException &e)
++	{
++		kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl;
++		m_run = false;
++	}
++}
++
++void GSMLibThread::SMSReceptionIndication(std::string storeName, unsigned int index, SMSMessageType messageType)
++{
++	kdDebug( 14160 ) << k_funcinfo << "New Message in store: "<<storeName.c_str() << endl;
++
++	try
++	{
++		if( messageType != gsmlib::GsmEvent::NormalSMS )
++			return;
++		
++		IncomingMessage m;
++		m.Index = index;
++		m.StoreName = storeName.c_str();
++		m.Type = messageType;
++		m_newMessages.push_back(m);
++	}
++	catch(gsmlib::GsmException &e)
++	{
++		kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl;
++		m_run = false;
++	}
++}
++
++void GSMLibThread::pollForMessages( )
++{
++	if( m_MeTa == NULL )
++		return;
++	
++	try
++	{
++		struct timeval timeoutVal;
++		timeoutVal.tv_sec = 1;
++		timeoutVal.tv_usec = 0;
++		m_MeTa->waitEvent(&timeoutVal);
++		
++		MessageList::iterator it;
++		for( it=m_newMessages.begin(); it!=m_newMessages.end(); it++)
++		{
++			IncomingMessage m = *it;
++			
++			// Do we need to fetch it from the ME?
++			if( m.Message.isnull() )
++			{
++				gsmlib::SMSStoreRef store = m_MeTa->getSMSStore(m.StoreName.latin1());
++				store->setCaching(false);
++
++				m.Message = (*store.getptr())[m.Index].message();
++				store->erase(store->begin() + m.Index);
++			}
++
++			GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::NEW_MESSAGE );
++			e->Text = m.Message->userData().c_str();
++			e->Number = m.Message->address().toString().c_str();
++
++			QApplication::postEvent(m_parent, e);
++
++		}
++		m_newMessages.clear();
++	}
++	catch(gsmlib::GsmException &e)
++	{
++		kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl;
++		m_run = false;
++	}
++}
++
++void GSMLibThread::sendMessageQueue()
++{
++	QMutexLocker _(&m_outMessagesMutex);
++	
++	if(m_outMessages.size() == 0 )
++		return;
++
++	KopeteMessageList::iterator it;
++	for( it=m_outMessages.begin(); it!=m_outMessages.end(); it++)
++		sendMessage(*it);
++	m_outMessages.clear();
++}
++
++void GSMLibThread::sendMessage(const Kopete::Message& msg)
++{
++	QString reason;
++
++	if (!m_MeTa)
++	{
++		GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT );
++		e->Reason = QString("GSMLib: Not Connected");
++		e->Message = msg;
++		QApplication::postEvent(m_parent, e);
++	}
++
++	QString message = msg.plainBody();
++	QString nr = msg.to().first()->contactId();
++
++	// send SMS
++	try
++	{
++		gsmlib::Ref<gsmlib::SMSSubmitMessage> submitSMS = new gsmlib::SMSSubmitMessage();
++		gsmlib::Address destAddr( nr.latin1() );
++		submitSMS->setDestinationAddress(destAddr);
++		m_MeTa->sendSMSs(submitSMS, message.latin1(), true);
++		
++		GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_SENT );
++		e->Message = msg;
++		QApplication::postEvent(m_parent, e);
++	}
++	catch(gsmlib::GsmException &e)
++	{
++		GSMLibEvent* ev = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT );
++		ev->Reason = QString("GSMLib: ") + e.what();
++		ev->Message = msg;
++		QApplication::postEvent(m_parent, ev);
++	}
++}
++
++/////////////////////////////////////////////////////////////////////
++
++GSMLib::GSMLib(Kopete::Account* account)
++	: SMSService(account)
++{
++	prefWidget = 0L;
++	m_thread = NULL;
++	
++	loadConfig();
++}
++
++GSMLib::~GSMLib()
++{
++	disconnect();
++}
++
++void GSMLib::saveConfig()
++{
++	if( m_account != NULL )
++	{
++		KConfigGroup* c = m_account->configGroup();
++
++		c->writeEntry(QString("%1:%2").arg("GSMLib").arg("Device"), m_device);
++	}
++}
++
++void GSMLib::loadConfig()
++{
++	m_device = "/dev/bluetooth/rfcomm0";
++	if( m_account != NULL )
++	{
++		QString temp;
++		KConfigGroup* c = m_account->configGroup();
++		
++		temp = c->readEntry(QString("%1:%2").arg("GSMLib").arg("Device"), QString::null);
++		if( temp != QString::null )
++			m_device = temp;
++	}
++}
++
++void GSMLib::connect()
++{
++	
++	m_thread = new GSMLibThread(m_device, this);
++	m_thread->start();
++	
++}
++
++void GSMLib::disconnect()
++{
++	kdDebug( 14160 ) << k_funcinfo <<endl;
++
++	if( m_thread )
++	{
++		m_thread->stop();
++		delete m_thread;
++		m_thread = NULL;
++		emit disconnected();
++	}
++
++}
++
++void GSMLib::setWidgetContainer(QWidget* parent, QGridLayout* layout)
++{
++	m_parent = parent;
++	m_layout = layout;
++	QWidget *configWidget = configureWidget(parent);
++	layout->addMultiCellWidget(configWidget, 0, 1, 0, 1);
++	configWidget->show();
++}
++
++void GSMLib::send(const Kopete::Message& msg)
++{
++	m_thread->send(msg);
++}
++
++QWidget* GSMLib::configureWidget(QWidget* parent)
++{
++
++	if (prefWidget == 0L)
++		prefWidget = new GSMLibPrefsUI(parent);
++
++	loadConfig();
++	prefWidget->device->setURL(m_device);
++
++	return prefWidget;
++}
++
++void GSMLib::savePreferences()
++{
++	if( prefWidget )
++	{
++		m_device = prefWidget->device->url();
++	}
++	saveConfig();
++}
++
++int GSMLib::maxSize()
++{
++	return 160;
++}
++
++void GSMLib::customEvent(QCustomEvent* e)
++{
++	if( e->type() != QEvent::User+GSMLIB_EVENT_ID )
++		return;
++
++	if( m_account == NULL )
++		return;
++
++	GSMLibEvent* ge = (GSMLibEvent*)e;
++	
++	kdDebug( 14160 ) << "Got event "<<ge->subType()<<endl;
++	switch( ge->subType() )
++	{
++		case GSMLibEvent::CONNECTED:
++			emit connected();
++			break;
++		case GSMLibEvent::DISCONNECTED:
++			disconnect();
++			break;
++		case GSMLibEvent::MSG_SENT:
++			emit messageSent(ge->Message);
++			break;
++		case GSMLibEvent::MSG_NOT_SENT:
++			emit messageNotSent(ge->Message, ge->Reason);
++			break;
++		case GSMLibEvent::NEW_MESSAGE:
++		{
++			QString nr = ge->Number;
++			QString text = ge->Text;
++			
++			// Locate a contact
++			SMSContact* contact = static_cast<SMSContact*>( m_account->contacts().find( nr ));
++			if ( contact==NULL )
++			{
++				// No contact found, make a new one
++				Kopete::MetaContact* metaContact = new Kopete::MetaContact ();
++				metaContact->setTemporary ( true );
++				contact = new SMSContact(m_account, nr, nr, metaContact );
++				Kopete::ContactList::self ()->addMetaContact( metaContact );
++				contact->setOnlineStatus( SMSProtocol::protocol()->SMSOnline );
++			}
++			
++			// Deliver the msg
++			Kopete::Message msg( contact, m_account->myself(), text, Kopete::Message::Inbound, Kopete::Message::RichText );
++			contact->manager(Kopete::Contact::CanCreate)->appendMessage( msg );
++			break;
++		}
++	}
++}
++
++
++
++
++const QString& GSMLib::description()
++{
++	QString url = "http://www.pxh.de/fs/gsmlib/";
++	m_description = i18n("<qt>GSMLib is a library (and utilities) for sending SMS via a GSM device. The program can be found on <a href=\"%1\">%1</a></qt>").arg(url).arg(url);
++	return m_description;
++}
++
++#include "gsmlib.moc"
++
++#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:
++
+--- kopete/protocols/sms/smscontact.cpp	(revision 568672)
++++ kopete/protocols/sms/smscontact.cpp	(revision 586398)
+@@ -24,10 +24,10 @@
+ #include "kopetechatsessionmanager.h"
+ #include "kopeteaccount.h"
+ #include "kopeteuiglobal.h"
+-#include "serviceloader.h"
+ 
+ #include "smscontact.h"
+ #include "smsprotocol.h"
++#include "smsservice.h"
+ #include "smsaccount.h"
+ #include "smsuserpreferences.h"
+ 
+@@ -35,18 +35,18 @@
+ 	const QString &displayName, Kopete::MetaContact *parent )
+ : Kopete::Contact( _account, phoneNumber, parent ), m_phoneNumber( phoneNumber )
+ {
+-	kdWarning( 14160 ) << k_funcinfo << " this = " << this << ", phone = " << phoneNumber << endl;
++//	kdWarning( 14160 ) << k_funcinfo << " this = " << this << ", phone = " << phoneNumber << endl;
+ 	setNickName( displayName );
+ 
+ 	m_msgManager = 0L;
+ 	m_actionPrefs = 0L;
+ 
+-	setOnlineStatus( SMSProtocol::protocol()->SMSUnknown );
++	if( account()->isConnected() )
++		setOnlineStatus( SMSProtocol::protocol()->SMSOnline );
+ }
+ 
+ void SMSContact::slotSendingSuccess(const Kopete::Message &msg)
+ {
+-//	KMessageBox::information(Kopete::UI::Global::mainWidget(), i18n("Message sent"), output.join("\n"), i18n("Message Sent"));
+ 	manager(Kopete::Contact::CanCreate)->messageSucceeded();
+ 	manager(Kopete::Contact::CanCreate)->appendMessage((Kopete::Message &)msg);
+ }
+@@ -70,7 +70,6 @@
+ 
+ Kopete::ChatSession* SMSContact::manager( Kopete::Contact::CanCreateFlags canCreate  )
+ {
+-	kdWarning( 14160 ) << k_funcinfo << " this = " << this << endl;
+ 	if ( m_msgManager || canCreate != Kopete::Contact::CanCreate )
+ 	{
+ 		return m_msgManager;
+@@ -81,9 +80,8 @@
+ 		contacts.append(this);
+ 		m_msgManager = Kopete::ChatSessionManager::self()->create(account()->myself(), contacts, protocol());
+ 		connect(m_msgManager, SIGNAL(messageSent(Kopete::Message&, Kopete::ChatSession*)),
+-		this, SLOT(slotSendMessage(Kopete::Message&)));
++			account(), SLOT(slotSendMessage(Kopete::Message&)));
+ 		connect(m_msgManager, SIGNAL(destroyed()), this, SLOT(slotChatSessionDestroyed()));
+-		connect(this, SIGNAL(messageSuccess()), m_msgManager, SIGNAL(messageSuccess()));
+ 		return m_msgManager;
+ 	}
+ }
+@@ -93,48 +91,13 @@
+ 	m_msgManager = 0L;
+ }
+ 
+-void SMSContact::slotSendMessage(Kopete::Message &msg)
+-{
+-	kdWarning( 14160 ) << k_funcinfo << " this = " << this << endl;
+-	QString sName = account()->configGroup()->readEntry("ServiceName", QString::null);
+ 
+-	SMSService *s = ServiceLoader::loadService(sName, account());
+-
+-	if (s == 0L) return;
+-
+-	connect (s, SIGNAL(messageSent(const Kopete::Message &)), this, SLOT(slotSendingSuccess(const Kopete::Message &)));
+-	connect (s, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)), this, SLOT(slotSendingFailure(const Kopete::Message &, const QString &)));
+-
+-	int msgLength = msg.plainBody().length();
+-
+-	if (s->maxSize() == -1)
+-		s->send(msg);
+-	else if (s->maxSize() < msgLength)
+-	{	if (dynamic_cast<SMSAccount *>(account())->splitNowMsgTooLong(s->maxSize(), msgLength))
+-			for (int i=0; i < msgLength / s->maxSize() + 1; i++)
+-			{	QString text = msg.plainBody();
+-				text = text.mid( s->maxSize() * i, s->maxSize() );
+-				Kopete::Message m( msg.from(), msg.to(), text, Kopete::Message::Outbound);
+-				s->send(m);
+-			}
+-		else
+-			slotSendingFailure(msg, i18n("Message too long."));
+-	}
+-	else
+-		s->send(msg);
+-
+-//	delete s;
+-
+-	kdWarning( 14160 ) << "<<<" << endl;
+-}
+-
+ void SMSContact::slotUserInfo()
+ {
+ }
+ 
+ void SMSContact::deleteContact()
+ {
+-	kdWarning( 14160 ) << k_funcinfo << " this = " << this << endl;
+ 	deleteLater();
+ }
+ 
+--- kopete/protocols/sms/smsaccount.cpp	(revision 568672)
++++ kopete/protocols/sms/smsaccount.cpp	(revision 586398)
+@@ -15,6 +15,7 @@
+ */
+ 
+ #undef KDE_NO_COMPAT
++
+ #include <kconfigbase.h>
+ #include <kaction.h>
+ #include <kpopupmenu.h>
+@@ -27,6 +28,8 @@
+ 
+ #include "kopeteuiglobal.h"
+ 
++#include "serviceloader.h"
++
+ #include "smsaccount.h"
+ #include "smsprotocol.h"
+ #include "smscontact.h"
+@@ -36,11 +39,27 @@
+ {
+ 	setMyself( new SMSContact(this, accountID, accountID, Kopete::ContactList::self()->myself()) );
+ 	loadConfig();
+-	connect();
++	myself()->setOnlineStatus( SMSProtocol::protocol()->SMSOffline );
++
++	QString sName = configGroup()->readEntry("ServiceName", QString::null);
++	theService = ServiceLoader::loadService(sName, this);
++	
++	if( theService )
++	{
++		QObject::connect (theService, SIGNAL(messageSent(const Kopete::Message &)), 
++					this, SLOT(slotSendingSuccess(const Kopete::Message &)));
++		QObject::connect (theService, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)), 
++					this, SLOT(slotSendingFailure(const Kopete::Message &, const QString &)));
++		QObject::connect (theService, SIGNAL(connected()), this, SLOT(slotConnected()));
++		QObject::connect (theService, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
++	}
++	
+ }
+ 
+ SMSAccount::~SMSAccount()
+ {
++	delete theService;
++	theService = NULL;
+ }
+ 
+ void SMSAccount::loadConfig()
+@@ -56,8 +75,12 @@
+ 		theNumber.replace(0, 1, theSubCode);
+ }
+ 
+-const bool SMSAccount::splitNowMsgTooLong(int max, int msgLength)
++const bool SMSAccount::splitNowMsgTooLong(int msgLength)
+ {
++	if( theService == NULL )
++		return false;
++	
++	int max = theService->maxSize();
+ 	if(theLongMsgAction == ACT_CANCEL) return false;
+ 	if(theLongMsgAction == ACT_SPLIT) return true;
+ 	if(KMessageBox::questionYesNo(Kopete::UI::Global::mainWidget(), i18n("This message is longer than the maximum length (%1). Should it be divided to %2 messages?").arg(max).arg(msgLength / max + 1),
+@@ -73,21 +96,79 @@
+ 
+ void SMSAccount::connect(const Kopete::OnlineStatus&)
+ {
+-	myself()->setOnlineStatus( SMSProtocol::protocol()->SMSOnline );
++	myself()->setOnlineStatus( SMSProtocol::protocol()->SMSConnecting );
++	if( theService )
++		theService->connect();
+ }
+ 
+-KActionMenu* SMSAccount::actionMenu()
++void SMSAccount::slotConnected()
+ {
+-	KActionMenu *theActionMenu = Kopete::Account::actionMenu();
+-
+-	return theActionMenu;
++	myself()->setOnlineStatus( SMSProtocol::protocol()->SMSOnline );
++	setAllContactsStatus( SMSProtocol::protocol()->SMSOnline );
+ }
+ 
+ void SMSAccount::disconnect()
+ {
++	if( theService )
++		theService->disconnect();
++}
++
++void SMSAccount::slotDisconnected()
++{
+ 	myself()->setOnlineStatus( SMSProtocol::protocol()->SMSOffline );
++	setAllContactsStatus( SMSProtocol::protocol()->SMSOffline );
+ }
+ 
++void SMSAccount::slotSendMessage(Kopete::Message &msg)
++{
++	kdWarning( 14160 ) << k_funcinfo << " this = " << this << endl;
++
++	if(theService == 0L)
++		return;
++
++	int msgLength = msg.plainBody().length();
++
++	if( theService->maxSize() == -1 )
++	{
++		theService->send(msg);
++	}
++	else if( theService->maxSize() < msgLength )
++	{
++		if( splitNowMsgTooLong(msgLength) )
++		{
++			for (int i=0; i < msgLength / theService->maxSize() + 1; i++)
++			{
++				QString text = msg.plainBody();
++				text = text.mid( theService->maxSize() * i, theService->maxSize() );
++				Kopete::Message m( msg.from(), msg.to(), text, Kopete::Message::Outbound);
++				
++				theService->send(m);
++			}
++		}
++		else
++			slotSendingFailure(msg, i18n("Message too long."));
++	}
++	else
++	{
++		theService->send(msg);
++	}
++
++}
++
++void SMSAccount::slotSendingSuccess(const Kopete::Message &msg)
++{
++	SMSContact* c = dynamic_cast<SMSContact*>(msg.to().first());
++	if( c )
++		c->slotSendingSuccess(msg);
++}
++
++void SMSAccount::slotSendingFailure(const Kopete::Message &msg, const QString &error)
++{
++	SMSContact* c = dynamic_cast<SMSContact*>(msg.to().first());
++	if( c )
++		c->slotSendingFailure(msg, error);
++}
++
+ bool SMSAccount::createContact( const QString &contactId,
+ 	Kopete::MetaContact * parentContact )
+ {
+@@ -97,6 +178,12 @@
+ 		return false;
+ }
+ 
++KActionMenu* SMSAccount::actionMenu()
++{
++	KActionMenu *theActionMenu = Kopete::Account::actionMenu();
++	return theActionMenu;
++}
++
+ void SMSAccount::setOnlineStatus( const Kopete::OnlineStatus & status , const QString &reason)
+ {
+ 	if ( myself()->onlineStatus().status() == Kopete::OnlineStatus::Offline && status.status() == Kopete::OnlineStatus::Online )
+@@ -107,4 +194,9 @@
+ 		setAway( true, reason );
+ }
+ 
++SMSService* SMSAccount::service()
++{
++	return theService;
++}
++
+ #include "smsaccount.moc"
+--- kopete/protocols/sms/smscontact.h	(revision 568672)
++++ kopete/protocols/sms/smscontact.h	(revision 586398)
+@@ -53,15 +53,9 @@
+ public slots:
+ 	virtual void slotUserInfo();
+ 	virtual void deleteContact();
+-	void slotSendMessage(Kopete::Message &msg);
+-
+-private slots:
+ 	void slotSendingSuccess(const Kopete::Message &msg);
+ 	void slotSendingFailure(const Kopete::Message &msg, const QString &error);
+ 
+-signals:
+-	void messageSuccess();
+-
+ private slots:
+ 	void userPrefs();
+ 	void slotChatSessionDestroyed();
+--- kopete/protocols/sms/smsservice.cpp	(revision 568672)
++++ kopete/protocols/sms/smsservice.cpp	(revision 586398)
+@@ -38,6 +38,18 @@
+ 		savePreferences();
+ }
+ 
++// The Default impl simply flips a signal back
++void SMSService::connect()
++{
++	emit connected();
++}
++
++// The Default impl simply flips a signal back
++void SMSService::disconnect()
++{
++	emit disconnected();
++}
++
+ /*
+  * Local variables:
+  * c-indentation-style: k&r
+--- kopete/protocols/sms/smsprotocol.cpp	(revision 568672)
++++ kopete/protocols/sms/smsprotocol.cpp	(revision 586398)
+@@ -35,8 +35,8 @@
+ SMSProtocol::SMSProtocol(QObject *parent, const char *name, const QStringList &/*args*/)
+ : Kopete::Protocol( SMSProtocolFactory::instance(), parent, name ),
+ 	SMSOnline(  Kopete::OnlineStatus::Online,  25, this, 0,  QString::null,   i18n( "Online" ), i18n( "Online" ), Kopete::OnlineStatusManager::Online ),
+-	SMSUnknown( Kopete::OnlineStatus::Unknown, 25, this, 1,  QString::null,  i18n( "Unknown" ) ),
+-	SMSOffline( Kopete::OnlineStatus::Offline, 25, this, 2,  QString::null,   i18n( "Offline" ), i18n( "Offline" ), Kopete::OnlineStatusManager::Offline )
++	SMSConnecting( Kopete::OnlineStatus::Connecting,2, this, 3, QString::null,    i18n( "Connecting" ) ),
++	SMSOffline( Kopete::OnlineStatus::Offline, 0, this, 2,  QString::null,   i18n( "Offline" ), i18n( "Offline" ), Kopete::OnlineStatusManager::Offline )
+ {
+ 	if (s_protocol)
+ 		kdWarning( 14160 ) << k_funcinfo << "s_protocol already defined!" << endl;
+--- kopete/protocols/sms/smsaccount.h	(revision 568672)
++++ kopete/protocols/sms/smsaccount.h	(revision 586398)
+@@ -22,6 +22,7 @@
+ class KActionMenu;
+ class SMSProtocol;
+ class SMSContact;
++class SMSService;
+ class KProcess;
+ 
+ enum SMSMsgAction { ACT_ASK = 0, ACT_CANCEL, ACT_SPLIT };
+@@ -45,16 +46,26 @@
+ 	 *
+ 	 * Only ever call in case of message being too long - may result in user interaction.
+ 	 */
+-	const bool splitNowMsgTooLong(int max, int msgLength);
++	const bool splitNowMsgTooLong(int msgLength);
+ 
++	SMSService* service();
++
+ public slots:
+ 	void loadConfig();
++	void setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason = QString::null);
+ 
+-	void setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason = QString::null);
+ public slots:
+ 	virtual void connect(const Kopete::OnlineStatus& initial= Kopete::OnlineStatus());
+ 	virtual void disconnect();
++	virtual void slotSendMessage(Kopete::Message &msg);
+ 
++protected slots:
++	virtual void slotSendingSuccess(const Kopete::Message &msg);
++	virtual void slotSendingFailure(const Kopete::Message &msg, const QString &error);
++	virtual void slotConnected();
++	virtual void slotDisconnected();
++	
++
+ protected:
+ 	bool createContact(const QString &contactId,  Kopete::MetaContact *parentContact);
+ 
+@@ -62,6 +73,7 @@
+ 	bool theSubEnable;
+ 	QString theSubCode;
+ 	SMSMsgAction theLongMsgAction;
++	SMSService* theService;
+ };
+ 
+ #endif
+--- kopete/protocols/sms/serviceloader.cpp	(revision 568672)
++++ kopete/protocols/sms/serviceloader.cpp	(revision 586398)
+@@ -14,6 +14,8 @@
+     *************************************************************************
+ */
+ 
++#include "config.h"
++
+ #include <kmessagebox.h>
+ #include <klocale.h>
+ #include <kdebug.h>
+@@ -21,6 +23,9 @@
+ #include "serviceloader.h"
+ #include "smssend.h"
+ #include "smsclient.h"
++#ifdef INCLUDE_SMSGSM
++#	include "gsmlib.h"
++#endif
+ #include "kopeteuiglobal.h"
+ 
+ SMSService* ServiceLoader::loadService(const QString& name, Kopete::Account* account)
+@@ -32,6 +37,10 @@
+ 		s = new SMSSend(account);
+ 	else if (name == "SMSClient")
+ 		s = new SMSClient(account);
++#ifdef INCLUDE_SMSGSM
++	else if (name == "GSMLib")
++		s = new GSMLib(account);
++#endif
+ 	else
+ 	{
+ 		KMessageBox::sorry(Kopete::UI::Global::mainWidget(), i18n("Could not load service %1.").arg(name),
+@@ -47,6 +56,9 @@
+ 	QStringList toReturn;
+ 	toReturn.append("SMSSend");
+ 	toReturn.append("SMSClient");
++#ifdef INCLUDE_SMSGSM
++	toReturn.append("GSMLib");
++#endif	
+ 	return toReturn;
+ }
+ 
+--- kopete/protocols/sms/smsservice.h	(revision 568672)
++++ kopete/protocols/sms/smsservice.h	(revision 586398)
+@@ -56,10 +56,14 @@
+ 
+ public slots:
+ 	virtual void savePreferences() = 0;
++	virtual void connect();
++	virtual void disconnect();
+ 
+ signals:
+ 	void messageSent(const Kopete::Message &);
+ 	void messageNotSent(const Kopete::Message &, const QString &);
++	void connected();
++	void disconnected();
+ 
+ protected:
+ 	Kopete::Account* m_account;
+--- kopete/protocols/sms/smsprotocol.h	(revision 568672)
++++ kopete/protocols/sms/smsprotocol.h	(revision 586398)
+@@ -58,8 +58,8 @@
+ 	virtual Kopete::Account *createNewAccount(const QString &accountId);
+ 
+ 	const Kopete::OnlineStatus SMSOnline;
+-	const Kopete::OnlineStatus SMSUnknown;
+ 	const Kopete::OnlineStatus SMSOffline;
++	const Kopete::OnlineStatus SMSConnecting;
+ 
+ private:
+ 	static SMSProtocol *s_protocol;
+--- kopete/protocols/groupwise/gwaccount.h	(revision 568672)
++++ kopete/protocols/groupwise/gwaccount.h	(revision 586398)
+@@ -21,6 +21,8 @@
+ #ifndef GW_ACCOUNT_H
+ #define GW_ACCOUNT_H
+ 
++#include <kaction.h>
++
+ #include <kopetechatsessionmanager.h>
+ 
+ #include "gwerror.h"
+@@ -138,6 +140,7 @@
+ 	bool dontSync();
+ 	
+ 	void syncContact( GroupWiseContact * contact );
++	
+ public slots:
+ 
+ 	void slotTestRTFize();
+@@ -169,7 +172,19 @@
+ 	 * Manage the user's privacy settings
+ 	 */
+ 	void slotPrivacy();
++	
++	/**
++	 * Show a dialog to join a chatroom without first adding it to the contact list
++	 */
++	void slotJoinChatRoom();
++
++	/**
++	 * Slot informing GroupWise when a group is renamed
++	 */
+  	void slotKopeteGroupRenamed( Kopete::Group * );
++	/**
++	 * Slot informing GroupWise when a group is removed
++	 */
+ 	void slotKopeteGroupRemoved( Kopete::Group * );
+ 
+ 	// SERVER SIDE CONTACT LIST PROCESSING
+@@ -308,6 +323,7 @@
+ 	KActionMenu * m_actionMenu;
+ 	KAction * m_actionAutoReply;
+ 	KAction * m_actionManagePrivacy;
++	KAction * m_actionJoinChatRoom;
+ 	// Network code
+ 	KNetworkConnector * m_connector;
+ 	QCA::TLS * m_QCATLS;
+@@ -322,4 +338,22 @@
+ 	GWContactList * m_serverListModel;
+ };
+ 
++/**
++ * @internal
++ * An action that selects an OnlineStatus and provides a status message, but not using Kopete::Away, because the status message relates only to this status.
++ */
++/*class OnlineStatusMessageAction : public KAction
++{
++	Q_OBJECT
++  public:
++	OnlineStatusMessageAction ( const Kopete::OnlineStatus& status, const QString &text, const QString &message, const QIconSet &pix, QObject *parent=0, const char *name=0);
++  signals:
++	void activated( const Kopete::OnlineStatus& status, const QString & );
++  private slots:
++	void slotActivated();
++  private:
++	Kopete::OnlineStatus m_status;
++	QString m_message;
++};
++*/
+ #endif
+--- kopete/protocols/groupwise/gwmessagemanager.cpp	(revision 568672)
++++ kopete/protocols/groupwise/gwmessagemanager.cpp	(revision 586398)
+@@ -361,7 +361,7 @@
+ 		QWidget * w = ( view(false) ? dynamic_cast<KMainWindow*>( view(false)->mainWidget()->topLevelWidget() ) : 
+ 					Kopete::UI::Global::mainWidget() );
+ 		m_searchDlg = new KDialogBase( w, "invitesearchdialog", false, i18n( "Search for Contact to Invite" ), KDialogBase::Ok|KDialogBase::Cancel );
+-		m_search = new GroupWiseSearch( account(), QListView::Single, true, m_searchDlg, "invitesearchwidget" );
++		m_search = new GroupWiseContactSearch( account(), QListView::Single, true, m_searchDlg, "invitesearchwidget" );
+ 		m_searchDlg->setMainWidget( m_search );
+ 		connect( m_search, SIGNAL( selectionValidates( bool ) ), m_searchDlg, SLOT( enableButtonOK( bool ) ) );
+ 		m_searchDlg->enableButtonOK( false );
+--- kopete/protocols/groupwise/gwmessagemanager.h	(revision 568672)
++++ kopete/protocols/groupwise/gwmessagemanager.h	(revision 586398)
+@@ -24,7 +24,7 @@
+ class KDialogBase;
+ class GroupWiseAccount;
+ class GroupWiseContact;
+-class GroupWiseSearch;
++class GroupWiseContactSearch;
+ /**
+  * Specialised message manager, which tracks the GUID used by GroupWise to uniquely identify a given chat, and provides invite actions and logging and security indicators.  To instantiate call @ref GroupWiseAccount::chatSession().
+  * @author SUSE AG
+@@ -158,7 +158,7 @@
+ 	KAction *m_secure;
+ 	KAction *m_logging;
+ 	// search widget and dialog used for inviting contacts
+-	GroupWiseSearch * m_search;
++	GroupWiseContactSearch * m_search;
+ 	KDialogBase * m_searchDlg;
+ 	// contacts who have been invited to join but have not yet joined the chat
+ 	Kopete::ContactPtrList m_invitees;
+--- kopete/protocols/groupwise/gwcontactlist.cpp	(revision 568672)
++++ kopete/protocols/groupwise/gwcontactlist.cpp	(revision 586398)
+@@ -168,7 +168,7 @@
+ 		}
+ 	}
+ 	else
+-		kdDebug() << "  contact list is empty." << endl;
++		kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "  contact list is empty." << endl;
+ }
+ 
+ void GWContactList::clear()
+--- kopete/protocols/groupwise/gwcontact.cpp	(revision 568672)
++++ kopete/protocols/groupwise/gwcontact.cpp	(revision 586398)
+@@ -67,9 +67,7 @@
+ 	// would not fetch details for this contact if they contact you
+ 	// again from off-contact-list.
+ 	if ( metaContact()->isTemporary() )
+-		if ( Client * c = account()->client() )
+-			if ( UserDetailsManager * udm = c->userDetailsManager() )
+-				udm->removeContact( contactId() );
++		account()->client()->userDetailsManager()->removeContact( contactId() );
+ }
+ 
+ QString GroupWiseContact::dn() const
+@@ -91,8 +89,8 @@
+ 	if ( !details.fullName.isNull() )
+ 		setProperty( protocol()->propFullName, details.fullName );
+ 	m_archiving = details.archive;
+-	//if ( !details.awayMessage.isNull() )
+-		//setProperty( protocol()->propAwayMessage, details.awayMessage );
++	if ( !details.awayMessage.isNull() )
++		setProperty( protocol()->propAwayMessage, details.awayMessage );
+ 	
+ 	m_serverProperties = details.properties;
+ 	
+@@ -115,11 +113,8 @@
+ 	if ( details.status != GroupWise::Invalid )
+ 	{	
+ 		Kopete::OnlineStatus status = protocol()->gwStatusToKOS( details.status );
+-		//kdDebug( GROUPWISE_DEBUG_GLOBAL ) << "setting initial status to " << status.description() << endl;
+ 		setOnlineStatus( status );
+ 	}
+-	//else 
+-		//kdDebug( GROUPWISE_DEBUG_GLOBAL ) << "initial status is, not setting " << details.status << endl; 
+ }
+ 
+ GroupWiseProtocol *GroupWiseContact::protocol()
+--- kopete/protocols/groupwise/gwaccount.cpp	(revision 568672)
++++ kopete/protocols/groupwise/gwaccount.cpp	(revision 586398)
+@@ -57,6 +57,7 @@
+ #include "tasks/movecontacttask.h"
+ #include "tasks/updatecontacttask.h"
+ #include "tasks/updatefoldertask.h"
++#include "ui/gwchatsearchdialog.h"
+ #include "ui/gwprivacy.h"
+ #include "ui/gwprivacydialog.h"
+ #include "ui/gwreceiveinvitationdialog.h"
+@@ -79,9 +80,11 @@
+ 
+ 	m_actionAutoReply = new KAction ( i18n( "&Set Auto-Reply..." ), QString::null, 0, this,
+ 			SLOT( slotSetAutoReply() ), this, "actionSetAutoReply");
++	m_actionJoinChatRoom = new KAction ( i18n( "&Join Channel..." ), QString::null, 0, this,
++										 SLOT( slotJoinChatRoom() ), this, "actionJoinChatRoom");
+ 	m_actionManagePrivacy = new KAction ( i18n( "&Manage Privacy..." ), QString::null, 0, this,
+ 			SLOT( slotPrivacy() ), this, "actionPrivacy");
+-
++			
+ 	m_connector = 0;
+ 	m_QCATLS = 0;
+ 	m_tlsHandler = 0;
+@@ -104,6 +107,7 @@
+ 	m_actionManagePrivacy->setEnabled( isConnected() );
+ 	m_actionMenu->insert( m_actionManagePrivacy );
+ 	m_actionMenu->insert( m_actionAutoReply );
++	m_actionMenu->insert( m_actionJoinChatRoom );
+ 	/* Used for debugging */
+ 	/*
+ 	theActionMenu->insert( new KAction ( "Test rtfize()", QString::null, 0, this,
+@@ -454,11 +458,15 @@
+ void GroupWiseAccount::slotLoggedIn()
+ {
+ 	reconcileOfflineChanges();
+-	
++	// set local status display
+ 	myself()->setOnlineStatus( protocol()->groupwiseAvailable );
+-	if ( initialStatus() != Kopete::OnlineStatus(Kopete::OnlineStatus::Online) )
++	// set status on server
++	if ( initialStatus() != Kopete::OnlineStatus(Kopete::OnlineStatus::Online) &&
++		( ( GroupWise::Status )initialStatus().internalStatus() != GroupWise::Unknown ) )
++	{
++		kdDebug( GROUPWISE_DEBUG_GLOBAL ) << "Initial status is not online, setting status to " << initialStatus().internalStatus() << endl;
+ 		m_client->setStatus( ( GroupWise::Status )initialStatus().internalStatus(), m_initialReason, configGroup()->readEntry( "AutoReply" ) );
+-	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << "initial status was " << initialStatus().description() << ", initial reason was " << m_initialReason << endl;
++	}
+ }
+ 
+ void GroupWiseAccount::reconcileOfflineChanges()
+@@ -522,21 +530,6 @@
+ 			}
+ 			if ( !found )
+ 			{
+-// sync debugging output
+-#if 0
+-				kdDebug( GROUPWISE_DEBUG_GLOBAL ) << "contact ' " << c->dn() << " 'with instances: " << endl;
+-				for ( instIt = instances.begin(); instIt != instances.end(); ++instIt )
+-				{
+-					kdDebug() << "  id: " << (*instIt )->id << " parent: " << ::qt_cast<GWFolder*>( ( *instIt )->parent() )->id <<  endl;
+-				}
+-				kdDebug( GROUPWISE_DEBUG_GLOBAL ) << " in MC groups: " << endl;
+-				QPtrListIterator<Kopete::Group> grpIt( groups );
+-				while ( *grpIt )
+-				{
+-					kdDebug() << "  display name: " << (*grpIt)->displayName() << " id: " <<  (*grpIt)->pluginData(  protocol(), accountId() + " objectId" ) << endl;
+-					++grpIt;
+-				}
+-#endif
+ 				if ( c->metaContact()->contacts().count() == 1 )
+ 				{
+ 					if ( c->metaContact()->groups().count() == 1 )
+@@ -954,7 +947,7 @@
+ 		<< ", givenname" << details.givenName
+ 		<< ", status" << details.status
+ 		<< endl;
+-	if ( details.cn.lower() == accountId().lower().section('@', 0, 0) )
++	if ( details.cn.lower() == accountId().lower().section('@', 0, 0) ) // incase user set account ID foo at novell.com
+ 	{
+ 		kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << " - got our details in contact list, updating them" << endl;
+ 		GroupWiseContact * detailsOwner= static_cast<GroupWiseContact *>( myself() );
+@@ -1087,7 +1080,7 @@
+ 	Kopete::GroupList groupList = parentContact->groups();
+ 	for ( Kopete::Group *group = groupList.first(); group; group = groupList.next() )
+ 	{
+-		if ( group->type() == Kopete::Group::TopLevel || group->displayName() == i18n("Top Level") ) // no need to create it on the server
++		if ( group->type() == Kopete::Group::TopLevel ) // no need to create it on the server
+ 		{
+ 			topLevel = true;
+ 			continue;
+@@ -1396,6 +1389,11 @@
+ 	new GroupWisePrivacyDialog( this, Kopete::UI::Global::mainWidget(), "gwprivacydialog" );
+ }
+ 
++void GroupWiseAccount::slotJoinChatRoom()
++{
++	new GroupWiseChatSearchDialog( this, Kopete::UI::Global::mainWidget(), "gwjoinchatdialog" );
++}
++
+ bool GroupWiseAccount::isContactBlocked( const QString & dn )
+ {
+ 	if ( isConnected() )
+--- kopete/protocols/groupwise/libgroupwise/chatroommanager.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/chatroommanager.cpp	(revision 586398)
+@@ -0,0 +1,143 @@
++/*
++    Kopete Groupwise Protocol
++    chatroommanager.cpp - tracks our knowledge of server side chatrooms
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qmap.h>
++#include <qvaluelist.h>
++
++#include <kdebug.h>
++
++#include "client.h"
++#include "tasks/chatcountstask.h"
++#include "tasks/chatpropertiestask.h"
++#include "tasks/searchchattask.h"
++
++#include "chatroommanager.h"
++
++ChatroomManager::ChatroomManager( Client * parent, const char *name)
++	: QObject(parent, name), m_client( parent ), m_replace( false )
++{
++}
++
++ChatroomManager::~ChatroomManager()
++{
++}
++
++void ChatroomManager::update()
++{
++	if ( m_rooms.isEmpty() )
++		getChatrooms( false );
++	else
++		updateCounts();
++}
++
++GroupWise::ChatroomMap ChatroomManager::rooms()
++{
++	return m_rooms;
++}
++
++void ChatroomManager::getChatrooms( bool refresh )
++{
++	m_replace = !refresh;
++	SearchChatTask * sct = new SearchChatTask( m_client->rootTask() );
++	sct->search( ( refresh ? SearchChatTask::SinceLastSearch : SearchChatTask::FetchAll ) );
++	connect( sct, SIGNAL( finished() ), SLOT( slotGotChatroomList() ) );
++	sct->go( true );
++}
++
++void ChatroomManager::slotGotChatroomList()
++{
++	kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
++	SearchChatTask * sct = (SearchChatTask *)sender();
++	if ( sct )
++	{
++		if ( m_replace )
++			m_rooms.clear();
++		
++		QValueList<ChatroomSearchResult> roomsFound = sct->results();
++		QValueList<ChatroomSearchResult>::Iterator it = roomsFound.begin();
++		const QValueList<ChatroomSearchResult>::Iterator end = roomsFound.end();
++		for ( ; it != end; ++it )
++		{
++			GroupWise::Chatroom c( *it );
++			m_rooms.insert( c.displayName, c );
++		}
++	}
++	emit updated();
++}
++
++void ChatroomManager::updateCounts()
++{
++	ChatCountsTask * cct = new ChatCountsTask( m_client->rootTask() );
++	connect( cct, SIGNAL( finished() ), SLOT( slotGotChatCounts() ) );
++	cct->go( true );
++}
++
++void ChatroomManager::slotGotChatCounts()
++{
++	ChatCountsTask * cct = (ChatCountsTask *)sender();
++	if ( cct )
++	{
++		QMap< QString, int > newCounts = cct->results();
++		QMap< QString, int >::iterator it = newCounts.begin();
++		const QMap< QString, int >::iterator end = newCounts.end();
++
++		for ( ; it != end; ++it )
++			if ( m_rooms.contains( it.key() ) )
++				m_rooms[ it.key() ].participantsCount = it.data();
++	}
++	emit updated();
++}
++
++void ChatroomManager::requestProperties( const QString & displayName )
++{
++	if ( 0 /*m_rooms.contains( displayName ) */)
++		emit gotProperties( m_rooms[ displayName ] );	
++	else
++	{
++		ChatPropertiesTask * cpt = new ChatPropertiesTask( m_client->rootTask() );
++		cpt->setChat( displayName );
++		connect ( cpt, SIGNAL( finished() ), SLOT( slotGotChatProperties() ) );
++		cpt->go( true );
++	}
++}
++
++void ChatroomManager::slotGotChatProperties()
++{
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
++	ChatPropertiesTask * cpt = (ChatPropertiesTask *)sender();
++	if ( cpt )
++	{
++		Chatroom room = m_rooms[ cpt->m_chat ];
++		room.displayName = cpt->m_chat;
++		room.ownerDN = cpt->m_ownerDn;
++		room.description = cpt->m_description;
++		room.disclaimer = cpt->m_disclaimer;
++		room.query = cpt->m_query;
++		room.archive = ( cpt->m_archive == "0" );
++		room.maxUsers = cpt->m_maxUsers.toInt();
++		room.topic = cpt->m_topic;
++		room.creatorDN = cpt->m_creatorDn;
++		room.createdOn = cpt->m_creationTime;
++		room.acl = cpt->m_aclEntries;
++		room.chatRights = cpt->m_rights;
++		m_rooms.insert( room.displayName, room );
++		emit gotProperties( room );
++	}
++}
++
++#include "chatroommanager.moc"
+--- kopete/protocols/groupwise/libgroupwise/coreprotocol.cpp	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/coreprotocol.cpp	(revision 586398)
+@@ -380,9 +380,10 @@
+ 	{
+ 		*m_din >> val;
+ 
+-		// if is 'HTTP', it's a Response
+-		if ( qstrncmp( (const char *)&val, "HTTP", strlen( "HTTP" ) ) == 0 )
+-		{
++		// if is 'HTTP', it's a Response. PTTH it is after endian conversion
++		if ( !qstrncmp( (const char *)&val, "HTTP", strlen( "HTTP" ) )  ||
++		     !qstrncmp( (const char *)&val, "PTTH", strlen( "PTTH" ) )
++		) {
+ 			Transfer * t = m_responseProtocol->parse( wire, bytesParsed );
+ 			if ( t )
+ 			{
+--- kopete/protocols/groupwise/libgroupwise/userdetailsmanager.cpp	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/userdetailsmanager.cpp	(revision 586398)
+@@ -41,6 +41,7 @@
+ {
+ 	if ( dn == m_client->userDN() )
+ 		return true;
++	// TODO: replace with m_detailsMap.contains( dn );
+ 	QStringList::Iterator found = m_detailsMap.keys().find( dn );
+ 	// we always know the local user's details, so don't look them up
+ 	return ( found !=m_detailsMap.keys().end() );
+--- kopete/protocols/groupwise/libgroupwise/client.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/client.h	(revision 586398)
+@@ -28,6 +28,7 @@
+ #include "rtf2html.h"
+ #include "transfer.h"
+ 
++class ChatroomManager;
+ class PrivacyManager;
+ class RequestFactory;
+ class UserDetailsManager;
+@@ -205,14 +206,26 @@
+ 		 * Host's IP address
+ 		 */
+ 		QCString ipAddress();
+-		
++
+ 		/**
++		 * Obtain the list of custom statuses stored on the server 
++		 */
++		QValueList<GroupWise::CustomStatus> customStatuses();
++
++		/**
+ 		 * Get a reference to the RequestFactory for this Client. 
+ 		 * Used by Tasks to generate Requests with an ascending sequence of transaction IDs 
+ 		 * for this connection
+ 		 */
+ 		RequestFactory * requestFactory();
++
+ 		/**
++		 * Get a reference to the ChatroomManager for this Client.
++		 * This is constructed the first time this function is called.  Used to manipulate chat rooms on the server.
++		 */
++		ChatroomManager * chatroomManager();
++
++		/**
+ 		 * Get a reference to the UserDetailsManager for this Client.
+ 		 * Used to track known user details and issue new details requests
+ 		 */
+@@ -353,6 +366,10 @@
+ 		 */ 
+ 		void ct_messageReceived( const ConferenceEvent & );
+ 		void jct_joinConfCompleted();
++		/**
++		 * Receive a custom status during login and record it
++		 */
++		void lt_gotCustomStatus( const GroupWise::CustomStatus & );
+ 
+ 		/**
+ 		 * Used by the client stream to notify errors to upper layers.
+--- kopete/protocols/groupwise/libgroupwise/gwerror.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/gwerror.h	(revision 586398)
+@@ -155,23 +155,19 @@
+ 		QString rtfMessage;
+ 	};
+ 
+-	/**
+-	* Represents an instance of a contact in the server side contact list
+-	*/
+-// 	struct ContactListInstance
+-// 	{
+-// 		int objectId;
+-// 		int parentId;
+-// 		int sequence;
+-// 	};
+-
+ 	struct UserSearchQueryTerm
+ 	{
+ 		QString field;
+ 		QString argument;
+ 		int operation;
+ 	};
+-	
++
++	struct CustomStatus
++	{
++		GroupWise::Status status;
++		QString name;
++		QString autoReply;
++	};
+ }
+ 
+ // temporary typedef pending implementation
+--- kopete/protocols/groupwise/libgroupwise/gwchatrooms.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/gwchatrooms.h	(revision 586398)
+@@ -0,0 +1,78 @@
++/*
++    Kopete Groupwise Protocol
++    gwchatrooms.h - Data types for group chat
++
++    Copyright (c) 2005      SUSE Linux AG	 	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qdatetime.h>
++#include <qvaluelist.h>
++
++#ifndef GROUPWISE_CHATROOMS_H
++#define GROUPWISE_CHATROOMS_H
++
++namespace GroupWise
++{
++	
++class ChatContact
++{
++	public:
++		QString dn;
++		uint chatRights;
++};
++typedef QValueList<GroupWise::ChatContact> ChatContactList;
++
++struct ChatroomSearchResult
++{
++	QString name;
++	QString ownerDN;
++	uint participants;
++};
++
++
++class Chatroom
++{
++	public:
++		enum UserStatus { Participating, NotParticipating };
++		enum Rights { Read = 1, Write = 2, Modify = 4, Moderator = 8, Owner = 16 };
++		QString creatorDN;
++		QString description;
++		QString disclaimer;
++		QString displayName;
++		QString objectId;
++		QString ownerDN;
++		QString query;
++		QString topic;
++		bool archive;
++		uint maxUsers;
++		uint chatRights;
++		UserStatus userStatus;
++		QDateTime createdOn;
++		uint participantsCount;
++		// haveParticipants, Acl, Invites indicate if we have obtained these lists from the server, so we can tell 'not fetched list' and 'fetched empty list' apart.
++		bool haveParticipants;
++		ChatContactList	participants;
++		bool haveAcl;
++		ChatContactList acl;
++		bool haveInvites;
++		ChatContactList invites;
++			
++		Chatroom() { archive = false; maxUsers = 0; chatRights = 0; participantsCount = 0; haveParticipants = false; haveAcl = false; haveInvites = false; }
++		Chatroom( ChatroomSearchResult csr ) { archive = false; maxUsers = 0; chatRights = 0; participantsCount = csr.participants; haveParticipants = false; haveAcl = false; haveInvites = false; ownerDN = csr.ownerDN; displayName = csr.name; }
++};
++
++typedef QValueList<Chatroom> ChatroomList;
++typedef QMap<QString, Chatroom> ChatroomMap;
++}
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchtask.cpp	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchtask.cpp	(revision 586398)
+@@ -1,137 +0,0 @@
+-/*
+-    Kopete Groupwise Protocol
+-    searchtask.cpp - high level search for users on the server - spawns PollSearchResultsTasks
+-
+-    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
+-    
+-    Based on Iris, Copyright (C) 2003  Justin Karneges
+-
+-    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
+- 
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#include <qdatetime.h>
+-#include <qtimer.h>
+-
+-#include "client.h"
+-#include "gwerror.h"
+-#include "gwfield.h"
+-#include "response.h"
+-
+-#include "pollsearchresultstask.h"
+-
+-#include "searchtask.h"
+-
+-// the delay we allow the server to initially do the search
+-#define GW_POLL_INITIAL_DELAY 1000
+-// the maximum number of times to poll the server
+-#define GW_POLL_MAXIMUM 5
+-// the frequency between subsequent polls
+-#define GW_POLL_FREQUENCY_MS 8000
+-
+-using namespace GroupWise;
+-
+-SearchTask::SearchTask(Task* parent): RequestTask(parent), m_polls( 0 )
+-{
+-}
+-
+-
+-SearchTask::~SearchTask()
+-{
+-}
+-
+-void SearchTask::search( const QValueList<UserSearchQueryTerm> & query )
+-{
+-	m_queryHandle = QString::number( QDateTime::currentDateTime().toTime_t () );
+-	Field::FieldList lst;
+-	if ( query.isEmpty() )
+-	{
+-		setError( 1, "no query terms" );
+-		return;
+-	}
+-	// object Id identifies the search for later reference
+-	lst.append( new Field::SingleField( NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, m_queryHandle ) );
+-	QValueList<UserSearchQueryTerm>::ConstIterator it = query.begin();
+-	const QValueList<UserSearchQueryTerm>::ConstIterator end = query.end();
+-	for ( ; it != end; ++it )
+-	{
+-		Field::SingleField * fld =  new Field::SingleField( (*it).field.ascii(), (*it).operation, 0, NMFIELD_TYPE_UTF8, (*it).argument );
+-		lst.append( fld );
+-	}
+-	//lst.append( new Field::SingleField( "Given Name", 0, NMFIELD_TYPE_UTF8, [ NMFIELD_METHOD_EQUAL | NMFIELD_METHOD_MATCHBEGIN | NMFIELD_METHOD_MATCHEND | NMFIELD_METHOD_SEARCH ], searchTerm );
+-	// Or "Surname", NM_A_SZ_USERID, NM_A_SZ_TITLE, NM_A_SZ_DEPARTMENT in other fields
+-	
+-	createTransfer( "createsearch", lst );
+-}
+-
+-bool SearchTask::take( Transfer * transfer )
+-{
+-	if ( !forMe( transfer ) )
+-		return false;
+-	Response * response = dynamic_cast<Response *>( transfer );
+-	if ( !response )
+-		return false;
+-	if ( response->resultCode() )
+-	{
+-		kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "got return code in response << " << response->resultCode() << endl;
+-		setError( response->resultCode() );
+-		return true;
+-	}
+-	// now start the results poll timer
+-	QTimer::singleShot( GW_POLL_INITIAL_DELAY, this, SLOT( slotPollForResults() ) );
+-	return true;
+-}
+-
+-void SearchTask::slotPollForResults()
+-{
+-	//create a PollSearchResultsTask
+-	PollSearchResultsTask * psrt = new PollSearchResultsTask( client()->rootTask() );
+-	psrt->poll( m_queryHandle );
+-	connect( psrt, SIGNAL( finished() ), SLOT( slotGotPollResults() ) );
+-	psrt->go( true );
+-}
+-
+-void SearchTask::slotGotPollResults()
+-{
+-	PollSearchResultsTask * psrt = (PollSearchResultsTask *)sender();
+-	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "status code is " << psrt->queryStatus() << endl;
+-	m_polls++;
+-	switch ( psrt->queryStatus() )
+-	{
+-		case PollSearchResultsTask::Pending:
+-		case PollSearchResultsTask::InProgess:
+-			if ( m_polls < GW_POLL_MAXIMUM ) // restart timer
+-				QTimer::singleShot( GW_POLL_FREQUENCY_MS, this, SLOT( slotPollForResults() ) );
+-			else
+-				setSuccess( psrt->statusCode() );
+-			break;
+-		case PollSearchResultsTask::Completed: 
+-			m_results = psrt->results();
+-			setSuccess();
+-			break;
+-		case PollSearchResultsTask::Cancelled:
+-			setError(psrt->statusCode() );
+-			break;
+-		case PollSearchResultsTask::Error:
+-			setError( psrt->statusCode() );
+-			break;
+-		case PollSearchResultsTask::TimeOut:
+-			setError( psrt->statusCode() );
+-			break;
+-	}
+-}
+-
+-QValueList< GroupWise::ContactDetails > SearchTask::results()
+-{
+-	return m_results;
+-}
+-
+-#include "searchtask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchtask.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchtask.h	(revision 586398)
+@@ -1,63 +0,0 @@
+-/*
+-    Kopete Groupwise Protocol
+-    searchtask.h - high level search for users on the server - spawns PollSearchResultsTasks
+-
+-    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
+-    
+-    Based on Iris, Copyright (C) 2003  Justin Karneges
+-
+-    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
+- 
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#ifndef SEARCHTASK_H
+-#define SEARCHTASK_H
+-
+-#include "requesttask.h"
+-
+-class QTimer;
+-
+-/**
+-This Task performs user searching on the server
+-
+- at author SUSE AG
+-*/
+-class SearchTask : public RequestTask
+-{
+-Q_OBJECT
+-public:
+-    SearchTask(Task* parent);
+-
+-    ~SearchTask();
+-	/**
+-	 * Create the search query
+-	 * @param query a list of search terms
+-	 */
+-	void search( const QValueList<GroupWise::UserSearchQueryTerm> & query);
+-	/** 
+-	 * If the query was accepted, start a timer to poll for results using PollSearchResultsTask
+-	 */
+-	virtual bool take( Transfer * transfer );
+-	/**
+-	 * Access the results of the search
+-	 */
+-	QValueList< GroupWise::ContactDetails > results();
+-protected slots:
+-	void slotPollForResults();
+-	void slotGotPollResults();
+-private: 
+-	QString m_queryHandle;  // used to identify our query to the server, so we can poll for its results
+-	QTimer * m_resultsPollTimer;
+-	QValueList< GroupWise::ContactDetails > m_results;
+-	int m_polls;
+-};
+-
+-#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/chatcountstask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/chatcountstask.cpp	(revision 586398)
+@@ -0,0 +1,87 @@
++/*
++    Kopete Groupwise Protocol
++    ChatCountsTask.cpp - Task to update chatroom participant counts
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qmap.h>
++#include <kdebug.h>
++
++#include "gwfield.h"
++#include "response.h"
++
++#include "chatcountstask.h"
++
++using namespace GroupWise;
++
++ChatCountsTask::ChatCountsTask(Task* parent): RequestTask(parent)
++{
++	Field::FieldList lst;
++	createTransfer( "chatcounts", lst );
++}
++
++
++ChatCountsTask::~ChatCountsTask()
++{
++}
++
++bool ChatCountsTask::take( Transfer * transfer )
++{
++	if ( !forMe( transfer ) )
++		return false;
++	Response * response = dynamic_cast<Response *>( transfer );
++	if ( !response )
++		return false;
++	if ( response->resultCode() )
++	{
++		setError( response->resultCode() );
++		return true;
++	}
++	
++	Field::FieldList responseFields = response->fields();
++	Field::MultiField * resultsArray = responseFields.findMultiField( NM_A_FA_RESULTS );
++	if ( !resultsArray )
++	{
++		setError( Protocol );
++		return true;
++	}
++	Field::FieldList counts = resultsArray->fields();
++	const Field::FieldListIterator end = counts.end();
++	for ( Field::FieldListIterator it = counts.find( NM_A_FA_CHAT );
++			 it != end;
++			 it = counts.find( ++it, NM_A_FA_CHAT ) )
++	{
++		Field::MultiField * mf = static_cast<Field::MultiField *>( *it );
++		Field::FieldList chat = mf->fields();
++		QString roomName;
++		int participants;
++		// read the supplied fields, set metadata and status.
++		Field::SingleField * sf;
++		if ( ( sf = chat.findSingleField ( NM_A_DISPLAY_NAME ) ) )
++			roomName = sf->value().toString();
++		if ( ( sf = chat.findSingleField ( NM_A_UD_PARTICIPANTS ) ) )
++			participants = sf->value().toInt();
++		
++		m_results.insert( roomName, participants );
++	}
++	return true;
++}
++
++QMap< QString, int > ChatCountsTask::results()
++{
++	return m_results;
++}
++
++#include "chatcountstask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/chatpropertiestask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/chatpropertiestask.cpp	(revision 586398)
+@@ -0,0 +1,139 @@
++/*
++    Kopete Groupwise Protocol
++    ChatPropertiesTask.cpp - Task to update chatroom participant counts
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <kdebug.h>
++
++#include "gwfield.h"
++#include "response.h"
++
++#include "chatpropertiestask.h"
++
++using namespace GroupWise;
++
++ChatPropertiesTask::ChatPropertiesTask(Task* parent): RequestTask(parent)
++{
++}
++
++
++ChatPropertiesTask::~ChatPropertiesTask()
++{
++}
++
++void ChatPropertiesTask::setChat( const QString &displayName )
++{
++	Field::FieldList lst;
++	m_chat = displayName;
++	lst.append( new Field::SingleField( NM_A_DISPLAY_NAME, 0, NMFIELD_TYPE_UTF8, m_chat ) );
++	createTransfer( "chatproperties", lst );
++}
++
++bool ChatPropertiesTask::take( Transfer * transfer )
++{
++	if ( !forMe( transfer ) )
++		return false;
++	Response * response = dynamic_cast<Response *>( transfer );
++	if ( !response )
++		return false;
++	if ( response->resultCode() )
++	{
++		setError( response->resultCode() );
++		return true;
++	}
++	
++	Field::FieldList responseFields = response->fields();
++	Field::MultiField * resultsArray = responseFields.findMultiField( NM_A_FA_CHAT );
++	if ( !resultsArray )
++	{
++		setError( Protocol );
++		return true;
++	}
++	
++	Field::FieldList lst = resultsArray->fields();
++	const Field::FieldListIterator end = lst.end();
++	for ( Field::FieldListIterator it = lst.begin();
++			 it != end;
++			 ++it )
++	{
++		Field::SingleField * sf = dynamic_cast<Field::SingleField *>( *it );
++		if ( sf )
++		{
++			if ( sf->tag() == NM_A_DISPLAY_NAME )
++				continue;
++			else if ( sf->tag() == NM_A_CHAT_OWNER_DN )
++				m_ownerDn = sf->value().toString();
++			else if ( sf->tag() == NM_A_CHAT_CREATOR_DN )
++				m_creatorDn= sf->value().toString();
++			else if ( sf->tag() == NM_A_DESCRIPTION )
++				m_description =  sf->value().toString();
++			else if ( sf->tag() == NM_A_DISCLAIMER )
++				m_disclaimer = sf->value().toString();
++			else if ( sf->tag() == NM_A_QUERY )
++				m_query = sf->value().toString();
++			else if ( sf->tag() == NM_A_ARCHIVE )
++				m_archive = sf->value().toString();
++			else if ( sf->tag() == NM_A_SZ_TOPIC )
++				m_topic = sf->value().toString();
++			else if ( sf->tag() == NM_A_CREATION_TIME )
++				m_creationTime.setTime_t( sf->value().toInt() );
++			else if ( sf->tag() == NM_A_UD_CHAT_RIGHTS )
++				m_rights = sf->value().toInt();
++			
++		}
++		else
++		{
++			Field::MultiField * mf = dynamic_cast<Field::MultiField *>( *it );
++			if ( mf )
++			{
++				if ( mf->tag() == NM_A_FA_CHAT_ACL )
++				{
++					Field::FieldList acl = mf->fields();
++					const Field::FieldListIterator aclEnd = acl.end();
++					for ( Field::FieldListIterator aclIt = acl.begin();
++										 aclIt != aclEnd;
++										 ++aclIt )
++					{
++						Field::MultiField * aclEntryFields = dynamic_cast<Field::MultiField *>( *aclIt );
++						if ( aclEntryFields )
++						{
++							ChatContact entry;
++							Field::FieldList entryFields = aclEntryFields->fields();
++							Field::SingleField * sf; 
++							if ( ( sf = entryFields.findSingleField ( NM_A_SZ_DN ) ) )
++								entry.dn = sf->value().toString();
++							if ( ( sf = entryFields.findSingleField ( NM_A_SZ_ACCESS_FLAGS ) ) )
++								entry.chatRights = sf->value().toInt();
++							kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "got acl entry: " << entry.dn << ", " << entry.chatRights << endl;
++							m_aclEntries.append( entry );
++						}
++						
++					}
++				}
++			}
++		}
++	}
++	kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "Got chatroom properties: " << m_chat << " : " << m_ownerDn << ", " << m_description << ", " << m_disclaimer << ", " << m_query << ", " << m_archive << ", " << m_topic << ", " << m_creatorDn << ", " << m_creationTime.toString() << ", " << m_rights << endl;
++	finished();
++	return true;
++}
++
++QValueList< ChatContact > ChatPropertiesTask::aclEntries()
++{
++	return m_aclEntries;
++}
++
++#include "chatpropertiestask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/joinchattask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/joinchattask.h	(revision 586398)
+@@ -0,0 +1,52 @@
++/*
++    Kopete Groupwise Protocol
++    joinchattask.h - Join a chatroom on the server, after having been invited.
++
++    Copyright (c) 2004      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef JOINCHATTASK_H
++#define JOINCHATTASK_H
++
++#include "requesttask.h"
++
++using namespace GroupWise;
++
++/**
++Sends Join Conference messages when the user accepts an invitation
++
++ at author SUSE Linux Products GmbH
++ */
++
++class JoinChatTask : public RequestTask
++{
++	Q_OBJECT
++	public:
++		JoinChatTask(Task* parent);
++		~JoinChatTask();
++		void join( const QString & displayName );
++		bool take( Transfer * transfer );
++		QStringList participants() const;
++		QStringList invitees() const;
++		QString displayName() const;
++	private:
++		ConferenceGuid m_displayName;
++		QStringList m_participants;
++		QStringList m_invitees;
++		QStringList m_unknowns;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/chatcountstask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/chatcountstask.h	(revision 586398)
+@@ -0,0 +1,49 @@
++/*
++    Kopete Groupwise Protocol
++    chatcountstask.cpp - Task to update chatroom participant counts
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHATCOUNTSTASK_H
++#define CHATCOUNTSTASK_H
++
++#include <qvaluelist.h>
++
++#include "gwerror.h"
++#include "gwfield.h"
++
++#include "requesttask.h"
++
++/**
++Get the current number of users in each chat on the server
++
++ at author SUSE Linux Products GmbH
++ */
++class ChatCountsTask : public RequestTask
++{
++	Q_OBJECT
++	public:
++		ChatCountsTask(Task* parent);
++		~ChatCountsTask();
++		bool take( Transfer * transfer );
++		/**
++		 * Contains a list of all the chatrooms that have participants on the server.  If a chatroom exists but is empty, this task does not return a result, so update the participants count to 0.
++		 */
++		QMap< QString, int > results();
++	private:
++		QMap< QString, int > m_results;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/getchatsearchresultstask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/getchatsearchresultstask.cpp	(revision 586398)
+@@ -0,0 +1,122 @@
++/*
++    Kopete Groupwise Protocol
++    getchatsearchresultstask.cpp - Poll the server to see if it has processed our search yet.
++
++    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <kdebug.h>
++
++#include "gwfield.h"
++#include "response.h"
++
++#include "logintask.h"
++
++#include "getchatsearchresultstask.h"
++
++using namespace GroupWise;
++
++GetChatSearchResultsTask::GetChatSearchResultsTask(Task* parent): RequestTask(parent)
++{
++}
++
++
++GetChatSearchResultsTask::~GetChatSearchResultsTask()
++{
++}
++
++void GetChatSearchResultsTask::poll( int queryHandle )
++{
++	Field::FieldList lst;
++	lst.append( new Field::SingleField( NM_A_UD_OBJECT_ID, 0, NMFIELD_TYPE_UDWORD, queryHandle ) );
++	lst.append( new Field::SingleField( NM_A_UD_QUERY_COUNT, 0, NMFIELD_TYPE_UDWORD, 10 ) );
++	createTransfer( "getchatsearchresults", lst );
++}
++
++bool GetChatSearchResultsTask::take( Transfer * transfer )
++{
++	if ( !forMe( transfer ) )
++		return false;
++	Response * response = dynamic_cast<Response *>( transfer );
++	if ( !response )
++		return false;
++	if ( response->resultCode() )
++	{
++		setError( response->resultCode() );
++		return true;
++	}
++	
++	// look for the status code
++	Field::FieldList responseFields = response->fields();
++	Field::SingleField * sf = responseFields.findSingleField( NM_A_UW_STATUS );
++	m_queryStatus = (SearchResultCode)sf->value().toInt();
++	
++	Field::MultiField * resultsArray = responseFields.findMultiField( NM_A_FA_RESULTS );
++	if ( !resultsArray )
++	{
++		setError( Protocol );
++		return true;
++	}
++	Field::FieldList matches = resultsArray->fields();
++	const Field::FieldListIterator end = matches.end();
++	for ( Field::FieldListIterator it = matches.find( NM_A_FA_CHAT );
++			it != end;
++			it = matches.find( ++it, NM_A_FA_CHAT ) )
++	{
++		Field::MultiField * mf = static_cast<Field::MultiField *>( *it );
++		Field::FieldList chat = mf->fields();
++		GroupWise::ChatroomSearchResult cd = extractChatDetails( chat );
++		m_results.append( cd );
++	}
++	
++	if ( m_queryStatus != DataRetrieved )
++		setError( m_queryStatus );
++	else
++	{
++		kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << " we won!" << endl;
++		setSuccess( m_queryStatus );
++	}
++	return true;
++}
++
++QValueList< GroupWise::ChatroomSearchResult > GetChatSearchResultsTask::results()
++{
++	return m_results;
++}
++
++int GetChatSearchResultsTask::queryStatus()
++{
++	return m_queryStatus;
++}
++
++GroupWise::ChatroomSearchResult GetChatSearchResultsTask::extractChatDetails( Field::FieldList & fields )
++{
++	ChatroomSearchResult csr;
++	csr.participants = 0;
++	// read the supplied fields, set metadata and status.
++	Field::SingleField * sf;
++	if ( ( sf = fields.findSingleField ( NM_A_DISPLAY_NAME ) ) )
++		csr.name = sf->value().toString();
++	if ( ( sf = fields.findSingleField ( NM_A_CHAT_OWNER_DN ) ) )
++		csr.ownerDN = sf->value().toString().lower(); // HACK: lowercased DN
++	if ( ( sf = fields.findSingleField ( NM_A_UD_PARTICIPANTS ) ) )
++		csr.participants = sf->value().toInt();
++	
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << csr.name << ", " << csr.ownerDN << ", " << csr.participants << endl;
++	return csr;
++}
++
++#include "getchatsearchresultstask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchchattask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchchattask.cpp	(revision 586398)
+@@ -0,0 +1,122 @@
++/*
++    Kopete Groupwise Protocol
++    searchchattask.cpp - high level search for users on the server - spawns PollSearchResultsTasks
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qdatetime.h>
++#include <qtimer.h>
++
++#include "client.h"
++#include "gwerror.h"
++#include "gwfield.h"
++#include "response.h"
++
++#include "getchatsearchresultstask.h"
++
++#include "searchchattask.h"
++
++
++// the delay we allow the server to initially do the search
++#define GW_POLL_INITIAL_DELAY 1000
++// the maximum number of times to poll the server
++#define GW_POLL_MAXIMUM 5
++// the frequency between subsequent polls
++#define GW_POLL_FREQUENCY_MS 8000
++
++using namespace GroupWise;
++
++SearchChatTask::SearchChatTask(Task* parent): RequestTask(parent), m_polls( 0 )
++{
++}
++
++
++SearchChatTask::~SearchChatTask()
++{
++}
++
++void SearchChatTask::search( SearchType type )
++{
++	Field::FieldList lst;
++	// object Id identifies the search for later reference
++	lst.append( new Field::SingleField( NM_A_B_ONLY_MODIFIED, 0, NMFIELD_TYPE_BOOL, ( type == FetchAll ? 0 : 1 ) ) );
++	createTransfer( "chatsearch", lst );
++}
++
++bool SearchChatTask::take( Transfer * transfer )
++{
++	if ( !forMe( transfer ) )
++		return false;
++	Response * response = dynamic_cast<Response *>( transfer );
++	if ( !response )
++		return false;
++	if ( response->resultCode() )
++	{
++		kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "got return code in response << " << response->resultCode() << endl;
++		setError( response->resultCode() );
++		return true;
++	}
++	Field::FieldList responseFields = response->fields();
++	Field::SingleField * sf = responseFields.findSingleField( NM_A_UD_OBJECT_ID );
++	m_objectId = sf->value().toInt();
++
++	// now start the results poll timer
++	QTimer::singleShot( GW_POLL_INITIAL_DELAY, this, SLOT( slotPollForResults() ) );
++	return true;
++}
++
++void SearchChatTask::slotPollForResults()
++{
++	//create a PollSearchResultsTask
++	GetChatSearchResultsTask * gcsrt = new GetChatSearchResultsTask( client()->rootTask() );
++	gcsrt->poll( m_objectId );
++	connect( gcsrt, SIGNAL( finished() ), SLOT( slotGotPollResults() ) );
++	gcsrt->go( true );
++}
++
++void SearchChatTask::slotGotPollResults()
++{
++	GetChatSearchResultsTask * gcsrt = (GetChatSearchResultsTask *)sender();
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "status code is " << gcsrt->queryStatus() << endl;
++	m_polls++;
++	switch ( gcsrt->queryStatus() )
++	{
++		case GetChatSearchResultsTask::GettingData:
++			if ( m_polls < GW_POLL_MAXIMUM ) // restart timer
++				QTimer::singleShot( GW_POLL_FREQUENCY_MS, this, SLOT( slotPollForResults() ) );
++			else
++				setSuccess( gcsrt->statusCode() );
++			break;
++		case GetChatSearchResultsTask::DataRetrieved: 
++			m_results = gcsrt->results();
++			setSuccess();
++			break;
++		case GetChatSearchResultsTask::Cancelled:
++			setError(gcsrt->statusCode() );
++			break;
++		case GetChatSearchResultsTask::Error:
++			setError( gcsrt->statusCode() );
++			break;
++	}
++}
++
++QValueList< GroupWise::ChatroomSearchResult > SearchChatTask::results()
++{
++	return m_results;
++}
++
++#include "searchchattask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchusertask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchusertask.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++    Kopete Groupwise Protocol
++    searchusertask.h - high level search for users on the server - spawns PollSearchResultsTasks
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SEARCHUSERTASK_H
++#define SEARCHUSERTASK_H
++
++#include "requesttask.h"
++
++class QTimer;
++
++/**
++This Task performs user searching on the server
++
++ at author SUSE AG
++*/
++class SearchUserTask : public RequestTask
++{
++Q_OBJECT
++public:
++    SearchUserTask(Task* parent);
++
++    ~SearchUserTask();
++	/**
++	 * Create the search query
++	 * @param query a list of search terms
++	 */
++	void search( const QValueList<GroupWise::UserSearchQueryTerm> & query);
++	/** 
++	 * If the query was accepted, start a timer to poll for results using PollSearchResultsTask
++	 */
++	virtual bool take( Transfer * transfer );
++	/**
++	 * Access the results of the search
++	 */
++	QValueList< GroupWise::ContactDetails > results();
++protected slots:
++	void slotPollForResults();
++	void slotGotPollResults();
++private: 
++	QString m_queryHandle;  // used to identify our query to the server, so we can poll for its results
++	QTimer * m_resultsPollTimer;
++	QValueList< GroupWise::ContactDetails > m_results;
++	int m_polls;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/logintask.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/logintask.h	(revision 586398)
+@@ -49,6 +49,7 @@
+ 	ContactDetails extractUserDetails( Field::FieldList & fields );
+ 	void extractPrivacy( Field::FieldList & fields );
+ 	QStringList readPrivacyItems( const QCString & tag, Field::FieldList & fields );
++	void extractCustomStatuses( Field::FieldList & fields );
+ 
+ signals:
+ 	void gotMyself( const GroupWise::ContactDetails & );
+@@ -56,6 +57,7 @@
+ 	void gotContact( const ContactItem & );
+ 	void gotContactUserDetails( const GroupWise::ContactDetails & );
+ 	void gotPrivacySettings( bool locked, bool defaultDeny, const QStringList & allowList, const QStringList & denyList );
++	void gotCustomStatus( const GroupWise::CustomStatus & );
+ };
+ 
+ #endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/getchatsearchresultstask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/getchatsearchresultstask.h	(revision 586398)
+@@ -0,0 +1,52 @@
++/*
++    Kopete Groupwise Protocol
++    getchatsearchresultstask.h - Poll the server once to see if it has processed our chatroom search yet.
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHATSEARCHRESULTSTASK_H
++#define CHATSEARCHRESULTSTASK_H
++
++#include <qvaluelist.h>
++
++#include "gwchatrooms.h"
++
++#include "requesttask.h"
++
++/**
++Search results are polled on the server, using the search handle returned by the server with the original query.  This is a single poll request, which if successful, will retrieve the results.  Otherwise, it will set a status code, so the SearchContactTask can decide whether to poll again.
++
++ at author SUSE Linux Products GmbH
++ */
++class GetChatSearchResultsTask : public RequestTask
++{
++	Q_OBJECT
++	public:
++		enum SearchResultCode { Cancelled=4, Error=5, GettingData=8, DataRetrieved=9 };
++		GetChatSearchResultsTask(Task* parent);
++		~GetChatSearchResultsTask();
++		void poll( int queryHandle);
++		bool take( Transfer * transfer );
++		int queryStatus();
++		QValueList< GroupWise::ChatroomSearchResult > results();
++	private:
++		GroupWise::ChatroomSearchResult extractChatDetails( Field::FieldList & fields );
++		SearchResultCode m_queryStatus;
++		QValueList< GroupWise::ChatroomSearchResult > m_results;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchusertask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchusertask.cpp	(revision 586398)
+@@ -0,0 +1,137 @@
++/*
++    Kopete Groupwise Protocol
++    searchusertask.cpp - high level search for users on the server - spawns PollSearchResultsTasks
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include <qdatetime.h>
++#include <qtimer.h>
++
++#include "client.h"
++#include "gwerror.h"
++#include "gwfield.h"
++#include "response.h"
++
++#include "pollsearchresultstask.h"
++
++#include "searchusertask.h"
++
++// the delay we allow the server to initially do the search
++#define GW_POLL_INITIAL_DELAY 1000
++// the maximum number of times to poll the server
++#define GW_POLL_MAXIMUM 5
++// the frequency between subsequent polls
++#define GW_POLL_FREQUENCY_MS 8000
++
++using namespace GroupWise;
++
++SearchUserTask::SearchUserTask(Task* parent): RequestTask(parent), m_polls( 0 )
++{
++}
++
++
++SearchUserTask::~SearchUserTask()
++{
++}
++
++void SearchUserTask::search( const QValueList<UserSearchQueryTerm> & query )
++{
++	m_queryHandle = QString::number( QDateTime::currentDateTime().toTime_t () );
++	Field::FieldList lst;
++	if ( query.isEmpty() )
++	{
++		setError( 1, "no query terms" );
++		return;
++	}
++	// object Id identifies the search for later reference
++	lst.append( new Field::SingleField( NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, m_queryHandle ) );
++	QValueList<UserSearchQueryTerm>::ConstIterator it = query.begin();
++	const QValueList<UserSearchQueryTerm>::ConstIterator end = query.end();
++	for ( ; it != end; ++it )
++	{
++		Field::SingleField * fld =  new Field::SingleField( (*it).field.ascii(), (*it).operation, 0, NMFIELD_TYPE_UTF8, (*it).argument );
++		lst.append( fld );
++	}
++	//lst.append( new Field::SingleField( "Given Name", 0, NMFIELD_TYPE_UTF8, [ NMFIELD_METHOD_EQUAL | NMFIELD_METHOD_MATCHBEGIN | NMFIELD_METHOD_MATCHEND | NMFIELD_METHOD_SEARCH ], searchTerm );
++	// Or "Surname", NM_A_SZ_USERID, NM_A_SZ_TITLE, NM_A_SZ_DEPARTMENT in other fields
++	
++	createTransfer( "createsearch", lst );
++}
++
++bool SearchUserTask::take( Transfer * transfer )
++{
++	if ( !forMe( transfer ) )
++		return false;
++	Response * response = dynamic_cast<Response *>( transfer );
++	if ( !response )
++		return false;
++	if ( response->resultCode() )
++	{
++		kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "got return code in response << " << response->resultCode() << endl;
++		setError( response->resultCode() );
++		return true;
++	}
++	// now start the results poll timer
++	QTimer::singleShot( GW_POLL_INITIAL_DELAY, this, SLOT( slotPollForResults() ) );
++	return true;
++}
++
++void SearchUserTask::slotPollForResults()
++{
++	//create a PollSearchResultsTask
++	PollSearchResultsTask * psrt = new PollSearchResultsTask( client()->rootTask() );
++	psrt->poll( m_queryHandle );
++	connect( psrt, SIGNAL( finished() ), SLOT( slotGotPollResults() ) );
++	psrt->go( true );
++}
++
++void SearchUserTask::slotGotPollResults()
++{
++	PollSearchResultsTask * psrt = (PollSearchResultsTask *)sender();
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << "status code is " << psrt->queryStatus() << endl;
++	m_polls++;
++	switch ( psrt->queryStatus() )
++	{
++		case PollSearchResultsTask::Pending:
++		case PollSearchResultsTask::InProgess:
++			if ( m_polls < GW_POLL_MAXIMUM ) // restart timer
++				QTimer::singleShot( GW_POLL_FREQUENCY_MS, this, SLOT( slotPollForResults() ) );
++			else
++				setSuccess( psrt->statusCode() );
++			break;
++		case PollSearchResultsTask::Completed: 
++			m_results = psrt->results();
++			setSuccess();
++			break;
++		case PollSearchResultsTask::Cancelled:
++			setError(psrt->statusCode() );
++			break;
++		case PollSearchResultsTask::Error:
++			setError( psrt->statusCode() );
++			break;
++		case PollSearchResultsTask::TimeOut:
++			setError( psrt->statusCode() );
++			break;
++	}
++}
++
++QValueList< GroupWise::ContactDetails > SearchUserTask::results()
++{
++	return m_results;
++}
++
++#include "searchusertask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/logintask.cpp	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/logintask.cpp	(revision 586398)
+@@ -70,6 +70,8 @@
+ 	// read the privacy settings first, because this affects all contacts' apparent status
+ 	extractPrivacy( loginResponseFields );
+ 
++	extractCustomStatuses( loginResponseFields );
++
+ 	// CREATE CONTACT LIST
+ 	// locate contact list
+ 	Field::MultiField * contactList = loginResponseFields.findMultiField( NM_A_FA_CONTACT_LIST );
+@@ -168,7 +170,7 @@
+ 	if ( ( sf = fields.findSingleField ( NM_A_SZ_AUTH_ATTRIBUTE ) ) )
+ 		cd.authAttribute = sf->value().toString();
+ 	if ( ( sf = fields.findSingleField ( NM_A_SZ_DN ) ) )
+-		cd.dn =sf->value().toString().lower(); // HACK: lowercased DN
++		cd.dn = sf->value().toString().lower(); // HACK: lowercased DN
+ 	if ( ( sf = fields.findSingleField ( "CN" ) ) )
+ 		cd.cn = sf->value().toString();
+ 	if ( ( sf = fields.findSingleField ( "Given Name" ) ) )
+@@ -191,10 +193,37 @@
+ 		const Field::FieldListIterator end = fl.end();
+ 		for ( Field::FieldListIterator it = fl.begin(); it != end; ++it )
+ 		{
+-			Field::SingleField * propField = static_cast<Field::SingleField *>( *it );
+-			QString propName = propField->tag();
+-			QString propValue = propField->value().toString();
+-			propMap.insert( propName, propValue );
++			Field::SingleField * propField = dynamic_cast<Field::SingleField *>( *it );
++			if ( propField )
++			{
++				QString propName = propField->tag();
++				QString propValue = propField->value().toString();
++				propMap.insert( propName, propValue );
++			}
++			else
++			{
++				Field::MultiField * propList = dynamic_cast<Field::MultiField*>( *it );
++				if ( propList )
++				{
++					// Hello A Nagappan. GW gave us a multiple field where we previously got a single field
++					QString parentName = propList->tag();
++					Field::FieldList propFields = propList->fields();
++					const Field::FieldListIterator end = propFields.end();
++					for ( Field::FieldListIterator it = propFields.begin(); it != end; ++it )
++					{
++						propField = dynamic_cast<Field::SingleField *>( *it );
++						if ( propField /*&& propField->tag() == parentName */)
++						{
++							QString propValue = propField->value().toString();
++							QString contents = propMap[ propField->tag() ];
++							if ( !contents.isEmpty() )
++								contents.append( ", " );
++							contents.append( propField->value().toString());
++							propMap.insert( propField->tag(), contents );
++						}
++					}
++				}
++			}	
+ 		}
+ 	}
+ 	if ( !propMap.empty() )
+@@ -276,4 +305,39 @@
+ 	}
+ 	return items;
+ }
++
++void LoginTask::extractCustomStatuses( Field::FieldList & fields )
++{
++	Field::FieldListIterator it = fields.find( NM_A_FA_CUSTOM_STATUSES );
++	if ( it != fields.end() )
++	{
++		if ( Field::MultiField * mf = dynamic_cast<Field::MultiField *>( *it ) )
++		{
++			Field::FieldList fl = mf->fields();
++			for ( Field::FieldListIterator custStatIt = fl.begin(); custStatIt != fl.end(); ++custStatIt )
++			{
++				Field::MultiField * mf2 = dynamic_cast<Field::MultiField *>( *custStatIt );
++				if ( mf2 && ( mf2->tag() == NM_A_FA_STATUS ) )
++				{
++					GroupWise::CustomStatus custom;
++					Field::FieldList fl2 = mf2->fields();
++					for ( Field::FieldListIterator custContentIt = fl2.begin(); custContentIt != fl2.end(); ++custContentIt )
++					{
++						if ( Field::SingleField * sf3 = dynamic_cast<Field::SingleField *>( *custContentIt ) )
++						{
++							if ( sf3->tag() == NM_A_SZ_TYPE )
++								custom.status = (GroupWise::Status)sf3->value().toInt();
++							else if ( sf3->tag() == NM_A_SZ_DISPLAY_NAME )
++								custom.name = sf3->value().toString();
++							else if ( sf3->tag() == NM_A_SZ_MESSAGE_BODY )
++								custom.autoReply = sf3->value().toString();
++						}
++					}
++					emit gotCustomStatus( custom );
++				}
++			}
++		}
++	}
++}
++
+ #include "logintask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/searchchattask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/searchchattask.h	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++    Kopete Groupwise Protocol
++    searchchattask.h - search for chatrooms on the server - spawns PollSearchResultsTasks
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef SEARCHCHATTASK_H
++#define SEARCHCHATTASK_H
++
++#include "gwerror.h"
++
++#include "requesttask.h"
++
++class QTimer;
++
++/**
++This Task searches for chatrooms on the server
++
++ at author SUSE Linux Products GmbH
++ */
++class SearchChatTask : public RequestTask
++{
++	Q_OBJECT
++	public:
++		enum SearchType { FetchAll=0, SinceLastSearch };
++		
++		SearchChatTask(Task* parent);
++
++		~SearchChatTask();
++	/**
++		 * Create the search query
++	 */
++		void search( SearchType type );
++	/** 
++		 * If the query was accepted, start a timer to poll for results using PollSearchResultsTask
++	 */
++		virtual bool take( Transfer * transfer );
++	/**
++		 * Access the results of the search
++	 */
++		QValueList< GroupWise::ChatroomSearchResult > results();
++	protected slots:
++		void slotPollForResults();
++		void slotGotPollResults();
++	private: 
++		QTimer * m_resultsPollTimer;
++		QValueList< GroupWise::ChatroomSearchResult > m_results;
++		int m_polls;
++		int m_objectId; // used to identify our query to the server, so we can poll for its results
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/pollsearchresultstask.h	(revision 586398)
+@@ -28,7 +28,7 @@
+ #include "requesttask.h"
+ 
+ /**
+-Search results are polled on the server, using the search handle supplied by the client with the original query.  This is a single poll request, which if successful, will retrieve the results.  Otherwise, it will set a status code, so the SearchTask can decide whether to poll again.
++Search results are polled on the server, using the search handle supplied by the client with the original query.  This is a single poll request, which if successful, will retrieve the results.  Otherwise, it will set a status code, so the ContactSearchTask can decide whether to poll again.
+ 
+ @author SUSE AG
+ */
+--- kopete/protocols/groupwise/libgroupwise/tasks/joinchattask.cpp	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/joinchattask.cpp	(revision 586398)
+@@ -0,0 +1,131 @@
++/*
++    Kopete Groupwise Protocol
++    joinchattask.cpp - Join a Chat on the server, after having been invited.
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++    
++    Based on Iris, Copyright (C) 2003  Justin Karneges
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "gwerror.h"
++#include "client.h"
++#include "response.h"
++#include "userdetailsmanager.h"
++
++#include "joinchattask.h"
++
++JoinChatTask::JoinChatTask(Task* parent): RequestTask(parent)
++{
++}
++
++JoinChatTask::~JoinChatTask()
++{
++}
++
++void JoinChatTask::join( const QString & displayName )
++{
++	m_displayName = displayName;
++	Field::FieldList lst, tmp;
++	tmp.append( new Field::SingleField( NM_A_SZ_OBJECT_ID, 0, NMFIELD_TYPE_UTF8, displayName ) );
++	lst.append( new Field::MultiField( NM_A_FA_CONVERSATION, NMFIELD_METHOD_VALID, 0, NMFIELD_TYPE_ARRAY, tmp ) );
++	createTransfer( "joinchat", lst );
++}
++
++bool JoinChatTask::take( Transfer * transfer )
++{
++	if ( forMe( transfer ) )
++	{
++		client()->debug( "JoinChatTask::take()" );
++		Response * response = dynamic_cast<Response *>( transfer );
++		Field::FieldList responseFields = response->fields();
++		// if the request was successful
++		if ( response->resultCode() == GroupWise::None )
++		{
++			// extract the list of participants and store them
++			Field::MultiField * participants = responseFields.findMultiField( NM_A_FA_CONTACT_LIST );
++			if ( participants )
++			{
++				Field::SingleField * contact = 0;
++				Field::FieldList contactList = participants->fields();
++				const Field::FieldListIterator end = contactList.end();
++				for ( Field::FieldListIterator it = contactList.find( NM_A_SZ_DN );
++								  it != end;
++								  it = contactList.find( ++it, NM_A_SZ_DN ) )
++				{
++					contact = static_cast<Field::SingleField *>( *it );
++					if ( contact )
++					{
++						// HACK: lowercased DN 
++						QString dn = contact->value().toString().lower();
++						m_participants.append( dn );
++						// need to ask for details for these contacts
++					}
++				}
++			}
++			else 
++				setError( GroupWise::Protocol );
++			
++			// now, extract the list of pending invites and store them
++			Field::MultiField * invitees = responseFields.findMultiField( NM_A_FA_RESULTS );
++			if ( invitees )
++			{
++				Field::SingleField * contact = 0;
++				Field::FieldList contactList = invitees->fields();
++				const Field::FieldListIterator end = contactList.end();
++				for ( Field::FieldListIterator it = contactList.find( NM_A_SZ_DN );
++								  it != end;
++								  it = contactList.find( ++it, NM_A_SZ_DN ) )
++				{
++					contact = static_cast<Field::SingleField *>( *it );
++					if ( contact )
++					{
++						// HACK: lowercased DN 
++						QString dn = contact->value().toString().lower();
++						m_invitees.append( dn );
++						// need to ask for details for these contacts
++						if ( !client()->userDetailsManager()->known( dn )  )
++							; // don't request details for chatrooms, there could be too many
++					}
++				}
++			}
++			else 
++				setError( GroupWise::Protocol );
++
++			client()->debug( "JoinChatTask::finished()" );
++			finished();	
++		}
++		else
++			setError( response->resultCode() );
++		return true;
++	}
++	else
++		return false;
++}
++
++QStringList JoinChatTask::participants() const
++{
++	return m_participants;
++}
++
++QStringList JoinChatTask::invitees() const
++{
++	return m_invitees;
++}
++
++QString JoinChatTask::displayName() const
++{
++	return m_displayName;
++}
++
++#include "joinchattask.moc"
+--- kopete/protocols/groupwise/libgroupwise/tasks/chatpropertiestask.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/tasks/chatpropertiestask.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++    Kopete Groupwise Protocol
++    chatcountstask.cpp - Task to update chatroom participant counts
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHATPROPERTIESTASK_H
++#define CHATPROPERTIESTASK_H
++
++#include <qdatetime.h>
++#include <qvaluelist.h>
++#include "gwchatrooms.h"
++#include "gwerror.h"
++#include "gwfield.h"
++
++#include "requesttask.h"
++
++/**
++Get the current number of users in each chat on the server
++
++ at author SUSE Linux Products GmbH
++ */
++class ChatPropertiesTask : public RequestTask
++{
++	Q_OBJECT
++	public:
++		ChatPropertiesTask(Task* parent);
++		~ChatPropertiesTask();
++		/**
++		 * Specify which chatroom to get properties for
++		 */
++		void setChat( const QString & );
++		bool take( Transfer * transfer );
++		/**
++		 * Contains a list of the ACL entries for the specified chatroom
++		 */
++		QValueList< GroupWise::ChatContact > aclEntries();
++		QString m_chat;
++		QString m_ownerDn;
++		QString m_description;
++		QString m_disclaimer;
++		QString m_query;
++		QString m_archive;
++		QString m_maxUsers;
++		QString m_topic;
++		QString m_creatorDn;
++		QDateTime m_creationTime;
++		uint m_rights;
++		QValueList< GroupWise::ChatContact > m_aclEntries;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/tasks/Makefile.am	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/tasks/Makefile.am	(revision 586398)
+@@ -5,20 +5,22 @@
+ noinst_LTLIBRARIES = libgroupwise_tasks.la
+ 
+ libgroupwise_tasks_la_SOURCES = requesttask.cpp eventtask.cpp logintask.cpp \
+-	setstatustask.cpp statustask.cpp conferencetask.cpp createconferencetask.cpp \
+-	sendmessagetask.cpp getdetailstask.cpp getstatustask.cpp typingtask.cpp connectiontask.cpp \
+-	sendinvitetask.cpp joinconferencetask.cpp leaveconferencetask.cpp rejectinvitetask.cpp \
+-	keepalivetask.cpp createcontacttask.cpp modifycontactlisttask.cpp createfoldertask.cpp \
+-	movecontacttask.cpp updateitemtask.cpp createcontactinstancetask.cpp deleteitemtask.cpp \
+-	updatefoldertask.cpp updatecontacttask.cpp searchtask.cpp pollsearchresultstask.cpp \
+-	privacyitemtask.cpp needfoldertask.cpp
++		setstatustask.cpp statustask.cpp conferencetask.cpp createconferencetask.cpp \
++		sendmessagetask.cpp getdetailstask.cpp getstatustask.cpp typingtask.cpp connectiontask.cpp \
++		sendinvitetask.cpp joinconferencetask.cpp leaveconferencetask.cpp rejectinvitetask.cpp \
++		keepalivetask.cpp createcontacttask.cpp modifycontactlisttask.cpp createfoldertask.cpp \
++		movecontacttask.cpp updateitemtask.cpp createcontactinstancetask.cpp deleteitemtask.cpp \
++		updatefoldertask.cpp updatecontacttask.cpp pollsearchresultstask.cpp privacyitemtask.cpp \
++		needfoldertask.cpp searchchattask.cpp searchusertask.cpp searchusertask.h \
++		getchatsearchresultstask.cpp chatcountstask.cpp chatpropertiestask.cpp joinchattask.cpp
+ noinst_HEADERS = requesttask.h eventtask.h logintask.h setstatustask.h \
+-	statustask.h conferencetask.h createconferencetask.h sendmessagetask.h \
+-	getdetailstask.h getstatustask.h typingtask.h connectiontask.h sendinvitetask.h \
+-	joinconferencetask.h leaveconferencetask.h rejectinvitetask.h createcontacttask.h \
+-	modifycontactlisttask.h createfoldertask.h movecontacttask.h updateitemtask.h deleteitemtask.h \
+-	updatefoldertask.h updatecontacttask.h searchtask.h pollsearchresultstask.h \
+-	privacyitemtask.h needfoldertask.h
++		statustask.h conferencetask.h createconferencetask.h sendmessagetask.h \
++		getdetailstask.h getstatustask.h typingtask.h connectiontask.h sendinvitetask.h \
++		joinconferencetask.h leaveconferencetask.h rejectinvitetask.h createcontacttask.h \
++		modifycontactlisttask.h createfoldertask.h movecontacttask.h updateitemtask.h deleteitemtask.h \
++		updatefoldertask.h updatecontacttask.h pollsearchresultstask.h privacyitemtask.h \
++		needfoldertask.h searchchattask.h getchatsearchresultstask.h searchusertask.h \
++		chatcountstask.h joinchattask.h
+ 
+ 
+ libgroupwise_tasks_la_LDFLAGS = -no-undefined $(all_libraries)
+--- kopete/protocols/groupwise/libgroupwise/chatroommanager.h	(revision 0)
++++ kopete/protocols/groupwise/libgroupwise/chatroommanager.h	(revision 586398)
+@@ -0,0 +1,67 @@
++/*
++    Kopete Groupwise Protocol
++    chatroommanager.h - tracks our knowledge of server side chatrooms
++
++    Copyright (c) 2005      SUSE Linux Products GmbH	 	 http://www.suse.com
++
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef CHATROOMMANAGER_H
++#define CHATROOMMANAGER_H
++
++#include <qobject.h>
++
++#include "gwchatrooms.h"
++
++class Client;
++
++/**
++ * Keeps a record of the server side chatrooms
++ * @author SUSE Linux Products GmbH
++ */
++class ChatroomManager : public QObject
++{
++	Q_OBJECT
++	public:
++		ChatroomManager( Client * client, const char *name = 0);
++		~ChatroomManager();
++		GroupWise::ChatroomMap rooms();
++		void requestProperties( const QString & displayName );
++		void update();
++	signals:
++		void gotProperties( const GroupWise::Chatroom & );
++		void updated();
++	public slots:
++	protected:
++		void updateCounts();
++		void getChatrooms( bool refresh );
++	protected slots:
++		/**
++		 * Used to initialise the list of chatrooms in response to a SearchChatTask.
++		 */
++		void slotGotChatroomList();
++		/**
++		 * Used to update the user counts of chatrooms.
++		 */
++		void slotGotChatCounts();
++		/**
++		 * Get the properties of a specific room.
++		 */
++		void slotGotChatProperties();
++	private:
++		Client * m_client;
++		GroupWise::ChatroomMap m_rooms;
++		bool m_replace;
++};
++
++#endif
+--- kopete/protocols/groupwise/libgroupwise/client.cpp	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/client.cpp	(revision 586398)
+@@ -20,6 +20,7 @@
+ 
+ #include <qapplication.h>
+ 
++#include "chatroommanager.h"
+ #include "gwclientstream.h"
+ #include "privacymanager.h"
+ #include "requestfactory.h"
+@@ -55,9 +56,11 @@
+ /*	int tzoffset;*/
+ 	bool active;
+ 	RequestFactory * requestFactory;
++	ChatroomManager * chatroomMgr;
+ 	UserDetailsManager * userDetailsMgr;
+ 	PrivacyManager * privacyMgr;
+ 	uint protocolVersion;
++	QValueList<GroupWise::CustomStatus> customStatuses;
+ };
+ 
+ Client::Client(QObject *par, uint protocolVersion )
+@@ -71,6 +74,7 @@
+ 	d->clientVersion = "0.0";
+ 	d->id_seed = 0xaaaa;
+ 	d->root = new Task(this, true);
++	d->chatroomMgr = 0;
+ 	d->requestFactory = new RequestFactory;
+ 	d->userDetailsMgr = new UserDetailsManager( this, "userdetailsmgr" );
+ 	d->privacyMgr = new PrivacyManager( this, "privacymgr" );
+@@ -139,7 +143,10 @@
+ 
+ 	connect( login, SIGNAL( gotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ),
+ 			privacyManager(), SLOT( slotGotPrivacySettings( bool, bool, const QStringList &, const QStringList & ) ) );
+-			
++
++	connect( login, SIGNAL( gotCustomStatus( const GroupWise::CustomStatus & ) ), 
++			SLOT( lt_gotCustomStatus( const GroupWise::CustomStatus & ) ) );
++
+ 	connect( login, SIGNAL( finished() ), this, SLOT( lt_loginFinished() ) );
+ 	
+ 	login->initialise();
+@@ -168,6 +175,11 @@
+ 	return d->port;
+ }
+ 
++QValueList<GroupWise::CustomStatus> Client::customStatuses()
++{
++	return d->customStatuses;
++}
++
+ void Client::initialiseEventTasks()
+ {
+ 	// The StatusTask handles incoming status changes
+@@ -379,6 +391,11 @@
+ 	emit conferenceJoined( jct->guid(), jct->participants(), jct->invitees() );
+ }
+ 
++void Client::lt_gotCustomStatus( const GroupWise::CustomStatus & custom )
++{
++	d->customStatuses.append( custom );
++}
++
+ // INTERNALS //
+ 
+ QString Client::userId()
+@@ -476,4 +493,12 @@
+ {
+ 	return d->protocolVersion;
+ }
++
++ChatroomManager * Client::chatroomManager()
++{
++	if ( !d->chatroomMgr )
++		d->chatroomMgr = new ChatroomManager( this, "chatroommgr" );
++	return d->chatroomMgr;
++}
++
+ #include "client.moc"
+--- kopete/protocols/groupwise/libgroupwise/gwfield.h	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/gwfield.h	(revision 586398)
+@@ -102,6 +102,7 @@
+ #define	NM_A_B_NO_CONTACTS				"NM_A_B_NO_CONTACTS"
+ #define	NM_A_B_NO_CUSTOMS				"NM_A_B_NO_CUSTOMS"
+ #define	NM_A_B_NO_PRIVACY				"NM_A_B_NO_PRIVACY"
++#define	NM_A_B_ONLY_MODIFIED			"NM_A_B_ONLY_MODIFIED"
+ #define	NM_A_UW_STATUS					"NM_A_UW_STATUS"
+ #define	NM_A_UD_OBJECT_ID				"NM_A_UD_OBJECT_ID"
+ #define	NM_A_SZ_TRANSACTION_ID			"NM_A_SZ_TRANSACTION_ID"
+@@ -118,9 +119,28 @@
+ #define NM_A_LOCKED_ATTR_LIST			"nnmLockedAttrList"
+ #define NM_A_SZ_DEPARTMENT				"OU"
+ #define NM_A_SZ_TITLE					"Title"
++// GW7
++#define NM_A_FA_CUSTOM_STATUSES			"NM_A_FA_CUSTOM_STATUSES"
++#define NM_A_FA_STATUS					"NM_A_FA_STATUS"
++#define NM_A_UD_QUERY_COUNT				"NM_A_UD_QUERY_COUNT"
++#define NM_A_FA_CHAT					"NM_A_FA_CHAT"
++#define NM_A_DISPLAY_NAME				"nnmDisplayName"
++#define NM_A_CHAT_OWNER_DN				"nnmChatOwnerDN"
++#define NM_A_UD_PARTICIPANTS			"NM_A_UD_PARTICIPANTS"
++#define NM_A_DESCRIPTION				"nnmDescription"
++#define NM_A_DISCLAIMER					"nnmDisclaimer"
++#define NM_A_QUERY						"nnmQuery"
++#define NM_A_ARCHIVE					"nnmArchive"
++#define NM_A_MAX_USERS					"nnmMaxUsers"
++#define NM_A_SZ_TOPIC					"NM_A_SZ_TOPIC"
++#define NM_A_FA_CHAT_ACL				"NM_A_FA_CHAT_ACL"
++#define NM_A_FA_CHAT_ACL_ENTRY			"NM_A_FA_CHAT_ACL_ENTRY"
++#define NM_A_SZ_ACCESS_FLAGS			"NM_A_SZ_ACCESS_FLAGS"
++#define NM_A_CHAT_CREATOR_DN			"nnmCreatorDN"
++#define NM_A_CREATION_TIME				"nnmCreationTime"
++#define NM_A_UD_CHAT_RIGHTS				"NM_A_UD_CHAT_RIGHTS"
+ 
+-#define NM_PROTOCOL_VERSION		 		2
+-
++#define NM_PROTOCOL_VERSION		 		5
+ #define	NM_FIELD_TRUE					"1"
+ #define	NM_FIELD_FALSE					"0"
+ 
+--- kopete/protocols/groupwise/libgroupwise/Makefile.am	(revision 568672)
++++ kopete/protocols/groupwise/libgroupwise/Makefile.am	(revision 586398)
+@@ -12,19 +12,19 @@
+ KDE_OPTIONS = nofinal
+ 
+ noinst_HEADERS = connector.h tlshandler.h qcatlshandler.h bytestream.h \
+-						gwclientstream.h securestream.h stream.h coreprotocol.h gwfield.h gwerror.h \
+-						usertransfer.h eventtransfer.h transfer.h request.h requestfactory.h client.h task.h \
+-						safedelete.h response.h rtf2html.h userdetailsmanager.h eventprotocol.h \
+-		inputprotocolbase.h responseprotocol.h privacymanager.h
++							gwclientstream.h securestream.h stream.h coreprotocol.h gwfield.h gwerror.h \
++							usertransfer.h eventtransfer.h transfer.h request.h requestfactory.h client.h task.h \
++							safedelete.h response.h rtf2html.h userdetailsmanager.h eventprotocol.h \
++			inputprotocolbase.h responseprotocol.h privacymanager.h gwchatrooms.h chatroommanager.h
+ 
+ noinst_LTLIBRARIES = libgroupwise.la libgwtest.la
+ libgroupwise_la_COMPILE_FIRST = securestream.moc 
+ libgroupwise_la_SOURCES = connector.cpp bytestream.cpp tlshandler.cpp \
+-								qcatlshandler.cpp gwclientstream.cpp securestream.cpp stream.cpp coreprotocol.cpp \
+-								gwfield.cpp transferbase.cpp usertransfer.cpp eventtransfer.cpp transfer.cpp \
+-								request.cpp requestfactory.cpp safedelete.cpp response.cpp client.cpp task.cpp \
+-						rtf.cc userdetailsmanager.cpp eventprotocol.cpp inputprotocolbase.cpp \
+-			responseprotocol.cpp privacymanager.cpp gwglobal.cpp
++									qcatlshandler.cpp gwclientstream.cpp securestream.cpp stream.cpp coreprotocol.cpp \
++									gwfield.cpp transferbase.cpp usertransfer.cpp eventtransfer.cpp transfer.cpp \
++									request.cpp requestfactory.cpp safedelete.cpp response.cpp client.cpp task.cpp \
++							rtf.cc userdetailsmanager.cpp eventprotocol.cpp inputprotocolbase.cpp \
++				responseprotocol.cpp privacymanager.cpp gwglobal.cpp chatroommanager.cpp
+ libgroupwise_la_LDFLAGS = -no-undefined $(all_libraries)
+ libgroupwise_la_LIBADD = tasks/libgroupwise_tasks.la -lqt-mt qca/src/libqca.la 
+ 
+--- kopete/protocols/groupwise/ui/gwsearchwidget.ui	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwsearchwidget.ui	(revision 586398)
+@@ -1,386 +0,0 @@
+-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+-<class>GroupWiseSearchWidget</class>
+-<widget class="QWidget">
+-    <property name="name">
+-        <cstring>GroupWiseSearchWidget</cstring>
+-    </property>
+-    <property name="geometry">
+-        <rect>
+-            <x>0</x>
+-            <y>0</y>
+-            <width>435</width>
+-            <height>410</height>
+-        </rect>
+-    </property>
+-    <property name="caption">
+-        <string>Search GroupWise Messenger</string>
+-    </property>
+-    <vbox>
+-        <property name="name">
+-            <cstring>unnamed</cstring>
+-        </property>
+-        <widget class="QLayoutWidget">
+-            <property name="name">
+-                <cstring>layout13</cstring>
+-            </property>
+-            <grid>
+-                <property name="name">
+-                    <cstring>unnamed</cstring>
+-                </property>
+-                <widget class="QLabel" row="0" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>&amp;First name</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>m_firstName</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="2" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel3</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>&amp;User ID</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>m_userId</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="3" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel4</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>&amp;Title</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>m_title</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="2" column="2">
+-                    <property name="name">
+-                        <cstring>m_userId</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="0" column="2">
+-                    <property name="name">
+-                        <cstring>m_firstName</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="4" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel5</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>&amp;Department</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>m_dept</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QComboBox" row="2" column="1">
+-                    <item>
+-                        <property name="text">
+-                            <string>contains</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>begins with</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>equals</string>
+-                        </property>
+-                    </item>
+-                    <property name="name">
+-                        <cstring>m_userIdOperation</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QComboBox" row="0" column="1">
+-                    <item>
+-                        <property name="text">
+-                            <string>contains</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>begins with</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>equals</string>
+-                        </property>
+-                    </item>
+-                    <property name="name">
+-                        <cstring>m_firstNameOperation</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="4" column="2">
+-                    <property name="name">
+-                        <cstring>m_dept</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QComboBox" row="1" column="1">
+-                    <item>
+-                        <property name="text">
+-                            <string>contains</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>begins with</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>equals</string>
+-                        </property>
+-                    </item>
+-                    <property name="name">
+-                        <cstring>m_lastNameOperation</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="1" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel2</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Last &amp;name</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>m_lastName</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QPushButton" row="1" column="3">
+-                    <property name="name">
+-                        <cstring>m_clear</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Cl&amp;ear</string>
+-                    </property>
+-                </widget>
+-                <widget class="QComboBox" row="4" column="1">
+-                    <item>
+-                        <property name="text">
+-                            <string>contains</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>begins with</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>equals</string>
+-                        </property>
+-                    </item>
+-                    <property name="name">
+-                        <cstring>m_deptOperation</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="3" column="2">
+-                    <property name="name">
+-                        <cstring>m_title</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLineEdit" row="1" column="2">
+-                    <property name="name">
+-                        <cstring>m_lastName</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QPushButton" row="0" column="3">
+-                    <property name="name">
+-                        <cstring>m_search</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>&amp;Search</string>
+-                    </property>
+-                    <property name="default">
+-                        <bool>true</bool>
+-                    </property>
+-                </widget>
+-                <widget class="QComboBox" row="3" column="1">
+-                    <item>
+-                        <property name="text">
+-                            <string>contains</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>begins with</string>
+-                        </property>
+-                    </item>
+-                    <item>
+-                        <property name="text">
+-                            <string>equals</string>
+-                        </property>
+-                    </item>
+-                    <property name="name">
+-                        <cstring>m_titleOperation</cstring>
+-                    </property>
+-                </widget>
+-            </grid>
+-        </widget>
+-        <widget class="Line">
+-            <property name="name">
+-                <cstring>line1</cstring>
+-            </property>
+-            <property name="frameShape">
+-                <enum>HLine</enum>
+-            </property>
+-            <property name="frameShadow">
+-                <enum>Sunken</enum>
+-            </property>
+-            <property name="orientation">
+-                <enum>Horizontal</enum>
+-            </property>
+-        </widget>
+-        <widget class="QLabel">
+-            <property name="name">
+-                <cstring>textLabel9</cstring>
+-            </property>
+-            <property name="text">
+-                <string>&amp;Results:</string>
+-            </property>
+-            <property name="buddy" stdset="0">
+-                <cstring>m_results</cstring>
+-            </property>
+-        </widget>
+-        <widget class="QLayoutWidget">
+-            <property name="name">
+-                <cstring>layout12</cstring>
+-            </property>
+-            <hbox>
+-                <property name="name">
+-                    <cstring>unnamed</cstring>
+-                </property>
+-                <widget class="QListView">
+-                    <column>
+-                        <property name="text">
+-                            <string>Status</string>
+-                        </property>
+-                        <property name="clickable">
+-                            <bool>true</bool>
+-                        </property>
+-                        <property name="resizable">
+-                            <bool>true</bool>
+-                        </property>
+-                    </column>
+-                    <column>
+-                        <property name="text">
+-                            <string>First Name</string>
+-                        </property>
+-                        <property name="clickable">
+-                            <bool>true</bool>
+-                        </property>
+-                        <property name="resizable">
+-                            <bool>true</bool>
+-                        </property>
+-                    </column>
+-                    <column>
+-                        <property name="text">
+-                            <string>Last Name</string>
+-                        </property>
+-                        <property name="clickable">
+-                            <bool>true</bool>
+-                        </property>
+-                        <property name="resizable">
+-                            <bool>true</bool>
+-                        </property>
+-                    </column>
+-                    <column>
+-                        <property name="text">
+-                            <string>User ID</string>
+-                        </property>
+-                        <property name="clickable">
+-                            <bool>true</bool>
+-                        </property>
+-                        <property name="resizable">
+-                            <bool>true</bool>
+-                        </property>
+-                    </column>
+-                    <property name="name">
+-                        <cstring>m_results</cstring>
+-                    </property>
+-                    <property name="resizePolicy">
+-                        <enum>AutoOneFit</enum>
+-                    </property>
+-                    <property name="resizeMode">
+-                        <enum>AllColumns</enum>
+-                    </property>
+-                </widget>
+-                <widget class="QLayoutWidget">
+-                    <property name="name">
+-                        <cstring>layout8</cstring>
+-                    </property>
+-                    <vbox>
+-                        <property name="name">
+-                            <cstring>unnamed</cstring>
+-                        </property>
+-                        <widget class="QPushButton">
+-                            <property name="name">
+-                                <cstring>m_details</cstring>
+-                            </property>
+-                            <property name="enabled">
+-                                <bool>true</bool>
+-                            </property>
+-                            <property name="text">
+-                                <string>Detai&amp;ls</string>
+-                            </property>
+-                        </widget>
+-                        <spacer>
+-                            <property name="name">
+-                                <cstring>spacer6</cstring>
+-                            </property>
+-                            <property name="orientation">
+-                                <enum>Vertical</enum>
+-                            </property>
+-                            <property name="sizeType">
+-                                <enum>Expanding</enum>
+-                            </property>
+-                            <property name="sizeHint">
+-                                <size>
+-                                    <width>20</width>
+-                                    <height>141</height>
+-                                </size>
+-                            </property>
+-                        </spacer>
+-                    </vbox>
+-                </widget>
+-            </hbox>
+-        </widget>
+-        <widget class="QLabel">
+-            <property name="name">
+-                <cstring>m_matchCount</cstring>
+-            </property>
+-            <property name="text">
+-                <string>0 matching users found</string>
+-            </property>
+-        </widget>
+-    </vbox>
+-</widget>
+-<tabstops>
+-    <tabstop>m_firstName</tabstop>
+-    <tabstop>m_lastNameOperation</tabstop>
+-    <tabstop>m_lastName</tabstop>
+-    <tabstop>m_userIdOperation</tabstop>
+-    <tabstop>m_userId</tabstop>
+-    <tabstop>m_titleOperation</tabstop>
+-    <tabstop>m_title</tabstop>
+-    <tabstop>m_deptOperation</tabstop>
+-    <tabstop>m_dept</tabstop>
+-    <tabstop>m_search</tabstop>
+-    <tabstop>m_clear</tabstop>
+-    <tabstop>m_results</tabstop>
+-    <tabstop>m_details</tabstop>
+-    <tabstop>m_firstNameOperation</tabstop>
+-</tabstops>
+-<layoutdefaults spacing="6" margin="11"/>
+-</UI>
+--- kopete/protocols/groupwise/ui/gwaddcontactpage.cpp	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwaddcontactpage.cpp	(revision 586398)
+@@ -53,7 +53,7 @@
+ 	( new QVBoxLayout( this ) )->setAutoAdd( true );
+ 	if (owner->isConnected ())
+ 	{
+-		m_searchUI = new GroupWiseSearch( m_account, QListView::Single, false,
++		m_searchUI = new GroupWiseContactSearch( m_account, QListView::Single, false,
+ 				 this, "acwsearchwidget" );
+ 		show();
+ 		m_canadd = true;
+--- kopete/protocols/groupwise/ui/gwchatpropswidget.ui	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatpropswidget.ui	(revision 586398)
+@@ -0,0 +1,394 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>GroupWiseChatPropsWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>GroupWiseChatPropsWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>493</width>
++            <height>425</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>GroupWiseChatPropertiesWidget</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>m_displayName</cstring>
++            </property>
++            <property name="text">
++                <string>DISPLAY NAME</string>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout16</cstring>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLineEdit" row="4" column="1">
++                    <property name="name">
++                        <cstring>m_creator</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>The user who created the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="2">
++                    <property name="name">
++                        <cstring>textLabel10_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Query:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_firstName_2</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>lblTopic</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Topic:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_displayName</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="3">
++                    <property name="name">
++                        <cstring>m_disclaimer</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>A disclaimer for users entering the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>m__2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Owner:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_displayName_3</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="1">
++                    <property name="name">
++                        <cstring>m_topic</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>The current topic of the discussion</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="3">
++                    <property name="name">
++                        <cstring>m_query</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>UNKNOWN</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="2">
++                    <property name="name">
++                        <cstring>textLabel11_2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Maximum Users:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_lastName_2_2</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="0">
++                    <property name="name">
++                        <cstring>m__2_2_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Created on:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_displayName_3</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="2">
++                    <property name="name">
++                        <cstring>lbl_displayName_2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Disclaimer:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_displayName_2</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="5" column="1">
++                    <property name="name">
++                        <cstring>m_description</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>General description of the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="3">
++                    <property name="name">
++                        <cstring>m_maxUsers</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Maximum simultaneous users allowed in the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="4" column="0">
++                    <property name="name">
++                        <cstring>textLabel10</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Creator:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_firstName</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="5" column="0">
++                    <property name="name">
++                        <cstring>textLabel11</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Description:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_lastName</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="1">
++                    <property name="name">
++                        <cstring>m_createdOn</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Date and time the chatroom was created</string>
++                    </property>
++                </widget>
++                <widget class="QCheckBox" row="4" column="2">
++                    <property name="name">
++                        <cstring>m_archive</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Archived</string>
++                    </property>
++                    <property name="accel">
++                        <string></string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Indicates if the chatroom is being archived on the server</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="1">
++                    <property name="name">
++                        <cstring>m_owner</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>false</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>The user who owns this chatroom</string>
++                    </property>
++                </widget>
++                <widget class="Line" row="0" column="0" rowspan="1" colspan="4">
++                    <property name="name">
++                        <cstring>line4</cstring>
++                    </property>
++                    <property name="frameShape">
++                        <enum>HLine</enum>
++                    </property>
++                    <property name="frameShadow">
++                        <enum>Sunken</enum>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <widget class="QButtonGroup">
++            <property name="name">
++                <cstring>buttonGroup2</cstring>
++            </property>
++            <property name="title">
++                <string>Default Access</string>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QCheckBox">
++                    <property name="name">
++                        <cstring>m_chkRead</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Read Message</string>
++                    </property>
++                    <property name="accel">
++                        <string></string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>General permission to read messages in the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QCheckBox">
++                    <property name="name">
++                        <cstring>m_chkWrite</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Write Message</string>
++                    </property>
++                    <property name="accel">
++                        <string></string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>General permission to write messages in the chatroom</string>
++                    </property>
++                </widget>
++                <widget class="QCheckBox">
++                    <property name="name">
++                        <cstring>m_chkModify</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Modify Access</string>
++                    </property>
++                    <property name="accel">
++                        <string></string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>General permission to modify the chatroom's access control list</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel1</cstring>
++            </property>
++            <property name="text">
++                <string>Access Control List</string>
++            </property>
++            <property name="buddy" stdset="0">
++                <cstring>kListBox1</cstring>
++            </property>
++        </widget>
++        <widget class="KListBox">
++            <property name="name">
++                <cstring>m_acl</cstring>
++            </property>
++            <property name="toolTip" stdset="0">
++                <string>Access permissions for specific users</string>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout15</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>m_btnAddAcl</cstring>
++                    </property>
++                    <property name="text">
++                        <string>A&amp;dd</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Add a new ACL entry</string>
++                    </property>
++                </widget>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>m_btnEditAcl</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Ed&amp;it</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Edit an existing ACL entry</string>
++                    </property>
++                </widget>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>m_btnDeleteAcl</cstring>
++                    </property>
++                    <property name="text">
++                        <string>D&amp;elete</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Delete a ACL entry</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>klistbox.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/protocols/groupwise/ui/gwprivacydialog.h	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwprivacydialog.h	(revision 586398)
+@@ -23,7 +23,7 @@
+ 
+ class GroupWiseAccount;
+ class GroupWisePrivacyWidget;
+-class GroupWiseSearch;
++class GroupWiseContactSearch;
+ class QListBoxItem;
+ 
+ /**
+@@ -58,7 +58,7 @@
+ private:
+ 	GroupWiseAccount * m_account;
+ 	GroupWisePrivacyWidget * m_privacy;
+-	GroupWiseSearch * m_search;
++	GroupWiseContactSearch * m_search;
+ 	QListBoxItem * m_defaultPolicy;
+ 	bool m_dirty;
+ 	KDialogBase * m_searchDlg;
+--- kopete/protocols/groupwise/ui/gwchatsearchwidget.ui	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatsearchwidget.ui	(revision 586398)
+@@ -0,0 +1,116 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>GroupWiseChatSearchWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>GroupWiseChatSearchWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>579</width>
++            <height>480</height>
++        </rect>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="KListView">
++            <column>
++                <property name="text">
++                    <string>Chatroom </string>
++                </property>
++                <property name="clickable">
++                    <bool>true</bool>
++                </property>
++                <property name="resizable">
++                    <bool>true</bool>
++                </property>
++            </column>
++            <column>
++                <property name="text">
++                    <string>Owner</string>
++                </property>
++                <property name="clickable">
++                    <bool>true</bool>
++                </property>
++                <property name="resizable">
++                    <bool>true</bool>
++                </property>
++            </column>
++            <column>
++                <property name="text">
++                    <string>Members</string>
++                </property>
++                <property name="clickable">
++                    <bool>true</bool>
++                </property>
++                <property name="resizable">
++                    <bool>true</bool>
++                </property>
++            </column>
++            <property name="name">
++                <cstring>m_chatrooms</cstring>
++            </property>
++            <property name="allColumnsShowFocus">
++                <bool>true</bool>
++            </property>
++            <property name="fullWidth">
++                <bool>true</bool>
++            </property>
++            <property name="itemsMovable">
++                <bool>false</bool>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout2</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>m_btnProperties</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Properties</string>
++                    </property>
++                </widget>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer3</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>340</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="QPushButton">
++                    <property name="name">
++                        <cstring>m_btnRefresh</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Refresh</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>klistview.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/protocols/groupwise/ui/gwsearch.cpp	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwsearch.cpp	(revision 586398)
+@@ -33,8 +33,7 @@
+ #include "gwcontact.h"
+ #include "gwcontactproperties.h"
+ #include "gwprotocol.h"
+-#include "gwsearchwidget.h"
+-#include "tasks/searchtask.h"
++#include "tasks/searchusertask.h"
+ 
+ #include "gwsearch.h"
+ 
+@@ -57,8 +56,8 @@
+ 	int m_status;
+ };
+ 
+-GroupWiseSearch::GroupWiseSearch( GroupWiseAccount * account, QListView::SelectionMode mode, bool onlineOnly,  QWidget *parent, const char *name)
+- : GroupWiseSearchWidget(parent, name), m_account( account ), m_onlineOnly( onlineOnly )
++GroupWiseContactSearch::GroupWiseContactSearch( GroupWiseAccount * account, QListView::SelectionMode mode, bool onlineOnly,  QWidget *parent, const char *name)
++ : GroupWiseContactSearchWidget(parent, name), m_account( account ), m_onlineOnly( onlineOnly )
+ {
+ 	m_results->setSelectionMode( mode );
+ 	m_results->setAllColumnsShowFocus( true );
+@@ -69,11 +68,11 @@
+ }
+ 
+ 
+-GroupWiseSearch::~GroupWiseSearch()
++GroupWiseContactSearch::~GroupWiseContactSearch()
+ {
+ }
+ 
+-void GroupWiseSearch::slotClear()
++void GroupWiseContactSearch::slotClear()
+ {
+ 	m_firstName->clear();
+ 	m_lastName->clear();
+@@ -82,7 +81,7 @@
+ 	m_dept->clear();
+ }
+ 
+-void GroupWiseSearch::slotDoSearch()
++void GroupWiseContactSearch::slotDoSearch()
+ {
+ 	// build a query
+ 	QValueList< GroupWise::UserSearchQueryTerm > searchTerms;
+@@ -129,7 +128,7 @@
+ 	if ( !searchTerms.isEmpty() )
+ 	{
+ 		// start a search task
+-		SearchTask * st = new SearchTask( m_account->client()->rootTask() );
++		SearchUserTask * st = new SearchUserTask( m_account->client()->rootTask() );
+ 		st->search( searchTerms );
+ 		connect( st, SIGNAL( finished() ), SLOT( slotGotSearchResults() ) );
+ 		st->go( true );
+@@ -142,7 +141,7 @@
+ 	
+ }
+ 
+-void GroupWiseSearch::slotShowDetails()
++void GroupWiseContactSearch::slotShowDetails()
+ {
+ 	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
+ 	// get the first selected result
+@@ -159,10 +158,10 @@
+ 	}
+ }
+ 
+-void GroupWiseSearch::slotGotSearchResults()
++void GroupWiseContactSearch::slotGotSearchResults()
+ {
+ 	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
+-	SearchTask * st = ( SearchTask * )sender();
++	SearchUserTask * st = ( SearchUserTask * ) sender();
+ 	m_searchResults = st->results();
+ 	
+ 	m_matchCount->setText( i18n( "1 matching user found", "%n matching users found", m_searchResults.count() ) );
+@@ -211,7 +210,7 @@
+ 	slotValidateSelection();
+ }
+ 
+-QValueList< GroupWise::ContactDetails > GroupWiseSearch::selectedResults()
++QValueList< GroupWise::ContactDetails > GroupWiseContactSearch::selectedResults()
+ {
+     QValueList< GroupWise::ContactDetails > lst;
+     QListViewItemIterator it( m_results );
+@@ -228,7 +227,7 @@
+ // 		displayName = selection->text( 1 ) + " " + selection->text( 3 );
+ 
+ 
+-unsigned char GroupWiseSearch::searchOperation( int comboIndex )
++unsigned char GroupWiseContactSearch::searchOperation( int comboIndex )
+ {
+ 	switch ( comboIndex )
+ 	{
+@@ -242,7 +241,7 @@
+ 	return NMFIELD_METHOD_IGNORE;
+ }
+ 
+-void GroupWiseSearch::slotValidateSelection()
++void GroupWiseContactSearch::slotValidateSelection()
+ {
+ 	bool ok = false;
+ 	// if we only allow online contacts to be selected
+--- kopete/protocols/groupwise/ui/gwaddcontactpage.h	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwaddcontactpage.h	(revision 586398)
+@@ -31,7 +31,8 @@
+ namespace Kopete { class MetaContact; }
+ class GroupWiseAccount;
+ class GroupWiseAddUI;
+-class GroupWiseSearch;
++//TODO: change this to a wrapper around Contact Search and Chatroom Search
++class GroupWiseContactSearch;
+ 
+ /**
+  * A page in the Add Contact Wizard
+@@ -57,7 +58,8 @@
+ 	unsigned char searchOperation( int comboIndex );
+ 	GroupWiseAccount * m_account;
+ 	GroupWiseAddUI * m_gwAddUI;
+-	GroupWiseSearch * m_searchUI;
++	//TODO: make wrapper
++	GroupWiseContactSearch * m_searchUI;
+ 	QLabel *m_noaddMsg1;
+ 	QLabel *m_noaddMsg2;
+ 	bool m_canadd;
+--- kopete/protocols/groupwise/ui/gwsearch.h	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwsearch.h	(revision 586398)
+@@ -19,24 +19,24 @@
+ #ifndef GWSEARCH_H
+ #define GWSEARCH_H
+ #include <qlistview.h>
+-#include "gwsearchwidget.h"
++#include "gwcontactsearch.h"
+ 
+ class GroupWiseAccount;
+ class GroupWiseContactProperties;
+-class GroupWiseSearchWidget;
++class GroupWiseContactSearchWidget;
+ 
+ /**
+-Logic for searching and displaying results using a GroupWiseSearchWidget
++Logic for searching for and displaying users and chat rooms using a GroupWiseContactSearchWidget
+ 
+- at author Kopete Developers
++ at author SUSE Linux Products GmbH
+ */
+-class GroupWiseSearch : public GroupWiseSearchWidget
++class GroupWiseContactSearch : public GroupWiseContactSearchWidget
+ {
+ Q_OBJECT
+ public:
+-	GroupWiseSearch( GroupWiseAccount * account, QListView::SelectionMode mode, bool onlineOnly, 
++	GroupWiseContactSearch( GroupWiseAccount * account, QListView::SelectionMode mode, bool onlineOnly, 
+ 			QWidget *parent = 0, const char *name = 0);
+-	~GroupWiseSearch();
++	~GroupWiseContactSearch();
+ 	QValueList< GroupWise::ContactDetails > selectedResults();
+ signals:
+ 	void selectionValidates( bool );
+--- kopete/protocols/groupwise/ui/gwcontactsearch.ui	(revision 0)
++++ kopete/protocols/groupwise/ui/gwcontactsearch.ui	(revision 586398)
+@@ -0,0 +1,386 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>GroupWiseContactSearchWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>GroupWiseContactSearchWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>435</width>
++            <height>410</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>Search GroupWise Messenger</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout13</cstring>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;First name</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_firstName</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="2" column="0">
++                    <property name="name">
++                        <cstring>textLabel3</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;User ID</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_userId</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="3" column="0">
++                    <property name="name">
++                        <cstring>textLabel4</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Title</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_title</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="2" column="2">
++                    <property name="name">
++                        <cstring>m_userId</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="0" column="2">
++                    <property name="name">
++                        <cstring>m_firstName</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="4" column="0">
++                    <property name="name">
++                        <cstring>textLabel5</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Department</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_dept</cstring>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="2" column="1">
++                    <item>
++                        <property name="text">
++                            <string>contains</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>begins with</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>equals</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>m_userIdOperation</cstring>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="0" column="1">
++                    <item>
++                        <property name="text">
++                            <string>contains</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>begins with</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>equals</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>m_firstNameOperation</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="4" column="2">
++                    <property name="name">
++                        <cstring>m_dept</cstring>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="1" column="1">
++                    <item>
++                        <property name="text">
++                            <string>contains</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>begins with</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>equals</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>m_lastNameOperation</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>textLabel2</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Last &amp;name</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>m_lastName</cstring>
++                    </property>
++                </widget>
++                <widget class="QPushButton" row="1" column="3">
++                    <property name="name">
++                        <cstring>m_clear</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Cl&amp;ear</string>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="4" column="1">
++                    <item>
++                        <property name="text">
++                            <string>contains</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>begins with</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>equals</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>m_deptOperation</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="3" column="2">
++                    <property name="name">
++                        <cstring>m_title</cstring>
++                    </property>
++                </widget>
++                <widget class="QLineEdit" row="1" column="2">
++                    <property name="name">
++                        <cstring>m_lastName</cstring>
++                    </property>
++                </widget>
++                <widget class="QPushButton" row="0" column="3">
++                    <property name="name">
++                        <cstring>m_search</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Search</string>
++                    </property>
++                    <property name="default">
++                        <bool>true</bool>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="3" column="1">
++                    <item>
++                        <property name="text">
++                            <string>contains</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>begins with</string>
++                        </property>
++                    </item>
++                    <item>
++                        <property name="text">
++                            <string>equals</string>
++                        </property>
++                    </item>
++                    <property name="name">
++                        <cstring>m_titleOperation</cstring>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++        <widget class="Line">
++            <property name="name">
++                <cstring>line1</cstring>
++            </property>
++            <property name="frameShape">
++                <enum>HLine</enum>
++            </property>
++            <property name="frameShadow">
++                <enum>Sunken</enum>
++            </property>
++            <property name="orientation">
++                <enum>Horizontal</enum>
++            </property>
++        </widget>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>textLabel9</cstring>
++            </property>
++            <property name="text">
++                <string>&amp;Results:</string>
++            </property>
++            <property name="buddy" stdset="0">
++                <cstring>m_results</cstring>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout12</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QListView">
++                    <column>
++                        <property name="text">
++                            <string>Status</string>
++                        </property>
++                        <property name="clickable">
++                            <bool>true</bool>
++                        </property>
++                        <property name="resizable">
++                            <bool>true</bool>
++                        </property>
++                    </column>
++                    <column>
++                        <property name="text">
++                            <string>First Name</string>
++                        </property>
++                        <property name="clickable">
++                            <bool>true</bool>
++                        </property>
++                        <property name="resizable">
++                            <bool>true</bool>
++                        </property>
++                    </column>
++                    <column>
++                        <property name="text">
++                            <string>Last Name</string>
++                        </property>
++                        <property name="clickable">
++                            <bool>true</bool>
++                        </property>
++                        <property name="resizable">
++                            <bool>true</bool>
++                        </property>
++                    </column>
++                    <column>
++                        <property name="text">
++                            <string>User ID</string>
++                        </property>
++                        <property name="clickable">
++                            <bool>true</bool>
++                        </property>
++                        <property name="resizable">
++                            <bool>true</bool>
++                        </property>
++                    </column>
++                    <property name="name">
++                        <cstring>m_results</cstring>
++                    </property>
++                    <property name="resizePolicy">
++                        <enum>AutoOneFit</enum>
++                    </property>
++                    <property name="resizeMode">
++                        <enum>AllColumns</enum>
++                    </property>
++                </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout8</cstring>
++                    </property>
++                    <vbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <widget class="QPushButton">
++                            <property name="name">
++                                <cstring>m_details</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>true</bool>
++                            </property>
++                            <property name="text">
++                                <string>Detai&amp;ls</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer6</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Vertical</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>20</width>
++                                    <height>141</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </vbox>
++                </widget>
++            </hbox>
++        </widget>
++        <widget class="QLabel">
++            <property name="name">
++                <cstring>m_matchCount</cstring>
++            </property>
++            <property name="text">
++                <string>0 matching users found</string>
++            </property>
++        </widget>
++    </vbox>
++</widget>
++<tabstops>
++    <tabstop>m_firstName</tabstop>
++    <tabstop>m_lastNameOperation</tabstop>
++    <tabstop>m_lastName</tabstop>
++    <tabstop>m_userIdOperation</tabstop>
++    <tabstop>m_userId</tabstop>
++    <tabstop>m_titleOperation</tabstop>
++    <tabstop>m_title</tabstop>
++    <tabstop>m_deptOperation</tabstop>
++    <tabstop>m_dept</tabstop>
++    <tabstop>m_search</tabstop>
++    <tabstop>m_clear</tabstop>
++    <tabstop>m_results</tabstop>
++    <tabstop>m_details</tabstop>
++    <tabstop>m_firstNameOperation</tabstop>
++</tabstops>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/groupwise/ui/gwchatpropsdialog.cpp	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatpropsdialog.cpp	(revision 586398)
+@@ -0,0 +1,122 @@
++/*
++    Kopete Groupwise Protocol
++    gwchatpropsdialog.h - dialog for viewing/modifying chat properties
++
++    Copyright (c) 2005      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library 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 <qcheckbox.h>
++#include <qlabel.h>
++#include <qlineedit.h>
++#include <qlistview.h>
++
++#include <kdebug.h>
++#include <kpushbutton.h>
++#include <klocale.h>
++#include "gwerror.h"
++#include "gwchatpropswidget.h"
++
++#include "gwchatpropsdialog.h"
++
++GroupWiseChatPropsDialog::GroupWiseChatPropsDialog( QWidget * parent, const char * name )
++ : KDialogBase( parent, name, false, i18n( "Chatroom properties" ),
++				KDialogBase::Ok|KDialogBase::Cancel, Ok, true ), m_dirty( false )
++{
++	initialise();
++}
++
++GroupWiseChatPropsDialog::GroupWiseChatPropsDialog( const GroupWise::Chatroom & room, bool readOnly,
++							   QWidget * parent, const char * name )
++	: KDialogBase( parent, name, false, i18n( "Chatroom properties" ),
++				   KDialogBase::Ok|KDialogBase::Cancel, Ok, true ), m_dirty( false )
++{
++	initialise();
++	m_widget->m_description->setText( room.description );
++	m_widget->m_displayName->setText( room.displayName );
++	m_widget->m_disclaimer->setText( room.disclaimer );
++	m_widget->m_owner->setText( room.ownerDN );
++	m_widget->m_query->setText( room.query );
++	m_widget->m_topic->setText( room.topic );
++	m_widget->m_archive->setChecked( room.archive );
++	m_widget->m_maxUsers->setText( QString::number( room.maxUsers ) );
++	m_widget->m_createdOn->setText( room.createdOn.toString() );
++	m_widget->m_creator->setText( room.creatorDN );
++	
++	m_widget->m_chkRead->setChecked( room.chatRights & GroupWise::Chatroom::Read || room.chatRights & GroupWise::Chatroom::Write || room.chatRights & GroupWise::Chatroom::Owner );
++	m_widget->m_chkWrite->setChecked( room.chatRights & GroupWise::Chatroom::Write || room.chatRights & GroupWise::Chatroom::Owner );
++	m_widget->m_chkModify->setChecked( room.chatRights & GroupWise::Chatroom::Modify || room.chatRights & GroupWise::Chatroom::Owner );
++
++	if ( readOnly )
++	{
++		m_widget->m_description->setReadOnly( true );
++		m_widget->m_disclaimer->setReadOnly( true );
++		m_widget->m_owner->setReadOnly( true );
++		m_widget->m_query->setReadOnly( true );
++		m_widget->m_topic->setReadOnly( true );
++		m_widget->m_archive->setEnabled( false );
++		m_widget->m_maxUsers->setReadOnly( true );
++		m_widget->m_createdOn->setReadOnly( true );
++		m_widget->m_creator->setReadOnly( true );
++		m_widget->m_chkRead->setEnabled( false );
++		m_widget->m_chkWrite->setEnabled( false );
++		m_widget->m_chkModify->setEnabled( false );
++		m_widget->m_btnAddAcl->setEnabled( false );
++		m_widget->m_btnEditAcl->setEnabled( false );
++		m_widget->m_btnDeleteAcl->setEnabled( false );
++	}
++	
++}
++
++void GroupWiseChatPropsDialog::initialise()
++{
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
++	m_widget = new GroupWiseChatPropsWidget( this );
++	connect( m_widget->m_topic, SIGNAL( textChanged( const QString & )  ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_owner, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_createdOn, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_creator, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_description, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_disclaimer, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_query, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_archive, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_maxUsers, SIGNAL( textChanged( const QString & ) ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_btnAddAcl, SIGNAL( clicked() ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_btnEditAcl, SIGNAL( clicked() ), SLOT( slotWidgetChanged() ) );
++	connect( m_widget->m_btnDeleteAcl, SIGNAL( clicked() ), SLOT( slotWidgetChanged() ) );
++	setMainWidget( m_widget );
++	show();
++}
++
++GroupWise::Chatroom GroupWiseChatPropsDialog::room()
++{
++	GroupWise::Chatroom room;
++	room.description = m_widget->m_description->text();
++	room.displayName = m_widget->m_displayName->text();
++	room.disclaimer = m_widget->m_disclaimer->text();
++	room.ownerDN = m_widget->m_owner->text();
++	room.query = m_widget->m_query->text();
++	room.topic = m_widget->m_topic->text();
++	room.archive = m_widget->m_archive->isChecked();
++	room.maxUsers = m_widget->m_maxUsers->text().toInt();
++	
++// 	room.
++	return room;
++}
++
++void GroupWiseChatPropsDialog::slotWidgetChanged()
++{
++	m_dirty = true;
++}
++
++#include "gwchatpropsdialog.moc"
+--- kopete/protocols/groupwise/ui/gwchatsearchdialog.cpp	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatsearchdialog.cpp	(revision 586398)
+@@ -0,0 +1,106 @@
++/*
++    Kopete Groupwise Protocol
++    gwchatsearchdialog.cpp - dialog for searching for chatrooms
++
++    Copyright (c) 2005      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library 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 <qmap.h>
++
++#include <klistview.h>
++#include <klistviewsearchline.h>
++
++#include <kpushbutton.h>
++#include <kdebug.h>
++#include <klocale.h>
++#include "client.h"
++#include "chatroommanager.h"
++
++#include "gwaccount.h"
++#include "gwprotocol.h"
++#include "gwchatsearchwidget.h"
++#include "gwchatpropsdialog.h"
++
++#include "gwchatsearchdialog.h"
++
++GroupWiseChatSearchDialog::GroupWiseChatSearchDialog( GroupWiseAccount * account, QWidget *parent, const char *name )
++	: KDialogBase(  parent, name, false, i18n( "Search Chatrooms" ),
++					KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, Ok, true ), m_account( account )
++{
++	m_widget = new GroupWiseChatSearchWidget( this );
++//	m_widget->m_searchLineWidget->createSearchLine( m_widget->m_chatrooms );
++	setMainWidget( m_widget );
++
++	m_manager = m_account->client()->chatroomManager();
++	
++	connect ( m_manager, SIGNAL( updated() ), SLOT( slotManagerUpdated() ) );
++	connect ( m_manager, SIGNAL( gotProperties( const GroupWise::Chatroom & ) ),
++			  SLOT( slotGotProperties( const GroupWise::Chatroom & ) ) );
++
++	connect( m_widget->m_btnRefresh, SIGNAL( clicked() ), SLOT( slotUpdateClicked() ) );
++	connect( m_widget->m_btnProperties, SIGNAL( clicked() ), SLOT( slotPropertiesClicked() ) );
++
++	m_manager->update();
++	show();
++}
++
++GroupWiseChatSearchDialog::~GroupWiseChatSearchDialog()
++{
++}
++
++void GroupWiseChatSearchDialog::slotUpdateClicked()
++{
++	kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "updating chatroom list " << endl;
++	QListViewItem * first = m_widget->m_chatrooms->firstChild();
++	QString updateMessage = i18n("Updating chatroom list..." );
++	if ( first )
++		new QListViewItem( first, updateMessage );
++	else
++		new QListViewItem( m_widget->m_chatrooms, updateMessage );
++	m_manager->update();
++
++}
++
++void GroupWiseChatSearchDialog::slotManagerUpdated()
++{
++	m_widget->m_chatrooms->clear();
++	ChatroomMap rooms = m_manager->rooms();
++	ChatroomMap::iterator it = rooms.begin();
++	const ChatroomMap::iterator end = rooms.end();
++	while ( it != end )
++	{
++		new QListViewItem( m_widget->m_chatrooms,
++						   it.data().displayName,
++						   m_account->protocol()->dnToDotted( it.data().ownerDN ),
++						   QString::number( it.data().participantsCount ) );
++		++it;
++	}
++}
++
++void GroupWiseChatSearchDialog::slotPropertiesClicked()
++{
++	QListViewItem * selected  = m_widget->m_chatrooms->selectedItem();
++	if ( selected )
++	{
++		m_manager->requestProperties( selected->text( 0 ) );
++	}
++}
++
++void GroupWiseChatSearchDialog::slotGotProperties(const GroupWise::Chatroom & room)
++{
++	kdDebug( GROUPWISE_DEBUG_GLOBAL ) << k_funcinfo << endl;
++	new GroupWiseChatPropsDialog( room, true, this, "chatpropsdlg" );
++}
++
++#include "gwchatsearchdialog.moc"
+--- kopete/protocols/groupwise/ui/gwchatpropsdialog.h	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatpropsdialog.h	(revision 586398)
+@@ -0,0 +1,69 @@
++/*
++    Kopete Groupwise Protocol
++    gwchatpropsdialog.h - dialog for viewing/modifying chat properties
++
++    Copyright (c) 2005      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library 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 GWCHATPROPSDIALOG_H
++#define GWCHATPROPSDIALOG_H
++
++#include <kdialogbase.h>
++
++#include "gwchatrooms.h"
++
++class GroupWiseChatPropsWidget;
++/**
++ * Dialog for viewing/modifying chat properties.
++ * Chatroom list dialog gets props from manager
++ * Chatroom list dialog opens chatpropsdlg using props, connects to OkClicked signal
++ * User makes changes
++ * CLD asks CPD for changes.
++ * CLD passes changes to manager
++ * manager sends ChatUpdate to server
++ * on success, manager updates own model.
++
++ 1) Create dialog with populated widget from supplied Chatroom.
++ 2) Add readonly mode.
++ 3) Track which things changed?  Easier to get the changed Chatroom back and diff in the manager, simpler api connecting 
++ */
++class GroupWiseChatPropsDialog : public KDialogBase
++{
++	Q_OBJECT
++	public:
++		/**
++		 * Construct an empty dialog
++		 */
++		GroupWiseChatPropsDialog( QWidget * parent, const char * name );
++		/**
++		 * Construct a populated dialog
++		 */
++		GroupWiseChatPropsDialog( const GroupWise::Chatroom & room, bool readOnly,
++									   QWidget * parent, const char * name );
++		
++		~GroupWiseChatPropsDialog() {}
++		
++		bool dirty() { return m_dirty; };
++		GroupWise::Chatroom room();
++	protected:
++		void initialise();
++	protected slots:
++		void slotWidgetChanged();
++	private:
++		GroupWiseChatPropsWidget * m_widget;
++		GroupWise::Chatroom m_room;
++		bool m_dirty;
++};
++
++#endif
+--- kopete/protocols/groupwise/ui/gwchatsearchdialog.h	(revision 0)
++++ kopete/protocols/groupwise/ui/gwchatsearchdialog.h	(revision 586398)
+@@ -0,0 +1,49 @@
++/*
++    Kopete Groupwise Protocol
++    gwchatsearchdialog.h - dialog for searching for chatrooms
++
++    Copyright (c) 2005      SUSE Linux AG	 	 http://www.suse.com
++    
++    Kopete (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
++ 
++    *************************************************************************
++    *                                                                       *
++    * This library 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 GWCHATSEARCHDIALOG_H
++#define GWCHATSEARCHDIALOG_H
++
++class GroupWiseAccount;
++class GroupWiseChatSearchWidget;
++
++#include "gwchatrooms.h"
++
++#include <kdialogbase.h>
++
++class GroupWiseChatSearchDialog : public KDialogBase
++{
++	Q_OBJECT
++	public:
++		GroupWiseChatSearchDialog( GroupWiseAccount * account, QWidget * parent, const char * name );
++		~GroupWiseChatSearchDialog();
++	protected:
++		void populateWidget();
++	protected slots:
++		/* Button handlers */
++		void slotPropertiesClicked();
++		void slotUpdateClicked();
++		/* Manager update handler */
++		void slotManagerUpdated();
++		void slotGotProperties( const GroupWise::Chatroom & room );
++	private:
++		GroupWiseAccount * m_account;
++		ChatroomManager * m_manager;
++		GroupWiseChatSearchWidget * m_widget;
++};
++#endif
+--- kopete/protocols/groupwise/ui/Makefile.am	(revision 568672)
++++ kopete/protocols/groupwise/ui/Makefile.am	(revision 586398)
+@@ -9,10 +9,11 @@
+ 
+ libkopetegroupwiseui_la_LDFLAGS = $(all_libraries)
+ libkopetegroupwiseui_la_SOURCES = gwaccountpreferences.ui gwaddcontactpage.cpp \
+-						gwaddui.ui gweditaccountwidget.cpp gwreceiveinvitationdialog.cpp \
+-						gwshowinvitation.ui gwcontactpropswidget.ui gwcontactproperties.cpp gwprivacy.ui \
+-						gwsearchwidget.ui gwprivacydialog.cpp gwsearch.cpp gwcustomstatuswidget.ui \
+-	gwcustomstatusedit.ui
++		gwaddui.ui gweditaccountwidget.cpp gwreceiveinvitationdialog.cpp \
++		gwshowinvitation.ui gwcontactpropswidget.ui gwcontactproperties.cpp gwprivacy.ui \
++		gwprivacydialog.cpp gwsearch.cpp gwcustomstatuswidget.ui gwcustomstatusedit.ui \
++		gwcontactsearch.ui gwchatsearchwidget.ui gwchatsearchdialog.cpp gwchatpropswidget.ui \
++	gwchatpropsdialog.cpp
+ 
+ noinst_HEADERS = gwreceiveinvitationdialog.h gwcontactproperties.h \
+-		gwprivacydialog.h gwsearch.h
++				gwprivacydialog.h gwsearch.h gwchatsearchdialog.h gwchatpropsdialog.h
+--- kopete/protocols/groupwise/ui/gwprivacydialog.cpp	(revision 568672)
++++ kopete/protocols/groupwise/ui/gwprivacydialog.cpp	(revision 586398)
+@@ -179,7 +179,7 @@
+ 		m_searchDlg = new KDialogBase( this, "privacysearchdialog", false, 
+ 				i18n( "Search for Contact to Block" ),
+ 				KDialogBase::Ok|KDialogBase::Cancel );
+-		m_search = new GroupWiseSearch( m_account, QListView::Multi, false, m_searchDlg, "privacysearchwidget" );
++		m_search = new GroupWiseContactSearch( m_account, QListView::Multi, false, m_searchDlg, "privacysearchwidget" );
+ 		m_searchDlg->setMainWidget( m_search );
+ 		connect( m_searchDlg, SIGNAL( okClicked() ), SLOT( slotSearchedForUsers() ) );
+ 		connect( m_search, SIGNAL( selectionValidates( bool ) ), m_searchDlg, SLOT( enableButtonOK( bool ) ) );
+--- kopete/protocols/jabber/jabberbookmarks.cpp	(revision 0)
++++ kopete/protocols/jabber/jabberbookmarks.cpp	(revision 586398)
+@@ -0,0 +1,149 @@
++ /*
++    Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
++
++    Kopete    (c) 2006 by the Kopete developers <kopete-devel at 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 "jabberbookmarks.h"
++#include "jabberaccount.h"
++
++#include <kopetecontact.h>
++
++
++#include <kdebug.h>
++#include <kaction.h>
++#include <klocale.h>
++
++#include "xmpp_tasks.h"
++
++
++JabberBookmarks::JabberBookmarks(JabberAccount *parent) : QObject(parent) , m_account(parent) 
++{
++	connect( m_account , SIGNAL( isConnectedChanged() ) , this , SLOT( accountConnected() ) );
++}
++
++void JabberBookmarks::accountConnected()
++{
++	if(!m_account->isConnected())
++		return;
++	
++	XMPP::JT_PrivateStorage * task = new XMPP::JT_PrivateStorage ( m_account->client()->rootTask ());
++	task->get( "storage" , "storage:bookmarks" );
++	QObject::connect ( task, SIGNAL ( finished () ), this, SLOT ( slotReceivedBookmarks() ) );
++	task->go ( true );
++}
++
++void JabberBookmarks::slotReceivedBookmarks( )
++{
++	XMPP::JT_PrivateStorage * task = (XMPP::JT_PrivateStorage*)(sender());
++	m_storage=QDomDocument("storage");
++	m_conferencesJID.clear();
++	if(task->success())
++	{
++		QDomElement storage_e=task->element();
++		if(!storage_e.isNull() && storage_e.tagName() == "storage")
++		{
++			storage_e=m_storage.importNode(storage_e,true).toElement();
++			m_storage.appendChild(storage_e);
++
++			for(QDomNode n = storage_e.firstChild(); !n.isNull(); n = n.nextSibling()) 
++			{
++				QDomElement i = n.toElement();
++				if(i.isNull())
++					continue;
++				if(i.tagName() == "conference")
++				{
++					QString jid=i.attribute("jid");
++					QString password;
++					for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) {
++						QDomElement e = n.toElement();
++						if(e.isNull())
++							continue;
++						else if(e.tagName() == "nick")
++							jid+="/"+e.text();
++						else if(e.tagName() == "password")
++							password=e.text();
++						
++					}
++					m_conferencesJID += jid;
++					if(i.attribute("autojoin") == "true")
++					{
++						XMPP::Jid x_jid(jid);
++						QString nick=x_jid.resource();
++						if(nick.isEmpty())
++							nick=m_account->myself()->nickName();
++
++						if(password.isEmpty())
++							m_account->client()->joinGroupChat(x_jid.host() , x_jid.user() , nick );
++						else
++							m_account->client()->joinGroupChat(x_jid.host() , x_jid.user() , nick , password);
++					}
++				}
++			}
++		}
++	}
++}
++
++
++void JabberBookmarks::insertGroupChat(const XMPP::Jid &jid)
++{
++	if(m_conferencesJID.contains(jid.full()) || !m_account->isConnected())
++	{
++		return;
++	}
++
++	QDomElement storage_e=m_storage.documentElement();
++	if(storage_e.isNull())
++	{
++		storage_e=m_storage.createElement("storage");
++		m_storage.appendChild(storage_e);
++		storage_e.setAttribute("xmlns","storage:bookmarks");
++	}
++	
++	QDomElement conference=m_storage.createElement("conference");
++	storage_e.appendChild(conference);
++	conference.setAttribute("jid",jid.userHost());
++	QDomElement nick=m_storage.createElement("nick");
++	conference.appendChild(nick);
++	nick.appendChild(m_storage.createTextNode(jid.resource()));
++	QDomElement name=m_storage.createElement("name");
++	conference.appendChild(name);
++	name.appendChild(m_storage.createTextNode(jid.full()));
++
++		
++	XMPP::JT_PrivateStorage * task = new XMPP::JT_PrivateStorage ( m_account->client()->rootTask ());
++	task->set( storage_e );
++	task->go ( true );
++	
++	m_conferencesJID += jid.full();
++}
++
++KAction * JabberBookmarks::bookmarksAction(QObject *parent)
++{
++	KSelectAction *groupchatBM = new KSelectAction( i18n("Groupchat bookmark") , "jabber_group" , 0 , parent , "actionBookMark" );
++	groupchatBM->setItems(m_conferencesJID);
++	QObject::connect(groupchatBM, SIGNAL(activated (const QString&)) , this, SLOT(slotJoinChatBookmark(const QString&)));
++	return groupchatBM;
++}
++
++void JabberBookmarks::slotJoinChatBookmark( const QString & _jid )
++{
++	if(!m_account->isConnected())
++		return;
++	XMPP::Jid jid(_jid);
++	m_account->client()->joinGroupChat( jid.host() , jid.user() , jid.resource() );
++}
++
++
++
++#include "jabberbookmarks.moc"
++
+--- kopete/protocols/jabber/jabbercapabilitiesmanager.h	(revision 0)
++++ kopete/protocols/jabber/jabbercapabilitiesmanager.h	(revision 586398)
+@@ -0,0 +1,211 @@
++ /*
++    jabbercapabilitiesmanager.h - Manage entity capabilities(JEP-0115) pool.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    Imported from caps.cpp from Psi:
++    Copyright (C) 2005  Remko Troncon
++
++    *************************************************************************
++    *                                                                       *
++    * 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 JABBERCAPABILITIESMANAGER_H
++#define JABBERCAPABILITIESMANAGER_H
++
++#include <qobject.h>
++#include <im.h>
++#include <xmpp.h>
++
++using namespace XMPP;
++
++class JabberAccount;
++
++/**
++ * @brief Manage Jabber entity capabilities (JEP-0115)
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ * @author Remko Troncon
++ */
++class JabberCapabilitiesManager : public QObject
++{
++	Q_OBJECT
++public:
++	/**
++	 * Construct
++	 */
++	JabberCapabilitiesManager();
++	~JabberCapabilitiesManager();
++
++	/**
++	 * Load cached information from local file.
++	 */
++	void loadCachedInformation();
++
++	/**
++	 * Check if the jid support Entity capabitilies.
++	 * @param jid JID to check.
++	 * @return true if the jid support entity capabitilies.
++	 */
++	bool capabilitiesEnabled(const Jid& jid) const;
++
++	/**
++	 * Remove account from manager.
++	 */
++	void removeAccount(JabberAccount *account);
++
++	/**
++	 * Return the features supported for the JID.
++	 */
++	XMPP::Features features(const Jid& jid) const;
++	/**
++	 * Return the client name for the current JID.
++	 */
++	QString clientName(const Jid& jid) const;
++	/**
++	 * Return the client version for the current JID.
++	 */
++	QString clientVersion(const Jid& jid) const;
++
++signals:
++	void capabilitiesChanged(const XMPP::Jid &jid);
++
++public slots:
++	/**
++	 * Update if necessary the capabities for the JID passed in args.
++	 * Caps are received in Presence messages so that's why we are
++	 * passing a XMPP::Status object.
++	 *
++	 * @param jid JID that capabilities was updated.
++	 * @param status The XMPP::Status that contain the caps.
++	 */
++	void updateCapabilities(JabberAccount *account, const XMPP::Jid &jid, const XMPP::Status &status);
++
++private slots:
++	/**
++	 * @brief Called when a reply to disco#info request was received.
++	 * If the result was succesful, the resulting features are recorded in the
++	 * features database for the requested node, and all the affected jids are
++	 * put in the queue for update notification.
++	 * If the result was unsuccesful, another jid with the same capabilities is
++	 * selected and sent a disco#info query.
++	 */
++	void discoRequestFinished();
++
++private:
++	/**
++	 * @brief Sends a disco#info request to a given node of a jid through an account.
++	 * When the request is finished, the discoRequestFinished() slot is called.
++	 *
++	 * @param account The account through which to send the disco request.
++	 * @param jid The target entity's JID 
++	 * @param node The target disco#info node
++	 */
++	void requestDiscoInfo(JabberAccount *account, const Jid& jid, const QString& node);
++
++	/**
++	 * Save capabilities information to disk.
++	 */
++	void saveInformation();
++
++	class Capabilities;
++	typedef QValueList<Capabilities> CapabilitiesList;
++	/**
++	 * @brief A class representing an entity capability specification.
++	 * An entity capability is a combination of a node, a version, and a set of
++	 * extensions.
++	 */
++	class Capabilities
++	{
++		public:
++			/**
++			 * Default constructor.
++			 */
++			Capabilities();
++			/**
++			 * Define capabilities.
++			 * @param node the node
++			 * @param version the version
++			 * @param extensions the list of extensions (separated by spaces)
++			 */
++			Capabilities(const QString &node, const QString &version, const QString &extensions);
++			/**
++			 * Returns the node of the capabilities specification.
++			 */
++			const QString& node() const;
++			/**
++			 * @brief Returns the version of the capabilities specification.
++			 */
++			const QString& version() const;
++			/**
++			 * @brief Returns the extensions of the capabilities specification.
++			 */
++			const QString& extensions() const; 
++			/**
++			 * \brief Flattens the caps specification into the set of 'simple' specifications.
++			 * A 'simple' specification is a specification with exactly one extension,
++			 * or with the version number as the extension.
++			 *
++			 * Example: A caps specification with node=http://psi-im.org, version=0.10,
++			 * and ext='achat vchat' would be expanded into the following list of specs:
++			 *	node=http://psi-im.org, ver=0.10, ext=0.10
++			 *	node=http://psi-im.org, ver=0.10, ext=achat
++			 *	node=http://psi-im.org, ver=0.10, ext=vchat
++			 */
++			CapabilitiesList flatten() const;
++	
++			bool operator==(const Capabilities&) const;
++			bool operator!=(const Capabilities&) const;
++			bool operator<(const Capabilities&) const;
++				
++		private:
++			QString m_node, m_version, m_extensions;
++	};
++
++	class CapabilitiesInformation
++	{
++		public:
++			CapabilitiesInformation();
++			const QStringList& features() const;
++			const DiscoItem::Identities& identities() const;
++			QStringList jids() const;
++			bool discovered() const;
++			int pendingRequests() const;
++
++			void reset();
++			void removeAccount(JabberAccount* acc);
++			void removeJid(const Jid&);
++			void addJid(const Jid&, JabberAccount*);
++			QPair<Jid,JabberAccount*> nextJid(const Jid&, const Task*);
++			
++			void setDiscovered(bool);
++			void setPendingRequests(int);
++			void setIdentities(const DiscoItem::Identities&);
++			void setFeatures(const QStringList&);
++			
++			QDomElement toXml(QDomDocument *) const;
++			void fromXml(const QDomElement&);
++
++		protected:
++			void updateLastSeen();
++			
++		private:
++			bool m_discovered;
++			int m_pendingRequests;
++			QStringList m_features;
++			DiscoItem::Identities m_identities;
++			QValueList<QPair<QString,JabberAccount*> > m_jids;
++			QDate m_lastSeen;
++	};
++
++	class Private;
++	Private *d;
++};
++
++#endif
+--- kopete/protocols/jabber/jabbercontact.h	(revision 568672)
++++ kopete/protocols/jabber/jabbercontact.h	(revision 586398)
+@@ -18,6 +18,10 @@
+ #ifndef JABBERCONTACT_H
+ #define JABBERCONTACT_H
+ 
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
+ #include "jabberbasecontact.h"
+ #include "xmpp_vcard.h"
+ 
+@@ -34,7 +38,9 @@
+ public:
+ 
+ 	JabberContact (const XMPP::RosterItem &rosterItem,
+-				   JabberAccount *account, Kopete::MetaContact * mc);
++				   Kopete::Account *account, Kopete::MetaContact * mc, const QString &legacyId = QString());
++	
++	~JabberContact();
+ 
+ 	/**
+ 	 * Create custom context menu items for the contact
+@@ -60,11 +66,6 @@
+ 	 */
+ 	Kopete::ChatSession *manager ( Kopete::Contact::CanCreateFlags );
+ 	
+-	/**
+-	 * Reads a vCard object and updates the contact's
+-	 * properties accordingly.
+-	 */
+-	void setPropertiesFromVCard ( const XMPP::VCard &vCard );
+ 
+ 	bool isContactRequestingEvent( XMPP::MsgEvent event );
+ 
+@@ -97,15 +98,22 @@
+ 		const QString &fileName = QString::null, uint fileSize = 0L );
+ 
+ 	/**
+-	 * Retrieve a vCard for the contact
+-	 */
+-	void slotUserInfo ();
+-
+-	/**
+ 	 * Update the vCard on the server.
++	 * @todo is that still used ?
+ 	 */ 
+ 	void slotSendVCard();
+ 
++	/**
++	 * Set contact photo.
++	 * @param path Path to the photo.
++	 */
++	void setPhoto(const QString &photoPath);
++	
++	/**
++	 * this will start a voice call to the contact
++	 */
++	void voiceCall();
++
+ private slots:
+ 
+ 	/**
+@@ -178,12 +186,17 @@
+ 	 * Display a error message if the vCard sent was unsuccesful.
+ 	 */
+ 	void slotSentVCard();
+-
+-       /**
+-        * actually perform operations of sync() with a delay.
+-        * slot received by the syncTimer.
+-        */
+-       void slotDelayedSync();
++	
++	/**
++	 * The service discovery on that contact is finished
++	 */
++	void slotDiscoFinished();
++	
++	/**
++	 * actually perform operations of sync() with a delay.
++	 * slot received by the syncTimer.
++	 */
++	void slotDelayedSync();
+ private:
+ 
+ 	/**
+@@ -233,12 +246,17 @@
+ 	 * Indicates whether the vCard is currently
+ 	 * being updated or not.
+ 	 */
+-	bool mVCardUpdateInProgress;
++	bool mVCardUpdateInProgress :1;
+ 
+-	bool mRequestComposingEvent;
+-	bool mRequestOfflineEvent;
+-	bool mRequestDisplayedEvent;
+-	bool mRequestDeliveredEvent;
++	bool mRequestComposingEvent :1;
++	bool mRequestOfflineEvent :1;
++	bool mRequestDisplayedEvent :1;
++	bool mRequestDeliveredEvent :1;
++	bool mRequestGoneEvent :1;
++	/**
++	 * tell if the disco#info has been done for this contact.
++	 */
++	bool mDiscoDone :1;
+ 
+ 	QString mLastReceivedMessageId;
+ 	QTimer *m_syncTimer;
+--- kopete/protocols/jabber/jabberaccount.h	(revision 568672)
++++ kopete/protocols/jabber/jabberaccount.h	(revision 586398)
+@@ -6,9 +6,9 @@
+     copyright            : (C) 2003 by Till Gerken <till at tantalo.net>
+ 							Based on JabberProtocol by Daniel Stone <dstone at kde.org>
+ 							and Till Gerken <till at tantalo.net>.
++   copyright            : (C) 2006 by Olivier Goffart <ogoffart at kde.org>
+ 
+-			   Kopete (C) 2001-2003 Kopete developers
+-			   <kopete-devel at kde.org>.
++			   Kopete (C) 2001-2003 Kopete developers  <kopete-devel at kde.org>.
+  ***************************************************************************/
+ 
+ /***************************************************************************
+@@ -23,6 +23,10 @@
+ #ifndef JABBERACCOUNT_H
+ #define JABBERACCOUNT_H
+ 
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
+ // we need these for type reasons
+ #include <kopetepasswordedaccount.h>
+ #include <kopeteonlinestatus.h>
+@@ -36,8 +40,18 @@
+ class JabberContact;
+ class JabberContactPool;
+ class JabberProtocol;
++class JabberTransport;
++class JabberBookmarks;
++
+ namespace Kopete { class MetaContact; }
+ 
++#ifdef SUPPORT_JINGLE
++//class JingleSessionManager; 
++//class JingleSession; 
++class VoiceCaller;
++#endif
++
++
+ /* @author Daniel Stone, Till Gerken */
+ 
+ class JabberAccount : public Kopete::PasswordedAccount
+@@ -69,7 +83,19 @@
+ 	{
+ 		return m_jabberClient;
+ 	}
++	
++#ifdef SUPPORT_JINGLE
++	VoiceCaller *voiceCaller() const
++	{
++		return m_voiceCaller;
++	}
+ 
++// 	JingleSessionManager *sessionManager()  const
++// 	{
++// 		return m_jingleSessionManager;
++// 	}
++#endif
++
+ 	// change the default S5B server port
+ 	void setS5BServerPort ( int port );
+ 
+@@ -81,9 +107,6 @@
+ 	 * an answer of him. */
+ 	void errorConnectionLost ();
+ 
+-	/* Tells the user that a connection attempt is already in progress */
+-	void errorConnectionInProgress ();
+-
+ 	/*
+ 	 * Handle TLS warnings. Displays a dialog and returns the user's choice.
+ 	 * Parameters: Warning code from QCA::TLS
+@@ -102,6 +125,15 @@
+ 	 * Handle stream errors. Displays a dialog and returns.
+ 	 */
+ 	static void handleStreamError (int streamError, int streamCondition, int connectorCode, const QString &server, Kopete::Account::DisconnectReason &errorClass);
++	
++	const QMap<QString, JabberTransport *> &transports()
++	{ return m_transports; }
++	
++	
++	/** 
++	 * called when the account is removed in the config ui
++	*/
++	virtual bool removeAccount();
+ 
+ public slots:
+ 	/* Connects to the server. */
+@@ -113,9 +145,15 @@
+ 	/* Disconnect with a reason */
+ 	void disconnect ( Kopete::Account::DisconnectReason reason );
+ 
++    /* Disconnect with a reason, and status */
++    void disconnect( Kopete::Account::DisconnectReason reason, XMPP::Status &status );
+ 	/* Reimplemented from Kopete::Account */
+ 	void setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason = QString::null);
++	
++	void addTransport( JabberTransport *tr ,  const QString &jid);
++	void removeTransport( const QString &jid );
+ 
++
+ protected:
+ 	/**
+ 	 * Create a new contact in the specified metacontact
+@@ -135,6 +173,8 @@
+ 	 * @param parentContact The metacontact to add this contact to
+ 	 */
+ 	virtual bool createContact (const QString & contactID, Kopete::MetaContact * parentContact);
++	
++	
+ 
+ private:
+ 	JabberProtocol *m_protocol;
+@@ -145,6 +185,13 @@
+ 	JabberResourcePool *m_resourcePool;
+ 	JabberContactPool *m_contactPool;
+ 
++#ifdef SUPPORT_JINGLE
++	VoiceCaller *m_voiceCaller;
++	//JingleSessionManager *m_jingleSessionManager;
++#endif
++
++	JabberBookmarks *m_bookmarks;
++
+ 	/* Set up our actions for the status menu. */
+ 	void initActions ();
+ 
+@@ -164,6 +211,13 @@
+ 	 */
+ 	bool isConnecting ();
+ 
++	QMap<QString, JabberTransport *>m_transports;
++	
++	/* used in removeAccount() */
++	bool m_removing;
++	/* keep track if we told the user we were not able to bind the
++	   jabber transfer port, to avoid popup insanity */
++	bool m_notifiedUserCannotBindTransferPort;
+ private slots:
+ 	/* Connects to the server. */
+ 	void slotConnect ();
+@@ -207,12 +261,16 @@
+ 
+ 	/* Incoming subscription request. */
+ 	void slotSubscription ( const XMPP::Jid &jid, const QString &type );
++	
++	/* the dialog that asked to add the contact was closed   (that dialog is shown in slotSubscription) */
++	void slotContactAddedNotifyDialogClosed(const QString& contactid);
+ 
+ 	/**
+ 	 * A new item appeared in our roster, synch it with the
+ 	 * contact list.
++	 * (or the contact has been updated
+ 	 */
+-	void slotNewContact ( const XMPP::RosterItem & );
++	void slotContactUpdated ( const XMPP::RosterItem & );
+ 
+ 	/**
+ 	 * An item has been deleted from our roster,
+@@ -220,8 +278,6 @@
+ 	 */
+ 	void slotContactDeleted ( const XMPP::RosterItem & );
+ 
+-	/* Update a contact's details. */
+-	void slotContactUpdated ( const XMPP::RosterItem & );
+ 
+ 	/* Someone on our contact list had (another) resource come online. */
+ 	void slotResourceAvailable ( const XMPP::Jid &, const XMPP::Resource & );
+@@ -240,6 +296,14 @@
+ 
+ 	/* Update the myself information if the global identity changes. */
+ 	void slotGlobalIdentityChanged( const QString &key, const QVariant &value );
++	
++	/* we received a voice invitation */	
++	void slotIncomingVoiceCall(const Jid&);
++	
++	/* the unregister task finished */
++	void slotUnregisterFinished();
++
++	//void slotIncomingJingleSession(const QString &sessionType, JingleSession *session);
+ };
+ 
+ #endif
+--- kopete/protocols/jabber/jabberprotocol.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberprotocol.cpp	(revision 586398)
+@@ -3,6 +3,7 @@
+   *
+   * Copyright (c) 2002-2003 by Till Gerken <till at tantalo.net>
+   * Copyright (c) 2002 by Daniel Stone <dstone at kde.org>
++  * Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
+   *
+   *  Kopete   (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -46,17 +47,21 @@
+ #include "kopeteglobal.h"
+ #include "kopeteprotocol.h"
+ #include "kopeteplugin.h"
++#include "kopeteaccountmanager.h"
+ #include "addcontactpage.h"
++#include "kopetecommandhandler.h"
++
+ #include "jabbercontact.h"
+-#include "dlgjabbersendraw.h"
+-#include "dlgjabberservices.h"
+-#include "dlgjabberchatjoin.h"
+ #include "jabberaddcontactpage.h"
+ #include "jabberprotocol.h"
+ #include "jabberaccount.h"
+-#include "kopeteaccountmanager.h"
+ #include "jabbereditaccountwidget.h"
+-#include "kopetecommandhandler.h"
++#include "jabbercapabilitiesmanager.h"
++#include "jabbertransport.h"
++#include "dlgjabbersendraw.h"
++#include "dlgjabberservices.h"
++#include "dlgjabberchatjoin.h"
++#include "dlgjabberregister.h"
+ 
+ JabberProtocol *JabberProtocol::protocolInstance = 0;
+ 
+@@ -71,7 +76,7 @@
+ 	JabberKOSAway(Kopete::OnlineStatus::Away,             80, this, JabberAway, "contact_away_overlay", i18n ("Away"), i18n ("Away"), Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HasAwayMessage),
+ 	JabberKOSXA(Kopete::OnlineStatus::Away,               70, this, JabberXA, "contact_xa_overlay", i18n ("Extended Away"), i18n ("Extended Away"), 0, Kopete::OnlineStatusManager::HasAwayMessage),
+ 	JabberKOSDND(Kopete::OnlineStatus::Away,              60, this, JabberDND, "contact_busy_overlay", i18n ("Do not Disturb"), i18n ("Do not Disturb"), Kopete::OnlineStatusManager::Busy, Kopete::OnlineStatusManager::HasAwayMessage),
+-	JabberKOSOffline(Kopete::OnlineStatus::Offline,       50, this, JabberOffline, QString::null, i18n ("Offline") ,i18n ("Offline"), Kopete::OnlineStatusManager::Offline ),
++	JabberKOSOffline(Kopete::OnlineStatus::Offline,       50, this, JabberOffline, QString::null, i18n ("Offline") ,i18n ("Offline"), Kopete::OnlineStatusManager::Offline, Kopete::OnlineStatusManager::HasAwayMessage ),
+ 	JabberKOSInvisible(Kopete::OnlineStatus::Invisible,   40, this, JabberInvisible, "contact_invisible_overlay",   i18n ("Invisible") ,i18n ("Invisible"), Kopete::OnlineStatusManager::Invisible),
+ 	JabberKOSConnecting(Kopete::OnlineStatus::Connecting, 30, this, JabberConnecting, "jabber_connecting",  i18n("Connecting")),
+ 	propLastSeen(Kopete::Global::Properties::self()->lastSeen()),
+@@ -89,6 +94,7 @@
+ 	propAuthorizationStatus("jabberAuthorizationStatus", i18n ("Authorization Status"), QString::null, true, false),
+ 	propAvailableResources("jabberAvailableResources", i18n ("Available Resources"), "jabber_chatty", false, true),
+ 	propVCardCacheTimeStamp("jabberVCardCacheTimeStamp", i18n ("vCard Cache Timestamp"), QString::null, true, false, true),
++	propPhoto(Kopete::Global::Properties::self()->photo()),
+ 	propJid("jabberVCardJid", i18n("Jabber ID"), QString::null, true, false),
+ 	propBirthday("jabberVCardBirthday", i18n("Birthday"), QString::null, true, false),
+ 	propTimezone("jabberVCardTimezone", i18n("Timezone"), QString::null, true, false),
+@@ -128,12 +134,20 @@
+ 	protocolInstance = this;
+ 
+ 	addAddressBookField ("messaging/xmpp", Kopete::Plugin::MakeIndexField);
++	setCapabilities(Kopete::Protocol::FullRTF|Kopete::Protocol::CanSendOffline);
++
++	// Init the Entity Capabilities manager.
++	capsManager = new JabberCapabilitiesManager;
++	capsManager->loadCachedInformation();
+ }
+ 
+ JabberProtocol::~JabberProtocol ()
+ {
+ 	//disconnectAll();
+ 
++	delete capsManager;
++	capsManager = 0L;
++
+ 	/* make sure that the next attempt to load Jabber
+ 	 * re-initializes the protocol class. */
+ 	protocolInstance = 0L;
+@@ -150,13 +164,46 @@
+ KopeteEditAccountWidget *JabberProtocol::createEditAccountWidget (Kopete::Account * account, QWidget * parent)
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << "[Jabber Protocol] Edit Account Widget\n" << endl;
+-	return new JabberEditAccountWidget (this, static_cast < JabberAccount * >(account), parent);
++	JabberAccount *ja=dynamic_cast < JabberAccount * >(account);
++	if(ja || !account)
++		return new JabberEditAccountWidget (this,ja , parent);
++	else
++	{
++		JabberTransport *transport = dynamic_cast < JabberTransport * >(account);
++		if(!transport)
++			return 0L;
++		dlgJabberRegister *registerDialog = new dlgJabberRegister (transport->account(), transport->myself()->contactId());
++		registerDialog->show (); 
++		registerDialog->raise ();
++		return 0l; //we make ourself our own dialog, not an editAccountWidget.
++	}
+ }
+ 
+ Kopete::Account *JabberProtocol::createNewAccount (const QString & accountId)
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << "[Jabber Protocol] Create New Account. ID: " << accountId << "\n" << endl;
+-	return new JabberAccount (this, accountId);
++	if( Kopete::AccountManager::self()->findAccount( pluginId() , accountId ) )
++		return 0L;  //the account may already exist if greated just above
++
++	int slash=accountId.find('/');
++	if(slash>=0)
++	{
++		QString realAccountId=accountId.left(slash);
++		JabberAccount *realAccount=dynamic_cast<JabberAccount*>(Kopete::AccountManager::self()->findAccount( pluginId() , realAccountId ));
++		if(!realAccount) //if it doesn't exist yet, create it
++		{
++			realAccount = new JabberAccount( this, realAccountId );
++			if(!Kopete::AccountManager::self()->registerAccount(  realAccount ) )
++				return 0L;
++		}
++		if(!realAccount)
++			return 0L;
++		return new JabberTransport( realAccount , accountId );
++	}
++	else
++	{
++		return new JabberAccount (this, accountId);
++	}
+ }
+ 
+ Kopete::OnlineStatus JabberProtocol::resourceToKOS ( const XMPP::Resource &resource )
+@@ -200,16 +247,30 @@
+ 		{
+ 			status = JabberKOSDND;
+ 		}
++		else if (resource.status ().show () == "online")
++		{ // the ApaSMSAgent sms gateway report status as "online" even if it's not in the RFC 3921 § 2.2.2.1 
++			// See Bug 129059
++			status = JabberKOSOnline;
++		}
+ 		else if (resource.status ().show () == "connecting")
+-		{
++		{ // this is for kopete internals
+ 			status = JabberKOSConnecting;
+ 		}
++		else
++		{
++			kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Unknown status <show>" << resource.status ().show () << "</show> for contact. One of your contact is probably using a broken client, ask him to report a bug" << endl;
++		}
+ 	}
+ 
+ 	return status;
+ 
+ }
+ 
++JabberCapabilitiesManager *JabberProtocol::capabilitiesManager()
++{
++	return capsManager;
++}
++
+ JabberProtocol *JabberProtocol::protocol ()
+ {
+ 	// return current instance
+@@ -224,19 +285,61 @@
+ 	QString contactId = serializedData["contactId"];
+ 	QString displayName = serializedData["displayName"];
+ 	QString accountId = serializedData["accountId"];
++	QString jid = serializedData["JID"];
+ 
+ 	QDict < Kopete::Account > accounts = Kopete::AccountManager::self ()->accounts (this);
+ 	Kopete::Account *account = accounts[accountId];
+-
++	
+ 	if (!account)
+ 	{
+ 		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: Account for contact does not exist, skipping." << endl;
+ 		return 0;
+ 	}
+-
+-	if (account)
++	
++	JabberTransport *transport = dynamic_cast<JabberTransport*>(account);
++	if( transport )
++		transport->account()->addContact ( jid.isEmpty() ? contactId : jid ,  metaContact);
++	else
+ 		account->addContact (contactId,  metaContact);
+ 	return account->contacts()[contactId];
+ }
+ 
++XMPP::Status JabberProtocol::kosToStatus( const Kopete::OnlineStatus & status , const QString & message )
++{
++	XMPP::Status xmppStatus ( "", message );
++
++	if( status.status() == Kopete::OnlineStatus::Offline )
++	{
++		xmppStatus.setIsAvailable( false );
++	}
++
++	switch ( status.internalStatus () )
++	{
++		case JabberProtocol::JabberFreeForChat:
++			xmppStatus.setShow ( "chat" );
++			break;
++
++		case JabberProtocol::JabberOnline:
++			xmppStatus.setShow ( "" );
++			break;
++
++		case JabberProtocol::JabberAway:
++			xmppStatus.setShow ( "away" );
++			break;
++
++		case JabberProtocol::JabberXA:
++			xmppStatus.setShow ( "xa" );
++			break;
++
++		case JabberProtocol::JabberDND:
++			xmppStatus.setShow ( "dnd" );
++			break;
++
++		case JabberProtocol::JabberInvisible:
++			xmppStatus.setIsInvisible ( true );
++			break;
++	}
++	return xmppStatus;
++}
++
+ #include "jabberprotocol.moc"
+--- kopete/protocols/jabber/jabbertransport.h	(revision 0)
++++ kopete/protocols/jabber/jabbertransport.h	(revision 586398)
+@@ -0,0 +1,138 @@
++ /*
++
++    Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
++
++    Kopete    (c) 2006 by the Kopete developers <kopete-devel at 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 JABBERTRANSPORT_H
++#define JABBERTRANSPORT_H
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++
++#include <kopeteaccount.h>
++
++
++namespace XMPP { 
++	class Jid;
++	class RosterItem;
++}
++class JabberAccount;
++class JabberProtocol;
++
++/**
++ * this class handle a jabber gateway
++ * @author Olivier Goffart */
++
++class JabberTransport : public Kopete::Account
++{
++	Q_OBJECT
++
++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: "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 QString& gateway_type=QString());
++	
++	/**
++	 * constructor called when the transport is loaded from config
++	 * @param parentAccount is the parent jabber account.
++	 * @param accountId is the accountId
++	 */
++	JabberTransport (JabberAccount * parentAccount, const QString &accountId );
++
++	~JabberTransport ();
++
++	/** Returns the action menu for this account. */
++	virtual KActionMenu *actionMenu ();
++	
++	/** the parent account */
++	JabberAccount *account() const 
++	{ return m_account; }
++
++	/* to get the protocol from the account */
++	JabberProtocol *protocol () const;
++
++	void connect( const Kopete::OnlineStatus& ) {}
++	virtual void disconnect( ) {}
++	
++	/** 
++	 * called when the account is removed in the config ui
++	 * will remove the subscription
++	 */
++	virtual bool removeAccount();
++	
++
++	enum TransportStatus { Normal , Creating, Removing , AccountRemoved };
++	TransportStatus transportStatus() { return m_status; };
++	
++	/**
++	 * return the legacyId conrresponding to the jid
++	 *  example:  jhon%msn.com at msn.foojabber.org  ->  jhon at msn.com
++	 */
++	QString legacyId( const XMPP::Jid &jid );
++	
++public slots:
++
++	/* Reimplemented from Kopete::Account */
++	void setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason = QString::null);
++	
++	/**
++	 * the account has been unregistered.
++	 * loop over all contact and remove them
++	 */
++	void removeAllContacts();
++	
++	/**
++	 * the JabberAccount has been removed from Kopete,  remove this account also
++	 */
++	void jabberAccountRemoved();
++
++	/**
++	 *  "eat" all contact in the account that have the same domain as us.
++	 */
++	void eatContacts();
++
++protected:
++	/**
++	 * Create a new contact in the specified metacontact
++	 *
++	 * You shouldn't ever call this method yourself, For adding contacts see @ref addContact()
++	 *
++	 * This method is called by @ref Kopete::Account::addContact() in this method, you should
++	 * simply create the new custom @ref Kopete::Contact in the given metacontact. You should
++	 * NOT add the contact to the server here as this method gets only called when synchronizing
++	 * the contact list on disk with the one in memory. As such, all created contacts from this
++	 * method should have the "dirty" flag set.
++	 *
++	 * This method should simply be used to intantiate the new contact, everything else
++	 * (updating the GUI, parenting to meta contact, etc.) is being taken care of.
++	 *
++	 * @param contactId The unique ID for this protocol
++	 * @param parentContact The metacontact to add this contact to
++	 */
++	virtual bool createContact (const QString & contactID, Kopete::MetaContact * parentContact);
++
++private:
++	JabberAccount *m_account;
++	TransportStatus m_status;
++
++};
++
++#endif
+--- kopete/protocols/jabber/jabbergroupmembercontact.h	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupmembercontact.h	(revision 586398)
+@@ -66,11 +66,6 @@
+ 	virtual void sendFile( const KURL &sourceURL = KURL(),
+ 		const QString &fileName = QString::null, uint fileSize = 0L );
+ 
+-	/**
+-	 * Retrieve a vCard for the contact
+-	 */
+-	void slotUserInfo ();
+-
+ private slots:
+ 	/**
+ 	 * Catch a dying message manager
+--- kopete/protocols/jabber/libiris/008_chatstatesfix.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/008_chatstatesfix.patch	(revision 586398)
+@@ -0,0 +1,38 @@
++Index: iris/xmpp-im/types.cpp
++===================================================================
++--- iris/xmpp-im/types.cpp	(revision 526236)
+++++ iris/xmpp-im/types.cpp	(working copy)
++@@ -544,7 +544,7 @@
++ 			else
++ 				x.appendChild(s.createTextElement("jabber:x:event","id",d->eventId));
++ 		}
++-		else
+++		else if (d->type=="chat" || d->type=="groupchat")
++ 			s.appendChild(  s.createElement(NS_CHATSTATES , "active" ) );
++ 
++ 		bool need_x_event=false;
++@@ -565,20 +565,20 @@
++ 				case ComposingEvent: 
++ 					x.appendChild(s.createElement("jabber:x:event", "composing"));
++ 					need_x_event=true;
++-					if (d->body.isEmpty())
+++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++ 						s.appendChild(  s.createElement(NS_CHATSTATES , "composing" ) ); 
++ 					break;
++ 				case CancelEvent:
++ 					need_x_event=true;
++-					if (d->body.isEmpty())
+++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++ 						s.appendChild(  s.createElement(NS_CHATSTATES , "paused" ) ); 
++ 					break;
++ 				case InactiveEvent:
++-					if (d->body.isEmpty())
+++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++ 						s.appendChild(  s.createElement(NS_CHATSTATES , "inactive" ) ); 
++ 					break;
++ 				case GoneEvent:
++-					if (d->body.isEmpty())
+++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++ 						s.appendChild(  s.createElement(NS_CHATSTATES , "gone" ) ); 
++ 					break;
++ 			}
+--- kopete/protocols/jabber/libiris/006_private_storage.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/006_private_storage.patch	(revision 586398)
+@@ -0,0 +1,130 @@
++Index: iris/xmpp-im/xmpp_tasks.h
++===================================================================
++--- iris/xmpp-im/xmpp_tasks.h	(revision 499691)
+++++ iris/xmpp-im/xmpp_tasks.h	(working copy)
++@@ -459,6 +459,27 @@
++ 		class Private;
++ 		Private *d;
++ 	};
+++	
+++	class JT_PrivateStorage : public Task
+++	{
+++		Q_OBJECT
+++	public:
+++		JT_PrivateStorage(Task *parent);
+++		~JT_PrivateStorage();
+++
+++		void set(const QDomElement &);
+++		void get(const QString &tag, const QString& xmlns);
+++		
+++		QDomElement element();
+++
+++		void onGo();
+++		bool take(const QDomElement &);
+++		
+++	private:
+++		class Private;
+++		Private *d;
+++	};
+++	
++ }
++ 
++ #endif
++Index: iris/xmpp-im/xmpp_tasks.cpp
++===================================================================
++--- iris/xmpp-im/xmpp_tasks.cpp	(revision 499691)
+++++ iris/xmpp-im/xmpp_tasks.cpp	(working copy)
++@@ -2028,3 +2028,93 @@
++ 	send(tag);
++ 	setSuccess();
++ }
+++
+++
+++//----------------------------------------------------------------------------
+++// JT_PrivateStorage
+++//----------------------------------------------------------------------------
+++class JT_PrivateStorage::Private
+++{
+++	public:
+++		Private() : type(-1) {}
+++
+++		QDomElement iq;
+++		QDomElement elem;
+++		int type;
+++};
+++
+++JT_PrivateStorage::JT_PrivateStorage(Task *parent)
+++	:Task(parent)
+++{
+++	d = new Private;
+++}
+++
+++JT_PrivateStorage::~JT_PrivateStorage()
+++{
+++	delete d;
+++}
+++
+++void JT_PrivateStorage::get(const QString& tag, const QString& xmlns)
+++{
+++	d->type = 0;
+++	d->iq = createIQ(doc(), "get" , QString() , id() );
+++	QDomElement query = doc()->createElement("query");
+++	query.setAttribute("xmlns", "jabber:iq:private");
+++	d->iq.appendChild(query);
+++	QDomElement s = doc()->createElement(tag);
+++	if(!xmlns.isEmpty())
+++		s.setAttribute("xmlns", xmlns);
+++	query.appendChild(s);
+++}
+++
+++void JT_PrivateStorage::set(const QDomElement& element)
+++{
+++	d->type = 1;
+++	d->elem=element;
+++	QDomNode n=doc()->importNode(element,true);
+++
+++	d->iq = createIQ(doc(), "set" , QString() , id() );
+++	QDomElement query = doc()->createElement("query");
+++	query.setAttribute("xmlns", "jabber:iq:private");
+++	d->iq.appendChild(query);
+++	query.appendChild(n);
+++}
+++
+++void JT_PrivateStorage::onGo()
+++{
+++	send(d->iq);
+++}
+++
+++bool JT_PrivateStorage::take(const QDomElement &x)
+++{
+++	QString to = client()->host();
+++	if(!iqVerify(x, to, id()))
+++		return false;
+++
+++	if(x.attribute("type") == "result") {
+++		if(d->type == 0) {
+++			QDomElement q = queryTag(x);
+++			for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
+++				QDomElement i = n.toElement();
+++				if(i.isNull())
+++					continue;
+++				d->elem=i;
+++				break;
+++			}
+++		}
+++		setSuccess();
+++		return true;
+++	}
+++	else {
+++		setError(x);
+++	}
+++
+++	return true;
+++}
+++
+++
+++QDomElement JT_PrivateStorage::element( )
+++{
+++	return d->elem;
+++}
+++
+--- kopete/protocols/jabber/libiris/004_xhtml_im.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/004_xhtml_im.patch	(revision 586398)
+@@ -0,0 +1,266 @@
++Index: iris/include/xmpp.h
++===================================================================
++--- iris/include/xmpp.h	(revision 470311)
+++++ iris/include/xmpp.h	(working copy)
++@@ -318,8 +318,11 @@
++ 
++ 		QDomDocument & doc() const;
++ 		QString baseNS() const;
+++		QString xhtmlImNS() const;
+++		QString xhtmlNS() const;
++ 		QDomElement createElement(const QString &ns, const QString &tagName);
++ 		QDomElement createTextElement(const QString &ns, const QString &tagName, const QString &text);
+++		QDomElement createXHTMLElement(const QString &xHTML);
++ 		void appendChild(const QDomElement &e);
++ 
++ 		Kind kind() const;
++@@ -372,6 +375,8 @@
++ 
++ 		virtual QDomDocument & doc() const=0;
++ 		virtual QString baseNS() const=0;
+++		virtual QString xhtmlImNS() const=0;
+++		virtual QString xhtmlNS() const=0;
++ 		virtual bool old() const=0;
++ 
++ 		virtual void close()=0;
++@@ -479,6 +484,8 @@
++ 		// reimplemented
++ 		QDomDocument & doc() const;
++ 		QString baseNS() const;
+++		QString xhtmlImNS() const;
+++		QString xhtmlNS() const;
++ 		bool old() const;
++ 
++ 		void close();
++Index: iris/include/im.h
++===================================================================
++--- iris/include/im.h	(revision 470311)
+++++ iris/include/im.h	(working copy)
++@@ -65,6 +65,7 @@
++ 		QString lang() const;
++ 		QString subject(const QString &lang="") const;
++ 		QString body(const QString &lang="") const;
+++		QString xHTMLBody(const QString &lang="") const;
++ 		QString thread() const;
++ 		Stanza::Error error() const;
++ 
++@@ -75,6 +76,7 @@
++ 		void setLang(const QString &s);
++ 		void setSubject(const QString &s, const QString &lang="");
++ 		void setBody(const QString &s, const QString &lang="");
+++		void setXHTMLBody(const QString &s, const QString &lang="", const QString &attr = "");
++ 		void setThread(const QString &s);
++ 		void setError(const Stanza::Error &err);
++ 
++@@ -286,6 +288,7 @@
++ 		bool canSearch() const;
++ 		bool canGroupchat() const;
++ 		bool canDisco() const;
+++		bool canXHTML() const;
++ 		bool isGateway() const;
++ 		bool haveVCard() const;
++ 
++@@ -298,6 +301,7 @@
++ 			FID_Disco,
++ 			FID_Gateway,
++ 			FID_VCard,
+++			FID_Xhtml,
++ 
++ 			// private Psi actions
++ 			FID_Add
++Index: iris/xmpp-im/types.cpp
++===================================================================
++--- iris/xmpp-im/types.cpp	(revision 470311)
+++++ iris/xmpp-im/types.cpp	(working copy)
++@@ -19,7 +19,7 @@
++  */
++ 
++ #include"im.h"
++-
+++#include "protocol.h"
++ #include<qmap.h>
++ #include<qapplication.h>
++ 
++@@ -180,7 +180,8 @@
++ 	Jid to, from;
++ 	QString id, type, lang;
++ 
++-	StringMap subject, body;
+++	StringMap subject, body, xHTMLBody;
+++
++ 	QString thread;
++ 	Stanza::Error error;
++ 
++@@ -279,6 +280,11 @@
++ 	return d->body[lang];
++ }
++ 
+++QString Message::xHTMLBody(const QString &lang) const
+++{
+++	return d->xHTMLBody[lang];
+++}
+++
++ QString Message::thread() const
++ {
++ 	return d->thread;
++@@ -340,9 +346,16 @@
++ void Message::setBody(const QString &s, const QString &lang)
++ {
++ 	d->body[lang] = s;
++-	//d->flag = false;
++ }
++ 
+++void Message::setXHTMLBody(const QString &s, const QString &lang, const QString &attr)
+++{
+++	//ugly but needed if s is not a node but a list of leaf
+++
+++	QString content = "<body xmlns='" + QString(NS_XHTML) + "' "+attr+" >\n" + s +"\n</body>";
+++	d->xHTMLBody[lang] = content;
+++}
+++
++ void Message::setThread(const QString &s)
++ {
++ 	d->thread = s;
++@@ -489,7 +502,19 @@
++ 			s.appendChild(e);
++ 		}
++ 	}
++-
+++	if ( !d->xHTMLBody.isEmpty()) {
+++		QDomElement parent = s.createElement(s.xhtmlImNS(), "html");
+++		for(it = d->xHTMLBody.begin(); it != d->xHTMLBody.end(); ++it) {
+++			const QString &str = it.data();
+++			if(!str.isEmpty()) {
+++				QDomElement child = s.createXHTMLElement(str);
+++				if(!it.key().isEmpty())
+++					child.setAttributeNS(NS_XML, "xml:lang", it.key());
+++				parent.appendChild(child);
+++			}
+++		}
+++		s.appendChild(parent);
+++	}
++ 	if(d->type == "error")
++ 		s.setError(d->error);
++ 
++@@ -591,6 +616,21 @@
++ 				else if(e.tagName() == "thread")
++ 					d->thread = e.text();
++ 			}
+++			else if (e.namespaceURI() == s.xhtmlImNS()) {
+++				 if (e.tagName() == "html") {
+++					QDomNodeList htmlNL= e.childNodes();
+++					for (unsigned int x = 0; x < htmlNL.count(); x++) {
+++						QDomElement i = htmlNL.item(x).toElement();
+++
+++						if (i.tagName() == "body") {
+++							QDomDocument RichText;
+++							QString lang = i.attributeNS(NS_XML, "lang", "");
+++							RichText.appendChild(i);
+++							d-> xHTMLBody[lang] = RichText.toString();
+++						}
+++					}
+++				}
+++			}
++ 			else {
++ 				//printf("extension element: [%s]\n", e.tagName().latin1());
++ 			}
++@@ -1418,6 +1458,16 @@
++ 	return test(ns);
++ }
++ 
+++#define FID_XHTML  "http://jabber.org/protocol/xhtml-im"
+++bool Features::canXHTML() const
+++{
+++	QStringList ns;
+++
+++	ns << FID_XHTML;
+++
+++	return test(ns);
+++}
+++
++ #define FID_GROUPCHAT "jabber:iq:conference"
++ bool Features::canGroupchat() const
++ {
++Index: iris/xmpp-im/xmpp_tasks.cpp
++===================================================================
++--- iris/xmpp-im/xmpp_tasks.cpp	(revision 470311)
+++++ iris/xmpp-im/xmpp_tasks.cpp	(working copy)
++@@ -1348,6 +1348,10 @@
++ 		query.appendChild(feature);
++ 
++ 		feature = doc()->createElement("feature");
+++		feature.setAttribute("var", "http://jabber.org/protocol/xhtml-im");
+++		query.appendChild(feature);
+++
+++		feature = doc()->createElement("feature");
++ 		feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
++ 		query.appendChild(feature);
++ 
++Index: iris/xmpp-core/protocol.h
++===================================================================
++--- iris/xmpp-core/protocol.h	(revision 470311)
+++++ iris/xmpp-core/protocol.h	(working copy)
++@@ -35,6 +35,8 @@
++ #define NS_SESSION  "urn:ietf:params:xml:ns:xmpp-session"
++ #define NS_STANZAS  "urn:ietf:params:xml:ns:xmpp-stanzas"
++ #define NS_BIND     "urn:ietf:params:xml:ns:xmpp-bind"
+++#define NS_XHTML_IM "http://jabber.org/protocol/xhtml-im"
+++#define NS_XHTML "http://www.w3.org/1999/xhtml"
++ 
++ namespace XMPP
++ {
++Index: iris/xmpp-core/stream.cpp
++===================================================================
++--- iris/xmpp-core/stream.cpp	(revision 470311)
+++++ iris/xmpp-core/stream.cpp	(working copy)
++@@ -293,6 +293,16 @@
++ 	return d->s->baseNS();
++ }
++ 
+++QString Stanza::xhtmlImNS() const
+++{
+++	return d->s->xhtmlImNS();
+++}
+++
+++QString Stanza::xhtmlNS() const
+++{
+++	return d->s->xhtmlNS();
+++}
+++
++ QDomElement Stanza::createElement(const QString &ns, const QString &tagName)
++ {
++ 	return d->s->doc().createElementNS(ns, tagName);
++@@ -305,6 +315,16 @@
++ 	return e;
++ }
++ 
+++QDomElement Stanza::createXHTMLElement(const QString &xHTML)
+++{
+++	QDomDocument doc;
+++
+++  	doc.setContent(xHTML, true);
+++	QDomElement root = doc.documentElement();
+++	//QDomElement e;
+++	return (root);
+++}
+++
++ void Stanza::appendChild(const QDomElement &e)
++ {
++ 	d->e.appendChild(e);
++@@ -861,6 +881,16 @@
++ 	return NS_CLIENT;
++ }
++ 
+++QString ClientStream::xhtmlImNS() const
+++{
+++	return NS_XHTML_IM;
+++}
+++
+++QString ClientStream::xhtmlNS() const
+++{
+++	return NS_XHTML;
+++}
+++
++ void ClientStream::setAllowPlain(bool b)
++ {
++ 	d->allowPlain = b;
+--- kopete/protocols/jabber/libiris/005_join_muc_with_password.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/005_join_muc_with_password.patch	(revision 586398)
+@@ -0,0 +1,163 @@
++Index: iris/include/im.h
++===================================================================
++--- iris/include/im.h	(révision 498969)
+++++ iris/include/im.h	(copie de travail)
++@@ -607,6 +607,7 @@
++ 		FileTransferManager *fileTransferManager() const;
++ 
++ 		bool groupChatJoin(const QString &host, const QString &room, const QString &nick);
+++		bool groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString &password);
++ 		void groupChatSetStatus(const QString &host, const QString &room, const Status &);
++ 		void groupChatChangeNick(const QString &host, const QString &room, const QString &nick, const Status &);
++ 		void groupChatLeave(const QString &host, const QString &room);
++Index: iris/xmpp-im/client.cpp
++===================================================================
++--- iris/xmpp-im/client.cpp	(révision 498969)
+++++ iris/xmpp-im/client.cpp	(copie de travail)
++@@ -315,6 +315,35 @@
++ 	return true;
++ }
++ 
+++bool Client::groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString &password)
+++{
+++	Jid jid(room + "@" + host + "/" + nick);
+++	for(QValueList<GroupChat>::Iterator it = d->groupChatList.begin(); it != d->groupChatList.end();) {
+++		GroupChat &i = *it;
+++		if(i.j.compare(jid, false)) {
+++			// if this room is shutting down, then free it up
+++			if(i.status == GroupChat::Closing)
+++				it = d->groupChatList.remove(it);
+++			else
+++				return false;
+++		}
+++		else
+++			++it;
+++	}
+++
+++	debug(QString("Client: Joined: [%1]\n").arg(jid.full()));
+++	GroupChat i;
+++	i.j = jid;
+++	i.status = GroupChat::Connecting;
+++	d->groupChatList += i;
+++
+++	JT_MucPresence *j = new JT_MucPresence(rootTask());
+++	j->pres(jid, Status(), password);
+++	j->go(true);
+++
+++	return true;
+++}
+++
++ void Client::groupChatSetStatus(const QString &host, const QString &room, const Status &_s)
++ {
++ 	Jid jid(room + "@" + host);
++Index: iris/xmpp-im/xmpp_tasks.h
++===================================================================
++--- iris/xmpp-im/xmpp_tasks.h	(révision 498969)
+++++ iris/xmpp-im/xmpp_tasks.h	(copie de travail)
++@@ -439,6 +439,26 @@
++ 		class Private;
++ 		Private *d;
++ 	};
+++
+++	class JT_MucPresence : public Task
+++	{
+++		Q_OBJECT
+++	public:
+++		JT_MucPresence(Task *parent);
+++		~JT_MucPresence();
+++
+++		void pres(const Status &);
+++		void pres(const Jid &, const Status &, const QString &password);
+++
+++		void onGo();
+++
+++	private:
+++		QDomElement tag;
+++		int type;
+++
+++		class Private;
+++		Private *d;
+++	};
++ }
++ 
++ #endif
++Index: iris/xmpp-im/xmpp_tasks.cpp
++===================================================================
++--- iris/xmpp-im/xmpp_tasks.cpp	(révision 498969)
+++++ iris/xmpp-im/xmpp_tasks.cpp	(copie de travail)
++@@ -1956,3 +1956,75 @@
++ 	return true;
++ }
++ 
+++//----------------------------------------------------------------------------
+++// JT_MucPresence
+++//----------------------------------------------------------------------------
+++JT_MucPresence::JT_MucPresence(Task *parent)
+++:Task(parent)
+++{
+++	type = -1;
+++}
+++
+++JT_MucPresence::~JT_MucPresence()
+++{
+++}
+++
+++void JT_MucPresence::pres(const Status &s)
+++{
+++	type = 0;
+++
+++	tag = doc()->createElement("presence");
+++	if(!s.isAvailable()) {
+++		tag.setAttribute("type", "unavailable");
+++		if(!s.status().isEmpty())
+++			tag.appendChild(textTag(doc(), "status", s.status()));
+++	}
+++	else {
+++		if(s.isInvisible())
+++			tag.setAttribute("type", "invisible");
+++
+++		if(!s.show().isEmpty())
+++			tag.appendChild(textTag(doc(), "show", s.show()));
+++		if(!s.status().isEmpty())
+++			tag.appendChild(textTag(doc(), "status", s.status()));
+++
+++		tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) );
+++
+++		if(!s.keyID().isEmpty()) {
+++			QDomElement x = textTag(doc(), "x", s.keyID());
+++			x.setAttribute("xmlns", "http://jabber.org/protocol/e2e");
+++			tag.appendChild(x);
+++		}
+++		if(!s.xsigned().isEmpty()) {
+++			QDomElement x = textTag(doc(), "x", s.xsigned());
+++			x.setAttribute("xmlns", "jabber:x:signed");
+++			tag.appendChild(x);
+++		}
+++
+++		if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) {
+++			QDomElement c = doc()->createElement("c");
+++			c.setAttribute("xmlns","http://jabber.org/protocol/caps");
+++			c.setAttribute("node",s.capsNode());
+++			c.setAttribute("ver",s.capsVersion());
+++			if (!s.capsExt().isEmpty()) 
+++				c.setAttribute("ext",s.capsExt());
+++			tag.appendChild(c);
+++		}
+++	}
+++}
+++
+++void JT_MucPresence::pres(const Jid &to, const Status &s, const QString &password)
+++{
+++	pres(s);
+++	tag.setAttribute("to", to.full());
+++	QDomElement x = textTag(doc(), "x", s.xsigned());
+++	x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+++	x.appendChild( textTag(doc(), "password", password.latin1()) );
+++	tag.appendChild(x);
+++}
+++
+++void JT_MucPresence::onGo()
+++{
+++	send(tag);
+++	setSuccess();
+++}
+--- kopete/protocols/jabber/libiris/iris/include/xmpp.h	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/include/xmpp.h	(revision 586398)
+@@ -318,8 +318,11 @@
+ 
+ 		QDomDocument & doc() const;
+ 		QString baseNS() const;
++		QString xhtmlImNS() const;
++		QString xhtmlNS() const;
+ 		QDomElement createElement(const QString &ns, const QString &tagName);
+ 		QDomElement createTextElement(const QString &ns, const QString &tagName, const QString &text);
++		QDomElement createXHTMLElement(const QString &xHTML);
+ 		void appendChild(const QDomElement &e);
+ 
+ 		Kind kind() const;
+@@ -372,6 +375,8 @@
+ 
+ 		virtual QDomDocument & doc() const=0;
+ 		virtual QString baseNS() const=0;
++		virtual QString xhtmlImNS() const=0;
++		virtual QString xhtmlNS() const=0;
+ 		virtual bool old() const=0;
+ 
+ 		virtual void close()=0;
+@@ -479,6 +484,8 @@
+ 		// reimplemented
+ 		QDomDocument & doc() const;
+ 		QString baseNS() const;
++		QString xhtmlImNS() const;
++		QString xhtmlNS() const;
+ 		bool old() const;
+ 
+ 		void close();
+--- kopete/protocols/jabber/libiris/iris/include/im.h	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/include/im.h	(revision 586398)
+@@ -22,6 +22,7 @@
+ #define XMPP_IM_H
+ 
+ #include<qdatetime.h>
++#include<qvaluelist.h>
+ #include"xmpp.h"
+ 
+ namespace XMPP
+@@ -48,7 +49,7 @@
+ 	typedef QValueList<Url> UrlList;
+ 	typedef QMap<QString, QString> StringMap;
+ 	typedef enum { OfflineEvent, DeliveredEvent, DisplayedEvent,
+-			ComposingEvent, CancelEvent } MsgEvent;
++			ComposingEvent, CancelEvent, InactiveEvent, GoneEvent } MsgEvent;
+                                            
+ 	class Message
+ 	{
+@@ -65,6 +66,7 @@
+ 		QString lang() const;
+ 		QString subject(const QString &lang="") const;
+ 		QString body(const QString &lang="") const;
++		QString xHTMLBody(const QString &lang="") const;
+ 		QString thread() const;
+ 		Stanza::Error error() const;
+ 
+@@ -75,6 +77,7 @@
+ 		void setLang(const QString &s);
+ 		void setSubject(const QString &s, const QString &lang="");
+ 		void setBody(const QString &s, const QString &lang="");
++		void setXHTMLBody(const QString &s, const QString &lang="", const QString &attr = "");
+ 		void setThread(const QString &s);
+ 		void setError(const Stanza::Error &err);
+ 
+@@ -153,6 +156,9 @@
+ 
+ 		const QString & xsigned() const;
+ 		const QString & songTitle() const;
++		const QString & capsNode() const;
++		const QString & capsVersion() const;
++		const QString & capsExt() const;
+ 
+ 		void setPriority(int);
+ 		void setShow(const QString &);
+@@ -162,6 +168,9 @@
+ 		void setIsAvailable(bool);
+ 		void setIsInvisible(bool);
+ 		void setError(int, const QString &);
++		void setCapsNode(const QString&);
++		void setCapsVersion(const QString&);
++		void setCapsExt(const QString&);
+ 
+ 		void setXSigned(const QString &);
+ 		void setSongTitle(const QString &);
+@@ -176,6 +185,7 @@
+ 		QString v_xsigned;
+ 		// gabber song extension
+ 		QString v_songTitle;
++		QString v_capsNode, v_capsVersion, v_capsExt;
+ 
+ 		int ecode;
+ 		QString estr;
+@@ -285,7 +295,9 @@
+ 		bool canRegister() const;
+ 		bool canSearch() const;
+ 		bool canGroupchat() const;
++		bool canVoice() const;
+ 		bool canDisco() const;
++		bool canXHTML() const;
+ 		bool isGateway() const;
+ 		bool haveVCard() const;
+ 
+@@ -298,6 +310,7 @@
+ 			FID_Disco,
+ 			FID_Gateway,
+ 			FID_VCard,
++			FID_Xhtml,
+ 
+ 			// private Psi actions
+ 			FID_Add
+@@ -567,12 +580,25 @@
+ 		int timeZoneOffset() const;
+ 		QString clientName() const;
+ 		QString clientVersion() const;
++		QString capsNode() const;
++		QString capsVersion() const;
++		QString capsExt() const;
+ 
+ 		void setOSName(const QString &);
+ 		void setTimeZone(const QString &, int);
+ 		void setClientName(const QString &);
+ 		void setClientVersion(const QString &);
++		void setCapsNode(const QString &);
++		void setCapsVersion(const QString &);
+ 
++		void setIdentity(DiscoItem::Identity);
++		DiscoItem::Identity identity();
++
++		void addExtension(const QString& ext, const Features& f);
++		void removeExtension(const QString& ext);
++		const Features& extension(const QString& ext) const;
++		QStringList extensions() const;
++		
+ 		S5BManager *s5bManager() const;
+ 		IBBManager *ibbManager() const;
+ 		JidLinkManager *jidLinkManager() const;
+@@ -581,6 +607,7 @@
+ 		FileTransferManager *fileTransferManager() const;
+ 
+ 		bool groupChatJoin(const QString &host, const QString &room, const QString &nick);
++		bool groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString &password);
+ 		void groupChatSetStatus(const QString &host, const QString &room, const Status &);
+ 		void groupChatChangeNick(const QString &host, const QString &room, const QString &nick, const Status &);
+ 		void groupChatLeave(const QString &host, const QString &room);
+--- kopete/protocols/jabber/libiris/iris/xmpp-im/client.cpp	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-im/client.cpp	(revision 586398)
+@@ -70,6 +70,7 @@
+ //!  \endcode
+ 
+ #include<stdarg.h>
++#include<qmap.h>
+ #include<qobjectlist.h>
+ #include<qtimer.h>
+ #include<qguardedptr.h>
+@@ -125,7 +126,9 @@
+ 	int id_seed;
+ 	Task *root;
+ 	QString host, user, pass, resource;
+-	QString osname, tzname, clientName, clientVersion;
++	QString osname, tzname, clientName, clientVersion, capsNode, capsVersion, capsExt;
++	DiscoItem::Identity identity;
++	QMap<QString,Features> extension_features;
+ 	int tzoffset;
+ 	bool active;
+ 
+@@ -149,6 +152,9 @@
+ 	d->osname = "N/A";
+ 	d->clientName = "N/A";
+ 	d->clientVersion = "0.0";
++	d->capsNode = "";
++	d->capsVersion = "";
++	d->capsExt = "";
+ 
+ 	d->id_seed = 0xaaaa;
+ 	d->root = new Task(this, true);
+@@ -309,6 +315,35 @@
+ 	return true;
+ }
+ 
++bool Client::groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString &password)
++{
++	Jid jid(room + "@" + host + "/" + nick);
++	for(QValueList<GroupChat>::Iterator it = d->groupChatList.begin(); it != d->groupChatList.end();) {
++		GroupChat &i = *it;
++		if(i.j.compare(jid, false)) {
++			// if this room is shutting down, then free it up
++			if(i.status == GroupChat::Closing)
++				it = d->groupChatList.remove(it);
++			else
++				return false;
++		}
++		else
++			++it;
++	}
++
++	debug(QString("Client: Joined: [%1]\n").arg(jid.full()));
++	GroupChat i;
++	i.j = jid;
++	i.status = GroupChat::Connecting;
++	d->groupChatList += i;
++
++	JT_MucPresence *j = new JT_MucPresence(rootTask());
++	j->pres(jid, Status(), password);
++	j->go(true);
++
++	return true;
++}
++
+ void Client::groupChatSetStatus(const QString &host, const QString &room, const Status &_s)
+ {
+ 	Jid jid(room + "@" + host);
+@@ -996,6 +1031,21 @@
+ 	return d->clientVersion;
+ }
+ 
++QString Client::capsNode() const
++{
++	return d->capsNode;
++}
++
++QString Client::capsVersion() const
++{
++	return d->capsVersion;
++}
++
++QString Client::capsExt() const
++{
++	return d->capsExt;
++}
++
+ void Client::setOSName(const QString &name)
+ {
+ 	d->osname = name;
+@@ -1017,6 +1067,52 @@
+ 	d->clientVersion = s;
+ }
+ 
++void Client::setCapsNode(const QString &s)
++{
++	d->capsNode = s;
++}
++
++void Client::setCapsVersion(const QString &s)
++{
++	d->capsVersion = s;
++}
++
++DiscoItem::Identity Client::identity()
++{
++	return d->identity;
++}
++
++void Client::setIdentity(DiscoItem::Identity identity)
++{
++	d->identity = identity;
++}
++
++void Client::addExtension(const QString& ext, const Features& features)
++{
++	if (!ext.isEmpty()) {
++		d->extension_features[ext] = features;
++		d->capsExt = extensions().join(" ");
++	}
++}
++
++void Client::removeExtension(const QString& ext)
++{
++	if (d->extension_features.contains(ext)) {
++		d->extension_features.remove(ext);
++		d->capsExt = extensions().join(" ");
++	}
++}
++
++QStringList Client::extensions() const
++{
++	return d->extension_features.keys();
++}
++
++const Features& Client::extension(const QString& ext) const
++{
++	return d->extension_features[ext];
++}
++
+ void Client::s5b_incomingReady()
+ {
+ 	S5BConnection *c = d->s5bman->takeIncoming();
+--- kopete/protocols/jabber/libiris/iris/xmpp-im/xmpp_tasks.h	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-im/xmpp_tasks.h	(revision 586398)
+@@ -412,6 +412,8 @@
+ 		void get(const DiscoItem &);
+ 	
+ 		const DiscoItem &item() const;
++		const Jid& jid() const;
++		const QString& node() const;
+ 	
+ 		void onGo();
+ 		bool take(const QDomElement &);
+@@ -437,6 +439,47 @@
+ 		class Private;
+ 		Private *d;
+ 	};
++
++	class JT_MucPresence : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_MucPresence(Task *parent);
++		~JT_MucPresence();
++
++		void pres(const Status &);
++		void pres(const Jid &, const Status &, const QString &password);
++
++		void onGo();
++
++	private:
++		QDomElement tag;
++		int type;
++
++		class Private;
++		Private *d;
++	};
++	
++	class JT_PrivateStorage : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_PrivateStorage(Task *parent);
++		~JT_PrivateStorage();
++
++		void set(const QDomElement &);
++		void get(const QString &tag, const QString& xmlns);
++		
++		QDomElement element();
++
++		void onGo();
++		bool take(const QDomElement &);
++		
++	private:
++		class Private;
++		Private *d;
++	};
++	
+ }
+ 
+ #endif
+--- kopete/protocols/jabber/libiris/iris/xmpp-im/types.cpp	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-im/types.cpp	(revision 586398)
+@@ -19,7 +19,7 @@
+  */
+ 
+ #include"im.h"
+-
++#include "protocol.h"
+ #include<qmap.h>
+ #include<qapplication.h>
+ 
+@@ -180,7 +180,8 @@
+ 	Jid to, from;
+ 	QString id, type, lang;
+ 
+-	StringMap subject, body;
++	StringMap subject, body, xHTMLBody;
++
+ 	QString thread;
+ 	Stanza::Error error;
+ 
+@@ -279,6 +280,11 @@
+ 	return d->body[lang];
+ }
+ 
++QString Message::xHTMLBody(const QString &lang) const
++{
++	return d->xHTMLBody[lang];
++}
++
+ QString Message::thread() const
+ {
+ 	return d->thread;
+@@ -340,9 +346,16 @@
+ void Message::setBody(const QString &s, const QString &lang)
+ {
+ 	d->body[lang] = s;
+-	//d->flag = false;
+ }
+ 
++void Message::setXHTMLBody(const QString &s, const QString &lang, const QString &attr)
++{
++	//ugly but needed if s is not a node but a list of leaf
++
++	QString content = "<body xmlns='" + QString(NS_XHTML) + "' "+attr+" >\n" + s +"\n</body>";
++	d->xHTMLBody[lang] = content;
++}
++
+ void Message::setThread(const QString &s)
+ {
+ 	d->thread = s;
+@@ -489,7 +502,19 @@
+ 			s.appendChild(e);
+ 		}
+ 	}
+-
++	if ( !d->xHTMLBody.isEmpty()) {
++		QDomElement parent = s.createElement(s.xhtmlImNS(), "html");
++		for(it = d->xHTMLBody.begin(); it != d->xHTMLBody.end(); ++it) {
++			const QString &str = it.data();
++			if(!str.isEmpty()) {
++				QDomElement child = s.createXHTMLElement(str);
++				if(!it.key().isEmpty())
++					child.setAttributeNS(NS_XML, "xml:lang", it.key());
++				parent.appendChild(child);
++			}
++		}
++		s.appendChild(parent);
++	}
+ 	if(d->type == "error")
+ 		s.setError(d->error);
+ 
+@@ -519,28 +544,49 @@
+ 			else
+ 				x.appendChild(s.createTextElement("jabber:x:event","id",d->eventId));
+ 		}
++		else if (d->type=="chat" || d->type=="groupchat")
++			s.appendChild(  s.createElement(NS_CHATSTATES , "active" ) );
+ 
++		bool need_x_event=false;
+ 		for(QValueList<MsgEvent>::ConstIterator ev = d->eventList.begin(); ev != d->eventList.end(); ++ev) {
+ 			switch (*ev) {
+ 				case OfflineEvent:
+ 					x.appendChild(s.createElement("jabber:x:event", "offline"));
++					need_x_event=true;
+ 					break;
+ 				case DeliveredEvent:
+ 					x.appendChild(s.createElement("jabber:x:event", "delivered"));
++					need_x_event=true;
+ 					break;
+ 				case DisplayedEvent:
+ 					x.appendChild(s.createElement("jabber:x:event", "displayed"));
++					need_x_event=true;
+ 					break;
+ 				case ComposingEvent: 
+ 					x.appendChild(s.createElement("jabber:x:event", "composing"));
++					need_x_event=true;
++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++						s.appendChild(  s.createElement(NS_CHATSTATES , "composing" ) ); 
+ 					break;
+ 				case CancelEvent:
+-					// Add nothing
++					need_x_event=true;
++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++						s.appendChild(  s.createElement(NS_CHATSTATES , "paused" ) ); 
+ 					break;
++				case InactiveEvent:
++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++						s.appendChild(  s.createElement(NS_CHATSTATES , "inactive" ) ); 
++					break;
++				case GoneEvent:
++					if (d->body.isEmpty() && (d->type=="chat" || d->type=="groupchat") )
++						s.appendChild(  s.createElement(NS_CHATSTATES , "gone" ) ); 
++					break;
+ 			}
+ 		}
+-		s.appendChild(x);
+-	} 
++		if(need_x_event)  //we don't need to have the (empty) x:event element if this is only <gone> or <inactive>
++			s.appendChild(x);
++	}
++		
+ 
+ 	// xencrypted
+ 	if(!d->xencrypted.isEmpty())
+@@ -570,6 +616,7 @@
+ 	d->subject.clear();
+ 	d->body.clear();
+ 	d->thread = QString();
++	d->eventList.clear();
+ 
+ 	QDomElement root = s.element();
+ 
+@@ -591,6 +638,48 @@
+ 				else if(e.tagName() == "thread")
+ 					d->thread = e.text();
+ 			}
++			else if (e.namespaceURI() == s.xhtmlImNS()) {
++				 if (e.tagName() == "html") {
++					QDomNodeList htmlNL= e.childNodes();
++					for (unsigned int x = 0; x < htmlNL.count(); x++) {
++						QDomElement i = htmlNL.item(x).toElement();
++
++						if (i.tagName() == "body") {
++							QDomDocument RichText;
++							QString lang = i.attributeNS(NS_XML, "lang", "");
++							RichText.appendChild(i);
++							d-> xHTMLBody[lang] = RichText.toString();
++						}
++					}
++				}
++			}
++			else if (e.namespaceURI() == NS_CHATSTATES)
++			{
++				if(e.tagName() == "active")
++				{
++					//like in JEP-0022  we let the client know that we can receive ComposingEvent
++					// (we can do that according to  §4.6  of the JEP-0085)
++					d->eventList += ComposingEvent;
++					d->eventList += InactiveEvent;
++					d->eventList += GoneEvent;
++				}
++				else if (e.tagName() == "composing")
++				{
++					d->eventList += ComposingEvent;
++				}
++				else if (e.tagName() == "paused")
++				{
++					d->eventList += CancelEvent;
++				}
++				else if (e.tagName() == "inactive")
++				{
++					d->eventList += InactiveEvent;
++				}
++				else if (e.tagName() == "gone")
++				{
++					d->eventList += GoneEvent;
++				}
++			}
+ 			else {
+ 				//printf("extension element: [%s]\n", e.tagName().latin1());
+ 			}
+@@ -624,7 +713,6 @@
+ 	}
+ 	
+     // events
+-	d->eventList.clear();
+ 	nl = root.elementsByTagNameNS("jabber:x:event", "x");
+ 	if (nl.count()) {
+ 		nl = nl.item(0).childNodes();
+@@ -786,6 +874,21 @@
+ 	v_songTitle = _songtitle;
+ }
+ 
++void Status::setCapsNode(const QString & _capsNode)
++{
++	v_capsNode = _capsNode;
++}
++
++void Status::setCapsVersion(const QString & _capsVersion)
++{
++	v_capsVersion = _capsVersion;
++}
++
++void Status::setCapsExt(const QString & _capsExt)
++{
++	v_capsExt = _capsExt;
++}
++
+ bool Status::isAvailable() const
+ {
+ 	return v_isAvailable;
+@@ -838,6 +941,21 @@
+ 	return v_songTitle;
+ }
+ 
++const QString & Status::capsNode() const
++{
++	return v_capsNode;
++}
++
++const QString & Status::capsVersion() const
++{
++	return v_capsVersion;
++}
++
++const QString & Status::capsExt() const
++{
++	return v_capsExt;
++}
++
+ int Status::errorCode() const
+ {
+ 	return ecode;
+@@ -1418,6 +1536,16 @@
+ 	return test(ns);
+ }
+ 
++#define FID_XHTML  "http://jabber.org/protocol/xhtml-im"
++bool Features::canXHTML() const
++{
++	QStringList ns;
++
++	ns << FID_XHTML;
++
++	return test(ns);
++}
++
+ #define FID_GROUPCHAT "jabber:iq:conference"
+ bool Features::canGroupchat() const
+ {
+@@ -1428,6 +1556,15 @@
+ 	return test(ns);
+ }
+ 
++#define FID_VOICE "http://www.google.com/xmpp/protocol/voice/v1"
++bool Features::canVoice() const
++{
++	QStringList ns;
++	ns << FID_VOICE;
++
++	return test(ns);
++}
++
+ #define FID_GATEWAY "jabber:iq:gateway"
+ bool Features::isGateway() const
+ {
+--- kopete/protocols/jabber/libiris/iris/xmpp-im/xmpp_tasks.cpp	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-im/xmpp_tasks.cpp	(revision 586398)
+@@ -516,6 +516,16 @@
+ 			x.setAttribute("xmlns", "jabber:x:signed");
+ 			tag.appendChild(x);
+ 		}
++
++		if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) {
++			QDomElement c = doc()->createElement("c");
++			c.setAttribute("xmlns","http://jabber.org/protocol/caps");
++			c.setAttribute("node",s.capsNode());
++			c.setAttribute("ver",s.capsVersion());
++			if (!s.capsExt().isEmpty()) 
++				c.setAttribute("ext",s.capsExt());
++			tag.appendChild(c);
++		}
+ 	}
+ }
+ 
+@@ -625,6 +635,11 @@
+ 		else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") {
+ 			p.setKeyID(tagContent(i));
+ 		}
++ 		else if(i.tagName() == "c" && i.attribute("xmlns") == "http://jabber.org/protocol/caps") {
++ 			p.setCapsNode(i.attribute("node"));
++ 			p.setCapsVersion(i.attribute("ver"));
++ 			p.setCapsExt(i.attribute("ext"));
++  		}
+ 	}
+ 
+ 	presence(j, p);
+@@ -1333,24 +1348,91 @@
+ 	//	return TRUE;
+ 	//}
+ 	else if(ns == "http://jabber.org/protocol/disco#info") {
++		// Find out the node
++		QString node;
++		bool found;
++		QDomElement q = findSubTag(e, "query", &found);
++		if(found) // NOTE: Should always be true, since a NS was found above
++				node = q.attribute("node");
++
+ 		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
+ 		QDomElement query = doc()->createElement("query");
+ 		query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
++		if (!node.isEmpty())
++				query.setAttribute("node", node);
+ 		iq.appendChild(query);
++
++		// Identity
++		DiscoItem::Identity identity = client()->identity();
++		QDomElement id = doc()->createElement("identity");
++		if (!identity.category.isEmpty() && !identity.type.isEmpty()) {
++				id.setAttribute("category",identity.category);
++				id.setAttribute("type",identity.type);
++				if (!identity.name.isEmpty()) {
++						id.setAttribute("name",identity.name);
++				}
++		}
++		else {
++				// Default values
++				id.setAttribute("category","client");
++				id.setAttribute("type","pc");
++		}
++		query.appendChild(id);
++
+ 		QDomElement feature;
++		if (node.isEmpty() || node == client()->capsNode() + "#" + client()->capsVersion()) {
++				// Standard features
++				feature = doc()->createElement("feature");
++				feature.setAttribute("var", "http://jabber.org/protocol/bytestreams");
++				query.appendChild(feature);
+ 
+-		feature = doc()->createElement("feature");
+-		feature.setAttribute("var", "http://jabber.org/protocol/bytestreams");
+-		query.appendChild(feature);
++				feature = doc()->createElement("feature");
++				feature.setAttribute("var", "http://jabber.org/protocol/si");
++				query.appendChild(feature);
+ 
+-		feature = doc()->createElement("feature");
+-		feature.setAttribute("var", "http://jabber.org/protocol/si");
+-		query.appendChild(feature);
++				feature = doc()->createElement("feature");
++				feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
++				query.appendChild(feature);
+ 
+-		feature = doc()->createElement("feature");
+-		feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
+-		query.appendChild(feature);
++				feature = doc()->createElement("feature");
++				feature.setAttribute("var", "http://jabber.org/protocol/xhtml-im");
++				query.appendChild(feature);
+ 
++				feature = doc()->createElement("feature");
++				feature.setAttribute("var", "http://jabber.org/protocol/disco#info");
++				query.appendChild(feature);
++
++				if (node.isEmpty()) {
++						// Extended features
++						QStringList exts = client()->extensions();
++						for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) {
++								const QStringList& l = client()->extension(*i).list();
++								for ( QStringList::ConstIterator j = l.begin(); j != l.end(); ++j ) {
++										feature = doc()->createElement("feature");
++										feature.setAttribute("var", *j);
++										query.appendChild(feature);
++								}
++						}
++				}
++		}
++		else if (node.startsWith(client()->capsNode() + "#")) {
++				QString ext = node.right(node.length()-client()->capsNode().length()-1);
++				if (client()->extensions().contains(ext)) {
++						const QStringList& l = client()->extension(ext).list();
++						for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) {
++								feature = doc()->createElement("feature");
++								feature.setAttribute("var", *it);
++								query.appendChild(feature);
++						}
++				}
++				else {
++						// TODO: ERROR
++				}
++		}
++		else {
++				// TODO: ERROR
++		}
++
+ 		send(iq);
+ 		return true;
+ 	}
+@@ -1667,6 +1749,7 @@
+ 
+ 	QDomElement iq;
+ 	Jid jid;
++	QString node;
+ 	DiscoItem item;
+ };
+ 
+@@ -1694,6 +1777,7 @@
+ 	d->item = DiscoItem(); // clear item
+ 
+ 	d->jid = j;
++	d->node = node;
+ 	d->iq = createIQ(doc(), "get", d->jid.full(), id());
+ 	QDomElement query = doc()->createElement("query");
+ 	query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
+@@ -1716,6 +1800,29 @@
+ 	d->iq.appendChild(query);
+ }
+ 
++
++/**
++ * Original requested jid.
++ * Is here because sometimes the responder does not include this information
++ * in the reply.
++ */
++const Jid& JT_DiscoInfo::jid() const
++{
++	return d->jid;
++}
++
++/**
++ * Original requested node.
++ * Is here because sometimes the responder does not include this information
++ * in the reply.
++ */
++const QString& JT_DiscoInfo::node() const
++{
++	return d->node;
++}
++
++
++
+ const DiscoItem &JT_DiscoInfo::item() const
+ {
+ 	return d->item;
+@@ -1849,3 +1956,165 @@
+ 	return true;
+ }
+ 
++//----------------------------------------------------------------------------
++// JT_MucPresence
++//----------------------------------------------------------------------------
++JT_MucPresence::JT_MucPresence(Task *parent)
++:Task(parent)
++{
++	type = -1;
++}
++
++JT_MucPresence::~JT_MucPresence()
++{
++}
++
++void JT_MucPresence::pres(const Status &s)
++{
++	type = 0;
++
++	tag = doc()->createElement("presence");
++	if(!s.isAvailable()) {
++		tag.setAttribute("type", "unavailable");
++		if(!s.status().isEmpty())
++			tag.appendChild(textTag(doc(), "status", s.status()));
++	}
++	else {
++		if(s.isInvisible())
++			tag.setAttribute("type", "invisible");
++
++		if(!s.show().isEmpty())
++			tag.appendChild(textTag(doc(), "show", s.show()));
++		if(!s.status().isEmpty())
++			tag.appendChild(textTag(doc(), "status", s.status()));
++
++		tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) );
++
++		if(!s.keyID().isEmpty()) {
++			QDomElement x = textTag(doc(), "x", s.keyID());
++			x.setAttribute("xmlns", "http://jabber.org/protocol/e2e");
++			tag.appendChild(x);
++		}
++		if(!s.xsigned().isEmpty()) {
++			QDomElement x = textTag(doc(), "x", s.xsigned());
++			x.setAttribute("xmlns", "jabber:x:signed");
++			tag.appendChild(x);
++		}
++
++		if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) {
++			QDomElement c = doc()->createElement("c");
++			c.setAttribute("xmlns","http://jabber.org/protocol/caps");
++			c.setAttribute("node",s.capsNode());
++			c.setAttribute("ver",s.capsVersion());
++			if (!s.capsExt().isEmpty()) 
++				c.setAttribute("ext",s.capsExt());
++			tag.appendChild(c);
++		}
++	}
++}
++
++void JT_MucPresence::pres(const Jid &to, const Status &s, const QString &password)
++{
++	pres(s);
++	tag.setAttribute("to", to.full());
++	QDomElement x = textTag(doc(), "x", s.xsigned());
++	x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
++	x.appendChild( textTag(doc(), "password", password.latin1()) );
++	tag.appendChild(x);
++}
++
++void JT_MucPresence::onGo()
++{
++	send(tag);
++	setSuccess();
++}
++
++
++//----------------------------------------------------------------------------
++// JT_PrivateStorage
++//----------------------------------------------------------------------------
++class JT_PrivateStorage::Private
++{
++	public:
++		Private() : type(-1) {}
++
++		QDomElement iq;
++		QDomElement elem;
++		int type;
++};
++
++JT_PrivateStorage::JT_PrivateStorage(Task *parent)
++	:Task(parent)
++{
++	d = new Private;
++}
++
++JT_PrivateStorage::~JT_PrivateStorage()
++{
++	delete d;
++}
++
++void JT_PrivateStorage::get(const QString& tag, const QString& xmlns)
++{
++	d->type = 0;
++	d->iq = createIQ(doc(), "get" , QString() , id() );
++	QDomElement query = doc()->createElement("query");
++	query.setAttribute("xmlns", "jabber:iq:private");
++	d->iq.appendChild(query);
++	QDomElement s = doc()->createElement(tag);
++	if(!xmlns.isEmpty())
++		s.setAttribute("xmlns", xmlns);
++	query.appendChild(s);
++}
++
++void JT_PrivateStorage::set(const QDomElement& element)
++{
++	d->type = 1;
++	d->elem=element;
++	QDomNode n=doc()->importNode(element,true);
++
++	d->iq = createIQ(doc(), "set" , QString() , id() );
++	QDomElement query = doc()->createElement("query");
++	query.setAttribute("xmlns", "jabber:iq:private");
++	d->iq.appendChild(query);
++	query.appendChild(n);
++}
++
++void JT_PrivateStorage::onGo()
++{
++	send(d->iq);
++}
++
++bool JT_PrivateStorage::take(const QDomElement &x)
++{
++	QString to = client()->host();
++	if(!iqVerify(x, to, id()))
++		return false;
++
++	if(x.attribute("type") == "result") {
++		if(d->type == 0) {
++			QDomElement q = queryTag(x);
++			for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
++				QDomElement i = n.toElement();
++				if(i.isNull())
++					continue;
++				d->elem=i;
++				break;
++			}
++		}
++		setSuccess();
++		return true;
++	}
++	else {
++		setError(x);
++	}
++
++	return true;
++}
++
++
++QDomElement JT_PrivateStorage::element( )
++{
++	return d->elem;
++}
++
+--- kopete/protocols/jabber/libiris/iris/xmpp-core/protocol.h	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-core/protocol.h	(revision 586398)
+@@ -35,6 +35,9 @@
+ #define NS_SESSION  "urn:ietf:params:xml:ns:xmpp-session"
+ #define NS_STANZAS  "urn:ietf:params:xml:ns:xmpp-stanzas"
+ #define NS_BIND     "urn:ietf:params:xml:ns:xmpp-bind"
++#define NS_XHTML_IM "http://jabber.org/protocol/xhtml-im"
++#define NS_XHTML "http://www.w3.org/1999/xhtml"
++#define NS_CHATSTATES "http://jabber.org/protocol/chatstates"
+ 
+ namespace XMPP
+ {
+--- kopete/protocols/jabber/libiris/iris/xmpp-core/Makefile.am	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-core/Makefile.am	(revision 586398)
+@@ -3,11 +3,11 @@
+ METASOURCES = ignore_this_warning.moc
+ 
+ noinst_LTLIBRARIES = libiris_xmpp_core.la
+-AM_CPPFLAGS = $(IDN_CPPFLAGS)
++AM_CPPFLAGS = $(IDN_CFLAGS)
+ INCLUDES = -I$(srcdir)/../include -I$(srcdir)/../xmpp-core -I$(srcdir)/../xmpp-im -I$(srcdir)/../../cutestuff/util -I$(srcdir)/../../cutestuff/network -I$(srcdir)/../../qca/src $(all_includes)
+ 
+-libiris_xmpp_core_la_CPPFLAGS = $(IDN_CPPFLAGS)
+-libiris_xmpp_core_la_LDFLAGS = $(IDN_LDFLAGS) $(IDN_LIBS)
++libiris_xmpp_core_la_CPPFLAGS = $(IDN_CFLAGS)
++libiris_xmpp_core_la_LDFLAGS = $(IDN_LIBS)
+ libiris_xmpp_core_la_SOURCES = \
+ 	connector.cpp \
+ 	jid.cpp \
+--- kopete/protocols/jabber/libiris/iris/xmpp-core/stream.cpp	(revision 568672)
++++ kopete/protocols/jabber/libiris/iris/xmpp-core/stream.cpp	(revision 586398)
+@@ -293,6 +293,16 @@
+ 	return d->s->baseNS();
+ }
+ 
++QString Stanza::xhtmlImNS() const
++{
++	return d->s->xhtmlImNS();
++}
++
++QString Stanza::xhtmlNS() const
++{
++	return d->s->xhtmlNS();
++}
++
+ QDomElement Stanza::createElement(const QString &ns, const QString &tagName)
+ {
+ 	return d->s->doc().createElementNS(ns, tagName);
+@@ -305,6 +315,16 @@
+ 	return e;
+ }
+ 
++QDomElement Stanza::createXHTMLElement(const QString &xHTML)
++{
++	QDomDocument doc;
++
++  	doc.setContent(xHTML, true);
++	QDomElement root = doc.documentElement();
++	//QDomElement e;
++	return (root);
++}
++
+ void Stanza::appendChild(const QDomElement &e)
+ {
+ 	d->e.appendChild(e);
+@@ -861,6 +881,16 @@
+ 	return NS_CLIENT;
+ }
+ 
++QString ClientStream::xhtmlImNS() const
++{
++	return NS_XHTML_IM;
++}
++
++QString ClientStream::xhtmlNS() const
++{
++	return NS_XHTML;
++}
++
+ void ClientStream::setAllowPlain(bool b)
+ {
+ 	d->allowPlain = b;
+--- kopete/protocols/jabber/libiris/007_chatstates.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/007_chatstates.patch	(revision 586398)
+@@ -0,0 +1,132 @@
++Index: iris/include/im.h
++===================================================================
++--- iris/include/im.h	(revision 525193)
+++++ iris/include/im.h	(working copy)
++@@ -49,7 +49,7 @@
++ 	typedef QValueList<Url> UrlList;
++ 	typedef QMap<QString, QString> StringMap;
++ 	typedef enum { OfflineEvent, DeliveredEvent, DisplayedEvent,
++-			ComposingEvent, CancelEvent } MsgEvent;
+++			ComposingEvent, CancelEvent, InactiveEvent, GoneEvent } MsgEvent;
++                                            
++ 	class Message
++ 	{
++Index: iris/xmpp-im/types.cpp
++===================================================================
++--- iris/xmpp-im/types.cpp	(revision 525193)
+++++ iris/xmpp-im/types.cpp	(working copy)
++@@ -544,28 +544,49 @@
++ 			else
++ 				x.appendChild(s.createTextElement("jabber:x:event","id",d->eventId));
++ 		}
+++		else
+++			s.appendChild(  s.createElement(NS_CHATSTATES , "active" ) );
++ 
+++		bool need_x_event=false;
++ 		for(QValueList<MsgEvent>::ConstIterator ev = d->eventList.begin(); ev != d->eventList.end(); ++ev) {
++ 			switch (*ev) {
++ 				case OfflineEvent:
++ 					x.appendChild(s.createElement("jabber:x:event", "offline"));
+++					need_x_event=true;
++ 					break;
++ 				case DeliveredEvent:
++ 					x.appendChild(s.createElement("jabber:x:event", "delivered"));
+++					need_x_event=true;
++ 					break;
++ 				case DisplayedEvent:
++ 					x.appendChild(s.createElement("jabber:x:event", "displayed"));
+++					need_x_event=true;
++ 					break;
++ 				case ComposingEvent: 
++ 					x.appendChild(s.createElement("jabber:x:event", "composing"));
+++					need_x_event=true;
+++					if (d->body.isEmpty())
+++						s.appendChild(  s.createElement(NS_CHATSTATES , "composing" ) ); 
++ 					break;
++ 				case CancelEvent:
++-					// Add nothing
+++					need_x_event=true;
+++					if (d->body.isEmpty())
+++						s.appendChild(  s.createElement(NS_CHATSTATES , "paused" ) ); 
++ 					break;
+++				case InactiveEvent:
+++					if (d->body.isEmpty())
+++						s.appendChild(  s.createElement(NS_CHATSTATES , "inactive" ) ); 
+++					break;
+++				case GoneEvent:
+++					if (d->body.isEmpty())
+++						s.appendChild(  s.createElement(NS_CHATSTATES , "gone" ) ); 
+++					break;
++ 			}
++ 		}
++-		s.appendChild(x);
++-	} 
+++		if(need_x_event)  //we don't need to have the (empty) x:event element if this is only <gone> or <inactive>
+++			s.appendChild(x);
+++	}
+++		
++ 
++ 	// xencrypted
++ 	if(!d->xencrypted.isEmpty())
++@@ -595,6 +616,7 @@
++ 	d->subject.clear();
++ 	d->body.clear();
++ 	d->thread = QString();
+++	d->eventList.clear();
++ 
++ 	QDomElement root = s.element();
++ 
++@@ -631,6 +653,33 @@
++ 					}
++ 				}
++ 			}
+++			else if (e.namespaceURI() == NS_CHATSTATES)
+++			{
+++				if(e.tagName() == "active")
+++				{
+++					//like in JEP-0022  we let the client know that we can receive ComposingEvent
+++					// (we can do that according to  §4.6  of the JEP-0085)
+++					d->eventList += ComposingEvent;
+++					d->eventList += InactiveEvent;
+++					d->eventList += GoneEvent;
+++				}
+++				else if (e.tagName() == "composing")
+++				{
+++					d->eventList += ComposingEvent;
+++				}
+++				else if (e.tagName() == "paused")
+++				{
+++					d->eventList += CancelEvent;
+++				}
+++				else if (e.tagName() == "inactive")
+++				{
+++					d->eventList += InactiveEvent;
+++				}
+++				else if (e.tagName() == "gone")
+++				{
+++					d->eventList += GoneEvent;
+++				}
+++			}
++ 			else {
++ 				//printf("extension element: [%s]\n", e.tagName().latin1());
++ 			}
++@@ -664,7 +713,6 @@
++ 	}
++ 	
++     // events
++-	d->eventList.clear();
++ 	nl = root.elementsByTagNameNS("jabber:x:event", "x");
++ 	if (nl.count()) {
++ 		nl = nl.item(0).childNodes();
++Index: iris/xmpp-core/protocol.h
++===================================================================
++--- iris/xmpp-core/protocol.h	(revision 525193)
+++++ iris/xmpp-core/protocol.h	(working copy)
++@@ -37,6 +37,7 @@
++ #define NS_BIND     "urn:ietf:params:xml:ns:xmpp-bind"
++ #define NS_XHTML_IM "http://jabber.org/protocol/xhtml-im"
++ #define NS_XHTML "http://www.w3.org/1999/xhtml"
+++#define NS_CHATSTATES "http://jabber.org/protocol/chatstates"
++ 
++ namespace XMPP
++ {
+--- kopete/protocols/jabber/libiris/jingle_iris.patch	(revision 0)
++++ kopete/protocols/jabber/libiris/jingle_iris.patch	(revision 586398)
+@@ -0,0 +1,432 @@
++diff -ur psi/iris/include/im.h psi-jingle/iris/include/im.h
++--- psi/iris/include/im.h	2005-12-27 15:12:42.000000000 +0100
+++++ psi-jingle/iris/include/im.h	2005-12-27 11:05:53.000000000 +0100
++@@ -22,6 +22,7 @@
++ #define XMPP_IM_H
++ 
++ #include<qdatetime.h>
+++#include<qvaluelist.h>
++ #include"xmpp.h"
++ 
++ namespace XMPP
++@@ -153,6 +154,9 @@
++ 
++ 		const QString & xsigned() const;
++ 		const QString & songTitle() const;
+++		const QString & capsNode() const;
+++		const QString & capsVersion() const;
+++		const QString & capsExt() const;
++ 
++ 		void setPriority(int);
++ 		void setShow(const QString &);
++@@ -162,6 +166,9 @@
++ 		void setIsAvailable(bool);
++ 		void setIsInvisible(bool);
++ 		void setError(int, const QString &);
+++		void setCapsNode(const QString&);
+++		void setCapsVersion(const QString&);
+++		void setCapsExt(const QString&);
++ 
++ 		void setXSigned(const QString &);
++ 		void setSongTitle(const QString &);
++@@ -176,6 +183,7 @@
++ 		QString v_xsigned;
++ 		// gabber song extension
++ 		QString v_songTitle;
+++		QString v_capsNode, v_capsVersion, v_capsExt;
++ 
++ 		int ecode;
++ 		QString estr;
++@@ -285,6 +293,7 @@
++ 		bool canRegister() const;
++ 		bool canSearch() const;
++ 		bool canGroupchat() const;
+++		bool canVoice() const;
++ 		bool canDisco() const;
++ 		bool isGateway() const;
++ 		bool haveVCard() const;
++@@ -567,12 +576,25 @@
++ 		int timeZoneOffset() const;
++ 		QString clientName() const;
++ 		QString clientVersion() const;
+++		QString capsNode() const;
+++		QString capsVersion() const;
+++		QString capsExt() const;
++ 
++ 		void setOSName(const QString &);
++ 		void setTimeZone(const QString &, int);
++ 		void setClientName(const QString &);
++ 		void setClientVersion(const QString &);
+++		void setCapsNode(const QString &);
+++		void setCapsVersion(const QString &);
++ 
+++		void setIdentity(DiscoItem::Identity);
+++		DiscoItem::Identity identity();
+++
+++		void addExtension(const QString& ext, const Features& f);
+++		void removeExtension(const QString& ext);
+++		const Features& extension(const QString& ext) const;
+++		QStringList extensions() const;
+++		
++ 		S5BManager *s5bManager() const;
++ 		IBBManager *ibbManager() const;
++ 		JidLinkManager *jidLinkManager() const;
++diff -ur psi/iris/xmpp-im/client.cpp psi-jingle/iris/xmpp-im/client.cpp
++--- psi/iris/xmpp-im/client.cpp	2005-12-27 15:12:44.000000000 +0100
+++++ psi-jingle/iris/xmpp-im/client.cpp	2005-12-27 11:05:53.000000000 +0100
++@@ -70,6 +70,7 @@
++ //!  \endcode
++ 
++ #include<stdarg.h>
+++#include<qmap.h>
++ #include<qobjectlist.h>
++ #include<qtimer.h>
++ #include<qguardedptr.h>
++@@ -125,7 +126,9 @@
++ 	int id_seed;
++ 	Task *root;
++ 	QString host, user, pass, resource;
++-	QString osname, tzname, clientName, clientVersion;
+++	QString osname, tzname, clientName, clientVersion, capsNode, capsVersion, capsExt;
+++	DiscoItem::Identity identity;
+++	QMap<QString,Features> extension_features;
++ 	int tzoffset;
++ 	bool active;
++ 
++@@ -149,6 +152,9 @@
++ 	d->osname = "N/A";
++ 	d->clientName = "N/A";
++ 	d->clientVersion = "0.0";
+++	d->capsNode = "";
+++	d->capsVersion = "";
+++	d->capsExt = "";
++ 
++ 	d->id_seed = 0xaaaa;
++ 	d->root = new Task(this, true);
++@@ -996,6 +1002,21 @@
++ 	return d->clientVersion;
++ }
++ 
+++QString Client::capsNode() const
+++{
+++	return d->capsNode;
+++}
+++
+++QString Client::capsVersion() const
+++{
+++	return d->capsVersion;
+++}
+++
+++QString Client::capsExt() const
+++{
+++	return d->capsExt;
+++}
+++
++ void Client::setOSName(const QString &name)
++ {
++ 	d->osname = name;
++@@ -1017,6 +1038,52 @@
++ 	d->clientVersion = s;
++ }
++ 
+++void Client::setCapsNode(const QString &s)
+++{
+++	d->capsNode = s;
+++}
+++
+++void Client::setCapsVersion(const QString &s)
+++{
+++	d->capsVersion = s;
+++}
+++
+++DiscoItem::Identity Client::identity()
+++{
+++	return d->identity;
+++}
+++
+++void Client::setIdentity(DiscoItem::Identity identity)
+++{
+++	d->identity = identity;
+++}
+++
+++void Client::addExtension(const QString& ext, const Features& features)
+++{
+++	if (!ext.isEmpty()) {
+++		d->extension_features[ext] = features;
+++		d->capsExt = extensions().join(" ");
+++	}
+++}
+++
+++void Client::removeExtension(const QString& ext)
+++{
+++	if (d->extension_features.contains(ext)) {
+++		d->extension_features.remove(ext);
+++		d->capsExt = extensions().join(" ");
+++	}
+++}
+++
+++QStringList Client::extensions() const
+++{
+++	return d->extension_features.keys();
+++}
+++
+++const Features& Client::extension(const QString& ext) const
+++{
+++	return d->extension_features[ext];
+++}
+++
++ void Client::s5b_incomingReady()
++ {
++ 	S5BConnection *c = d->s5bman->takeIncoming();
++diff -ur psi/iris/xmpp-im/types.cpp psi-jingle/iris/xmpp-im/types.cpp
++--- psi/iris/xmpp-im/types.cpp	2005-12-27 15:12:55.000000000 +0100
+++++ psi-jingle/iris/xmpp-im/types.cpp	2005-12-27 11:05:53.000000000 +0100
++@@ -784,6 +784,21 @@
++ 	v_songTitle = _songtitle;
++ }
++ 
+++void Status::setCapsNode(const QString & _capsNode)
+++{
+++	v_capsNode = _capsNode;
+++}
+++
+++void Status::setCapsVersion(const QString & _capsVersion)
+++{
+++	v_capsVersion = _capsVersion;
+++}
+++
+++void Status::setCapsExt(const QString & _capsExt)
+++{
+++	v_capsExt = _capsExt;
+++}
+++
++ bool Status::isAvailable() const
++ {
++ 	return v_isAvailable;
++@@ -836,6 +851,21 @@
++ 	return v_songTitle;
++ }
++ 
+++const QString & Status::capsNode() const
+++{
+++	return v_capsNode;
+++}
+++
+++const QString & Status::capsVersion() const
+++{
+++	return v_capsVersion;
+++}
+++
+++const QString & Status::capsExt() const
+++{
+++	return v_capsExt;
+++}
+++
++ int Status::errorCode() const
++ {
++ 	return ecode;
++@@ -1427,6 +1457,15 @@
++ 	return test(ns);
++ }
++ 
+++#define FID_VOICE "http://www.google.com/xmpp/protocol/voice/v1"
+++bool Features::canVoice() const
+++{
+++	QStringList ns;
+++	ns << FID_VOICE;
+++
+++	return test(ns);
+++}
+++
++ #define FID_GATEWAY "jabber:iq:gateway"
++ bool Features::isGateway() const
++ {
++diff -ur psi/iris/xmpp-im/xmpp_tasks.cpp psi-jingle/iris/xmpp-im/xmpp_tasks.cpp
++--- psi/iris/xmpp-im/xmpp_tasks.cpp	2005-12-27 15:12:45.000000000 +0100
+++++ psi-jingle/iris/xmpp-im/xmpp_tasks.cpp	2005-12-27 11:05:53.000000000 +0100
++@@ -516,6 +516,16 @@
++ 			x.setAttribute("xmlns", "jabber:x:signed");
++ 			tag.appendChild(x);
++ 		}
+++
+++		if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) {
+++			QDomElement c = doc()->createElement("c");
+++			c.setAttribute("xmlns","http://jabber.org/protocol/caps");
+++			c.setAttribute("node",s.capsNode());
+++			c.setAttribute("ver",s.capsVersion());
+++			if (!s.capsExt().isEmpty()) 
+++				c.setAttribute("ext",s.capsExt());
+++			tag.appendChild(c);
+++		}
++ 	}
++ }
++ 
++@@ -625,6 +635,11 @@
++ 		else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") {
++ 			p.setKeyID(tagContent(i));
++ 		}
+++ 		else if(i.tagName() == "c" && i.attribute("xmlns") == "http://jabber.org/protocol/caps") {
+++ 			p.setCapsNode(i.attribute("node"));
+++ 			p.setCapsVersion(i.attribute("ver"));
+++ 			p.setCapsExt(i.attribute("ext"));
+++  		}
++ 	}
++ 
++ 	presence(j, p);
++@@ -1265,23 +1280,86 @@
++ 	//	return TRUE;
++ 	//}
++ 	else if(ns == "http://jabber.org/protocol/disco#info") {
+++		// Find out the node
+++		QString node;
+++		bool found;
+++		QDomElement q = findSubTag(e, "query", &found);
+++		if(found) // NOTE: Should always be true, since a NS was found above
+++			node = q.attribute("node");
+++		
++ 		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
++ 		QDomElement query = doc()->createElement("query");
++ 		query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
+++		if (!node.isEmpty())
+++			query.setAttribute("node", node);
++ 		iq.appendChild(query);
++-		QDomElement feature;
++ 
++-		feature = doc()->createElement("feature");
++-		feature.setAttribute("var", "http://jabber.org/protocol/bytestreams");
++-		query.appendChild(feature);
++-
++-		feature = doc()->createElement("feature");
++-		feature.setAttribute("var", "http://jabber.org/protocol/si");
++-		query.appendChild(feature);
++-
++-		feature = doc()->createElement("feature");
++-		feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
++-		query.appendChild(feature);
+++		// Identity
+++		DiscoItem::Identity identity = client()->identity();
+++		QDomElement id = doc()->createElement("identity");
+++		if (!identity.category.isEmpty() && !identity.type.isEmpty()) {
+++			id.setAttribute("category",identity.category);
+++			id.setAttribute("type",identity.type);
+++			if (!identity.name.isEmpty()) {
+++				id.setAttribute("name",identity.name);
+++			}
+++		}
+++		else {
+++			// Default values
+++			id.setAttribute("category","client");
+++			id.setAttribute("type","pc");
+++		}
+++		query.appendChild(id);
+++
+++		QDomElement feature;
+++		if (node.isEmpty() || node == client()->capsNode() + "#" + client()->capsVersion()) {
+++			// Standard features
+++			feature = doc()->createElement("feature");
+++			feature.setAttribute("var", "http://jabber.org/protocol/bytestreams");
+++			query.appendChild(feature);
+++
+++			feature = doc()->createElement("feature");
+++			feature.setAttribute("var", "http://jabber.org/protocol/si");
+++			query.appendChild(feature);
+++
+++			feature = doc()->createElement("feature");
+++			feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
+++			query.appendChild(feature);
+++			
+++			feature = doc()->createElement("feature");
+++			feature.setAttribute("var", "http://jabber.org/protocol/disco#info");
+++			query.appendChild(feature);
+++
+++			if (node.isEmpty()) {
+++				// Extended features
+++				QStringList exts = client()->extensions();
+++				for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) {
+++					const QStringList& l = client()->extension(*i).list();
+++					for ( QStringList::ConstIterator j = l.begin(); j != l.end(); ++j ) {
+++						feature = doc()->createElement("feature");
+++						feature.setAttribute("var", *j);
+++						query.appendChild(feature);
+++					}
+++				}
+++			}
+++		}
+++		else if (node.startsWith(client()->capsNode() + "#")) {
+++			QString ext = node.right(node.length()-client()->capsNode().length()-1);
+++			if (client()->extensions().contains(ext)) {
+++				const QStringList& l = client()->extension(ext).list();
+++				for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) {
+++					feature = doc()->createElement("feature");
+++					feature.setAttribute("var", *it);
+++					query.appendChild(feature);
+++				}
+++			}
+++			else {
+++				// TODO: ERROR
+++			}
+++		}
+++		else {
+++			// TODO: ERROR
+++		}
++ 
++ 		send(iq);
++ 		return true;
++@@ -1599,6 +1677,7 @@
++ 
++ 	QDomElement iq;
++ 	Jid jid;
+++	QString node;
++ 	DiscoItem item;
++ };
++ 
++@@ -1626,6 +1705,7 @@
++ 	d->item = DiscoItem(); // clear item
++ 
++ 	d->jid = j;
+++	d->node = node;
++ 	d->iq = createIQ(doc(), "get", d->jid.full(), id());
++ 	QDomElement query = doc()->createElement("query");
++ 	query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
++@@ -1648,6 +1728,29 @@
++ 	d->iq.appendChild(query);
++ }
++ 
+++
+++/**
+++ * Original requested jid.
+++ * Is here because sometimes the responder does not include this information
+++ * in the reply.
+++ */
+++const Jid& JT_DiscoInfo::jid() const
+++{
+++	return d->jid;
+++}
+++
+++/**
+++ * Original requested node.
+++ * Is here because sometimes the responder does not include this information
+++ * in the reply.
+++ */
+++const QString& JT_DiscoInfo::node() const
+++{
+++	return d->node;
+++}
+++
+++
+++
++ const DiscoItem &JT_DiscoInfo::item() const
++ {
++ 	return d->item;
++diff -ur psi/iris/xmpp-im/xmpp_tasks.h psi-jingle/iris/xmpp-im/xmpp_tasks.h
++--- psi/iris/xmpp-im/xmpp_tasks.h	2005-12-27 15:12:45.000000000 +0100
+++++ psi-jingle/iris/xmpp-im/xmpp_tasks.h	2005-12-27 11:05:53.000000000 +0100
++@@ -389,6 +389,8 @@
++ 		void get(const DiscoItem &);
++ 	
++ 		const DiscoItem &item() const;
+++		const Jid& jid() const;
+++		const QString& node() const;
++ 	
++ 		void onGo();
++ 		bool take(const QDomElement &);
+--- kopete/protocols/jabber/jabbergroupcontact.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupcontact.cpp	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabbercontact.cpp  -  Regular Kopete Jabber protocol contact
+   *
+   * Copyright (c) 2002-2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c) 2006      by Olivier Goffart <ogoffart @ kde.org>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -20,6 +21,7 @@
+ #include <kdebug.h>
+ #include <klocale.h>
+ #include <kfiledialog.h>
++#include <kinputdialog.h>
+ #include "jabberprotocol.h"
+ #include "jabberaccount.h"
+ #include "jabberclient.h"
+@@ -28,14 +30,16 @@
+ #include "jabbergroupmembercontact.h"
+ #include "jabbercontactpool.h"
+ #include "kopetemetacontact.h"
++#include "xmpp_tasks.h"
+ 
+ /**
+  * JabberGroupContact constructor
+  */
+ JabberGroupContact::JabberGroupContact (const XMPP::RosterItem &rosterItem, JabberAccount *account, Kopete::MetaContact * mc)
+-				: JabberBaseContact ( XMPP::RosterItem ( rosterItem.jid().userHost () ), account, mc)
++	: JabberBaseContact ( XMPP::RosterItem ( rosterItem.jid().userHost () ), account, mc) , mNick( rosterItem.jid().resource() )
+ {
+-
++	setIcon( "jabber_group" );
++	
+ 	// initialize here, we need it set before we instantiate the manager below
+ 	mManager = 0;
+ 
+@@ -46,15 +50,18 @@
+ 	 * because we need to set this contact as myself() of the message
+ 	 * manager).
+ 	 */
+-	JabberBaseContact *subContact = addSubContact ( rosterItem );
++	mSelfContact = addSubContact ( rosterItem );
+ 
+ 	/**
+ 	 * Instantiate a new message manager without members.
+ 	 */
+-	mManager = new JabberGroupChatManager ( protocol (), subContact,
++	mManager = new JabberGroupChatManager ( protocol (), mSelfContact,
+ 											Kopete::ContactPtrList (), XMPP::Jid ( rosterItem.jid().userHost () ) );
+ 
+ 	connect ( mManager, SIGNAL ( closing ( Kopete::ChatSession* ) ), this, SLOT ( slotChatSessionDeleted () ) );
++	
++	connect ( account->myself() , SIGNAL(onlineStatusChanged( Kopete::Contact*, const Kopete::OnlineStatus&, const Kopete::OnlineStatus& ) ) ,
++			  this , SLOT(slotStatusChanged()  ) ) ;
+ 
+ 	/**
+ 	 * FIXME: The first contact in the list of the message manager
+@@ -64,10 +71,17 @@
+ 	 * is empty. This makes at least the history plugin crash.
+ 	 */
+ 	mManager->addContact ( this );
+-
+-	// call moved from superclass, see JabberBaseContact for details
+-	reevaluateStatus ();
+-
++	
++	
++	
++	/**
++	 * Let's construct the window:
++	 *  otherwise, the ref count of maznager is equal to zero. 
++	 *   and if we receive a message before the window is shown,
++	 *   it will be deleted and we will be out of the channel
++	 * In all case, there are no reason to don't show it.
++	 */
++	mManager->view( true , "kopete_chatwindow" );
+ }
+ 
+ JabberGroupContact::~JabberGroupContact ()
+@@ -75,32 +89,51 @@
+ 
+ 	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << endl;
+ 
+-	delete mManager;
+-
++	if(mManager) 
++	{
++		mManager->deleteLater();
++	}
++	
+ 	for ( Kopete::Contact *contact = mContactList.first (); contact; contact = mContactList.next () )
+ 	{
++		/*if(mManager)
++		mManager->removeContact( contact );*/
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Deleting KC " << contact->contactId () << endl;
+-		delete contact;
++		contact->deleteLater();
+ 	}
+ 
+ 	for ( Kopete::MetaContact *metaContact = mMetaContactList.first (); metaContact; metaContact = mMetaContactList.next () )
+ 	{
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Deleting KMC " << metaContact->metaContactId () << endl;
+-		delete metaContact;
++		metaContact->deleteLater();
+ 	}
+-
+ }
+ 
+ QPtrList<KAction> *JabberGroupContact::customContextMenuActions ()
+ {
++	QPtrList<KAction> *actionCollection = new QPtrList<KAction>();
+ 
+-	return 0;
++	KAction *actionSetNick = new KAction (i18n ("Change nick name"), 0, 0, this, SLOT (slotChangeNick()), this, "jabber_changenick");
++	actionCollection->append( actionSetNick );
+ 
++	return actionCollection;
+ }
+ 
+-Kopete::ChatSession *JabberGroupContact::manager ( Kopete::Contact::CanCreateFlags /*canCreate*/ )
++Kopete::ChatSession *JabberGroupContact::manager ( Kopete::Contact::CanCreateFlags canCreate )
+ {
++	if(!mManager && canCreate == Kopete::Contact::CanCreate)
++	{
++		kdWarning (JABBER_DEBUG_GLOBAL) << k_funcinfo << "somehow, the chat manager was removed, and the contact is still there" << endl;
++		mManager = new JabberGroupChatManager ( protocol (), mSelfContact,
++				Kopete::ContactPtrList (), XMPP::Jid ( rosterItem().jid().userHost() ) );
+ 
++		mManager->addContact ( this );
++		
++		connect ( mManager, SIGNAL ( closing ( Kopete::ChatSession* ) ), this, SLOT ( slotChatSessionDeleted () ) );
++		
++		//if we have to recreate the manager, we probably have to connect again to the chat.
++		slotStatusChanged();
++	}
+ 	return mManager;
+ 
+ }
+@@ -110,9 +143,9 @@
+ 	// message type is always chat in a groupchat
+ 	QString viewType = "kopete_chatwindow";
+ 	Kopete::Message *newMessage = 0L;
++	
++	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Received a message"  << endl;
+ 
+-	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Received Message Type:" << message.type () << endl;
+-
+ 	/**
+ 	 * Don't display empty messages, these were most likely just carrying
+ 	 * event notifications or other payload.
+@@ -120,8 +153,9 @@
+ 	if ( message.body().isEmpty () )
+ 		return;
+ 
+-	Kopete::ContactPtrList contactList;
+-	contactList.append ( mManager->user () );
++	manager(CanCreate); //force to create mManager
++	
++	Kopete::ContactPtrList contactList = manager()->members();
+ 
+ 	// check for errors
+ 	if ( message.type () == "error" )
+@@ -146,6 +180,8 @@
+ 
+ 		if ( !subContact )
+ 		{
++			kdWarning (JABBER_DEBUG_GLOBAL) << k_funcinfo << "the contact is not in the list   : " <<  message.from().full()<< endl;
++			return;
+ 			/**
+ 			 * We couldn't find the contact for this message. That most likely means
+ 			 * that it originated from a history backlog or something similar and
+@@ -181,7 +217,7 @@
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Contact already exists, not adding again." << endl;
+ 		return subContact;
+ 	}
+-
++	
+ 	// Create new meta contact that holds the group chat contact.
+ 	Kopete::MetaContact *metaContact = new Kopete::MetaContact ();
+ 	metaContact->setTemporary ( true );
+@@ -201,6 +237,8 @@
+ 
+ 	// now, add the contact also to our own list
+ 	mContactList.append ( subContact );
++	
++	connect(subContact , SIGNAL(contactDestroyed(Kopete::Contact*)) , this , SLOT(slotSubContactDestroyed(Kopete::Contact*)));
+ 
+ 	return subContact;
+ 
+@@ -225,9 +263,18 @@
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "WARNING: Subcontact couldn't be located!" << endl;
+ 		return;
+ 	}
++	
++	if(mManager && subContact->contactId() == mManager->myself()->contactId() )
++	{
++		//HACK WORKAROUND FIXME KDE4
++		//impossible to remove myself, or we will die
++		//subContact->setNickName( mNick ); //this is even worse than nothing
++		return;
++	}
+ 
+ 	// remove the contact from the message manager first
+-	mManager->removeContact ( subContact );
++	if(mManager)
++		mManager->removeContact ( subContact );
+ 
+ 	// remove the contact's meta contact from our internal list
+ 	mMetaContactList.remove ( subContact->metaContact () );
+@@ -263,11 +310,6 @@
+ 
+ }
+ 
+-void JabberGroupContact::slotUserInfo ()
+-{
+-
+-}
+-
+ void JabberGroupContact::slotChatSessionDeleted ()
+ {
+ 
+@@ -278,8 +320,59 @@
+ 		account()->client()->leaveGroupChat ( mRosterItem.jid().host (), mRosterItem.jid().user () );
+ 	}
+ 	
+-	deleteLater();
++	//deleteLater(); //we will be deleted later when the the account will know we have left
+ 
+ }
+ 
++void JabberGroupContact::slotStatusChanged( )
++{
++	if( !account()->isConnected() )
++	{
++		//we need to remove all contact, because when we connect again, we will not receive the notificaion they are gone.
++		QPtrList<Kopete::Contact> copy_contactlist=mContactList;
++		for ( Kopete::Contact *contact = copy_contactlist.first (); contact; contact = copy_contactlist.next () )
++		{
++			removeSubContact( XMPP::Jid(contact->contactId()) );
++		}
++		return;
++	}
++	
++	
++	if( !isOnline() )
++	{
++		//HACK WORKAROUND   XMPP::client->d->groupChatList must contains us.
++		account()->client()->joinGroupChat( rosterItem().jid().host() , rosterItem().jid().user() , mNick );
++	}
++	
++	//TODO: away message
++	XMPP::Status newStatus = account()->protocol()->kosToStatus( account()->myself()->onlineStatus() );
++	account()->client()->setGroupChatStatus( rosterItem().jid().host() , rosterItem().jid().user() , newStatus );
++}
++
++void JabberGroupContact::slotChangeNick( )
++{
++	
++	bool ok;
++	QString futureNewNickName = KInputDialog::getText( i18n( "Change nickanme - Jabber Plugin" ),
++			i18n( "Please enter the new nick name you want to have on the room <i>%1</i>" ).arg(rosterItem().jid().userHost()),
++			mNick, &ok );
++	if ( !ok || !account()->isConnected())
++		return;
++	
++	mNick=futureNewNickName;
++	
++	XMPP::Status status = account()->protocol()->kosToStatus( account()->myself()->onlineStatus() );
++	account()->client()->changeGroupChatNick( rosterItem().jid().host() , rosterItem().jid().user()  , mNick , status);
++
++}
++
++void JabberGroupContact::slotSubContactDestroyed( Kopete::Contact * deadContact )
++{
++	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "cleaning dead subcontact " << deadContact->contactId() << " from room " << mRosterItem.jid().full () << endl;
++
++	mMetaContactList.remove ( deadContact->metaContact () );
++	mContactList.remove ( deadContact );
++
++}
++
+ #include "jabbergroupcontact.moc"
+--- kopete/protocols/jabber/jabberresourcepool.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberresourcepool.cpp	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabberresourcepool.cpp
+   *
+   * Copyright (c) 2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c) 2006 by Michaël Larouche <michael.larouche at kdemail.net>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -17,11 +18,14 @@
+ 
+ #include <qptrlist.h>
+ #include <kdebug.h>
++
+ #include "jabberresourcepool.h"
+ #include "jabberresource.h"
+ #include "jabbercontactpool.h"
+ #include "jabberbasecontact.h"
+ #include "jabberaccount.h"
++#include "jabberprotocol.h"
++#include "jabbercapabilitiesmanager.h"
+ 
+ /**
+  * This resource will be returned if no other resource
+@@ -30,18 +34,32 @@
+  */
+ XMPP::Resource JabberResourcePool::EmptyResource ( "", XMPP::Status ( "", "", 0, false ) );
+ 
+-JabberResourcePool::JabberResourcePool ( JabberAccount *account )
++class JabberResourcePool::Private
+ {
++public:
++	Private(JabberAccount *pAccount)
++	 : account(pAccount)
++	{
++		// automatically delete all resources in the pool upon removal
++		pool.setAutoDelete(true);
++	}
++	
++	QPtrList<JabberResource> pool;
++	QPtrList<JabberResource> lockList;
+ 
+-	// automatically delete all resources in the pool upon removal
+-	mPool.setAutoDelete (true);
++	/**
++	 * Pointer to the JabberAccount instance.
++	 */
++	JabberAccount *account;
++};
+ 
+-	mAccount = account;
++JabberResourcePool::JabberResourcePool ( JabberAccount *account )
++	: d(new Private(account))
++{}
+ 
+-}
+-
+ JabberResourcePool::~JabberResourcePool ()
+ {
++	delete d;
+ }
+ 
+ void JabberResourcePool::slotResourceDestroyed (QObject *sender)
+@@ -51,39 +69,40 @@
+ 	JabberResource *oldResource = static_cast<JabberResource *>(sender);
+ 
+ 	// remove this resource from the lock list if it existed
+-	mLockList.remove ( oldResource );
+-
++	d->lockList.remove ( oldResource );
+ }
+ 
+ void JabberResourcePool::slotResourceUpdated ( JabberResource *resource )
+ {
++	QPtrList<JabberBaseContact> list = d->account->contactPool()->findRelevantSources ( resource->jid () );
+ 
+-	QPtrList<JabberBaseContact> list = mAccount->contactPool()->findRelevantSources ( resource->jid () );
+-
+ 	for(JabberBaseContact *mContact = list.first (); mContact; mContact = list.next ())
+ 	{
+ 		mContact->updateResourceList ();
+ 	}
+ 
++	// Update capabilities
++	if( !resource->resource().status().capsNode().isEmpty() )
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating capabilities for JID: " << resource->jid().full() << endl;
++		d->account->protocol()->capabilitiesManager()->updateCapabilities( d->account, resource->jid(), resource->resource().status() );
++	}
+ }
+ 
+ void JabberResourcePool::notifyRelevantContacts ( const XMPP::Jid &jid )
+ {
++	QPtrList<JabberBaseContact> list = d->account->contactPool()->findRelevantSources ( jid );
+ 
+-	QPtrList<JabberBaseContact> list = mAccount->contactPool()->findRelevantSources ( jid );
+-
+ 	for(JabberBaseContact *mContact = list.first (); mContact; mContact = list.next ())
+ 	{
+ 		mContact->reevaluateStatus ();
+ 	}
+-
+ }
+ 
+ void JabberResourcePool::addResource ( const XMPP::Jid &jid, const XMPP::Resource &resource )
+ {
+-
+ 	// see if the resource already exists
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( (mResource->jid().userHost().lower() == jid.userHost().lower()) && (mResource->resource().name().lower() == resource.name().lower()) )
+ 		{
+@@ -104,41 +123,47 @@
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Adding new resource " << resource.name() << " for " << jid.userHost() << endl;
+ 
++	// Update initial capabilities if available.
++	// Called before creating JabberResource so JabberResource wouldn't ask for disco information. 
++	if( !resource.status().capsNode().isEmpty() )
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Initial update of capabilities for JID: " << jid.full() << endl;
++		d->account->protocol()->capabilitiesManager()->updateCapabilities( d->account, jid, resource.status() );
++	}
++
+ 	// create new resource instance and add it to the dictionary
+-	JabberResource *newResource = new JabberResource(mAccount, jid, resource);
++	JabberResource *newResource = new JabberResource(d->account, jid, resource);
+ 	connect ( newResource, SIGNAL ( destroyed (QObject *) ), this, SLOT ( slotResourceDestroyed (QObject *) ) );
+ 	connect ( newResource, SIGNAL ( updated (JabberResource *) ), this, SLOT ( slotResourceUpdated (JabberResource *) ) );
+-	mPool.append ( newResource );
++	d->pool.append ( newResource );
+ 
+ 	// send notifications out to the relevant contacts that
+ 	// a new resource is available for them
+ 	notifyRelevantContacts ( jid );
+-
+ }
+ 
+ void JabberResourcePool::removeResource ( const XMPP::Jid &jid, const XMPP::Resource &resource )
+ {
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing resource " << resource.name() << " from " << jid.userHost() << endl;
+ 
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( (mResource->jid().userHost().lower() == jid.userHost().lower()) && (mResource->resource().name().lower() == resource.name().lower()) )
+ 		{
+-			mPool.remove ();
++			d->pool.remove ();
+ 			notifyRelevantContacts ( jid );
+ 			return;
+ 		}
+ 	}
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: No match found!" << endl;
+-
+ }
+ 
+ void JabberResourcePool::removeAllResources ( const XMPP::Jid &jid )
+ {
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing all resources for " << jid.userHost() << endl;
+ 
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( mResource->jid().userHost().lower() == jid.userHost().lower() )
+ 		{
+@@ -146,11 +171,10 @@
+ 			if ( jid.resource().isEmpty () || ( jid.resource().lower () == mResource->resource().name().lower () ) )
+ 			{
+ 				kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing resource " << jid.userHost() << "/" << mResource->resource().name () << endl;
+-				mPool.remove ();
++				d->pool.remove ();
+ 			}
+ 		}
+ 	}
+-
+ }
+ 
+ void JabberResourcePool::clear ()
+@@ -167,7 +191,7 @@
+ 
+ 	QStringList jidList;
+ 
+-	for ( JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next () )
++	for ( JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next () )
+ 	{
+ 		jidList += mResource->jid().full ();
+ 	}
+@@ -176,7 +200,7 @@
+ 	 * Since mPool has autodeletion enabled, this will cause all
+ 	 * items to be deleted. The lock list will be cleaned automatically.
+ 	 */
+-	mPool.clear ();
++	d->pool.clear ();
+ 
+ 	/*
+ 	 * Now go through the list of JIDs and notify each contact
+@@ -191,24 +215,22 @@
+ 
+ void JabberResourcePool::lockToResource ( const XMPP::Jid &jid, const XMPP::Resource &resource )
+ {
+-
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Locking " << jid.full() << " to " << resource.name() << endl;
+ 
+ 	// remove all existing locks first
+ 	removeLock ( jid );
+ 
+ 	// find the resource in our dictionary that matches
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( (mResource->jid().userHost().lower() == jid.full().lower()) && (mResource->resource().name().lower() == resource.name().lower()) )
+ 		{
+-			mLockList.append ( mResource );
++			d->lockList.append ( mResource );
+ 			return;
+ 		}
+ 	}
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: No match found!" << endl;
+-
+ }
+ 
+ void JabberResourcePool::removeLock ( const XMPP::Jid &jid )
+@@ -216,68 +238,69 @@
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing resource lock for " << jid.userHost() << endl;
+ 
+ 	// find the resource in our dictionary that matches
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( (mResource->jid().userHost().lower() == jid.userHost().lower()) )
+ 		{
+-			mLockList.remove (mResource);
++			d->lockList.remove (mResource);
+ 		}
+ 	}
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "No locks found." << endl;
+-
+ }
+ 
+-const XMPP::Resource &JabberResourcePool::lockedResource ( const XMPP::Jid &jid )
++JabberResource *JabberResourcePool::lockedJabberResource( const XMPP::Jid &jid )
+ {
+-
+ 	// check if the JID already carries a resource, then we will have to use that one
+ 	if ( !jid.resource().isEmpty () )
+ 	{
+ 		// we are subscribed to a JID, find the according resource in the pool
+-		for ( JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next () )
++		for ( JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next () )
+ 		{
+ 			if ( ( mResource->jid().userHost().lower () == jid.userHost().lower () ) && ( mResource->resource().name () == jid.resource () ) )
+ 			{
+-				return mResource->resource ();
++				return mResource;
+ 			}
+ 		}
+ 
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "WARNING: No resource found in pool, returning as offline." << endl;
+ 
+-		return EmptyResource;
++		return 0L;
+ 	}
+ 
+ 	// see if we have a locked resource
+-	for(JabberResource *mResource = mLockList.first (); mResource; mResource = mLockList.next ())
++	for(JabberResource *mResource = d->lockList.first (); mResource; mResource = d->lockList.next ())
+ 	{
+ 		if ( mResource->jid().userHost().lower() == jid.userHost().lower() )
+ 		{
+ 			kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Current lock for " << jid.userHost () << " is '" << mResource->resource().name () << "'" << endl;
+-			return mResource->resource ();
++			return mResource;
+ 		}
+ 	}
+ 
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "No lock available for " << jid.userHost () << endl;
+ 
+ 	// there's no locked resource, return an empty resource
+-	return EmptyResource;
++	return 0L;
++}
+ 
++const XMPP::Resource &JabberResourcePool::lockedResource ( const XMPP::Jid &jid )
++{
++	JabberResource *resource = lockedJabberResource( jid );
++	return (resource) ? resource->resource() : EmptyResource;
+ }
+ 
+-const XMPP::Resource &JabberResourcePool::bestResource ( const XMPP::Jid &jid, bool honourLock )
++JabberResource *JabberResourcePool::bestJabberResource( const XMPP::Jid &jid, bool honourLock )
+ {
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Determining best resource for " << jid.full () << endl;
+ 
+-	// FIXME: the code below would be more efficient if it would cache results
+-
+ 	if ( honourLock )
+ 	{
+ 		// if we are locked to a certain resource, always return that one
+-		const XMPP::Resource &mResource = lockedResource ( jid );
+-		if ( !mResource.name().isEmpty() )
++		JabberResource *mResource = lockedJabberResource ( jid );
++		if ( mResource )
+ 		{
+-			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "We have a locked resource '" << mResource.name () << "' for " << jid.full () << endl;
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "We have a locked resource '" << mResource->resource().name () << "' for " << jid.full () << endl;
+ 			return mResource;
+ 		}
+ 	}
+@@ -285,7 +308,7 @@
+ 	JabberResource *bestResource = 0L;
+ 	JabberResource *currentResource = 0L;
+ 
+-	for(currentResource = mPool.first (); currentResource; currentResource = mPool.next ())
++	for(currentResource = d->pool.first (); currentResource; currentResource = d->pool.next ())
+ 	{
+ 		// make sure we are only looking up resources for the specified JID
+ 		if ( currentResource->jid().userHost().lower() != jid.userHost().lower() )
+@@ -324,14 +347,19 @@
+ 		}
+ 	}
+ 
+-	return (bestResource == 0L) ? EmptyResource : bestResource->resource();
++	return (bestResource) ? bestResource : 0L;
++}
+ 
++const XMPP::Resource &JabberResourcePool::bestResource ( const XMPP::Jid &jid, bool honourLock )
++{
++	JabberResource *bestResource = bestJabberResource( jid, honourLock);
++	return (bestResource) ? bestResource->resource() : EmptyResource;
+ }
+ 
++//TODO: Find Resources based on certain Features.
+ void JabberResourcePool::findResources ( const XMPP::Jid &jid, JabberResourcePool::ResourceList &resourceList )
+ {
+-
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( mResource->jid().userHost().lower() == jid.userHost().lower() )
+ 		{
+@@ -344,13 +372,11 @@
+ 			resourceList.append ( mResource );
+ 		}
+ 	}
+-
+ }
+ 
+ void JabberResourcePool::findResources ( const XMPP::Jid &jid, XMPP::ResourceList &resourceList )
+ {
+-
+-	for(JabberResource *mResource = mPool.first (); mResource; mResource = mPool.next ())
++	for(JabberResource *mResource = d->pool.first (); mResource; mResource = d->pool.next ())
+ 	{
+ 		if ( mResource->jid().userHost().lower() == jid.userHost().lower() )
+ 		{
+@@ -363,7 +389,6 @@
+ 			resourceList.append ( mResource->resource () );
+ 		}
+ 	}
+-
+ }
+ 
+ #include "jabberresourcepool.moc"
+--- kopete/protocols/jabber/jabberclient.h	(revision 568672)
++++ kopete/protocols/jabber/jabberclient.h	(revision 586398)
+@@ -4,8 +4,9 @@
+                              -------------------
+     begin                : Sat May 25 2005
+     copyright            : (C) 2005 by Till Gerken <till at tantalo.net>
++                           (C) 2006 by Michaël Larouche <michael.larouche at kdemail.net>
+ 
+-			   Kopete (C) 2001-2005 Kopete developers
++			   Kopete (C) 2001-2006 Kopete developers
+ 			   <kopete-devel at kde.org>.
+  ***************************************************************************/
+ 
+@@ -67,7 +68,11 @@
+ 		Ok,					/** No error. */
+ 		InvalidPassword,	/** Password used to connect to the server was incorrect. */
+ 		AlreadyConnected,	/** A new connection was attempted while the previous one hasn't been closed. */
+-		NoTLS				/** Use of TLS has been forced (see @ref forceTLS) but TLS is not available, either server- or client-side. */
++		NoTLS,				/** Use of TLS has been forced (see @ref forceTLS) but TLS is not available, either server- or client-side. */
++		InvalidPasswordForMUC = 401,	/** A password is require to enter on this Multi-User Chat */
++		NicknameConflict = 409,		/** There is already someone with that nick connected to the Multi-User Chat */
++		BannedFromThisMUC = 403,	/** You can't join this Multi-User Chat because you were bannished */
++		MaxUsersReachedForThisMuc = 503	/** You can't join this Multi-User Chat because it is full */
+ 	};
+ 
+ 	JabberClient();
+@@ -85,6 +90,12 @@
+ 	 * Disconnect from Jabber server.
+ 	 */
+ 	void disconnect ();
++	
++	/**
++	 * Disconnect from Jabber server with reason
++	 * @param reason The reason for disconnecting
++	 */
++	void disconnect (XMPP::Status &reason);
+ 
+ 	/**
+ 	 * Returns if this instance is connected to a server.
+@@ -242,6 +253,53 @@
+ 	QString osName () const;
+ 
+ 	/**
++	 * Set the caps(JEP-0115: Entity capabilities) node name.
++	 * @param node Node name.
++	 */
++	void setCapsNode( const QString &capsNode );
++	/**
++	 * Return the caps node name for this client.
++	 * @return the caps node name.
++	 */
++	QString capsNode() const;
++	
++	/**
++	 * Set the caps(JEP-0115: Entity capabilities) node version.
++	 * @param capsVersion the node version.
++	 */
++	void setCapsVersion( const QString &capsVersion );
++	/**
++	 * Return the caps version for this client.
++	 * @return the caps version.
++	 */
++	QString capsVersion() const;
++
++	/**
++	 * Return the caps extension list for this client.
++	 * @return A string containing all extensions separated by space.
++	 */
++	QString capsExt() const;
++
++	/**
++	 * Set the disco Identity information for this client.
++	 * Create a Disco identity like this:
++	 * @code
++	 * DiscoItem::Identity identity;
++	 * identity.category = "client";
++	 * identity.type = "pc";
++	 * identity.name = "Kopete";
++	 * @endcode
++	 *
++	 * @param identity DiscoItem::Identity for the client.
++	 */
++	void setDiscoIdentity(DiscoItem::Identity identity);
++	/**
++	 * Get the disco Identity information for this client.
++	 * @return the DiscoItem::Identity for this client.
++	 */
++	DiscoItem::Identity discoIdentity() const;
++
++	/**
+ 	 * Set timezone information. Default is UTC.
+ 	 */
+ 	void setTimeZone ( const QString &timeZoneName, int timeZoneOffset );
+@@ -302,11 +360,29 @@
+ 	void joinGroupChat ( const QString &host, const QString &room, const QString &nick );
+ 
+ 	/**
++	 * Join a group chat that require a password.
++	 * @param host Node to join the room at.
++	 * @param room Name of room to join.
++	 * @param nick Nick name you want to join with.
++	 * @param password The password to join the room.
++	 */
++	void joinGroupChat ( const QString &host, const QString &room, const QString &nick, const QString &password );
++
++	/**
+ 	 * Leave a group chat.
+ 	 * @param host Node to leave room at.
+ 	 * @param room Name of room to leave.
+ 	 */
+ 	void leaveGroupChat ( const QString &host, const QString &room );
++	
++	/**
++	 * change the status of a group chat
++	 */
++	void setGroupChatStatus(const QString &host, const QString &room, const XMPP::Status &);
++	/**
++	 * change the nick in a group chat
++	 */
++	void changeGroupChatNick(const QString &host, const QString &room, const QString &nick, const XMPP::Status &status =XMPP::Status());
+ 
+ 	/**
+ 	 * Send a message.
+@@ -435,71 +511,25 @@
+ 	void debugMessage ( const QString &message );
+ 
+ private:
+-	// connection details
+-	XMPP::Jid m_jid;
+-	QString m_password;
++	class Private;
++	Private *d;
+ 
+-	// XMPP backend
+-	XMPP::Client *m_jabberClient;
+-	XMPP::ClientStream *m_jabberClientStream;
+-	JabberConnector *m_jabberClientConnector;
+-	QCA::TLS *m_jabberTLS;
+-	XMPP::QCATLSHandler *m_jabberTLSHandler;
+-
+-	// ignore TLS warnings
+-	bool m_ignoreTLSWarnings;
+-
+-	// current S5B server instance
+-	static XMPP::S5BServer *m_s5bServer;
+-	// address list being handled by the S5B server instance
+-	static QStringList m_s5bAddressList;
+-	// port of S5B server
+-	static int m_s5bServerPort;
+-
+-	// local IP address
+-	QString m_localAddress;
+-
+-	// whether TLS (or direct SSL in case of the old protocol) should be used
+-	bool m_forceTLS;
+-
+-	// whether direct SSL connections should be used
+-	bool m_useSSL;
+-
+-	// use XMPP 1.0 or the older protocol version
+-	bool m_useXMPP09;
+-
+-	// whether SSL support should be probed in case the old protocol is used
+-	bool m_probeSSL;
+-
+-	// override the default server name and port (only pre-XMPP 1.0)
+-	bool m_overrideHost;
+-	QString m_server;
+-	int m_port;
+-
+-	// allow transmission of plaintext passwords
+-	bool m_allowPlainTextPassword;
+-
+-	// enable file transfers
+-	bool m_fileTransfersEnabled;
+-
+-	// current penalty time
+-	int m_currentPenaltyTime;
+-
+-	// client information
+-	QString m_clientName, m_clientVersion, m_osName;
+-
+-	// timezone information
+-	QString m_timeZoneName;
+-	int m_timeZoneOffset;
+-
+-	// delete all member classes and reset the class to a predefined state
++	/**
++	 * Delete all member classes and reset the class to a predefined state.
++	 */
+ 	void cleanUp ();
+ 
+-	// return current instance of the S5B server
++	/** 
++	 * Return current instance of the S5B server.
++	 */
+ 	XMPP::S5BServer *s5bServer ();
+-	// add an address that the S5B server should handle
++	/** 
++	 * Add an address that the S5B server should handle.
++	 */
+ 	void addS5BServerAddress ( const QString &address );
+-	// remove an address that the S5B server currently handles
++	/** 
++	 * Remove an address that the S5B server currently handles.
++	 */
+ 	void removeS5BServerAddress ( const QString &address );
+ 
+ private slots:
+--- kopete/protocols/jabber/jabbercapabilitiesmanager.cpp	(revision 0)
++++ kopete/protocols/jabber/jabbercapabilitiesmanager.cpp	(revision 586398)
+@@ -0,0 +1,656 @@
++ /*
++    jabbercapabilitiesmanager.cpp - Manage entity capabilities(JEP-0115).
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at kde.org>
++
++    Imported from caps.cpp from Psi:
++    Copyright (C) 2005  Remko Troncon
++
++    *************************************************************************
++    *                                                                       *
++    * 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 "jabbercapabilitiesmanager.h"
++
++#include <qstring.h>
++#include <qstringlist.h>
++#include <qtimer.h>
++#include <qpair.h>
++#include <qdom.h>
++#include <qtextstream.h>
++
++#include <kstandarddirs.h>
++#include <kdebug.h>
++
++#include <xmpp_tasks.h>
++
++#include "jabberaccount.h"
++#include "jabberprotocol.h"
++
++using namespace XMPP;
++
++//BEGIN Capabilities
++JabberCapabilitiesManager::Capabilities::Capabilities()
++{}
++
++JabberCapabilitiesManager::Capabilities::Capabilities(const QString& node, const QString& version, const QString& extensions) 
++	: m_node(node), m_version(version), m_extensions(extensions) 
++{}
++
++const QString& JabberCapabilitiesManager::Capabilities::node() const 
++{ 
++	return m_node; 
++}
++
++const QString& JabberCapabilitiesManager::Capabilities::version() const 
++{ 
++	return m_version; 
++}
++
++const QString& JabberCapabilitiesManager::Capabilities::extensions() const 
++{ 
++	return m_extensions; 
++}
++
++JabberCapabilitiesManager::CapabilitiesList JabberCapabilitiesManager::Capabilities::flatten() const 
++{
++	CapabilitiesList capsList;
++	capsList.append( Capabilities(node(), version(), version()) );
++
++	QStringList extensionList = QStringList::split(" ",extensions());
++	QStringList::ConstIterator it, itEnd = extensionList.constEnd();
++	for(it = extensionList.constBegin(); it != itEnd; ++it)
++	{
++		capsList.append( Capabilities(node(),version(),*it) );
++	}
++
++	return capsList;
++}
++
++bool JabberCapabilitiesManager::Capabilities::operator==(const Capabilities &other) const 
++{
++	return (node() == other.node() && version() == other.version() && extensions() == other.extensions());
++}
++
++bool JabberCapabilitiesManager::Capabilities::operator!=(const Capabilities &other) const 
++{
++	return !((*this) == other);
++}
++
++bool JabberCapabilitiesManager::Capabilities::operator<(const Capabilities &other) const 
++{
++	return (node() != other.node() ? node() < other.node() :
++			(version() != other.version() ? version() < other.version() : 
++			 extensions() < other.extensions()));
++}
++//END Capabilities
++
++//BEGIN CapabilitiesInformation
++JabberCapabilitiesManager::CapabilitiesInformation::CapabilitiesInformation() 
++	: m_discovered(false), m_pendingRequests(0)
++{
++	updateLastSeen();
++}
++
++const QStringList& JabberCapabilitiesManager::CapabilitiesInformation::features() const
++{
++	return m_features;
++}
++
++const DiscoItem::Identities& JabberCapabilitiesManager::CapabilitiesInformation::identities() const
++{
++	return m_identities;
++}
++
++QStringList JabberCapabilitiesManager::CapabilitiesInformation::jids() const
++{
++	QStringList jids;
++	
++	QValueList<QPair<QString,JabberAccount*> >::ConstIterator it = m_jids.constBegin(), itEnd = m_jids.constEnd();
++	for( ; it != itEnd; ++it) 
++	{
++		QString jid( (*it).first );
++		if( !jids.contains(jid) )
++			jids.push_back(jid);
++	}
++
++	return jids;
++}
++
++bool JabberCapabilitiesManager::CapabilitiesInformation::discovered() const
++{
++	return m_discovered;
++}
++
++int JabberCapabilitiesManager::CapabilitiesInformation::pendingRequests() const
++{
++	return m_pendingRequests;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::reset()
++{
++	m_features.clear();
++	m_identities.clear();
++	m_discovered = false;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::removeAccount(JabberAccount *account)
++{
++	QValueList<QPair<QString,JabberAccount*> >::Iterator it = m_jids.begin();
++	while( it != m_jids.end() ) 
++	{
++		if( (*it).second == account) 
++		{
++			QValueList<QPair<QString,JabberAccount*> >::Iterator otherIt = it;
++			it++;
++			m_jids.remove(otherIt);
++		}
++		else 
++		{
++			it++;
++		}
++	}
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::addJid(const Jid& jid, JabberAccount* account)
++{
++	QPair<QString,JabberAccount*> jidAccountPair(jid.full(),account);
++
++	if( !m_jids.contains(jidAccountPair) ) 
++	{
++		m_jids.push_back(jidAccountPair);
++		updateLastSeen();
++	}
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::removeJid(const Jid& jid)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Unregistering " << QString(jid.full()).replace('%',"%%") << endl;
++
++	QValueList<QPair<QString,JabberAccount*> >::Iterator it = m_jids.begin();
++	while( it != m_jids.end() ) 
++	{
++		if( (*it).first == jid.full() ) 
++		{
++			QValueList<QPair<QString,JabberAccount*> >::Iterator otherIt = it;
++			it++;
++			m_jids.remove(otherIt);
++		}
++		else 
++		{
++			it++;
++		}
++	}
++}
++
++QPair<Jid,JabberAccount*> JabberCapabilitiesManager::CapabilitiesInformation::nextJid(const Jid& jid, const Task* t)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Looking for next JID" << endl;
++
++	QValueList<QPair<QString,JabberAccount*> >::ConstIterator it = m_jids.constBegin(), itEnd = m_jids.constEnd();
++	for( ; it != itEnd; ++it) 
++	{
++		if( (*it).first == jid.full() && (*it).second->client()->rootTask() == t) 
++		{
++			it++;
++			if (it == itEnd) 
++			{
++				kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "No more JIDs" << endl;
++
++				return QPair<Jid,JabberAccount*>(Jid(),0L);
++			}
++			else if( (*it).second->isConnected() ) 
++			{
++				//qDebug("caps.cpp: Account isn't active");
++				kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Account isn't connected." << endl;
++
++				return QPair<Jid,JabberAccount*>( (*it).first,(*it).second );
++			}
++		}
++	}
++	return QPair<Jid,JabberAccount*>(Jid(),0L);
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::setDiscovered(bool value)
++{
++	m_discovered = value;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::setPendingRequests(int pendingRequests)
++{
++	m_pendingRequests = pendingRequests;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::setIdentities(const DiscoItem::Identities& identities)
++{
++	m_identities = identities;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::setFeatures(const QStringList& featureList)
++{
++	m_features = featureList;
++}
++	
++void JabberCapabilitiesManager::CapabilitiesInformation::updateLastSeen()
++{
++	m_lastSeen = QDate::currentDate();
++}
++
++QDomElement JabberCapabilitiesManager::CapabilitiesInformation::toXml(QDomDocument *doc) const
++{
++	QDomElement info = doc->createElement("info");
++	//info.setAttribute("last-seen",lastSeen_.toString(Qt::ISODate));
++
++	// Identities
++	DiscoItem::Identities::ConstIterator discoIt = m_identities.constBegin(), discoItEnd = m_identities.constEnd();
++	for( ; discoIt != discoItEnd; ++discoIt ) 
++	{
++		QDomElement identity = doc->createElement("identity");
++		identity.setAttribute("category",(*discoIt).category);
++		identity.setAttribute("name",(*discoIt).name);
++		identity.setAttribute("type",(*discoIt).type);
++		info.appendChild(identity);
++	}
++
++	// Features
++	QStringList::ConstIterator featuresIt = m_features.constBegin(), featuresItEnd = m_features.constEnd();
++	for( ; featuresIt != featuresItEnd; ++featuresIt )
++	{
++		QDomElement feature = doc->createElement("feature");
++		feature.setAttribute("node",*featuresIt);
++		info.appendChild(feature);
++	}
++
++	return info;
++}
++
++void JabberCapabilitiesManager::CapabilitiesInformation::fromXml(const QDomElement &element)
++{
++	if( element.tagName() != "info") 
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Invalid info element" << endl;
++		return;
++	}
++	
++	//if (!e.attribute("last-seen").isEmpty())
++	//	lastSeen_ = QDate::fromString(e.attribute("last-seen"),Qt::ISODate);
++
++	for(QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) 
++	{
++		QDomElement infoElement = node.toElement();
++		if( infoElement.isNull() ) 
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Null element" << endl;
++			continue;
++		}
++
++		if( infoElement.tagName() == "identity") 
++		{
++			DiscoItem::Identity id;
++			id.category = infoElement.attribute("category");
++			id.name = infoElement.attribute("name");
++			id.type = infoElement.attribute("type");
++			m_identities += id;
++		}
++		else if( infoElement.tagName() == "feature" ) 
++		{
++			m_features += infoElement.attribute("node");
++		}
++		else 
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Unknown element" << endl;
++		}
++
++		m_discovered = true;
++	}
++}
++//END CapabilitiesInformation
++
++//BEGIN Private(d-ptr)
++class JabberCapabilitiesManager::Private
++{
++public:
++	Private()
++	{}
++
++	// Map a full jid to a capabilities
++	QMap<QString,Capabilities> jidCapabilitiesMap;
++	// Map a capabilities to its detail information
++	QMap<Capabilities,CapabilitiesInformation> capabilitiesInformationMap;
++};
++//END Private(d-ptr)
++
++JabberCapabilitiesManager::JabberCapabilitiesManager()
++	: d(new Private)
++{
++}
++
++JabberCapabilitiesManager::~JabberCapabilitiesManager()
++{
++	saveInformation();
++	delete d;
++}
++
++void JabberCapabilitiesManager::removeAccount(JabberAccount *account)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing account " << account->accountId() << endl;
++
++	QValueList<CapabilitiesInformation> info = d->capabilitiesInformationMap.values();
++
++	QValueList<CapabilitiesInformation>::Iterator it, itEnd = info.end();
++	for(it = info.begin(); it != info.end(); ++it) 
++	{
++		(*it).removeAccount(account);
++	}
++}
++
++void JabberCapabilitiesManager::updateCapabilities(JabberAccount *account, const XMPP::Jid &jid, const XMPP::Status &status )
++{
++	if( !account->client() || !account->client()->rootTask() )
++		return;
++	
++	
++	// Do don't anything if the jid correspond to the account's JabberClient jid.
++	// false means that we don't check for resources.
++	if( jid.compare(account->client()->jid(), false) )
++		return;
++
++	QString node = status.capsNode(), version = status.capsVersion(), extensions = status.capsExt();
++	Capabilities capabilities( node, version, extensions );
++	
++	// Check if the capabilities was really updated(i.e the content is different)
++	if( d->jidCapabilitiesMap[jid.full()] != capabilities) 
++	{
++		// Unregister from all old caps nodes
++		// FIXME: We should only unregister & register from changed nodes
++		CapabilitiesList oldCaps = d->jidCapabilitiesMap[jid.full()].flatten();
++		CapabilitiesList::Iterator oldCapsIt = oldCaps.begin(), oldCapsItEnd = oldCaps.end();
++		for( ; oldCapsIt != oldCapsItEnd; ++oldCapsIt) 
++		{
++			if( (*oldCapsIt) != Capabilities() ) 
++			{
++				d->capabilitiesInformationMap[*oldCapsIt].removeJid(jid);
++			}
++		}
++
++		// Check if the jid has caps in his presence message.
++		if( !status.capsNode().isEmpty() && !status.capsVersion().isEmpty() ) 
++		{
++			// Register with all new caps nodes
++			d->jidCapabilitiesMap[jid.full()] = capabilities;
++			CapabilitiesList caps = capabilities.flatten();
++			CapabilitiesList::Iterator newCapsIt = caps.begin(), newCapsItEnd = caps.end();
++			for( ; newCapsIt != newCapsItEnd; ++newCapsIt ) 
++			{
++				d->capabilitiesInformationMap[*newCapsIt].addJid(jid,account);
++			}
++			
++			emit capabilitiesChanged(jid); 
++
++			// Register new caps and check if we need to discover features
++			newCapsIt = caps.begin();
++			for( ; newCapsIt != newCapsItEnd; ++newCapsIt ) 
++			{
++				if( !d->capabilitiesInformationMap[*newCapsIt].discovered() && d->capabilitiesInformationMap[*newCapsIt].pendingRequests() == 0 ) 
++				{
++					kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << QString("Sending disco request to %1, node=%2").arg(QString(jid.full()).replace('%',"%%")).arg(node + "#" + (*newCapsIt).extensions()) << endl;
++
++					d->capabilitiesInformationMap[*newCapsIt].setPendingRequests(1);
++					requestDiscoInfo(account, jid, node + "#" + (*newCapsIt).extensions());
++				}
++			}
++		}
++		else 
++		{
++			// Remove all caps specifications
++			kdDebug(JABBER_DEBUG_GLOBAL) << QString("Illegal caps info from %1: node=%2, ver=%3").arg(QString(jid.full()).replace('%',"%%")).arg(node).arg(version) << endl;
++
++			d->jidCapabilitiesMap.remove( jid.full() );
++		}
++	}
++	else
++	{
++		// Add to the list of jids
++		CapabilitiesList caps = capabilities.flatten();
++		CapabilitiesList::Iterator capsIt = caps.begin(), capsItEnd = caps.end();
++		for( ; capsIt != capsItEnd; ++capsIt) 
++		{
++			d->capabilitiesInformationMap[*capsIt].addJid(jid,account);
++		}
++	}
++}
++
++void JabberCapabilitiesManager::requestDiscoInfo(JabberAccount *account, const Jid& jid, const QString& node) 
++{
++	if( !account->client()->rootTask() )
++		return;
++ 
++	JT_DiscoInfo *discoInfo = new JT_DiscoInfo(account->client()->rootTask());
++	connect(discoInfo, SIGNAL(finished()), SLOT(discoRequestFinished()));
++	discoInfo->get(jid, node);
++	//pending_++;
++	//timer_.start(REQUEST_TIMEOUT,true);
++	discoInfo->go(true);
++}
++
++void JabberCapabilitiesManager::discoRequestFinished()
++{
++	JT_DiscoInfo *discoInfo = (JT_DiscoInfo*)sender();
++	if (!discoInfo)
++		return;
++
++	DiscoItem item = discoInfo->item();
++	Jid jid = discoInfo->jid();
++	kdDebug(JABBER_DEBUG_GLOBAL) << QString("Disco response from %1, node=%2, success=%3").arg(QString(jid.full()).replace('%',"%%")).arg(discoInfo->node()).arg(discoInfo->success()) << endl;
++
++	QStringList tokens = QStringList::split("#",discoInfo->node());
++
++	// Update features
++	Q_ASSERT(tokens.count() == 2);
++	QString node = tokens[0];
++	QString extensions = tokens[1];
++
++	Capabilities jidCapabilities = d->jidCapabilitiesMap[jid.full()];
++	if( jidCapabilities.node() == node )
++	{
++		Capabilities capabilities(node, jidCapabilities.version(), extensions);
++
++		if( discoInfo->success() )
++		{
++			// Save identities & features
++			d->capabilitiesInformationMap[capabilities].setIdentities(item.identities());
++			d->capabilitiesInformationMap[capabilities].setFeatures(item.features().list());
++			d->capabilitiesInformationMap[capabilities].setPendingRequests(0);
++			d->capabilitiesInformationMap[capabilities].setDiscovered(true);
++
++			// Save(Cache) information
++			saveInformation();
++			
++			// Notify affected jids.
++			QStringList jids = d->capabilitiesInformationMap[capabilities].jids();
++			QStringList::ConstIterator jidsIt = jids.constBegin(), jidsItEnd = jids.constEnd();
++			for( ; jidsIt != jidsItEnd; ++jidsItEnd ) 
++			{
++				emit capabilitiesChanged(*jidsIt);
++			}
++		}
++		else 
++		{
++			QPair<Jid,JabberAccount*> jidAccountPair = d->capabilitiesInformationMap[capabilities].nextJid(jid,discoInfo->parent());
++			if( jidAccountPair.second ) 
++			{
++				kdDebug(JABBER_DEBUG_GLOBAL) << QString("Falling back on %1.").arg(QString(jidAccountPair.first.full()).replace('%',"%%")) << endl;
++				requestDiscoInfo( jidAccountPair.second, jidAccountPair.first, discoInfo->node() );
++			}
++			else 
++			{
++				kdDebug(JABBER_DEBUG_GLOBAL) << "No valid disco request avalable." << endl;
++				d->capabilitiesInformationMap[capabilities].setPendingRequests(0);
++			}
++		}
++	}
++	else 
++		kdDebug(JABBER_DEBUG_GLOBAL) << QString("Current client node '%1' does not match response '%2'").arg(jidCapabilities.node()).arg(node) << endl;
++
++	//for (unsigned int i = 0; i < item.features().list().count(); i++) 
++	//	printf("    Feature: %s\n",item.features().list()[i].latin1());
++
++	// Check pending requests
++//	pending_ = (pending_ > 0 ? pending_-1 : 0);
++//	if (!pending_) {
++//		timer_.stop();
++//		updatePendingJIDs();
++//	}
++}
++
++void JabberCapabilitiesManager::loadCachedInformation()
++{
++	QString capsFileName;
++	capsFileName = locateLocal("appdata", QString::fromUtf8("jabber-capabilities-cache.xml"));
++
++	// Load settings
++	QDomDocument doc;
++	QFile cacheFile(capsFileName);
++	if( !cacheFile.open(IO_ReadOnly) )
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Could not open the Capabilities cache from disk." << endl;
++		return;
++	}
++	if( !doc.setContent(&cacheFile) )
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Could not set the Capabilities cache from file." << endl;
++		return;
++	}
++	cacheFile.close();
++
++	QDomElement caps = doc.documentElement();
++	if( caps.tagName() != "capabilities" ) 
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Invalid capabilities element." << endl;
++		return;
++	}
++	
++	QDomNode node;	
++	for(node = caps.firstChild(); !node.isNull(); node = node.nextSibling()) 
++	{
++		QDomElement element = node.toElement();
++		if( element.isNull() ) 
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Found a null element." << endl;
++			continue;
++		}
++
++		if( element.tagName() == "info" ) 
++		{
++			CapabilitiesInformation info;
++			info.fromXml(element);
++			Capabilities entityCaps( element.attribute("node"),element.attribute("ver"),element.attribute("ext") );
++			d->capabilitiesInformationMap[entityCaps] = info;
++		}
++		else 
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Unknow element" << endl;
++		}
++	}
++}
++
++bool JabberCapabilitiesManager::capabilitiesEnabled(const Jid &jid) const
++{
++	return d->jidCapabilitiesMap.contains( jid.full() );	
++}
++
++XMPP::Features JabberCapabilitiesManager::features(const Jid& jid) const
++{
++	QStringList featuresList;
++
++	if( capabilitiesEnabled(jid) ) 
++	{
++		CapabilitiesList capabilitiesList = d->jidCapabilitiesMap[jid.full()].flatten();
++		CapabilitiesList::ConstIterator capsIt = capabilitiesList.constBegin(), capsItEnd = capabilitiesList.constEnd();
++		for( ; capsIt != capsItEnd; ++capsIt) 
++		{
++			featuresList += d->capabilitiesInformationMap[*capsIt].features();
++		}
++	}
++
++	return Features(featuresList);
++}
++
++QString JabberCapabilitiesManager::clientName(const Jid& jid) const
++{
++	if( capabilitiesEnabled(jid) ) 
++	{
++		Capabilities caps = d->jidCapabilitiesMap[jid.full()];
++		QString name = d->capabilitiesInformationMap[Capabilities(caps.node(),caps.version(),caps.version())].identities().first().name;
++		
++		// Try to be intelligent about the name
++		/*if (name.isEmpty()) {
++			name = cs.node();
++			if (name.startsWith("http://"))
++				name = name.right(name.length() - 7);
++				
++			if (name.startsWith("www."))
++				name = name.right(name.length() - 4);
++			
++			int cut_pos = name.find(".");
++			if (cut_pos != -1) {
++				name = name.left(cut_pos);
++			}
++		}*/
++
++		return name;
++	}
++	else 
++	{
++		return QString();
++	}
++}
++
++QString JabberCapabilitiesManager::clientVersion(const Jid& jid) const
++{
++	return (capabilitiesEnabled(jid) ? d->jidCapabilitiesMap[jid.full()].version() : QString());
++}
++
++void JabberCapabilitiesManager::saveInformation()
++{
++	QString capsFileName;
++	capsFileName = locateLocal("appdata", QString::fromUtf8("jabber-capabilities-cache.xml"));
++
++	// Generate XML
++	QDomDocument doc;
++	QDomElement capabilities = doc.createElement("capabilities");
++	doc.appendChild(capabilities);
++	QMap<Capabilities,CapabilitiesInformation>::ConstIterator it = d->capabilitiesInformationMap.constBegin(), itEnd = d->capabilitiesInformationMap.constEnd();
++	for( ; it != itEnd; ++it ) 
++	{
++		QDomElement info = it.data().toXml(&doc);
++		info.setAttribute("node",it.key().node());
++		info.setAttribute("ver",it.key().version());
++		info.setAttribute("ext",it.key().extensions());
++		capabilities.appendChild(info);
++	}
++
++	// Save
++	QFile capsFile(capsFileName);
++	if( !capsFile.open(IO_WriteOnly) ) 
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL	) << k_funcinfo << "Error while opening Capabilities cache file." << endl;
++		return;
++	}
++
++	QTextStream textStream;
++	textStream.setDevice(&capsFile);
++	textStream.setEncoding(QTextStream::UnicodeUTF8);
++	textStream << doc.toString();
++	textStream.unsetDevice();
++	capsFile.close();
++}
++
++#include "jabbercapabilitiesmanager.moc"
+--- kopete/protocols/jabber/jabberchatsession.h	(revision 568672)
++++ kopete/protocols/jabber/jabberchatsession.h	(revision 586398)
+@@ -28,6 +28,7 @@
+ namespace Kopete { class Message; }
+ class QString;
+ 
++
+ /**
+  * @author Till Gerken
+  */
+@@ -39,7 +40,9 @@
+ 	JabberChatSession ( JabberProtocol *protocol, const JabberBaseContact *user,
+ 						   Kopete::ContactPtrList others, const QString &resource = "",
+ 						   const char *name = 0 );
+-
++	
++	~JabberChatSession();
++	
+ 	/**
+ 	 * @brief Get the local user in the session
+ 	 * @return the local user in the session, same as account()->myself()
+@@ -82,6 +85,8 @@
+ 	 */
+ 	void slotUpdateDisplayName ();
+ 
++	void slotSendFile();
++
+ private:
+ 	/**
+ 	 * Send a notification (XMPP::MsgEvent) to the members of the chatsession.
+--- kopete/protocols/jabber/jabbercontactpool.h	(revision 568672)
++++ kopete/protocols/jabber/jabbercontactpool.h	(revision 586398)
+@@ -28,6 +28,7 @@
+ class JabberContact;
+ class JabberGroupContact;
+ class JabberAccount;
++class JabberTransport;
+ 
+ /**
+  * @author Till Gerken <till at tantalo.net>
+@@ -51,7 +52,7 @@
+ 	/**
+ 	 * Add a contact to the pool
+ 	 */
+-	JabberContact *addContact ( const XMPP::RosterItem &contact, Kopete::MetaContact *metaContact, bool dirty = true );
++	JabberContact *addContact ( const XMPP::RosterItem &contact, Kopete::MetaContact *metaContact, bool dirty = true  );
+ 	JabberBaseContact *addGroupContact ( const XMPP::RosterItem &contact, bool roomContact, Kopete::MetaContact *metaContact, bool dirty = true );
+ 
+ 	/**
+--- kopete/protocols/jabber/jabbercontact.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabbercontact.cpp	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabbercontact.cpp  -  Regular Kopete Jabber protocol contact
+   *
+   * Copyright (c) 2002-2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c) 2006     by Olivier Goffart <ogoffart at kde.org>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -23,6 +24,9 @@
+ #include <qtimer.h>
+ #include <qdatetime.h>
+ #include <qstylesheet.h>
++#include <qimage.h>
++#include <qregexp.h>
++#include <qbuffer.h>
+ 
+ #include <kdebug.h>
+ #include <klocale.h>
+@@ -30,11 +34,16 @@
+ #include <kfiledialog.h>
+ #include <kaction.h>
+ #include <kapplication.h>
++#include <kstandarddirs.h>
++#include <kio/netaccess.h>
++#include <kinputdialog.h>
++#include <kopeteview.h>
+ 
+ #include "kopetecontactlist.h"
+ #include "kopetegroup.h"
+ #include "kopeteuiglobal.h"
+ #include "kopetechatsessionmanager.h"
++#include "kopeteaccountmanager.h"
+ #include "jabberprotocol.h"
+ #include "jabberaccount.h"
+ #include "jabberclient.h"
+@@ -42,16 +51,22 @@
+ #include "jabberresource.h"
+ #include "jabberresourcepool.h"
+ #include "jabberfiletransfer.h"
++#include "jabbertransport.h"
+ #include "dlgjabbervcard.h"
+ 
++#ifdef SUPPORT_JINGLE
++// #include "jinglesessionmanager.h"
++// #include "jinglevoicesession.h"
++#include "jinglevoicesessiondialog.h"
++#endif
+ 
+ /**
+  * JabberContact constructor
+  */
+-JabberContact::JabberContact (const XMPP::RosterItem &rosterItem, JabberAccount *account, Kopete::MetaContact * mc)
+-				: JabberBaseContact ( rosterItem, account, mc)
++JabberContact::JabberContact (const XMPP::RosterItem &rosterItem, Kopete::Account *_account, Kopete::MetaContact * mc, const QString &legacyId)
++	: JabberBaseContact ( rosterItem, _account, mc, legacyId)  , mDiscoDone(false), m_syncTimer(0L)
+ {
+-
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << contactId() << "  is created  - " << this << endl;
+ 	// this contact is able to transfer files
+ 	setFileCapable ( true );
+ 
+@@ -70,21 +85,21 @@
+ 
+ 	mVCardUpdateInProgress = false;
+ 
+-	if ( !account->myself () )
++	if ( !account()->myself () )
+ 	{
+-		// this contact is the myself instance
++		// this contact is a regular contact
+ 		connect ( this,
+ 				  SIGNAL ( onlineStatusChanged ( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
+ 				  this, SLOT ( slotCheckVCard () ) );
+ 	}
+ 	else
+ 	{
+-		// this contact is a regular contact
+-		connect ( account->myself (),
++		// this contact is the myself instance
++		connect ( account()->myself (),
+ 				  SIGNAL ( onlineStatusChanged ( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
+ 				  this, SLOT ( slotCheckVCard () ) );
+ 
+-		connect ( account->myself (),
++		connect ( account()->myself (),
+ 				  SIGNAL ( onlineStatusChanged ( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
+ 				  this, SLOT ( slotCheckLastActivity ( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
+ 
+@@ -92,21 +107,26 @@
+ 		 * Trigger update once if we're already connected for contacts
+ 		 * that are being added while we are online.
+ 		 */
+-		if ( account->myself()->onlineStatus().isDefinitelyOnline() )
++		if ( account()->myself()->onlineStatus().isDefinitelyOnline() )
+ 		{
+ 			slotGetTimedVCard ();
+ 		}
+ 	}
+ 
+-	// call moved from superclass, see JabberBaseContact for details
+-	reevaluateStatus ();
+-
+ 	mRequestOfflineEvent = false;
+ 	mRequestDisplayedEvent = false;
+ 	mRequestDeliveredEvent = false;
+ 	mRequestComposingEvent = false;
++	mRequestGoneEvent = false;
+ }
+ 
++
++
++JabberContact::~JabberContact()
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << contactId() << "  is destroyed  - " << this << endl;
++}
++
+ QPtrList<KAction> *JabberContact::customContextMenuActions ()
+ {
+ 
+@@ -114,13 +134,23 @@
+ 
+ 	KActionMenu *actionAuthorization = new KActionMenu ( i18n ("Authorization"), "connect_established", this, "jabber_authorization");
+ 
+-	actionAuthorization->insert (new KAction (i18n ("(Re)send Authorization To"), "mail_forward", 0,
+-								 this, SLOT (slotSendAuth ()), actionAuthorization, "actionSendAuth"));
+-	actionAuthorization->insert (new KAction (i18n ("(Re)request Authorization From"), "mail_reply", 0,
+-								 this, SLOT (slotRequestAuth ()), actionAuthorization, "actionRequestAuth"));
+-	actionAuthorization->insert (new KAction (i18n ("Remove Authorization From"), "mail_delete", 0,
+-								 this, SLOT (slotRemoveAuth ()), actionAuthorization, "actionRemoveAuth"));
++	KAction *resendAuthAction, *requestAuthAction, *removeAuthAction;
++	
++	resendAuthAction = new KAction (i18n ("(Re)send Authorization To"), "mail_forward", 0,
++								 this, SLOT (slotSendAuth ()), actionAuthorization, "actionSendAuth");
++	resendAuthAction->setEnabled( mRosterItem.subscription().type() == XMPP::Subscription::To || mRosterItem.subscription().type() == XMPP::Subscription::None );
++	actionAuthorization->insert(resendAuthAction);
+ 
++	requestAuthAction = new KAction (i18n ("(Re)request Authorization From"), "mail_reply", 0,
++								 this, SLOT (slotRequestAuth ()), actionAuthorization, "actionRequestAuth");
++	requestAuthAction->setEnabled( mRosterItem.subscription().type() == XMPP::Subscription::From || mRosterItem.subscription().type() == XMPP::Subscription::None );
++	actionAuthorization->insert(requestAuthAction);
++	
++	removeAuthAction = new KAction (i18n ("Remove Authorization From"), "mail_delete", 0,
++								 this, SLOT (slotRemoveAuth ()), actionAuthorization, "actionRemoveAuth");
++	removeAuthAction->setEnabled( mRosterItem.subscription().type() == XMPP::Subscription::Both || mRosterItem.subscription().type() == XMPP::Subscription::From );
++	actionAuthorization->insert(removeAuthAction);
++
+ 	KActionMenu *actionSetAvailability = new KActionMenu (i18n ("Set Availability"), "kopeteavailable", this, "jabber_online");
+ 
+ 	actionSetAvailability->insert(new KAction (i18n ("Online"), protocol()->JabberKOSOnline.iconFor(this),
+@@ -197,9 +227,23 @@
+ 	actionCollection->append( actionAuthorization );
+ 	actionCollection->append( actionSetAvailability );
+ 	actionCollection->append( actionSelectResource );
++	
++	
++#ifdef SUPPORT_JINGLE
++	KAction *actionVoiceCall = new KAction (i18n ("Voice call"), "voicecall", 0, this, SLOT (voiceCall ()), this, "jabber_voicecall");
++	actionVoiceCall->setEnabled( false );
+ 
++	actionCollection->append( actionVoiceCall );
++
++	// Check if the current contact support Voice calls, also honour lock by default.
++	JabberResource *bestResource = account()->resourcePool()->bestJabberResource( mRosterItem.jid() );
++	if( bestResource && bestResource->features().canVoice() )
++	{
++		actionVoiceCall->setEnabled( true );
++	}
++#endif
++	
+ 	return actionCollection;
+-
+ }
+ 
+ void JabberContact::handleIncomingMessage (const XMPP::Message & message)
+@@ -215,7 +259,27 @@
+ 	// evaluate notifications
+ 	if ( message.type () != "error" )
+ 	{
+-		if (message.body().isEmpty())
++		if (!message.invite().isEmpty())
++		{
++			QString room=message.invite();
++			QString originalBody=message.body().isEmpty() ? QString() :
++					i18n( "The original message is : <i>\" %1 \"</i><br>" ).arg(QStyleSheet::escape(message.body()));
++			QString mes=i18n("<qt><i>%1</i> invited you to join the conference <b>%2</b><br>%3<br>"
++					"If you want to accept and join, just <b>enter your nickname</b> and press ok<br>"
++							 "If you want to decline, press cancel</qt>")
++					.arg(message.from().full(), room , originalBody);
++			
++			bool ok=false;
++			QString futureNewNickName = KInputDialog::getText( i18n( "Invited to a conference - Jabber Plugin" ),
++					mes, QString() , &ok , (mManager ? dynamic_cast<QWidget*>(mManager->view(false)) : 0) );
++			if ( !ok || !account()->isConnected() || futureNewNickName.isEmpty() )
++				return;
++			
++			XMPP::Jid roomjid(room);
++			account()->client()->joinGroupChat( roomjid.host() , roomjid.user() , futureNewNickName );
++			return;
++		}
++		else if (message.body().isEmpty())
+ 		// Then here could be event notifications
+ 		{
+ 			if (message.containsEvent ( XMPP::CancelEvent ) )
+@@ -230,14 +294,26 @@
+ 			{
+ 	        	mManager->receivedEventNotification( i18n("Message stored on the server, contact offline") );
+ 			}
++			else if (message.containsEvent ( XMPP::GoneEvent ) )
++			{
++				if(mManager->view( Kopete::Contact::CannotCreate ))
++				{   //show an internal message if the user has not already closed his window
++					Kopete::Message m=Kopete::Message ( this, mManager->members(),
++						i18n("%1 has ended their participation in the chat session.").arg(metaContact()->displayName()),
++						Kopete::Message::Internal  );
++					m.setImportance(Kopete::Message::Low);
++					mManager->view()->appendMessage ( m ); //use KopeteView::AppendMessage to bypass notifications
++				}
++			}
+ 		}
+ 		else
+ 		// Then here could be event notification requests
+ 		{
+-			mRequestComposingEvent = message.containsEvent ( XMPP::ComposingEvent ) ? true : false;
+-			mRequestOfflineEvent = message.containsEvent ( XMPP::OfflineEvent ) ? true : false;
+-			mRequestDeliveredEvent = message.containsEvent ( XMPP::DeliveredEvent ) ? true : false;
+-			mRequestDisplayedEvent = message.containsEvent ( XMPP::DisplayedEvent) ? true : false;
++			mRequestComposingEvent = message.containsEvent ( XMPP::ComposingEvent );
++			mRequestOfflineEvent = message.containsEvent ( XMPP::OfflineEvent );
++			mRequestDeliveredEvent = message.containsEvent ( XMPP::DeliveredEvent );
++			mRequestDisplayedEvent = message.containsEvent ( XMPP::DisplayedEvent);
++			mRequestGoneEvent= message.containsEvent ( XMPP::GoneEvent);
+ 		}
+ 	}
+ 
+@@ -245,7 +321,7 @@
+ 	 * Don't display empty messages, these were most likely just carrying
+ 	 * event notifications or other payload.
+ 	 */
+-	if ( message.body().isEmpty () && message.urlList().isEmpty () )
++	if ( message.body().isEmpty () && message.urlList().isEmpty () && message.xHTMLBody().isEmpty() && !message.xencrypted() )
+ 		return;
+ 
+ 	// determine message type
+@@ -272,15 +348,26 @@
+ 
+ 		// retrieve and reformat body
+ 		QString body = message.body ();
+-
++		QString xHTMLBody;
+ 		if( !message.xencrypted().isEmpty () )
+ 		{
+ 			body = QString ("-----BEGIN PGP MESSAGE-----\n\n") + message.xencrypted () + QString ("\n-----END PGP MESSAGE-----\n");
+ 		}
++		else
++		{
++			xHTMLBody = message.xHTMLBody ();
++		}
+ 
+ 		// convert XMPP::Message into Kopete::Message
+-		if ( !message.body().isEmpty () )
++		if (!xHTMLBody.isEmpty()) {
++			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Received a xHTML message" << endl;
++			newMessage = new Kopete::Message ( message.timeStamp (), this, contactList, xHTMLBody,
++											 message.subject (), Kopete::Message::Inbound,
++											 Kopete::Message::RichText, viewPlugin );
++		}
++		else if ( !body.isEmpty () )
+ 		{
++			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Received a plain text message" << endl;
+ 			newMessage = new Kopete::Message ( message.timeStamp (), this, contactList, body,
+ 											 message.subject (), Kopete::Message::Inbound,
+ 											 Kopete::Message::PlainText, viewPlugin );
+@@ -332,7 +419,25 @@
+ 	{
+ 		return;
+ 	}
++	
++	if(!mDiscoDone)
++	{
++		if(transport()) //no need to disco if this is a legacy contact
++			mDiscoDone = true;
++		else if(!rosterItem().jid().node().isEmpty())
++			mDiscoDone = true; //contact with an @ are not transport for sure
++		else
++		{
++			mDiscoDone = true; //or it will happen twice, we don't want that.
++			//disco to see if it's not a transport
++			XMPP::JT_DiscoInfo *jt = new XMPP::JT_DiscoInfo(account()->client()->rootTask());
++			QObject::connect(jt, SIGNAL(finished()),this, SLOT(slotDiscoFinished()));
++			jt->get(rosterItem().jid(), QString());
++			jt->go(true);
++		}
++	}
+ 
++
+ 	// avoid warning if key does not exist in configuration file
+ 	if ( cacheDateString.isNull () )
+ 		cacheDate = QDateTime::currentDateTime().addDays ( -2 );
+@@ -355,7 +460,6 @@
+ 
+ void JabberContact::slotGetTimedVCard ()
+ {
+-
+ 	mVCardUpdateInProgress = false;
+ 
+ 	// check if we are still connected - eventually we lost our connection in the meantime
+@@ -364,6 +468,22 @@
+ 		// we are not connected, discard this update
+ 		return;
+ 	}
++	
++	if(!mDiscoDone)
++	{
++		if(transport()) //no need to disco if this is a legacy contact
++			mDiscoDone = true;
++		else if(!rosterItem().jid().node().isEmpty())
++			mDiscoDone = true; //contact with an @ are not transport for sure
++		else
++		{
++			//disco to see if it's not a transport
++			XMPP::JT_DiscoInfo *jt = new XMPP::JT_DiscoInfo(account()->client()->rootTask());
++			QObject::connect(jt, SIGNAL(finished()),this, SLOT(slotDiscoFinished()));
++			jt->get(rosterItem().jid(), QString());
++			jt->go(true);
++		}
++	}
+ 
+ 	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Requesting vCard for " << contactId () << " from update timer." << endl;
+ 
+@@ -480,216 +600,6 @@
+ 
+ }
+ 
+-void JabberContact::setPropertiesFromVCard ( const XMPP::VCard &vCard )
+-{
+-	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Updating vCard for " << contactId () << endl;
+-
+-	// update vCard cache timestamp if this is not a temporary contact
+-	if ( metaContact() && !metaContact()->isTemporary () )
+-	{
+-		setProperty ( protocol()->propVCardCacheTimeStamp, QDateTime::currentDateTime().toString ( Qt::ISODate ) );
+-	}
+-
+-	/*
+-	 * Set the nickname property.
+-	 */
+-	if ( !vCard.nickName().isEmpty () )
+-	{
+-		setProperty ( protocol()->propNickName, vCard.nickName () );
+-	}
+-	else
+-	{
+-		removeProperty ( protocol()->propNickName );
+-	}
+-
+-	/**
+-	 * Kopete does not allow a modification of the "full name"
+-	 * property. However, some vCards specify only the full name,
+-	 * some specify only first and last name.
+-	 * Due to these inconsistencies, if first and last name don't
+-	 * exist, it is attempted to parse the full name.
+-	 */
+-
+-	// remove all properties first
+-	removeProperty ( protocol()->propFirstName );
+-	removeProperty ( protocol()->propLastName );
+-
+-	if ( !vCard.fullName().isEmpty () && vCard.givenName().isEmpty () && vCard.familyName().isEmpty () )
+-	{
+-		QString lastName = vCard.fullName().section ( ' ', 0, -1 );
+-		QString firstName = vCard.fullName().left(vCard.fullName().length () - lastName.length ()).stripWhiteSpace ();
+-
+-		setProperty ( protocol()->propFirstName, firstName );
+-		setProperty ( protocol()->propLastName, lastName );
+-	}
+-	else
+-	{
+-		if ( !vCard.givenName().isEmpty () )
+-			setProperty ( protocol()->propFirstName, vCard.givenName () );
+-
+-		if ( !vCard.familyName().isEmpty () )
+-			setProperty ( protocol()->propLastName, vCard.familyName () );
+-	}
+-
+-	/* 
+-	 * Set the general information 
+-	 */
+-	removeProperty( protocol()->propJid );
+-	removeProperty( protocol()->propBirthday );
+-	removeProperty( protocol()->propTimezone );
+-	removeProperty( protocol()->propHomepage );
+-
+-	setProperty( protocol()->propJid, vCard.jid() );
+-	
+-	if( !vCard.bdayStr().isEmpty () )
+-		setProperty( protocol()->propBirthday, vCard.bdayStr() );
+-	if( !vCard.timezone().isEmpty () )
+-		setProperty( protocol()->propTimezone, vCard.timezone() );
+-	if( !vCard.url().isEmpty () )
+-		setProperty( protocol()->propHomepage, vCard.url() );
+-
+-	/*
+-	 * Set the work information.
+-	 */
+-	removeProperty( protocol()->propCompanyName );
+-	removeProperty( protocol()->propCompanyDepartement );
+-	removeProperty( protocol()->propCompanyPosition );
+-	removeProperty( protocol()->propCompanyRole );
+-	
+-	if( !vCard.org().name.isEmpty() )
+-		setProperty( protocol()->propCompanyName, vCard.org().name );
+-	if( !vCard.org().unit.join(",").isEmpty() )
+-		setProperty( protocol()->propCompanyDepartement, vCard.org().unit.join(",")) ;
+-	if( !vCard.title().isEmpty() )
+-		setProperty( protocol()->propCompanyPosition, vCard.title() );
+-	if( !vCard.role().isEmpty() )
+-		setProperty( protocol()->propCompanyRole, vCard.role() );
+-
+-	/*
+-	 * Set the about information
+-	 */
+-	removeProperty( protocol()->propAbout );
+-
+-	if( !vCard.desc().isEmpty() )
+-		setProperty( protocol()->propAbout, vCard.desc() );
+-
+-	
+-	/*
+-	 * Set the work and home addresses information
+-	 */
+-	removeProperty( protocol()->propWorkStreet );
+-	removeProperty( protocol()->propWorkExtAddr );
+-	removeProperty( protocol()->propWorkPOBox );
+-	removeProperty( protocol()->propWorkCity );
+-	removeProperty( protocol()->propWorkPostalCode );
+-	removeProperty( protocol()->propWorkCountry );
+-
+-	removeProperty( protocol()->propHomeStreet );
+-	removeProperty( protocol()->propHomeExtAddr );
+-	removeProperty( protocol()->propHomePOBox );
+-	removeProperty( protocol()->propHomeCity );
+-	removeProperty( protocol()->propHomePostalCode );
+-	removeProperty( protocol()->propHomeCountry );
+-
+-	for(XMPP::VCard::AddressList::const_iterator it = vCard.addressList().begin(); it != vCard.addressList().end(); it++)
+-	{
+-		XMPP::VCard::Address address = (*it);
+-
+-		if(address.work)
+-		{
+-			setProperty( protocol()->propWorkStreet, address.street );
+-			setProperty( protocol()->propWorkExtAddr, address.extaddr );
+-			setProperty( protocol()->propWorkPOBox, address.pobox );
+-			setProperty( protocol()->propWorkCity, address.locality );
+-			setProperty( protocol()->propWorkPostalCode, address.pcode );
+-			setProperty( protocol()->propWorkCountry, address.country );
+-		}
+-		else
+-		if(address.home)
+-		{
+-			setProperty( protocol()->propHomeStreet, address.street );
+-			setProperty( protocol()->propHomeExtAddr, address.extaddr );
+-			setProperty( protocol()->propHomePOBox, address.pobox );
+-			setProperty( protocol()->propHomeCity, address.locality );
+-			setProperty( protocol()->propHomePostalCode, address.pcode );
+-			setProperty( protocol()->propHomeCountry, address.country );
+-		}
+-	}
+-
+-
+-	/*
+-	 * Delete emails first, they might not be present
+-	 * in the vCard at all anymore.
+-	 */
+-	removeProperty ( protocol()->propEmailAddress );
+-	removeProperty ( protocol()->propWorkEmailAddress );
+-
+-	/*
+-	 * Set the home and work email information.
+-	 */
+-	XMPP::VCard::EmailList::const_iterator emailEnd = vCard.emailList().end ();
+-	for(XMPP::VCard::EmailList::const_iterator it = vCard.emailList().begin(); it != emailEnd; ++it)
+-	{
+-		XMPP::VCard::Email email = (*it);
+-		
+-		if(email.work)
+-		{
+-			if( !email.userid.isEmpty() )
+-				setProperty ( protocol()->propWorkEmailAddress, email.userid );
+-		}
+-		else
+-		if(email.home)
+-		{	
+-			if( !email.userid.isEmpty() )
+-				setProperty ( protocol()->propEmailAddress, email.userid );
+-		}
+-	}
+-
+-	/*
+-	 * Delete phone number properties first as they might have
+-	 * been unset during an update and are not present in
+-	 * the vCard at all anymore.
+-	 */
+-	removeProperty ( protocol()->propPrivatePhone );
+-	removeProperty ( protocol()->propPrivateMobilePhone );
+-	removeProperty ( protocol()->propWorkPhone );
+-	removeProperty ( protocol()->propWorkMobilePhone );
+-
+-	/*
+-	 * Set phone numbers. Note that if a mobile phone number
+-	 * is specified, it's assigned to the private mobile
+-	 * phone number property. This might not be the desired
+-	 * behavior for all users.
+-	 */
+-	XMPP::VCard::PhoneList::const_iterator phoneEnd = vCard.phoneList().end ();
+-	for(XMPP::VCard::PhoneList::const_iterator it = vCard.phoneList().begin(); it != phoneEnd; ++it)
+-	{
+-		XMPP::VCard::Phone phone = (*it);
+-
+-		if(phone.work)
+-		{
+-			setProperty ( protocol()->propWorkPhone, phone.number );
+-		}
+-		else
+-		if(phone.fax)
+-		{
+-			setProperty ( protocol()->propPhoneFax, phone.number);
+-		}
+-		else
+-		if(phone.cell)
+-		{
+-			setProperty ( protocol()->propPrivateMobilePhone, phone.number );
+-		}
+-		else
+-		if(phone.home)
+-		{
+-			setProperty ( protocol()->propPrivatePhone, phone.number );
+-		}
+-
+-	}
+-
+-}
+-
+ void JabberContact::slotSendVCard()
+ {
+ 	XMPP::VCard vCard;
+@@ -790,6 +700,18 @@
+ 	// about tab
+ 	vCard.setDesc(property(protocol()->propAbout).value().toString());
+ 
++	// Set contact photo as a binary value (if he has set a photo)
++	if( hasProperty( protocol()->propPhoto.key() ) )
++	{
++		QString photoPath = property( protocol()->propPhoto ).value().toString();
++		QImage image( photoPath );
++		QByteArray ba;
++		QBuffer buffer( ba );
++		buffer.open( IO_WriteOnly );
++		image.save( &buffer, "PNG" );
++		vCard.setPhoto( ba );
++	}
++
+ 	vCard.setVersion("3.0");
+ 	vCard.setProdId("Kopete");
+ 
+@@ -800,19 +722,73 @@
+ 	task->go (true);
+ }
+ 
+-void JabberContact::slotSentVCard ()
++void JabberContact::setPhoto( const QString &photoPath )
+ {
+-	XMPP::JT_VCard * vCard = (XMPP::JT_VCard *) sender ();
++	QImage contactPhoto(photoPath);
++	QString newPhotoPath = photoPath;
++	if(contactPhoto.width() > 96 || contactPhoto.height() > 96)
++	{
++		// Save image to a new location if the image isn't the correct format.
++		QString newLocation( locateLocal( "appdata", "jabberphotos/"+ KURL(photoPath).fileName().lower() ) );
+ 	
+-	if (!vCard->success())
++		// Scale and crop the picture.
++		contactPhoto = contactPhoto.smoothScale( 96, 96, QImage::ScaleMin );
++		// crop image if not square
++		if(contactPhoto.width() < contactPhoto.height()) 
++			contactPhoto = contactPhoto.copy((contactPhoto.width()-contactPhoto.height())/2, 0, 96, 96);
++		else if (contactPhoto.width() > contactPhoto.height())
++			contactPhoto = contactPhoto.copy(0, (contactPhoto.height()-contactPhoto.width())/2, 96, 96);
++	
++		// Use the cropped/scaled image now.
++		if(!contactPhoto.save(newLocation, "PNG"))
++			newPhotoPath = QString::null;
++		else
++			newPhotoPath = newLocation;
++	}
++	else if (contactPhoto.width() < 32 || contactPhoto.height() < 32)
+ 	{
+-		// unsuccessful, or incomplete
+-		KMessageBox::error (Kopete::UI::Global::mainWidget (), i18n("Unable to store vCard for %1").arg (vCard->jid ().userHost ()));
+-		return;
++		// Save image to a new location if the image isn't the correct format.
++		QString newLocation( locateLocal( "appdata", "jabberphotos/"+ KURL(photoPath).fileName().lower() ) );
++	
++		// Scale and crop the picture.
++		contactPhoto = contactPhoto.smoothScale( 32, 32, QImage::ScaleMin );
++		// crop image if not square
++		if(contactPhoto.width() < contactPhoto.height())
++			contactPhoto = contactPhoto.copy((contactPhoto.width()-contactPhoto.height())/2, 0, 32, 32);
++		else if (contactPhoto.width() > contactPhoto.height())
++			contactPhoto = contactPhoto.copy(0, (contactPhoto.height()-contactPhoto.width())/2, 32, 32);
++	
++		// Use the cropped/scaled image now.
++		if(!contactPhoto.save(newLocation, "PNG"))
++			newPhotoPath = QString::null;
++		else
++			newPhotoPath = newLocation;
+ 	}
++	else if (contactPhoto.width() != contactPhoto.height())
++	{
++		// Save image to a new location if the image isn't the correct format.
++		QString newLocation( locateLocal( "appdata", "jabberphotos/"+ KURL(photoPath).fileName().lower() ) );
+ 
++		if(contactPhoto.width() < contactPhoto.height())
++			contactPhoto = contactPhoto.copy((contactPhoto.width()-contactPhoto.height())/2, 0, contactPhoto.height(), contactPhoto.height());
++		else if (contactPhoto.width() > contactPhoto.height())
++			contactPhoto = contactPhoto.copy(0, (contactPhoto.height()-contactPhoto.width())/2, contactPhoto.height(), contactPhoto.height());
++
++		// Use the cropped/scaled image now.
++		if(!contactPhoto.save(newLocation, "PNG"))
++			newPhotoPath = QString::null;
++		else
++			newPhotoPath = newLocation;
++	}
++
++	setProperty( protocol()->propPhoto, newPhotoPath );
+ }
+ 
++void JabberContact::slotSentVCard ()
++{
++	
++}
++
+ void JabberContact::slotChatSessionDeleted ( QObject *sender )
+ {
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Message manager deleted, collecting the pieces..." << endl;
+@@ -836,7 +812,7 @@
+ 	 */
+ 	if ( !manager &&  canCreate )
+ 	{
+-		XMPP::Jid jid ( contactId () );
++		XMPP::Jid jid = rosterItem().jid();
+ 
+ 		/*
+ 		 * If we have no hardwired JID, set any eventually
+@@ -928,20 +904,44 @@
+ 		account()->errorConnectFirst ();
+ 		return;
+ 	}
++	
++	/*
++	* Follow the recommendation of
++	*  JEP-0162: Best Practices for Roster and Subscription Management
++	* http://www.jabber.org/jeps/jep-0162.html#removal
++	*/
+ 
+-	if ( KMessageBox::questionYesNo (Kopete::UI::Global::mainWidget(),
+-		 i18n ( "Do you also want to remove the authorization from user %1 to see your status?" ).
+-				arg ( mRosterItem.jid().bare () ), i18n ("Notification"),
+-				KStdGuiItem::del (), i18n("Keep"), "JabberRemoveAuthorizationOnDelete" ) == KMessageBox::Yes )
++	bool remove_from_roster=false;
++	
++	if( mRosterItem.subscription().type() == XMPP::Subscription::Both || mRosterItem.subscription().type() == XMPP::Subscription::From )
+ 	{
+-		sendSubscription ("unsubscribed");
++		int result = KMessageBox::questionYesNoCancel (Kopete::UI::Global::mainWidget(),
++		 				i18n ( "Do you also want to remove the authorization from user %1 to see your status?" ).
++						arg ( mRosterItem.jid().bare () ), i18n ("Notification"),
++						KStdGuiItem::del (), i18n("Keep"), "JabberRemoveAuthorizationOnDelete" );
++		if(result == KMessageBox::Yes )
++			remove_from_roster = true;
++		else if( result == KMessageBox::Cancel)
++			return;
+ 	}
++	else if( mRosterItem.subscription().type() == XMPP::Subscription::None || mRosterItem.subscription().type() == XMPP::Subscription::To )
++		remove_from_roster = true;
++	
++	if( remove_from_roster )
++	{
++		XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( account()->client()->rootTask () );
++		rosterTask->remove ( mRosterItem.jid () );
++		rosterTask->go ( true );
++	}
++	else
++	{
++		sendSubscription("unsubscribe");
+ 
+-	XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( account()->client()->rootTask () );
++		XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( account()->client()->rootTask () );
++		rosterTask->set ( mRosterItem.jid (), QString() , QStringList() );
++		rosterTask->go (true);
++	}
+ 
+-	rosterTask->remove ( mRosterItem.jid () );
+-	rosterTask->go ( true );
+-
+ }
+ 
+ void JabberContact::sync ( unsigned int )
+@@ -950,7 +950,7 @@
+ 	if ( dontSync () || !account()->isConnected () || metaContact()->isTemporary () || metaContact() == Kopete::ContactList::self()->myself() )
+ 		return;
+ 	
+-//	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << contactId () << " - " <<kdBacktrace() << endl;
++	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << contactId () /*<< " - " <<kdBacktrace()*/ << endl;
+ 
+ 	if(!m_syncTimer);
+ 	{
+@@ -1029,24 +1029,7 @@
+ 
+ }
+ 
+-void JabberContact::slotUserInfo ()
+-{
+ 
+-	if ( !account()->isConnected () )
+-	{
+-		account()->errorConnectFirst ();
+-		return;
+-	}
+-	
+-	// Update the vCard
+-	slotGetTimedVCard();
+-
+-	dlgJabberVCard *dlgVCard = new dlgJabberVCard ( account(), this, Kopete::UI::Global::mainWidget () );
+-	
+-	connect(dlgVCard, SIGNAL(informationChanged()), this, SLOT(slotSendVCard()));
+-
+-}
+-
+ void JabberContact::slotSendAuth ()
+ {
+ 
+@@ -1114,7 +1097,7 @@
+ 	{
+ 		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing active resource, trusting bestResource()." << endl;
+ 
+-		account()->resourcePool()->removeLock ( XMPP::Jid ( contactId () ) );
++		account()->resourcePool()->removeLock ( rosterItem().jid() );
+ 	}
+ 	else
+ 	{
+@@ -1122,7 +1105,7 @@
+ 
+ 		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Moving to resource " << selectedResource << endl;
+ 
+-		account()->resourcePool()->lockToResource ( XMPP::Jid ( contactId () ), XMPP::Resource ( selectedResource ) );
++		account()->resourcePool()->lockToResource ( rosterItem().jid() , XMPP::Resource ( selectedResource ) );
+ 	}
+ 
+ }
+@@ -1139,7 +1122,8 @@
+ 	XMPP::Status newStatus = status;
+ 
+ 	// honour our priority
+-	newStatus.setPriority ( account()->configGroup()->readNumEntry ( "Priority", 5 ) );
++	if(newStatus.isAvailable())
++		newStatus.setPriority ( account()->configGroup()->readNumEntry ( "Priority", 5 ) );
+ 
+ 	XMPP::JT_Presence * task = new XMPP::JT_Presence ( account()->client()->rootTask () );
+ 
+@@ -1204,8 +1188,7 @@
+ {
+ 
+ 	XMPP::Status status;
+-	status.setShow ("away");
+-	status.setIsInvisible ( true );
++	status.setIsAvailable( false );
+ 
+ 	sendPresence ( status );
+ 
+@@ -1223,6 +1206,8 @@
+ 		return mRequestComposingEvent;
+ 	else if ( event == CancelEvent )
+ 		return mRequestComposingEvent;
++	else if ( event == GoneEvent )
++		return mRequestGoneEvent;
+ 	else
+ 		return false;
+ }
+@@ -1232,7 +1217,112 @@
+ 	return mLastReceivedMessageId;
+ }
+ 
++void JabberContact::voiceCall( )
++{
++#ifdef SUPPORT_JINGLE
++	Jid jid = mRosterItem.jid();
++	
++	// It's honour lock by default.
++	JabberResource *bestResource = account()->resourcePool()->bestJabberResource( jid );
++	if( bestResource )
++	{
++		if( jid.resource().isEmpty() )
++		{
++			// If the jid resource is empty, get the JID from best resource for this contact.
++			jid = bestResource->jid();
++		}
++	
++		// Check if the voice caller exist and the current resource support voice.
++		if( account()->voiceCaller() && bestResource->features().canVoice() )
++		{
++			JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog( jid, account()->voiceCaller() );
++			voiceDialog->show();
++			voiceDialog->start();
++		}
++#if 0
++		if( account()->sessionManager() && bestResource->features().canVoice() )
++		{
++			JingleVoiceSession *session = static_cast<JingleVoiceSession*>(account()->sessionManager()->createSession("http://www.google.com/session/phone", jid));
+ 
++			JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog(session);
++			voiceDialog->show();
++			voiceDialog->start();
++		}
++#endif
++	}
++	else
++	{
++		// Shouldn't never go there.
++	}
++#endif
++}
+ 
++void JabberContact::slotDiscoFinished( )
++{
++	mDiscoDone = true;
++	JT_DiscoInfo *jt = (JT_DiscoInfo *)sender();
++	
++	bool is_transport=false;
++	QString tr_type;
+ 
++	if ( jt->success() )
++ 	{
++		QValueList<XMPP::DiscoItem::Identity> identities = jt->item().identities();
++		QValueList<XMPP::DiscoItem::Identity>::Iterator it;
++		for ( it = identities.begin(); it != identities.end(); ++it )
++		{
++			XMPP::DiscoItem::Identity ident=*it;
++			if(ident.category == "gateway")
++			{
++				is_transport=true;
++				tr_type=ident.type;
++				//name=ident.name;
++				
++				break;  //(we currently only support gateway)
++			}
++			else if (ident.category == "service")
++			{
++				//The ApaSMSAgent is reporting itself as service (instead of gateway) which is broken.
++				//we anyway support it.  See bug  127811
++				if(ident.type == "sms")
++				{
++					is_transport=true;
++					tr_type=ident.type;
++				}
++			}
++		}
++ 	}
++
++	if(is_transport && !transport()) 
++ 	{   //ok, we are not a contact, we are a transport....
++		
++		XMPP::RosterItem ri = rosterItem();
++		Kopete::MetaContact *mc=metaContact();
++		JabberAccount *parentAccount=account();
++		Kopete::OnlineStatus status=onlineStatus();
++		
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << ri.jid().full() << " is not a contact but a gateway   - " << this << endl;
++		
++		if( Kopete::AccountManager::self()->findAccount( protocol()->pluginId() , account()->accountId() + "/" + ri.jid().bare() ) )
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "oops, transport already exists, abort operation " <<  endl;
++			return;
++		}
++		
++		delete this; //we are not a contact i said !
++		
++		if(mc->contacts().count() == 0)
++			Kopete::ContactList::self()->removeMetaContact( mc );
++		
++		//we need to create the transport when 'this' is already deleted, so transport->myself() will not conflict with it
++		JabberTransport *transport = new JabberTransport( parentAccount , ri , tr_type );
++		if(!Kopete::AccountManager::self()->registerAccount( transport ))
++			return;
++		transport->myself()->setOnlineStatus( status ); //push back the online status
++		return;
++	}
++}
++
++
++
+ #include "jabbercontact.moc"
+--- kopete/protocols/jabber/jabberbasecontact.h	(revision 568672)
++++ kopete/protocols/jabber/jabberbasecontact.h	(revision 586398)
+@@ -27,7 +27,9 @@
+ class JabberProtocol;
+ class JabberAccount;
+ class JabberResource;
++class JabberTransport;
+ namespace Kopete { class MetaContact; }
++namespace XMPP { class VCard; }
+ 
+ class JabberBaseContact : public Kopete::Contact
+ {
+@@ -37,8 +39,12 @@
+ 
+ public:
+ 
++	/**
++	 * @param legacyId is the contactId of the contact if != Jid
++	 */
+ 	JabberBaseContact (const XMPP::RosterItem &rosterItem,
+-				   JabberAccount *account, Kopete::MetaContact * mc);
++					   Kopete::Account *account, Kopete::MetaContact * mc, 
++					   const QString &legacyId=QString());
+ 
+ 	/********************************************************************
+ 	 *
+@@ -54,9 +60,14 @@
+ 	/**
+ 	 * Return the account instance associated with this contact
+ 	 */
+-	JabberAccount *account ();
+-
++	JabberAccount *account () const { return m_account; };
++	
+ 	/**
++	 * return the transport if any, or null
++	 */
++	JabberTransport *transport();
++			
++	/**
+ 	 * Return if the contact is reachable (this is true if the account
+ 	 * is online)
+ 	 */
+@@ -91,13 +102,6 @@
+ 	void updateResourceList ();
+ 
+ 	/**
+-	 * Re-evaluate online status. Gets called
+-	 * whenever a resource is added, removed, or
+-	 * changed in the resource pool.
+-	 */
+-	void reevaluateStatus ();
+-
+-	/**
+ 	 * Return current full address.
+ 	 * Uses bestResource() if no presubscribed
+ 	 * address exists.
+@@ -126,13 +130,34 @@
+ 	 * See @ref setDontSync for a full description.
+ 	 */
+ 	bool dontSync ();
++	
++	/**
++	 * return the roster item of the contact.
++	 * to get the jid, use  rosterItem().jid().full()  don't use contactId as it is not the same with transport
++	 */
++	XMPP::RosterItem rosterItem() const { return mRosterItem; }
++	
++	/**
++	 * Reads a vCard object and updates the contact's
++	 * properties accordingly.
++	 */
++	void setPropertiesFromVCard ( const XMPP::VCard &vCard );
+ 
++
+ public slots:
+ 
+ 	/**
+ 	 * Retrieve a vCard for the contact
+ 	 */
+-	virtual void slotUserInfo () = 0;
++	virtual void slotUserInfo ();
++	
++	
++	/**
++	 * Re-evaluate online status. Gets called
++	 * whenever a resource is added, removed, or
++	 * changed in the resource pool.
++	 */
++	void reevaluateStatus ();
+ 
+ protected:
+ 	/**
+@@ -151,6 +176,7 @@
+ 
+ private:
+ 	bool mDontSync;
++	JabberAccount *m_account;
+ 
+ };
+ 
+--- kopete/protocols/jabber/jabbergroupchatmanager.h	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupchatmanager.h	(revision 586398)
+@@ -37,6 +37,8 @@
+ public:
+ 	JabberGroupChatManager ( JabberProtocol *protocol, const JabberBaseContact *user,
+ 							 Kopete::ContactPtrList others, XMPP::Jid roomJid, const char *name = 0 );
++	
++	~JabberGroupChatManager();
+ 
+ 	/**
+ 	 * @brief Get the local user in the session
+@@ -54,10 +56,18 @@
+ 	 * Re-generate the display name
+ 	 */
+ 	void updateDisplayName ();
++	
++	/**
++	 * reimplemented from Kopete::ChatSession
++	 * called when a contact is droped in the window
++	 */
++	virtual void inviteContact(const QString &contactId);
+ 
+ private slots:
+ 	void slotMessageSent ( Kopete::Message &message, Kopete::ChatSession *kmm );
++	
+ 
++
+ private:
+ 	XMPP::Jid mRoomJid;
+ };
+--- kopete/protocols/jabber/jabberaccount.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberaccount.cpp	(revision 586398)
+@@ -6,6 +6,7 @@
+     copyright            : (C) 2003 by Till Gerken <till at tantalo.net>
+ 							Based on JabberProtocol by Daniel Stone <dstone at kde.org>
+ 							and Till Gerken <till at tantalo.net>.
++	copyright            : (C) 2006 by Olivier Goffart <ogoffart at kde.org>
+ 
+ 			   Kopete (C) 2001-2003 Kopete developers
+ 			   <kopete-devel at kde.org>.
+@@ -28,6 +29,7 @@
+ #include "bsocket.h"
+ 
+ #include "jabberaccount.h"
++#include "jabberbookmarks.h"
+ 
+ #include <time.h>
+ 
+@@ -42,6 +44,8 @@
+ #include <kapplication.h>
+ #include <kaboutdata.h>
+ #include <ksocketbase.h>
++#include <kpassdlg.h>
++#include <kinputdialog.h>
+ 
+ #include "kopetepassword.h"
+ #include "kopeteawayaction.h"
+@@ -49,6 +53,9 @@
+ #include "kopeteuiglobal.h"
+ #include "kopetegroup.h"
+ #include "kopetecontactlist.h"
++#include "kopeteaccountmanager.h"
++#include "contactaddednotifydialog.h"
++
+ #include "jabberconnector.h"
+ #include "jabberclient.h"
+ #include "jabberprotocol.h"
+@@ -57,12 +64,29 @@
+ #include "jabberfiletransfer.h"
+ #include "jabbercontact.h"
+ #include "jabbergroupcontact.h"
++#include "jabbercapabilitiesmanager.h"
++#include "jabbertransport.h"
+ #include "dlgjabbersendraw.h"
+ #include "dlgjabberservices.h"
+ #include "dlgjabberchatjoin.h"
+ 
+ #include <sys/utsname.h>
+ 
++#ifdef SUPPORT_JINGLE
++#include "voicecaller.h"
++#include "jinglevoicecaller.h"
++
++// NOTE: Disabled for 0.12, will develop them futher in KDE4
++// #include "jinglesessionmanager.h"
++// #include "jinglesession.h"
++// #include "jinglevoicesession.h"
++#include "jinglevoicesessiondialog.h"
++#endif
++
++#define KOPETE_CAPS_NODE "http://kopete.kde.org/jabber/caps"
++
++
++
+ JabberAccount::JabberAccount (JabberProtocol * parent, const QString & accountId, const char *name)
+ 			  :Kopete::PasswordedAccount ( parent, accountId, 0, name )
+ {
+@@ -74,7 +98,13 @@
+ 
+ 	m_resourcePool = 0L;
+ 	m_contactPool = 0L;
+-
++#ifdef SUPPORT_JINGLE
++	m_voiceCaller = 0L;
++	//m_jingleSessionManager = 0L; // NOTE: Disabled for 0.12
++#endif
++	m_bookmarks = new JabberBookmarks(this);
++	m_removing=false;
++	m_notifiedUserCannotBindTransferPort = false;
+ 	// add our own contact to the pool
+ 	JabberContact *myContact = contactPool()->addContact ( XMPP::RosterItem ( accountId ), Kopete::ContactList::self()->myself(), false );
+ 	setMyself( myContact );
+@@ -89,14 +119,22 @@
+ {
+ 	disconnect ( Kopete::Account::Manual );
+ 
++	// Remove this account from Capabilities manager.
++	protocol()->capabilitiesManager()->removeAccount( this );
++
+ 	cleanup ();
++	
++	QMap<QString,JabberTransport*> tranposrts_copy=m_transports;
++	QMap<QString,JabberTransport*>::Iterator it;
++	for ( it = tranposrts_copy.begin(); it != tranposrts_copy.end(); ++it ) 
++		delete it.data();
+ }
+ 
+ void JabberAccount::cleanup ()
+ {
+ 
+ 	delete m_jabberClient;
+-
++	
+ 	m_jabberClient = 0L;
+ 
+ 	delete m_resourcePool;
+@@ -104,7 +142,14 @@
+ 
+ 	delete m_contactPool;
+ 	m_contactPool = 0L;
++	
++#ifdef SUPPORT_JINGLE
++	delete m_voiceCaller;
++	m_voiceCaller = 0L;
+ 
++// 	delete m_jingleSessionManager;
++// 	m_jingleSessionManager = 0L;
++#endif
+ }
+ 
+ void JabberAccount::setS5BServerPort ( int port )
+@@ -115,11 +160,12 @@
+ 		return;
+ 	}
+ 
+-	if ( !m_jabberClient->setS5BServerPort ( port ) )
++	if ( !m_jabberClient->setS5BServerPort ( port ) && !m_notifiedUserCannotBindTransferPort)
+ 	{
+-		KMessageBox::sorry ( Kopete::UI::Global::mainWidget (),
++		KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (), KMessageBox::Sorry,
+ 							 i18n ( "Could not bind Jabber file transfer manager to local port. Please check if the file transfer port is already in use or choose another port in the account settings." ),
+ 							 i18n ( "Failed to start Jabber File Transfer Manager" ) );
++		m_notifiedUserCannotBindTransferPort = true;
+ 	}
+ 
+ }
+@@ -130,19 +176,34 @@
+ 
+ 	m_actionMenu->popupMenu()->insertSeparator();
+ 
+-	m_actionMenu->insert(new KAction (i18n ("Join Groupchat..."), "jabber_group", 0,
+-		this, SLOT (slotJoinNewChat ()), this, "actionJoinChat"));
++	KAction *action;
++	
++	action = new KAction (i18n ("Join Groupchat..."), "jabber_group", 0, this, SLOT (slotJoinNewChat ()), this, "actionJoinChat");
++	m_actionMenu->insert(action);
++	action->setEnabled( isConnected() );
++	
++	action = m_bookmarks->bookmarksAction( m_bookmarks );
++	m_actionMenu->insert(action);
++	action->setEnabled( isConnected() );
+ 
++
+ 	m_actionMenu->popupMenu()->insertSeparator();
++	
++	action =  new KAction ( i18n ("Services..."), "jabber_serv_on", 0,
++							this, SLOT ( slotGetServices () ), this, "actionJabberServices");
++	action->setEnabled( isConnected() );
++	m_actionMenu->insert ( action );
+ 
+-	m_actionMenu->insert ( new KAction ( i18n ("Services..."), "jabber_serv_on", 0,
+-										 this, SLOT ( slotGetServices () ), this, "actionJabberServices") );
++	action = new KAction ( i18n ("Send Raw Packet to Server..."), "mail_new", 0,
++										 this, SLOT ( slotSendRaw () ), this, "actionJabberSendRaw") ;
++	action->setEnabled( isConnected() );
++	m_actionMenu->insert ( action );
+ 
+-	m_actionMenu->insert ( new KAction ( i18n ("Send Raw Packet to Server..."), "mail_new", 0,
+-										 this, SLOT ( slotSendRaw () ), this, "actionJabberSendRaw") );
++	action = new KAction ( i18n ("Edit User Info..."), "identity", 0,
++										 this, SLOT ( slotEditVCard () ), this, "actionEditVCard") ;
++	action->setEnabled( isConnected() );
++	m_actionMenu->insert ( action );
+ 
+-	m_actionMenu->insert ( new KAction ( i18n ("Edit User Info..."), "identity", 0,
+-										 this, SLOT ( slotEditVCard () ), this, "actionEditVCard") );
+ 
+ 	return m_actionMenu;
+ 
+@@ -201,27 +262,9 @@
+ 
+ void JabberAccount::errorConnectionLost ()
+ {
+-
+-	KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
+-									KMessageBox::Error,
+-									i18n ("Your connection to the server has been lost in the meantime. "
+-									"This means that your last action could not complete successfully. "
+-									"Please reconnect and try again."), i18n ("Jabber Error") );
+-
++	disconnected( Kopete::Account::ConnectionReset );
+ }
+ 
+-void JabberAccount::errorConnectionInProgress ()
+-{
+-
+-	KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
+-									KMessageBox::Information,
+-									i18n ("A connection attempt is already in progress. "
+-									"Please wait until the previous attempt finished or "
+-									"disconnect to start over."),
+-									i18n ("Connection Attempt Already in Progress") );
+-
+-}
+-
+ bool JabberAccount::isConnecting ()
+ {
+ 
+@@ -263,7 +306,7 @@
+ 		QObject::connect ( m_jabberClient, SIGNAL ( rosterRequestFinished ( bool ) ),
+ 				   this, SLOT ( slotRosterRequestFinished ( bool ) ) );
+ 		QObject::connect ( m_jabberClient, SIGNAL ( newContact ( const XMPP::RosterItem & ) ),
+-				   this, SLOT ( slotNewContact ( const XMPP::RosterItem & ) ) );
++				   this, SLOT ( slotContactUpdated ( const XMPP::RosterItem & ) ) );
+ 		QObject::connect ( m_jabberClient, SIGNAL ( contactUpdated ( const XMPP::RosterItem & ) ),
+ 				   this, SLOT ( slotContactUpdated ( const XMPP::RosterItem & ) ) );
+ 		QObject::connect ( m_jabberClient, SIGNAL ( contactDeleted ( const XMPP::RosterItem & ) ),
+@@ -322,7 +365,19 @@
+ 		m_jabberClient->setClientVersion (kapp->aboutData ()->version ());
+ 		m_jabberClient->setOSName (QString ("%1 %2").arg (utsBuf.sysname, 1).arg (utsBuf.release, 2));
+ 	}
++
++	// Set caps node information
++	m_jabberClient->setCapsNode(KOPETE_CAPS_NODE);
++	m_jabberClient->setCapsVersion(kapp->aboutData()->version());
+ 	
++	// Set Disco Identity information
++	DiscoItem::Identity identity;
++	identity.category = "client";
++	identity.type = "pc";
++	identity.name = "Kopete";
++	m_jabberClient->setDiscoIdentity(identity);
++
++	//BEGIN TIMEZONE INFORMATION
+ 	//
+ 	// Set timezone information (code from Psi)
+ 	// Copyright (C) 2001-2003  Justin Karneges
+@@ -351,7 +406,7 @@
+ 
+ 	if ( strcmp ( fmt, str ) )
+ 		timezoneString = str;
+-	// end of timezone code
++	//END of timezone code
+ 
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Determined timezone " << timezoneString << " with UTC offset " << timezoneOffset << " hours." << endl;
+ 
+@@ -374,6 +429,7 @@
+ 		case JabberClient::Ok:
+ 		default:
+ 			// everything alright!
++
+ 			break;
+ 	}
+ 
+@@ -482,7 +538,7 @@
+ 	{
+ 		case JabberClient::NoTLS:
+ 		default:
+-			KMessageBox::error ( Kopete::UI::Global::mainWidget (),
++			KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (), KMessageBox::Error,
+ 					     i18n ("An encrypted connection with the Jabber server could not be established."),
+ 					     i18n ("Jabber Connection Error"));
+ 			disconnect ( Kopete::Account::Manual );
+@@ -494,10 +550,33 @@
+ void JabberAccount::slotConnected ()
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Connected to Jabber server." << endl;
++	
++#ifdef SUPPORT_JINGLE
++	if(!m_voiceCaller)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Creating Jingle Voice caller..." << endl;
++		m_voiceCaller = new JingleVoiceCaller( this );
++		QObject::connect(m_voiceCaller,SIGNAL(incoming(const Jid&)),this,SLOT(slotIncomingVoiceCall( const Jid& )));
++		m_voiceCaller->initialize();
++	}
++	
+ 
++
++#if 0
++	if(!m_jingleSessionManager)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Creating Jingle Session Manager..." << endl;
++		m_jingleSessionManager = new JingleSessionManager( this );
++		QObject::connect(m_jingleSessionManager, SIGNAL(incomingSession(const QString &, JingleSession *)), this, SLOT(slotIncomingJingleSession(const QString &, JingleSession *)));
++	}
++#endif
++
++	// Set caps extensions
++	m_jabberClient->client()->addExtension("voice-v1", Features(QString("http://www.google.com/xmpp/protocol/voice/v1")));
++#endif
++
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Requesting roster..." << endl;
+ 	m_jabberClient->requestRoster ();
+-
+ }
+ 
+ void JabberAccount::slotRosterRequestFinished ( bool success )
+@@ -530,52 +609,27 @@
+ 
+ void JabberAccount::setOnlineStatus( const Kopete::OnlineStatus& status  , const QString &reason)
+ {
++	XMPP::Status xmppStatus = m_protocol->kosToStatus( status, reason);
++
+ 	if( status.status() == Kopete::OnlineStatus::Offline )
+ 	{
+-		disconnect( Kopete::Account::Manual );
+-		return;
+-	}
++			xmppStatus.setIsAvailable( false );
++			kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "CROSS YOUR FINGERS! THIS IS GONNA BE WILD" << endl;
++            disconnect (Manual, xmppStatus);
++            return;
++    }
+ 
+ 	if( isConnecting () )
+ 	{
+-		errorConnectionInProgress ();
+ 		return;
+ 	}
++	
+ 
+-	XMPP::Status xmppStatus ( "", reason );
+-
+-	switch ( status.internalStatus () )
+-	{
+-		case JabberProtocol::JabberFreeForChat:
+-			xmppStatus.setShow ( "chat" );
+-			break;
+-
+-		case JabberProtocol::JabberOnline:
+-			xmppStatus.setShow ( "" );
+-			break;
+-
+-		case JabberProtocol::JabberAway:
+-			xmppStatus.setShow ( "away" );
+-			break;
+-
+-		case JabberProtocol::JabberXA:
+-			xmppStatus.setShow ( "xa" );
+-			break;
+-
+-		case JabberProtocol::JabberDND:
+-			xmppStatus.setShow ( "dnd" );
+-			break;
+-
+-		case JabberProtocol::JabberInvisible:
+-			xmppStatus.setIsInvisible ( true );
+-			break;
+-	}
+-
+ 	if ( !isConnected () )
+ 	{
+ 		// we are not connected yet, so connect now
+ 		m_initialPresence = xmppStatus;
+-		connect ();
++		connect ( status );
+ 	}
+ 	else
+ 	{
+@@ -597,6 +651,7 @@
+ 	// make sure that the connection animation gets stopped if we're still
+ 	// in the process of connecting
+ 	setPresence ( XMPP::Status ("", "", 0, false) );
++	m_initialPresence = XMPP::Status ("", "", 5, true);
+ 
+ 	/* FIXME:
+ 	 * We should delete the JabberClient instance here,
+@@ -608,6 +663,34 @@
+ 	 */
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Disconnected." << endl;
+ 
++	disconnected ( reason );
++}
++
++void JabberAccount::disconnect( Kopete::Account::DisconnectReason reason, XMPP::Status &status )
++{
++    kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "disconnect( reason, status ) called" << endl;
++    
++	if (isConnected ())
++	{
++		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Still connected, closing connection..." << endl;
++		/* Tell backend class to disconnect. */
++		m_jabberClient->disconnect (status);
++	}
++
++	// make sure that the connection animation gets stopped if we're still
++	// in the process of connecting
++	setPresence ( status );
++
++	/* FIXME:
++	 * We should delete the JabberClient instance here,
++	 * but active timers in Iris prevent us from doing so.
++	 * (in a failed connection attempt, these timers will
++	 * try to access an already deleted object).
++	 * Instead, the instance will lurk until the next
++	 * connection attempt.
++	 */
++	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Disconnected." << endl;
++
+ 	Kopete::Account::disconnected ( reason );
+ }
+ 
+@@ -711,6 +794,7 @@
+ 			switch(connectorCode)
+ 			{
+  				case KNetwork::KSocketBase::LookupFailure:
++					errorClass = Kopete::Account::InvalidHost;
+ 					errorCondition = i18n("Host not found.");
+ 					break;
+ 				case KNetwork::KSocketBase::AddressInUse:
+@@ -756,11 +840,12 @@
+ 					errorCondition = i18n("Socket timed out.");
+ 					break;
+ 				default:
+-					errorCondition = i18n("Sorry, something unexpected happened that I do not know more about.");
++					errorClass = Kopete::Account::ConnectionReset;
++					//errorCondition = i18n("Sorry, something unexpected happened that I do not know more about.");
+ 					break;
+ 			}
+-
+-			errorText = i18n("There was a connection error: %1").arg(errorCondition);
++			if(!errorCondition.isEmpty())
++				errorText = i18n("There was a connection error: %1").arg(errorCondition);
+ 			break;
+ 
+ 		case XMPP::ClientStream::ErrNeg:
+@@ -893,7 +978,8 @@
+ 	 * API will attempt to reconnect, queueing another
+ 	 * error until memory is exhausted.
+ 	 */
+-	KMessageBox::error (Kopete::UI::Global::mainWidget (),
++	if(!errorText.isEmpty())
++		KMessageBox::error (Kopete::UI::Global::mainWidget (),
+ 						errorText,
+ 						i18n("Connection problem with Jabber server %1").arg(server));
+ 
+@@ -908,23 +994,22 @@
+ 		&& ( client()->clientStream()->errorCondition () == XMPP::ClientStream::NotAuthorized ) )
+ 	{
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Incorrect password, retrying." << endl;
+-
+-		// FIXME: This should be unified in libkopete as disconnect(IncorrectPassword)
+-		password().setWrong ();
+-		disconnect ();
+-		connect ();
++		disconnect(Kopete::Account::BadPassword);
+ 	}
+ 	else
+ 	{
+-		Kopete::Account::DisconnectReason errorClass;
++		Kopete::Account::DisconnectReason errorClass =  Kopete::Account::Unknown;
+ 
+ 		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Disconnecting." << endl;
+ 
+ 		// display message to user
+-		handleStreamError (error, client()->clientStream()->errorCondition (), client()->clientConnector()->errorCode (), server (), errorClass);
++		if(!m_removing) //when removing the account, connection errors are normal.
++			handleStreamError (error, client()->clientStream()->errorCondition (), client()->clientConnector()->errorCode (), server (), errorClass);
+ 
+ 		disconnect ( errorClass );
+-
++		
++		/*	slotCSDisconnected  will not be called*/
++		resourcePool()->clear();
+ 	}
+ 
+ }
+@@ -936,6 +1021,15 @@
+ 
+ 	// fetch input status
+ 	XMPP::Status newStatus = status;
++	
++	// TODO: Check if Caps is enabled
++	// Send entity capabilities
++	if( client() )
++	{
++		newStatus.setCapsNode( client()->capsNode() );
++		newStatus.setCapsVersion( client()->capsVersion() );
++		newStatus.setCapsExt( client()->capsExt() );
++	}
+ 
+ 	// make sure the status gets the correct priority
+ 	newStatus.setPriority ( configGroup()->readNumEntry ( "Priority", 5 ) );
+@@ -998,91 +1092,28 @@
+ 		 */
+ 		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << jid.full () << " is asking for authorization to subscribe." << endl;
+ 
++		// Is the user already in our contact list?
++		JabberBaseContact *contact = contactPool()->findExactMatch( jid );
+ 		Kopete::MetaContact *metaContact=0L;
+-		Kopete::Contact *contact;
+-		XMPP::JT_Presence *task;
+-
+-		switch (KMessageBox::questionYesNoCancel (Kopete::UI::Global::mainWidget (),
+-												  i18n
+-												  ("The Jabber user %1 wants to add you to their "
+-												   "contact list; do you want to authorize them? "
+-												   "Selecting Cancel will ignore the request.").
+-												  arg (jid.userHost (), 1), i18n ("Authorize Jabber User?"), i18n ("Authorize"), i18n ("Deny")))
+-		{
+-			case KMessageBox::Yes:
+-				/*
+-				 * Authorize user.
+-				 */
+-
+-				// this safety check needs to be here because
+-				// a long time could have passed between the
+-				// actual request and the user's answer
+-				if ( !isConnected () )
+-				{
+-					errorConnectionLost ();
+-					break;
+-				}
+-
+-				task = new XMPP::JT_Presence ( client()->rootTask () );
+-
+-				task->sub ( jid, "subscribed" );
+-				task->go ( true );
+-
+-				// Is the user already in our contact list?
+-				contact = Kopete::ContactList::self ()->findContact (protocol ()->pluginId (), accountId (), jid.full().lower () );
+-				if(contact)
+-					metaContact=contact->metaContact();
+-
+-				// If it is not, ask the user if he wants to subscribe in return.
+-				if ( ( !metaContact || metaContact->isTemporary() ) &&
+-					 ( KMessageBox::questionYesNo (Kopete::UI::Global::mainWidget (),
+-												   i18n ( "Do you want to add %1 to your contact list in return?").
+-												   arg (jid.userHost (), 1), i18n ("Add Jabber User?"),i18n("Add"), i18n("Do Not Add")) == KMessageBox::Yes) )
+-				{
+-					// Subscribe to user's presence.
+-					task = new XMPP::JT_Presence ( client()->rootTask () );
+-
+-					task->sub ( jid, "subscribe" );
+-					task->go ( true );
+-				}
+-
+-				break;
+-
+-			case KMessageBox::No:
+-				/*
+-				 * Reject subscription.
+-				 */
+-
+-				// this safety check needs to be here because
+-				// a long time could have passed between the
+-				// actual request and the user's answer
+-				if ( !isConnected () )
+-				{
+-					errorConnectionLost ();
+-					break;
+-				}
+-
+-				task = new XMPP::JT_Presence ( client()->rootTask () );
+-
+-				task->sub ( jid, "unsubscribed" );
+-				task->go ( true );
+-
+-				break;
+-
+-			case KMessageBox::Cancel:
+-				/*
+-				 * Simply ignore the request.
+-				 */
+-				break;
+-		}
+-
++		if(contact)
++			metaContact=contact->metaContact();
++		
++		int hideFlags=Kopete::UI::ContactAddedNotifyDialog::InfoButton;
++		if( metaContact && !metaContact->isTemporary() )
++			hideFlags |= Kopete::UI::ContactAddedNotifyDialog::AddCheckBox | Kopete::UI::ContactAddedNotifyDialog::AddGroupBox ;
++		
++		Kopete::UI::ContactAddedNotifyDialog *dialog=
++				new Kopete::UI::ContactAddedNotifyDialog( jid.full() ,QString::null,this, hideFlags );
++		QObject::connect(dialog,SIGNAL(applyClicked(const QString&)),
++						this,SLOT(slotContactAddedNotifyDialogClosed(const QString& )));
++		dialog->show();
+ 	}
+ 	else if (type == "unsubscribed")
+ 	{
+ 		/*
+ 		 * Someone else removed our authorization to see them.
+ 		 */
+-		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << jid.userHost () << " revoked our presence authorization" << endl;
++		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << jid.full() << " revoked our presence authorization" << endl;
+ 
+ 		XMPP::JT_Roster *task;
+ 
+@@ -1091,7 +1122,7 @@
+ 								  ("The Jabber user %1 removed %2's subscription to them. "
+ 								   "This account will no longer be able to view their online/offline status. "
+ 								   "Do you want to delete the contact?").
+-								  arg (jid.userHost (), 1).arg (accountId(), 2), i18n ("Notification"), KStdGuiItem::del(), i18n("Keep")))
++										  arg (jid.full(), 1).arg (accountId(), 2), i18n ("Notification"), KStdGuiItem::del(), i18n("Keep")))
+ 		{
+ 
+ 			case KMessageBox::Yes:
+@@ -1119,7 +1150,73 @@
+ 	}
+ }
+ 
+-void JabberAccount::slotNewContact (const XMPP::RosterItem & item)
++void JabberAccount::slotContactAddedNotifyDialogClosed( const QString & contactid )
++{	// the dialog that asked the authorisation is closed. (it was shown in slotSubscrition)
++	
++	XMPP::JT_Presence *task;
++	XMPP::Jid jid(contactid);
++
++	const Kopete::UI::ContactAddedNotifyDialog *dialog =
++			dynamic_cast<const Kopete::UI::ContactAddedNotifyDialog *>(sender());
++	if(!dialog || !isConnected())
++		return;
++
++	if ( dialog->authorized() )
++	{
++		/*
++		* Authorize user.
++		*/
++
++		task = new XMPP::JT_Presence ( client()->rootTask () );
++		task->sub ( jid, "subscribed" );
++		task->go ( true );
++	}
++	else
++	{
++		/*
++		* Reject subscription.
++		*/
++		task = new XMPP::JT_Presence ( client()->rootTask () );
++		task->sub ( jid, "unsubscribed" );
++		task->go ( true );
++	}
++
++
++	if(dialog->added())
++	{
++		Kopete::MetaContact *parentContact=dialog->addContact();
++		if(parentContact)
++		{
++			QStringList groupNames;
++			Kopete::GroupList groupList = parentContact->groups();
++			for(Kopete::Group *group = groupList.first(); group; group = groupList.next())
++				groupNames += group->displayName();
++
++			XMPP::RosterItem item;
++//			XMPP::Jid jid ( contactId );
++
++			item.setJid ( jid );
++			item.setName ( parentContact->displayName() );
++			item.setGroups ( groupNames );
++
++			// add the new contact to our roster.
++			XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( client()->rootTask () );
++
++			rosterTask->set ( item.jid(), item.name(), item.groups() );
++			rosterTask->go ( true );
++
++			// send a subscription request.
++			XMPP::JT_Presence *presenceTask = new XMPP::JT_Presence ( client()->rootTask () );
++	
++			presenceTask->sub ( jid, "subscribe" );
++			presenceTask->go ( true );
++		}
++	}
++}
++
++
++
++void JabberAccount::slotContactUpdated (const XMPP::RosterItem & item)
+ {
+ 
+ 	/**
+@@ -1140,50 +1237,85 @@
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "New roster item " << item.jid().full () << " (Subscription: " << item.subscription().toString () << ")" << endl;
+ 
+ 	/*
++	 * See if the contact need to be added, according to the criterias of 
++	 *  JEP-0162: Best Practices for Roster and Subscription Management
++	 * http://www.jabber.org/jeps/jep-0162.html#contacts
++	 */
++	bool need_to_add=false;
++	if(item.subscription().type() == XMPP::Subscription::Both || item.subscription().type() == XMPP::Subscription::To)
++		need_to_add = true;
++	else if( !item.ask().isEmpty() )
++		need_to_add = true;
++	else if( !item.name().isEmpty() || !item.groups().isEmpty() )
++		need_to_add = true;
++	
++	/*
+ 	 * See if the contact is already on our contact list
+ 	 */
+-	Kopete::MetaContact *metaContact;
+-	Kopete::Contact *c= Kopete::ContactList::self()->findContact ( protocol()->pluginId (), accountId (), item.jid().full().lower () ) ;
+-	if ( !c  )
++	Kopete::Contact *c= contactPool()->findExactMatch( item.jid() );
++	
++	if( c && c == c->Kopete::Contact::account()->myself() )  //don't use JabberBaseContact::account() which return alwaus the JabberAccount, and not the transport
+ 	{
+-		/*
+-		 * No metacontact has been found which contains a contact with this ID,
+-		 * so add a new metacontact to the list.
+-		 */
+-		metaContact = new Kopete::MetaContact ();
+-		QStringList groups = item.groups ();
++		// don't let remove the gateway contact, eh!
++		need_to_add = true;  
++	}
+ 
+-		// add this metacontact to all groups the contact is a member of
+-		for (QStringList::Iterator it = groups.begin (); it != groups.end (); ++it)
+-			metaContact->addToGroup (Kopete::ContactList::self ()->findGroup (*it));
+-
+-		// put it onto contact list
+-		Kopete::ContactList::self ()->addMetaContact ( metaContact );
+-	}
+-	else
++	if(need_to_add)
+ 	{
+-		metaContact=c->metaContact();
+-	}
++		Kopete::MetaContact *metaContact=0L;
++		if (!c)
++		{
++			/*
++			* No metacontact has been found which contains a contact with this ID,
++			* so add a new metacontact to the list.
++			*/
++			metaContact = new Kopete::MetaContact ();
++			QStringList groups = item.groups ();
++	
++			// add this metacontact to all groups the contact is a member of
++			for (QStringList::Iterator it = groups.begin (); it != groups.end (); ++it)
++				metaContact->addToGroup (Kopete::ContactList::self ()->findGroup (*it));
++	
++			// put it onto contact list
++			Kopete::ContactList::self ()->addMetaContact ( metaContact );
++		}
++		else
++		{
++			metaContact=c->metaContact();
++			//TODO: syncronize groups
++		}
+ 
+-	/*
+-	 * Add / update the contact in our pool. In case the contact is already there,
+-	 * it will be updated. In case the contact is not in the meta contact yet, it
+-	 * will be added to it.
+-	 * The "dirty" flag is false here, because we just received the contact from
+-	 * the server's roster. As such, it is now a synchronized entry.
+-	 */
+-	JabberContact *contact = contactPool()->addContact ( item, metaContact, false );
++		/*
++		* Add / update the contact in our pool. In case the contact is already there,
++		* it will be updated. In case the contact is not in the meta contact yet, it
++		* will be added to it.
++		* The "dirty" flag is false here, because we just received the contact from
++		* the server's roster. As such, it is now a synchronized entry.
++		*/
++		JabberContact *contact = contactPool()->addContact ( item, metaContact, false );
+ 
+-	/*
+-	 * Set authorization property
+-	 */
+-	if ( !item.ask().isEmpty () )
+-	{
+-		contact->setProperty ( protocol()->propAuthorizationStatus, i18n ( "Waiting for authorization" ) );
++		/*
++		* Set authorization property
++		*/
++		if ( !item.ask().isEmpty () )
++		{
++			contact->setProperty ( protocol()->propAuthorizationStatus, i18n ( "Waiting for authorization" ) );
++		}
++		else
++		{
++			contact->removeProperty ( protocol()->propAuthorizationStatus );
++		}
+ 	}
+-	else
++	else if(c)  //we don't need to add it, and it is in the contactlist
+ 	{
+-		contact->removeProperty ( protocol()->propAuthorizationStatus );
++		Kopete::MetaContact *metaContact=c->metaContact();
++		if(metaContact->isTemporary())
++			return;
++		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << c->contactId() << 
++				" is on the contactlist while it shouldn't.  we are removing it.  - " << c << endl;
++		delete c;
++		if(metaContact->contacts().isEmpty())
++			Kopete::ContactList::self()->removeMetaContact( metaContact );
+ 	}
+ 
+ }
+@@ -1197,31 +1329,6 @@
+ 
+ }
+ 
+-void JabberAccount::slotContactUpdated (const XMPP::RosterItem & item)
+-{
+-	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Status update for " << item.jid().full () << endl;
+-
+-	/*
+-	 * Sanity check: make sure that we have a matchin contact
+-	 * in our local pool before we try to updating it.
+-	 * (if no contact would be present, we'd add a contact
+-	 * without parent meta contact)
+-	 */
+-	if ( !contactPool()->findExactMatch ( item.jid () ) )
+-	{
+-		kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: Trying to update non-existing contact " << item.jid().full () << endl;
+-		return;
+-	}
+-
+-	/*
+-	 * Adding the contact again will update the existing instance.
+-	 * We're also explicitely setting the dirty flag to "false" since
+-	 * we are in synch with the server.
+-	 */
+-	contactPool()->addContact ( item, 0L, false );
+-
+-}
+-
+ void JabberAccount::slotReceivedMessage (const XMPP::Message & message)
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "New message from " << message.from().full () << endl;
+@@ -1315,11 +1422,16 @@
+ 	// Create a groupchat contact for this room
+ 	JabberGroupContact *groupContact = dynamic_cast<JabberGroupContact *>( contactPool()->addGroupContact ( XMPP::RosterItem ( jid ), true, metaContact, false ) );
+ 
+-	// Add the groupchat contact to the meta contact.
+-	metaContact->addContact ( groupContact );
++	if(groupContact)
++	{
++		// Add the groupchat contact to the meta contact.
++		//metaContact->addContact ( groupContact );
++	
++		Kopete::ContactList::self ()->addMetaContact ( metaContact );
++	}
++	else
++		delete metaContact;
+ 
+-	Kopete::ContactList::self ()->addMetaContact ( metaContact );
+-
+ 	/**
+ 	 * Add an initial resource for this contact to the pool. We need
+ 	 * to do this to be able to lock the group status to our own presence.
+@@ -1331,22 +1443,30 @@
+ 
+ 	// lock the room to our own status
+ 	resourcePool()->lockToResource ( XMPP::Jid ( jid.userHost () ), jid.resource () );
+-
++	
++	m_bookmarks->insertGroupChat(jid);	
+ }
+ 
+ void JabberAccount::slotGroupChatLeft (const XMPP::Jid & jid)
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo "Left groupchat " << jid.full () << endl;
+-
++	
+ 	// remove group contact from list
+-	Kopete::MetaContact *metaContact = Kopete::ContactList::self()->findMetaContactByContactId ( jid.userHost () );
++	Kopete::Contact *contact = 
++			Kopete::ContactList::self()->findContact( protocol()->pluginId() , accountId() , jid.userHost() );
+ 
+-	if ( metaContact )
+-		Kopete::ContactList::self()->removeMetaContact ( metaContact );
++	if ( contact )
++	{
++		Kopete::MetaContact *metaContact= contact->metaContact();
++		if( metaContact && metaContact->isTemporary() )
++			Kopete::ContactList::self()->removeMetaContact ( metaContact );
++		else
++			contact->deleteLater();
++	}
+ 
+ 	// now remove it from our pool, which should clean up all subcontacts as well
+ 	contactPool()->removeContact ( XMPP::Jid ( jid.userHost () ) );
+-
++	
+ }
+ 
+ void JabberAccount::slotGroupChatPresence (const XMPP::Jid & jid, const XMPP::Status & status)
+@@ -1387,18 +1507,61 @@
+ {
+ 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Group chat error - room " << jid.full () << " had error " << error << " (" << reason << ")" << endl;
+ 
+-	QString detailedReason = reason.isEmpty () ? i18n ( "No reason given by the server" ) : reason;
++	switch (error)
++	{
++	case JabberClient::InvalidPasswordForMUC:
++		{
++			QCString password;
++ 			int result = KPasswordDialog::getPassword(password, i18n("A password is required to join the room %1.").arg(jid.node()));
++			if (result == KPasswordDialog::Accepted)
++				m_jabberClient->joinGroupChat(jid.domain(), jid.node(), jid.resource(), password);
++		}
++		break;
+ 
+-	KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
++	case JabberClient::NicknameConflict:
++		{
++			bool ok;
++			QString nickname = KInputDialog::getText(i18n("Error trying to join %1 : nickname %2 is already in use").arg(jid.node(), jid.resource()),
++									i18n("Give your nickname"),
++									QString(),
++									&ok);
++			if (ok)
++			{
++				m_jabberClient->joinGroupChat(jid.domain(), jid.node(), nickname);
++			}
++		}
++		break;
++
++	case JabberClient::BannedFromThisMUC:
++		KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
+ 									KMessageBox::Error,
++									i18n ("You can't join the room %1 because you were banned").arg(jid.node()),
++									i18n ("Jabber Group Chat") );
++		break;
++
++	case JabberClient::MaxUsersReachedForThisMuc:
++		KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
++									KMessageBox::Error,
++									i18n ("You can't join the room %1 because the maximum users has been reached").arg(jid.node()),
++									i18n ("Jabber Group Chat") );
++		break;
++
++	default:
++		{
++		QString detailedReason = reason.isEmpty () ? i18n ( "No reason given by the server" ) : reason;
++
++		KMessageBox::queuedMessageBox ( Kopete::UI::Global::mainWidget (),
++									KMessageBox::Error,
+ 									i18n ("There was an error processing your request for group chat %1. (Reason: %2, Code %3)").arg ( jid.full (), detailedReason, QString::number ( error ) ),
+ 									i18n ("Jabber Group Chat") );
++		}
++	}
+ }
+ 
+ void JabberAccount::slotResourceAvailable (const XMPP::Jid & jid, const XMPP::Resource & resource)
+ {
+ 
+-	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "New resource available for " << jid.userHost () << endl;
++	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "New resource available for " << jid.full() << endl;
+ 
+ 	resourcePool()->addResource ( jid, resource );
+ 
+@@ -1407,7 +1570,7 @@
+ void JabberAccount::slotResourceUnavailable (const XMPP::Jid & jid, const XMPP::Resource & resource)
+ {
+ 
+-	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Resource now unavailable for " << jid.userHost () << endl;
++	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Resource now unavailable for " << jid.full () << endl;
+ 
+ 	resourcePool()->removeResource ( jid, resource );
+ 
+@@ -1420,17 +1583,29 @@
+ 
+ void JabberAccount::slotGlobalIdentityChanged (const QString &key, const QVariant &value)
+ {
+-	JabberContact *jabberMyself = static_cast<JabberContact *>( myself() );
+-	if( key == Kopete::Global::Properties::self()->nickName().key() )
++	// Check if this account is excluded from Global Identity.
++	if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
+ 	{
+-		QString oldNick = jabberMyself->property( protocol()->propNickName ).value().toString();
+-		QString newNick = value.toString();
+-	
+-		if( newNick != oldNick && isConnected() )
++		JabberContact *jabberMyself = static_cast<JabberContact *>( myself() );
++		if( key == Kopete::Global::Properties::self()->nickName().key() )
+ 		{
+-			jabberMyself->setProperty( protocol()->propNickName, newNick );
+-			jabberMyself->slotSendVCard();
++			QString oldNick = jabberMyself->property( protocol()->propNickName ).value().toString();
++			QString newNick = value.toString();
++		
++			if( newNick != oldNick && isConnected() )
++			{
++				jabberMyself->setProperty( protocol()->propNickName, newNick );
++				jabberMyself->slotSendVCard();
++			}
+ 		}
++		if( key == Kopete::Global::Properties::self()->photo().key() )
++		{
++			if( isConnected() )
++			{
++				jabberMyself->setPhoto( value.toString() );
++				jabberMyself->slotSendVCard();
++			}
++		}
+ 	}
+ }
+ 
+@@ -1463,6 +1638,115 @@
+ 	dialog->raise ();
+ }
+ 
++void JabberAccount::slotIncomingVoiceCall( const Jid &jid )
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++#ifdef SUPPORT_JINGLE
++	if(voiceCaller())
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Showing voice dialog." << endl;
++		JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog( jid, voiceCaller() );
++		voiceDialog->show();
++	}
++#else
++	Q_UNUSED(jid);
++#endif
++}
++
++// void JabberAccount::slotIncomingJingleSession( const QString &sessionType, JingleSession *session )
++// {
++// #ifdef SUPPORT_JINGLE
++// 	if(sessionType == "http://www.google.com/session/phone")
++// 	{
++// 		QString from = ((XMPP::Jid)session->peers().first()).full();
++// 		//KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Information, QString("Received a voice session invitation from %1.").arg(from) );
++// 		JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog( static_cast<JingleVoiceSession*>(session) );
++// 		voiceDialog->show();
++// 	}
++// #else
++// 	Q_UNUSED( sessionType );
++// 	Q_UNUSED( session );
++// #endif
++// }
++
++
++void JabberAccount::addTransport( JabberTransport * tr, const QString &jid )
++{
++	m_transports.insert(jid,tr);
++}
++
++void JabberAccount::removeTransport( const QString &jid )
++{
++	m_transports.remove(jid);
++}
++
++bool JabberAccount::removeAccount( )
++{
++	if(!m_removing)
++	{
++		int result=KMessageBox::warningYesNoCancel( Kopete::UI::Global::mainWidget () ,
++				   i18n( "Do you want to also unregister \"%1\" from the Jabber server ?\n"
++				   			    "If you unregister, all your contact list may be removed on the server,"
++							    "And you will never be able to connect to this account with any client").arg( accountLabel() ),
++					i18n("Unregister"),
++					KGuiItem(i18n( "Remove and Unregister" ), "editdelete"),
++					KGuiItem(i18n( "Remove from kopete only"), "edittrash"),
++					QString(), KMessageBox::Notify | KMessageBox::Dangerous );
++		if(result == KMessageBox::Cancel)
++		{
++			return false;
++		}
++		else if(result == KMessageBox::Yes)
++		{
++			if (!isConnected())
++			{
++				errorConnectFirst ();
++				return false;
++			}
++			
++			XMPP::JT_Register *task = new XMPP::JT_Register ( client()->rootTask () );
++			QObject::connect ( task, SIGNAL ( finished () ), this, SLOT ( slotUnregisterFinished ) );
++			task->unreg ();
++			task->go ( true );
++			m_removing=true;
++			// from my experiment, not all server reply us with a response.   it simply dosconnect
++			// so after one seconde, we will force to remove the account
++			QTimer::singleShot(1111, this, SLOT(slotUnregisterFinished())); 
++			
++			return false; //the account will be removed when the task will be finished
++		}
++	}
++	
++	//remove transports from config file.
++	QMap<QString,JabberTransport*> tranposrts_copy=m_transports;
++	QMap<QString,JabberTransport*>::Iterator it;
++	for ( it = tranposrts_copy.begin(); it != tranposrts_copy.end(); ++it )
++	{
++		(*it)->jabberAccountRemoved();
++	}
++	return true;
++}
++
++void JabberAccount::slotUnregisterFinished( )
++{
++	const XMPP::JT_Register * task = dynamic_cast<const XMPP::JT_Register *>(sender ());
++
++	if ( task && ! task->success ())
++	{
++		KMessageBox::queuedMessageBox ( 0L, KMessageBox::Error,
++			i18n ("An error occured when trying to remove the account:\n%1").arg(task->statusString()),
++			i18n ("Jabber Account Unregistration"));
++		m_removing=false;
++		return;
++	}
++	if(m_removing)  //it may be because this is now the timer.
++		Kopete::AccountManager::self()->removeAccount( this ); //this will delete this
++}
++
++
++
++
++
+ #include "jabberaccount.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/jabber/jabberresource.h	(revision 568672)
++++ kopete/protocols/jabber/jabberresource.h	(revision 586398)
+@@ -1,9 +1,10 @@
+  /*
+   * jabberresource.h
+   *
++  * Copyright (c) 2005-2006 by Michaël Larouche <michael.larouche at kdemail.net>
+   * Copyright (c) 2004 by Till Gerken <till at tantalo.net>
+   *
+-  * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
++  * Kopete    (c) 2001-2006 by the Kopete developers  <kopete-devel at kde.org>
+   *
+   * *************************************************************************
+   * *                                                                       *
+@@ -24,17 +25,24 @@
+ 
+ #include <qobject.h>
+ #include <qstring.h>
+-#include <im.h>
+-#include "jabberprotocol.h"
+ 
+ class JabberAccount;
+ 
+-class JabberResource:public QObject
++namespace XMPP
+ {
++class Resource;
++class Jid;
++class Features;
++}
+ 
++class JabberResource : public QObject
++{
+ Q_OBJECT
+ 
+ public:
++	/**
++	 * Create a new Jabber resource.
++	 */
+ 	JabberResource (JabberAccount *account, const XMPP::Jid &jid, const XMPP::Resource &resource);
+ 	~JabberResource ();
+ 
+@@ -43,22 +51,34 @@
+ 
+ 	void setResource ( const XMPP::Resource &resource );
+ 
++	/**
++	 * Return the client name for this resource.
++	 * @return the client name
++	 */
+ 	const QString &clientName () const;
++	/**
++	 * Return the client system for this resource.
++	 * @return the client system.
++	 */
+ 	const QString &clientSystem () const;
+ 
++	/**
++	 * Get the available features for this resource.
++	 */
++	XMPP::Features features() const;
++
+ signals:
+ 	void updated ( JabberResource * );
+ 
+ private slots:
+ 	void slotGetTimedClientVersion ();
+ 	void slotGotClientVersion ();
++	void slotGetDiscoCapabilties ();
++	void slotGotDiscoCapabilities ();
+ 
+ private:
+-	XMPP::Jid mJid;
+-	XMPP::Resource mResource;
+-	JabberAccount *mAccount;
+-	QString mClientName, mClientSystem;
+-
++	class Private;
++	Private *d;
+ };
+ 
+ #endif
+--- kopete/protocols/jabber/jabbertransport.cpp	(revision 0)
++++ kopete/protocols/jabber/jabbertransport.cpp	(revision 586398)
+@@ -0,0 +1,345 @@
++ /*
++
++    Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
++
++    Kopete    (c) 2006 by the Kopete developers <kopete-devel at 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 "jabbertransport.h"
++#include "jabbercontact.h"
++#include "jabberaccount.h"
++#include "jabberprotocol.h"
++#include "jabbercontactpool.h"
++#include "jabberchatsession.h"
++
++#include <kopeteaccountmanager.h>
++#include <kopetecontact.h>
++#include <kopetecontactlist.h>
++
++#include <kopeteversion.h>
++
++
++#include <qpixmap.h>
++#include <qtimer.h>
++#include <kaction.h>
++#include <kdebug.h>
++#include <klocale.h>
++#include <kconfig.h>
++
++#include "xmpp_tasks.h"
++
++JabberTransport::JabberTransport (JabberAccount * parentAccount, const XMPP::RosterItem & item, const QString& gateway_type)
++	: Kopete::Account ( parentAccount->protocol(), parentAccount->accountId()+"/"+ item.jid().bare() )
++{
++	m_status=Creating;
++	m_account = parentAccount;
++	m_account->addTransport( this,item.jid().bare() );
++	
++	JabberContact *myContact = m_account->contactPool()->addContact ( item , Kopete::ContactList::self()->myself(), false );
++	setMyself( myContact );
++	
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << accountId() <<" transport created:  myself: " << myContact << endl;
++	
++	setColor( account()->color() );
++
++#if KOPETE_IS_VERSION(0,11,51)  //setCustomIcon is new in kopete 0.12
++	QString cIcon;
++	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";
++	else if(gateway_type=="yahoo")
++		cIcon="jabber_gateway_yahoo";
++	else if(gateway_type=="sms")
++		cIcon="jabber_gateway_sms";
++	else if(gateway_type=="gadu-gadu")
++		cIcon="jabber_gateway_gadu";
++	else if(gateway_type=="smtp")
++		cIcon="jabber_gateway_smtp";
++	else if(gateway_type=="http-ws") 
++		cIcon="jabber_gateway_http-ws";
++	else if(gateway_type=="qq")
++		cIcon="jabber_gateway_qq";
++	else if(gateway_type=="tlen")
++		cIcon="jabber_gateway_tlen";
++	else if(gateway_type=="irc")  //NOTE: this is not official 
++		cIcon="irc_protocol";
++
++	if( !cIcon.isEmpty() )
++		setCustomIcon( cIcon );
++#endif		
++
++	configGroup()->writeEntry("GatewayJID" , item.jid().full() );
++
++	QTimer::singleShot(0, this, SLOT(eatContacts()));
++	
++	m_status=Normal;
++}
++
++JabberTransport::JabberTransport( JabberAccount * parentAccount, const QString & _accountId )
++	: Kopete::Account ( parentAccount->protocol(), _accountId )
++{
++	m_status=Creating;
++	m_account = parentAccount;
++	
++	const QString contactJID_s = configGroup()->readEntry("GatewayJID");
++	
++	if(contactJID_s.isEmpty())
++	{
++		kdError(JABBER_DEBUG_GLOBAL) << k_funcinfo << _accountId <<": GatewayJID is empty: MISCONFIGURATION  (have you used Kopete 0.12 beta ?)" << endl;
++	}
++	
++	XMPP::Jid contactJID= XMPP::Jid( contactJID_s );
++	
++	m_account->addTransport( this, contactJID.bare() );
++	
++	JabberContact *myContact = m_account->contactPool()->addContact ( contactJID , Kopete::ContactList::self()->myself(), false );
++	setMyself( myContact );
++	
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << accountId() <<" transport created:  myself: " << myContact << endl;
++	
++	m_status=Normal;
++}
++
++
++
++
++JabberTransport::~JabberTransport ()
++{
++	m_account->removeTransport( myself()->contactId() );
++}
++
++KActionMenu *JabberTransport::actionMenu ()
++{
++	KActionMenu *menu = new KActionMenu( accountId(), myself()->onlineStatus().iconFor( this ),  this );
++	QString nick = myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString();
++
++	menu->popupMenu()->insertTitle( myself()->onlineStatus().iconFor( myself() ),
++	nick.isNull() ? accountLabel() : i18n( "%2 <%1>" ).arg( accountLabel(), nick )
++								  );
++	
++	QPtrList<KAction> *customActions = myself()->customContextMenuActions(  );
++	if( customActions && !customActions->isEmpty() )
++	{
++		menu->popupMenu()->insertSeparator();
++
++		for( KAction *a = customActions->first(); a; a = customActions->next() )
++			a->plug( menu->popupMenu() );
++	}
++	delete customActions;
++
++	return menu;
++
++/*	KActionMenu *m_actionMenu = Kopete::Account::actionMenu();
++
++	m_actionMenu->popupMenu()->insertSeparator();
++
++	m_actionMenu->insert(new KAction (i18n ("Join Groupchat..."), "jabber_group", 0,
++		this, SLOT (slotJoinNewChat ()), this, "actionJoinChat"));
++
++	m_actionMenu->popupMenu()->insertSeparator();
++
++	m_actionMenu->insert ( new KAction ( i18n ("Services..."), "jabber_serv_on", 0,
++										 this, SLOT ( slotGetServices () ), this, "actionJabberServices") );
++
++	m_actionMenu->insert ( new KAction ( i18n ("Send Raw Packet to Server..."), "mail_new", 0,
++										 this, SLOT ( slotSendRaw () ), this, "actionJabberSendRaw") );
++
++	m_actionMenu->insert ( new KAction ( i18n ("Edit User Info..."), "identity", 0,
++										 this, SLOT ( slotEditVCard () ), this, "actionEditVCard") );
++
++	return m_actionMenu;*/
++}
++
++
++bool JabberTransport::createContact (const QString & contactId,  Kopete::MetaContact * metaContact)
++{
++#if 0 //TODO
++	// collect all group names
++	QStringList groupNames;
++	Kopete::GroupList groupList = metaContact->groups();
++	for(Kopete::Group *group = groupList.first(); group; group = groupList.next())
++		groupNames += group->displayName();
++
++	XMPP::Jid jid ( contactId );
++	XMPP::RosterItem item ( jid );
++	item.setName ( metaContact->displayName () );
++	item.setGroups ( groupNames );
++
++	// this contact will be created with the "dirty" flag set
++	// (it will get reset if the contact appears in the roster during connect)
++	JabberContact *contact = contactPool()->addContact ( item, metaContact, true );
++
++	return ( contact != 0 );
++#endif
++	return false;
++}
++
++
++void JabberTransport::setOnlineStatus( const Kopete::OnlineStatus& status  , const QString &reason)
++{
++#if 0
++	if( status.status() == Kopete::OnlineStatus::Offline )
++	{
++		disconnect( Kopete::Account::Manual );
++		return;
++	}
++
++	if( isConnecting () )
++	{
++		errorConnectionInProgress ();
++		return;
++	}
++
++	XMPP::Status xmppStatus ( "", reason );
++
++	switch ( status.internalStatus () )
++	{
++		case JabberProtocol::JabberFreeForChat:
++			xmppStatus.setShow ( "chat" );
++			break;
++
++		case JabberProtocol::JabberOnline:
++			xmppStatus.setShow ( "" );
++			break;
++
++		case JabberProtocol::JabberAway:
++			xmppStatus.setShow ( "away" );
++			break;
++
++		case JabberProtocol::JabberXA:
++			xmppStatus.setShow ( "xa" );
++			break;
++
++		case JabberProtocol::JabberDND:
++			xmppStatus.setShow ( "dnd" );
++			break;
++
++		case JabberProtocol::JabberInvisible:
++			xmppStatus.setIsInvisible ( true );
++			break;
++	}
++
++	if ( !isConnected () )
++	{
++		// we are not connected yet, so connect now
++		m_initialPresence = xmppStatus;
++		connect ();
++	}
++	else
++	{
++		setPresence ( xmppStatus );
++	}
++#endif
++}
++
++JabberProtocol * JabberTransport::protocol( ) const
++{
++	return m_account->protocol(); 
++}
++
++bool JabberTransport::removeAccount( )
++{
++	if(m_status == Removing  ||  m_status == AccountRemoved)
++		return true; //so it can be deleted
++	
++	if (!account()->isConnected())
++	{
++		account()->errorConnectFirst ();
++		return false;
++	}
++	
++	m_status = Removing;
++	XMPP::JT_Register *task = new XMPP::JT_Register ( m_account->client()->rootTask () );
++	QObject::connect ( task, SIGNAL ( finished () ), this, SLOT ( removeAllContacts() ) );
++
++	//JabberContact *my=static_cast<JabberContact*>(myself());
++	task->unreg ( myself()->contactId() );
++	task->go ( true );
++	return false; //delay the removal
++}
++
++void JabberTransport::removeAllContacts( )
++{
++//	XMPP::JT_Register * task = (XMPP::JT_Register *) sender ();
++
++/*	if ( ! task->success ())
++	KMessageBox::queuedMessageBox ( 0L, KMessageBox::Error,
++									i18n ("An error occured when trying to remove the transport:\n%1").arg(task->statusString()),
++									i18n ("Jabber Service Unregistration"));
++	*/ //we don't really care, we remove everithing anyway.
++
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "delete all contacts of the transport"<< endl;
++	QDictIterator<Kopete::Contact> it( contacts() ); 
++	for( ; it.current(); ++it )
++	{
++		XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( account()->client()->rootTask () );
++		rosterTask->remove ( static_cast<JabberBaseContact*>(it.current())->rosterItem().jid() );
++		rosterTask->go ( true );
++	}
++	m_status = Removing; //in theory that's already our status
++	Kopete::AccountManager::self()->removeAccount( this ); //this will delete this
++}
++
++QString JabberTransport::legacyId( const XMPP::Jid & jid )
++{
++	if(jid.node().isEmpty())
++		return QString();
++	QString node = jid.node();
++	return node.replace("%","@");
++}
++
++void JabberTransport::jabberAccountRemoved( )
++{
++	m_status = AccountRemoved;
++	Kopete::AccountManager::self()->removeAccount( this ); //this will delete this	
++}
++
++void JabberTransport::eatContacts( )
++{
++	/*
++	* "Gateway Contact Eating" (c)(r)(tm)(g)(o)(f)
++	* this comes directly from my mind into the kopete code.
++	* principle: - the transport is hungry
++	*            - it will eat contacts which belong to him
++	*            - the contact will die
++	*            - a new contact will born, with the same characteristics, but owned by the transport
++	* - Olivier 2006-01-17 -
++	*/
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++	QDict<Kopete::Contact> cts=account()->contacts();
++	QDictIterator<Kopete::Contact> it( cts ); 
++	for( ; it.current(); ++it )
++	{
++		JabberContact *contact=dynamic_cast<JabberContact*>(it.current());
++		if( contact && !contact->transport() && contact->rosterItem().jid().domain() == myself()->contactId() && contact != account()->myself())
++		{
++			XMPP::RosterItem item=contact->rosterItem();
++			Kopete::MetaContact *mc=contact->metaContact();
++			Kopete::OnlineStatus status = contact->onlineStatus();
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << item.jid().full() << " will be soon eat  - " << contact << endl;
++			delete contact;
++			Kopete::Contact *c2=account()->contactPool()->addContact( item , mc , false ); //not sure this is false;
++			if(c2)
++				c2->setOnlineStatus( status ); //put back the old status
++		}
++	}
++}
++
++
++
++#include "jabbertransport.moc"
++
++// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/jabber/jabberbookmarks.h	(revision 0)
++++ kopete/protocols/jabber/jabberbookmarks.h	(revision 586398)
+@@ -0,0 +1,68 @@
++ /*
++
++    Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
++
++    Kopete    (c) 2006 by the Kopete developers <kopete-devel at 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 JABBERBOOKMARKS_H
++#define JABBERBOOKMARKS_H
++
++#include <qobject.h>
++#include <qdom.h>
++#include <qstringlist.h>
++
++namespace XMPP { class Jid; }
++class JabberAccount;
++class JabberProtocol;
++
++class KAction;
++
++/**
++ * This is a class that hanlde the bookmark collection  (JEP-0048)
++ * There is one instance of that class by accounts.
++ * @author Olivier Goffart 
++ */
++class JabberBookmarks : public QObject
++{
++	Q_OBJECT
++	public:
++		/**
++		 * Constructor
++		 */
++		JabberBookmarks(JabberAccount *parent);
++		~JabberBookmarks(){}
++		
++		/**
++		 * update or create en entry with the given jid.
++		 * the jid ressource is the nickname
++		 */
++		void insertGroupChat(const XMPP::Jid &jid);
++		
++		/**
++		 * return an action that will be added in the jabber popup menu
++		 */
++		KAction *bookmarksAction(QObject * parent);
++	private slots:
++		void accountConnected();
++		void slotReceivedBookmarks();
++		void slotJoinChatBookmark(const QString&);
++		
++
++	private:
++		JabberAccount *m_account;
++		QDomDocument m_storage;
++		QStringList m_conferencesJID;
++};
++
++#endif
+--- kopete/protocols/jabber/jabberchatui.rc	(revision 0)
++++ kopete/protocols/jabber/jabberchatui.rc	(revision 586398)
+@@ -0,0 +1,19 @@
++<!DOCTYPE kpartgui>
++<kpartgui version="11" name="kopete_jabber_chat">
++	<MenuBar>
++		<Menu noMerge="1" name="file">
++			<text>&amp;Chat</text>
++			<Action name="jabber_voicecall" />
++			<Action name="jabberSendFile" />
++		</Menu>
++	</MenuBar>
++
++
++	<ToolBar name="statusToolBar">
++		<Action name="jabberDisplayPicture" />
++		<Action name="jabber_voicecall" />
++		<Action name="jabberSendFile" />		
++	</ToolBar>
++
++
++</kpartgui>
+\ No newline at end of file
+--- kopete/protocols/jabber/jabbergroupmembercontact.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupmembercontact.cpp	(revision 586398)
+@@ -50,9 +50,10 @@
+  */
+ JabberGroupMemberContact::~JabberGroupMemberContact ()
+ {
+-
+-	delete mManager;
+-	
++	if(mManager)
++	{
++		mManager->deleteLater();
++	}
+ }
+ 
+ QPtrList<KAction> *JabberGroupMemberContact::customContextMenuActions ()
+@@ -107,8 +108,10 @@
+ 	if ( message.body().isEmpty () )
+ 		return;
+ 
+-	Kopete::ContactPtrList contactList;
+-	contactList.append ( manager( Kopete::Contact::CanCreate )->myself() );
++	Kopete::ChatSession *kmm = manager( Kopete::Contact::CanCreate );
++	if(!kmm)
++		return;
++	Kopete::ContactPtrList contactList = kmm->members();
+ 
+ 	// check for errors
+ 	if ( message.type () == "error" )
+@@ -135,7 +138,7 @@
+ 	}
+ 
+ 	// append message to manager
+-	manager( Kopete::Contact::CanCreate )->appendMessage ( *newMessage );
++	kmm->appendMessage ( *newMessage );
+ 
+ 	delete newMessage;
+ 
+@@ -161,9 +164,5 @@
+ 
+ }
+ 
+-void JabberGroupMemberContact::slotUserInfo ()
+-{
+ 
+-}
+-
+ #include "jabbergroupmembercontact.moc"
+--- kopete/protocols/jabber/jabberprotocol.h	(revision 568672)
++++ kopete/protocols/jabber/jabberprotocol.h	(revision 586398)
+@@ -39,18 +39,19 @@
+ namespace XMPP
+ {
+ 	class Resource;
++	class Status;
+ }
+ 
+ class JabberContact;
+ class dlgJabberStatus;
+ class dlgJabberSendRaw;
++class JabberCapabilitiesManager;
+ 
+ class JabberProtocol:public Kopete::Protocol
+ {
+ 	Q_OBJECT
+ 
+ public:
+-
+ 	/**
+ 	 * Object constructor and destructor
+ 	 */
+@@ -97,6 +98,7 @@
+ 	const Kopete::ContactPropertyTmpl propAuthorizationStatus;
+ 	const Kopete::ContactPropertyTmpl propAvailableResources;
+ 	const Kopete::ContactPropertyTmpl propVCardCacheTimeStamp;
++	const Kopete::ContactPropertyTmpl propPhoto;
+ 	// extra properties to match with vCard
+ 	const Kopete::ContactPropertyTmpl propJid;
+ 	const Kopete::ContactPropertyTmpl propBirthday;
+@@ -136,13 +138,27 @@
+ 	 * Convert an XMPP::Resource status to a Kopete::OnlineStatus
+ 	 */
+ 	Kopete::OnlineStatus resourceToKOS ( const XMPP::Resource &resource );
++	
++	/**
++	 * Convert an online status to a  XMPP::Status
++	 */
++	XMPP::Status kosToStatus( const Kopete::OnlineStatus & status, const QString& message=QString() );
+ 
++	/**
++	 * Return the Entity Capabilities(JEP-0115) manager instance.
++	 */
++	JabberCapabilitiesManager *capabilitiesManager();
++
+ private:
+ 	/*
+ 	 * Singleton instance of our protocol class
+ 	 */
+ 	static JabberProtocol *protocolInstance;
+ 
++	/**
++	 * Unique Instance of the Entity Capabilities(JEP-0115) manager for Kopete Jabber plugin.
++	 */
++	JabberCapabilitiesManager *capsManager;
+ };
+ 
+ #endif
+--- kopete/protocols/jabber/jabbergroupcontact.h	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupcontact.h	(revision 586398)
+@@ -72,17 +72,27 @@
+ 	virtual void sendFile( const KURL &sourceURL = KURL(),
+ 		const QString &fileName = QString::null, uint fileSize = 0L );
+ 
+-	/**
+-	 * Retrieve a vCard for the contact
+-	 */
+-	void slotUserInfo ();
+-
+ private slots:
+ 
+ 	/**
+ 	 * Catch a dying message manager and leave the room.
+ 	 */
+ 	void slotChatSessionDeleted ();
++	
++	/**
++	 * When our own status change, we need to manually send the presence.
++	 */
++	void slotStatusChanged();
++	
++	/**
++	 * ask the user to change the nick, and change it
++	 */
++	void slotChangeNick();
++	
++	/**
++	 * a subcontact has been destroyed   (may happen when closing kopete)
++	 */
++	void slotSubContactDestroyed(Kopete::Contact*);
+ 
+ private:
+ 
+@@ -90,7 +100,8 @@
+ 	QPtrList<Kopete::MetaContact> mMetaContactList;
+ 
+ 	JabberGroupChatManager *mManager;
+-
++	JabberBaseContact *mSelfContact;
++	QString mNick;
+ };
+ 
+ #endif
+--- kopete/protocols/jabber/jabberclient.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberclient.cpp	(revision 586398)
+@@ -4,8 +4,9 @@
+                              -------------------
+     begin                : Sat May 25 2005
+     copyright            : (C) 2005 by Till Gerken <till at tantalo.net>
++                           (C) 2006 by Michaël Larouche <michael.larouche at kdemail.net>
+ 
+-			   Kopete (C) 2001-2005 Kopete developers
++			   Kopete (C) 2001-2006 Kopete developers
+ 			   <kopete-devel at kde.org>.
+  ***************************************************************************/
+ 
+@@ -32,19 +33,96 @@
+ 
+ #define JABBER_PENALTY_TIME	2
+ 
+-XMPP::S5BServer *JabberClient::m_s5bServer = 0L;
+-QStringList JabberClient::m_s5bAddressList;
+-int JabberClient::m_s5bServerPort = 8010;
++class JabberClient::Private
++{
++public:
++	Private()
++	 : jabberClient(0L), jabberClientStream(0L), jabberClientConnector(0L), jabberTLS(0L), jabberTLSHandler(0L)
++	{}
++	~Private()
++	{
++		if ( jabberClient )
++		{
++			jabberClient->close ();
++		}
++		
++		delete jabberClient;
++		delete jabberClientStream;
++		delete jabberClientConnector;
++		delete jabberTLSHandler;
++		delete jabberTLS;
++	}
+ 
++	// connection details
++	XMPP::Jid jid;
++	QString password;
++
++	// XMPP backend
++	XMPP::Client *jabberClient;
++	XMPP::ClientStream *jabberClientStream;
++	JabberConnector *jabberClientConnector;
++	QCA::TLS *jabberTLS;
++	XMPP::QCATLSHandler *jabberTLSHandler;
++
++	// ignore TLS warnings
++	bool ignoreTLSWarnings;
++
++	// current S5B server instance
++	static XMPP::S5BServer *s5bServer;
++	// address list being handled by the S5B server instance
++	static QStringList s5bAddressList;
++	// port of S5B server
++	static int s5bServerPort;
++
++	// local IP address
++	QString localAddress;
++
++	// whether TLS (or direct SSL in case of the old protocol) should be used
++	bool forceTLS;
++
++	// whether direct SSL connections should be used
++	bool useSSL;
++
++	// use XMPP 1.0 or the older protocol version
++	bool useXMPP09;
++
++	// whether SSL support should be probed in case the old protocol is used
++	bool probeSSL;
++
++	// override the default server name and port (only pre-XMPP 1.0)
++	bool overrideHost;
++	QString server;
++	int port;
++
++	// allow transmission of plaintext passwords
++	bool allowPlainTextPassword;
++
++	// enable file transfers
++	bool fileTransfersEnabled;
++
++	// current penalty time
++	int currentPenaltyTime;
++
++	// client information
++	QString clientName, clientVersion, osName;
++
++	// timezone information
++	QString timeZoneName;
++	int timeZoneOffset;
++
++	// Caps(JEP-0115: Entity Capabilities) information
++	QString capsNode, capsVersion;
++	DiscoItem::Identity discoIdentity;
++};
++
++XMPP::S5BServer *JabberClient::Private::s5bServer = 0L;
++QStringList JabberClient::Private::s5bAddressList;
++int JabberClient::Private::s5bServerPort = 8010;
++
+ JabberClient::JabberClient ()
+ {
++	d = new Private();
+ 
+-	m_jabberClient = 0L;
+-	m_jabberClientStream = 0L;
+-	m_jabberClientConnector = 0L;
+-	m_jabberTLS = 0L;
+-	m_jabberTLSHandler = 0L;
+-
+ 	cleanUp ();
+ 
+ 	// initiate penalty timer
+@@ -54,32 +132,32 @@
+ 
+ JabberClient::~JabberClient ()
+ {
+-
++	delete d;
+ }
+ 
+ void JabberClient::cleanUp ()
+ {
+-	if ( m_jabberClient )
++	if ( d->jabberClient )
+ 	{
+-		m_jabberClient->close ();
++		d->jabberClient->close ();
+ 	}
+ 	
+-	delete m_jabberClient;
+-	delete m_jabberClientStream;
+-	delete m_jabberClientConnector;
+-	delete m_jabberTLSHandler;
+-	delete m_jabberTLS;
++	delete d->jabberClient;
++	delete d->jabberClientStream;
++	delete d->jabberClientConnector;
++	delete d->jabberTLSHandler;
++	delete d->jabberTLS;
+ 
+-	m_jabberClient = 0L;
+-	m_jabberClientStream = 0L;
+-	m_jabberClientConnector = 0L;
+-	m_jabberTLSHandler = 0L;
+-	m_jabberTLS = 0L;
++	d->jabberClient = 0L;
++	d->jabberClientStream = 0L;
++	d->jabberClientConnector = 0L;
++	d->jabberTLSHandler = 0L;
++	d->jabberTLS = 0L;
+ 
+-	m_currentPenaltyTime = 0;
++	d->currentPenaltyTime = 0;
+ 
+-	m_jid = XMPP::Jid ();
+-	m_password = QString::null;
++	d->jid = XMPP::Jid ();
++	d->password = QString::null;
+ 
+ 	setForceTLS ( false );
+ 	setUseSSL ( false );
+@@ -106,10 +184,10 @@
+ void JabberClient::slotUpdatePenaltyTime ()
+ {
+ 
+-	if ( m_currentPenaltyTime >= JABBER_PENALTY_TIME )
+-		m_currentPenaltyTime -= JABBER_PENALTY_TIME;
++	if ( d->currentPenaltyTime >= JABBER_PENALTY_TIME )
++		d->currentPenaltyTime -= JABBER_PENALTY_TIME;
+ 	else
+-		m_currentPenaltyTime = 0;
++		d->currentPenaltyTime = 0;
+ 
+ 	QTimer::singleShot ( JABBER_PENALTY_TIME * 1000, this, SLOT ( slotUpdatePenaltyTime () ) );
+ 
+@@ -118,21 +196,21 @@
+ void JabberClient::setIgnoreTLSWarnings ( bool flag )
+ {
+ 
+-	m_ignoreTLSWarnings = flag;
++	d->ignoreTLSWarnings = flag;
+ 
+ }
+ 
+ bool JabberClient::ignoreTLSWarnings ()
+ {
+ 
+-	return m_ignoreTLSWarnings;
++	return d->ignoreTLSWarnings;
+ 
+ }
+ 
+ bool JabberClient::setS5BServerPort ( int port )
+ {
+ 
+-	m_s5bServerPort = port;
++	d->s5bServerPort = port;
+ 
+ 	if ( fileTransfersEnabled () )
+ 	{
+@@ -146,17 +224,17 @@
+ int JabberClient::s5bServerPort () const
+ {
+ 
+-	return m_s5bServerPort;
++	return d->s5bServerPort;
+ 
+ }
+ 
+ XMPP::S5BServer *JabberClient::s5bServer ()
+ {
+ 
+-	if ( !m_s5bServer )
++	if ( !d->s5bServer )
+ 	{
+-		m_s5bServer = new XMPP::S5BServer ();
+-		QObject::connect ( m_s5bServer, SIGNAL ( destroyed () ), this, SLOT ( slotS5BServerGone () ) );
++		d->s5bServer = new XMPP::S5BServer ();
++		QObject::connect ( d->s5bServer, SIGNAL ( destroyed () ), this, SLOT ( slotS5BServerGone () ) );
+ 
+ 		/*
+ 		 * Try to start the server at the default port here.
+@@ -167,21 +245,21 @@
+ 		 */
+ 		if ( fileTransfersEnabled () )
+ 		{
+-			s5bServer()->start ( m_s5bServerPort );
++			s5bServer()->start ( d->s5bServerPort );
+ 		}
+ 	}
+ 
+-	return m_s5bServer;
++	return d->s5bServer;
+ 
+ }
+ 
+ void JabberClient::slotS5BServerGone ()
+ {
+ 
+-	m_s5bServer = 0L;
++	d->s5bServer = 0L;
+ 
+-	if ( m_jabberClient )
+-		m_jabberClient->s5bManager()->setServer( 0L );
++	if ( d->jabberClient )
++		d->jabberClient->s5bManager()->setServer( 0L );
+ 
+ }
+ 
+@@ -189,10 +267,10 @@
+ {
+ 	QStringList newList;
+ 
+-	m_s5bAddressList.append ( address );
++	d->s5bAddressList.append ( address );
+ 
+ 	// now filter the list without dupes
+-	for ( QStringList::Iterator it = m_s5bAddressList.begin (); it != m_s5bAddressList.end (); ++it )
++	for ( QStringList::Iterator it = d->s5bAddressList.begin (); it != d->s5bAddressList.end (); ++it )
+ 	{
+ 		if ( !newList.contains ( *it ) )
+ 			newList.append ( *it );
+@@ -206,21 +284,21 @@
+ {
+ 	QStringList newList;
+ 
+-	QStringList::iterator it = m_s5bAddressList.find ( address );
+-	if ( it != m_s5bAddressList.end () )
++	QStringList::iterator it = d->s5bAddressList.find ( address );
++	if ( it != d->s5bAddressList.end () )
+ 	{
+-		m_s5bAddressList.remove ( it );
++		d->s5bAddressList.remove ( it );
+ 	}
+ 
+-	if ( m_s5bAddressList.isEmpty () )
++	if ( d->s5bAddressList.isEmpty () )
+ 	{
+-		delete m_s5bServer;
+-		m_s5bServer = 0L;
++		delete d->s5bServer;
++		d->s5bServer = 0L;
+ 	}
+ 	else
+ 	{
+ 		// now filter the list without dupes
+-		for ( QStringList::Iterator it = m_s5bAddressList.begin (); it != m_s5bAddressList.end (); ++it )
++		for ( QStringList::Iterator it = d->s5bAddressList.begin (); it != d->s5bAddressList.end (); ++it )
+ 		{
+ 			if ( !newList.contains ( *it ) )
+ 				newList.append ( *it );
+@@ -234,181 +312,220 @@
+ void JabberClient::setForceTLS ( bool flag )
+ {
+ 
+-	m_forceTLS = flag;
++	d->forceTLS = flag;
+ 
+ }
+ 
+ bool JabberClient::forceTLS () const
+ {
+ 
+-	return m_forceTLS;
++	return d->forceTLS;
+ 
+ }
+ 
+ void JabberClient::setUseSSL ( bool flag )
+ {
+ 
+-	m_useSSL = flag;
++	d->useSSL = flag;
+ 
+ }
+ 
+ bool JabberClient::useSSL () const
+ {
+ 
+-	return m_useSSL;
++	return d->useSSL;
+ 
+ }
+ 
+ void JabberClient::setUseXMPP09 ( bool flag )
+ {
+ 
+-	m_useXMPP09 = flag;
++	d->useXMPP09 = flag;
+ 
+ }
+ 
+ bool JabberClient::useXMPP09 () const
+ {
+ 
+-	return m_useXMPP09;
++	return d->useXMPP09;
+ 
+ }
+ 
+ void JabberClient::setProbeSSL ( bool flag )
+ {
+ 
+-	m_probeSSL = flag;
++	d->probeSSL = flag;
+ 
+ }
+ 
+ bool JabberClient::probeSSL () const
+ {
+ 
+-	return m_probeSSL;
++	return d->probeSSL;
+ 
+ }
+ 
+ void JabberClient::setOverrideHost ( bool flag, const QString &server, int port )
+ {
+ 
+-	m_overrideHost = flag;
+-	m_server = server;
+-	m_port = port;
++	d->overrideHost = flag;
++	d->server = server;
++	d->port = port;
+ 
+ }
+ 
+ bool JabberClient::overrideHost () const
+ {
+ 
+-	return m_overrideHost;
++	return d->overrideHost;
+ 
+ }
+ 
+ void JabberClient::setAllowPlainTextPassword ( bool flag )
+ {
+ 
+-	m_allowPlainTextPassword = flag;
++	d->allowPlainTextPassword = flag;
+ 
+ }
+ 
+ bool JabberClient::allowPlainTextPassword () const
+ {
+ 
+-	return m_allowPlainTextPassword;
++	return d->allowPlainTextPassword;
+ 
+ }
+ 
+ void JabberClient::setFileTransfersEnabled ( bool flag, const QString &localAddress )
+ {
+ 
+-	m_fileTransfersEnabled = flag;
+-	m_localAddress = localAddress;
++	d->fileTransfersEnabled = flag;
++	d->localAddress = localAddress;
+ 
+ }
+ 
+ QString JabberClient::localAddress () const
+ {
+ 
+-	return m_localAddress;
++	return d->localAddress;
+ 
+ }
+ 
+ bool JabberClient::fileTransfersEnabled () const
+ {
+ 
+-	return m_fileTransfersEnabled;
++	return d->fileTransfersEnabled;
+ 
+ }
+ 
+ void JabberClient::setClientName ( const QString &clientName )
+ {
+ 
+-	m_clientName = clientName;
++	d->clientName = clientName;
+ 
+ }
+ 
+ QString JabberClient::clientName () const
+ {
+ 
+-	return m_clientName;
++	return d->clientName;
+ 
+ }
+ 
+ void JabberClient::setClientVersion ( const QString &clientVersion )
+ {
+ 
+-	m_clientVersion = clientVersion;
++	d->clientVersion = clientVersion;
+ 
+ }
+ 
+ QString JabberClient::clientVersion () const
+ {
+ 
+-	return m_clientVersion;
++	return d->clientVersion;
+ 
+ }
+ 
+ void JabberClient::setOSName ( const QString &osName )
+ {
+ 
+-	m_osName = osName;
++	d->osName = osName;
+ 
+ }
+ 
+ QString JabberClient::osName () const
+ {
+ 
+-	return m_osName;
++	return d->osName;
+ 
+ }
+ 
++void JabberClient::setCapsNode( const QString &capsNode )
++{
++	d->capsNode = capsNode;
++}
++
++QString JabberClient::capsNode() const
++{
++	return d->capsNode;
++}
++
++void JabberClient::setCapsVersion( const QString &capsVersion )
++{
++	d->capsVersion = capsVersion;
++}
++
++QString JabberClient::capsVersion() const
++{
++	return d->capsVersion;
++}
++
++QString JabberClient::capsExt() const
++{
++	if(d->jabberClient)
++	{
++		return d->jabberClient->capsExt();
++	}
++
++	return QString();
++}
++void JabberClient::setDiscoIdentity( DiscoItem::Identity identity )
++{
++	d->discoIdentity = identity;
++}
++
++DiscoItem::Identity JabberClient::discoIdentity() const
++{
++	return d->discoIdentity;
++}
++
+ void JabberClient::setTimeZone ( const QString &timeZoneName, int timeZoneOffset )
+ {
+ 
+-	m_timeZoneName = timeZoneName;
+-	m_timeZoneOffset = timeZoneOffset;
++	d->timeZoneName = timeZoneName;
++	d->timeZoneOffset = timeZoneOffset;
+ 
+ }
+ 
+ QString JabberClient::timeZoneName () const
+ {
+ 
+-	return m_timeZoneName;
++	return d->timeZoneName;
+ 
+ }
+ 
+ int JabberClient::timeZoneOffset () const
+ {
+ 
+-	return m_timeZoneOffset;
++	return d->timeZoneOffset;
+ 
+ }
+ 
+ int JabberClient::getPenaltyTime ()
+ {
+ 
+-	int currentTime = m_currentPenaltyTime;
++	int currentTime = d->currentPenaltyTime;
+ 
+-	m_currentPenaltyTime += JABBER_PENALTY_TIME;
++	d->currentPenaltyTime += JABBER_PENALTY_TIME;
+ 
+ 	return currentTime;
+ 
+@@ -417,21 +534,21 @@
+ XMPP::Client *JabberClient::client () const
+ {
+ 
+-	return m_jabberClient;
++	return d->jabberClient;
+ 
+ }
+ 
+ XMPP::ClientStream *JabberClient::clientStream () const
+ {
+ 
+-	return m_jabberClientStream;
++	return d->jabberClientStream;
+ 
+ }
+ 
+ JabberConnector *JabberClient::clientConnector () const
+ {
+ 
+-	return m_jabberClientConnector;
++	return d->jabberClientConnector;
+ 
+ }
+ 
+@@ -466,7 +583,7 @@
+ XMPP::Jid JabberClient::jid () const
+ {
+ 
+-	return m_jid;
++	return d->jid;
+ 
+ }
+ 
+@@ -475,13 +592,13 @@
+ 	/*
+ 	 * Close any existing connection.
+ 	 */
+-	if ( m_jabberClient )
++	if ( d->jabberClient )
+ 	{
+-		m_jabberClient->close ();
++		d->jabberClient->close ();
+ 	}
+ 
+-	m_jid = jid;
+-	m_password = password;
++	d->jid = jid;
++	d->password = password;
+ 
+ 	/*
+ 	 * Return an error if we should force TLS but it's not available.
+@@ -496,18 +613,18 @@
+ 	 * This class uses KDE's socket code, which in turn makes use of
+ 	 * the global proxy settings.
+ 	 */
+-	m_jabberClientConnector = new JabberConnector;
++	d->jabberClientConnector = new JabberConnector;
+ 
+-	m_jabberClientConnector->setOptSSL ( useSSL () );
++	d->jabberClientConnector->setOptSSL ( useSSL () );
+ 
+ 	if ( useXMPP09 () )
+ 	{
+ 		if ( overrideHost () )
+ 		{
+-			m_jabberClientConnector->setOptHostPort ( m_server, m_port );
++			d->jabberClientConnector->setOptHostPort ( d->server, d->port );
+ 		}
+ 
+-		m_jabberClientConnector->setOptProbe ( probeSSL () );
++		d->jabberClientConnector->setOptProbe ( probeSSL () );
+ 
+ 	}
+ 
+@@ -516,56 +633,56 @@
+ 	 */
+ 	if ( QCA::isSupported ( QCA::CAP_TLS ) )
+ 	{
+-		m_jabberTLS = new QCA::TLS;
+-		m_jabberTLSHandler = new XMPP::QCATLSHandler ( m_jabberTLS );
++		d->jabberTLS = new QCA::TLS;
++		d->jabberTLSHandler = new XMPP::QCATLSHandler ( d->jabberTLS );
+ 
+ 		{
+ 			using namespace XMPP;
+-			QObject::connect ( m_jabberTLSHandler, SIGNAL ( tlsHandshaken() ), this, SLOT ( slotTLSHandshaken () ) );
++			QObject::connect ( d->jabberTLSHandler, SIGNAL ( tlsHandshaken() ), this, SLOT ( slotTLSHandshaken () ) );
+ 		}
+ 
+ 		QPtrList<QCA::Cert> certStore;
+-		m_jabberTLS->setCertificateStore ( certStore );
++		d->jabberTLS->setCertificateStore ( certStore );
+ 	}
+ 
+ 	/*
+ 	 * Instantiate client stream which handles the network communication by referring
+ 	 * to a connector (proxying etc.) and a TLS handler (security layer)
+ 	 */
+-	m_jabberClientStream = new XMPP::ClientStream ( m_jabberClientConnector, m_jabberTLSHandler );
++	d->jabberClientStream = new XMPP::ClientStream ( d->jabberClientConnector, d->jabberTLSHandler );
+ 
+ 	{
+ 		using namespace XMPP;
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( needAuthParams(bool, bool, bool) ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( needAuthParams(bool, bool, bool) ),
+ 				   this, SLOT ( slotCSNeedAuthParams (bool, bool, bool) ) );
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( authenticated () ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( authenticated () ),
+ 				   this, SLOT ( slotCSAuthenticated () ) );
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( connectionClosed () ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( connectionClosed () ),
+ 				   this, SLOT ( slotCSDisconnected () ) );
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( delayedCloseFinished () ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( delayedCloseFinished () ),
+ 				   this, SLOT ( slotCSDisconnected () ) );
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( warning (int) ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( warning (int) ),
+ 				   this, SLOT ( slotCSWarning (int) ) );
+-		QObject::connect ( m_jabberClientStream, SIGNAL ( error (int) ),
++		QObject::connect ( d->jabberClientStream, SIGNAL ( error (int) ),
+ 				   this, SLOT ( slotCSError (int) ) );
+ 	}
+ 
+-	m_jabberClientStream->setOldOnly ( useXMPP09 () );
++	d->jabberClientStream->setOldOnly ( useXMPP09 () );
+ 
+ 	/*
+ 	 * Initiate anti-idle timer (will be triggered every 55 seconds).
+ 	 */
+-	m_jabberClientStream->setNoopTime ( 55000 );
++	d->jabberClientStream->setNoopTime ( 55000 );
+ 
+ 	/*
+ 	 * Allow plaintext password authentication or not?
+ 	 */
+-	m_jabberClientStream->setAllowPlain( allowPlainTextPassword () );
++	d->jabberClientStream->setAllowPlain( allowPlainTextPassword () );
+ 
+ 	/*
+ 	 * Setup client layer.
+ 	 */
+-	m_jabberClient = new XMPP::Client ( this );
++	d->jabberClient = new XMPP::Client ( this );
+ 
+ 	/*
+ 	 * Enable file transfer (IP and server will be set after connection
+@@ -573,11 +690,11 @@
+ 	 */
+ 	if ( fileTransfersEnabled () )
+ 	{
+-		m_jabberClient->setFileTransferEnabled ( true );
++		d->jabberClient->setFileTransferEnabled ( true );
+ 
+ 		{
+ 			using namespace XMPP;
+-			QObject::connect ( m_jabberClient->fileTransferManager(), SIGNAL ( incomingReady() ),
++			QObject::connect ( d->jabberClient->fileTransferManager(), SIGNAL ( incomingReady() ),
+ 					   this, SLOT ( slotIncomingFileTransfer () ) );
+ 		}
+ 	}
+@@ -587,46 +704,53 @@
+ 	 */
+ 	{
+ 		using namespace XMPP;
+-		QObject::connect ( m_jabberClient, SIGNAL ( subscription (const Jid &, const QString &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( subscription (const Jid &, const QString &) ),
+ 				   this, SLOT ( slotSubscription (const Jid &, const QString &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( rosterRequestFinished ( bool, int, const QString & ) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( rosterRequestFinished ( bool, int, const QString & ) ),
+ 				   this, SLOT ( slotRosterRequestFinished ( bool, int, const QString & ) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( rosterItemAdded (const RosterItem &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( rosterItemAdded (const RosterItem &) ),
+ 				   this, SLOT ( slotNewContact (const RosterItem &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( rosterItemUpdated (const RosterItem &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( rosterItemUpdated (const RosterItem &) ),
+ 				   this, SLOT ( slotContactUpdated (const RosterItem &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( rosterItemRemoved (const RosterItem &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( rosterItemRemoved (const RosterItem &) ),
+ 				   this, SLOT ( slotContactDeleted (const RosterItem &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( resourceAvailable (const Jid &, const Resource &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( resourceAvailable (const Jid &, const Resource &) ),
+ 				   this, SLOT ( slotResourceAvailable (const Jid &, const Resource &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( resourceUnavailable (const Jid &, const Resource &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( resourceUnavailable (const Jid &, const Resource &) ),
+ 				   this, SLOT ( slotResourceUnavailable (const Jid &, const Resource &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( messageReceived (const Message &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( messageReceived (const Message &) ),
+ 				   this, SLOT ( slotReceivedMessage (const Message &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( groupChatJoined (const Jid &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( groupChatJoined (const Jid &) ),
+ 				   this, SLOT ( slotGroupChatJoined (const Jid &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( groupChatLeft (const Jid &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( groupChatLeft (const Jid &) ),
+ 				   this, SLOT ( slotGroupChatLeft (const Jid &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( groupChatPresence (const Jid &, const Status &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( groupChatPresence (const Jid &, const Status &) ),
+ 				   this, SLOT ( slotGroupChatPresence (const Jid &, const Status &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( groupChatError (const Jid &, int, const QString &) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( groupChatError (const Jid &, int, const QString &) ),
+ 				   this, SLOT ( slotGroupChatError (const Jid &, int, const QString &) ) );
+-		//QObject::connect ( m_jabberClient, SIGNAL (debugText (const QString &) ),
++		//QObject::connect ( d->jabberClient, SIGNAL (debugText (const QString &) ),
+ 		//		   this, SLOT ( slotPsiDebug (const QString &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( xmlIncoming(const QString& ) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( xmlIncoming(const QString& ) ),
+ 				   this, SLOT ( slotIncomingXML (const QString &) ) );
+-		QObject::connect ( m_jabberClient, SIGNAL ( xmlOutgoing(const QString& ) ),
++		QObject::connect ( d->jabberClient, SIGNAL ( xmlOutgoing(const QString& ) ),
+ 				   this, SLOT ( slotOutgoingXML (const QString &) ) );
+ 	}
+ 
+-	m_jabberClient->setClientName ( clientName () );
+-	m_jabberClient->setClientVersion ( clientVersion () );
+-	m_jabberClient->setOSName ( osName () );
++	d->jabberClient->setClientName ( clientName () );
++	d->jabberClient->setClientVersion ( clientVersion () );
++	d->jabberClient->setOSName ( osName () );
+ 
+-	m_jabberClient->setTimeZone ( timeZoneName (), timeZoneOffset () );
++	// Set caps information
++	d->jabberClient->setCapsNode( capsNode() );
++	d->jabberClient->setCapsVersion( capsVersion() );
++	
++	// Set Disco Identity
++	d->jabberClient->setIdentity( discoIdentity() );
+ 
+-	m_jabberClient->connectToServer ( m_jabberClientStream, jid, auth );
++	d->jabberClient->setTimeZone ( timeZoneName (), timeZoneOffset () );
+ 
++	d->jabberClient->connectToServer ( d->jabberClientStream, jid, auth );
++
+ 	return Ok;
+ 
+ }
+@@ -634,9 +758,9 @@
+ void JabberClient::disconnect ()
+ {
+ 
+-	if ( m_jabberClient )
++	if ( d->jabberClient )
+ 	{
+-		m_jabberClient->close ();
++		d->jabberClient->close ();
+ 	}
+ 	else
+ 	{
+@@ -645,12 +769,33 @@
+ 
+ }
+ 
++void JabberClient::disconnect( XMPP::Status &reason )
++{
++    if ( d->jabberClient )
++    {
++        if ( d->jabberClientStream->isActive() )
++        {
++            XMPP::JT_Presence *pres = new JT_Presence(rootTask());
++            reason.setIsAvailable( false );
++            pres->pres( reason );
++            pres->go();
++            
++            d->jabberClientStream->close();
++            d->jabberClient->close();
++        }
++    }
++    else
++    {
++        cleanUp();
++    }
++}
++
+ bool JabberClient::isConnected () const
+ {
+ 
+-	if ( m_jabberClient )
++	if ( d->jabberClient )
+ 	{
+-		return m_jabberClient->isActive ();
++		return d->jabberClient->isActive ();
+ 	}
+ 
+ 	return false;
+@@ -664,6 +809,13 @@
+ 
+ }
+ 
++void JabberClient::joinGroupChat ( const QString &host, const QString &room, const QString &nick, const QString &password )
++{
++
++	client()->groupChatJoin ( host, room, nick, password );
++
++}
++
+ void JabberClient::leaveGroupChat ( const QString &host, const QString &room )
+ {
+ 
+@@ -671,6 +823,17 @@
+ 
+ }
+ 
++void JabberClient::setGroupChatStatus( const QString & host, const QString & room, const XMPP::Status & status )
++{
++	client()->groupChatSetStatus( host, room, status);
++}
++
++void JabberClient::changeGroupChatNick( const QString & host, const QString & room, const QString & nick, const XMPP::Status & status )
++{
++	client()->groupChatChangeNick( host, room, nick, status );
++}
++
++
+ void JabberClient::sendMessage ( const XMPP::Message &message )
+ {
+ 
+@@ -731,14 +894,14 @@
+ 	emit debugMessage ( "TLS handshake done, testing certificate validity..." );
+ 
+ 	// FIXME: in the future, this should be handled by KDE, not QCA
+-	int validityResult = m_jabberTLS->certificateValidityResult ();
++	int validityResult = d->jabberTLS->certificateValidityResult ();
+ 
+ 	if ( validityResult == QCA::TLS::Valid )
+ 	{
+ 		emit debugMessage ( "Certificate is valid, continuing." );
+ 
+ 		// valid certificate, continue
+-		m_jabberTLSHandler->continueAfterHandshake ();
++		d->jabberTLSHandler->continueAfterHandshake ();
+ 	}
+ 	else
+ 	{
+@@ -748,7 +911,7 @@
+ 		if ( ignoreTLSWarnings () )
+ 		{
+ 			emit debugMessage ( "We are supposed to ignore TLS warnings, continuing." );
+-			m_jabberTLSHandler->continueAfterHandshake ();
++			d->jabberTLSHandler->continueAfterHandshake ();
+ 		}
+ 
+ 		emit tlsWarning ( validityResult );
+@@ -759,9 +922,9 @@
+ void JabberClient::continueAfterTLSWarning ()
+ {
+ 
+-	if ( m_jabberTLSHandler )
++	if ( d->jabberTLSHandler )
+ 	{
+-		m_jabberTLSHandler->continueAfterHandshake ();
++		d->jabberTLSHandler->continueAfterHandshake ();
+ 	}
+ 
+ }
+@@ -772,20 +935,20 @@
+ 
+ 	if ( user )
+ 	{
+-		m_jabberClientStream->setUsername ( jid().node () );
++		d->jabberClientStream->setUsername ( jid().node () );
+ 	}
+ 
+ 	if ( pass )
+ 	{
+-		m_jabberClientStream->setPassword ( m_password );
++		d->jabberClientStream->setPassword ( d->password );
+ 	}
+ 
+ 	if ( realm )
+ 	{
+-		m_jabberClientStream->setRealm ( jid().domain () );
++		d->jabberClientStream->setRealm ( jid().domain () );
+ 	}
+ 
+-	m_jabberClientStream->continueAfterParams ();
++	d->jabberClientStream->continueAfterParams ();
+ 
+ }
+ 
+@@ -800,17 +963,17 @@
+ 	if ( localAddress().isEmpty () )
+ 	{
+ 		// code for Iris-type bytestreams
+-		ByteStream *irisByteStream = m_jabberClientConnector->stream();
++		ByteStream *irisByteStream = d->jabberClientConnector->stream();
+ 		if ( irisByteStream->inherits ( "BSocket" ) || irisByteStream->inherits ( "XMPP::BSocket" ) )
+ 		{
+-			m_localAddress = ( (BSocket *)irisByteStream )->address().toString ();
++			d->localAddress = ( (BSocket *)irisByteStream )->address().toString ();
+ 		}
+ 
+ 		// code for the KDE-type bytestream
+-		JabberByteStream *kdeByteStream = dynamic_cast<JabberByteStream*>(m_jabberClientConnector->stream());
++		JabberByteStream *kdeByteStream = dynamic_cast<JabberByteStream*>(d->jabberClientConnector->stream());
+ 		if ( kdeByteStream )
+ 		{
+-			m_localAddress = kdeByteStream->socket()->localAddress().nodeName ();
++			d->localAddress = kdeByteStream->socket()->localAddress().nodeName ();
+ 		}
+ 	}
+ 
+@@ -818,11 +981,11 @@
+ 	{
+ 		// setup file transfer
+ 		addS5BServerAddress ( localAddress () );
+-		m_jabberClient->s5bManager()->setServer ( s5bServer () );
++		d->jabberClient->s5bManager()->setServer ( s5bServer () );
+ 	}
+ 
+ 	// start the client operation
+-	m_jabberClient->start ( jid().domain (), jid().node (), m_password, jid().resource () );
++	d->jabberClient->start ( jid().domain (), jid().node (), d->password, jid().resource () );
+ 
+ 	emit connected ();
+ }
+@@ -866,7 +1029,7 @@
+ 			break;
+ 	}
+ 
+-	m_jabberClientStream->continueAfterWarning ();
++	d->jabberClientStream->continueAfterWarning ();
+ 
+ }
+ 
+@@ -970,4 +1133,5 @@
+ 
+ }
+ 
++
+ #include "jabberclient.moc"
+--- kopete/protocols/jabber/jingle/jinglevoicesession.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicesession.cpp	(revision 586398)
+@@ -0,0 +1,333 @@
++/*
++    jinglevoicesession.cpp - Define a Jingle voice session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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.                                   *
++    *                                                                       *
++    *************************************************************************
++*/
++
++// libjingle before everything else to not clash with Qt
++#define POSIX
++#include "talk/xmpp/constants.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/jid.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/base/network.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/base/physicalsocketserver.h"
++#include "talk/base/thread.h"
++#include "talk/base/socketaddress.h"
++#include "talk/session/phone/call.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/session/sessionsendtask.h"
++
++#include "jinglevoicesession.h"
++#include "jinglesessionmanager.h"
++
++// Qt includes
++#include <qdom.h>
++
++// KDE includes
++#include <kdebug.h>
++
++// Kopete Jabber includes
++#include "jabberaccount.h"
++#include "jabberprotocol.h"
++
++#include <xmpp.h>
++#include <xmpp_xmlcommon.h>
++
++#define JINGLE_NS "http://www.google.com/session"
++#define JINGLE_VOICE_SESSION_NS "http://www.google.com/session/phone"
++
++static bool hasPeer(const JingleVoiceSession::JidList &jidList, const XMPP::Jid &peer)
++{
++	JingleVoiceSession::JidList::ConstIterator it, itEnd = jidList.constEnd();
++	for(it = jidList.constBegin(); it != itEnd; ++it)
++	{
++		if( (*it).compare(peer, true) )
++			return true;
++	}
++
++	return false;
++}
++//BEGIN SlotsProxy
++/**
++ * This class is used to receive signals from libjingle, 
++ * which is are not compatible with Qt signals.
++ * So it's a proxy between JingeVoiceSession(qt)<->linjingle class.
++ */
++class JingleVoiceSession::SlotsProxy : public sigslot::has_slots<> 
++{
++public:
++	SlotsProxy(JingleVoiceSession *parent)
++	 : voiceSession(parent)
++	{}
++	
++	void OnCallCreated(cricket::Call* call)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "SlotsProxy: CallCreated." << endl;
++
++		call->SignalSessionState.connect(this, &JingleVoiceSession::SlotsProxy::PhoneSessionStateChanged);
++		voiceSession->setCall(call);
++	}
++		
++	void PhoneSessionStateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "State changed: " << state << endl;
++
++		XMPP::Jid jid(session->remote_address().c_str());
++		
++		// Do nothing if the session do not contain a peers.
++		//if( !voiceSession->peers().contains(jid) )
++		if( !hasPeer(voiceSession->peers(), jid) )
++			return;
++
++		if (state == cricket::Session::STATE_INIT) 
++		{}
++		else if (state == cricket::Session::STATE_SENTINITIATE) 
++		{}
++		else if (state == cricket::Session::STATE_RECEIVEDINITIATE) 
++		{
++			voiceSession->setCall(call);
++		}
++		else if (state == cricket::Session::STATE_SENTACCEPT) 
++		{}
++		else if (state == cricket::Session::STATE_RECEIVEDACCEPT) 
++		{
++			emit voiceSession->accepted();
++		}
++		else if (state == cricket::Session::STATE_SENTMODIFY) 
++		{}
++		else if (state == cricket::Session::STATE_RECEIVEDMODIFY) 
++		{
++			//qWarning(QString("jinglevoicecaller.cpp: RECEIVEDMODIFY not implemented yet (was from %1)").arg(jid.full()));
++		}
++		else if (state == cricket::Session::STATE_SENTREJECT) 
++		{}
++		else if (state == cricket::Session::STATE_RECEIVEDREJECT) 
++		{
++			emit voiceSession->declined();
++		}
++		else if (state == cricket::Session::STATE_SENTREDIRECT) 
++		{}
++		else if (state == cricket::Session::STATE_SENTTERMINATE) 
++		{
++			emit voiceSession->terminated();
++		}
++		else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) 
++		{
++			emit voiceSession->terminated();
++		}
++		else if (state == cricket::Session::STATE_INPROGRESS) 
++		{
++			emit voiceSession->sessionStarted();
++		}
++	}
++
++	void OnSendingStanza(cricket::SessionClient*, const buzz::XmlElement *buzzStanza)
++	{
++		QString irisStanza(buzzStanza->Str().c_str());
++		irisStanza.replace("cli:iq","iq");
++		irisStanza.replace(":cli=","=");
++	
++		voiceSession->sendStanza(irisStanza);
++	}
++private:
++	JingleVoiceSession *voiceSession;
++};
++//END SlotsProxy
++
++//BEGIN JingleIQResponder
++class JingleVoiceSession::JingleIQResponder : public XMPP::Task
++{
++public:
++	JingleIQResponder(XMPP::Task *);
++	~JingleIQResponder();
++
++	bool take(const QDomElement &);
++};
++
++/**
++ * \class JingleIQResponder
++ * \brief A task that responds to jingle candidate queries with an empty reply.
++ */
++ 
++JingleVoiceSession::JingleIQResponder::JingleIQResponder(Task *parent) :Task(parent)
++{
++}
++
++JingleVoiceSession::JingleIQResponder::~JingleIQResponder()
++{
++}
++
++bool JingleVoiceSession::JingleIQResponder::take(const QDomElement &e)
++{
++	if(e.tagName() != "iq")
++		return false;
++	
++	QDomElement first = e.firstChild().toElement();
++	if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) {
++		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
++		send(iq);
++		return true;
++	}
++	
++	return false;
++}
++//END JingleIQResponder
++
++class JingleVoiceSession::Private
++{
++public:
++	Private()
++	 : phoneSessionClient(0L), currentCall(0L)
++	{}
++
++	~Private()
++	{
++		if(currentCall)
++			currentCall->Terminate();
++
++		delete currentCall;
++	}
++
++	cricket::PhoneSessionClient *phoneSessionClient;
++	cricket::Call* currentCall;
++};
++
++JingleVoiceSession::JingleVoiceSession(JabberAccount *account, const JidList &peers)
++ : JingleSession(account, peers), d(new Private)
++{
++	slotsProxy = new SlotsProxy(this);
++
++	buzz::Jid buzzJid( account->client()->jid().full().ascii() );
++
++	// Create the phone(voice) session.
++	d->phoneSessionClient = new cricket::PhoneSessionClient( buzzJid, account->sessionManager()->cricketSessionManager() );
++
++	d->phoneSessionClient->SignalSendStanza.connect(slotsProxy, &JingleVoiceSession::SlotsProxy::OnSendingStanza);
++	d->phoneSessionClient->SignalCallCreate.connect(slotsProxy, &JingleVoiceSession::SlotsProxy::OnCallCreated);
++
++	// Listen to incoming packets
++	connect(account->client()->client(), SIGNAL(xmlIncoming(const QString&)), this, SLOT(receiveStanza(const QString&)));
++
++	new JingleIQResponder(account->client()->rootTask());
++}
++
++JingleVoiceSession::~JingleVoiceSession()
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++	delete slotsProxy;
++	delete d;
++}
++
++QString JingleVoiceSession::sessionType()
++{
++	return QString(JINGLE_VOICE_SESSION_NS);
++}
++
++void JingleVoiceSession::start()
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Starting a voice session..." << endl;
++	d->currentCall = d->phoneSessionClient->CreateCall();
++
++	QString firstPeerJid = ((XMPP::Jid)peers().first()).full();
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "With peer: " << firstPeerJid << endl;
++	d->currentCall->InitiateSession( buzz::Jid(firstPeerJid.ascii()) );
++
++	d->phoneSessionClient->SetFocus(d->currentCall);
++}
++
++void JingleVoiceSession::accept()
++{	
++	if(d->currentCall)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Accepting a voice session..." << endl;
++
++		d->currentCall->AcceptSession(d->currentCall->sessions()[0]);
++		d->phoneSessionClient->SetFocus(d->currentCall);
++	}
++}
++
++void JingleVoiceSession::decline()
++{
++	if(d->currentCall)
++	{
++		d->currentCall->RejectSession(d->currentCall->sessions()[0]);
++	}
++}
++
++void JingleVoiceSession::terminate()
++{
++	if(d->currentCall)
++	{
++		d->currentCall->Terminate();
++	}
++}
++
++void JingleVoiceSession::setCall(cricket::Call *call)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating cricket::call object." << endl;
++	d->currentCall = call;
++	d->phoneSessionClient->SetFocus(d->currentCall);
++}
++
++void JingleVoiceSession::receiveStanza(const QString &stanza)
++{
++	QDomDocument doc;
++	doc.setContent(stanza);
++
++	// Check if it is offline presence from an open chat
++	if( doc.documentElement().tagName() == "presence" ) 
++	{
++		XMPP::Jid from = XMPP::Jid(doc.documentElement().attribute("from"));
++		QString type = doc.documentElement().attribute("type");
++		if( type == "unavailable" && hasPeer(peers(), from) ) 
++		{
++			//qDebug("JingleVoiceCaller: User went offline without closing a call.");
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "User went offline without closing a call." << endl;
++			emit terminated();
++		}
++		return;
++	}
++	
++	// Check if the packet is destined for libjingle.
++	// We could use Session::IsClientStanza to check this, but this one crashes
++	// for some reason.
++	QDomNode node = doc.documentElement().firstChild();
++	bool ok = false;
++	while( !node.isNull() && !ok ) 
++	{
++		QDomElement element = node.toElement();
++		if( !element.isNull() && element.attribute("xmlns") == JINGLE_NS) 
++		{
++			ok = true;
++		}
++		node = node.nextSibling();
++	}
++	
++	// Spread the word
++	if( ok )
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Handing down buzz::stanza" << endl;
++		buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii());
++		d->phoneSessionClient->OnIncomingStanza(e);
++	}
++}
++
++#include "jinglevoicesession.moc"
+--- kopete/protocols/jabber/jingle/jinglevoicesession.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicesession.h	(revision 586398)
+@@ -0,0 +1,70 @@
++/*
++    jinglevoicesession.h - Define a Jingle voice session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 JINGLEVOICESESSION_H
++#define JINGLEVOICESESSION_H
++
++#include <jinglesession.h>
++
++#include <xmpp.h> // XMPP::Jid
++#include <qvaluelist.h>
++
++namespace cricket
++{
++	class Call;
++}
++
++class JabberAccount;
++class JingleSession;
++
++/**
++ * Implement a Jingle voice peer-to-peer session that is compatible with Google Talk voice offering.
++ *
++ * @author Michaël Larouche
++*/
++class JingleVoiceSession : public JingleSession
++{
++	Q_OBJECT
++public:
++	typedef QValueList<XMPP::Jid> JidList;
++
++	JingleVoiceSession(JabberAccount *account, const JidList &peers);
++	virtual ~JingleVoiceSession();
++
++	virtual QString sessionType();
++
++public slots:
++	virtual void accept();
++	virtual void decline();
++	virtual void start();
++	virtual void terminate();
++
++protected slots:
++	void receiveStanza(const QString &stanza);
++
++private:
++	void setCall(cricket::Call *call);
++
++	class Private;
++	Private *d;
++
++	class SlotsProxy;
++	SlotsProxy *slotsProxy;
++	
++	class JingleIQResponder;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/jinglesessionmanager.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglesessionmanager.cpp	(revision 586398)
+@@ -0,0 +1,205 @@
++/*
++    jinglesessionmanager.cpp - Manage Jingle sessions.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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.                                   *
++    *                                                                       *
++    *************************************************************************
++*/
++// libjingle before everything else to not clash with Qt
++#define POSIX
++#include "talk/xmpp/constants.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/jid.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/base/network.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/base/physicalsocketserver.h"
++#include "talk/base/thread.h"
++#include "talk/base/socketaddress.h"
++#include "talk/session/phone/call.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/session/sessionsendtask.h"
++
++
++#include "jinglesessionmanager.h"
++
++//#include "jinglesession.h"
++#include "jinglevoicesession.h"
++
++#include "jinglewatchsessiontask.h"
++
++#include "jabberaccount.h"
++#include "jabberprotocol.h"
++
++#include <kdebug.h>
++
++#define JINGLE_NS "http://www.google.com/session"
++#define JINGLE_VOICE_SESSION_NS "http://www.google.com/session/phone"
++
++//BEGIN JingleSessionManager::SlotsProxy
++class JingleSessionManager;
++class JingleSessionManager::SlotsProxy : public sigslot::has_slots<>
++{
++public:
++	SlotsProxy(JingleSessionManager *parent)
++	 : sessionManager(parent)
++	{}
++	
++	void OnSignalingRequest()
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Requesting Jingle signaling." << endl;
++		sessionManager->cricketSessionManager()->OnSignalingReady();
++	}
++	
++	
++private:
++	JingleSessionManager *sessionManager;
++};
++
++//END JingleSessionManager::SlotsProxy
++
++//BEGIN JingleSessionManager::Private
++class JingeSession;
++class JingleSessionManager::Private
++{
++public:
++	Private(JabberAccount *t_account)
++	 : account(t_account), watchSessionTask(0L)
++	{}
++
++	~Private()
++	{
++		delete networkManager;
++		delete portAllocator;
++		delete sessionThread;
++		delete cricketSessionManager;
++	}
++	
++	JabberAccount *account;
++	QValueList<JingleSession*> sessionList;
++	JingleWatchSessionTask *watchSessionTask;
++
++	cricket::NetworkManager *networkManager;
++	cricket::BasicPortAllocator *portAllocator;
++	cricket::Thread *sessionThread;
++	cricket::SessionManager *cricketSessionManager;
++};
++//END JingleSessionManager::Private
++
++JingleSessionManager::JingleSessionManager(JabberAccount *account)
++ : QObject(account, 0), d(new Private(account))
++{
++	// Create slots proxy for libjingle
++	slotsProxy = new SlotsProxy(this);
++
++	// Create watch incoming session task.
++	d->watchSessionTask = new JingleWatchSessionTask(account->client()->rootTask());
++	connect(d->watchSessionTask, SIGNAL(watchSession(const QString &, const QString &)), this, SLOT(slotIncomingSession(const QString &, const QString &)));
++
++	// Create global cricket variables common to all sessions.
++	// Seed random generation with the JID of the account.
++	QString accountJid = account->client()->jid().full();
++	cricket::InitRandom( accountJid.ascii(), accountJid.length() );
++
++	// Create the libjingle NetworkManager that manager local network connections
++	d->networkManager = new cricket::NetworkManager();
++	
++	// Init the port allocator(select best ports) with the Google STUN server to help.
++	cricket::SocketAddress *googleStunAddress = new cricket::SocketAddress("64.233.167.126", 19302);
++	// TODO: Define a relay server.
++  	d->portAllocator = new cricket::BasicPortAllocator(d->networkManager, googleStunAddress, 0L);
++
++	// Create the Session manager that manager peer-to-peer sessions.
++	d->sessionThread = new cricket::Thread();
++	d->cricketSessionManager = new cricket::SessionManager(d->portAllocator, d->sessionThread);
++	d->cricketSessionManager->SignalRequestSignaling.connect(slotsProxy, &JingleSessionManager::SlotsProxy::OnSignalingRequest);
++	d->cricketSessionManager->OnSignalingReady();
++
++	d->sessionThread->Start();
++}
++
++JingleSessionManager::~JingleSessionManager()
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Cleaning up Jingle sessions." << endl;
++	QValueList<JingleSession*>::Iterator it, itEnd = d->sessionList.end();
++	for(it = d->sessionList.begin(); it != itEnd; ++it)
++	{
++		JingleSession *deletedSession = *it;
++		if( deletedSession )
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "deleting a session." << endl;
++			delete deletedSession;
++		}
++	}
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Done Cleaning up Jingle sessions." << endl;
++
++	delete d;
++}
++
++cricket::SessionManager *JingleSessionManager::cricketSessionManager()
++{
++	return d->cricketSessionManager;
++}
++
++JabberAccount *JingleSessionManager::account()
++{
++	return d->account;
++}
++
++JingleSession *JingleSessionManager::createSession(const QString &sessionType, const JidList &peers)
++{	
++	JingleSession *newSession = 0L;
++
++	if(sessionType == JINGLE_VOICE_SESSION_NS)
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Creating a voice session" << endl;
++		newSession = new JingleVoiceSession(account(), peers);
++	}
++	
++	if(newSession)
++		d->sessionList.append(newSession);
++
++	return newSession;
++}
++
++JingleSession *JingleSessionManager::createSession(const QString &sessionType, const XMPP::Jid &user)
++{
++	JingleSessionManager::JidList jidList;
++	jidList.append(user);
++	
++	return createSession(sessionType, jidList);
++}
++
++void JingleSessionManager::removeSession(JingleSession *session)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing a jingle session." << endl;
++
++	d->sessionList.remove(session);
++	delete session;	
++}
++
++void JingleSessionManager::slotIncomingSession(const QString &sessionType, const QString &initiator)
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Incoming session: " << sessionType << ". Initiator: " << initiator << endl;
++
++	JingleSession *newSession = createSession(sessionType, XMPP::Jid(initiator));
++	emit incomingSession(sessionType, newSession);
++}
++
++#include "jinglesessionmanager.moc"
+--- kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui	(revision 586398)
+@@ -0,0 +1,369 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>JingleVoiceSessionDialogBase</class>
++<widget class="QDialog">
++    <property name="name">
++        <cstring>JingleVoiceSessionDialogBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>329</width>
++            <height>188</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>JabberVoiceSessionDialogBase</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout8</cstring>
++            </property>
++            <vbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout5</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer9</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>16</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>textLabel1</cstring>
++                            </property>
++                            <property name="text">
++                                <string>Voice session with:</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer10</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>20</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </hbox>
++                </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout4</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer7</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>16</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>labelContactPhoto</cstring>
++                            </property>
++                            <property name="sizePolicy">
++                                <sizepolicy>
++                                    <hsizetype>4</hsizetype>
++                                    <vsizetype>4</vsizetype>
++                                    <horstretch>0</horstretch>
++                                    <verstretch>0</verstretch>
++                                </sizepolicy>
++                            </property>
++                            <property name="maximumSize">
++                                <size>
++                                    <width>128</width>
++                                    <height>128</height>
++                                </size>
++                            </property>
++                            <property name="scaledContents">
++                                <bool>true</bool>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer8</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>16</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </hbox>
++                </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout7</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer11</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>40</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>labelDisplayName</cstring>
++                            </property>
++                            <property name="text">
++                                <string>Contact displayname</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer12</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>40</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </hbox>
++                </widget>
++            </vbox>
++        </widget>
++        <spacer>
++            <property name="name">
++                <cstring>spacer5</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>20</width>
++                    <height>16</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="Line">
++            <property name="name">
++                <cstring>line1</cstring>
++            </property>
++            <property name="frameShape">
++                <enum>HLine</enum>
++            </property>
++            <property name="frameShadow">
++                <enum>Sunken</enum>
++            </property>
++            <property name="orientation">
++                <enum>Horizontal</enum>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout1</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer1</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>40</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>buttonAccept</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>false</bool>
++                    </property>
++                    <property name="text">
++                        <string>Accep&amp;t</string>
++                    </property>
++                </widget>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>buttonDecline</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>false</bool>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Decline</string>
++                    </property>
++                </widget>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>buttonTerminate</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>false</bool>
++                    </property>
++                    <property name="text">
++                        <string>Termi&amp;nate</string>
++                    </property>
++                </widget>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer2</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>40</width>
++                            <height>20</height>
++                        </size>
++                    </property>
++                </spacer>
++            </hbox>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout3</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>textLabel4</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Current status:</string>
++                    </property>
++                </widget>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>labelSessionStatus</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>5</hsizetype>
++                            <vsizetype>7</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                    <property name="text">
++                        <string>Session status</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++        <spacer>
++            <property name="name">
++                <cstring>spacer5_2</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>20</width>
++                    <height>16</height>
++                </size>
++            </property>
++        </spacer>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/protocols/jabber/jingle/configure.in.in	(revision 0)
++++ kopete/protocols/jabber/jingle/configure.in.in	(revision 586398)
+@@ -0,0 +1,87 @@
++AC_DEFINE(PRODUCTION_BUILD, 1, [Build as a production build])
++AC_DEFINE(PRODUCTION, 1, [Build as a production build])
++AC_DEFINE(POSIX, 1, [If we're using configure, we're on POSIX])
++
++# Check if the user want Jabber Jingle voice support
++AC_ARG_ENABLE(jingle, [  --enable-jingle     enable Jabber Jingle voice support ],  with_jingle=$enableval, with_jingle=no)
++
++# Here we go
++HAVE_EXPAT=no
++AC_CHECK_LIB(expat, XML_ParserCreate, HAVE_EXPAT="yes")
++if test "x$HAVE_EXPAT" = xyes ; then
++  EXPAT_LIBS="-lexpat"
++  AC_SUBST(EXPAT_LIBS)
++else
++  with_jingle=no
++  AC_MSG_WARN([Expat is required to build Jabber Jingle voice support. You can get it from http://expat.sourceforge.net/])
++fi
++
++AC_CHECK_HEADERS(alsa/asoundlib.h,
++	[AC_CHECK_LIB(asound, snd_pcm_open,
++		[ALSA_LIBS="-lasound" ; AC_DEFINE(__ALSA_ENABLED__,1,[Defined when alsa support is enabled]) ])
++	]
++)
++AC_SUBST(ALSA_LIBS)
++
++# We test for GLIB in protocols/configure.in.in
++if test x$have_glib = xno; then
++	with_jingle=no
++fi
++
++PKG_CHECK_MODULES(ORTP, ortp, enable_ortp=yes, enable_ortp=no)
++if test x$enable_ortp = xno ; then
++      with_jingle=no
++      AC_MSG_WARN([oRTP is required to build Jabber Jingle voice support. You can get it from http://www.linphone.org/ortp/])
++fi 
++AC_SUBST(ORTP_CFLAGS)
++AC_SUBST(ORTP_LIBS)
++
++AC_ARG_WITH( speex,
++      [  --with-speex      Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ],
++      [ speex_prefix=${withval}],[ speex_prefix="/usr" ])
++
++PKG_CHECK_MODULES(SPEEX, speex, speex_found=yes, speex_found=no)
++AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)],speex_found=no)
++AC_CHECK_HEADERS(speex/speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)],speex_found=no)
++
++if test x$speex_found = xno; then
++	AC_MSG_WARN([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6 from http://www.speex.org/])
++else
++	SPEEX_CFLAGS="$SPEEX_CFLAGS -I${speex_prefix}/include -I${speex_prefix}/include/speex"
++	AC_SUBST(SPEEX_CFLAGS)
++	AC_SUBST(SPEEX_LIBS)
++	AC_DEFINE(HAVE_SPEEX,1,[Speex codec is enabled])
++fi
++
++
++# dnl only accept speex>=1.1.6 or 1.0.5 (the versions that have speex_encode_int )
++# AC_ARG_WITH( speex,
++#       [  --with-speex      Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ],
++#       [ speex_prefix=${withval}],[ speex_prefix="/usr" ])
++#                                                                                                                                      
++# AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)
++# ],speex_found=no)
++#                                                                                                                                      
++# if test "$speex_found" = "no" ; then
++# AC_MSG_WARN([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6 from http://www.speex.org/])
++# else
++# SPEEX_CFLAGS=" -I${speex_prefix}/include -I${speex_prefix}/include/speex"
++# SPEEX_LIBS="-L${speex_prefix}/lib -lspeex -lm"
++# CPPFLAGS_save=$CPPFLAGS
++# CPPFLAGS=$SPEEX_CFLAGS
++# LDFLAGS_save=$LDFLAGS
++# LDFLAGS=$SPEEX_LIBS
++# AC_DEFINE(HAVE_SPEEX,1,[has speex])
++# fi
++#                                                                                                                                      
++# AC_SUBST(SPEEX_CFLAGS)
++# AC_SUBST(SPEEX_LIBS)
++# CPPFLAGS=$CPPFLAGS_save
++# LDFLAGS=$LDFLAGS_save
++ilbc_found="no"
++
++AM_CONDITIONAL(include_jingle, test "$with_jingle" = "yes")
++
++if test "$with_jingle" = "yes" ; then
++	AC_DEFINE(SUPPORT_JINGLE,1,[Jingle support is enabled])
++fi
+--- kopete/protocols/jabber/jingle/jinglesessionmanager.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglesessionmanager.h	(revision 586398)
+@@ -0,0 +1,89 @@
++/*
++    jinglesessionmanager.h - Manage Jingle sessions.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 JINGLESESSIONMANAGER_H
++#define JINGLESESSIONMANAGER_H
++
++#include <xmpp.h>
++#include <im.h>
++
++#include <qobject.h>
++#include <qvaluelist.h>
++
++namespace cricket
++{
++	class SessionManager;
++}
++
++class JingleSession;
++class JingleVoiceSession;
++class JabberAccount;
++
++/**
++ * @brief Manage Jingle sessions. 
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
++class JingleSessionManager : public QObject
++{
++	Q_OBJECT
++public:
++	typedef QValueList<XMPP::Jid> JidList;
++
++	JingleSessionManager(JabberAccount *account);
++	~JingleSessionManager();
++
++	/**
++	 * Get the (single) instance of the cricket session manager.
++	 */
++	cricket::SessionManager *cricketSessionManager();
++
++	/**
++	 * Return the JabberAccount associated with this session manager.
++	 */
++	JabberAccount *account();
++
++public slots:
++	/**
++	 * Create a new Jingle session. Returned pointer is managed by this class.
++	 * @param sessionType the session you want to create. You must pass its XML namespace(ex: http://jabber.org/protocol/sessions/audio)
++	 * @param peers Lists of participants of the session.
++	 */
++	JingleSession *createSession(const QString &sessionType, const JidList &peers);
++	/**
++	 * Override method that create a session for a one-to-one session.
++	 * It behave like createSession method.
++	 * @param sessionType the sesion you want to create. You must pass its XML namespace(ex: http://jabber.org/protocol/sessions/audio)
++	 * @param user The JID of the user you want to begin a session with.
++	 */
++	JingleSession *createSession(const QString &sessionType, const XMPP::Jid &user);
++	
++	void removeSession(JingleSession *session);
++
++signals:
++	void incomingSession(const QString &sessionType, JingleSession *session);
++
++private slots:
++	void slotIncomingSession(const QString &sessionType, const QString &initiator);
++
++private:
++	class Private;
++	Private *d;
++
++	class SlotsProxy;
++	SlotsProxy *slotsProxy;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/jinglesession.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglesession.cpp	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++    jinglesession.h - Define a Jingle session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 "jinglesession.h"
++
++#include <kdebug.h>
++
++#include "jabberaccount.h"
++#include "jabberprotocol.h"
++
++class JingleSession::Private
++{
++public:
++	Private(JabberAccount *t_account, const JidList &t_peers)
++	 :  peers(t_peers), account(t_account)
++	{}
++
++	XMPP::Jid myself;
++	JidList peers;
++	JabberAccount *account;
++};
++
++JingleSession::JingleSession(JabberAccount *account, const JidList &peers)
++ : QObject(account, 0), d(new Private(account, peers))
++{
++	d->myself = account->client()->jid();
++}
++
++JingleSession::~JingleSession()
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++	delete d;
++}
++
++const XMPP::Jid &JingleSession::myself() const
++{
++	return d->myself;
++}
++
++const JingleSession::JidList &JingleSession::peers() const
++{
++	return d->peers;
++}
++
++JingleSession::JidList &JingleSession::peers()
++{
++	return d->peers;
++}
++JabberAccount *JingleSession::account()
++{
++	return d->account;
++}
++
++void JingleSession::sendStanza(const QString &stanza)
++{
++	account()->client()->send( stanza );
++}
++
++#include "jinglesession.moc"
+--- kopete/protocols/jabber/jingle/libjingle/AUTHORS	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/AUTHORS	(revision 586398)
+@@ -0,0 +1 @@
++Google Inc.
+--- kopete/protocols/jabber/jingle/libjingle/INSTALL	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/INSTALL	(revision 586398)
+@@ -0,0 +1,229 @@
++Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
++Foundation, Inc.
++
++   This file is free documentation; the Free Software Foundation gives
++unlimited permission to copy, distribute and modify it.
++
++Basic Installation
++==================
++
++   These are generic installation instructions.
++
++   The `configure' shell script attempts to guess correct values for
++various system-dependent variables used during compilation.  It uses
++those values to create a `Makefile' in each directory of the package.
++It may also create one or more `.h' files containing system-dependent
++definitions.  Finally, it creates a shell script `config.status' that
++you can run in the future to recreate the current configuration, and a
++file `config.log' containing compiler output (useful mainly for
++debugging `configure').
++
++   It can also use an optional file (typically called `config.cache'
++and enabled with `--cache-file=config.cache' or simply `-C') that saves
++the results of its tests to speed up reconfiguring.  (Caching is
++disabled by default to prevent problems with accidental use of stale
++cache files.)
++
++   If you need to do unusual things to compile the package, please try
++to figure out how `configure' could check whether to do them, and mail
++diffs or instructions to the address given in the `README' so they can
++be considered for the next release.  If you are using the cache, and at
++some point `config.cache' contains results you don't want to keep, you
++may remove or edit it.
++
++   The file `configure.ac' (or `configure.in') is used to create
++`configure' by a program called `autoconf'.  You only need
++`configure.ac' if you want to change it or regenerate `configure' using
++a newer version of `autoconf'.
++
++The simplest way to compile this package is:
++
++  1. `cd' to the directory containing the package's source code and type
++     `./configure' to configure the package for your system.  If you're
++     using `csh' on an old version of System V, you might need to type
++     `sh ./configure' instead to prevent `csh' from trying to execute
++     `configure' itself.
++
++     Running `configure' takes awhile.  While running, it prints some
++     messages telling which features it is checking for.
++
++  2. Type `make' to compile the package.
++
++  3. Optionally, type `make check' to run any self-tests that come with
++     the package.
++
++  4. Type `make install' to install the programs and any data files and
++     documentation.
++
++  5. You can remove the program binaries and object files from the
++     source code directory by typing `make clean'.  To also remove the
++     files that `configure' created (so you can compile the package for
++     a different kind of computer), type `make distclean'.  There is
++     also a `make maintainer-clean' target, but that is intended mainly
++     for the package's developers.  If you use it, you may have to get
++     all sorts of other programs in order to regenerate files that came
++     with the distribution.
++
++Compilers and Options
++=====================
++
++   Some systems require unusual options for compilation or linking that
++the `configure' script does not know about.  Run `./configure --help'
++for details on some of the pertinent environment variables.
++
++   You can give `configure' initial values for configuration parameters
++by setting variables in the command line or in the environment.  Here
++is an example:
++
++     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
++
++   *Note Defining Variables::, for more details.
++
++Compiling For Multiple Architectures
++====================================
++
++   You can compile the package for more than one kind of computer at the
++same time, by placing the object files for each architecture in their
++own directory.  To do this, you must use a version of `make' that
++supports the `VPATH' variable, such as GNU `make'.  `cd' to the
++directory where you want the object files and executables to go and run
++the `configure' script.  `configure' automatically checks for the
++source code in the directory that `configure' is in and in `..'.
++
++   If you have to use a `make' that does not support the `VPATH'
++variable, you have to compile the package for one architecture at a
++time in the source code directory.  After you have installed the
++package for one architecture, use `make distclean' before reconfiguring
++for another architecture.
++
++Installation Names
++==================
++
++   By default, `make install' will install the package's files in
++`/usr/local/bin', `/usr/local/man', etc.  You can specify an
++installation prefix other than `/usr/local' by giving `configure' the
++option `--prefix=PATH'.
++
++   You can specify separate installation prefixes for
++architecture-specific files and architecture-independent files.  If you
++give `configure' the option `--exec-prefix=PATH', the package will use
++PATH as the prefix for installing programs and libraries.
++Documentation and other data files will still use the regular prefix.
++
++   In addition, if you use an unusual directory layout you can give
++options like `--bindir=PATH' to specify different values for particular
++kinds of files.  Run `configure --help' for a list of the directories
++you can set and what kinds of files go in them.
++
++   If the package supports it, you can cause programs to be installed
++with an extra prefix or suffix on their names by giving `configure' the
++option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
++
++Optional Features
++=================
++
++   Some packages pay attention to `--enable-FEATURE' options to
++`configure', where FEATURE indicates an optional part of the package.
++They may also pay attention to `--with-PACKAGE' options, where PACKAGE
++is something like `gnu-as' or `x' (for the X Window System).  The
++`README' should mention any `--enable-' and `--with-' options that the
++package recognizes.
++
++   For packages that use the X Window System, `configure' can usually
++find the X include and library files automatically, but if it doesn't,
++you can use the `configure' options `--x-includes=DIR' and
++`--x-libraries=DIR' to specify their locations.
++
++Specifying the System Type
++==========================
++
++   There may be some features `configure' cannot figure out
++automatically, but needs to determine by the type of machine the package
++will run on.  Usually, assuming the package is built to be run on the
++_same_ architectures, `configure' can figure that out, but if it prints
++a message saying it cannot guess the machine type, give it the
++`--build=TYPE' option.  TYPE can either be a short name for the system
++type, such as `sun4', or a canonical name which has the form:
++
++     CPU-COMPANY-SYSTEM
++
++where SYSTEM can have one of these forms:
++
++     OS KERNEL-OS
++
++   See the file `config.sub' for the possible values of each field.  If
++`config.sub' isn't included in this package, then this package doesn't
++need to know the machine type.
++
++   If you are _building_ compiler tools for cross-compiling, you should
++use the `--target=TYPE' option to select the type of system they will
++produce code for.
++
++   If you want to _use_ a cross compiler, that generates code for a
++platform different from the build platform, you should specify the
++"host" platform (i.e., that on which the generated programs will
++eventually be run) with `--host=TYPE'.
++
++Sharing Defaults
++================
++
++   If you want to set default values for `configure' scripts to share,
++you can create a site shell script called `config.site' that gives
++default values for variables like `CC', `cache_file', and `prefix'.
++`configure' looks for `PREFIX/share/config.site' if it exists, then
++`PREFIX/etc/config.site' if it exists.  Or, you can set the
++`CONFIG_SITE' environment variable to the location of the site script.
++A warning: not all `configure' scripts look for a site script.
++
++Defining Variables
++==================
++
++   Variables not defined in a site shell script can be set in the
++environment passed to `configure'.  However, some packages may run
++configure again during the build, and the customized values of these
++variables may be lost.  In order to avoid this problem, you should set
++them in the `configure' command line, using `VAR=value'.  For example:
++
++     ./configure CC=/usr/local2/bin/gcc
++
++will cause the specified gcc to be used as the C compiler (unless it is
++overridden in the site shell script).
++
++`configure' Invocation
++======================
++
++   `configure' recognizes the following options to control how it
++operates.
++
++`--help'
++`-h'
++     Print a summary of the options to `configure', and exit.
++
++`--version'
++`-V'
++     Print the version of Autoconf used to generate the `configure'
++     script, and exit.
++
++`--cache-file=FILE'
++     Enable the cache: use and save the results of the tests in FILE,
++     traditionally `config.cache'.  FILE defaults to `/dev/null' to
++     disable caching.
++
++`--config-cache'
++`-C'
++     Alias for `--cache-file=config.cache'.
++
++`--quiet'
++`--silent'
++`-q'
++     Do not print messages saying which checks are being made.  To
++     suppress all normal output, redirect it to `/dev/null' (any error
++     messages will still be shown).
++
++`--srcdir=DIR'
++     Look for the package's source code in directory DIR.  Usually
++     `configure' can determine that directory automatically.
++
++`configure' also accepts some other, not widely useful, options.  Run
++`configure --help' for more details.
++
+--- kopete/protocols/jabber/jingle/libjingle/ChangeLog	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/ChangeLog	(revision 586398)
+@@ -0,0 +1,4 @@
++Libjingle
++
++0.1.0 - Dec 15 2005
++	- Initial release
+--- kopete/protocols/jabber/jingle/libjingle/COPYING	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/COPYING	(revision 586398)
+@@ -0,0 +1,25 @@
++Copyright (c) 2004--2005, Google Inc.
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without modification,
++are permitted provided that the following conditions are met:
++
++    * Redistributions of source code must retain the above copyright notice,
++      this list of conditions and the following disclaimer.
++    * Redistributions in binary form must reproduce the above copyright notice,
++      this list of conditions and the following disclaimer in the documentation
++      and/or other materials provided with the distribution.
++    * The name of the author may not be used to endorse or promote products
++      derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
++LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
++GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 
++WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
++SUCH DAMAGE.
+--- kopete/protocols/jabber/jingle/libjingle/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/Makefile.am	(revision 586398)
+@@ -0,0 +1,4 @@
++SUBDIRS=talk
++
++dist-hook:
++	sed -i -f talk/sanitize.sed `find $(distdir) -type f`
+\ No newline at end of file
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS=base client
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc	(revision 586398)
+@@ -0,0 +1,250 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/p2p/base/tcpport.h"
++#include "talk/base/logging.h"
++#ifdef WIN32
++#include "talk/base/winfirewall.h"
++#endif // WIN32
++#include <iostream>
++#include <cassert>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++#ifdef WIN32
++static WinFirewall win_firewall;
++#endif  // WIN32
++
++TCPPort::TCPPort(Thread* thread, SocketFactory* factory, Network* network,
++                 const SocketAddress& address)
++    : Port(thread, LOCAL_PORT_TYPE, factory, network), error_(0) {
++  incoming_only_ = (address.port() != 0);
++  socket_ = thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
++  socket_->SignalReadEvent.connect(this, &TCPPort::OnAcceptEvent);
++  if (socket_->Bind(address) < 0)
++    LOG(INFO) << "bind: " << std::strerror(socket_->GetError());
++}
++
++TCPPort::~TCPPort() {
++  delete socket_;
++}
++
++Connection* TCPPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
++  // We only support TCP protocols
++  if ((address.protocol() != "tcp") && (address.protocol() != "ssltcp"))
++    return 0;
++
++  // We can't accept TCP connections incoming on other ports
++  if (origin == ORIGIN_OTHER_PORT)
++    return 0;
++
++  // Check if we are allowed to make outgoing TCP connections
++  if (incoming_only_ && (origin == ORIGIN_MESSAGE))
++    return 0;
++
++  // We don't know how to act as an ssl server yet
++  if ((address.protocol() == "ssltcp") && (origin == ORIGIN_THIS_PORT))
++    return 0;
++
++  TCPConnection* conn = 0;
++  if (AsyncTCPSocket * socket = GetIncoming(address.address(), true)) {
++    socket->SignalReadPacket.disconnect(this);
++    conn = new TCPConnection(this, address, socket);
++  } else {
++    conn = new TCPConnection(this, address);
++  }
++  AddConnection(conn);
++  return conn;
++}
++
++void TCPPort::PrepareAddress() {
++  assert(socket_);
++
++  bool allow_listen = true;
++#ifdef WIN32
++  if (win_firewall.Initialize()) {
++    char module_path[MAX_PATH + 1] = { 0 };
++    ::GetModuleFileNameA(NULL, module_path, MAX_PATH);
++    if (win_firewall.Enabled() && !win_firewall.Authorized(module_path)) {
++      allow_listen = false;
++    }
++  }
++#endif // WIN32
++  if (allow_listen) {
++    if (socket_->Listen(5) < 0)
++      LOG(INFO) << "listen: " << std::strerror(socket_->GetError());
++  } else {
++    LOG(INFO) << "not listening due to firewall restrictions";
++  }
++  // Note: We still add the address, since otherwise the remote side won't recognize
++  // our incoming TCP connections.
++  add_address(socket_->GetLocalAddress(), "tcp");
++}
++
++int TCPPort::SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload) {
++  AsyncTCPSocket * socket = 0;
++
++  if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
++    socket = conn->socket();
++  } else {
++    socket = GetIncoming(addr);
++  }
++  if (!socket) {
++    LOG(INFO) << "Unknown destination for SendTo: " << addr.ToString();
++    return -1; // TODO: Set error_
++  }
++
++  //LOG(INFO) << "TCPPort::SendTo(" << size << ", " << addr.ToString() << ")";
++
++  int sent = socket->Send(data, size);
++  if (sent < 0)
++    error_ = socket->GetError();
++  return sent;
++}
++
++int TCPPort::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int TCPPort::GetError() {
++  assert(socket_);
++  return error_;
++}
++
++void TCPPort::OnAcceptEvent(AsyncSocket* socket) {
++  assert(socket == socket_);
++
++  Incoming incoming;
++  AsyncSocket * newsocket = static_cast<AsyncSocket *>(socket->Accept(&incoming.addr));
++  if (!newsocket) {
++    // TODO: Do something better like forwarding the error to the user.
++    LOG(INFO) << "accept: " << socket_->GetError() << " " <<  std::strerror(socket_->GetError());
++    return;
++  }
++  incoming.socket = new AsyncTCPSocket(newsocket);
++  incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket);
++
++  LOG(INFO) << "accepted incoming connection from " << incoming.addr.ToString();
++  incoming_.push_back(incoming);
++
++  // Prime a read event in case data is waiting
++  newsocket->SignalReadEvent(newsocket);
++}
++
++AsyncTCPSocket * TCPPort::GetIncoming(const SocketAddress& addr, bool remove) {
++  AsyncTCPSocket * socket = 0;
++  for (std::list<Incoming>::iterator it = incoming_.begin(); it != incoming_.end(); ++it) {
++    if (it->addr == addr) {
++      socket = it->socket;
++      if (remove)
++        incoming_.erase(it);
++      break;
++    }
++  }
++  return socket;
++}
++
++void TCPPort::OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket) {
++  Port::OnReadPacket(data, size, remote_addr);
++}
++
++TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate, AsyncTCPSocket* socket)
++    : Connection(port, 0, candidate), socket_(socket), error_(0) {
++  bool outgoing = (socket_ == 0);
++  if (outgoing) {
++    socket_ = static_cast<AsyncTCPSocket *>(port->CreatePacketSocket(
++                (candidate.protocol() == "ssltcp") ? PROTO_SSLTCP : PROTO_TCP));
++  }
++  socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
++  socket_->SignalClose.connect(this, &TCPConnection::OnClose);
++  if (outgoing) {
++    connected_ = false;
++    socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
++    socket_->Connect(candidate.address());
++    LOG(INFO) << "Connecting to " << candidate.address().ToString();
++  }
++}
++
++TCPConnection::~TCPConnection() {
++}
++
++int TCPConnection::Send(const void* data, size_t size) {
++  if (write_state() != STATE_WRITABLE)
++    return 0;
++
++  int sent = socket_->Send(data, size);
++  if (sent < 0) {
++    error_ = socket_->GetError();
++  } else {
++    sent_total_bytes_ += sent;
++  }
++  return sent;
++}
++
++int TCPConnection::GetError() {
++  return error_;
++}
++
++TCPPort* TCPConnection::tcpport() {
++  return static_cast<TCPPort*>(port_);
++}
++
++void TCPConnection::OnConnect(AsyncTCPSocket* socket) {
++  assert(socket == socket_);
++  LOG(INFO) << "tcp connected to " << socket->GetRemoteAddress().ToString();
++  set_connected(true);
++}
++
++void TCPConnection::OnClose(AsyncTCPSocket* socket, int error) {
++  assert(socket == socket_);
++  LOG(INFO) << "tcp closed with error: " << error;
++  set_connected(false);
++}
++
++void TCPConnection::OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket) {
++  assert(socket == socket_);
++  Connection::OnReadPacket(data, size);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h	(revision 586398)
+@@ -0,0 +1,116 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __TCPPORT_H__
++#define __TCPPORT_H__
++
++#include <list>
++#include "talk/base/asynctcpsocket.h"
++#include "talk/p2p/base/port.h"
++
++namespace cricket {
++
++class TCPConnection;
++
++extern const std::string LOCAL_PORT_TYPE; // type of TCP ports
++
++// Communicates using a local TCP port.
++//
++// This class is designed to allow subclasses to take advantage of the
++// connection management provided by this class.  A subclass should take of all
++// packet sending and preparation, but when a packet is received, it should
++// call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection.
++class TCPPort : public Port {
++public:
++  TCPPort(Thread* thread, SocketFactory* factory, Network* network,
++          const SocketAddress& address);
++  virtual ~TCPPort();
++
++  virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
++
++  virtual void PrepareAddress();
++
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError();
++
++protected:
++  // Handles sending using the local TCP socket.
++  virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
++
++  // Creates TCPConnection for incoming sockets
++  void OnAcceptEvent(AsyncSocket* socket);
++
++  AsyncSocket* socket() { return socket_; }
++
++private:
++  bool incoming_only_;
++  AsyncSocket* socket_;
++  int error_;
++
++  struct Incoming {
++    SocketAddress addr;
++    AsyncTCPSocket * socket;
++  };
++  std::list<Incoming> incoming_;
++
++  AsyncTCPSocket * GetIncoming(const SocketAddress& addr, bool remove = false);
++
++  // Receives packet signal from the local TCP Socket.
++  void OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++  friend class TCPConnection;
++};
++
++class TCPConnection : public Connection {
++public:
++  // Connection is outgoing unless socket is specified
++  TCPConnection(TCPPort* port, const Candidate& candidate, AsyncTCPSocket* socket = 0);
++  virtual ~TCPConnection();
++
++  virtual int Send(const void* data, size_t size);
++  virtual int GetError();
++
++  AsyncTCPSocket * socket() { return socket_; }
++
++private:
++  TCPPort* tcpport();
++  AsyncTCPSocket* socket_;
++  bool connected_;
++  int error_;
++
++  void OnConnect(AsyncTCPSocket* socket);
++  void OnClose(AsyncTCPSocket* socket, int error);
++  void OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++  friend class TCPPort;
++};
++
++} // namespace cricket
++
++#endif // __TCPPORT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc	(revision 586398)
+@@ -0,0 +1,171 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/logging.h"
++#include "talk/p2p/base/stunport.h"
++#include "talk/p2p/base/helpers.h"
++#include <iostream>
++#include <cassert>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts
++const int RETRY_DELAY = 50; // 50ms, from ICE spec
++const uint32 RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs
++
++// Handles a binding request sent to the STUN server.
++class StunPortBindingRequest : public StunRequest {
++public:
++  StunPortBindingRequest(StunPort* port) : port_(port) {
++    start_time_ = GetMillisecondCount();
++  }
++
++  virtual ~StunPortBindingRequest() {
++  }
++
++  virtual void Prepare(StunMessage* request) {
++    request->SetType(STUN_BINDING_REQUEST);
++  }
++
++  virtual void OnResponse(StunMessage* response) {
++    const StunAddressAttribute* addr_attr =
++        response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
++    if (!addr_attr) {
++      LOG(LERROR) << "Binding response missing mapped address.";
++    } else if (addr_attr->family() != 1) {
++      LOG(LERROR) << "Binding address has bad family";
++    } else {
++      SocketAddress addr(addr_attr->ip(), addr_attr->port());
++      if (port_->candidates().empty())
++        port_->add_address(addr, "udp");
++    }
++
++    // We will do a keep-alive regardless of whether this request suceeds.
++    // This should have almost no impact on network usage.
++    port_->requests_.SendDelayed(new StunPortBindingRequest(port_), KEEPALIVE_DELAY);
++  }
++
++  virtual void OnErrorResponse(StunMessage* response) {
++    const StunErrorCodeAttribute* attr = response->GetErrorCode();
++    if (!attr) {
++      LOG(LERROR) << "Bad allocate response error code";
++    } else {
++      LOG(LERROR) << "Binding error response:"
++                 << " class=" << attr->error_class()
++                 << " number=" << attr->number()
++                 << " reason='" << attr->reason() << "'";
++    }
++
++    if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
++      port_->requests_.SendDelayed(new StunPortBindingRequest(port_), KEEPALIVE_DELAY);
++  }
++
++  virtual void OnTimeout() {
++    LOG(LERROR) << "Binding request timed out";
++    if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
++      port_->requests_.SendDelayed(new StunPortBindingRequest(port_), RETRY_DELAY);
++  }
++
++private:
++  uint32 start_time_;
++  StunPort* port_;
++};
++
++const std::string STUN_PORT_TYPE("stun");
++
++StunPort::StunPort(Thread* thread, SocketFactory* factory, Network* network,
++                   const SocketAddress& local_addr,
++                   const SocketAddress& server_addr)
++  : UDPPort(thread, STUN_PORT_TYPE, factory, network),
++    server_addr_(server_addr), requests_(thread), error_(0) {
++
++  socket_ = CreatePacketSocket(PROTO_UDP);
++  socket_->SignalReadPacket.connect(this, &StunPort::OnReadPacket);
++  if (socket_->Bind(local_addr) < 0)
++    PLOG(LERROR, socket_->GetError()) << "bind";
++
++  requests_.SignalSendPacket.connect(this, &StunPort::OnSendPacket);
++}
++
++StunPort::~StunPort() {
++  delete socket_;
++}
++
++void StunPort::PrepareAddress() {
++  requests_.Send(new StunPortBindingRequest(this));
++}
++
++int StunPort::SendTo(
++    const void* data, size_t size, const SocketAddress& addr, bool payload) {
++  int sent = socket_->SendTo(data, size, addr);
++  if (sent < 0)
++    error_ = socket_->GetError();
++  return sent;
++}
++
++int StunPort::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int StunPort::GetError() {
++  return error_;
++}
++
++void StunPort::OnReadPacket(
++    const char* data, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket) {
++  assert(socket == socket_);
++
++  // Look for a response to a binding request.
++  if (requests_.CheckResponse(data, size))
++    return;
++
++  // Process this data packet in the normal manner.
++  UDPPort::OnReadPacket(data, size, remote_addr);
++}
++
++void StunPort::OnSendPacket(const void* data, size_t size) {
++  if (socket_->SendTo(data, size, server_addr_) < 0)
++    PLOG(LERROR, socket_->GetError()) << "sendto";
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc	(revision 586398)
+@@ -0,0 +1,129 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/p2p/base/helpers.h"
++#include "talk/base/jtime.h"
++#include <cstdlib>
++#include <cassert>
++
++// TODO: Change this implementation to use OpenSSL's RAND_bytes.  That will
++//       give cryptographically random values on all platforms.
++
++#ifdef WIN32
++#include <time.h>
++#include <windows.h>
++#endif
++
++namespace cricket {
++
++static long g_seed = 1L;
++
++int GetRandom() {
++  return ((g_seed = g_seed * 214013L + 2531011L) >> 16) & 0x7fff;
++}
++
++void SetRandomSeed(unsigned long seed)
++{
++  g_seed = (long)seed;
++}
++
++static bool s_initrandom;
++
++void InitRandom(const char *client_unique, size_t len) {
++  s_initrandom = true;
++
++  // Hash this string - unique per client
++
++  uint32 hash = 0;
++  if (client_unique != NULL) {
++    for (int i = 0; i < (int)len; i++)
++      hash = ((hash << 2) + hash) + client_unique[i];
++  }
++
++  // Now initialize the seed against a high resolution
++  // counter
++
++#ifdef WIN32
++  LARGE_INTEGER big;
++  QueryPerformanceCounter(&big);
++  SetRandomSeed(big.LowPart ^ hash);
++#else
++  SetRandomSeed(Time() ^ hash);
++#endif
++}
++
++const char BASE64[64] = {
++  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
++  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
++  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
++  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
++  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
++};
++
++// Generates a random string of the given length.  We generate base64 values so
++// that they will be printable, though that's not necessary.
++
++std::string CreateRandomString(int len) {
++  // Random number generator should of been initialized!
++  assert(s_initrandom);
++  if (!s_initrandom)
++    InitRandom(0, 0);
++
++  std::string str;
++  for (int i = 0; i < len; i++)
++#if defined(_MSC_VER) && _MSC_VER < 1300
++    str.insert(str.end(), BASE64[GetRandom() & 63]);
++#else
++    str.push_back(BASE64[GetRandom() & 63]);
++#endif
++  return str;
++}
++
++uint32 CreateRandomId() {
++  uint8 b1 = (uint8)(GetRandom() & 255);
++  uint8 b2 = (uint8)(GetRandom() & 255);
++  uint8 b3 = (uint8)(GetRandom() & 255);
++  uint8 b4 = (uint8)(GetRandom() & 255);
++  return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
++}
++
++bool IsBase64Char(char ch) {
++  return (('A' <= ch) && (ch <= 'Z')) ||
++         (('a' <= ch) && (ch <= 'z')) ||
++         (('0' <= ch) && (ch <= '9')) ||
++         (ch == '+') || (ch == '/');
++}
++
++bool IsBase64Encoded(const std::string& str) {
++  for (size_t i = 0; i < str.size(); ++i) {
++    if (!IsBase64Char(str.at(i)))
++      return false;
++  }
++  return true;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc	(revision 586398)
+@@ -0,0 +1,657 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/p2p/base/relayserver.h"
++#include "talk/p2p/base/helpers.h"
++#include <algorithm>
++#include <cassert>
++#include <cstring>
++#include <iostream>
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++// By default, we require a ping every 90 seconds.
++const int MAX_LIFETIME = 15 * 60 * 1000;
++
++// The number of bytes in each of the usernames we use.
++const uint32 USERNAME_LENGTH = 16;
++
++// Calls SendTo on the given socket and logs any bad results.
++void Send(AsyncPacketSocket* socket, const char* bytes, size_t size,
++          const SocketAddress& addr) {
++  int result = socket->SendTo(bytes, size, addr);
++  if (result < int(size)) {
++    std::cerr << "SendTo wrote only " << result << " of " << int(size)
++              << " bytes" << std::endl;
++  } else if (result < 0) {
++    std::cerr << "SendTo: " << std::strerror(errno) << std::endl;
++  }
++}
++
++// Sends the given STUN message on the given socket.
++void SendStun(const StunMessage& msg,
++              AsyncPacketSocket* socket,
++              const SocketAddress& addr) {
++  ByteBuffer buf;
++  msg.Write(&buf);
++  Send(socket, buf.Data(), buf.Length(), addr);
++}
++
++// Constructs a STUN error response and sends it on the given socket.
++void SendStunError(const StunMessage& msg, AsyncPacketSocket* socket,
++                   const SocketAddress& remote_addr, int error_code,
++                   const char* error_desc, const std::string& magic_cookie) {
++
++  StunMessage err_msg;
++  err_msg.SetType(GetStunErrorResponseType(msg.type()));
++  err_msg.SetTransactionID(msg.transaction_id());
++
++  StunByteStringAttribute* magic_cookie_attr =
++      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
++  if (magic_cookie.size() == 0)
++    magic_cookie_attr->CopyBytes(cricket::STUN_MAGIC_COOKIE_VALUE, 4);
++  else
++    magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
++  err_msg.AddAttribute(magic_cookie_attr);
++
++  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
++  err_code->SetErrorClass(error_code / 100);
++  err_code->SetNumber(error_code % 100);
++  err_code->SetReason(error_desc);
++  err_msg.AddAttribute(err_code);
++
++  SendStun(err_msg, socket, remote_addr);
++}
++
++RelayServer::RelayServer(Thread* thread) : thread_(thread) {
++}
++
++RelayServer::~RelayServer() {
++  for (unsigned i = 0; i < internal_sockets_.size(); i++)
++    delete internal_sockets_[i];
++  for (unsigned i = 0; i < external_sockets_.size(); i++)
++    delete external_sockets_[i];
++}
++
++void RelayServer::AddInternalSocket(AsyncPacketSocket* socket) {
++  assert(internal_sockets_.end() ==
++      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket));
++  internal_sockets_.push_back(socket);
++  socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);
++}
++
++void RelayServer::RemoveInternalSocket(AsyncPacketSocket* socket) {
++  SocketList::iterator iter =
++      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket);
++  assert(iter != internal_sockets_.end());
++  internal_sockets_.erase(iter);
++  socket->SignalReadPacket.disconnect(this);
++}
++
++void RelayServer::AddExternalSocket(AsyncPacketSocket* socket) {
++  assert(external_sockets_.end() ==
++      std::find(external_sockets_.begin(), external_sockets_.end(), socket));
++  external_sockets_.push_back(socket);
++  socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);
++}
++
++void RelayServer::RemoveExternalSocket(AsyncPacketSocket* socket) {
++  SocketList::iterator iter =
++      std::find(external_sockets_.begin(), external_sockets_.end(), socket);
++  assert(iter != external_sockets_.end());
++  external_sockets_.erase(iter);
++  socket->SignalReadPacket.disconnect(this);
++}
++
++void RelayServer::OnInternalPacket(
++    const char* bytes, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket) {
++
++  // Get the address of the connection we just received on.
++  SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++  assert(!ap.destination().IsAny());
++
++  // If this did not come from an existing connection, it should be a STUN
++  // allocate request.
++  ConnectionMap::iterator piter = connections_.find(ap);
++  if (piter == connections_.end()) {
++    HandleStunAllocate(bytes, size, ap, socket);
++    return;
++  }
++
++  RelayServerConnection* int_conn = piter->second;
++
++  // Handle STUN requests to the server itself.
++  if (int_conn->binding()->HasMagicCookie(bytes, size)) {
++    HandleStun(int_conn, bytes, size);
++    return;
++  }
++
++  // Otherwise, this is a non-wrapped packet that we are to forward.  Make sure
++  // that this connection has been locked.  (Otherwise, we would not know what
++  // address to forward to.)
++  if (!int_conn->locked()) {
++    std::cerr << "Dropping packet: connection not locked" << std::endl;
++    return;
++  }
++
++  // Forward this to the destination address into the connection.
++  RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(
++      int_conn->default_destination());
++  if (ext_conn) {
++    // TODO: Check the HMAC.
++    ext_conn->Send(bytes, size);
++  } else {
++    // This happens very often and is not an error.
++    //std::cerr << "Dropping packet: no external connection" << std::endl;
++  }
++}
++
++void RelayServer::OnExternalPacket(
++    const char* bytes, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket) {
++
++  // Get the address of the connection we just received on.
++  SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++  assert(!ap.destination().IsAny());
++
++  // If this connection already exists, then forward the traffic.
++  ConnectionMap::iterator piter = connections_.find(ap);
++  if (piter != connections_.end()) {
++    // TODO: Check the HMAC.
++    RelayServerConnection* ext_conn = piter->second;
++    RelayServerConnection* int_conn =
++        ext_conn->binding()->GetInternalConnection(
++            ext_conn->addr_pair().source());
++    assert(int_conn);
++    int_conn->Send(bytes, size, ext_conn->addr_pair().source());
++    return;
++  }
++
++  // The first packet should always be a STUN / TURN packet.  If it isn't, then
++  // we should just ignore this packet.
++  StunMessage msg;
++  ByteBuffer buf = ByteBuffer(bytes, size);
++  if (!msg.Read(&buf)) {
++    std::cerr << "Dropping packet: first packet not STUN" << std::endl;
++    return;
++  }
++
++  // The initial packet should have a username (which identifies the binding).
++  const StunByteStringAttribute* username_attr =
++      msg.GetByteString(STUN_ATTR_USERNAME);
++  if (!username_attr) {
++    std::cerr << "Dropping packet: no username" << std::endl;
++    return;
++  }
++
++  uint32 length = _min(uint32(username_attr->length()), USERNAME_LENGTH);
++  std::string username(username_attr->bytes(), length);
++  // TODO: Check the HMAC.
++
++  // The binding should already be present.
++  BindingMap::iterator biter = bindings_.find(username);
++  if (biter == bindings_.end()) {
++    // TODO: Turn this back on.  This is the sign of a client bug.
++    //std::cerr << "Dropping packet: no binding with username" << std::endl;
++    return;
++  }
++
++  // Add this authenticted connection to the binding.
++  RelayServerConnection* ext_conn =
++      new RelayServerConnection(biter->second, ap, socket);
++  ext_conn->binding()->AddExternalConnection(ext_conn);
++  AddConnection(ext_conn);
++
++  // We always know where external packets should be forwarded, so we can lock
++  // them from the beginning.
++  ext_conn->Lock();
++
++  // Send this message on the appropriate internal connection.
++  RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(
++      ext_conn->addr_pair().source());
++  assert(int_conn);
++  int_conn->Send(bytes, size, ext_conn->addr_pair().source());
++}
++
++bool RelayServer::HandleStun(
++    const char* bytes, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket, std::string* username, StunMessage* msg) {
++
++  // Parse this into a stun message.
++  ByteBuffer buf = ByteBuffer(bytes, size);
++  if (!msg->Read(&buf)) {
++    SendStunError(*msg, socket, remote_addr, 400, "Bad Request", "");
++    return false;
++  }
++
++  // The initial packet should have a username (which identifies the binding).
++  const StunByteStringAttribute* username_attr =
++      msg->GetByteString(STUN_ATTR_USERNAME);
++  if (!username_attr) {
++    SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");
++    return false;
++  }
++
++  // Record the username if requested.
++  if (username)
++    username->append(username_attr->bytes(), username_attr->length());
++
++  // TODO: Check for unknown attributes (<= 0x7fff)
++
++  return true;
++}
++
++void RelayServer::HandleStunAllocate(
++    const char* bytes, size_t size, const SocketAddressPair& ap,
++    AsyncPacketSocket* socket) {
++
++  // Make sure this is a valid STUN request.
++  StunMessage request;
++  std::string username;
++  if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))
++    return;
++
++  // Make sure this is a an allocate request.
++  if (request.type() != STUN_ALLOCATE_REQUEST) {
++    SendStunError(request,
++                  socket,
++                  ap.source(),
++                  600,
++                  "Operation Not Supported",
++                  "");
++    return;
++  }
++
++  // TODO: Check the HMAC.
++
++  // Find or create the binding for this username.
++
++  RelayServerBinding* binding;
++
++  BindingMap::iterator biter = bindings_.find(username);
++  if (biter != bindings_.end()) {
++
++    binding = biter->second;
++
++  } else {
++
++    // NOTE: In the future, bindings will be created by the bot only.  This
++    //       else-branch will then disappear.
++
++    // Compute the appropriate lifetime for this binding.
++    uint32 lifetime = MAX_LIFETIME;
++    const StunUInt32Attribute* lifetime_attr =
++        request.GetUInt32(STUN_ATTR_LIFETIME);
++    if (lifetime_attr)
++      lifetime = _min(lifetime, lifetime_attr->value() * 1000);
++
++    binding = new RelayServerBinding(this, username, "0", lifetime);
++    binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);
++    bindings_[username] = binding;
++
++    std::cout << "Added new binding: " << bindings_.size() << " total" << std::endl;
++  }
++
++  // Add this connection to the binding.  It starts out unlocked.
++  RelayServerConnection* int_conn =
++      new RelayServerConnection(binding, ap, socket);
++  binding->AddInternalConnection(int_conn);
++  AddConnection(int_conn);
++
++  // Now that we have a connection, this other method takes over.
++  HandleStunAllocate(int_conn, request);
++}
++
++void RelayServer::HandleStun(
++    RelayServerConnection* int_conn, const char* bytes, size_t size) {
++
++  // Make sure this is a valid STUN request.
++  StunMessage request;
++  std::string username;
++  if (!HandleStun(bytes, size, int_conn->addr_pair().source(),
++                  int_conn->socket(), &username, &request))
++    return;
++
++  // Make sure the username is the one were were expecting.
++  if (username != int_conn->binding()->username()) {
++    int_conn->SendStunError(request, 430, "Stale Credentials");
++    return;
++  }
++
++  // TODO: Check the HMAC.
++
++  // Send this request to the appropriate handler.
++  if (request.type() == STUN_SEND_REQUEST)
++    HandleStunSend(int_conn, request);
++  else if (request.type() == STUN_ALLOCATE_REQUEST)
++    HandleStunAllocate(int_conn, request);
++  else
++    int_conn->SendStunError(request, 600, "Operation Not Supported");
++}
++
++void RelayServer::HandleStunAllocate(
++    RelayServerConnection* int_conn, const StunMessage& request) {
++
++  // Create a response message that includes an address with which external
++  // clients can communicate.
++
++  StunMessage response;
++  response.SetType(STUN_ALLOCATE_RESPONSE);
++  response.SetTransactionID(request.transaction_id());
++
++  StunByteStringAttribute* magic_cookie_attr =
++      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
++  magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
++                               int_conn->binding()->magic_cookie().size());
++  response.AddAttribute(magic_cookie_attr);
++
++  size_t index = rand() % external_sockets_.size();
++  SocketAddress ext_addr = external_sockets_[index]->GetLocalAddress();
++
++  StunAddressAttribute* addr_attr =
++      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
++  addr_attr->SetFamily(1);
++  addr_attr->SetIP(ext_addr.ip());
++  addr_attr->SetPort(ext_addr.port());
++  response.AddAttribute(addr_attr);
++
++  StunUInt32Attribute* res_lifetime_attr =
++      StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
++  res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000);
++  response.AddAttribute(res_lifetime_attr);
++
++  // TODO: Support transport-prefs (preallocate RTCP port).
++  // TODO: Support bandwidth restrictions.
++  // TODO: Add message integrity check.
++
++  // Send a response to the caller.
++  int_conn->SendStun(response);
++}
++
++void RelayServer::HandleStunSend(
++    RelayServerConnection* int_conn, const StunMessage& request) {
++
++  const StunAddressAttribute* addr_attr =
++      request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
++  if (!addr_attr) {
++    int_conn->SendStunError(request, 400, "Bad Request");
++    return;
++  }
++
++  const StunByteStringAttribute* data_attr =
++      request.GetByteString(STUN_ATTR_DATA);
++  if (!data_attr) {
++    int_conn->SendStunError(request, 400, "Bad Request");
++    return;
++  }
++
++  SocketAddress ext_addr(addr_attr->ip(), addr_attr->port());
++  RelayServerConnection* ext_conn =
++      int_conn->binding()->GetExternalConnection(ext_addr);
++  if (!ext_conn) {
++    // This happens very often and is not an error.
++    //std::cerr << "Dropping packet: no external connection" << std::endl;
++    return;
++  }
++
++  ext_conn->Send(data_attr->bytes(), data_attr->length());
++
++  const StunUInt32Attribute* options_attr =
++      request.GetUInt32(STUN_ATTR_OPTIONS);
++  if (options_attr && (options_attr->value() & 0x01 != 0)) {
++    int_conn->set_default_destination(ext_addr);
++    int_conn->Lock();
++
++    StunMessage response;
++    response.SetType(STUN_SEND_RESPONSE);
++    response.SetTransactionID(request.transaction_id());
++
++    StunByteStringAttribute* magic_cookie_attr =
++        StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
++    magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
++                                 int_conn->binding()->magic_cookie().size());
++    response.AddAttribute(magic_cookie_attr);
++
++    StunUInt32Attribute* options2_attr =
++      StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS);
++    options2_attr->SetValue(0x01);
++    response.AddAttribute(options2_attr);
++    
++    int_conn->SendStun(response);
++  }
++}
++
++void RelayServer::AddConnection(RelayServerConnection* conn) {
++  assert(connections_.find(conn->addr_pair()) == connections_.end());
++  connections_[conn->addr_pair()] = conn;
++}
++
++void RelayServer::RemoveConnection(RelayServerConnection* conn) {
++  ConnectionMap::iterator iter = connections_.find(conn->addr_pair());
++  assert(iter != connections_.end());
++  connections_.erase(iter);
++}
++
++void RelayServer::RemoveBinding(RelayServerBinding* binding) {
++  BindingMap::iterator iter = bindings_.find(binding->username());
++  assert(iter != bindings_.end());
++  bindings_.erase(iter);
++
++  std::cout << "Removed a binding: " << bindings_.size() << " remaining" << std::endl;
++}
++
++void RelayServer::OnTimeout(RelayServerBinding* binding) {
++  // This call will result in all of the necessary clean-up.
++  delete binding;
++}
++
++RelayServerConnection::RelayServerConnection(
++    RelayServerBinding* binding, const SocketAddressPair& addrs,
++    AsyncPacketSocket* socket)
++  : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) {
++
++  // The creation of a new connection constitutes a use of the binding.
++  binding_->NoteUsed();
++}
++
++RelayServerConnection::~RelayServerConnection() {
++  // Remove this connection from the server's map (if it exists there).
++  binding_->server()->RemoveConnection(this);
++}
++
++void RelayServerConnection::Send(const char* data, size_t size) {
++  // Note that the binding has been used again.
++  binding_->NoteUsed();
++
++  cricket::Send(socket_, data, size, addr_pair_.source());
++}
++
++void RelayServerConnection::Send(
++    const char* data, size_t size, const SocketAddress& from_addr) {
++  // If the from address is known to the client, we don't need to send it.
++  if (locked() && (from_addr == default_dest_)) {
++    Send(data, size);
++    return;
++  }
++
++  // Wrap the given data in a data-indication packet.
++
++  StunMessage msg;
++  msg.SetType(STUN_DATA_INDICATION);
++  msg.SetTransactionID("0000000000000000");
++
++  StunByteStringAttribute* magic_cookie_attr =
++      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
++  magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(),
++                               binding_->magic_cookie().size());
++  msg.AddAttribute(magic_cookie_attr);
++
++  StunAddressAttribute* addr_attr =
++      StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
++  addr_attr->SetFamily(1);
++  addr_attr->SetIP(from_addr.ip());
++  addr_attr->SetPort(from_addr.port());
++  msg.AddAttribute(addr_attr);
++
++  StunByteStringAttribute* data_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_DATA);
++  assert(size <= 65536);
++  data_attr->CopyBytes(data, uint16(size));
++  msg.AddAttribute(data_attr);
++
++  SendStun(msg);
++}
++
++void RelayServerConnection::SendStun(const StunMessage& msg) {
++  // Note that the binding has been used again.
++  binding_->NoteUsed();
++
++  cricket::SendStun(msg, socket_, addr_pair_.source());
++}
++
++void RelayServerConnection::SendStunError(
++      const StunMessage& request, int error_code, const char* error_desc) {
++  // An error does not indicate use.  If no legitimate use off the binding
++  // occurs, we want it to be cleaned up even if errors are still occuring.
++
++  cricket::SendStunError(
++      request, socket_, addr_pair_.source(), error_code, error_desc,
++      binding_->magic_cookie());
++}
++
++void RelayServerConnection::Lock() {
++  locked_ = true;
++}
++
++void RelayServerConnection::Unlock() {
++  locked_ = false;
++}
++
++// IDs used for posted messages:
++const uint32 MSG_LIFETIME_TIMER = 1;
++
++RelayServerBinding::RelayServerBinding(
++    RelayServer* server, const std::string& username,
++    const std::string& password, uint32 lifetime)
++  : server_(server), username_(username), password_(password),
++    lifetime_(lifetime) {
++
++  // For now, every connection uses the standard magic cookie value.
++  magic_cookie_.append(
++      reinterpret_cast<const char*>(STUN_MAGIC_COOKIE_VALUE), 4);
++
++  // Initialize the last-used time to now.
++  NoteUsed();
++
++  // Set the first timeout check.
++  server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
++}
++
++RelayServerBinding::~RelayServerBinding() {
++  // Clear the outstanding timeout check.
++  server_->thread()->Clear(this);
++
++  // Clean up all of the connections.
++  for (size_t i = 0; i < internal_connections_.size(); ++i)
++    delete internal_connections_[i];
++  for (size_t i = 0; i < external_connections_.size(); ++i)
++    delete external_connections_[i];
++
++  // Remove this binding from the server's map.
++  server_->RemoveBinding(this);
++}
++
++void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
++  internal_connections_.push_back(conn);
++}
++
++void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
++  external_connections_.push_back(conn);
++}
++
++void RelayServerBinding::NoteUsed() {
++  last_used_ = GetMillisecondCount();
++}
++
++bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
++  if (size < 24 + magic_cookie_.size()) {
++    return false;
++  } else {
++    return 0 == std::memcmp(
++        bytes + 24, magic_cookie_.c_str(), magic_cookie_.size());
++  }
++}
++
++RelayServerConnection* RelayServerBinding::GetInternalConnection(
++    const SocketAddress& ext_addr) {
++
++  // Look for an internal connection that is locked to this address.
++  for (size_t i = 0; i < internal_connections_.size(); ++i) {
++    if (internal_connections_[i]->locked() &&
++        (ext_addr == internal_connections_[i]->default_destination()))
++      return internal_connections_[i];
++  }
++
++  // If one was not found, we send to the first connection.
++  assert(internal_connections_.size() > 0);
++  return internal_connections_[0];
++}
++
++RelayServerConnection* RelayServerBinding::GetExternalConnection(
++    const SocketAddress& ext_addr) {
++  for (size_t i = 0; i < external_connections_.size(); ++i) {
++    if (ext_addr == external_connections_[i]->addr_pair().source())
++      return external_connections_[i];
++  }
++  return 0;
++}
++
++void RelayServerBinding::OnMessage(Message *pmsg) {
++  if (pmsg->message_id == MSG_LIFETIME_TIMER) {
++    assert(!pmsg->pdata);
++
++    // If the lifetime timeout has been exceeded, then send a signal.
++    // Otherwise, just keep waiting.
++    if (GetMillisecondCount() >= last_used_ + lifetime_) {
++      SignalTimeout(this);
++    } else {
++      server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
++    }
++
++  } else {
++    assert(false);
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h	(revision 586398)
+@@ -0,0 +1,126 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __STUNREQUESTMANAGER_H__
++#define __STUNREQUESTMANAGER_H__
++
++#include "talk/base/sigslot.h"
++#include "talk/base/thread.h"
++#include "talk/p2p/base/stun.h"
++#include <map>
++#include <string>
++
++namespace cricket {
++
++class StunRequest;
++
++// Manages a set of STUN requests, sending and resending until we receive a
++// response or determine that the request has timed out.
++class StunRequestManager {
++public:
++  StunRequestManager(Thread* thread);
++  ~StunRequestManager();
++
++  // Starts sending the given request (perhaps after a delay).
++  void Send(StunRequest* request);
++  void SendDelayed(StunRequest* request, int delay);
++
++  // Removes a stun request that was added previously.  This will happen
++  // automatically when a request succeeds, fails, or times out.
++  void Remove(StunRequest* request);
++
++  // Removes all stun requests that were added previously.
++  void Clear();
++
++  // Determines whether the given message is a response to one of the
++  // outstanding requests, and if so, processes it appropriately.
++  bool CheckResponse(StunMessage* msg);
++  bool CheckResponse(const char* data, size_t size);
++
++  // Raised when there are bytes to be sent.
++  sigslot::signal2<const void*, size_t> SignalSendPacket;
++
++private:
++  typedef std::map<std::string, StunRequest*> RequestMap;
++
++  Thread* thread_;
++  RequestMap requests_;
++
++  friend class StunRequest;
++};
++
++// Represents an individual request to be sent.  The STUN message can either be
++// constructed beforehand or built on demand.
++class StunRequest : public MessageHandler {
++public:
++  StunRequest();
++  StunRequest(StunMessage* request);
++  virtual ~StunRequest();
++
++  // The manager handling this request (if it has been scheduled for sending).
++  StunRequestManager* manager() { return manager_; }
++
++  // Returns the transaction ID of this request.
++  const std::string& id() { return id_; }
++
++  // Returns the STUN type of the request message.
++  const StunMessageType type();
++
++  // Handles messages for sending and timeout.
++  void OnMessage(Message* pmsg);
++
++  // Time elapsed since last send (in ms)
++  uint32 Elapsed() const;
++
++protected:
++  int count_;
++  bool timeout_;
++
++  // Fills in the actual request to be sent.  Note that the transaction ID will
++  // already be set and cannot be changed.
++  virtual void Prepare(StunMessage* request) {}
++
++  // Called when the message receives a response or times out.
++  virtual void OnResponse(StunMessage* response) {}
++  virtual void OnErrorResponse(StunMessage* response) {}
++  virtual void OnTimeout() {}
++  virtual int GetNextDelay();
++
++private:
++  StunRequestManager* manager_;
++  std::string id_;
++  StunMessage* msg_;
++  uint32 tstamp_;
++
++  void set_manager(StunRequestManager* manager);
++
++  friend class StunRequestManager;
++};
++
++} // namespace cricket
++
++#endif // __STUNREQUESTMANAGER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h	(revision 586398)
+@@ -0,0 +1,210 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __RELAYSERVER_H__
++#define __RELAYSERVER_H__
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/socketaddresspair.h"
++#include "talk/base/thread.h"
++#include "talk/base/jtime.h"
++#include "talk/p2p/base/stun.h"
++
++#include <string>
++#include <vector>
++#include <map>
++
++namespace cricket {
++
++class RelayServerBinding;
++class RelayServerConnection;
++
++// Relays traffic between connections to the server that are "bound" together.
++// All connections created with the same username/password are bound together.
++class RelayServer : public sigslot::has_slots<> {
++public:
++  // Creates a server, which will use this thread to post messages to itself.
++  RelayServer(Thread* thread);
++  ~RelayServer();
++
++  Thread* thread() { return thread_; }
++
++  // Updates the set of sockets that the server uses to talk to "internal"
++  // clients.  These are clients that do the "port allocations".
++  void AddInternalSocket(AsyncPacketSocket* socket);
++  void RemoveInternalSocket(AsyncPacketSocket* socket);
++
++  // Updates the set of sockets that the server uses to talk to "external"
++  // clients.  These are the clients that do not do allocations.  They do not
++  // know that these addresses represent a relay server.
++  void AddExternalSocket(AsyncPacketSocket* socket);
++  void RemoveExternalSocket(AsyncPacketSocket* socket);
++
++private:
++  typedef std::vector<AsyncPacketSocket*> SocketList;
++  typedef std::map<std::string,RelayServerBinding*> BindingMap;
++  typedef std::map<SocketAddressPair,RelayServerConnection*> ConnectionMap;
++
++  Thread* thread_;
++  SocketList internal_sockets_;
++  SocketList external_sockets_;
++  BindingMap bindings_;
++  ConnectionMap connections_;
++
++  // Called when a packet is received by the server on one of its sockets.
++  void OnInternalPacket(
++      const char* bytes, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++  void OnExternalPacket(
++      const char* bytes, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++  // Processes the relevant STUN request types from the client.
++  bool HandleStun(const char* bytes, size_t size,
++                  const SocketAddress& remote_addr, AsyncPacketSocket* socket,
++                  std::string* username, StunMessage* msg);
++  void HandleStunAllocate(const char* bytes, size_t size,
++                          const SocketAddressPair& ap,
++                          AsyncPacketSocket* socket);
++  void HandleStun(RelayServerConnection* int_conn, const char* bytes,
++                  size_t size);
++  void HandleStunAllocate(RelayServerConnection* int_conn,
++                          const StunMessage& msg);
++  void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg);
++
++  // Adds/Removes the a connection or binding.
++  void AddConnection(RelayServerConnection* conn);
++  void RemoveConnection(RelayServerConnection* conn);
++  void RemoveBinding(RelayServerBinding* binding);
++
++  // Called when the timer for checking lifetime times out.
++  void OnTimeout(RelayServerBinding* binding);
++
++  friend class RelayServerConnection;
++  friend class RelayServerBinding;
++};
++
++// Maintains information about a connection to the server.  Each connection is
++// part of one and only one binding.
++class RelayServerConnection {
++public:
++  RelayServerConnection(RelayServerBinding* binding,
++                        const SocketAddressPair& addrs,
++                        AsyncPacketSocket* socket);
++  ~RelayServerConnection();
++
++  RelayServerBinding* binding() { return binding_; }
++  AsyncPacketSocket* socket() { return socket_; }
++
++  // Returns a pair where the source is the remote address and the destination
++  // is the local address.
++  const SocketAddressPair& addr_pair() { return addr_pair_; }
++
++  // Sends a packet to the connected client.  If an address is provided, then
++  // we make sure the internal client receives it, wrapping if necessary.
++  void Send(const char* data, size_t size);
++  void Send(const char* data, size_t size, const SocketAddress& ext_addr);
++
++  // Sends a STUN message to the connected client with no wrapping.
++  void SendStun(const StunMessage& msg);
++  void SendStunError(const StunMessage& request, int code, const char* desc);
++
++  // A locked connection is one for which we know the intended destination of
++  // any raw packet received.
++  bool locked() const { return locked_; }
++  void Lock();
++  void Unlock();
++
++  // Records the address that raw packets should be forwarded to (for internal
++  // packets only; for external, we already know where they go).
++  const SocketAddress& default_destination() const { return default_dest_; }
++  void set_default_destination(const SocketAddress& addr) {
++    default_dest_ = addr;
++  }
++
++private:
++  RelayServerBinding* binding_;
++  SocketAddressPair addr_pair_;
++  AsyncPacketSocket* socket_;
++  bool locked_;
++  SocketAddress default_dest_;
++};
++
++// Records a set of internal and external connections that we relay between,
++// or in other words, that are "bound" together.
++class RelayServerBinding : public MessageHandler {
++public:
++  RelayServerBinding(
++      RelayServer* server, const std::string& username,
++      const std::string& password, uint32 lifetime);
++  virtual ~RelayServerBinding();
++
++  RelayServer* server() { return server_; }
++  uint32 lifetime() { return lifetime_; }
++  const std::string& username() { return username_; }
++  const std::string& password() { return password_; }
++  const std::string& magic_cookie() { return magic_cookie_; }
++
++  // Adds/Removes a connection into the binding.
++  void AddInternalConnection(RelayServerConnection* conn);
++  void AddExternalConnection(RelayServerConnection* conn);
++
++  // We keep track of the use of each binding.  If we detect that it was not
++  // used for longer than the lifetime, then we send a signal.
++  void NoteUsed();
++  sigslot::signal1<RelayServerBinding*> SignalTimeout;
++
++  // Determines whether the given packet has the magic cookie present (in the
++  // right place).
++  bool HasMagicCookie(const char* bytes, size_t size) const;
++
++  // Determines the connection to use to send packets to or from the given
++  // external address.
++  RelayServerConnection* GetInternalConnection(const SocketAddress& ext_addr);
++  RelayServerConnection* GetExternalConnection(const SocketAddress& ext_addr);
++
++  // MessageHandler:
++  void OnMessage(Message *pmsg);
++
++private:
++  RelayServer* server_;
++
++  std::string username_;
++  std::string password_;
++  std::string magic_cookie_;
++
++  std::vector<RelayServerConnection*> internal_connections_;
++  std::vector<RelayServerConnection*> external_connections_;
++
++  uint32 lifetime_;
++  uint32 last_used_;
++  // TODO: bandwidth
++};
++
++} // namespace cricket
++
++#endif // __RELAYSERVER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc	(revision 586398)
+@@ -0,0 +1,75 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/host.h"
++#include "talk/base/thread.h"
++#include "talk/p2p/base/relayserver.h"
++#include <iostream>
++#include <assert.h>
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++using namespace cricket;
++
++int main(int argc, char **argv) {
++  if (argc != 1) {
++    std::cerr << "usage: relayserver" << std::endl;
++    return 1;
++  }
++
++  assert(LocalHost().networks().size() >= 2);
++  SocketAddress int_addr(LocalHost().networks()[1]->ip(), 5000);
++  SocketAddress ext_addr(LocalHost().networks()[1]->ip(), 5001);
++  
++  Thread *pthMain = Thread::Current(); 
++  
++  AsyncUDPSocket* int_socket = CreateAsyncUDPSocket(pthMain->socketserver());
++  if (int_socket->Bind(int_addr) < 0) {
++    std::cerr << "bind: " << std::strerror(errno) << std::endl;
++    return 1;
++  }
++
++  AsyncUDPSocket* ext_socket = CreateAsyncUDPSocket(pthMain->socketserver());
++  if (ext_socket->Bind(ext_addr) < 0) {
++    std::cerr << "bind: " << std::strerror(errno) << std::endl;
++    return 1;
++  }
++
++  RelayServer server(pthMain);
++  server.AddInternalSocket(int_socket);
++  server.AddExternalSocket(ext_socket);
++
++  std::cout << "Listening internally at " << int_addr.ToString() << std::endl;
++  std::cout << "Listening externally at " << ext_addr.ToString() << std::endl;
++
++  pthMain->Loop();
++  return 0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h	(revision 586398)
+@@ -0,0 +1,164 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++// P2PSocket wraps up the state management of the connection between two
++// P2P clients.  Clients have candidate ports for connecting, and connections
++// which are combinations of candidates from each end (Alice and Bob each
++// have candidates, one candidate from Alice and one candidate from Bob are
++// used to make a connection, repeat to make many connections).
++//
++// When all of the available connections become invalid (non-writable), we
++// kick off a process of determining more candidates and more connections.
++//
++#ifndef _CRICKET_P2P_BASE_P2PSOCKET_H_
++#define _CRICKET_P2P_BASE_P2PSOCKET_H_
++
++#include <vector>
++#include <string>
++#include "talk/base/sigslot.h"
++#include "talk/p2p/base/candidate.h"
++#include "talk/p2p/base/port.h"
++#include "talk/p2p/base/portallocator.h"
++
++namespace cricket {
++
++// Adds the port on which the candidate originated.
++class RemoteCandidate: public Candidate {
++ public:
++  RemoteCandidate(const Candidate& c, Port* origin_port)
++    : Candidate(c), origin_port_(origin_port) {}
++
++  Port* origin_port() { return origin_port_; }
++
++ private:
++  Port* origin_port_;
++};
++
++// P2PSocket manages the candidates and connection process to keep two P2P
++// clients connected to each other.
++class P2PSocket : public MessageHandler, public sigslot::has_slots<> {
++ public:
++  enum State {
++    STATE_CONNECTING = 0,    // establishing writability
++    STATE_WRITABLE,          // connected - ready for writing
++  };
++
++  P2PSocket(const std::string &name, PortAllocator *allocator);
++  virtual ~P2PSocket();
++
++  // Typically SocketManager calls these
++
++  const std::string &name() const;
++  void StartProcessingCandidates();
++  void AddRemoteCandidates(const std::vector<Candidate> &remote_candidates);
++  void OnSignalingReady();
++  void Reset();
++
++  // Typically the Session Client calls these
++
++  int Send(const char *data, size_t len);
++  int SetOption(Socket::Option opt, int value);
++  int GetError();
++
++  State state();
++  bool writable();
++  const std::vector<Connection *>& connections();
++  Connection* best_connection() { return best_connection_; }
++  Thread *thread();
++
++  sigslot::signal2<P2PSocket *, State> SignalState;
++  sigslot::signal0<> SignalRequestSignaling;
++  sigslot::signal3<P2PSocket *, const char *, size_t> SignalReadPacket;
++  sigslot::signal2<P2PSocket *, const SocketAddress &> SignalConnectionChanged;
++  sigslot::signal2<P2PSocket *, const std::vector<Candidate>&> 
++      SignalCandidatesReady;
++  sigslot::signal1<P2PSocket *> SignalConnectionMonitor;
++
++  // Handler for internal messages.
++  virtual void OnMessage(Message *pmsg);
++
++ private:
++  void set_state(State state);
++  void UpdateConnectionStates();
++  void RequestSort();
++  void SortConnections();
++  void SwitchBestConnectionTo(Connection* conn);
++  void HandleWritable();
++  void HandleNotWritable();
++  void HandleAllTimedOut();
++  Connection* GetBestConnectionOnNetwork(Network* network);
++  bool CreateConnections(const Candidate &remote_candidate, Port* origin_port, 
++                         bool readable);
++  bool CreateConnection(Port* port, const Candidate& remote_candidate, 
++                        Port* origin_port, bool readable);
++  void RememberRemoteCandidate(const Candidate& remote_candidate, 
++                               Port* origin_port);
++  void OnUnknownAddress(Port *port, const SocketAddress &addr, 
++                        StunMessage *stun_msg, 
++                        const std::string &remote_username);
++  void OnPortReady(PortAllocatorSession *session, Port* port);
++  void OnCandidatesReady(PortAllocatorSession *session, 
++                         const std::vector<Candidate>& candidates);
++  void OnConnectionStateChange(Connection *connection);
++  void OnConnectionDestroyed(Connection *connection);
++  void OnPortDestroyed(Port* port);
++  void OnAllocate();
++  void OnReadPacket(Connection *connection, const char *data, size_t len);
++  void OnSort();
++  void OnPing();
++  bool IsPingable(Connection* conn);
++  Connection* FindNextPingableConnection();
++  uint32 NumPingableConnections();
++  PortAllocatorSession* allocator_session() {
++    return allocator_sessions_.back();
++  }
++  void AddAllocatorSession(PortAllocatorSession* session);
++
++  Thread *worker_thread_;
++  State state_;
++  bool waiting_for_signaling_;
++  int error_;
++  std::string name_;
++  PortAllocator *allocator_;
++  std::vector<PortAllocatorSession*> allocator_sessions_;
++  std::vector<Port *> ports_;
++  std::vector<Connection *> connections_;
++  Connection *best_connection_;
++  std::vector<RemoteCandidate> remote_candidates_;
++  bool pinging_started_;  // indicates whether StartGetAllCandidates has been called
++  bool sort_dirty_; // indicates whether another sort is needed right now
++  bool was_writable_;
++  bool was_timed_out_;
++  typedef std::map<Socket::Option, int> OptionMap;
++  OptionMap options_;
++
++  DISALLOW_EVIL_CONSTRUCTORS(P2PSocket);
++};
++
++} // namespace cricket
++
++#endif // _CRICKET_P2P_BASE_P2PSOCKET_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc	(revision 586398)
+@@ -0,0 +1,173 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/common.h"
++#include "talk/p2p/base/helpers.h"
++#include "sessionmanager.h"
++
++namespace cricket {
++
++SessionManager::SessionManager(PortAllocator *allocator, Thread *worker) {
++  allocator_ = allocator;
++  signaling_thread_ = Thread::Current();
++  if (worker == NULL) {
++    worker_thread_ = Thread::Current();
++  } else {
++    worker_thread_ = worker;
++  }
++  timeout_ = 50;
++}
++
++SessionManager::~SessionManager() {
++  // Note: Session::Terminate occurs asynchronously, so it's too late to
++  // delete them now.  They better be all gone.
++  ASSERT(session_map_.empty());
++  //TerminateAll();
++}
++
++Session *SessionManager::CreateSession(const std::string &name, const std::string& initiator) {
++  return CreateSession(name, SessionID(initiator, CreateRandomId()), false);
++}
++
++Session *SessionManager::CreateSession(const std::string &name, const SessionID& id, bool received_initiate) {
++  Session *session = new Session(this, name, id);
++  session_map_[session->id()] = session;
++  session->SignalRequestSignaling.connect(this, &SessionManager::OnRequestSignaling);
++  SignalSessionCreate(session, received_initiate);
++  return session;
++}
++
++void SessionManager::DestroySession(Session *session) {
++  if (session != NULL) {
++    std::map<SessionID, Session *>::iterator it = session_map_.find(session->id());
++    if (it != session_map_.end()) {
++      SignalSessionDestroy(session);
++      session_map_.erase(it);
++      delete session;
++    }
++  }
++}
++
++Session *SessionManager::GetSession(const SessionID& id) {
++  // If the id isn't present, the [] operator will make a NULL entry
++  std::map<SessionID, Session *>::iterator it = session_map_.find(id);
++  if (it != session_map_.end())
++    return (*it).second;
++  return NULL;
++}
++
++void SessionManager::TerminateAll() {
++  while (session_map_.begin() != session_map_.end()) {
++    Session *session = session_map_.begin()->second;
++    session->Terminate();
++  }
++}
++
++void SessionManager::OnIncomingError(const SessionMessage &m) {
++  // Incoming signaling error. This means, as the result of trying
++  // to send message m, and error was generated. In all cases, a
++  // session should already exist
++
++  Session *session;
++  switch (m.type()) {
++  case SessionMessage::TYPE_INITIATE:
++  case SessionMessage::TYPE_ACCEPT:
++  case SessionMessage::TYPE_MODIFY:
++  case SessionMessage::TYPE_CANDIDATES:
++  case SessionMessage::TYPE_REJECT:
++  case SessionMessage::TYPE_TERMINATE:
++    session = GetSession(m.session_id());
++    break;
++
++  default:
++    return;
++  }
++
++  if (session != NULL)
++    session->OnIncomingError(m);  
++
++}
++
++void SessionManager::OnIncomingMessage(const SessionMessage &m) {
++  // In the case of an incoming initiate, there is no session yet, and one needs to be created.
++  // The other cases have sessions already.
++
++  Session *session;
++  switch (m.type()) {
++  case SessionMessage::TYPE_INITIATE:
++    session = CreateSession(m.name(), m.session_id(), true);
++    break;
++
++  case SessionMessage::TYPE_ACCEPT:
++  case SessionMessage::TYPE_MODIFY:
++  case SessionMessage::TYPE_CANDIDATES:
++  case SessionMessage::TYPE_REJECT:
++  case SessionMessage::TYPE_REDIRECT:
++  case SessionMessage::TYPE_TERMINATE:
++    session = GetSession(m.session_id());
++    break;
++
++  default:
++    return;
++  }
++
++  if (session != NULL)
++    session->OnIncomingMessage(m);
++}
++
++void SessionManager::OnSignalingReady() {
++  for (std::map<SessionID, Session *>::iterator it = session_map_.begin();
++      it != session_map_.end(); ++it) {
++    it->second->OnSignalingReady();
++  }
++}
++
++void SessionManager::OnRequestSignaling() {
++  SignalRequestSignaling();
++}
++
++PortAllocator *SessionManager::port_allocator() const {
++  return allocator_;
++}
++
++Thread *SessionManager::worker_thread() const {
++  return worker_thread_;
++}
++
++Thread *SessionManager::signaling_thread() const {
++  return signaling_thread_;
++}
++
++int SessionManager::session_timeout() {
++  return timeout_;
++}
++
++void SessionManager::set_session_timeout(int timeout) {
++  timeout_ = timeout;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h	(revision 586398)
+@@ -0,0 +1,118 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CANDIDATE_H_
++#define _CANDIDATE_H_
++
++#include <string>
++#include <sstream>
++#include "talk/base/socketaddress.h"
++
++namespace cricket {
++
++// Candidate for ICE based connection discovery.
++
++class Candidate {
++public:
++
++  const std::string & name() const { return name_; }
++  void set_name(const std::string & name) { name_ = name; }
++
++  const std::string & protocol() const { return protocol_; }
++  void set_protocol(const std::string & protocol) { protocol_ = protocol; }
++
++  const SocketAddress & address() const { return address_; }
++  void set_address(const SocketAddress & address) { address_ = address; }
++
++  const float preference() const { return preference_; }
++  void set_preference(const float preference) { preference_ = preference; }
++  const std::string preference_str() const {
++    std::ostringstream ost;
++    ost << preference_;
++    return ost.str();
++  }
++  void set_preference_str(const std::string & preference) {
++    std::istringstream ist(preference);
++    ist >> preference_;
++  }
++
++  const std::string & username() const { return username_; }
++  void set_username(const std::string & username) { username_ = username; }
++
++  const std::string & password() const { return password_; }
++  void set_password(const std::string & password) { password_ = password; }
++
++  const std::string & type() const { return type_; }
++  void set_type(const std::string & type) { type_ = type; }
++
++  const std::string & network_name() const { return network_name_; }
++  void set_network_name(const std::string & network_name) {
++    network_name_ = network_name;
++  }
++
++  // Candidates in a new generation replace those in the old generation.
++  uint32 generation() const { return generation_; }
++  void set_generation(uint32 generation) { generation_ = generation; }
++  const std::string generation_str() const {
++    std::ostringstream ost;
++    ost << generation_;
++    return ost.str();
++  }
++  void set_generation_str(const std::string& str) {
++    std::istringstream ist(str);
++    ist >> generation_;
++  }
++
++  // Determines whether this candidate is equivalent to the given one.
++  bool IsEquivalent(const Candidate& c) const {
++    // We ignore the network name, since that is just debug information, and
++    // the preference, since that should be the same if the rest is (and it's
++    // a float so equality checking is always worrisome).
++    return (name_ == c.name_) &&
++           (protocol_ == c.protocol_) &&
++           (address_ == c.address_) &&
++           (username_ == c.username_) &&
++           (password_ == c.password_) &&
++           (type_ == c.type_) &&
++           (generation_ == c.generation_);
++  }
++
++private:
++  std::string name_;
++  std::string protocol_;
++  SocketAddress address_;
++  float preference_;
++  std::string username_;
++  std::string password_;
++  std::string type_;
++  std::string network_name_;
++  uint32 generation_;
++};
++
++} // namespace cricket
++
++#endif // _CANDIDATE_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc	(revision 586398)
+@@ -0,0 +1,160 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/bytebuffer.h"
++#include "talk/p2p/base/stunserver.h"
++#include <iostream>
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++StunServer::StunServer(AsyncUDPSocket* socket) : socket_(socket) {
++  socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
++}
++
++StunServer::~StunServer() {
++  socket_->SignalReadPacket.disconnect(this);
++}
++
++void StunServer::OnPacket(
++    const char* buf, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket) {
++
++  // TODO: If appropriate, look for the magic cookie before parsing.
++
++  // Parse the STUN message.
++  ByteBuffer bbuf(buf, size);
++  StunMessage msg;
++  if (!msg.Read(&bbuf)) {
++    SendErrorResponse(msg, remote_addr, 400, "Bad Request");
++    return;
++  }
++
++  // TODO: If this is UDP, then we shouldn't allow non-fully-parsed messages.
++
++  // TODO: If unknown non-optiional (<= 0x7fff) attributes are found, send a
++  //       420 "Unknown Attribute" response.
++
++  // TODO: Check that a message-integrity attribute was given (or send 401
++  //       "Unauthorized").  Check that a username attribute was given (or send
++  //       432 "Missing Username").  Look up the username and password.  If it
++  //       is missing or the HMAC is wrong, send 431 "Integrity Check Failure".
++
++  // Send the message to the appropriate handler function.
++  switch (msg.type()) {
++  case STUN_BINDING_REQUEST:
++    OnBindingRequest(&msg, remote_addr);
++    return;
++
++  case STUN_ALLOCATE_REQUEST:
++    OnAllocateRequest(&msg, remote_addr);
++    return;
++
++  default:
++    SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
++  }
++}
++
++void StunServer::OnBindingRequest(
++    StunMessage* msg, const SocketAddress& remote_addr) {
++  StunMessage response;
++  response.SetType(STUN_BINDING_RESPONSE);
++  response.SetTransactionID(msg->transaction_id());
++
++  // Tell the user the address that we received their request from.
++  StunAddressAttribute* mapped_addr =
++      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
++  mapped_addr->SetFamily(1);
++  mapped_addr->SetPort(remote_addr.port());
++  mapped_addr->SetIP(remote_addr.ip());
++  response.AddAttribute(mapped_addr);
++
++  // Tell the user the address that we are sending the response from.
++  SocketAddress local_addr = socket_->GetLocalAddress();
++  StunAddressAttribute* source_addr =
++      StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
++  source_addr->SetFamily(1);
++  source_addr->SetPort(local_addr.port());
++  source_addr->SetIP(local_addr.ip());
++  response.AddAttribute(source_addr);
++
++  // TODO: Add username and message-integrity.
++
++  // TODO: Add changed-address.  (Keep information about three other servers.)
++
++  SendResponse(response, remote_addr);
++}
++
++void StunServer::OnAllocateRequest(
++    StunMessage* msg, const SocketAddress& addr) {
++  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
++}
++
++void StunServer::OnSharedSecretRequest(
++    StunMessage* msg, const SocketAddress& addr) {
++  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
++}
++
++void StunServer::OnSendRequest(StunMessage* msg, const SocketAddress& addr) {
++  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
++}
++
++void StunServer::SendErrorResponse(
++    const StunMessage& msg, const SocketAddress& addr, int error_code,
++    const char* error_desc) {
++
++  StunMessage err_msg;
++  err_msg.SetType(GetStunErrorResponseType(msg.type()));
++  err_msg.SetTransactionID(msg.transaction_id());
++
++  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
++  err_code->SetErrorClass(error_code / 100);
++  err_code->SetNumber(error_code % 100);
++  err_code->SetReason(error_desc);
++  err_msg.AddAttribute(err_code);
++
++  SendResponse(err_msg, addr);
++}
++
++void StunServer::SendResponse(
++    const StunMessage& msg, const SocketAddress& addr) {
++
++  ByteBuffer buf;
++  msg.Write(&buf);
++
++  // TODO: Allow response addr attribute if sent from another stun server.
++
++  if (socket_->SendTo(buf.Data(), buf.Length(), addr) < 0)
++    std::cerr << "sendto: " << std::strerror(errno) << std::endl;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc	(revision 586398)
+@@ -0,0 +1,273 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "socketmanager.h"
++#include <cassert>
++
++namespace cricket {
++
++const uint32 MSG_CREATESOCKET = 1;
++const uint32 MSG_DESTROYSOCKET = 2;
++const uint32 MSG_ONSIGNALINGREADY = 3;
++const uint32 MSG_CANDIDATESREADY = 4;
++const uint32 MSG_ADDREMOTECANDIDATES = 5;
++const uint32 MSG_ONREQUESTSIGNALING = 6;
++const uint32 MSG_RESETSOCKETS = 7;
++
++struct CreateParams {
++  CreateParams() {}
++  P2PSocket *socket;
++  std::string name;
++};
++
++SocketManager::SocketManager(SessionManager *session_manager) {
++  session_manager_ = session_manager;
++  candidates_requested_ = false;
++  writable_ = false;
++}
++
++SocketManager::~SocketManager() {
++  assert(Thread::Current() == session_manager_->signaling_thread());
++
++  // Are the sockets destroyed? If not, destroy them
++
++  critSM_.Enter();
++  while (sockets_.size() != 0) {
++    P2PSocket *socket = sockets_[0];
++    critSM_.Leave();
++    DestroySocket(socket);
++    critSM_.Enter();
++  }
++  critSM_.Leave();
++
++  // Clear queues
++
++  session_manager_->signaling_thread()->Clear(this);
++  session_manager_->worker_thread()->Clear(this);
++}
++
++P2PSocket *SocketManager::CreateSocket(const std::string &name) {
++  // Can occur on any thread
++  CreateParams params;
++  params.name = name;
++  params.socket = NULL;
++  TypedMessageData<CreateParams *> data(&params);
++  session_manager_->worker_thread()->Send(this, MSG_CREATESOCKET, &data);
++  return data.data()->socket;
++}
++
++P2PSocket *SocketManager::CreateSocket_w(const std::string &name) {
++  // Only on worker thread
++  assert(Thread::Current() == session_manager_->worker_thread());
++  CritScope cs(&critSM_);
++  P2PSocket *socket = new P2PSocket(name, session_manager_->port_allocator());
++  socket->SignalCandidatesReady.connect(this, &SocketManager::OnCandidatesReady);
++  socket->SignalState.connect(this, &SocketManager::OnSocketState);
++  socket->SignalRequestSignaling.connect(this, &SocketManager::OnRequestSignaling);
++  sockets_.push_back(socket);
++  socket->StartProcessingCandidates();
++  return socket;
++}
++
++void SocketManager::DestroySocket(P2PSocket *socket) {
++  // Can occur on any thread
++  TypedMessageData<P2PSocket *> data(socket);
++  session_manager_->worker_thread()->Send(this, MSG_DESTROYSOCKET, &data);
++}
++
++void SocketManager::DestroySocket_w(P2PSocket *socket) {
++  // Only on worker thread
++  assert(Thread::Current() == session_manager_->worker_thread());
++
++  // Only if socket exists
++  CritScope cs(&critSM_);
++  std::vector<P2PSocket *>::iterator it;
++  it = std::find(sockets_.begin(), sockets_.end(), socket);
++  if (it == sockets_.end())
++    return;
++  sockets_.erase(it);
++  delete socket;
++}
++
++void SocketManager::StartProcessingCandidates() {
++  // Only on signaling thread
++  assert(Thread::Current() == session_manager_->signaling_thread());  
++
++  // When sockets are created, their candidates are requested. 
++  // When the candidates are ready, the client is signaled
++  // on the signaling thread
++  candidates_requested_ = true;
++  session_manager_->signaling_thread()->Post(this, MSG_CANDIDATESREADY);
++}
++
++void SocketManager::OnSignalingReady() {
++  session_manager_->worker_thread()->Post(this, MSG_ONSIGNALINGREADY);
++}
++
++void SocketManager::OnSignalingReady_w() {
++  // Only on worker thread
++  assert(Thread::Current() == session_manager_->worker_thread());
++  for (uint32 i = 0; i < sockets_.size(); ++i) {
++    sockets_[i]->OnSignalingReady();
++  }
++}
++
++void SocketManager::OnCandidatesReady(
++    P2PSocket *socket, const std::vector<Candidate>& candidates) {
++  // Only on worker thread
++  assert(Thread::Current() == session_manager_->worker_thread());
++
++  // Remember candidates
++  CritScope cs(&critSM_);
++  std::vector<Candidate>::const_iterator it;
++  for (it = candidates.begin(); it != candidates.end(); it++)
++    candidates_.push_back(*it);
++
++  // If candidates requested, tell signaling thread 
++  if (candidates_requested_)
++    session_manager_->signaling_thread()->Post(this, MSG_CANDIDATESREADY);
++}
++
++void SocketManager::ResetSockets() {
++  assert(Thread::Current() == session_manager_->signaling_thread());  
++  session_manager_->worker_thread()->Post(this, MSG_RESETSOCKETS);
++}
++
++void SocketManager::ResetSockets_w() {
++  assert(Thread::Current() == session_manager_->worker_thread());  
++
++  for (size_t i = 0; i < sockets_.size(); ++i)
++    sockets_[i]->Reset();
++}
++
++void SocketManager::OnSocketState(P2PSocket* socket, P2PSocket::State state) {
++  assert(Thread::Current() == session_manager_->worker_thread());
++
++  bool writable = false;
++  for (uint32 i = 0; i < sockets_.size(); ++i)
++    if (sockets_[i]->writable())
++      writable = true;
++
++  if (writable_ != writable) {
++    writable_ = writable;
++    SignalState();
++  }
++}
++
++void SocketManager::OnRequestSignaling() {
++  assert(Thread::Current() == session_manager_->worker_thread());
++  session_manager_->signaling_thread()->Post(this, MSG_ONREQUESTSIGNALING);
++}
++
++
++void SocketManager::AddRemoteCandidates(const std::vector<Candidate> &remote_candidates) {
++  assert(Thread::Current() == session_manager_->signaling_thread());
++  TypedMessageData<std::vector<Candidate> > *data = new TypedMessageData<std::vector<Candidate> >(remote_candidates);
++  session_manager_->worker_thread()->Post(this, MSG_ADDREMOTECANDIDATES, data);
++}
++
++void SocketManager::AddRemoteCandidates_w(const std::vector<Candidate> &remote_candidates) {
++  assert(Thread::Current() == session_manager_->worker_thread());
++
++  // Local and remote candidates now exist, so connectivity checking can
++  // commence. Tell the P2PSockets about the remote candidates.
++  // Group candidates by socket name
++
++  CritScope cs(&critSM_);
++  std::vector<P2PSocket *>::iterator it_socket;
++  for (it_socket = sockets_.begin(); it_socket != sockets_.end(); it_socket++) {
++    // Create a vector of remote candidates for each socket
++    std::string name = (*it_socket)->name();
++    std::vector<Candidate> candidate_bundle;
++    std::vector<Candidate>::const_iterator it_candidate;
++    for (it_candidate = remote_candidates.begin(); it_candidate != remote_candidates.end(); it_candidate++) {
++      if ((*it_candidate).name() == name)
++        candidate_bundle.push_back(*it_candidate);
++    }
++    if (candidate_bundle.size() != 0)
++      (*it_socket)->AddRemoteCandidates(candidate_bundle);
++  }
++}
++
++void SocketManager::OnMessage(Message *message) {
++  switch (message->message_id) {
++  case MSG_CREATESOCKET:
++    {
++      assert(Thread::Current() == session_manager_->worker_thread());
++      TypedMessageData<CreateParams *> *params = static_cast<TypedMessageData<CreateParams *> *>(message->pdata);
++      params->data()->socket = CreateSocket_w(params->data()->name);
++    }
++    break;
++
++  case MSG_DESTROYSOCKET:
++    {
++      assert(Thread::Current() == session_manager_->worker_thread());
++      TypedMessageData<P2PSocket *> *data = static_cast<TypedMessageData<P2PSocket *> *>(message->pdata);
++      DestroySocket_w(data->data());
++    }
++    break;
++
++  case MSG_ONSIGNALINGREADY:
++    assert(Thread::Current() == session_manager_->worker_thread());
++    OnSignalingReady_w();
++    break;
++
++  case MSG_ONREQUESTSIGNALING:
++    assert(Thread::Current() == session_manager_->signaling_thread());  
++    SignalRequestSignaling();
++    break;
++
++  case MSG_CANDIDATESREADY:
++    assert(Thread::Current() == session_manager_->signaling_thread());  
++    if (candidates_requested_) {
++      CritScope cs(&critSM_);
++      if (candidates_.size() > 0) {
++        SignalCandidatesReady(candidates_);
++        candidates_.clear();
++      }
++    }
++    break;
++
++  case MSG_ADDREMOTECANDIDATES:
++    {
++      assert(Thread::Current() == session_manager_->worker_thread());
++      TypedMessageData<const std::vector<Candidate> > *data = static_cast<TypedMessageData<const std::vector<Candidate> > *>(message->pdata);
++      AddRemoteCandidates_w(data->data());
++      delete data;
++    }
++    break;
++
++  case MSG_RESETSOCKETS:
++    ResetSockets_w();
++    break;
++  }
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h	(revision 586398)
+@@ -0,0 +1,101 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SOCKETMANAGER_H_
++#define _SOCKETMANAGER_H_
++
++#include "talk/base/criticalsection.h"
++#include "talk/base/messagequeue.h"
++#include "talk/base/sigslot.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/candidate.h"
++#include "talk/p2p/base/p2psocket.h"
++#include "talk/p2p/base/socketmanager.h"
++
++#include <string>
++#include <vector>
++
++namespace cricket {
++
++class SessionManager;
++
++// Manages P2PSocket creation/destruction/readiness.
++// Provides thread separation between session and sockets.
++// This allows session to execute on the signaling thread,
++// and sockets to execute on the worker thread, if desired,
++// which is good for some media types (audio/video for example).
++
++class SocketManager : public MessageHandler, public sigslot::has_slots<> {
++public:
++  SocketManager(SessionManager *session_manager);
++  virtual ~SocketManager();
++
++  // Determines whether any of the created sockets are currently writable.
++  bool writable() { return writable_; }
++
++  P2PSocket *CreateSocket(const std::string & name);
++  void DestroySocket(P2PSocket *socket);
++
++  // Start discovering local candidates
++  void StartProcessingCandidates();
++  
++  // Adds the given candidates that were sent by the remote side.
++  void AddRemoteCandidates(const std::vector<Candidate>& candidates);
++
++  // signaling channel is up, ready to transmit candidates as they are discovered
++  void OnSignalingReady();
++
++  // Put all of the sockets back into the initial state.
++  void ResetSockets();
++  
++  sigslot::signal1<const std::vector<Candidate>&> SignalCandidatesReady;
++  sigslot::signal0<> SignalNetworkError;
++  sigslot::signal0<> SignalState;
++  sigslot::signal0<> SignalRequestSignaling;
++
++private:
++  P2PSocket *CreateSocket_w(const std::string &name);
++  void DestroySocket_w(P2PSocket *socket);
++  void OnSignalingReady_w();
++  void AddRemoteCandidates_w(const std::vector<Candidate> &candidates);
++  virtual void OnMessage(Message *message);
++  void OnCandidatesReady(P2PSocket *socket, const std::vector<Candidate>&);
++  void OnSocketState(P2PSocket* socket, P2PSocket::State state);
++  void OnRequestSignaling(void);
++  void ResetSockets_w();
++
++  SessionManager *session_manager_;
++  std::vector<Candidate> candidates_;
++  CriticalSection critSM_;
++  std::vector<P2PSocket *> sockets_;
++  bool candidates_requested_;
++  bool writable_;
++};
++
++}
++
++#endif // _SOCKETMANAGER_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h	(revision 586398)
+@@ -0,0 +1,367 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __PORT_H__
++#define __PORT_H__
++
++#include "talk/base/network.h"
++#include "talk/base/socketaddress.h"
++#include "talk/base/proxyinfo.h"
++#include "talk/base/sigslot.h"
++#include "talk/base/thread.h"
++#include "talk/p2p/base/candidate.h"
++#include "talk/p2p/base/stun.h"
++#include "talk/p2p/base/stunrequest.h"
++
++#include <string>
++#include <vector>
++#include <map>
++
++namespace cricket {
++
++class Connection;
++class AsyncPacketSocket;
++
++enum ProtocolType { PROTO_UDP, PROTO_TCP, PROTO_SSLTCP, PROTO_LAST = PROTO_SSLTCP };
++const char * ProtoToString(ProtocolType proto);
++bool StringToProto(const char * value, ProtocolType& proto);
++
++struct ProtocolAddress {
++  SocketAddress address;
++  ProtocolType proto;
++
++  ProtocolAddress(const SocketAddress& a, ProtocolType p) : address(a), proto(p) { }
++};
++
++// Represents a local communication mechanism that can be used to create
++// connections to similar mechanisms of the other client.  Subclasses of this
++// one add support for specific mechanisms like local UDP ports.
++class Port: public MessageHandler, public sigslot::has_slots<> {
++public:
++  Port(Thread* thread, const std::string &type, SocketFactory* factory,
++       Network* network);
++  virtual ~Port();
++
++  // The thread on which this port performs its I/O.
++  Thread* thread() { return thread_; }
++
++  // The factory used to create the sockets of this port.
++  SocketFactory* socket_factory() const { return factory_; }
++  void set_socket_factory(SocketFactory* factory) { factory_ = factory; }
++
++  // Each port is identified by a name (for debugging purposes).
++  const std::string& name() const { return name_; }
++  void set_name(const std::string& name) { name_ = name; }
++
++  // In order to establish a connection to this Port (so that real data can be
++  // sent through), the other side must send us a STUN binding request that is
++  // authenticated with this username and password.
++  const std::string& username_fragment() const { return username_frag_; }
++  const std::string& password() const { return password_; }
++
++  // A value in [0,1] that indicates the preference for this port versus other
++  // ports on this client.  (Larger indicates more preference.)
++  float preference() const { return preference_; }
++  void set_preference(float preference) { preference_ = preference; }
++
++  // Identifies the port type.
++  //const std::string& protocol() const { return proto_; }
++  const std::string& type() const { return type_; }
++
++  // Identifies network that this port was allocated on.
++  Network* network() { return network_; }
++
++  // Identifies the generation that this port was created in.
++  uint32 generation() { return generation_; }
++  void set_generation(uint32 generation) { generation_ = generation; }
++
++  // PrepareAddress will attempt to get an address for this port that other
++  // clients can send to.  It may take some time before the address is read.
++  // Once it is ready, we will send SignalAddressReady.
++  virtual void PrepareAddress() = 0;
++  sigslot::signal1<Port*> SignalAddressReady;
++  //const SocketAddress& address() const { return address_; }
++
++  // Provides all of the above information in one handy object.
++  const std::vector<Candidate>& candidates() const { return candidates_; }
++
++  // Returns a map containing all of the connections of this port, keyed by the
++  // remote address.
++  typedef std::map<SocketAddress, Connection*> AddressMap;
++  const AddressMap& connections() { return connections_; }  
++
++  // Returns the connection to the given address or NULL if none exists.
++  Connection* GetConnection(const SocketAddress& remote_addr);
++
++  // Creates a new connection to the given address.
++  enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE };
++  virtual Connection* CreateConnection(const Candidate& remote_candidate, CandidateOrigin origin) = 0;
++
++  // Called each time a connection is created.
++  sigslot::signal2<Port*, Connection*> SignalConnectionCreated;
++
++  // Sends the given packet to the given address, provided that the address is
++  // that of a connection or an address that has sent to us already.
++  virtual int SendTo(
++      const void* data, size_t size, const SocketAddress& addr, bool payload) = 0;
++
++  // Indicates that we received a successful STUN binding request from an
++  // address that doesn't correspond to any current connection.  To turn this
++  // into a real connection, call CreateConnection.
++  sigslot::signal4<Port*, const SocketAddress&, StunMessage*, const std::string&> SignalUnknownAddress;
++
++  // Sends a response message (normal or error) to the given request.  One of
++  // these methods should be called as a response to SignalUnknownAddress.
++  // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse.
++  void SendBindingResponse(StunMessage* request, const SocketAddress& addr);
++  void SendBindingErrorResponse(
++      StunMessage* request, const SocketAddress& addr, int error_code,
++      const std::string& reason);
++
++  // Indicates that errors occurred when performing I/O.
++  sigslot::signal2<Port*, int> SignalReadError;
++  sigslot::signal2<Port*, int> SignalWriteError;
++
++  // Functions on the underlying socket(s).
++  virtual int SetOption(Socket::Option opt, int value) = 0;
++  virtual int GetError() = 0;
++
++  static void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; }
++  static const ProxyInfo& proxy() { return proxy_; }
++
++  AsyncPacketSocket * CreatePacketSocket(ProtocolType proto);
++
++  virtual void OnMessage(Message *pmsg);
++
++  // Indicates to the port that its official use has now begun.  This will
++  // start the timer that checks to see if the port is being used.
++  void Start();
++
++  // Signaled when this port decides to delete itself because it no longer has
++  // any usefulness.
++  sigslot::signal1<Port*> SignalDestroyed;
++
++protected:
++  Thread* thread_;
++  SocketFactory* factory_;
++  std::string type_;
++  Network* network_;
++  uint32 generation_;
++  std::string name_;
++  std::string username_frag_;
++  std::string password_;
++  float preference_;
++  std::vector<Candidate> candidates_;
++  AddressMap connections_;
++  enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
++
++  // Fills in the username fragment and password.  These will be initially set
++  // in the constructor to random values.  Subclasses can override, though.
++  void set_username_fragment(const std::string& username_fragment);
++  void set_password(const std::string& password);
++
++  // Fills in the local address of the port.
++  void add_address(const SocketAddress& address, const std::string& protocol, bool final = true);
++
++  // Adds the given connection to the list.  (Deleting removes them.)
++  void AddConnection(Connection* conn);
++
++  // Called when a packet is received from an unknown address that is not
++  // currently a connection.  If this is an authenticated STUN binding request,
++  // then we will signal the client.
++  void OnReadPacket(const char* data, size_t size, const SocketAddress& addr);
++
++  // Constructs a STUN binding request for the given connection and sends it.
++  void SendBindingRequest(Connection* conn);
++
++  // If the given data comprises a complete and correct STUN message then the
++  // return value is true, otherwise false. If the message username corresponds
++  // with this port's username fragment, msg will contain the parsed STUN
++  // message.  Otherwise, the function may send a STUN response internally.
++  // remote_username contains the remote fragment of the STUN username.
++  bool GetStunMessage(const char* data, size_t size, const SocketAddress& addr,
++    StunMessage *& msg, std::string& remote_username);
++
++  friend class Connection;
++
++private:
++  // Called when one of our connections deletes itself.
++  void OnConnectionDestroyed(Connection* conn);
++
++  // Checks if this port is useless, and hence, should be destroyed.
++  void CheckTimeout();
++
++  static ProxyInfo proxy_;
++};
++
++// Represents a communication link between a port on the local client and a
++// port on the remote client.
++class Connection : public MessageHandler, public sigslot::has_slots<> {
++public:
++  virtual ~Connection();
++
++  // The local port where this connection sends and receives packets.
++  Port* port() { return port_; }
++  const Port* port() const { return port_; }
++
++  // Returns the description of the local port
++  virtual const Candidate& local_candidate() const;
++
++  // Returns the description of the remote port to which we communicate.
++  const Candidate& remote_candidate() const { return remote_candidate_; }
++
++  enum ReadState {
++    STATE_READABLE     = 0, // we have received pings recently
++    STATE_READ_TIMEOUT = 1  // we haven't received pings in a while
++  };
++
++  ReadState read_state() const { return read_state_; }
++
++  enum WriteState {
++    STATE_WRITABLE      = 0, // we have received ping responses recently
++    STATE_WRITE_CONNECT = 1, // we have had a few ping failures
++    STATE_WRITE_TIMEOUT = 2  // we have had a large number of ping failures
++  };
++
++  WriteState write_state() const { return write_state_; }
++
++  // Determines whether the connection has finished connecting.  This can only
++  // be false for TCP connections.
++  bool connected() const { return connected_; }
++
++  // Estimate of the round-trip time over this connection.
++  uint32 rtt() const { return rtt_; }
++
++  size_t sent_total_bytes();
++  size_t sent_bytes_second();
++  size_t recv_total_bytes();
++  size_t recv_bytes_second();
++  sigslot::signal1<Connection*> SignalStateChange;
++
++  // Sent when the connection has decided that it is no longer of value.  It
++  // will delete itself immediately after this call.
++  sigslot::signal1<Connection*> SignalDestroyed;
++
++  // The connection can send and receive packets asynchronously.  This matches
++  // the interface of AsyncPacketSocket, which may use UDP or TCP under the covers.
++  virtual int Send(const void* data, size_t size) = 0;
++
++  // Error if Send() returns < 0
++  virtual int GetError() = 0;
++
++  sigslot::signal3<Connection*, const char*, size_t> SignalReadPacket;
++
++  // Called when a packet is received on this connection.
++  void OnReadPacket(const char* data, size_t size);
++
++  // Called when a connection is determined to be no longer useful to us.  We
++  // still keep it around in case the other side wants to use it.  But we can
++  // safely stop pinging on it and we can allow it to time out if the other
++  // side stops using it as well.
++  bool pruned() { return pruned_; }
++  void Prune();
++
++  // Makes the connection go away.
++  void Destroy();
++
++  // Checks that the state of this connection is up-to-date.  The argument is
++  // the current time, which is compared against various timeouts.
++  void UpdateState(uint32 now);
++
++  // Called when this connection should try checking writability again.
++  uint32 last_ping_sent() { return last_ping_sent_; }
++  void Ping(uint32 now);
++
++  // Called whenever a valid ping is received on this connection.  This is
++  // public because the connection intercepts the first ping for us.
++  void ReceivedPing();
++
++protected:
++  Port* port_;
++  size_t local_candidate_index_;
++  Candidate remote_candidate_;
++  ReadState read_state_;
++  WriteState write_state_;
++  bool connected_;
++  bool pruned_;
++  StunRequestManager requests_;
++  uint32 rtt_;
++  uint32 rtt_data_points_;
++  uint32 last_ping_sent_;     // last time we sent a ping to the other side
++  uint32 last_ping_received_; // last time we received a ping from the other side
++  std::vector<uint32> pings_since_last_response_;
++
++  size_t recv_total_bytes_;
++  size_t recv_bytes_second_;
++  uint32 last_recv_bytes_second_time_;
++  size_t last_recv_bytes_second_calc_;
++
++  size_t sent_total_bytes_;
++  size_t sent_bytes_second_;
++  uint32 last_sent_bytes_second_time_;
++  size_t last_sent_bytes_second_calc_;
++
++  // Callbacks from ConnectionRequest
++  void OnConnectionRequestResponse(StunMessage *response, uint32 rtt);
++  void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt);
++
++  // Called back when StunRequestManager has a stun packet to send
++  void OnSendStunPacket(const void* data, size_t size);
++
++  // Constructs a new connection to the given remote port.
++  Connection(Port* port, size_t index, const Candidate& candidate);
++
++  // Changes the state and signals if necessary.
++  void set_read_state(ReadState value);
++  void set_write_state(WriteState value);
++  void set_connected(bool value);
++
++  // Checks if this connection is useless, and hence, should be destroyed.
++  void CheckTimeout();
++
++  void OnMessage(Message *pmsg);
++
++  friend class Port;
++  friend class ConnectionRequest;
++};
++
++// ProxyConnection defers all the interesting work to the port
++
++class ProxyConnection : public Connection {
++public:
++  ProxyConnection(Port* port, size_t index, const Candidate& candidate);
++
++  virtual int Send(const void* data, size_t size);
++  virtual int GetError() { return error_; }
++
++private:
++  int error_;
++};
++
++} // namespace cricket
++
++#endif // __PORT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h	(revision 586398)
+@@ -0,0 +1,91 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _PORTALLOCATOR_H_
++#define _PORTALLOCATOR_H_
++
++#include "talk/base/sigslot.h"
++#include "talk/p2p/base/port.h"
++#include <string>
++#undef SetPort
++
++namespace cricket {
++
++// PortAllocator is responsible for allocating Port types for a given
++// P2PSocket. It also handles port freeing.
++//
++// Clients can override this class to control port allocation, including
++// what kinds of ports are allocated.
++
++class PortAllocatorSession : public sigslot::has_slots<> {
++public:
++  // Prepares an initial set of ports to try.
++  virtual void GetInitialPorts() = 0;
++
++  // Starts and stops the flow of additional ports to try.
++  virtual void StartGetAllPorts() = 0;
++  virtual void StopGetAllPorts() = 0;
++  virtual bool IsGettingAllPorts() = 0;
++
++  sigslot::signal2<PortAllocatorSession*, Port*> SignalPortReady;
++  sigslot::signal2<PortAllocatorSession*, const std::vector<Candidate>&> SignalCandidatesReady;
++
++  uint32 generation() { return generation_; }
++  void set_generation(uint32 generation) { generation_ = generation; }
++
++private:
++  uint32 generation_;
++};
++
++const uint32 PORTALLOCATOR_DISABLE_UDP = 0x01;
++const uint32 PORTALLOCATOR_DISABLE_STUN = 0x02;
++const uint32 PORTALLOCATOR_DISABLE_RELAY = 0x04;
++const uint32 PORTALLOCATOR_DISABLE_TCP = 0x08;
++const uint32 PORTALLOCATOR_ENABLE_SHAKER = 0x10;
++
++const uint32 kDefaultPortAllocatorFlags = 0;
++
++class PortAllocator {
++public:
++  PortAllocator() : flags_(kDefaultPortAllocatorFlags) {}
++
++  virtual PortAllocatorSession *CreateSession(const std::string &name) = 0;
++
++  uint32 flags() const { return flags_; }
++  void set_flags(uint32 flags) { flags_ = flags; }
++
++  const ProxyInfo& proxy() const { return proxy_; }
++  void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; }
++
++protected:
++  uint32 flags_;
++  ProxyInfo proxy_;
++};
++
++} // namespace cricket
++
++#endif // _PORTALLOCATOR_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc	(revision 586398)
+@@ -0,0 +1,576 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/logging.h"
++#include "talk/p2p/base/stun.h"
++#include <iostream>
++#include <cassert>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::memcpy;
++}
++#endif
++
++namespace cricket {
++
++const std::string STUN_ERROR_REASON_BAD_REQUEST = "BAD REQUEST";
++const std::string STUN_ERROR_REASON_UNAUTHORIZED = "UNAUTHORIZED";
++const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE = "UNKNOWN ATTRIBUTE";
++const std::string STUN_ERROR_REASON_STALE_CREDENTIALS = "STALE CREDENTIALS";
++const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE = "INTEGRITY CHECK FAILURE";
++const std::string STUN_ERROR_REASON_MISSING_USERNAME = "MISSING USERNAME";
++const std::string STUN_ERROR_REASON_USE_TLS = "USE TLS";
++const std::string STUN_ERROR_REASON_SERVER_ERROR = "SERVER ERROR";
++const std::string STUN_ERROR_REASON_GLOBAL_FAILURE = "GLOBAL FAILURE";
++
++StunMessage::StunMessage() : type_(0), length_(0),
++    transaction_id_("0000000000000000") {
++  assert(transaction_id_.size() == 16);
++  attrs_ = new std::vector<StunAttribute*>();
++}
++
++StunMessage::~StunMessage() {
++  for (unsigned i = 0; i < attrs_->size(); i++)
++    delete (*attrs_)[i];
++  delete attrs_;
++}
++
++void StunMessage::SetTransactionID(const std::string& str) {
++  assert(str.size() == 16);
++  transaction_id_ = str;
++}
++
++void StunMessage::AddAttribute(StunAttribute* attr) {
++  attrs_->push_back(attr);
++  length_ += attr->length() + 4;
++}
++
++const StunAddressAttribute*
++StunMessage::GetAddress(StunAttributeType type) const {
++  switch (type) {
++  case STUN_ATTR_MAPPED_ADDRESS:
++  case STUN_ATTR_RESPONSE_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS:
++  case STUN_ATTR_CHANGED_ADDRESS:
++  case STUN_ATTR_REFLECTED_FROM:
++  case STUN_ATTR_ALTERNATE_SERVER:
++  case STUN_ATTR_DESTINATION_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS2:
++    return reinterpret_cast<const StunAddressAttribute*>(GetAttribute(type));
++
++  default:
++    assert(0);
++    return 0;
++  }
++}
++
++const StunUInt32Attribute*
++StunMessage::GetUInt32(StunAttributeType type) const {
++  switch (type) {
++  case STUN_ATTR_CHANGE_REQUEST:
++  case STUN_ATTR_LIFETIME:
++  case STUN_ATTR_BANDWIDTH:
++  case STUN_ATTR_OPTIONS:
++    return reinterpret_cast<const StunUInt32Attribute*>(GetAttribute(type));
++
++  default:
++    assert(0);
++    return 0;
++  }
++}
++
++const StunByteStringAttribute*
++StunMessage::GetByteString(StunAttributeType type) const {
++  switch (type) {
++  case STUN_ATTR_USERNAME:
++  case STUN_ATTR_PASSWORD:
++  case STUN_ATTR_MESSAGE_INTEGRITY:
++  case STUN_ATTR_DATA:
++  case STUN_ATTR_MAGIC_COOKIE:
++    return reinterpret_cast<const StunByteStringAttribute*>(GetAttribute(type));
++
++  default:
++    assert(0);
++    return 0;
++  }
++}
++
++const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
++  return reinterpret_cast<const StunErrorCodeAttribute*>(
++      GetAttribute(STUN_ATTR_ERROR_CODE));
++}
++
++const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
++  return reinterpret_cast<const StunUInt16ListAttribute*>(
++      GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
++}
++
++const StunTransportPrefsAttribute* StunMessage::GetTransportPrefs() const {
++  return reinterpret_cast<const StunTransportPrefsAttribute*>(
++      GetAttribute(STUN_ATTR_TRANSPORT_PREFERENCES));
++}
++
++const StunAttribute* StunMessage::GetAttribute(StunAttributeType type) const {
++  for (unsigned i = 0; i < attrs_->size(); i++) {
++    if ((*attrs_)[i]->type() == type)
++      return (*attrs_)[i];
++  }
++  return 0;
++}
++
++bool StunMessage::Read(ByteBuffer* buf) {
++  if (!buf->ReadUInt16(type_))
++    return false;
++
++  if (!buf->ReadUInt16(length_))
++    return false;
++
++  std::string transaction_id;
++  if (!buf->ReadString(transaction_id, 16))
++    return false;
++  assert(transaction_id.size() == 16);
++  transaction_id_ = transaction_id;
++
++  if (length_ > buf->Length())
++    return false;
++
++  attrs_->resize(0);
++
++  size_t rest = buf->Length() - length_;
++  while (buf->Length() > rest) {
++    uint16 attr_type, attr_length;
++    if (!buf->ReadUInt16(attr_type))
++      return false;
++    if (!buf->ReadUInt16(attr_length))
++      return false;
++
++    StunAttribute* attr = StunAttribute::Create(attr_type, attr_length);
++    if (!attr || !attr->Read(buf))
++      return false;
++
++    attrs_->push_back(attr);
++  }
++
++  if (buf->Length() != rest) {
++    // fixme: shouldn't be doing this
++    LOG(LERROR) << "wrong message length" 
++               << " (" << (int)rest << " != " << (int)buf->Length() << ")";
++    return false;
++  }
++
++  return true;
++}
++
++void StunMessage::Write(ByteBuffer* buf) const {
++  buf->WriteUInt16(type_);
++  buf->WriteUInt16(length_);
++  buf->WriteString(transaction_id_);
++
++  for (unsigned i = 0; i < attrs_->size(); i++) {
++    buf->WriteUInt16((*attrs_)[i]->type());
++    buf->WriteUInt16((*attrs_)[i]->length());
++    (*attrs_)[i]->Write(buf);
++  }
++}
++
++StunAttribute::StunAttribute(uint16 type, uint16 length)
++    : type_(type), length_(length) {
++}
++
++StunAttribute* StunAttribute::Create(uint16 type, uint16 length) {
++  switch (type) {
++  case STUN_ATTR_MAPPED_ADDRESS:
++  case STUN_ATTR_RESPONSE_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS:
++  case STUN_ATTR_CHANGED_ADDRESS:
++  case STUN_ATTR_REFLECTED_FROM:
++  case STUN_ATTR_ALTERNATE_SERVER:
++  case STUN_ATTR_DESTINATION_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS2:
++    if (length != StunAddressAttribute::SIZE)
++      return 0;
++    return new StunAddressAttribute(type);
++
++  case STUN_ATTR_CHANGE_REQUEST:
++  case STUN_ATTR_LIFETIME:
++  case STUN_ATTR_BANDWIDTH:
++  case STUN_ATTR_OPTIONS:
++    if (length != StunUInt32Attribute::SIZE)
++      return 0;
++    return new StunUInt32Attribute(type);
++
++  case STUN_ATTR_USERNAME:
++  case STUN_ATTR_PASSWORD:
++  case STUN_ATTR_MAGIC_COOKIE:
++    return (length % 4 == 0) ? new StunByteStringAttribute(type, length) : 0;
++
++  case STUN_ATTR_MESSAGE_INTEGRITY:
++    return (length == 20) ? new StunByteStringAttribute(type, length) : 0;
++
++  case STUN_ATTR_DATA:
++    return new StunByteStringAttribute(type, length);
++
++  case STUN_ATTR_ERROR_CODE:
++    if (length < StunErrorCodeAttribute::MIN_SIZE)
++      return 0;
++    return new StunErrorCodeAttribute(type, length);
++
++  case STUN_ATTR_UNKNOWN_ATTRIBUTES:
++    return (length % 2 == 0) ? new StunUInt16ListAttribute(type, length) : 0;
++
++  case STUN_ATTR_TRANSPORT_PREFERENCES:
++    if ((length != StunTransportPrefsAttribute::SIZE1) &&
++	(length != StunTransportPrefsAttribute::SIZE2))
++      return 0;
++    return new StunTransportPrefsAttribute(type, length);
++
++  default:
++    return 0;
++  }
++}
++
++StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
++  switch (type) {
++  case STUN_ATTR_MAPPED_ADDRESS:
++  case STUN_ATTR_RESPONSE_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS:
++  case STUN_ATTR_CHANGED_ADDRESS:
++  case STUN_ATTR_REFLECTED_FROM:
++  case STUN_ATTR_ALTERNATE_SERVER:
++  case STUN_ATTR_DESTINATION_ADDRESS:
++  case STUN_ATTR_SOURCE_ADDRESS2:
++    return new StunAddressAttribute(type);
++
++  default:
++    assert(false);
++    return 0;
++  }
++}
++
++StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
++  switch (type) {
++  case STUN_ATTR_CHANGE_REQUEST:
++  case STUN_ATTR_LIFETIME:
++  case STUN_ATTR_BANDWIDTH:
++  case STUN_ATTR_OPTIONS:
++    return new StunUInt32Attribute(type);
++
++  default:
++    assert(false);
++    return 0;
++  }
++}
++
++StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
++  switch (type) {
++  case STUN_ATTR_USERNAME:
++  case STUN_ATTR_PASSWORD:
++  case STUN_ATTR_MESSAGE_INTEGRITY:
++  case STUN_ATTR_DATA:
++  case STUN_ATTR_MAGIC_COOKIE:
++    return new StunByteStringAttribute(type, 0);
++
++  default:
++    assert(false);
++    return 0;
++  }
++}
++
++StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
++  return new StunErrorCodeAttribute(
++      STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
++}
++
++StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
++  return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
++}
++
++StunTransportPrefsAttribute* StunAttribute::CreateTransportPrefs() {
++  return new StunTransportPrefsAttribute(
++      STUN_ATTR_TRANSPORT_PREFERENCES, StunTransportPrefsAttribute::SIZE1);
++}
++
++StunAddressAttribute::StunAddressAttribute(uint16 type)
++    : StunAttribute(type, SIZE), family_(0), port_(0), ip_(0) {
++}
++
++bool StunAddressAttribute::Read(ByteBuffer* buf) {
++  uint8 dummy;
++  if (!buf->ReadUInt8(dummy))
++    return false;
++  if (!buf->ReadUInt8(family_))
++    return false;
++  if (!buf->ReadUInt16(port_))
++    return false;
++  if (!buf->ReadUInt32(ip_))
++    return false;
++  return true;
++}
++
++void StunAddressAttribute::Write(ByteBuffer* buf) const {
++  buf->WriteUInt8(0);
++  buf->WriteUInt8(family_);
++  buf->WriteUInt16(port_);
++  buf->WriteUInt32(ip_);
++}
++
++StunUInt32Attribute::StunUInt32Attribute(uint16 type)
++    : StunAttribute(type, SIZE), bits_(0) {
++}
++
++bool StunUInt32Attribute::GetBit(int index) const {
++  assert((0 <= index) && (index < 32));
++  return static_cast<bool>((bits_ >> index) & 0x1);
++}
++
++void StunUInt32Attribute::SetBit(int index, bool value) {
++  assert((0 <= index) && (index < 32));
++  bits_ &= ~(1 << index);
++  bits_ |= value ? (1 << index) : 0;
++}
++
++bool StunUInt32Attribute::Read(ByteBuffer* buf) {
++  if (!buf->ReadUInt32(bits_))
++    return false;
++  return true;
++}
++
++void StunUInt32Attribute::Write(ByteBuffer* buf) const {
++  buf->WriteUInt32(bits_);
++}
++
++StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
++    : StunAttribute(type, length), bytes_(0) {
++}
++
++StunByteStringAttribute::~StunByteStringAttribute() {
++  delete [] bytes_;
++}
++
++void StunByteStringAttribute::SetBytes(char* bytes, uint16 length) {
++  delete [] bytes_;
++  bytes_ = bytes;
++  SetLength(length);
++}
++
++void StunByteStringAttribute::CopyBytes(const char* bytes) {
++  CopyBytes(bytes, (uint16)strlen(bytes));
++}
++
++void StunByteStringAttribute::CopyBytes(const void* bytes, uint16 length) {
++  char* new_bytes = new char[length];
++  std::memcpy(new_bytes, bytes, length);
++  SetBytes(new_bytes, length);
++}
++
++uint8 StunByteStringAttribute::GetByte(int index) const {
++  assert(bytes_);
++  assert((0 <= index) && (index < length()));
++  return static_cast<uint8>(bytes_[index]);
++}
++
++void StunByteStringAttribute::SetByte(int index, uint8 value) {
++  assert(bytes_);
++  assert((0 <= index) && (index < length()));
++  bytes_[index] = value;
++}
++
++bool StunByteStringAttribute::Read(ByteBuffer* buf) {
++  bytes_ = new char[length()];
++  if (!buf->ReadBytes(bytes_, length()))
++    return false;
++  return true;
++}
++
++void StunByteStringAttribute::Write(ByteBuffer* buf) const {
++  buf->WriteBytes(bytes_, length());
++}
++
++StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
++    : StunAttribute(type, length), class_(0), number_(0) {
++}
++
++StunErrorCodeAttribute::~StunErrorCodeAttribute() {
++}
++
++void StunErrorCodeAttribute::SetErrorCode(uint32 code) {
++  class_ = (uint8)((code >> 8) & 0x7);
++  number_ = (uint8)(code & 0xff);
++}
++
++void StunErrorCodeAttribute::SetReason(const std::string& reason) {
++  SetLength(MIN_SIZE + (uint16)reason.size());
++  reason_ = reason;
++}
++
++bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
++  uint32 val;
++  if (!buf->ReadUInt32(val))
++    return false;
++
++  if ((val >> 11) != 0)
++    LOG(LERROR) << "error-code bits not zero";
++
++  SetErrorCode(val);
++
++  if (!buf->ReadString(reason_, length() - 4))
++    return false;
++
++  return true;
++}
++
++void StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
++  buf->WriteUInt32(error_code());
++  buf->WriteString(reason_);
++}
++
++StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
++    : StunAttribute(type, length) {
++  attr_types_ = new std::vector<uint16>();
++}
++
++StunUInt16ListAttribute::~StunUInt16ListAttribute() {
++  delete attr_types_;
++}
++
++size_t StunUInt16ListAttribute::Size() const {
++  return attr_types_->size();
++}
++
++uint16 StunUInt16ListAttribute::GetType(int index) const {
++  return (*attr_types_)[index];
++}
++
++void StunUInt16ListAttribute::SetType(int index, uint16 value) {
++  (*attr_types_)[index] = value;
++}
++
++void StunUInt16ListAttribute::AddType(uint16 value) {
++  attr_types_->push_back(value);
++  SetLength((uint16)attr_types_->size() * 2);
++}
++
++bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
++  for (int i = 0; i < length() / 2; i++) {
++    uint16 attr;
++    if (!buf->ReadUInt16(attr))
++      return false;
++    attr_types_->push_back(attr);
++  }
++  return true;
++}
++
++void StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
++  for (unsigned i = 0; i < attr_types_->size(); i++)
++    buf->WriteUInt16((*attr_types_)[i]);
++}
++
++StunTransportPrefsAttribute::StunTransportPrefsAttribute(
++    uint16 type, uint16 length)
++    : StunAttribute(type, length), preallocate_(false), prefs_(0), addr_(0) { 
++}
++
++StunTransportPrefsAttribute::~StunTransportPrefsAttribute() {
++  delete addr_;
++}
++
++void StunTransportPrefsAttribute::SetPreallocateAddress(
++    StunAddressAttribute* addr) {
++  if (!addr) {
++    preallocate_ = false;
++    addr_ = 0;
++    SetLength(SIZE1);
++  } else {
++    preallocate_ = true;
++    addr_ = addr;
++    SetLength(SIZE2);
++  }
++}
++
++bool StunTransportPrefsAttribute::Read(ByteBuffer* buf) {
++  uint32 val;
++  if (!buf->ReadUInt32(val))
++    return false;
++
++  if ((val >> 3) != 0)
++    LOG(LERROR) << "transport-preferences bits not zero";
++
++  preallocate_ = static_cast<bool>((val >> 2) & 0x1);
++  prefs_ = (uint8)(val & 0x3);
++
++  if (preallocate_ && (prefs_ == 3))
++    LOG(LERROR) << "transport-preferences imcompatible P and Typ";
++
++  if (!preallocate_) {
++    if (length() != StunUInt32Attribute::SIZE)
++      return false;
++  } else {
++    if (length() != StunUInt32Attribute::SIZE + StunAddressAttribute::SIZE)
++      return false;
++
++    addr_ = new StunAddressAttribute(STUN_ATTR_SOURCE_ADDRESS);
++    addr_->Read(buf);
++  }
++
++  return true;
++}
++
++void StunTransportPrefsAttribute::Write(ByteBuffer* buf) const {
++  buf->WriteUInt32((preallocate_ ? 4 : 0) | prefs_);
++
++  if (preallocate_)
++    addr_->Write(buf);
++}
++
++StunMessageType GetStunResponseType(StunMessageType request_type) {
++  switch (request_type) {
++  case STUN_SHARED_SECRET_REQUEST:
++    return STUN_SHARED_SECRET_RESPONSE;
++  case STUN_ALLOCATE_REQUEST:
++    return STUN_ALLOCATE_RESPONSE;
++  case STUN_SEND_REQUEST:
++    return STUN_SEND_RESPONSE;
++  default:
++    return STUN_BINDING_RESPONSE;
++  }
++}
++
++StunMessageType GetStunErrorResponseType(StunMessageType request_type) {
++  switch (request_type) {
++  case STUN_SHARED_SECRET_REQUEST:
++    return STUN_SHARED_SECRET_ERROR_RESPONSE;
++  case STUN_ALLOCATE_REQUEST:
++    return STUN_ALLOCATE_ERROR_RESPONSE;
++  case STUN_SEND_REQUEST:
++    return STUN_SEND_ERROR_RESPONSE;
++  default:
++    return STUN_BINDING_ERROR_RESPONSE;
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h	(revision 586398)
+@@ -0,0 +1,42 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSIONDESCRIPTION_H_
++#define _SESSIONDESCRIPTION_H_
++
++namespace cricket {
++
++// The client overrides this with whatever 
++
++class SessionDescription {
++public:
++  virtual ~SessionDescription() {}
++};
++
++} // namespace cricket
++
++#endif // _SESSIONDESCRIPTION_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h	(revision 586398)
+@@ -0,0 +1,364 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __STUN_H__
++#define __STUN_H__
++
++// This file contains classes for dealing with the STUN and TURN protocols.
++// Both protocols use the same wire format.
++
++#include "talk/base/basictypes.h"
++#include "talk/base/bytebuffer.h"
++#include <string>
++#include <vector>
++
++namespace cricket {
++
++// These are the types of STUN & TURN messages as of last check.
++enum StunMessageType {
++  STUN_BINDING_REQUEST              = 0x0001,
++  STUN_BINDING_RESPONSE             = 0x0101,
++  STUN_BINDING_ERROR_RESPONSE       = 0x0111,
++  STUN_SHARED_SECRET_REQUEST        = 0x0002,
++  STUN_SHARED_SECRET_RESPONSE       = 0x0102,
++  STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112,
++  STUN_ALLOCATE_REQUEST             = 0x0003,
++  STUN_ALLOCATE_RESPONSE            = 0x0103,
++  STUN_ALLOCATE_ERROR_RESPONSE      = 0x0113,
++  STUN_SEND_REQUEST                 = 0x0004,
++  STUN_SEND_RESPONSE                = 0x0104,
++  STUN_SEND_ERROR_RESPONSE          = 0x0114,
++  STUN_DATA_INDICATION              = 0x0115
++};
++
++// These are the types of attributes defined in STUN & TURN.  Next to each is
++// the name of the class (T is StunTAttribute) that implements that type.
++enum StunAttributeType {
++  STUN_ATTR_MAPPED_ADDRESS        = 0x0001, // Address
++  STUN_ATTR_RESPONSE_ADDRESS      = 0x0002, // Address
++  STUN_ATTR_CHANGE_REQUEST        = 0x0003, // UInt32
++  STUN_ATTR_SOURCE_ADDRESS        = 0x0004, // Address
++  STUN_ATTR_CHANGED_ADDRESS       = 0x0005, // Address
++  STUN_ATTR_USERNAME              = 0x0006, // ByteString, multiple of 4 bytes
++  STUN_ATTR_PASSWORD              = 0x0007, // ByteString, multiple of 4 bytes
++  STUN_ATTR_MESSAGE_INTEGRITY     = 0x0008, // ByteString, 20 bytes
++  STUN_ATTR_ERROR_CODE            = 0x0009, // ErrorCode
++  STUN_ATTR_UNKNOWN_ATTRIBUTES    = 0x000a, // UInt16List
++  STUN_ATTR_REFLECTED_FROM        = 0x000b, // Address
++  STUN_ATTR_TRANSPORT_PREFERENCES = 0x000c, // TransportPrefs
++  STUN_ATTR_LIFETIME              = 0x000d, // UInt32
++  STUN_ATTR_ALTERNATE_SERVER      = 0x000e, // Address
++  STUN_ATTR_MAGIC_COOKIE          = 0x000f, // ByteString, 4 bytes
++  STUN_ATTR_BANDWIDTH             = 0x0010, // UInt32
++  STUN_ATTR_DESTINATION_ADDRESS   = 0x0011, // Address
++  STUN_ATTR_SOURCE_ADDRESS2       = 0x0012, // Address
++  STUN_ATTR_DATA                  = 0x0013, // ByteString
++  STUN_ATTR_OPTIONS               = 0x8001  // UInt32
++};
++
++enum StunErrorCodes {
++  STUN_ERROR_BAD_REQUEST          = 400,
++  STUN_ERROR_UNAUTHORIZED         = 401,
++  STUN_ERROR_UNKNOWN_ATTRIBUTE    = 420,
++  STUN_ERROR_STALE_CREDENTIALS    = 430,
++  STUN_ERROR_INTEGRITY_CHECK_FAILURE = 431,
++  STUN_ERROR_MISSING_USERNAME     = 432,
++  STUN_ERROR_USE_TLS              = 433,
++  STUN_ERROR_SERVER_ERROR         = 500,
++  STUN_ERROR_GLOBAL_FAILURE       = 600
++};
++
++extern const std::string STUN_ERROR_REASON_BAD_REQUEST;
++extern const std::string STUN_ERROR_REASON_UNAUTHORIZED;
++extern const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE;
++extern const std::string STUN_ERROR_REASON_STALE_CREDENTIALS;
++extern const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE;
++extern const std::string STUN_ERROR_REASON_MISSING_USERNAME;
++extern const std::string STUN_ERROR_REASON_USE_TLS;
++extern const std::string STUN_ERROR_REASON_SERVER_ERROR;
++extern const std::string STUN_ERROR_REASON_GLOBAL_FAILURE;
++
++class StunAttribute;
++class StunAddressAttribute;
++class StunUInt32Attribute;
++class StunByteStringAttribute;
++class StunErrorCodeAttribute;
++class StunUInt16ListAttribute;
++class StunTransportPrefsAttribute;
++
++// Records a complete STUN/TURN message.  Each message consists of a type and
++// any number of attributes.  Each attribute is parsed into an instance of an
++// appropriate class (see above).  The Get* methods will return instances of
++// that attribute class.
++class StunMessage {
++public:
++  StunMessage();
++  ~StunMessage();
++
++  StunMessageType type() const { return static_cast<StunMessageType>(type_); }
++  uint16 length() const { return length_; }
++  const std::string& transaction_id() const { return transaction_id_; }
++
++  void SetType(StunMessageType type) { type_ = type; }
++  void SetTransactionID(const std::string& str);
++
++  const StunAddressAttribute* GetAddress(StunAttributeType type) const;
++  const StunUInt32Attribute* GetUInt32(StunAttributeType type) const;
++  const StunByteStringAttribute* GetByteString(StunAttributeType type) const;
++  const StunErrorCodeAttribute* GetErrorCode() const;
++  const StunUInt16ListAttribute* GetUnknownAttributes() const;
++  const StunTransportPrefsAttribute* GetTransportPrefs() const;
++
++  void AddAttribute(StunAttribute* attr);
++
++  // Parses the STUN/TURN packet in the given buffer and records it here.  The
++  // return value indicates whether this was successful.
++  bool Read(ByteBuffer* buf);
++
++  // Writes this object into a STUN/TURN packet.  Return value is true if
++  // successful.
++  void Write(ByteBuffer* buf) const;
++
++private:
++  uint16 type_;
++  uint16 length_;
++  std::string transaction_id_;
++  std::vector<StunAttribute*>* attrs_;
++
++  const StunAttribute* GetAttribute(StunAttributeType type) const;
++};
++
++// Base class for all STUN/TURN attributes.
++class StunAttribute {
++public:
++  virtual ~StunAttribute() {}
++
++  StunAttributeType type() const {
++    return static_cast<StunAttributeType>(type_);
++  } 
++  uint16 length() const { return length_; }
++
++  // Reads the body (not the type or length) for this type of attribute from
++  // the given buffer.  Return value is true if successful.
++  virtual bool Read(ByteBuffer* buf) = 0;
++
++  // Writes the body (not the type or length) to the given buffer.  Return
++  // value is true if successful.
++  virtual void Write(ByteBuffer* buf) const = 0;
++
++  // Creates an attribute object with the given type and len.
++  static StunAttribute* Create(uint16 type, uint16 length);
++
++  // Creates an attribute object with the given type and smallest length.
++  static StunAddressAttribute* CreateAddress(uint16 type);
++  static StunUInt32Attribute* CreateUInt32(uint16 type);
++  static StunByteStringAttribute* CreateByteString(uint16 type);
++  static StunErrorCodeAttribute* CreateErrorCode();
++  static StunUInt16ListAttribute* CreateUnknownAttributes();
++  static StunTransportPrefsAttribute* CreateTransportPrefs();
++
++protected:
++  StunAttribute(uint16 type, uint16 length);
++
++  void SetLength(uint16 length) { length_ = length; }
++
++private:
++  uint16 type_;
++  uint16 length_;
++};
++
++// Implements STUN/TURN attributes that record an Internet address.
++class StunAddressAttribute : public StunAttribute {
++public:
++  StunAddressAttribute(uint16 type);
++
++#if (_MSC_VER < 1300)
++  enum { SIZE = 8 };
++#else
++  static const uint16 SIZE = 8;
++#endif
++
++  uint8 family() const { return family_; }
++  uint16 port() const { return port_; }
++  uint32 ip() const { return ip_; }
++
++  void SetFamily(uint8 family) { family_ = family; }
++  void SetIP(uint32 ip) { ip_ = ip; }
++  void SetPort(uint16 port) { port_ = port; }
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  uint8 family_;
++  uint16 port_;
++  uint32 ip_;
++};
++
++// Implements STUN/TURN attributs that record a 32-bit integer.
++class StunUInt32Attribute : public StunAttribute {
++public:
++  StunUInt32Attribute(uint16 type);
++
++#if (_MSC_VER < 1300)
++  enum { SIZE = 4 };
++#else
++  static const uint16 SIZE = 4;
++#endif
++
++  uint32 value() const { return bits_; }
++
++  void SetValue(uint32 bits) { bits_ = bits; }
++
++  bool GetBit(int index) const;
++  void SetBit(int index, bool value);
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  uint32 bits_;
++};
++
++// Implements STUN/TURN attributs that record an arbitrary byte string
++class StunByteStringAttribute : public StunAttribute {
++public:
++  StunByteStringAttribute(uint16 type, uint16 length);
++  ~StunByteStringAttribute();
++
++  const char* bytes() const { return bytes_; }
++
++  void SetBytes(char* bytes, uint16 length);
++
++  void CopyBytes(const char* bytes); // uses strlen
++  void CopyBytes(const void* bytes, uint16 length);
++
++  uint8 GetByte(int index) const;
++  void SetByte(int index, uint8 value);
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  char* bytes_;
++};
++
++// Implements STUN/TURN attributs that record an error code.
++class StunErrorCodeAttribute : public StunAttribute {
++public:
++  StunErrorCodeAttribute(uint16 type, uint16 length);
++  ~StunErrorCodeAttribute();
++
++#if (_MSC_VER < 1300)
++  enum { MIN_SIZE = 4 };
++#else
++  static const uint16 MIN_SIZE = 4;
++#endif
++
++  uint32 error_code() const { return (class_ << 8) | number_; }
++  uint8 error_class() const { return class_; }
++  uint8 number() const { return number_; }
++  const std::string& reason() const { return reason_; }
++
++  void SetErrorCode(uint32 code);
++  void SetErrorClass(uint8 eclass) { class_ = eclass; }
++  void SetNumber(uint8 number) { number_ = number; }
++  void SetReason(const std::string& reason);
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  uint8 class_;
++  uint8 number_;
++  std::string reason_;
++};
++
++// Implements STUN/TURN attributs that record a list of attribute names.
++class StunUInt16ListAttribute : public StunAttribute {
++public:
++  StunUInt16ListAttribute(uint16 type, uint16 length);
++  ~StunUInt16ListAttribute();
++
++  size_t Size() const;
++  uint16 GetType(int index) const;
++  void SetType(int index, uint16 value);
++  void AddType(uint16 value);
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  std::vector<uint16>* attr_types_;
++};
++
++// Implements the TURN TRANSPORT-PREFS attribute, which provides information
++// about the ports to allocate.
++class StunTransportPrefsAttribute : public StunAttribute {
++public:
++  StunTransportPrefsAttribute(uint16 type, uint16 length);
++  ~StunTransportPrefsAttribute();
++
++#if (_MSC_VER < 1300)
++  enum { SIZE1 = 4, SIZE2 = 12 };
++#else
++  static const uint16 SIZE1 = 4;
++  static const uint16 SIZE2 = 12;
++#endif
++
++  bool preallocate() const { return preallocate_; }
++  uint8 preference_type() const { return prefs_; }
++  const StunAddressAttribute* address() const { return addr_; }
++
++  void SetPreferenceType(uint8 prefs) { prefs_ = prefs; }
++
++  // Sets the preallocate address to the given value, or if 0 is given, it sets
++  // to not preallocate.
++  void SetPreallocateAddress(StunAddressAttribute* addr);
++
++  bool Read(ByteBuffer* buf);
++  void Write(ByteBuffer* buf) const;
++
++private:
++  bool preallocate_;
++  uint8 prefs_;
++  StunAddressAttribute* addr_;
++};
++
++// The special MAGIC-COOKIE attribute is used to distinguish TURN packets from
++// other kinds of traffic.
++const char STUN_MAGIC_COOKIE_VALUE[] = { 0x72, char(0xc6), 0x4b, char(0xc6) };
++
++// Returns the (successful) response type for the given request type.
++StunMessageType GetStunResponseType(StunMessageType request_type);
++
++// Returns the error response type for the given request type.
++StunMessageType GetStunErrorResponseType(StunMessageType request_type);
++
++} // namespace cricket
++
++#endif // __STUN_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro	(revision 586398)
+@@ -0,0 +1,14 @@
++TEMPLATE = app
++INCLUDEPATH = ../../..
++DEFINES += POSIX
++
++include(../../../../../conf.pri)
++
++# Input
++SOURCES += \
++	stunserver.cc \
++	stunserver_main.cc \
++	../../base/host.cc #\
++#	../../base/socketaddresspair.cc
++
++LIBS += ../../../liblibjingle.a
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc	(revision 586398)
+@@ -0,0 +1,117 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/logging.h"
++#include "talk/p2p/base/udpport.h"
++#include <iostream>
++#include <cassert>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++const std::string LOCAL_PORT_TYPE("local");
++
++UDPPort::UDPPort(Thread* thread, SocketFactory* factory, Network* network,
++                 const SocketAddress& address)
++    : Port(thread, LOCAL_PORT_TYPE, factory, network), error_(0) {
++  socket_ = CreatePacketSocket(PROTO_UDP);
++  socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacketSlot);
++  if (socket_->Bind(address) < 0)
++    PLOG(LERROR, socket_->GetError()) << "bind";
++}
++
++UDPPort::UDPPort(Thread* thread, const std::string &type,
++                 SocketFactory* factory, Network* network)
++  : Port(thread, type, factory, network), socket_(0), error_(0) {
++}
++
++UDPPort::~UDPPort() {
++  delete socket_;
++}
++
++void UDPPort::PrepareAddress() {
++  assert(socket_);
++  add_address(socket_->GetLocalAddress(), "udp");
++}
++
++Connection* UDPPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
++  if (address.protocol() != "udp")
++    return 0;
++
++  Connection * conn = new ProxyConnection(this, 0, address);
++  AddConnection(conn);
++  return conn;
++}
++
++int UDPPort::SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload) {
++  assert(socket_);
++  int sent = socket_->SendTo(data, size, addr);
++  if (sent < 0)
++    error_ = socket_->GetError();
++  return sent;
++}
++
++int UDPPort::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int UDPPort::GetError() {
++  assert(socket_);
++  return error_;
++}
++
++void UDPPort::OnReadPacketSlot(
++    const char* data, size_t size, const SocketAddress& remote_addr,
++    AsyncPacketSocket* socket) {
++  assert(socket == socket_);
++  OnReadPacket(data, size, remote_addr);
++}
++
++void UDPPort::OnReadPacket(
++    const char* data, size_t size, const SocketAddress& remote_addr) {
++  if (Connection* conn = GetConnection(remote_addr)) {
++    conn->OnReadPacket(data, size);
++  } else {
++    Port::OnReadPacket(data, size, remote_addr);
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __UDPPORT_H__
++#define __UDPPORT_H__
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/p2p/base/port.h"
++
++namespace cricket {
++
++extern const std::string LOCAL_PORT_TYPE; // type of UDP ports
++
++// Communicates using a local UDP port.
++//
++// This class is designed to allow subclasses to take advantage of the
++// connection management provided by this class.  A subclass should take of all
++// packet sending and preparation, but when a packet is received, it should
++// call this UDPPort::OnReadPacket (3 arg) to dispatch to a connection.
++class UDPPort : public Port {
++public:
++  UDPPort(Thread* thread, SocketFactory* factory, Network* network,
++          const SocketAddress& address);
++  virtual ~UDPPort();
++
++  virtual void PrepareAddress();
++  virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
++
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError();
++
++protected:
++  UDPPort(Thread* thread, const std::string &type, SocketFactory* factory,
++          Network* network);
++
++  // Handles sending using the local UDP socket.
++  virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
++
++  // Dispatches the given packet to the port or connection as appropriate.
++  void OnReadPacket(
++      const char* data, size_t size, const SocketAddress& remote_addr);
++
++  AsyncPacketSocket* socket() { return socket_; }
++
++private:
++  AsyncPacketSocket* socket_;
++  int error_;
++
++  // Receives packet signal from the local UDP Socket.
++  void OnReadPacketSlot(
++      const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++};
++
++} // namespace cricket
++
++#endif // __UDPPORT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __STUNPORT_H__
++#define __STUNPORT_H__
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/p2p/base/udpport.h"
++#include "talk/p2p/base/stunrequest.h"
++
++namespace cricket {
++
++extern const std::string STUN_PORT_TYPE;
++
++// Communicates using the address on the outside of a NAT.
++class StunPort : public UDPPort {
++public:
++  StunPort(Thread* thread, SocketFactory* factory, Network* network,
++           const SocketAddress& local_addr, const SocketAddress& server_addr);
++  virtual ~StunPort();
++
++  virtual void PrepareAddress();
++
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError();
++
++protected:
++  virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
++
++  void OnReadPacket(
++      const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++private:
++  AsyncPacketSocket* socket_;
++  SocketAddress server_addr_;
++  StunRequestManager requests_;
++  int error_;
++
++  friend class StunPortBindingRequest;
++
++  // Sends STUN requests to the server.
++  void OnSendPacket(const void* data, size_t size);
++};
++
++} // namespace cricket
++
++#endif // __STUNPORT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc	(revision 586398)
+@@ -0,0 +1,198 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/logging.h"
++#include "talk/p2p/base/stunrequest.h"
++#include "talk/p2p/base/helpers.h"
++#include <iostream>
++#include <cassert>
++
++namespace cricket {
++
++const uint32 MSG_STUN_SEND = 1;
++
++const int MAX_SENDS = 9;
++const int DELAY_UNIT = 100; // 100 milliseconds
++const int DELAY_MAX_FACTOR = 16;
++
++StunRequestManager::StunRequestManager(Thread* thread) : thread_(thread) {
++}
++
++StunRequestManager::~StunRequestManager() {
++  while (requests_.begin() != requests_.end()) {
++    StunRequest *request = requests_.begin()->second;
++    requests_.erase(requests_.begin());
++    delete request;
++  }
++}
++
++void StunRequestManager::Send(StunRequest* request) {
++  SendDelayed(request, 0);
++}
++
++void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
++  request->set_manager(this);
++  assert(requests_.find(request->id()) == requests_.end());
++  requests_[request->id()] = request;
++  thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
++}
++
++void StunRequestManager::Remove(StunRequest* request) {
++  assert(request->manager() == this);
++  RequestMap::iterator iter = requests_.find(request->id());
++  if (iter != requests_.end()) {
++    assert(iter->second == request);
++    requests_.erase(iter);
++    thread_->Clear(request);
++  }
++}
++
++void StunRequestManager::Clear() {
++  std::vector<StunRequest*> requests;
++  for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
++    requests.push_back(i->second);
++
++  for (uint32 i = 0; i < requests.size(); ++i)
++    Remove(requests[i]);
++}
++
++bool StunRequestManager::CheckResponse(StunMessage* msg) {
++  RequestMap::iterator iter = requests_.find(msg->transaction_id());
++  if (iter == requests_.end())
++    return false;
++
++  StunRequest* request = iter->second;
++  if (msg->type() == GetStunResponseType(request->type())) {
++    request->OnResponse(msg);
++  } else if (msg->type() == GetStunErrorResponseType(request->type())) {
++    request->OnErrorResponse(msg);
++  } else {
++    LOG(LERROR) << "Received response with wrong type: " << msg->type()
++               << " (expecting " << GetStunResponseType(request->type()) << ")";
++    return false;
++  }
++
++  delete request;
++  return true;
++}
++
++bool StunRequestManager::CheckResponse(const char* data, size_t size) {
++  // Check the appropriate bytes of the stream to see if they match the
++  // transaction ID of a response we are expecting.
++
++  if (size < 20)
++    return false;
++
++  std::string id;
++  id.append(data + 4, 16);
++
++  RequestMap::iterator iter = requests_.find(id);
++  if (iter == requests_.end())
++    return false;
++
++  // Parse the STUN message and continue processing as usual.
++
++  ByteBuffer buf(data, size);
++  StunMessage msg;
++  if (!msg.Read(&buf))
++    return false;
++
++  return CheckResponse(&msg);
++}
++
++StunRequest::StunRequest()
++  : manager_(0), id_(CreateRandomString(16)), msg_(0), count_(0),
++    timeout_(false), tstamp_(0) {
++}
++
++StunRequest::StunRequest(StunMessage* request)
++  : manager_(0), id_(request->transaction_id()), msg_(request),
++    count_(0), timeout_(false) {
++}
++
++StunRequest::~StunRequest() {
++  assert(manager_ != NULL);
++  if (manager_) {
++    manager_->Remove(this);
++    manager_->thread_->Clear(this);
++  }
++  delete msg_;
++}
++
++const StunMessageType StunRequest::type() {
++  assert(msg_);
++  return msg_->type();
++}
++
++void StunRequest::set_manager(StunRequestManager* manager) {
++  assert(!manager_);
++  manager_ = manager;
++}
++
++void StunRequest::OnMessage(Message* pmsg) {
++  assert(manager_);
++  assert(pmsg->message_id == MSG_STUN_SEND);
++
++  if (!msg_) {
++    msg_ = new StunMessage();
++    msg_->SetTransactionID(id_);
++    Prepare(msg_);
++    assert(msg_->transaction_id() == id_);
++  }
++
++  if (timeout_) {
++    OnTimeout();
++    delete this;
++    return;
++  }
++
++  tstamp_ = GetMillisecondCount();
++
++  ByteBuffer buf;
++  msg_->Write(&buf);
++  manager_->SignalSendPacket(buf.Data(), buf.Length());
++
++  int delay = GetNextDelay();
++  manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL);
++}
++
++uint32 StunRequest::Elapsed() const {
++  return (GetMillisecondCount() - tstamp_);
++}
++
++int StunRequest::GetNextDelay() {
++  int delay = DELAY_UNIT * _min(1 << count_, DELAY_MAX_FACTOR);
++  count_ += 1;
++  if (count_ == MAX_SENDS)
++    timeout_ = true;
++  return delay;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h	(revision 586398)
+@@ -0,0 +1,94 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSIONID_H_
++#define _SESSIONID_H_
++
++#include "talk/base/basictypes.h"
++#include <string>
++#include <sstream>
++
++namespace cricket {
++
++// Each session is identified by a pair (from,id), where id is only
++// assumed to be unique to the machine identified by from.
++class SessionID {
++public:
++  SessionID() : id_str_("0") {
++  }
++  SessionID(const std::string& initiator, uint32 id)
++    : initiator_(initiator) {
++    set_id(id);
++  }
++  SessionID(const SessionID& sid) 
++    : id_str_(sid.id_str_), initiator_(sid.initiator_) {
++  }
++
++  void set_id(uint32 id) {
++    std::stringstream st;
++    st << id;
++    st >> id_str_;
++  }
++  const std::string id_str() const {
++    return id_str_;
++  }
++  void set_id_str(const std::string &id_str) {
++    id_str_ = id_str;
++  }
++
++  const std::string &initiator() const {
++    return initiator_;
++  }
++  void set_initiator(const std::string &initiator) {
++    initiator_ = initiator;
++  }
++
++  bool operator <(const SessionID& sid) const {
++    int r = initiator_.compare(sid.initiator_);
++    if (r == 0)
++      r = id_str_.compare(sid.id_str_);
++    return r < 0;
++  }
++
++  bool operator ==(const SessionID& sid) const {
++    return (id_str_ == sid.id_str_) && (initiator_ == sid.initiator_);
++  }
++
++  SessionID& operator =(const SessionID& sid) {
++    id_str_ = sid.id_str_;
++    initiator_ = sid.initiator_;
++    return *this;
++  }
++
++private:
++  std::string id_str_;
++  std::string initiator_;
++};
++
++} // namespace cricket
++
++#endif // _SESSIONID_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h	(revision 586398)
+@@ -0,0 +1,51 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __HELPERS_H__
++#define __HELPERS_H__
++
++#include "talk/base/basictypes.h"
++#include <string>
++
++namespace cricket {
++
++// srand initializer
++void InitRandom(const char *client_unique, size_t len);
++
++// Generates a (cryptographically) random string of the given length.
++std::string CreateRandomString(int length);
++
++// Generates a random id
++uint32 CreateRandomId();
++
++// Determines whether the given string consists entirely of valid base64
++// encoded characters.
++bool IsBase64Encoded(const std::string& str);
++
++} // namespace cricket
++
++#endif // __HELPERS_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc	(revision 586398)
+@@ -0,0 +1,910 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++// Description of the P2PSocket class in P2PSocket.h
++//
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include <iostream>
++#include <cassert>
++#include "talk/base/logging.h" 
++#include "talk/p2p/base/p2psocket.h"
++#include <errno.h>
++namespace {
++
++// messages for queuing up work for ourselves
++const uint32 MSG_SORT = 1;
++const uint32 MSG_PING = 2;
++const uint32 MSG_ALLOCATE = 3;
++
++// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
++// for pinging.  When the socket is writable, we will use only 1 Kbps because
++// we don't want to degrade the quality on a modem.  These numbers should work
++// well on a 28.8K modem, which is the slowest connection on which the voice
++// quality is reasonable at all.
++static const uint32 PING_PACKET_SIZE = 60 * 8;
++static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000;   // 480ms
++static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000;// 50ms
++
++// If there is a current writable connection, then we will also try hard to
++// make sure it is pinged at this rate.
++static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900; // 2*WRITABLE_DELAY - bit
++
++// The minimum improvement in MOS that justifies a switch.
++static const double kMinImprovement = 10;
++
++// Amount of time that we wait when *losing* writability before we try doing
++// another allocation.
++static const int kAllocateDelay = 1 * 1000; // 1 second
++
++// We will try creating a new allocator from scratch after a delay of this
++// length without becoming writable (or timing out).
++static const int kAllocatePeriod = 20 * 1000; // 20 seconds
++
++cricket::Port::CandidateOrigin GetOrigin(cricket::Port* port,
++                                         cricket::Port* origin_port) {
++  if (!origin_port)
++    return cricket::Port::ORIGIN_MESSAGE;
++  else if (port == origin_port)
++    return cricket::Port::ORIGIN_THIS_PORT;
++  else
++    return cricket::Port::ORIGIN_OTHER_PORT;
++}
++
++// Compares two connections based only on static information about them.
++int CompareConnectionCandidates(cricket::Connection* a,
++                                cricket::Connection* b) {
++  // Combine local and remote preferences
++  assert(a->local_candidate().preference() == a->port()->preference());
++  assert(b->local_candidate().preference() == b->port()->preference());
++  double a_pref = a->local_candidate().preference() 
++                * a->remote_candidate().preference();
++  double b_pref = b->local_candidate().preference() 
++                * b->remote_candidate().preference();
++
++  // Now check combined preferences. Lower values get sorted last.
++  if (a_pref > b_pref)
++    return 1;
++  if (a_pref < b_pref)
++    return -1;
++
++  return 0;
++}
++
++// Compare two connections based on their writability and static preferences.
++int CompareConnections(cricket::Connection *a, cricket::Connection *b) {
++  // Sort based on write-state.  Better states have lower values.
++  if (a->write_state() < b->write_state())
++    return 1;
++  if (a->write_state() > b->write_state())
++    return -1;
++
++  // Compare the candidate information.
++  return CompareConnectionCandidates(a, b);
++}
++
++// Wraps the comparison connection into a less than operator that puts higher
++// priority writable connections first.
++class ConnectionCompare {
++public:
++  bool operator()(const cricket::Connection *ca, 
++                  const cricket::Connection *cb) {
++    cricket::Connection* a = const_cast<cricket::Connection*>(ca);
++    cricket::Connection* b = const_cast<cricket::Connection*>(cb);
++
++    // Compare first on writability and static preferences.
++    int cmp = CompareConnections(a, b);
++    if (cmp > 0)
++      return true;
++    if (cmp < 0)
++      return false;
++    
++    // Otherwise, sort based on latency estimate.
++    return a->rtt() < b->rtt();
++
++    // Should we bother checking for the last connection that last received 
++    // data? It would help rendezvous on the connection that is also receiving
++    // packets.
++    //
++    // TODO: Yes we should definitely do this.  The TCP protocol gains
++    // efficiency by being used bidirectionally, as opposed to two separate
++    // unidirectional streams.  This test should probably occur before
++    // comparison of local prefs (assuming combined prefs are the same).  We
++    // need to be careful though, not to bounce back and forth with both sides
++    // trying to rendevous with the other.
++  }
++};
++
++// Determines whether we should switch between two connections, based first on
++// static preferences and then (if those are equal) on latency estimates.
++bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
++  if (a_conn == b_conn)
++    return false;
++
++  if ((a_conn == NULL) || (b_conn == NULL))  // don't think the latter should happen
++    return true;
++
++  int prefs_cmp = CompareConnections(a_conn, b_conn);
++  if (prefs_cmp < 0)
++    return true;
++  if (prefs_cmp > 0)
++    return false;
++
++  return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
++}
++
++}  // unnamed namespace
++
++namespace cricket {
++
++P2PSocket::P2PSocket(const std::string &name, PortAllocator *allocator)
++: worker_thread_(Thread::Current()), name_(name), allocator_(allocator), 
++  error_(0), state_(STATE_CONNECTING), waiting_for_signaling_(false),
++  best_connection_(NULL), pinging_started_(false), sort_dirty_(false), 
++  was_writable_(false), was_timed_out_(true) {
++}
++
++P2PSocket::~P2PSocket() {
++  assert(worker_thread_ == Thread::Current());
++
++  thread()->Clear(this);
++
++  for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
++    delete allocator_sessions_[i];
++}
++
++// Add the allocator session to our list so that we know which sessions
++// are still active.
++void P2PSocket::AddAllocatorSession(PortAllocatorSession* session) {
++  session->set_generation(static_cast<uint32>(allocator_sessions_.size()));
++  allocator_sessions_.push_back(session);
++
++  // We now only want to apply new candidates that we receive to the ports
++  // created by this new session because these are replacing those of the
++  // previous sessions.
++  ports_.clear();
++
++  session->SignalPortReady.connect(this, &P2PSocket::OnPortReady);
++  session->SignalCandidatesReady.connect(this, &P2PSocket::OnCandidatesReady);
++  session->GetInitialPorts();
++  if (pinging_started_)
++    session->StartGetAllPorts();
++}
++
++// Go into the state of processing candidates, and running in general
++void P2PSocket::StartProcessingCandidates() {
++  assert(worker_thread_ == Thread::Current());
++
++  // Kick off an allocator session
++  OnAllocate();
++
++  // Start pinging as the ports come in.
++  thread()->Post(this, MSG_PING);
++}
++
++// Reset the socket, clear up any previous allocations and start over
++void P2PSocket::Reset() {
++  assert(worker_thread_ == Thread::Current());
++
++  // Get rid of all the old allocators.  This should clean up everything.
++  for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
++    delete allocator_sessions_[i];
++
++  allocator_sessions_.clear();
++  ports_.clear();
++  connections_.clear();
++  best_connection_ = NULL;
++
++  // Forget about all of the candidates we got before.
++  remote_candidates_.clear();
++
++  // Revert to the connecting state.
++  set_state(STATE_CONNECTING);
++
++  // Reinitialize the rest of our state.
++  waiting_for_signaling_ = false;
++  pinging_started_ = false;
++  sort_dirty_ = false;
++  was_writable_ = false;
++  was_timed_out_ = true;
++
++  // Start a new allocator.
++  OnAllocate();
++
++  // Start pinging as the ports come in.
++  thread()->Clear(this);
++  thread()->Post(this, MSG_PING);
++}
++
++// A new port is available, attempt to make connections for it
++void P2PSocket::OnPortReady(PortAllocatorSession *session, Port* port) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Set in-effect options on the new port
++  for (OptionMap::const_iterator it = options_.begin(); it != options_.end(); ++it) {
++    int val = port->SetOption(it->first, it->second);
++    if (val < 0) {
++      LOG(WARNING) << "SetOption(" << it->first << ", " << it->second << ") failed: " << port->GetError();
++    }
++  }
++
++  // Remember the ports and candidates, and signal that candidates are ready.
++  // The session will handle this, and send an initiate/accept/modify message
++  // if one is pending.
++
++  ports_.push_back(port);
++  port->SignalUnknownAddress.connect(this, &P2PSocket::OnUnknownAddress);
++  port->SignalDestroyed.connect(this, &P2PSocket::OnPortDestroyed);
++
++  // Attempt to create a connection from this new port to all of the remote
++  // candidates that we were given so far.
++
++  std::vector<RemoteCandidate>::iterator iter;
++  for (iter = remote_candidates_.begin(); iter != remote_candidates_.end(); 
++       ++iter)
++    CreateConnection(port, *iter, iter->origin_port(), false);
++
++  SortConnections();
++}
++
++// A new candidate is available, let listeners know
++void P2PSocket::OnCandidatesReady(PortAllocatorSession *session, 
++                                  const std::vector<Candidate>& candidates) {
++  SignalCandidatesReady(this, candidates);
++}
++
++// Handle stun packets                                  
++void P2PSocket::OnUnknownAddress(Port *port,
++                                 const SocketAddress &address,
++                                 StunMessage *stun_msg,
++                                 const std::string &remote_username) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Port has received a valid stun packet from an address that no Connection
++  // is currently available for. See if the remote user name is in the remote
++  // candidate list. If it isn't return error to the stun request.
++
++  const Candidate *candidate = NULL;
++  std::vector<RemoteCandidate>::iterator it;
++  for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
++    if ((*it).username() == remote_username) {
++      candidate = &(*it);
++      break;
++    }
++  }
++  if (candidate == NULL) {
++    // Don't know about this username, the request is bogus
++    // This sometimes happens if a binding response comes in before the ACCEPT
++    // message.  It is totally valid; the retry state machine will try again.
++
++    port->SendBindingErrorResponse(stun_msg, address, 
++        STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS);
++    delete stun_msg;
++    return;
++  }
++
++  // Check for connectivity to this address. Create connections
++  // to this address across all local ports. First, add this as a new remote
++  // address
++
++  Candidate new_remote_candidate = *candidate;
++  new_remote_candidate.set_address(address);
++  //new_remote_candidate.set_protocol(port->protocol());
++
++  // This remote username exists. Now create connections using this candidate,
++  // and resort
++
++  if (CreateConnections(new_remote_candidate, port, true)) {
++    // Send the pinger a successful stun response.
++    port->SendBindingResponse(stun_msg, address);
++
++    // Update the list of connections since we just added another.  We do this
++    // after sending the response since it could (in principle) delete the
++    // connection in question.
++    SortConnections();
++  } else {
++    // Hopefully this won't occur, because changing a destination address
++    // shouldn't cause a new connection to fail
++    assert(false);
++    port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
++        STUN_ERROR_REASON_SERVER_ERROR);
++  }
++
++  delete stun_msg;
++}
++
++// We received a candidate from the other side, make connections so we
++// can try to use these remote candidates with our local candidates.                                 
++void P2PSocket::AddRemoteCandidates(
++    const std::vector<Candidate> &remote_candidates) {
++  assert(worker_thread_ == Thread::Current());
++
++  // The remote candidates have come in. Remember them and start to establish
++  // connections
++
++  std::vector<Candidate>::const_iterator it;
++  for (it = remote_candidates.begin(); it != remote_candidates.end(); ++it)
++    CreateConnections(*it, NULL, false);
++
++  // Resort the connections 
++
++  SortConnections();
++}
++
++// Creates connections from all of the ports that we care about to the given
++// remote candidate.  The return value is true iff we created a connection from
++// the origin port.
++bool P2PSocket::CreateConnections(const Candidate &remote_candidate,
++                                  Port* origin_port,
++                                  bool readable) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Add a new connection for this candidate to every port that allows such a
++  // connection (i.e., if they have compatible protocols) and that does not
++  // already have a connection to an equivalent candidate.  We must be careful
++  // to make sure that the origin port is included, even if it was pruned,
++  // since that may be the only port that can create this connection.
++
++  bool created = false;
++
++  std::vector<Port *>::reverse_iterator it;
++  for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
++    if (CreateConnection(*it, remote_candidate, origin_port, readable)) {
++      if (*it == origin_port)
++        created = true;
++    }
++  }
++
++  if ((origin_port != NULL) &&
++      find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
++    if (CreateConnection(origin_port, remote_candidate, origin_port, readable))
++      created = true;
++  }
++
++  // Remember this remote candidate so that we can add it to future ports.
++  RememberRemoteCandidate(remote_candidate, origin_port);
++
++  return created;
++}
++
++// Setup a connection object for the local and remote candidate combination.
++// And then listen to connection object for changes.
++bool P2PSocket::CreateConnection(Port* port,
++                                 const Candidate& remote_candidate,
++                                 Port* origin_port,
++                                 bool readable) {
++  // Look for an existing connection with this remote address.  If one is not
++  // found, then we can create a new connection for this address.
++  Connection* connection = port->GetConnection(remote_candidate.address());
++  if (connection != NULL) {
++    // It is not legal to try to change any of the parameters of an existing
++    // connection; however, the other side can send a duplicate candidate.
++    if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
++      LOG(INFO) << "Attempt to change a remote candidate";
++      return false;
++    }
++  } else {
++    Port::CandidateOrigin origin = GetOrigin(port, origin_port);
++    connection = port->CreateConnection(remote_candidate, origin);
++    if (!connection)
++      return false;
++
++    connections_.push_back(connection);
++    connection->SignalReadPacket.connect(this, &P2PSocket::OnReadPacket);
++    connection->SignalStateChange.connect(this, &P2PSocket::OnConnectionStateChange);
++    connection->SignalDestroyed.connect(this, &P2PSocket::OnConnectionDestroyed);
++  }
++
++  // If we are readable, it is because we are creating this in response to a
++  // ping from the other side.  This will cause the state to become readable.
++  if (readable)
++    connection->ReceivedPing();
++
++  return true;
++}
++
++// Maintain our remote candidate list, adding this new remote one.
++void P2PSocket::RememberRemoteCandidate(const Candidate& remote_candidate,
++                                        Port* origin_port) {
++  // Remove any candidates whose generation is older than this one.  The
++  // presence of a new generation indicates that the old ones are not useful.
++  uint32 i = 0;
++  while (i < remote_candidates_.size()) {
++    if (remote_candidates_[i].generation() < remote_candidate.generation()) {
++      remote_candidates_.erase(remote_candidates_.begin() + i);
++      LOG(INFO) << "Pruning candidate from old generation: "
++                << remote_candidates_[i].address().ToString();
++
++    } else {
++      i += 1;
++    }
++  }
++
++  // Make sure this candidate is not a duplicate.
++  for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
++    if (remote_candidates_[i].IsEquivalent(remote_candidate)) {
++      LOG(INFO) << "Duplicate candidate: "
++                << remote_candidate.address().ToString();
++      return;
++    }
++  }
++
++  // Try this candidate for all future ports.
++  remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
++
++  // We have some candidates from the other side, we are now serious about
++  // this connection.  Let's do the StartGetAllPorts thing.
++  if (!pinging_started_) {
++    pinging_started_ = true;
++    for (size_t i = 0; i < allocator_sessions_.size(); ++i) {
++      if (!allocator_sessions_[i]->IsGettingAllPorts())
++        allocator_sessions_[i]->StartGetAllPorts();
++    }
++  }
++}
++
++// Send data to the other side, using our best connection
++int P2PSocket::Send(const char *data, size_t len) {
++  // This can get called on any thread that is convenient to write from!
++  if (best_connection_ == NULL) {
++    error_ = EWOULDBLOCK;
++    return SOCKET_ERROR;
++  }
++  int sent = best_connection_->Send(data, len);
++  if (sent <= 0) {
++    assert(sent < 0);
++    error_ = best_connection_->GetError();
++  }
++  return sent;
++}
++
++// Monitor connection states
++void P2PSocket::UpdateConnectionStates() {
++  uint32 now = Time();
++
++  // We need to copy the list of connections since some may delete themselves
++  // when we call UpdateState.
++  for (uint32 i = 0; i < connections_.size(); ++i)
++    connections_[i]->UpdateState(now);
++}
++
++// Prepare for best candidate sorting
++void P2PSocket::RequestSort() {
++  if (!sort_dirty_) {
++    worker_thread_->Post(this, MSG_SORT);
++    sort_dirty_ = true;
++  }
++}
++
++// Sort the available connections to find the best one.  We also monitor
++// the number of available connections and the current state so that we 
++// can possibly kick off more allocators (for more connections).
++void P2PSocket::SortConnections() {
++  assert(worker_thread_ == Thread::Current());
++
++  // Make sure the connection states are up-to-date since this affects how they
++  // will be sorted.
++  UpdateConnectionStates();
++
++  // Any changes after this point will require a re-sort.
++  sort_dirty_ = false;
++
++  // Get a list of the networks that we are using.
++  std::set<Network*> networks;
++  for (uint32 i = 0; i < connections_.size(); ++i)
++    networks.insert(connections_[i]->port()->network());
++
++  // Find the best alternative connection by sorting.  It is important to note
++  // that amongst equal preference, writable connections, this will choose the
++  // one whose estimated latency is lowest.  So it is the only one that we
++  // need to consider switching to.
++
++  ConnectionCompare cmp;
++  std::stable_sort(connections_.begin(), connections_.end(), cmp);
++  Connection* top_connection = NULL;
++  if (connections_.size() > 0)
++    top_connection = connections_[0];
++
++  // If necessary, switch to the new choice.
++  if (ShouldSwitch(best_connection_, top_connection))
++    SwitchBestConnectionTo(top_connection);
++
++  // We can prune any connection for which there is a writable connection on
++  // the same network with better or equal prefences.  We leave those with
++  // better preference just in case they become writable later (at which point,
++  // we would prune out the current best connection).  We leave connections on
++  // other networks because they may not be using the same resources and they
++  // may represent very distinct paths over which we can switch.
++  std::set<Network*>::iterator network;
++  for (network = networks.begin(); network != networks.end(); ++network) {
++    Connection* primier = GetBestConnectionOnNetwork(*network);
++    if (!primier || (primier->write_state() != Connection::STATE_WRITABLE))
++      continue;
++
++    for (uint32 i = 0; i < connections_.size(); ++i) {
++      if ((connections_[i] != primier) &&
++          (connections_[i]->port()->network() == *network) &&
++          (CompareConnectionCandidates(primier, connections_[i]) >= 0)) {
++        connections_[i]->Prune();
++      }
++    }
++  }
++
++  // Count the number of connections in the various states.
++
++  int writable = 0;
++  int write_connect = 0;
++  int write_timeout = 0;
++
++  for (uint32 i = 0; i < connections_.size(); ++i) {
++    switch (connections_[i]->write_state()) {
++    case Connection::STATE_WRITABLE:
++      ++writable;
++      break;
++    case Connection::STATE_WRITE_CONNECT:
++      ++write_connect;
++      break;
++    case Connection::STATE_WRITE_TIMEOUT:
++      ++write_timeout;
++      break;
++    default:
++      assert(false);
++    }
++  }
++
++  if (writable > 0) {
++    HandleWritable();
++  } else if (write_connect > 0) {
++    HandleNotWritable();
++  } else {
++    HandleAllTimedOut();
++  }
++
++  // Notify of connection state change
++  SignalConnectionMonitor(this);
++}
++
++// Track the best connection, and let listeners know
++void P2PSocket::SwitchBestConnectionTo(Connection* conn) {
++  best_connection_ = conn;
++  if (best_connection_)
++    SignalConnectionChanged(this, 
++                            best_connection_->remote_candidate().address());
++}
++
++// We checked the status of our connections and we had at least one that
++// was writable, go into the writable state.
++void P2PSocket::HandleWritable() {
++  //
++  // One or more connections writable!
++  //
++  if (state_ != STATE_WRITABLE) {
++    for (uint32 i = 0; i < allocator_sessions_.size(); ++i) {
++      if (allocator_sessions_[i]->IsGettingAllPorts()) {
++        allocator_sessions_[i]->StopGetAllPorts();
++      }
++    }
++
++    // Stop further allocations.
++    thread()->Clear(this, MSG_ALLOCATE);
++  }
++
++  // We're writable, obviously we aren't timed out
++  was_writable_ = true;
++  was_timed_out_ = false;
++  set_state(STATE_WRITABLE);
++}
++
++// We checked the status of our connections and we didn't have any that
++// were writable, go into the connecting state (kick off a new allocator
++// session).
++void P2PSocket::HandleNotWritable() {
++  //
++  // No connections are writable but not timed out!
++  //
++  if (was_writable_) {
++    // If we were writable, let's kick off an allocator session immediately
++    was_writable_ = false;
++    OnAllocate();
++  }
++
++  // We were connecting, obviously not ALL timed out.
++  was_timed_out_ = false;
++  set_state(STATE_CONNECTING);
++}
++
++// We checked the status of our connections and not only weren't they writable
++// but they were also timed out, we really need a new allocator.
++void P2PSocket::HandleAllTimedOut() {
++  //
++  // No connections... all are timed out!
++  //
++  if (!was_timed_out_) {
++    // We weren't timed out before, so kick off an allocator now (we'll still
++    // be in the fully timed out state until the allocator actually gives back
++    // new ports)
++    OnAllocate();
++  }
++
++  // NOTE: we start was_timed_out_ in the true state so that we don't get
++  // another allocator created WHILE we are in the process of building up
++  // our first allocator.
++  was_timed_out_ = true;
++  was_writable_ = false;
++  set_state(STATE_CONNECTING);
++}
++
++// If we have a best connection, return it, otherwise return top one in the
++// list (later we will mark it best).
++Connection* P2PSocket::GetBestConnectionOnNetwork(Network* network) {
++  // If the best connection is on this network, then it wins.
++  if (best_connection_ && (best_connection_->port()->network() == network))
++    return best_connection_;
++
++  // Otherwise, we return the top-most in sorted order.
++  for (uint32 i = 0; i < connections_.size(); ++i) {
++    if (connections_[i]->port()->network() == network)
++      return connections_[i];
++  }
++
++  return NULL;
++}
++
++// Handle any queued up requests
++void P2PSocket::OnMessage(Message *pmsg) {
++  if (pmsg->message_id == MSG_SORT)
++    OnSort();
++  else if (pmsg->message_id == MSG_PING)
++    OnPing();
++  else if (pmsg->message_id == MSG_ALLOCATE)
++    OnAllocate();
++  else
++    assert(false);
++}
++
++// Handle queued up sort request
++void P2PSocket::OnSort() {
++  // Resort the connections based on the new statistics.
++  SortConnections();
++}
++
++// Handle queued up ping request
++void P2PSocket::OnPing() {
++  // Make sure the states of the connections are up-to-date (since this affects
++  // which ones are pingable).
++  UpdateConnectionStates();
++
++  // Find the oldest pingable connection and have it do a ping.
++  Connection* conn = FindNextPingableConnection();
++  if (conn)
++    conn->Ping(Time());
++
++  // Post ourselves a message to perform the next ping.
++  uint32 delay = (state_ == STATE_WRITABLE) ? WRITABLE_DELAY : UNWRITABLE_DELAY;
++  thread()->PostDelayed(delay, this, MSG_PING);
++}
++
++// Is the connection in a state for us to even consider pinging the other side?
++bool P2PSocket::IsPingable(Connection* conn) {
++  // An unconnected connection cannot be written to at all, so pinging is out
++  // of the question.
++  if (!conn->connected())
++    return false;
++
++  if (state_ == STATE_WRITABLE) {
++    // If we are writable, then we only want to ping connections that could be
++    // better than this one, i.e., the ones that were not pruned.
++    return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT);
++  } else {
++    // If we are not writable, then we need to try everything that might work.
++    // This includes both connections that do not have write timeout as well as
++    // ones that do not have read timeout.  A connection could be readable but
++    // be in write-timeout if we pruned it before.  Since the other side is
++    // still pinging it, it very well might still work.
++    return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) ||
++           (conn->read_state() != Connection::STATE_READ_TIMEOUT);
++  }
++}
++
++// Returns the next pingable connection to ping.  This will be the oldest
++// pingable connection unless we have a writable connection that is past the
++// maximum acceptable ping delay.
++Connection* P2PSocket::FindNextPingableConnection() {
++  uint32 now = Time();
++  if (best_connection_ &&
++      (best_connection_->write_state() == Connection::STATE_WRITABLE) &&
++      (best_connection_->last_ping_sent() 
++       + MAX_CURRENT_WRITABLE_DELAY <= now)) {
++    return best_connection_;
++  }
++
++  Connection* oldest_conn = NULL;
++  uint32 oldest_time = 0xFFFFFFFF;
++  for (uint32 i = 0; i < connections_.size(); ++i) {
++    if (IsPingable(connections_[i])) {
++      if (connections_[i]->last_ping_sent() < oldest_time) {
++        oldest_time = connections_[i]->last_ping_sent();
++        oldest_conn = connections_[i];
++      }
++    }
++  }
++  return oldest_conn;
++}
++
++// return the number of "pingable" connections
++uint32 P2PSocket::NumPingableConnections() {
++  uint32 count = 0;
++  for (uint32 i = 0; i < connections_.size(); ++i) {
++    if (IsPingable(connections_[i]))
++      count += 1;
++  }
++  return count;
++}
++
++// When a connection's state changes, we need to figure out who to use as
++// the best connection again.  It could have become usable, or become unusable.
++void P2PSocket::OnConnectionStateChange(Connection *connection) {
++  assert(worker_thread_ == Thread::Current());
++
++  // We have to unroll the stack before doing this because we may be changing
++  // the state of connections while sorting.
++  RequestSort();
++}
++
++// When a connection is removed, edit it out, and then update our best
++// connection.
++void P2PSocket::OnConnectionDestroyed(Connection *connection) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Remove this connection from the list.
++  std::vector<Connection*>::iterator iter =
++      find(connections_.begin(), connections_.end(), connection);
++  assert(iter != connections_.end());
++  connections_.erase(iter);
++
++  LOG(INFO) << "Removed connection from p2p socket: "
++            << static_cast<int>(connections_.size()) << " remaining";
++
++  // If this is currently the best connection, then we need to pick a new one.
++  // The call to SortConnections will pick a new one.  It looks at the current
++  // best connection in order to avoid switching between fairly similar ones.
++  // Since this connection is no longer an option, we can just set best to NULL
++  // and re-choose a best assuming that there was no best connection.
++  if (best_connection_ == connection) {
++    SwitchBestConnectionTo(NULL);
++    RequestSort();
++  }
++}
++
++// When a port is destroyed remove it from our list of ports to use for
++// connection attempts.
++void P2PSocket::OnPortDestroyed(Port* port) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Remove this port from the list (if we didn't drop it already).
++  std::vector<Port*>::iterator iter = find(ports_.begin(), ports_.end(), port);
++  if (iter != ports_.end())
++    ports_.erase(iter);
++
++  LOG(INFO) << "Removed port from p2p socket: "
++            << static_cast<int>(ports_.size()) << " remaining";
++}
++
++// We data is available, let listeners know
++void P2PSocket::OnReadPacket(Connection *connection, 
++                             const char *data, size_t len) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Let the client know of an incoming packet
++
++  SignalReadPacket(this, data, len);
++}
++
++// return socket name
++const std::string &P2PSocket::name() const {
++  return name_;
++}
++
++// return socket error value
++int P2PSocket::GetError() {
++  return error_;
++}
++
++// return a reference to the list of connections
++const std::vector<Connection *>& P2PSocket::connections() {
++  return connections_;
++}
++
++// Set options on ourselves is simply setting options on all of our available
++// port objects.
++int P2PSocket::SetOption(Socket::Option opt, int value) {
++  OptionMap::iterator it = options_.find(opt);
++  if (it == options_.end()) {
++    options_.insert(std::make_pair(opt, value));
++  } else if (it->second == value) {
++    return 0;
++  } else {
++    it->second = value;
++  }
++
++  for (uint32 i = 0; i < ports_.size(); ++i) {
++    int val = ports_[i]->SetOption(opt, value);
++    if (val < 0) {
++      // Because this also occurs deferred, probably no point in reporting an error
++      LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: " << ports_[i]->GetError();
++    }
++  }
++  return 0;
++}
++
++// returns the current state
++P2PSocket::State P2PSocket::state() {
++  return state_;
++}
++
++// Set the current state, and let listeners know when it changes
++void P2PSocket::set_state(P2PSocket::State state) {
++  assert(worker_thread_ == Thread::Current());
++  if (state != state_) {
++    state_ = state;
++    SignalState(this, state);
++  }
++}
++
++// Time for a new allocator, lets make sure we have a signalling channel
++// to communicate candidates through first.
++void P2PSocket::OnAllocate() {
++  // Allocation timer went off
++  waiting_for_signaling_ = true;
++  SignalRequestSignaling();
++}
++
++// When the signalling channel is ready, we can really kick off the allocator
++void P2PSocket::OnSignalingReady() {
++  if (waiting_for_signaling_) {
++    waiting_for_signaling_ = false;
++    AddAllocatorSession(allocator_->CreateSession(name_));
++    thread()->PostDelayed(kAllocatePeriod, this, MSG_ALLOCATE);
++  }
++}
++
++// return the current best connection writable state.
++bool P2PSocket::writable() {
++  assert(worker_thread_ == Thread::Current());
++
++  if (best_connection_ == NULL)
++    return false;
++  return best_connection_->write_state() == Connection::STATE_WRITABLE;
++}
++
++// return the worker thread
++Thread *P2PSocket::thread() {
++  return worker_thread_;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro	(revision 586398)
+@@ -0,0 +1,14 @@
++TEMPLATE = app
++INCLUDEPATH = ../../..
++DEFINES += POSIX
++
++include(../../../../../conf.pri)
++
++# Input
++SOURCES += \
++	relayserver.cc \
++	relayserver_main.cc \
++	../../base/host.cc \
++	../../base/socketaddresspair.cc
++
++LIBS += ../../../liblibjingle.a
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h	(revision 586398)
+@@ -0,0 +1,86 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSIONMANAGER_H_
++#define _SESSIONMANAGER_H_
++
++#include "talk/base/thread.h"
++#include "talk/p2p/base/portallocator.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/sessionmessage.h"
++#include "talk/base/sigslot.h"
++
++#include <string>
++#include <utility>
++#include <map>
++
++namespace cricket {
++
++class Session;
++
++// SessionManager manages session instances
++
++class SessionManager : public sigslot::has_slots<> {
++public:
++  SessionManager(PortAllocator *allocator, Thread *worker_thread = NULL);
++  virtual ~SessionManager();
++
++  Session *CreateSession(const std::string &name, const std::string& initiator);
++  void DestroySession(Session *session);
++  Session *GetSession(const SessionID& id);
++  void TerminateAll();
++  void OnIncomingMessage(const SessionMessage &m);
++  void OnIncomingError(const SessionMessage &m);
++  void OnSignalingReady();
++
++  PortAllocator *port_allocator() const;
++  Thread *worker_thread() const;
++  Thread *signaling_thread() const;
++  int session_timeout();
++  void set_session_timeout(int timeout);
++
++  sigslot::signal2<Session *, bool> SignalSessionCreate;
++  sigslot::signal1<Session *> SignalSessionDestroy;
++
++  // Note: you can connect this directly to OnSignalingReady(), if a signalling
++  // check is not required.
++  sigslot::signal0<> SignalRequestSignaling;
++
++private:
++  Session *CreateSession(const std::string &name, const SessionID& id, bool received_initiate);
++  void OnRequestSignaling();
++
++  int timeout_;
++  Thread *worker_thread_;
++  Thread *signaling_thread_;
++  PortAllocator *allocator_;
++  std::map<SessionID, Session *> session_map_;
++};
++
++} // namespace cricket
++
++#endif // _SESSIONMANAGER_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc	(revision 586398)
+@@ -0,0 +1,640 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/logging.h"
++#include "talk/base/asynctcpsocket.h"
++#include "talk/p2p/base/relayport.h"
++#include "talk/p2p/base/helpers.h"
++#include <iostream>
++#include <cassert>
++#ifdef OSX
++#include <errno.h>
++#endif
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++const int KEEPALIVE_DELAY = 10 * 60 * 1000;
++const int RETRY_DELAY = 50; // 50ms, from ICE spec
++const uint32 RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs
++
++const uint32 MSG_DISPOSE_SOCKET = 100; // needs to be more than ID used by Port
++typedef TypedMessageData<AsyncPacketSocket *> DisposeSocketData;
++
++class AsyncTCPSocket;
++
++// Manages a single connection to the relayserver.  We aim to use each
++// connection for only a specific destination address so that we can avoid
++// wrapping every packet in a STUN send / data indication.
++class RelayEntry : public sigslot::has_slots<> {
++public:
++  RelayEntry(RelayPort* port, const SocketAddress& ext_addr, const SocketAddress& local_addr);
++  ~RelayEntry();
++
++  RelayPort* port() { return port_; }
++
++  const SocketAddress& address() { return ext_addr_; }
++  void set_address(const SocketAddress& addr) { ext_addr_ = addr; }
++
++  AsyncPacketSocket* socket() { return socket_; }
++
++  bool connected() { return connected_; }
++  void set_connected(bool connected) { connected_ = connected; }
++
++  bool locked() { return locked_; }
++
++  // Returns the last error on the socket of this entry.
++  int GetError() { return socket_->GetError(); }
++
++  // Sends the STUN requests to the server to initiate this connection.
++  void Connect();
++
++  // Called when this entry becomes connected.  The address given is the one
++  // exposed to the outside world on the relay server.
++  void OnConnect(const SocketAddress& mapped_addr);
++
++  // Sends a packet to the given destination address using the socket of this
++  // entry.  This will wrap the packet in STUN if necessary.
++  int SendTo(const void* data, size_t size, const SocketAddress& addr);
++
++  // Schedules a keep-alive allocate request.
++  void ScheduleKeepAlive();
++
++  void SetServerIndex(size_t sindex) { server_index_ = sindex; }
++  size_t ServerIndex() const { return server_index_; }
++
++  // Try a different server address
++  void HandleConnectFailure();
++
++private:
++  RelayPort* port_;
++  SocketAddress ext_addr_, local_addr_;
++  size_t server_index_;
++  AsyncPacketSocket* socket_;
++  bool connected_;
++  bool locked_;
++  StunRequestManager requests_;
++
++  // Called when a TCP connection is established or fails
++  void OnSocketConnect(AsyncTCPSocket* socket);
++  void OnSocketClose(AsyncTCPSocket* socket, int error);
++
++  // Called when a packet is received on this socket.
++  void OnReadPacket(
++      const char* data, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++  // Called on behalf of a StunRequest to write data to the socket.  This is
++  // already STUN intended for the server, so no wrapping is necessary.
++  void OnSendPacket(const void* data, size_t size);
++
++  // Sends the given data on the socket to the server with no wrapping.  This
++  // returns the number of bytes written or -1 if an error occurred.
++  int SendPacket(const void* data, size_t size);
++};
++
++// Handles an allocate request for a particular RelayEntry.
++class AllocateRequest : public StunRequest {
++public:
++  AllocateRequest(RelayEntry* entry);
++  virtual ~AllocateRequest() {}
++
++  virtual void Prepare(StunMessage* request);
++
++  virtual int GetNextDelay();
++
++  virtual void OnResponse(StunMessage* response);
++  virtual void OnErrorResponse(StunMessage* response);
++  virtual void OnTimeout();
++
++private:
++  RelayEntry* entry_;
++  uint32 start_time_;
++};
++
++const std::string RELAY_PORT_TYPE("relay");
++
++RelayPort::RelayPort(
++    Thread* thread, SocketFactory* factory, Network* network,
++    const SocketAddress& local_addr, const std::string& username,
++    const std::string& password, const std::string& magic_cookie)
++  : Port(thread, RELAY_PORT_TYPE, factory, network), local_addr_(local_addr),
++    ready_(false), magic_cookie_(magic_cookie), error_(0) {
++
++  entries_.push_back(new RelayEntry(this, SocketAddress(), local_addr_));
++
++  set_username_fragment(username);
++  set_password(password);
++
++  if (magic_cookie_.size() == 0)
++    magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);
++}
++
++RelayPort::~RelayPort() {
++  for (unsigned i = 0; i < entries_.size(); ++i)
++    delete entries_[i];
++  thread_->Clear(this);
++}
++
++void RelayPort::AddServerAddress(const ProtocolAddress& addr) {
++  // Since HTTP proxies usually only allow 443, let's up the priority on PROTO_SSLTCP
++  if ((addr.proto == PROTO_SSLTCP)
++      && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) {
++    server_addr_.push_front(addr);
++  } else {
++    server_addr_.push_back(addr);
++  }
++}
++
++void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
++  std::string proto_name = ProtoToString(addr.proto);
++  for (std::vector<Candidate>::const_iterator it = candidates().begin(); it != candidates().end(); ++it) {
++    if ((it->address() == addr.address) && (it->protocol() == proto_name)) {
++      LOG(INFO) << "Redundant relay address: " << proto_name << " @ " << addr.address.ToString();
++      return;
++    }
++  }
++  add_address(addr.address, proto_name, false);
++}
++
++void RelayPort::SetReady() {
++  if (!ready_) {
++    ready_ = true;
++    SignalAddressReady(this);
++  }
++}
++
++const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
++  if ((index >= 0) && (index < server_addr_.size()))
++    return &server_addr_[index];
++  return 0;
++}
++
++bool RelayPort::HasMagicCookie(const char* data, size_t size) {
++  if (size < 24 + magic_cookie_.size()) {
++    return false;
++  } else {
++    return 0 == std::memcmp(data + 24,
++                            magic_cookie_.c_str(),
++                            magic_cookie_.size());
++  }
++}
++
++void RelayPort::PrepareAddress() {
++  // We initiate a connect on the first entry.  If this completes, it will fill
++  // in the server address as the address of this port.
++  assert(entries_.size() == 1);
++  entries_[0]->Connect();
++  ready_ = false;
++}
++
++Connection* RelayPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
++  // We only create connections to non-udp sockets if they are incoming on this port
++  if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT))
++    return 0;
++
++  // We don't support loopback on relays
++  if (address.type() == type())
++    return 0;
++
++  size_t index = 0;
++  for (size_t i = 0; i < candidates().size(); ++i) {
++    const Candidate& local = candidates()[i];
++    if (local.protocol() == address.protocol()) {
++      index = i;
++      break;
++    }
++  }
++
++  Connection * conn = new ProxyConnection(this, index, address);
++  AddConnection(conn);
++  return conn;
++}
++
++int RelayPort::SendTo(const void* data,
++                      size_t size,
++                      const SocketAddress& addr, bool payload) {
++
++  // Try to find an entry for this specific address.  Note that the first entry
++  // created was not given an address initially, so it can be set to the first
++  // address that comes along.
++
++  RelayEntry* entry = 0;
++
++  for (unsigned i = 0; i < entries_.size(); ++i) {
++    if (entries_[i]->address().IsAny() && payload) {
++      entry = entries_[i];
++      entry->set_address(addr);
++      break;
++    } else if (entries_[i]->address() == addr) {
++      entry = entries_[i];
++      break;
++    }
++  }
++
++  // If we did not find one, then we make a new one.  This will not be useable
++  // until it becomes connected, however.
++  if (!entry && payload) {
++    entry = new RelayEntry(this, addr, local_addr_);
++    if (!entries_.empty()) {
++      // Use the same port to connect to relay server
++      entry->SetServerIndex(entries_[0]->ServerIndex());
++    }
++    entry->Connect();
++    entries_.push_back(entry);
++  }
++
++  // If the entry is connected, then we can send on it (though wrapping may
++  // still be necessary).  Otherwise, we can't yet use this connection, so we
++  // default to the first one.
++  if (!entry || !entry->connected()) {
++    assert(!entries_.empty());
++    entry = entries_[0];
++    if (!entry->connected()) {
++      error_ = EWOULDBLOCK;
++      return SOCKET_ERROR;
++    }
++  }
++
++  // Send the actual contents to the server using the usual mechanism.
++  int sent = entry->SendTo(data, size, addr);
++  if (sent <= 0) {
++    assert(sent < 0);
++    error_ = entry->GetError();
++    return SOCKET_ERROR;
++  }
++
++  // The caller of the function is expecting the number of user data bytes,
++  // rather than the size of the packet.
++  return (int)size;
++}
++
++void RelayPort::OnMessage(Message *pmsg) {
++  switch (pmsg->message_id) {
++  case MSG_DISPOSE_SOCKET: {
++    DisposeSocketData * data = static_cast<DisposeSocketData *>(pmsg->pdata);
++    delete data->data();
++    delete data;
++    break; }
++  default:
++    Port::OnMessage(pmsg);
++  }
++}
++
++int RelayPort::SetOption(Socket::Option opt, int value) {
++  int result = 0;
++  for (unsigned i = 0; i < entries_.size(); ++i) {
++    if (entries_[i]->socket()->SetOption(opt, value) < 0) {
++      result = -1;
++      error_ = entries_[i]->socket()->GetError();
++    }
++  }
++  options_.push_back(OptionValue(opt, value));
++  return result;
++}
++
++int RelayPort::GetError() {
++  return error_;
++}
++
++void RelayPort::OnReadPacket(
++    const char* data, size_t size, const SocketAddress& remote_addr) {
++  if (Connection* conn = GetConnection(remote_addr)) {
++    conn->OnReadPacket(data, size);
++  } else {
++    Port::OnReadPacket(data, size, remote_addr);
++  }
++}
++
++void RelayPort::DisposeSocket(AsyncPacketSocket * socket) {
++  thread_->Post(this, MSG_DISPOSE_SOCKET, new DisposeSocketData(socket));
++}
++
++RelayEntry::RelayEntry(RelayPort* port, const SocketAddress& ext_addr,
++                       const SocketAddress& local_addr)
++  : port_(port), ext_addr_(ext_addr), local_addr_(local_addr), server_index_(0),
++    socket_(0), connected_(false), locked_(false), requests_(port->thread()) {
++
++  requests_.SignalSendPacket.connect(this, &RelayEntry::OnSendPacket);
++}
++
++RelayEntry::~RelayEntry() {
++  delete socket_;
++}
++
++void RelayEntry::Connect() {
++  assert(socket_ == 0);
++  const ProtocolAddress * ra = port()->ServerAddress(server_index_);
++  if (!ra) {
++    LOG(INFO) << "Out of relay server connections";
++    return;
++  }
++
++  LOG(INFO) << "Connecting to relay via " << ProtoToString(ra->proto) << " @ " << ra->address.ToString();
++
++  socket_ = port_->CreatePacketSocket(ra->proto);
++  assert(socket_ != 0);
++
++  socket_->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
++  if (socket_->Bind(local_addr_) < 0)
++    LOG(INFO) << "bind: " << std::strerror(socket_->GetError());
++
++  for (unsigned i = 0; i < port_->options().size(); ++i)
++    socket_->SetOption(port_->options()[i].first, port_->options()[i].second);
++
++  if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
++    AsyncTCPSocket * tcp = static_cast<AsyncTCPSocket *>(socket_);
++    tcp->SignalClose.connect(this, &RelayEntry::OnSocketClose);
++    tcp->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
++    tcp->Connect(ra->address);
++  } else {
++    requests_.Send(new AllocateRequest(this));
++  }
++}
++
++void RelayEntry::OnConnect(const SocketAddress& mapped_addr) {
++  ProtocolType proto = PROTO_UDP;
++  LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto) << " @ " << mapped_addr.ToString();
++  connected_ = true;
++
++  port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
++  port_->SetReady();
++}
++
++int RelayEntry::SendTo(const void* data,
++                        size_t size,
++                        const SocketAddress& addr) {
++
++  // If this connection is locked to the address given, then we can send the
++  // packet with no wrapper.
++  if (locked_ && (ext_addr_ == addr))
++    return SendPacket(data, size);
++
++  // Otherwise, we must wrap the given data in a STUN SEND request so that we
++  // can communicate the destination address to the server.
++  //
++  // Note that we do not use a StunRequest here.  This is because there is
++  // likely no reason to resend this packet. If it is late, we just drop it.
++  // The next send to this address will try again.
++
++  StunMessage request;
++  request.SetType(STUN_SEND_REQUEST);
++  request.SetTransactionID(CreateRandomString(16));
++
++  StunByteStringAttribute* magic_cookie_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
++  magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
++                               (uint16)port_->magic_cookie().size());
++  request.AddAttribute(magic_cookie_attr);
++
++  StunByteStringAttribute* username_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++  username_attr->CopyBytes(port_->username_fragment().c_str(),
++                           (uint16)port_->username_fragment().size());
++  request.AddAttribute(username_attr);
++
++  StunAddressAttribute* addr_attr =
++      StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
++  addr_attr->SetFamily(1);
++  addr_attr->SetIP(addr.ip());
++  addr_attr->SetPort(addr.port());
++  request.AddAttribute(addr_attr);
++
++  // Attempt to lock
++  if (ext_addr_ == addr) {
++    StunUInt32Attribute* options_attr =
++      StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
++    options_attr->SetValue(0x1);
++    request.AddAttribute(options_attr);
++  }
++
++  StunByteStringAttribute* data_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_DATA);
++  data_attr->CopyBytes(data, (uint16)size);
++  request.AddAttribute(data_attr);
++
++  // TODO: compute the HMAC.
++
++  ByteBuffer buf;
++  request.Write(&buf);
++
++  return SendPacket(buf.Data(), buf.Length());
++}
++
++void RelayEntry::ScheduleKeepAlive() {
++  requests_.SendDelayed(new AllocateRequest(this), KEEPALIVE_DELAY);
++}
++
++void RelayEntry::HandleConnectFailure() {
++  //if (GetMillisecondCount() - start_time_ > RETRY_TIMEOUT)
++  //  return;
++  //ScheduleKeepAlive();
++
++  connected_ = false;
++  port()->DisposeSocket(socket_);
++  socket_ = 0;
++  server_index_ += 1;
++  Connect();
++}
++
++void RelayEntry::OnSocketConnect(AsyncTCPSocket* socket) {
++  assert(socket == socket_);
++  LOG(INFO) << "relay tcp connected to " << socket->GetRemoteAddress().ToString();
++  requests_.Send(new AllocateRequest(this));
++}
++
++void RelayEntry::OnSocketClose(AsyncTCPSocket* socket, int error) {
++  assert(socket == socket_);
++  PLOG(LERROR, error) << "relay tcp connect failed";
++  HandleConnectFailure();
++}
++
++void RelayEntry::OnReadPacket(const char* data,
++                              size_t size,
++                              const SocketAddress& remote_addr,
++                              AsyncPacketSocket* socket) {
++  assert(socket == socket_);
++  //assert(remote_addr == port_->server_addr()); TODO: are we worried about this?
++
++  // If the magic cookie is not present, then this is an unwrapped packet sent
++  // by the server,  The actual remote address is the one we recorded.
++  if (!port_->HasMagicCookie(data, size)) {
++    if (locked_) {
++      port_->OnReadPacket(data, size, ext_addr_);
++    } else {
++      LOG(WARNING) << "Dropping packet: entry not locked";
++    }
++    return;
++  }
++
++  ByteBuffer buf(data, size);
++  StunMessage msg;
++  if (!msg.Read(&buf)) {
++    LOG(INFO) << "Incoming packet was not STUN";
++    return;
++  }
++
++  // The incoming packet should be a STUN ALLOCATE response, SEND response, or
++  // DATA indication.
++  if (requests_.CheckResponse(&msg)) {
++    return;
++  } else if (msg.type() == STUN_SEND_RESPONSE) {
++    if (const StunUInt32Attribute* options_attr = msg.GetUInt32(STUN_ATTR_OPTIONS)) {
++      if (options_attr->value() & 0x1) {
++        locked_ = true;
++      }
++    }
++    return;
++  } else if (msg.type() != STUN_DATA_INDICATION) {
++    LOG(INFO) << "Received BAD stun type from server: " << msg.type()
++             ;
++    return;
++  }
++
++  // This must be a data indication.
++
++  const StunAddressAttribute* addr_attr =
++      msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
++  if (!addr_attr) {
++    LOG(INFO) << "Data indication has no source address";
++    return;
++  } else if (addr_attr->family() != 1) {
++    LOG(INFO) << "Source address has bad family";
++    return;
++  }
++
++  SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port());
++
++  const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
++  if (!data_attr) {
++    LOG(INFO) << "Data indication has no data";
++    return;
++  }
++
++  // Process the actual data and remote address in the normal manner.
++  port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2);
++}
++
++void RelayEntry::OnSendPacket(const void* data, size_t size) {
++  SendPacket(data, size);
++}
++
++int RelayEntry::SendPacket(const void* data, size_t size) {
++  const ProtocolAddress * ra = port_->ServerAddress(server_index_);
++  if (!ra) {
++    socket_->SetError(ENOTCONN);
++    return SOCKET_ERROR;
++  }
++  int sent = socket_->SendTo(data, size, ra->address);
++  if (sent <= 0) {
++    LOG(LS_VERBOSE) << "sendto: " << std::strerror(socket_->GetError());
++    assert(sent < 0);
++  }
++  return sent;
++}
++
++AllocateRequest::AllocateRequest(RelayEntry* entry) : entry_(entry) {
++  start_time_ = GetMillisecondCount();
++}
++
++void AllocateRequest::Prepare(StunMessage* request) {
++  request->SetType(STUN_ALLOCATE_REQUEST);
++
++  StunByteStringAttribute* magic_cookie_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
++  magic_cookie_attr->CopyBytes(
++      entry_->port()->magic_cookie().c_str(),
++      (uint16)entry_->port()->magic_cookie().size());
++  request->AddAttribute(magic_cookie_attr);
++
++  StunByteStringAttribute* username_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++  username_attr->CopyBytes(
++      entry_->port()->username_fragment().c_str(),
++      (uint16)entry_->port()->username_fragment().size());
++  request->AddAttribute(username_attr);
++}
++
++int AllocateRequest::GetNextDelay() {
++  int delay = 100 * _max(1 << count_, 2);
++  count_ += 1;
++  if (count_ == 5)
++    timeout_ = true;
++  return delay;
++}
++
++void AllocateRequest::OnResponse(StunMessage* response) {
++  const StunAddressAttribute* addr_attr =
++      response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
++  if (!addr_attr) {
++    LOG(INFO) << "Allocate response missing mapped address.";
++  } else if (addr_attr->family() != 1) {
++    LOG(INFO) << "Mapped address has bad family";
++  } else {
++    SocketAddress addr(addr_attr->ip(), addr_attr->port());
++    entry_->OnConnect(addr);
++  }
++
++  // We will do a keep-alive regardless of whether this request suceeds.
++  // This should have almost no impact on network usage.
++  entry_->ScheduleKeepAlive();
++}
++
++void AllocateRequest::OnErrorResponse(StunMessage* response) {
++  const StunErrorCodeAttribute* attr = response->GetErrorCode();
++  if (!attr) {
++    LOG(INFO) << "Bad allocate response error code";
++  } else {
++    LOG(INFO) << "Allocate error response:"
++              << " code=" << static_cast<int>(attr->error_code())
++              << " reason='" << attr->reason() << "'";
++  }
++
++  if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
++    entry_->ScheduleKeepAlive();
++}
++
++void AllocateRequest::OnTimeout() {
++  LOG(INFO) << "Allocate request timed out";
++  entry_->HandleConnectFailure();
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __STUNSERVER_H__
++#define __STUNSERVER_H__
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/p2p/base/stun.h"
++
++namespace cricket {
++
++const int STUN_SERVER_PORT = 3478;
++
++class StunServer : public sigslot::has_slots<> {
++public:
++  // Creates a STUN server, which will listen on the given socket.
++  StunServer(AsyncUDPSocket* socket);
++
++  // Removes the STUN server from the socket, but does not delete the socket.
++  ~StunServer();
++
++protected:
++
++  // Slot for AsyncSocket.PacketRead:
++  void OnPacket(
++      const char* buf, size_t size, const SocketAddress& remote_addr,
++      AsyncPacketSocket* socket);
++
++  // Handlers for the different types of STUN/TURN requests:
++  void OnBindingRequest(StunMessage* msg, const SocketAddress& addr);
++  void OnAllocateRequest(StunMessage* msg, const SocketAddress& addr);
++  void OnSharedSecretRequest(StunMessage* msg, const SocketAddress& addr);
++  void OnSendRequest(StunMessage* msg, const SocketAddress& addr);
++
++  // Sends an error response to the given message back to the user.
++  void SendErrorResponse(
++      const StunMessage& msg, const SocketAddress& addr, int error_code,
++      const char* error_desc);
++
++  // Sends the given message to the appropriate destination.
++  void SendResponse(const StunMessage& msg, const SocketAddress& addr);
++
++private:
++  AsyncUDPSocket* socket_;
++};
++
++} // namespace cricket
++
++#endif // __STUNSERVER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h	(revision 586398)
+@@ -0,0 +1,93 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __RELAYPORT_H__
++#define __RELAYPORT_H__
++
++#include "talk/p2p/base/port.h"
++#include "talk/p2p/base/stunrequest.h"
++#include <vector>
++
++namespace cricket {
++
++extern const std::string RELAY_PORT_TYPE;
++class RelayEntry;
++
++// Communicates using an allocated port on the relay server.
++class RelayPort: public Port {
++public:
++  RelayPort(
++      Thread* thread, SocketFactory* factory, Network*,
++      const SocketAddress& local_addr,
++      const std::string& username, const std::string& password,
++      const std::string& magic_cookie);
++  virtual ~RelayPort();
++
++  void AddServerAddress(const ProtocolAddress& addr);
++  void AddExternalAddress(const ProtocolAddress& addr);
++
++  typedef std::pair<Socket::Option, int> OptionValue;
++  const std::vector<OptionValue>& options() const { return options_; }
++
++  const std::string& magic_cookie() const { return magic_cookie_; }
++  bool HasMagicCookie(const char* data, size_t size);
++
++  virtual void PrepareAddress();
++  virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
++
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError();
++
++  const ProtocolAddress * ServerAddress(size_t index) const;
++
++  void DisposeSocket(AsyncPacketSocket * socket);
++
++protected:
++  void SetReady();
++
++  virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
++  virtual void OnMessage(Message *pmsg);
++
++  // Dispatches the given packet to the port or connection as appropriate.
++  void OnReadPacket(
++      const char* data, size_t size, const SocketAddress& remote_addr);
++
++private:
++  friend class RelayEntry;
++
++  SocketAddress local_addr_;
++  std::deque<ProtocolAddress> server_addr_;
++  bool ready_;
++  std::vector<RelayEntry*> entries_;
++  std::vector<OptionValue> options_;
++  std::string magic_cookie_;
++  int error_;
++};
++
++} // namespace cricket
++
++#endif // __RELAYPORT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc	(revision 586398)
+@@ -0,0 +1,421 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/common.h"
++#include "talk/base/logging.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/p2p/base/session.h"
++
++namespace cricket {
++
++const uint32 MSG_TIMEOUT = 1;
++const uint32 MSG_ERROR = 2;
++const uint32 MSG_STATE = 3;
++
++Session::Session(SessionManager *session_manager, const std::string &name,
++    const SessionID& id) {
++  session_manager_ = session_manager;
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++  name_ = name;
++  id_ = id;
++  error_ = ERROR_NONE;
++  state_ = STATE_INIT;
++  initiator_ = false;
++  description_ = NULL;
++  remote_description_ = NULL;
++  socket_manager_ = new SocketManager(session_manager_);
++  socket_manager_->SignalCandidatesReady.connect(this, &Session::OnCandidatesReady);
++  socket_manager_->SignalNetworkError.connect(this, &Session::OnNetworkError);
++  socket_manager_->SignalState.connect(this, &Session::OnSocketState);
++  socket_manager_->SignalRequestSignaling.connect(this, &Session::OnRequestSignaling);
++}
++
++Session::~Session() {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++  delete description_;
++  delete remote_description_;
++  delete socket_manager_;
++  session_manager_->signaling_thread()->Clear(this);
++}
++
++P2PSocket *Session::CreateSocket(const std::string &name) {
++  return socket_manager_->CreateSocket(name);
++}
++
++void Session::DestroySocket(P2PSocket *socket) {
++  socket_manager_->DestroySocket(socket);
++}
++
++void Session::OnCandidatesReady(const std::vector<Candidate>& candidates) {
++  SendSessionMessage(SessionMessage::TYPE_CANDIDATES, NULL, &candidates, NULL);
++}
++
++void Session::OnNetworkError() {
++  // Socket manager is experiencing a network error trying to allocate
++  // network resources (usually port allocation)
++
++  set_error(ERROR_NETWORK);
++}
++
++void Session::OnSocketState() {
++  // If the call is not in progress, then we don't care about writability.
++  // We have separate timers for making sure we transition back to the in-
++  // progress state in time.
++  if (state_ != STATE_INPROGRESS)
++    return;
++
++  // Put the timer into the write state.  This is called when the state changes,
++  // so we will restart the timer each time we lose writability.
++  if (socket_manager_->writable()) {
++    session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
++  } else {
++    session_manager_->signaling_thread()->PostDelayed(
++        session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
++  }
++}
++
++void Session::OnRequestSignaling() {
++  SignalRequestSignaling();
++}
++
++void Session::OnSignalingReady() {
++  socket_manager_->OnSignalingReady();
++}
++
++void Session::SendSessionMessage(SessionMessage::Type type,
++                                 const SessionDescription* description,
++                                 const std::vector<Candidate>* candidates,
++                                 SessionMessage::Cookie* redirect_cookie) {
++  SessionMessage m;
++  m.set_type(type);
++  m.set_to(remote_address_);
++  m.set_name(name_);
++  m.set_description(description);
++  m.set_session_id(id_);
++  if (candidates)
++    m.set_candidates(*candidates);
++  m.set_redirect_target(redirect_target_);
++  m.set_redirect_cookie(redirect_cookie);
++  SignalOutgoingMessage(this, m);
++}
++
++bool Session::Initiate(const std::string &to, const SessionDescription *description) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Only from STATE_INIT
++  if (state_ != STATE_INIT)
++    return false;
++
++  // Setup for signaling. Initiate is asynchronous. It occurs once the address
++  // candidates are ready.
++  initiator_ = true;
++  remote_address_ = to;
++  description_ = description;
++  SendSessionMessage(SessionMessage::TYPE_INITIATE, description, NULL, NULL);
++  set_state(Session::STATE_SENTINITIATE);
++
++  // Let the socket manager know we now want the candidates
++  socket_manager_->StartProcessingCandidates();
++
++  // Start the session timeout
++  session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
++  session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
++  return true;
++}
++
++bool Session::Accept(const SessionDescription *description) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Only if just received initiate
++  if (state_ != STATE_RECEIVEDINITIATE)
++    return false;
++
++  // Setup for signaling. Accept is asynchronous. It occurs once the address
++  // candidates are ready.
++  initiator_ = false;
++  description_ = description;
++  SendSessionMessage(SessionMessage::TYPE_ACCEPT, description, NULL, NULL);
++  set_state(Session::STATE_SENTACCEPT);
++
++  return true;
++}
++
++bool Session::Modify(const SessionDescription *description) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Only if session already STATE_INPROGRESS
++  if (state_ != STATE_INPROGRESS)
++    return false;
++
++  // Modify is asynchronous. It occurs once the address candidates are ready.
++  // Either side can send a modify. It is only valid in an already accepted
++  // session.
++  description_ = description;
++  SendSessionMessage(SessionMessage::TYPE_MODIFY, description, NULL, NULL);
++  set_state(Session::STATE_SENTMODIFY);
++
++  // Start the session timeout
++  session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
++  session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
++  return true;
++}
++
++bool Session::Redirect(const std::string& target) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Redirect is sent in response to an initiate or modify, to redirect the
++  // request
++  if (state_ != STATE_RECEIVEDINITIATE)
++    return false;
++
++  initiator_ = false;
++  redirect_target_ = target;
++  SendSessionMessage(SessionMessage::TYPE_REDIRECT, NULL, NULL, NULL);
++
++  // A redirect puts us in the same state as reject.  It just sends a different
++  // kind of reject message, if you like.
++  set_state(STATE_SENTREDIRECT);
++
++  return true;
++}
++
++bool Session::Reject() {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Reject is sent in response to an initiate or modify, to reject the
++  // request
++  if (state_ != STATE_RECEIVEDINITIATE && state_ != STATE_RECEIVEDMODIFY)
++    return false;
++
++  initiator_ = false;
++  SendSessionMessage(SessionMessage::TYPE_REJECT, NULL, NULL, NULL);
++  set_state(STATE_SENTREJECT);
++
++  return true;
++}
++
++bool Session::Terminate() {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // Either side can terminate, at any time.
++  if (state_ == STATE_SENTTERMINATE && state_ != STATE_RECEIVEDTERMINATE)
++    return false;
++
++  // But we don't need to terminate if we already rejected.  The other client
++  // already knows that we're done with this session.
++  if (state_ != STATE_SENTREDIRECT)
++    SendSessionMessage(SessionMessage::TYPE_TERMINATE, NULL, NULL, NULL);
++
++  set_state(STATE_SENTTERMINATE);
++
++  return true;
++}
++
++void Session::OnIncomingError(const SessionMessage &m) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  // If a candidate message errors out or gets dropped for some reason we
++  // ignore the error.
++  if (m.type() != SessionMessage::TYPE_CANDIDATES) {
++    set_error(ERROR_RESPONSE);
++  }
++}
++
++void Session::OnIncomingMessage(const SessionMessage &m) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++
++  switch (m.type()) {
++  case SessionMessage::TYPE_INITIATE:
++    remote_description_ = m.description();
++    remote_address_ = m.from();
++    name_ = m.name();
++    initiator_ = false;
++    set_state(STATE_RECEIVEDINITIATE);
++
++    // Let the socket manager know we now want the initial candidates
++    socket_manager_->StartProcessingCandidates();
++    break;
++
++  case SessionMessage::TYPE_ACCEPT:
++    remote_description_ = m.description();
++    set_state(STATE_RECEIVEDACCEPT);
++    break;
++
++  case SessionMessage::TYPE_MODIFY:
++    remote_description_ = m.description();
++    set_state(STATE_RECEIVEDMODIFY);
++    break;
++
++  case SessionMessage::TYPE_CANDIDATES:
++    socket_manager_->AddRemoteCandidates(m.candidates());
++    break;
++
++  case SessionMessage::TYPE_REJECT:
++    set_state(STATE_RECEIVEDREJECT);
++    break;
++
++  case SessionMessage::TYPE_REDIRECT:
++    OnRedirectMessage(m);
++    break;
++
++  case SessionMessage::TYPE_TERMINATE:
++    set_state(STATE_RECEIVEDTERMINATE);
++    break;
++  }
++}
++
++void Session::OnRedirectMessage(const SessionMessage &m) {
++  ASSERT(state_ == STATE_SENTINITIATE);
++  if (state_ != STATE_SENTINITIATE)
++    return;
++
++  ASSERT(m.redirect_target().size() != 0);
++  remote_address_ = m.redirect_target();
++
++  SendSessionMessage(SessionMessage::TYPE_INITIATE, description_, NULL,
++                     m.redirect_cookie()->Copy());
++
++  // Restart the session timeout.
++  session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
++  session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
++
++  // Reset all of the sockets back into the initial state.
++  socket_manager_->ResetSockets();
++}
++
++Session::State Session::state() {
++  return state_;
++}
++
++void Session::set_state(State state) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++  if (state != state_) {
++    state_ = state;
++    SignalState(this, state);
++    session_manager_->signaling_thread()->Post(this, MSG_STATE);
++  }
++}
++
++Session::Error Session::error() {
++  return error_;
++}
++
++void Session::set_error(Error error) {
++  ASSERT(session_manager_->signaling_thread()->IsCurrent());
++  if (error != error_) {
++    error_ = error;
++    SignalError(this, error);
++    session_manager_->signaling_thread()->Post(this, MSG_ERROR);
++  }
++}
++
++const std::string &Session::name() {
++  return name_;
++}
++
++const std::string &Session::remote_address() {
++  return remote_address_;
++}
++
++bool Session::initiator() {
++  return initiator_;
++}
++
++const SessionID& Session::id() {
++  return id_;
++}
++
++const SessionDescription *Session::description() {
++  return description_;
++}
++
++const SessionDescription *Session::remote_description() {
++  return remote_description_;
++}
++
++SessionManager *Session::session_manager() {
++  return session_manager_;
++}
++
++void Session::OnMessage(Message *pmsg) {
++  switch(pmsg->message_id) {
++  case MSG_TIMEOUT:
++    // Session timeout has occured. Check to see if the session is still trying
++    // to signal. If so, the session has timed out.
++    // The Sockets have their own timeout for connectivity.
++    set_error(ERROR_TIME);
++    break;
++
++  case MSG_ERROR:
++    switch (error_) {
++    case ERROR_RESPONSE:
++      // This state could be reached if we get an error in response to an IQ
++      // or if the network is so slow we time out on an individual IQ exchange.
++      // In either case, Terminate (send more messages) and ignore the likely
++      // cascade of more errors.
++
++      // fall through
++    case ERROR_NETWORK:
++    case ERROR_TIME:
++      // Time ran out - no response
++      Terminate();
++      break;
++
++    default:
++      break;
++    }
++    break;
++
++  case MSG_STATE:
++    switch (state_) {
++    case STATE_SENTACCEPT:
++    case STATE_RECEIVEDACCEPT:
++      set_state(STATE_INPROGRESS);
++      session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
++      OnSocketState(); // Update the writability timeout state.
++      break;
++
++    case STATE_SENTREJECT:
++    case STATE_SENTREDIRECT:
++    case STATE_RECEIVEDREJECT:
++      Terminate();
++      break;
++
++    case STATE_SENTTERMINATE:
++    case STATE_RECEIVEDTERMINATE:
++      session_manager_->DestroySession(this);
++      break;
++
++    default:
++      // explicitly ignoring some states here
++      break;
++    }
++    break;
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc	(revision 586398)
+@@ -0,0 +1,869 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/logging.h"
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/asynctcpsocket.h"
++#include "talk/base/socketadapters.h"
++#include "talk/p2p/base/port.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/base/scoped_ptr.h"
++#include <errno.h>
++#include <algorithm>
++#include <iostream>
++#include <cassert>
++#include <vector>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::memcmp;
++}
++#endif
++
++namespace {
++
++// The length of time we wait before timing out readability on a connection.
++const uint32 CONNECTION_READ_TIMEOUT = 30 * 1000; // 30 seconds
++
++// The length of time we wait before timing out writability on a connection.
++const uint32 CONNECTION_WRITE_TIMEOUT = 15 * 1000; // 15 seconds
++
++// The length of time we wait before we become unwritable.
++const uint32 CONNECTION_WRITE_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds
++
++// The number of pings that must fail to respond before we become unwritable.
++const uint32 CONNECTION_WRITE_CONNECT_FAILURES = 5;
++
++// This is the length of time that we wait for a ping response to come back.
++const int CONNECTION_RESPONSE_TIMEOUT = 5 * 1000; // 5 seconds
++
++// Determines whether we have seen at least the given maximum number of
++// pings fail to have a response.
++inline bool TooManyFailures(
++    const std::vector<uint32>& pings_since_last_response,
++    uint32 maximum_failures,
++    uint32 rtt_estimate,
++    uint32 now) {
++
++  // If we haven't sent that many pings, then we can't have failed that many.
++  if (pings_since_last_response.size() < maximum_failures)
++    return false;
++
++  // Check if the window in which we would expect a response to the ping has
++  // already elapsed.
++  return pings_since_last_response[maximum_failures - 1] + rtt_estimate < now;
++}
++
++// Determines whether we have gone too long without seeing any response.
++inline bool TooLongWithoutResponse(
++    const std::vector<uint32>& pings_since_last_response,
++    uint32 maximum_time,
++    uint32 now) {
++
++  if (pings_since_last_response.size() == 0)
++    return false;
++
++  return pings_since_last_response[0] + maximum_time < now;
++}
++
++// We will restrict RTT estimates (when used for determining state) to be
++// within a reasonable range.
++const uint32 MINIMUM_RTT = 100;  // 0.1 seconds
++const uint32 MAXIMUM_RTT = 3000; // 3 seconds
++
++// When we don't have any RTT data, we have to pick something reasonable.  We
++// use a large value just in case the connection is really slow.
++const uint32 DEFAULT_RTT = MAXIMUM_RTT;
++
++// Computes our estimate of the RTT given the current estimate and the number
++// of data points on which it is based.
++inline uint32 ConservativeRTTEstimate(uint32 rtt, uint32 rtt_data_points) {
++  if (rtt_data_points == 0)
++    return DEFAULT_RTT;
++  else
++    return cricket::_max(MINIMUM_RTT, cricket::_min(MAXIMUM_RTT, 2 * rtt));
++}
++
++// Weighting of the old rtt value to new data.
++const int RTT_RATIO = 3; // 3 : 1
++
++// The delay before we begin checking if this port is useless.
++const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
++
++const uint32 MSG_CHECKTIMEOUT = 1;
++const uint32 MSG_DELETE = 1;
++
++}
++
++namespace cricket {
++
++static const char * const PROTO_NAMES[PROTO_LAST+1] = { "udp", "tcp", "ssltcp" };
++
++const char * ProtoToString(ProtocolType proto) {
++  return PROTO_NAMES[proto];
++}
++
++bool StringToProto(const char * value, ProtocolType& proto) {
++  for (size_t i=0; i<=PROTO_LAST; ++i) {
++    if (strcmp(PROTO_NAMES[i], value) == 0) {
++      proto = static_cast<ProtocolType>(i);
++      return true;
++    }
++  }
++  return false;
++}
++
++ProxyInfo Port::proxy_;
++
++Port::Port(Thread* thread, const std::string& type, SocketFactory* factory,
++           Network* network)
++  : thread_(thread), factory_(factory), type_(type), network_(network),
++    preference_(-1), lifetime_(LT_PRESTART) {
++
++  if (factory_ == NULL)
++    factory_ = thread_->socketserver();
++
++  set_username_fragment(CreateRandomString(16));
++  set_password(CreateRandomString(16));
++}
++
++Port::~Port() {
++  // Delete all of the remaining connections.  We copy the list up front
++  // because each deletion will cause it to be modified.
++
++  std::vector<Connection*> list;
++
++  AddressMap::iterator iter = connections_.begin();
++  while (iter != connections_.end()) {
++    list.push_back(iter->second);
++    ++iter;
++  }
++
++  for (uint32 i = 0; i < list.size(); i++)
++    delete list[i];
++}
++
++Connection* Port::GetConnection(const SocketAddress& remote_addr) {
++  AddressMap::const_iterator iter = connections_.find(remote_addr);
++  if (iter != connections_.end())
++    return iter->second;
++  else
++    return NULL;
++}
++
++void Port::set_username_fragment(const std::string& username_fragment) {
++  username_frag_ = username_fragment;
++}
++
++void Port::set_password(const std::string& password) {
++  password_ = password;
++}
++
++void Port::add_address(const SocketAddress& address, const std::string& protocol, bool final) {
++  Candidate c;
++  c.set_name(name_);
++  c.set_type(type_);
++  c.set_protocol(protocol);
++  c.set_address(address);
++  c.set_preference(preference_);
++  c.set_username(username_frag_);
++  c.set_password(password_);
++  c.set_network_name(network_->name());
++  c.set_generation(generation_);
++  candidates_.push_back(c);
++
++  if (final)
++    SignalAddressReady(this);
++}
++
++void Port::AddConnection(Connection* conn) {
++  connections_[conn->remote_candidate().address()] = conn;
++  conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
++  SignalConnectionCreated(this, conn);
++}
++
++void Port::OnReadPacket(
++    const char* data, size_t size, const SocketAddress& addr) {
++
++  // If this is an authenticated STUN request, then signal unknown address and
++  // send back a proper binding response.
++  StunMessage* msg;
++  std::string remote_username;
++  if (!GetStunMessage(data, size, addr, msg, remote_username)) {
++    LOG(LERROR) << "Received non-STUN packet from unknown address: "
++               << addr.ToString();
++  } else if (!msg) {
++    // STUN message handled already
++  } else if (msg->type() == STUN_BINDING_REQUEST) {
++    SignalUnknownAddress(this, addr, msg, remote_username);
++  } else {
++    LOG(LERROR) << "Received unexpected STUN message type (" << msg->type()
++               << ") from unknown address: " << addr.ToString();
++    delete msg;
++  }
++}
++
++void Port::SendBindingRequest(Connection* conn) {
++
++  // Construct the request message.
++
++  StunMessage request;
++  request.SetType(STUN_BINDING_REQUEST);
++  request.SetTransactionID(CreateRandomString(16));
++
++  StunByteStringAttribute* username_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++  std::string username = conn->remote_candidate().username();
++  username.append(username_frag_);
++  username_attr->CopyBytes(username.c_str(), (uint16)username.size());
++  request.AddAttribute(username_attr);
++
++  // Send the request message.
++  // NOTE: If we wanted to, this is where we would add the HMAC.
++  ByteBuffer buf;
++  request.Write(&buf);
++  SendTo(buf.Data(), buf.Length(), conn->remote_candidate().address(), false);
++}
++
++bool Port::GetStunMessage(const char* data, size_t size,
++                          const SocketAddress& addr, StunMessage *& msg,
++                          std::string& remote_username) {
++  // NOTE: This could clearly be optimized to avoid allocating any memory.
++  //       However, at the data rates we'll be looking at on the client side,
++  //       this probably isn't worth worrying about.
++
++  msg = 0;
++
++  // Parse the request message.  If the packet is not a complete and correct
++  // STUN message, then ignore it.
++  buzz::scoped_ptr<StunMessage> stun_msg(new StunMessage());
++  ByteBuffer buf(data, size);
++  if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
++    return false;
++  }
++
++  // The packet must include a username that either begins or ends with our
++  // fragment.  It should begin with our fragment if it is a request and it
++  // should end with our fragment if it is a response.
++  const StunByteStringAttribute* username_attr =
++      stun_msg->GetByteString(STUN_ATTR_USERNAME);
++
++  int remote_frag_len = (username_attr ? username_attr->length() : 0);
++  remote_frag_len -= static_cast<int>(username_frag_.size());
++
++  if (stun_msg->type() == STUN_BINDING_REQUEST) {
++    if ((remote_frag_len < 0)
++        || (std::memcmp(username_attr->bytes(),
++                        username_frag_.c_str(), username_frag_.size()) != 0)) {
++      LOG(LERROR) << "Received STUN request with bad username";
++      SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
++        STUN_ERROR_REASON_BAD_REQUEST);
++      return true;
++    }
++
++    remote_username.assign(username_attr->bytes() + username_frag_.size(),
++      username_attr->bytes() + username_attr->length());
++  } else if ((stun_msg->type() == STUN_BINDING_RESPONSE)
++      || (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
++    if ((remote_frag_len < 0)
++        || (std::memcmp(username_attr->bytes() + remote_frag_len,
++                        username_frag_.c_str(), username_frag_.size()) != 0)) {
++      LOG(LERROR) << "Received STUN response with bad username";
++      // Do not send error response to a response
++      return true;
++    }
++
++    remote_username.assign(username_attr->bytes(),
++      username_attr->bytes() + remote_frag_len);
++
++    if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
++      if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
++        LOG(LERROR) << "Received STUN binding error:"
++                   << " class=" << error_code->error_class()
++                   << " number=" << error_code->number()
++                   << " reason='" << error_code->reason() << "'";
++        // Return message to allow error-specific processing
++      } else {
++        LOG(LERROR) << "Received STUN error response with no error code";
++        // Drop corrupt message
++        return true;
++      }
++    }
++  } else {
++    LOG(LERROR) << "Received STUN packet with invalid type: "
++               << stun_msg->type();
++    return true;
++  }
++
++  // Return the STUN message found.
++  msg = stun_msg.release();
++  return true;
++}
++
++void Port::SendBindingResponse(
++    StunMessage* request, const SocketAddress& addr) {
++
++  assert(request->type() == STUN_BINDING_REQUEST);
++
++  // Retrieve the username from the request.
++  const StunByteStringAttribute* username_attr =
++      request->GetByteString(STUN_ATTR_USERNAME);
++  assert(username_attr);
++
++  // Fill in the response message.
++
++  StunMessage response;
++  response.SetType(STUN_BINDING_RESPONSE);
++  response.SetTransactionID(request->transaction_id());
++
++  StunByteStringAttribute* username2_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++  username2_attr->CopyBytes(username_attr->bytes(), username_attr->length());
++  response.AddAttribute(username2_attr);
++
++  StunAddressAttribute* addr_attr =
++      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
++  addr_attr->SetFamily(1);
++  addr_attr->SetPort(addr.port());
++  addr_attr->SetIP(addr.ip());
++  response.AddAttribute(addr_attr);
++
++  // Send the response message.
++  // NOTE: If we wanted to, this is where we would add the HMAC.
++  ByteBuffer buf;
++  response.Write(&buf);
++  SendTo(buf.Data(), buf.Length(), addr, false);
++
++  // The fact that we received a successful request means that this connection
++  // (if one exists) should now be readable.
++  Connection* conn = GetConnection(addr);
++  assert(conn);
++  if (conn)
++    conn->ReceivedPing();
++}
++
++void Port::SendBindingErrorResponse(
++    StunMessage* request, const SocketAddress& addr, int error_code,
++    const std::string& reason) {
++
++  assert(request->type() == STUN_BINDING_REQUEST);
++
++  // Retrieve the username from the request.  If it didn't have one, we
++  // shouldn't be responding at all.
++  const StunByteStringAttribute* username_attr =
++      request->GetByteString(STUN_ATTR_USERNAME);
++  assert(username_attr);
++
++  // Fill in the response message.
++
++  StunMessage response;
++  response.SetType(STUN_BINDING_ERROR_RESPONSE);
++  response.SetTransactionID(request->transaction_id());
++
++  StunByteStringAttribute* username2_attr =
++      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++  username2_attr->CopyBytes(username_attr->bytes(), username_attr->length());
++  response.AddAttribute(username2_attr);
++
++  StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
++  error_attr->SetErrorCode(error_code);
++  error_attr->SetReason(reason);
++  response.AddAttribute(error_attr);
++
++  // Send the response message.
++  // NOTE: If we wanted to, this is where we would add the HMAC.
++  ByteBuffer buf;
++  response.Write(&buf);
++  SendTo(buf.Data(), buf.Length(), addr, false);
++}
++
++AsyncPacketSocket * Port::CreatePacketSocket(ProtocolType proto) {
++  if (proto == PROTO_UDP) {
++    return new AsyncUDPSocket(factory_->CreateAsyncSocket(SOCK_DGRAM));
++  } else if ((proto == PROTO_TCP) || (proto == PROTO_SSLTCP)) {
++    AsyncSocket * socket = factory_->CreateAsyncSocket(SOCK_STREAM);
++    switch (proxy().type) {
++    case PROXY_NONE:
++      break;
++    case PROXY_SOCKS5:
++      socket = new AsyncSocksProxySocket(socket, proxy().address, proxy().username, proxy().password);
++      break;
++    case PROXY_HTTPS:
++    default:
++      socket = new AsyncHttpsProxySocket(socket, proxy().address, proxy().username, proxy().password);
++      break;
++    }
++    if (proto == PROTO_SSLTCP) {
++      socket = new AsyncSSLSocket(socket);
++    }
++    return new AsyncTCPSocket(socket);
++  } else {
++    LOG(INFO) << "Unknown protocol: " << proto;
++    return 0;
++  }
++}
++
++void Port::OnMessage(Message *pmsg) {
++  assert(pmsg->message_id == MSG_CHECKTIMEOUT);
++  assert(lifetime_ == LT_PRETIMEOUT);
++  lifetime_ = LT_POSTTIMEOUT;
++  CheckTimeout();
++}
++
++void Port::Start() {
++  // The port sticks around for a minimum lifetime, after which
++  // we destroy it when it drops to zero connections.
++  if (lifetime_ == LT_PRESTART) {
++    lifetime_ = LT_PRETIMEOUT;
++    thread_->PostDelayed(kPortTimeoutDelay, this, MSG_CHECKTIMEOUT);
++  } else {
++    LOG(WARNING) << "Port restart attempted";
++  }
++}
++
++void Port::OnConnectionDestroyed(Connection* conn) {
++  AddressMap::iterator iter = connections_.find(conn->remote_candidate().address());
++  assert(iter != connections_.end());
++  connections_.erase(iter);
++
++  CheckTimeout();
++}
++
++void Port::CheckTimeout() {
++  // If this port has no connections, then there's no reason to keep it around.
++  // When the connections time out (both read and write), they will delete
++  // themselves, so if we have any connections, they are either readable or
++  // writable (or still connecting).
++  if ((lifetime_ == LT_POSTTIMEOUT) && connections_.empty()) {
++    LOG(INFO) << "Destroying port: " << name_ << "-" << type_;
++    SignalDestroyed(this);
++    delete this;
++  }
++}
++
++// A ConnectionRequest is a simple STUN ping used to determine writability.
++class ConnectionRequest : public StunRequest {
++public:
++  ConnectionRequest(Connection* connection) : connection_(connection) {
++  }
++
++  virtual ~ConnectionRequest() {
++  }
++
++  virtual void Prepare(StunMessage* request) {
++    request->SetType(STUN_BINDING_REQUEST);
++    StunByteStringAttribute* username_attr =
++        StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
++    std::string username = connection_->remote_candidate().username();
++    username.append(connection_->port()->username_fragment());
++    username_attr->CopyBytes(username.c_str(), (uint16)username.size());
++    request->AddAttribute(username_attr);
++  }
++
++  virtual void OnResponse(StunMessage* response) {
++    connection_->OnConnectionRequestResponse(response, Elapsed());
++  }
++
++  virtual void OnErrorResponse(StunMessage* response) {
++    connection_->OnConnectionRequestErrorResponse(response, Elapsed());
++  }
++
++  virtual void OnTimeout() {
++  }
++
++  virtual int GetNextDelay() {
++    // Each request is sent only once.  After a single delay , the request will
++    // time out.
++    timeout_ = true;
++    return CONNECTION_RESPONSE_TIMEOUT;
++  }
++
++private:
++  Connection* connection_;
++};
++
++//
++// Connection
++//
++
++Connection::Connection(Port* port, size_t index, const Candidate& remote_candidate)
++  : requests_(port->thread()), port_(port), local_candidate_index_(index),
++    remote_candidate_(remote_candidate), read_state_(STATE_READ_TIMEOUT),
++    write_state_(STATE_WRITE_CONNECT), connected_(true), pruned_(false),
++    rtt_(0), rtt_data_points_(0), last_ping_sent_(0), last_ping_received_(0),
++    recv_total_bytes_(0), recv_bytes_second_(0),
++    last_recv_bytes_second_time_((uint32)-1), last_recv_bytes_second_calc_(0),
++    sent_total_bytes_(0), sent_bytes_second_(0),
++    last_sent_bytes_second_time_((uint32)-1), last_sent_bytes_second_calc_(0) {
++
++  // Wire up to send stun packets
++  requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
++}
++
++Connection::~Connection() {
++}
++
++const Candidate& Connection::local_candidate() const {
++  if (local_candidate_index_ < port_->candidates().size())
++    return port_->candidates()[local_candidate_index_];
++  assert(false);
++  static Candidate foo;
++  return foo;
++}
++
++void Connection::set_read_state(ReadState value) {
++  ReadState old_value = read_state_;
++  read_state_ = value;
++  if (value != old_value) {
++    SignalStateChange(this);
++    CheckTimeout();
++  }
++}
++
++void Connection::set_write_state(WriteState value) {
++  WriteState old_value = write_state_;
++  write_state_ = value;
++  if (value != old_value) {
++    SignalStateChange(this);
++    CheckTimeout();
++  }
++}
++
++void Connection::set_connected(bool value) {
++  bool old_value = connected_;
++  connected_ = value;
++
++  // When connectedness is turned off, this connection is done.
++  if (old_value && !value)
++    set_write_state(STATE_WRITE_TIMEOUT);
++}
++
++void Connection::OnSendStunPacket(const void* data, size_t size) {
++  port_->SendTo(data, size, remote_candidate_.address(), false);
++}
++
++void Connection::OnReadPacket(const char* data, size_t size) {
++  StunMessage* msg;
++  std::string remote_username;
++  const SocketAddress& addr(remote_candidate_.address());
++  if (!port_->GetStunMessage(data, size, addr, msg, remote_username)) {
++    // The packet did not parse as a valid STUN message
++  
++    // If this connection is readable, then pass along the packet.
++    if (read_state_ == STATE_READABLE) {
++      // readable means data from this address is acceptable
++      // Send it on!
++
++      recv_total_bytes_ += size;
++      SignalReadPacket(this, data, size);
++
++      // If timed out sending writability checks, start up again
++      if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
++        set_write_state(STATE_WRITE_CONNECT);
++    } else {
++      // Not readable means the remote address hasn't send a valid
++      // binding request yet.
++
++      LOG(WARNING) << "Received non-STUN packet from an unreadable connection.";
++    }
++  } else if (!msg) {
++    // The packet was STUN, but was already handled
++  } else if (remote_username != remote_candidate_.username()) {
++    // Not destined this connection
++    LOG(LERROR) << "Received STUN packet on wrong address.";
++    if (msg->type() == STUN_BINDING_REQUEST) {
++      port_->SendBindingErrorResponse(msg, addr, STUN_ERROR_BAD_REQUEST,
++                                      STUN_ERROR_REASON_BAD_REQUEST);
++    }
++    delete msg;
++  } else {
++    // The packet is STUN, with the current username
++    // If this is a STUN request, then update the readable bit and respond.
++    // If this is a STUN response, then update the writable bit.
++
++    switch (msg->type()) {
++    case STUN_BINDING_REQUEST:
++      // Incoming, validated stun request from remote peer.
++      // This call will also set the connection readable.
++
++      port_->SendBindingResponse(msg, addr);
++
++      // If timed out sending writability checks, start up again
++      if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
++        set_write_state(STATE_WRITE_CONNECT);
++      break;
++
++    case STUN_BINDING_RESPONSE:
++    case STUN_BINDING_ERROR_RESPONSE:
++      // Response from remote peer. Does it match request sent?
++      // This doesn't just check, it makes callbacks if transaction
++      // id's match
++      requests_.CheckResponse(msg);
++      break;
++
++    default:
++      assert(false);
++      break;
++    }
++
++    // Done with the message; delete
++
++    delete msg;
++  }
++}
++
++void Connection::Prune() {
++  pruned_ = true;
++  requests_.Clear();
++  set_write_state(STATE_WRITE_TIMEOUT);
++}
++
++void Connection::Destroy() {
++  set_read_state(STATE_READ_TIMEOUT);
++  set_write_state(STATE_WRITE_TIMEOUT);
++}
++
++void Connection::UpdateState(uint32 now) {
++  // Check the readable state.
++  //
++  // Since we don't know how many pings the other side has attempted, the best
++  // test we can do is a simple window.
++
++  if ((read_state_ == STATE_READABLE) &&
++      (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now)) {
++    set_read_state(STATE_READ_TIMEOUT);
++  }
++
++  // Check the writable state.  (The order of these checks is important.)
++  //
++  // Before becoming unwritable, we allow for a fixed number of pings to fail
++  // (i.e., receive no response).  We also have to give the response time to
++  // get back, so we include a conservative estimate of this.
++  //
++  // Before timing out writability, we give a fixed amount of time.  This is to
++  // allow for changes in network conditions.
++
++  uint32 rtt = ConservativeRTTEstimate(rtt_, rtt_data_points_);
++
++  if ((write_state_ == STATE_WRITABLE) &&
++      TooManyFailures(pings_since_last_response_,
++                      CONNECTION_WRITE_CONNECT_FAILURES,
++                      rtt,
++                      now) &&
++      TooLongWithoutResponse(pings_since_last_response_,
++                             CONNECTION_WRITE_CONNECT_TIMEOUT,
++                             now)) {
++    set_write_state(STATE_WRITE_CONNECT);
++  }
++
++  if ((write_state_ == STATE_WRITE_CONNECT) &&
++      TooLongWithoutResponse(pings_since_last_response_,
++                             CONNECTION_WRITE_TIMEOUT,
++                             now)) {
++    set_write_state(STATE_WRITE_TIMEOUT);
++  }
++}
++
++void Connection::Ping(uint32 now) {
++  assert(connected_);
++  last_ping_sent_ = now;
++  pings_since_last_response_.push_back(now);
++  requests_.Send(new ConnectionRequest(this));
++}
++
++void Connection::ReceivedPing() {
++  last_ping_received_ = Time();
++  set_read_state(STATE_READABLE);
++}
++
++void Connection::OnConnectionRequestResponse(StunMessage *response, uint32 rtt) {
++  // We have a potentially valid reply from the remote address.
++  // The packet must include a username that ends with our fragment,
++  // since it is a response.
++
++  // Check exact message type
++  bool valid = true;
++  if (response->type() != STUN_BINDING_RESPONSE)
++    valid = false;
++
++  // Must have username attribute
++  const StunByteStringAttribute* username_attr =
++      response->GetByteString(STUN_ATTR_USERNAME);
++  if (valid) {
++    if (!username_attr) {
++      LOG(LERROR) << "Received likely STUN packet with no username";
++      valid = false;
++    }
++  }
++
++  // Length must be at least the size of our fragment (actually, should
++  // be bigger since our fragment is at the end!)
++  if (valid) {
++    if (username_attr->length() <= port_->username_fragment().size()) {
++      LOG(LERROR) << "Received likely STUN packet with short username";
++      valid = false;
++    }
++  }
++
++  // Compare our fragment with the end of the username - must be exact match
++  if (valid) {
++    std::string username_fragment = port_->username_fragment();
++    int offset = (int)(username_attr->length() - username_fragment.size());
++    if (std::memcmp(username_attr->bytes() + offset,
++        username_fragment.c_str(), username_fragment.size()) != 0) {
++      LOG(LERROR) << "Received STUN response with bad username";
++      valid = false;
++    }
++  }
++
++  if (valid) {
++    // Valid response. If we're not already, become writable.  We may be
++    // bringing a pruned connection back to life, but if we don't really want
++    // it, we can always prune it again.
++    set_write_state(STATE_WRITABLE);
++
++    pings_since_last_response_.clear();
++    rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
++    rtt_data_points_ += 1;
++  }
++}
++
++void Connection::OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt) {
++  const StunErrorCodeAttribute* error = response->GetErrorCode();
++  uint32 error_code = error ? error->error_code() : STUN_ERROR_GLOBAL_FAILURE;
++
++  if ((error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE)
++      || (error_code == STUN_ERROR_SERVER_ERROR)
++      || (error_code == STUN_ERROR_UNAUTHORIZED)) {
++    // Recoverable error, retry
++  } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
++    // Race failure, retry
++  } else {
++    // This is not a valid connection.
++    set_connected(false);
++  }
++}
++
++void Connection::CheckTimeout() {
++  // If both read and write have timed out, then this connection can contribute
++  // no more to p2p socket unless at some later date readability were to come
++  // back.  However, we gave readability a long time to timeout, so at this
++  // point, it seems fair to get rid of this connectoin.
++  if ((read_state_ == STATE_READ_TIMEOUT) &&
++      (write_state_ == STATE_WRITE_TIMEOUT)) {
++    port_->thread()->Post(this, MSG_DELETE);
++  }
++}
++
++void Connection::OnMessage(Message *pmsg) {
++  assert(pmsg->message_id == MSG_DELETE);
++
++  LOG(INFO) << "Destroying connection: from "
++            << local_candidate().address().ToString()
++            << " to " << remote_candidate_.address().ToString();
++
++  SignalDestroyed(this);
++  delete this;
++}
++
++size_t Connection::recv_bytes_second() {
++  // Snapshot bytes / second calculator
++
++  uint32 current_time = Time();
++  if (last_recv_bytes_second_time_ != (uint32)-1) {
++    int delta = TimeDiff(current_time, last_recv_bytes_second_time_);
++    if (delta >= 1000) {
++      int fraction_time = delta % 1000;
++      int seconds_time = delta - fraction_time;
++      int fraction_bytes = (int)(recv_total_bytes_ - last_recv_bytes_second_calc_) * fraction_time / delta;
++      recv_bytes_second_ = (recv_total_bytes_ - last_recv_bytes_second_calc_ - fraction_bytes) * seconds_time / delta;
++      last_recv_bytes_second_time_ = current_time - fraction_time;
++      last_recv_bytes_second_calc_ = recv_total_bytes_ - fraction_bytes;
++    }
++  }
++  if (last_recv_bytes_second_time_ == (uint32)-1) {
++    last_recv_bytes_second_time_ = current_time;
++    last_recv_bytes_second_calc_ = recv_total_bytes_;
++  }
++
++  return recv_bytes_second_;
++}
++
++size_t Connection::recv_total_bytes() {
++  return recv_total_bytes_;
++}
++
++size_t Connection::sent_bytes_second() {
++  // Snapshot bytes / second calculator
++
++  uint32 current_time = Time();
++  if (last_sent_bytes_second_time_ != (uint32)-1) {
++    int delta = TimeDiff(current_time, last_sent_bytes_second_time_);
++    if (delta >= 1000) {
++      int fraction_time = delta % 1000;
++      int seconds_time = delta - fraction_time;
++      int fraction_bytes = (int)(sent_total_bytes_ - last_sent_bytes_second_calc_) * fraction_time / delta;
++      sent_bytes_second_ = (sent_total_bytes_ - last_sent_bytes_second_calc_ - fraction_bytes) * seconds_time / delta;
++      last_sent_bytes_second_time_ = current_time - fraction_time;
++      last_sent_bytes_second_calc_ = sent_total_bytes_ - fraction_bytes;
++    }
++  }
++  if (last_sent_bytes_second_time_ == (uint32)-1) {
++    last_sent_bytes_second_time_ = current_time;
++    last_sent_bytes_second_calc_ = sent_total_bytes_;
++  }
++
++  return sent_bytes_second_;
++}
++
++size_t Connection::sent_total_bytes() {
++  return sent_total_bytes_;
++}
++
++ProxyConnection::ProxyConnection(Port* port, size_t index, const Candidate& candidate)
++  : Connection(port, index, candidate), error_(0) {
++}
++
++int ProxyConnection::Send(const void* data, size_t size) {
++  if (write_state() != STATE_WRITABLE) {
++    error_ = EWOULDBLOCK;
++    return SOCKET_ERROR;
++  }
++  int sent = port_->SendTo(data, size, remote_candidate_.address(), true);
++  if (sent <= 0) {
++    assert(sent < 0);
++    error_ = port_->GetError();
++  } else {
++    sent_total_bytes_ += sent;
++  }
++  return sent;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/host.h"
++#include "talk/base/thread.h"
++#include "talk/p2p/base/stunserver.h"
++#include <iostream>
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++using namespace cricket;
++
++int main(int argc, char* argv[]) {
++  if (argc != 1) {
++    std::cerr << "usage: stunserver" << std::endl;
++    return 1;
++  }
++
++  SocketAddress server_addr(LocalHost().networks()[1]->ip(), 7000);
++
++  Thread *pthMain = Thread::Current(); 
++  
++  AsyncUDPSocket* server_socket = CreateAsyncUDPSocket(pthMain->socketserver());
++  if (server_socket->Bind(server_addr) < 0) {
++    std::cerr << "bind: " << std::strerror(errno) << std::endl;
++    return 1;
++  }
++
++  StunServer* server = new StunServer(server_socket);
++
++  std::cout << "Listening at " << server_addr.ToString() << std::endl;
++
++  pthMain->Loop();
++
++  delete server;
++  delete server_socket;
++  return 0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h	(revision 586398)
+@@ -0,0 +1,140 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSION_H_
++#define _SESSION_H_
++
++#include "talk/base/socketaddress.h"
++#include "talk/p2p/base/sessiondescription.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/sessionmessage.h"
++#include "talk/p2p/base/socketmanager.h"
++#include "talk/p2p/base/p2psocket.h"
++#include "talk/p2p/base/port.h"
++#include <string>
++
++namespace cricket {
++
++class SessionManager;
++class SocketManager;
++
++// A specific Session created by the SessionManager
++// A Session manages signaling for session setup and tear down, and connectivity
++// with P2PSockets
++
++class Session : public MessageHandler, public sigslot::has_slots<> {
++public:
++  enum State {
++    STATE_INIT = 0,
++    STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject
++    STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject
++    STATE_SENTACCEPT, // sent accept. begin connectivity establishment
++    STATE_RECEIVEDACCEPT, // received accept. begin connectivity establishment
++    STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject
++    STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject
++    STATE_SENTREJECT, // sent reject after receiving initiate
++    STATE_RECEIVEDREJECT, // received reject after sending initiate
++    STATE_SENTREDIRECT, // sent direct after receiving initiate
++    STATE_SENTTERMINATE, // sent terminate (any time / either side)
++    STATE_RECEIVEDTERMINATE, // received terminate (any time / either side)
++    STATE_INPROGRESS, // session accepted and in progress
++  };
++
++  enum Error {
++    ERROR_NONE = 0, // no error
++    ERROR_TIME, // no response to signaling
++    ERROR_RESPONSE, // error during signaling
++    ERROR_NETWORK, // network error, could not allocate network resources
++  };
++
++  Session(SessionManager *session_manager, const std::string &name, const SessionID& id);
++  ~Session();
++
++  // From MessageHandler
++  void OnMessage(Message *pmsg);
++
++  P2PSocket *CreateSocket(const std::string & name);
++  void DestroySocket(P2PSocket *socket);
++
++  bool Initiate(const std::string &to, const SessionDescription *description);
++  bool Accept(const SessionDescription *description);
++  bool Modify(const SessionDescription *description);
++  bool Reject();
++  bool Redirect(const std::string& target);
++  bool Terminate();
++
++  SessionManager *session_manager();
++  const std::string &name();
++  const std::string &remote_address();
++  bool initiator();
++  const SessionID& id();
++  const SessionDescription *description();
++  const SessionDescription *remote_description();
++
++  State state();
++  Error error();
++
++  void OnSignalingReady();
++  void OnIncomingMessage(const SessionMessage &m);
++  void OnIncomingError(const SessionMessage &m);
++
++  sigslot::signal2<Session *, State> SignalState;
++  sigslot::signal2<Session *, Error> SignalError;
++  sigslot::signal2<Session *, const SessionMessage &> SignalOutgoingMessage;
++  sigslot::signal0<> SignalRequestSignaling;
++
++private:
++  void SendSessionMessage(SessionMessage::Type type,
++                          const SessionDescription* description,
++                          const std::vector<Candidate>* candidates,
++                          SessionMessage::Cookie* redirect_cookie);
++  void OnCandidatesReady(const std::vector<Candidate>& candidates);
++  void OnNetworkError();
++  void OnSocketState();
++  void OnRequestSignaling();
++  void OnRedirectMessage(const SessionMessage &m);
++
++  void set_state(State state);
++  void set_error(Error error);
++
++  bool initiator_;
++  SessionManager *session_manager_;
++  SessionID id_;
++  SocketManager *socket_manager_;
++  std::string name_;
++  std::string remote_address_;
++  const SessionDescription *description_;
++  const SessionDescription *remote_description_;
++  std::string redirect_target_;
++  State state_;
++  Error error_;
++  CriticalSection crit_;
++};
++
++} // namespace cricket
++
++#endif // _SESSION_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am	(revision 586398)
+@@ -0,0 +1,44 @@
++libcricketp2pbase_la_SOURCES = stun.cc \
++			       port.cc \
++			       udpport.cc \
++			       tcpport.cc \
++			       helpers.cc \
++			       sessionmanager.cc \
++			       session.cc \
++			       p2psocket.cc \
++			       relayport.cc \
++			       stunrequest.cc \
++			       stunport.cc \
++			       socketmanager.cc 
++
++noinst_HEADERS =               candidate.h \
++                               portallocator.h \
++			       relayport.h \
++		     	       session.h \
++		       	       sessionmessage.h \
++			       stunport.h \
++			       tcpport.h \
++                               helpers.h \
++			       port.h \
++		       	       sessionid.h \
++			       socketmanager.h \
++			       stunrequest.h \
++			       udpport.h \
++                               p2psocket.h \
++			       sessiondescription.h \
++			       sessionmanager.h \
++			       stun.h  \
++			       relayserver.h \
++			       stunserver.h
++
++AM_CPPFLAGS = -DPOSIX  $(all_includes) -I$(srcdir)/../../..
++
++bin_PROGRAMS = relayserver stunserver
++relayserver_SOURCES = relayserver.cc relayserver_main.cc
++relayserver_LDADD = ../../base/libcricketbase.la libcricketp2pbase.la -lpthread
++stunserver_SOURCES = stunserver.cc stunserver_main.cc
++stunserver_LDADD = ../../base/libcricketbase.la libcricketp2pbase.la -lpthread
++
++noinst_LTLIBRARIES = libcricketp2pbase.la
++
++DEFAULT_INCLUDES = -I$(srcdir)/../../..
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h	(revision 586398)
+@@ -0,0 +1,133 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSIONMESSAGE_H_
++#define _SESSIONMESSAGE_H_
++
++#include "talk/p2p/base/candidate.h"
++#include "talk/p2p/base/sessiondescription.h"
++#include "talk/p2p/base/sessionid.h"
++#include "talk/base/basictypes.h"
++#include <string>
++#include <vector>
++#include <sstream>
++
++namespace cricket {
++
++class SessionMessage {
++public:
++  enum Type {
++    TYPE_INITIATE = 0,          // Initiate message
++    TYPE_ACCEPT,                // Accept message
++    TYPE_MODIFY,                // Modify message
++    TYPE_CANDIDATES,            // Candidates message
++    TYPE_REJECT,                // Reject message
++    TYPE_REDIRECT,              // Reject message
++    TYPE_TERMINATE,             // Terminate message
++  };
++
++  class Cookie {
++  public:
++    virtual ~Cookie() {}
++
++    // Returns a copy of this cookie.
++    virtual Cookie* Copy() = 0;
++  };
++
++  Type type() const {
++    return type_;
++  }
++  void set_type(Type type) {
++    type_ = type;
++  }
++  const SessionID& session_id() const {
++    return id_;
++  }
++  SessionID& session_id() {
++    return id_;
++  }
++  void set_session_id(const SessionID& id) {
++    id_ = id;
++  }
++  const std::string &from() const {
++    return from_;
++  }
++  void set_from(const std::string &from) {
++    from_ = from;
++  }
++  const std::string &to() const {
++    return to_;
++  }
++  void set_to(const std::string &to) {
++    to_ = to;
++  }
++  const std::string &name() const {
++    return name_;
++  }
++  void set_name(const std::string &name) {
++    name_ = name;
++  }
++  const std::string &redirect_target() const {
++    return redirect_target_;
++  }
++  void set_redirect_target(const std::string &redirect_target) {
++    redirect_target_ = redirect_target;
++  }
++  Cookie *redirect_cookie() const {
++    return redirect_cookie_;
++  }
++  void set_redirect_cookie(Cookie* redirect_cookie) {
++    redirect_cookie_ = redirect_cookie;
++  }
++  const SessionDescription *description() const {
++    return description_;
++  }
++  void set_description(const SessionDescription *description) {
++    description_ = description;
++  }
++  const std::vector<Candidate> &candidates() const {
++    return candidates_;
++  }
++  void set_candidates(const std::vector<Candidate> &candidates) {
++    candidates_ = candidates;
++  }
++
++private:
++  Type type_;
++  SessionID id_;
++  std::string from_;
++  std::string to_;
++  std::string name_;
++  const SessionDescription *description_;
++  std::vector<Candidate> candidates_;
++  std::string redirect_target_;
++  Cookie* redirect_cookie_;
++};
++
++} // namespace cricket
++
++#endif // _SESSIONMESSAGE_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc	(revision 586398)
+@@ -0,0 +1,149 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "socketmonitor.h"
++#include <cassert>
++
++namespace cricket {
++
++const uint32 MSG_MONITOR_POLL = 1;
++const uint32 MSG_MONITOR_START = 2;
++const uint32 MSG_MONITOR_STOP = 3;
++const uint32 MSG_MONITOR_SIGNAL = 4;
++
++SocketMonitor::SocketMonitor(P2PSocket *socket, Thread *monitor_thread) {
++  socket_ = socket;
++  monitoring_thread_ = monitor_thread;
++  monitoring_ = false;
++}
++
++SocketMonitor::~SocketMonitor() {
++  socket_->thread()->Clear(this);
++  monitoring_thread_->Clear(this);
++}
++
++void SocketMonitor::Start(int milliseconds) {
++  rate_ = milliseconds;
++  if (rate_ < 250)
++    rate_ = 250;
++  socket_->thread()->Post(this, MSG_MONITOR_START);
++}
++
++void SocketMonitor::Stop() {
++  socket_->thread()->Post(this, MSG_MONITOR_STOP);
++}
++
++void SocketMonitor::OnMessage(Message *message) {
++  CritScope cs(&crit_);
++
++  switch (message->message_id) {
++  case MSG_MONITOR_START:
++    assert(Thread::Current() == socket_->thread());
++    if (!monitoring_) {
++      monitoring_ = true;
++      socket_->SignalConnectionMonitor.connect(this, &SocketMonitor::OnConnectionMonitor);
++      PollSocket(true);
++    }
++    break;
++
++  case MSG_MONITOR_STOP:
++    assert(Thread::Current() == socket_->thread());
++    if (monitoring_) {
++      monitoring_ = false;
++      socket_->SignalConnectionMonitor.disconnect(this);
++      socket_->thread()->Clear(this);
++    }
++    break;
++
++  case MSG_MONITOR_POLL:
++    assert(Thread::Current() == socket_->thread());
++    PollSocket(true);
++    break;
++
++  case MSG_MONITOR_SIGNAL:
++    {
++      assert(Thread::Current() == monitoring_thread_);
++      std::vector<ConnectionInfo> infos = connection_infos_;
++      crit_.Leave();
++      SignalUpdate(this, infos);
++      crit_.Enter();
++    }
++    break;
++  }
++}
++
++void SocketMonitor::OnConnectionMonitor(P2PSocket *socket) {
++  CritScope cs(&crit_);
++  if (monitoring_)
++    PollSocket(false);
++}
++
++void SocketMonitor::PollSocket(bool poll) {
++  CritScope cs(&crit_);
++  assert(Thread::Current() == socket_->thread());
++
++  // Gather connection infos
++
++  connection_infos_.clear();
++  const std::vector<Connection *> &connections = socket_->connections();
++  std::vector<Connection *>::const_iterator it;
++  for (it = connections.begin(); it != connections.end(); it++) {
++    Connection *connection = *it;
++    ConnectionInfo info;
++    info.best_connection = socket_->best_connection() == connection;
++    info.readable = connection->read_state() == Connection::STATE_READABLE;
++    info.writable = connection->write_state() == Connection::STATE_WRITABLE;
++    info.timeout = connection->write_state() == Connection::STATE_WRITE_TIMEOUT;
++    info.new_connection = false; // connection->new_connection();
++    info.rtt = connection->rtt();
++    info.sent_total_bytes = connection->sent_total_bytes();
++    info.sent_bytes_second = connection->sent_bytes_second();
++    info.recv_total_bytes = connection->recv_total_bytes();
++    info.recv_bytes_second = connection->recv_bytes_second();
++    info.local_candidate = connection->local_candidate();
++    info.remote_candidate = connection->remote_candidate();
++    info.est_quality = connection->port()->network()->quality();
++    info.key = reinterpret_cast<void *>(connection);
++    connection_infos_.push_back(info);
++  }
++
++  // Signal the monitoring thread, start another poll timer
++
++  monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
++  if (poll)
++    socket_->thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL);
++}
++
++P2PSocket *SocketMonitor::socket() {
++  return socket_;
++}
++
++Thread *SocketMonitor::monitor_thread() {
++  return monitoring_thread_;
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc	(revision 586398)
+@@ -0,0 +1,545 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/base/logging.h"
++#include "talk/xmllite/qname.h"
++#include "talk/xmpp/constants.h"
++#include "talk/xmllite/xmlprinter.h"
++#include <iostream>
++#undef SetPort
++
++namespace {
++
++// We only allow usernames to be this many characters or fewer.
++const size_t kMaxUsernameSize = 16;
++
++}
++
++namespace cricket {
++
++#if 0
++>>>>>>
++<iq from="..." to="..." type="set" id="27">
++  <session xmlns="http://www.google.com/session" type="initiate" id="Dr45JU8A34DF" initiator="...">
++    <description xmlns="http://www.whoever.com/whatever">
++      ...
++    </description>
++  </session>
++</iq>
++
++<<<<<<
++<iq from="..." to="..." type="result" id="27"/>
++
++>>>>>>
++<iq from="..." to="..." type="set" id="28">
++  <session xmlns="http://www.google.com/session" type="candidates" id="Dr45JU8A34DF" initiator="...">
++    <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
++    <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
++    <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
++  </session>
++</iq>>
++
++<<<<<<
++<iq from="..." to="..." type="result" id="28"/>
++
++#endif
++
++const std::string NS_GOOGLESESSION("http://www.google.com/session");
++const buzz::QName QN_GOOGLESESSION_SESSION(true, NS_GOOGLESESSION, "session");
++const buzz::QName QN_GOOGLESESSION_CANDIDATE(true, NS_GOOGLESESSION, "candidate");
++const buzz::QName QN_GOOGLESESSION_TARGET(true, NS_GOOGLESESSION, "target");
++const buzz::QName QN_GOOGLESESSION_COOKIE(true, NS_GOOGLESESSION, "cookie");
++const buzz::QName QN_GOOGLESESSION_REGARDING(true, NS_GOOGLESESSION, "regarding");
++
++const buzz::QName QN_TYPE(true, buzz::STR_EMPTY, "type");
++const buzz::QName QN_ID(true, buzz::STR_EMPTY, "id");
++const buzz::QName QN_INITIATOR(true, buzz::STR_EMPTY, "initiator");
++const buzz::QName QN_NAME(true, buzz::STR_EMPTY, "name");
++const buzz::QName QN_PORT(true, buzz::STR_EMPTY, "port");
++const buzz::QName QN_NETWORK(true, buzz::STR_EMPTY, "network");
++const buzz::QName QN_GENERATION(true, buzz::STR_EMPTY, "generation");
++const buzz::QName QN_ADDRESS(true, buzz::STR_EMPTY, "address");
++const buzz::QName QN_USERNAME(true, buzz::STR_EMPTY, "username");
++const buzz::QName QN_PASSWORD(true, buzz::STR_EMPTY, "password");
++const buzz::QName QN_PREFERENCE(true, buzz::STR_EMPTY, "preference");
++const buzz::QName QN_PROTOCOL(true, buzz::STR_EMPTY, "protocol");
++const buzz::QName QN_KEY(true, buzz::STR_EMPTY, "key");
++
++class XmlCookie: public SessionMessage::Cookie {
++public:
++  XmlCookie(const buzz::XmlElement* elem)
++    : elem_(new buzz::XmlElement(*elem)) {
++  }
++
++  virtual ~XmlCookie() {
++    delete elem_;
++  }
++
++  const buzz::XmlElement* elem() const { return elem_; }
++
++  virtual Cookie* Copy() {
++    return new XmlCookie(elem_);
++  }
++
++private:
++  buzz::XmlElement* elem_;
++};
++
++SessionClient::SessionClient(SessionManager *session_manager) {
++  session_manager_ = session_manager;
++  session_manager_->SignalSessionCreate.connect(this, &SessionClient::OnSessionCreateSlot);
++  session_manager_->SignalSessionDestroy.connect(this, &SessionClient::OnSessionDestroySlot);
++}
++
++SessionClient::~SessionClient() {
++}
++
++void SessionClient::OnSessionCreateSlot(Session *session, bool received_initiate) {
++  // Does this session belong to this session client?
++  if (session->name() == GetSessionDescriptionName()) {
++    session->SignalOutgoingMessage.connect(this, &SessionClient::OnOutgoingMessage);
++    OnSessionCreate(session, received_initiate);
++  }
++}
++
++void SessionClient::OnSessionDestroySlot(Session *session) {
++  if (session->name() == GetSessionDescriptionName()) {
++    session->SignalOutgoingMessage.disconnect(this);
++    OnSessionDestroy(session);
++  }
++}
++
++bool SessionClient::IsClientStanza(const buzz::XmlElement *stanza) {
++  // Is it a IQ set stanza?
++  if (stanza->Name() != buzz::QN_IQ)
++    return false;
++  if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET)
++    return false;
++
++  // Make sure it has the right child element
++  const buzz::XmlElement* element
++    = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++  if (element == NULL)
++    return false;
++
++  // Is it one of the allowed types?
++  std::string type;
++  if (element->HasAttr(QN_TYPE)) {
++    type = element->Attr(QN_TYPE);
++    if (type != "initiate" && type != "accept" && type != "modify" &&
++        type != "candidates" && type != "reject" && type != "redirect" &&
++        type != "terminate") {
++      return false;
++    }
++  }
++
++  // Does this client own the session description namespace?
++  buzz::QName qn_session_desc(GetSessionDescriptionName(), "description");
++  const buzz::XmlElement* description = element->FirstNamed(qn_session_desc);
++  if (type == "initiate" || type == "accept" || type == "modify") {
++    if (description == NULL)
++      return false;
++  } else {
++    if (description != NULL)
++      return false;
++  }
++
++  // It's good
++  return true;
++}
++
++void SessionClient::OnIncomingStanza(const buzz::XmlElement *stanza) {
++  SessionMessage message;
++  if (!ParseIncomingMessage(stanza, message))
++    return;
++
++  session_manager_->OnIncomingMessage(message);
++}
++
++void SessionClient::OnFailedSend(const buzz::XmlElement *original_stanza,
++                                 const buzz::XmlElement *failure_stanza) {
++  SessionMessage message;
++  if (!ParseIncomingMessage(original_stanza, message))
++    return;
++
++  // Note the from/to represents the *original* stanza and not the from/to
++  // on any return path
++  session_manager_->OnIncomingError(message);
++}
++
++bool SessionClient::ParseIncomingMessage(const buzz::XmlElement *stanza,
++                                         SessionMessage& message) {
++  // Parse stanza into SessionMessage
++  const buzz::XmlElement* element
++    = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++
++  std::string type = element->Attr(QN_TYPE);
++  if (type == "initiate" || type == "accept" || type == "modify") {
++    ParseInitiateAcceptModify(stanza, message);
++  } else if (type == "candidates") {
++    ParseCandidates(stanza, message);
++  } else if (type == "reject" || type == "terminate") {
++    ParseRejectTerminate(stanza, message);
++  } else if (type == "redirect") {
++    ParseRedirect(stanza, message);
++  } else {
++    return false;
++  }
++
++  return true;
++}
++
++void SessionClient::ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message) {
++  if (stanza->HasAttr(buzz::QN_FROM))
++    message.set_from(stanza->Attr(buzz::QN_FROM));
++  if (stanza->HasAttr(buzz::QN_TO))
++    message.set_to(stanza->Attr(buzz::QN_TO));
++
++  const buzz::XmlElement *element
++    = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++  if (element->HasAttr(QN_ID))
++    message.session_id().set_id_str(element->Attr(QN_ID));
++
++  if (element->HasAttr(QN_INITIATOR))
++    message.session_id().set_initiator(element->Attr(QN_INITIATOR));
++
++  std::string type = element->Attr(QN_TYPE);
++  if (type == "initiate") {
++    message.set_type(SessionMessage::TYPE_INITIATE);
++  } else if (type == "accept") {
++    message.set_type(SessionMessage::TYPE_ACCEPT);
++  } else if (type == "modify") {
++    message.set_type(SessionMessage::TYPE_MODIFY);
++  } else if (type == "candidates") {
++    message.set_type(SessionMessage::TYPE_CANDIDATES);
++  } else if (type == "reject") {
++    message.set_type(SessionMessage::TYPE_REJECT);
++  } else if (type == "redirect") {
++    message.set_type(SessionMessage::TYPE_REDIRECT);
++  } else if (type == "terminate") {
++    message.set_type(SessionMessage::TYPE_TERMINATE);
++  } else {
++    assert(false);
++  }
++}
++
++void SessionClient::ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message) {
++  // Pull the standard header pieces out
++  ParseHeader(stanza, message);
++
++  // Parse session description
++  const buzz::XmlElement *session
++    = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++  buzz::QName qn_session_desc(GetSessionDescriptionName(), "description");
++  const buzz::XmlElement* desc_elem = session->FirstNamed(qn_session_desc);
++  const SessionDescription *description = NULL;
++  if (desc_elem)
++    description = CreateSessionDescription(desc_elem);
++  message.set_name(GetSessionDescriptionName());
++  message.set_description(description);
++}
++
++void SessionClient::ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message) {
++  // Pull the standard header pieces out
++  ParseHeader(stanza, message);
++
++  // Parse candidates and session description
++  std::vector<Candidate> candidates;
++  const buzz::XmlElement *element
++    = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++  const buzz::XmlElement *child = element->FirstElement();
++  while (child != NULL) {
++    if (child->Name() == QN_GOOGLESESSION_CANDIDATE) {
++      Candidate candidate;
++      if (ParseCandidate(child, &candidate))
++        candidates.push_back(candidate);
++    }
++    child = child->NextElement();
++  }
++  message.set_name(GetSessionDescriptionName());
++  message.set_candidates(candidates);
++}
++
++void SessionClient::ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message) {
++  // Reject and terminate are very simple
++  ParseHeader(stanza, message);
++}
++
++bool SessionClient::ParseCandidate(const buzz::XmlElement *child,
++                                   Candidate* candidate) {
++  // Check for all of the required attributes.
++  if (!child->HasAttr(QN_NAME) ||
++      !child->HasAttr(QN_ADDRESS) ||
++      !child->HasAttr(QN_PORT) ||
++      !child->HasAttr(QN_USERNAME) ||
++      !child->HasAttr(QN_PREFERENCE) ||
++      !child->HasAttr(QN_PROTOCOL) ||
++      !child->HasAttr(QN_GENERATION)) {
++    LOG(LERROR) << "Candidate missing required attribute";
++    return false;
++  }
++
++  SocketAddress address;
++  address.SetIP(child->Attr(QN_ADDRESS));
++  std::istringstream ist(child->Attr(QN_PORT));
++  int port;
++  ist >> port;
++  address.SetPort(port);
++
++  if (address.IsAny()) {
++    LOG(LERROR) << "Candidate has address 0";
++    return false;
++  }
++
++  // Always disallow addresses that refer to the local host.
++  if (address.IsLocalIP()) {
++    LOG(LERROR) << "Candidate has local IP address";
++    return false;
++  }
++
++  // Disallow all ports below 1024, except for 80 and 443 on public addresses.
++  if (port < 1024) {
++    if ((port != 80) && (port != 443)) {
++      LOG(LERROR) << "Candidate has port below 1024, not 80 or 443";
++      return false;
++    }
++    if (address.IsPrivateIP()) {
++      LOG(LERROR) << "Candidate has port of 80 or 443 with private IP address";
++      return false;
++    }
++  }
++
++  candidate->set_name(child->Attr(QN_NAME));
++  candidate->set_address(address);
++  candidate->set_username(child->Attr(QN_USERNAME));
++  candidate->set_preference_str(child->Attr(QN_PREFERENCE));
++  candidate->set_protocol(child->Attr(QN_PROTOCOL));
++  candidate->set_generation_str(child->Attr(QN_GENERATION));
++
++  // Check that the username is not too long and does not use any bad chars.
++  if (candidate->username().size() > kMaxUsernameSize) {
++    LOG(LERROR) << "Candidate username is too long";
++    return false;
++  }
++  if (!IsBase64Encoded(candidate->username())) {
++    LOG(LERROR) << "Candidate username has non-base64 encoded characters";
++    return false;
++  }
++
++  // Look for the non-required attributes.
++  if (child->HasAttr(QN_PASSWORD))
++    candidate->set_password(child->Attr(QN_PASSWORD));
++  if (child->HasAttr(QN_TYPE))
++    candidate->set_type(child->Attr(QN_TYPE));
++  if (child->HasAttr(QN_NETWORK))
++    candidate->set_network_name(child->Attr(QN_NETWORK));
++
++  return true;
++}
++
++void SessionClient::ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message) {
++  // Pull the standard header pieces out
++  ParseHeader(stanza, message);
++  const buzz::XmlElement *session = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
++
++  // Parse the target and cookie.
++
++  const buzz::XmlElement* target = session->FirstNamed(QN_GOOGLESESSION_TARGET);
++  if (target)
++    message.set_redirect_target(target->Attr(QN_NAME));
++
++  const buzz::XmlElement* cookie = session->FirstNamed(QN_GOOGLESESSION_COOKIE);
++  if (cookie)
++    message.set_redirect_cookie(new XmlCookie(cookie));
++}
++
++void SessionClient::OnOutgoingMessage(Session *session, const SessionMessage &message) {
++  // Translate the message into an XMPP stanza
++
++  buzz::XmlElement *result = NULL;
++  switch (message.type()) {
++  case SessionMessage::TYPE_INITIATE:
++  case SessionMessage::TYPE_ACCEPT:
++  case SessionMessage::TYPE_MODIFY:
++    result = TranslateInitiateAcceptModify(message);
++    break;
++
++  case SessionMessage::TYPE_CANDIDATES:
++    result = TranslateCandidates(message);
++    break;
++
++  case SessionMessage::TYPE_REJECT:
++  case SessionMessage::TYPE_TERMINATE:
++    result = TranslateRejectTerminate(message);
++    break;
++
++  case SessionMessage::TYPE_REDIRECT:
++    result = TranslateRedirect(message);
++    break;
++  }
++
++  // Send the stanza. Note that SessionClient is passing on ownership
++  // of result.
++  if (result != NULL) {
++    SignalSendStanza(this, result);
++  }
++}
++
++buzz::XmlElement *SessionClient::TranslateHeader(const SessionMessage &message) {
++  buzz::XmlElement *result = new buzz::XmlElement(buzz::QN_IQ);
++  result->AddAttr(buzz::QN_TO, message.to());
++  result->AddAttr(buzz::QN_TYPE, buzz::STR_SET);
++  buzz::XmlElement *session = new buzz::XmlElement(QN_GOOGLESESSION_SESSION, true);
++  result->AddElement(session);
++  switch (message.type()) {
++  case SessionMessage::TYPE_INITIATE:
++    session->AddAttr(QN_TYPE, "initiate");
++    break;
++  case SessionMessage::TYPE_ACCEPT:
++    session->AddAttr(QN_TYPE, "accept");
++    break;
++  case SessionMessage::TYPE_MODIFY:
++    session->AddAttr(QN_TYPE, "modify");
++    break;
++  case SessionMessage::TYPE_CANDIDATES:
++    session->AddAttr(QN_TYPE, "candidates");
++    break;
++  case SessionMessage::TYPE_REJECT:
++    session->AddAttr(QN_TYPE, "reject");
++    break;
++  case SessionMessage::TYPE_REDIRECT:
++    session->AddAttr(QN_TYPE, "redirect");
++    break;
++  case SessionMessage::TYPE_TERMINATE:
++    session->AddAttr(QN_TYPE, "terminate");
++    break;
++  }
++  session->AddAttr(QN_ID, message.session_id().id_str());
++  session->AddAttr(QN_INITIATOR, message.session_id().initiator());
++  return result;
++}
++
++buzz::XmlElement *SessionClient::TranslateCandidate(const Candidate &candidate) {
++  buzz::XmlElement *result = new buzz::XmlElement(QN_GOOGLESESSION_CANDIDATE);
++  result->AddAttr(QN_NAME, candidate.name());
++  result->AddAttr(QN_ADDRESS, candidate.address().IPAsString());
++  result->AddAttr(QN_PORT, candidate.address().PortAsString());
++  result->AddAttr(QN_USERNAME, candidate.username());
++  result->AddAttr(QN_PASSWORD, candidate.password());
++  result->AddAttr(QN_PREFERENCE, candidate.preference_str());
++  result->AddAttr(QN_PROTOCOL, candidate.protocol());
++  result->AddAttr(QN_TYPE, candidate.type());
++  result->AddAttr(QN_NETWORK, candidate.network_name());
++  result->AddAttr(QN_GENERATION, candidate.generation_str());
++  return result;
++}
++
++buzz::XmlElement *SessionClient::TranslateInitiateAcceptModify(const SessionMessage &message) {
++  // Header info common to all message types
++  buzz::XmlElement *result = TranslateHeader(message);
++  buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
++
++  // Candidates
++  assert(message.candidates().size() == 0);
++
++  // Session Description
++  buzz::XmlElement* description = TranslateSessionDescription(message.description());
++  assert(description->Name().LocalPart() == "description");
++  assert(description->Name().Namespace() == GetSessionDescriptionName());
++  session->AddElement(description);
++
++  if (message.redirect_cookie() != NULL) {
++    const buzz::XmlElement* cookie =
++      reinterpret_cast<XmlCookie*>(message.redirect_cookie())->elem();
++    for (const buzz::XmlElement* elem = cookie->FirstElement(); elem; elem = elem->NextElement())
++      session->AddElement(new buzz::XmlElement(*elem));
++  }
++
++  return result;
++}
++
++buzz::XmlElement *SessionClient::TranslateCandidates(const SessionMessage &message) {
++  // Header info common to all message types
++  buzz::XmlElement *result = TranslateHeader(message);
++  buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
++
++  // Candidates
++  std::vector<Candidate>::const_iterator it;
++  for (it = message.candidates().begin(); it != message.candidates().end(); it++)
++    session->AddElement(TranslateCandidate(*it));
++
++  return result;
++}
++
++buzz::XmlElement *SessionClient::TranslateRejectTerminate(const SessionMessage &message) {
++  // These messages are simple, and only have a header
++  return TranslateHeader(message);
++}
++
++buzz::XmlElement *SessionClient::TranslateRedirect(const SessionMessage &message) {
++  // Header info common to all message types
++  buzz::XmlElement *result = TranslateHeader(message);
++  buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
++
++  assert(message.candidates().size() == 0);
++  assert(message.description() == NULL);
++
++  assert(message.redirect_target().size() > 0);
++  buzz::XmlElement* target = new buzz::XmlElement(QN_GOOGLESESSION_TARGET);
++  target->AddAttr(QN_NAME, message.redirect_target());
++  session->AddElement(target);
++
++  buzz::XmlElement* cookie = new buzz::XmlElement(QN_GOOGLESESSION_COOKIE);
++  session->AddElement(cookie);
++
++  // If the message does not have a redirect cookie, then this is a redirect
++  // initiated by us.  We will automatically add a regarding cookie.
++  if (message.redirect_cookie() == NULL) {
++    buzz::XmlElement* regarding = new buzz::XmlElement(QN_GOOGLESESSION_REGARDING);
++    regarding->AddAttr(QN_NAME, GetJid().BareJid().Str());
++    cookie->AddElement(regarding);
++  } else {
++    const buzz::XmlElement* cookie_elem = 
++        reinterpret_cast<const XmlCookie*>(message.redirect_cookie())->elem();
++    const buzz::XmlElement* elem;
++    for (elem = cookie_elem->FirstElement(); elem; elem = elem->NextElement())
++      cookie->AddElement(new buzz::XmlElement(*elem));
++  }
++
++  return result;
++}
++
++SessionManager *SessionClient::session_manager() {
++  return session_manager_;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SOCKETMONITOR_H_
++#define _SOCKETMONITOR_H_
++
++#include "talk/base/thread.h"
++#include "talk/base/sigslot.h"
++#include "talk/base/criticalsection.h"
++#include "talk/p2p/base/p2psocket.h"
++#include "talk/p2p/base/port.h"
++#include <vector>
++
++namespace cricket {
++
++struct ConnectionInfo {
++  bool best_connection;
++  bool writable;
++  bool readable;
++  bool timeout;
++  bool new_connection;
++  size_t rtt;
++  size_t sent_total_bytes;
++  size_t sent_bytes_second;
++  size_t recv_total_bytes;
++  size_t recv_bytes_second;
++  Candidate local_candidate;
++  Candidate remote_candidate;
++  double est_quality;
++  void *key;
++};
++
++class SocketMonitor : public MessageHandler, public sigslot::has_slots<> {
++public:
++  SocketMonitor(P2PSocket *socket, Thread *monitor_thread);
++  ~SocketMonitor();
++
++  void Start(int cms);
++  void Stop();
++
++  P2PSocket *socket();
++  Thread *monitor_thread();
++
++  sigslot::signal2<SocketMonitor *, const std::vector<ConnectionInfo> &> SignalUpdate;
++
++protected:
++  void OnMessage(Message *message);
++  void OnConnectionMonitor(P2PSocket *socket);
++  void PollSocket(bool poll);
++
++  std::vector<ConnectionInfo> connection_infos_;
++  P2PSocket *socket_;
++  Thread *monitoring_thread_;
++  CriticalSection crit_;
++  uint32 rate_;
++  bool monitoring_;
++};
++
++}
++
++#endif // _SOCKETMONITOR_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h	(revision 586398)
+@@ -0,0 +1,104 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SESSIONCLIENT_H_
++#define _SESSIONCLIENT_H_
++
++#include "talk/p2p/base/sessiondescription.h"
++#include "talk/p2p/base/sessionmessage.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmpp/jid.h"
++namespace cricket {
++
++// Generic XMPP session client. This class knows how to translate
++// a SessionMessage to and from XMPP stanzas. The SessionDescription
++// is a custom description implemented by the client.
++
++// This class knows how to talk to the session manager, however the
++// session manager doesn't have knowledge of a particular SessionClient.
++
++class SessionClient : public sigslot::has_slots<> {
++public:
++  SessionClient(SessionManager *psm);
++  virtual ~SessionClient();
++
++  // Call this method to determine if a stanza is for this session client
++  bool IsClientStanza(const buzz::XmlElement *stanza);
++
++  // Call this method to deliver a stanza to this session client
++  void OnIncomingStanza(const buzz::XmlElement *stanza);
++
++  // Call this whenever an error is recieved in response to an outgoing
++  // session IQ.  Include the original stanza and any failure stanza.  If
++  // the failure is due to a time out, the failure_stanza should be NULL
++  void OnFailedSend(const buzz::XmlElement* original_stanza,
++                    const buzz::XmlElement* failure_stanza);
++
++  SessionManager *session_manager();
++
++  // Implement this method for stanza sending
++  sigslot::signal2<SessionClient*, const buzz::XmlElement*> SignalSendStanza;
++
++protected:
++  // Override these to know when sessions belonging to this client create/destroy
++
++  virtual void OnSessionCreate(Session * /*session*/, bool /*received_initiate*/) {}
++  virtual void OnSessionDestroy(Session * /*session*/) {}
++
++  // Implement these methods for a custom session description
++  virtual const SessionDescription *CreateSessionDescription(const buzz::XmlElement *element) = 0;
++  virtual buzz::XmlElement *TranslateSessionDescription(const SessionDescription *description) = 0;
++  virtual const std::string &GetSessionDescriptionName() = 0;
++  virtual const buzz::Jid &GetJid() const = 0;
++
++  SessionManager *session_manager_;
++
++private:
++  void OnSessionCreateSlot(Session *session, bool received_initiate);
++  void OnSessionDestroySlot(Session *session);
++  void OnOutgoingMessage(Session *session, const SessionMessage &message);
++  void ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message);
++  bool ParseCandidate(const buzz::XmlElement *child, Candidate* candidate);
++  bool ParseIncomingMessage(const buzz::XmlElement *stanza,
++                            SessionMessage& message);
++  void ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message);
++  void ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message);
++  void ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message);
++  void ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message);
++  buzz::XmlElement *TranslateHeader(const SessionMessage &message);
++  buzz::XmlElement *TranslateCandidate(const Candidate &candidate);
++  buzz::XmlElement *TranslateInitiateAcceptModify(const SessionMessage &message);
++  buzz::XmlElement *TranslateCandidates(const SessionMessage &message);
++  buzz::XmlElement *TranslateRejectTerminate(const SessionMessage &message);
++  buzz::XmlElement *TranslateRedirect(const SessionMessage &message);
++
++};
++
++} // namespace cricket
++
++#endif // _SESSIONCLIENT_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am	(revision 586398)
+@@ -0,0 +1,11 @@
++libcricketp2pclient_la_SOURCES = sessionclient.cc \
++				 basicportallocator.cc \
++				 socketmonitor.cc
++
++noinst_HEADERS =                 basicportallocator.h \
++				 sessionclient.h \
++				 socketmonitor.h 
++
++AM_CPPFLAGS = -I$(srcdir)/../../.. -DLINUX -DPOSIX -DINTERNAL_BUILD
++
++noinst_LTLIBRARIES = libcricketp2pclient.la
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc	(revision 586398)
+@@ -0,0 +1,667 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/host.h"
++#include "talk/base/logging.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/base/port.h"
++#include "talk/p2p/base/udpport.h"
++#include "talk/p2p/base/tcpport.h"
++#include "talk/p2p/base/stunport.h"
++#include "talk/p2p/base/relayport.h"
++#include "talk/p2p/base/helpers.h"
++#include <cassert>
++
++namespace {
++
++const uint32 MSG_CONFIG_START = 1;
++const uint32 MSG_CONFIG_READY = 2;
++const uint32 MSG_ALLOCATE = 3;
++const uint32 MSG_ALLOCATION_PHASE = 4;
++const uint32 MSG_SHAKE = 5;
++
++const uint32 ALLOCATE_DELAY = 250;
++const uint32 ALLOCATION_STEP_DELAY = 1 * 1000;
++
++const int PHASE_UDP = 0;
++const int PHASE_RELAY = 1;
++const int PHASE_TCP = 2;
++const int PHASE_SSLTCP = 3;
++const int kNumPhases = 4;
++
++const float PREF_LOCAL_UDP = 1.0f;
++const float PREF_LOCAL_STUN = 0.9f;
++const float PREF_LOCAL_TCP = 0.8f;
++const float PREF_RELAY = 0.5f;
++
++const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f; // modifiers of the above constants
++const float RELAY_BACKUP_PREF_MODIFIER = -0.2f;
++
++
++// Returns the phase in which a given local candidate (or rather, the port that
++// gave rise to that local candidate) would have been created.
++int LocalCandidateToPhase(const cricket::Candidate& candidate) {
++  cricket::ProtocolType proto;
++  bool result = cricket::StringToProto(candidate.protocol().c_str(), proto);
++  if (result) {
++    if (candidate.type() == cricket::LOCAL_PORT_TYPE) {
++      switch (proto) {
++      case cricket::PROTO_UDP: return PHASE_UDP;
++      case cricket::PROTO_TCP: return PHASE_TCP;
++      default: assert(false);
++      }
++    } else if (candidate.type() == cricket::STUN_PORT_TYPE) {
++      return PHASE_UDP;
++    } else if (candidate.type() == cricket::RELAY_PORT_TYPE) {
++      switch (proto) {
++      case cricket::PROTO_UDP: return PHASE_RELAY;
++      case cricket::PROTO_TCP: return PHASE_TCP;
++      case cricket::PROTO_SSLTCP: return PHASE_SSLTCP;
++      default: assert(false);
++      }
++    } else {
++      assert(false);
++    }
++  } else {
++    assert(false);
++  }
++  return PHASE_UDP; // reached only with assert failure
++}
++
++const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds
++const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds
++
++int ShakeDelay() {
++  int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
++  return SHAKE_MIN_DELAY + cricket::CreateRandomId() % range;
++}
++
++}
++
++namespace cricket {
++
++// Performs the allocation of ports, in a sequenced (timed) manner, for a given
++// network and IP address.
++class AllocationSequence: public MessageHandler {
++public:
++  AllocationSequence(BasicPortAllocatorSession* session,
++                     Network* network,
++                     PortConfiguration* config);
++  ~AllocationSequence();
++
++  // Determines whether this sequence is operating on an equivalent network
++  // setup to the one given.
++  bool IsEquivalent(Network* network);
++
++  // Starts and stops the sequence.  When started, it will continue allocating
++  // new ports on its own timed schedule.
++  void Start();
++  void Stop();
++
++  // MessageHandler:
++  void OnMessage(Message* msg);
++
++  void EnableProtocol(ProtocolType proto);
++  bool ProtocolEnabled(ProtocolType proto) const;
++
++private:
++  BasicPortAllocatorSession* session_;
++  Network* network_;
++  uint32 ip_;
++  PortConfiguration* config_;
++  bool running_;
++  int step_;
++  int step_of_phase_[kNumPhases];
++
++  typedef std::vector<ProtocolType> ProtocolList;
++  ProtocolList protocols_;
++
++  void CreateUDPPorts();
++  void CreateTCPPorts();
++  void CreateStunPorts();
++  void CreateRelayPorts();
++};
++
++
++// BasicPortAllocator
++
++BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager)
++  : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(NULL), relay_address_(NULL) {
++}
++
++BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager, SocketAddress* stun_address, SocketAddress *relay_address)
++  : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(stun_address), relay_address_(relay_address) {
++}
++
++BasicPortAllocator::~BasicPortAllocator() {
++}
++
++int BasicPortAllocator::best_writable_phase() const {
++  // If we are configured with an HTTP proxy, the best bet is to use the relay
++  if ((best_writable_phase_ == -1)
++      && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) {
++    return PHASE_RELAY;
++  }
++  return best_writable_phase_;
++}
++
++PortAllocatorSession *BasicPortAllocator::CreateSession(const std::string &name) {
++  return new BasicPortAllocatorSession(this, name, stun_address_, relay_address_);
++}
++
++void BasicPortAllocator::AddWritablePhase(int phase) {
++  if ((best_writable_phase_ == -1) || (phase < best_writable_phase_))
++    best_writable_phase_ = phase;
++}
++
++// BasicPortAllocatorSession
++
++BasicPortAllocatorSession::BasicPortAllocatorSession(
++    BasicPortAllocator *allocator,
++    const std::string &name)
++  : allocator_(allocator), name_(name), network_thread_(NULL),
++    config_thread_(NULL), allocation_started_(false), running_(false),
++    stun_address_(NULL), relay_address_(NULL) {
++}
++
++BasicPortAllocatorSession::BasicPortAllocatorSession(
++    BasicPortAllocator *allocator,
++    const std::string &name,
++    SocketAddress *stun_address,
++    SocketAddress *relay_address)
++  : allocator_(allocator), name_(name), network_thread_(NULL),
++    config_thread_(NULL), allocation_started_(false), running_(false),
++    stun_address_(stun_address), relay_address_(relay_address) {
++}
++
++BasicPortAllocatorSession::~BasicPortAllocatorSession() {
++  if (config_thread_ != NULL)
++    config_thread_->Clear(this);
++  if (network_thread_ != NULL)
++    network_thread_->Clear(this);
++
++  std::vector<PortData>::iterator it;
++  for (it = ports_.begin(); it != ports_.end(); it++)
++    delete it->port;
++
++  for (uint32 i = 0; i < configs_.size(); ++i)
++    delete configs_[i];
++
++  for (uint32 i = 0; i < sequences_.size(); ++i)
++    delete sequences_[i];
++}
++
++void BasicPortAllocatorSession::GetInitialPorts() {
++  network_thread_ = Thread::Current();
++  if (!config_thread_)
++    config_thread_ = network_thread_;
++
++  config_thread_->Post(this, MSG_CONFIG_START);
++
++  if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHAKER)
++    network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
++}
++
++void BasicPortAllocatorSession::StartGetAllPorts() {
++  assert(Thread::Current() == network_thread_);
++  running_ = true;
++  if (allocation_started_)
++    network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
++  for (uint32 i = 0; i < sequences_.size(); ++i)
++    sequences_[i]->Start();
++  for (size_t i = 0; i < ports_.size(); ++i)
++    ports_[i].port->Start();
++}
++
++void BasicPortAllocatorSession::StopGetAllPorts() {
++  assert(Thread::Current() == network_thread_);
++  running_ = false;
++  network_thread_->Clear(this, MSG_ALLOCATE);
++  for (uint32 i = 0; i < sequences_.size(); ++i)
++    sequences_[i]->Stop();
++}
++
++void BasicPortAllocatorSession::OnMessage(Message *message) {
++  switch (message->message_id) {
++  case MSG_CONFIG_START:
++    assert(Thread::Current() == config_thread_);
++    GetPortConfigurations();
++    break;
++
++  case MSG_CONFIG_READY:
++    assert(Thread::Current() == network_thread_);
++    OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
++    break;
++
++  case MSG_ALLOCATE:
++    assert(Thread::Current() == network_thread_);
++    OnAllocate();
++    break;
++
++  case MSG_SHAKE:
++    assert(Thread::Current() == network_thread_);
++    OnShake();
++    break;
++
++  default:
++    assert(false);
++  }
++}
++
++void BasicPortAllocatorSession::GetPortConfigurations() {
++  PortConfiguration* config = NULL;
++  if (stun_address_ != NULL)
++    config = new PortConfiguration(*stun_address_,
++				   CreateRandomString(16),
++				   CreateRandomString(16),
++				   "");
++  PortConfiguration::PortList ports;
++  if (relay_address_ != NULL) {
++    ports.push_back(ProtocolAddress(*relay_address_, PROTO_UDP));
++    config->AddRelay(ports, RELAY_PRIMARY_PREF_MODIFIER);
++  }
++
++  ConfigReady(config);
++}
++
++void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
++  network_thread_->Post(this, MSG_CONFIG_READY, config);
++}
++
++// Adds a configuration to the list.
++void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
++  if (config)
++    configs_.push_back(config);
++
++  AllocatePorts();
++}
++
++void BasicPortAllocatorSession::AllocatePorts() {
++  assert(Thread::Current() == network_thread_);
++
++  if (allocator_->proxy().type != PROXY_NONE)
++    Port::set_proxy(allocator_->proxy());
++
++  network_thread_->Post(this, MSG_ALLOCATE);
++}
++
++// For each network, see if we have a sequence that covers it already.  If not,
++// create a new sequence to create the appropriate ports.
++void BasicPortAllocatorSession::OnAllocate() {
++  std::vector<Network*> networks;
++  allocator_->network_manager()->GetNetworks(networks);
++
++  for (uint32 i = 0; i < networks.size(); ++i) {
++    if (HasEquivalentSequence(networks[i]))
++      continue;
++
++    PortConfiguration* config = NULL;
++    if (configs_.size() > 0)
++      config = configs_.back();
++
++    AllocationSequence* sequence =
++        new AllocationSequence(this, networks[i], config);
++    if (running_)
++      sequence->Start();
++
++    sequences_.push_back(sequence);
++  }
++
++  allocation_started_ = true;
++  if (running_)
++    network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
++}
++
++bool BasicPortAllocatorSession::HasEquivalentSequence(Network* network) {
++  for (uint32 i = 0; i < sequences_.size(); ++i)
++    if (sequences_[i]->IsEquivalent(network))
++      return true;
++  return false;
++}
++
++void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
++                                                 AllocationSequence * seq,
++                                                 float pref,
++                                                 bool prepare_address) {
++  if (!port)
++    return;
++
++  port->set_name(name_);
++  port->set_preference(pref);
++  port->set_generation(generation());
++  PortData data;
++  data.port = port;
++  data.sequence = seq;
++  data.ready = false;
++  ports_.push_back(data);
++  port->SignalAddressReady.connect(this, &BasicPortAllocatorSession::OnAddressReady);
++  port->SignalConnectionCreated.connect(this, &BasicPortAllocatorSession::OnConnectionCreated);
++  port->SignalDestroyed.connect(this, &BasicPortAllocatorSession::OnPortDestroyed);
++  if (prepare_address)
++    port->PrepareAddress();
++  if (running_)
++    port->Start();
++}
++
++void BasicPortAllocatorSession::OnAddressReady(Port *port) {
++  assert(Thread::Current() == network_thread_);
++  std::vector<PortData>::iterator it = std::find(ports_.begin(), ports_.end(), port);
++  assert(it != ports_.end());
++  assert(!it->ready);
++  it->ready = true;
++  SignalPortReady(this, port);
++
++  // Only accumulate the candidates whose protocol has been enabled
++  std::vector<Candidate> candidates;
++  const std::vector<Candidate>& potentials = port->candidates();
++  for (size_t i=0; i<potentials.size(); ++i) {
++    ProtocolType pvalue;
++    if (!StringToProto(potentials[i].protocol().c_str(), pvalue))
++      continue;
++    if (it->sequence->ProtocolEnabled(pvalue)) {
++      candidates.push_back(potentials[i]);
++    }
++  }
++  if (!candidates.empty()) {
++    SignalCandidatesReady(this, candidates);
++  }
++}
++
++void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto) {
++  std::vector<Candidate> candidates;
++  for (std::vector<PortData>::iterator it = ports_.begin(); it != ports_.end(); ++it) {
++    if (!it->ready || (it->sequence != seq))
++      continue;
++
++    const std::vector<Candidate>& potentials = it->port->candidates();
++    for (size_t i=0; i<potentials.size(); ++i) {
++      ProtocolType pvalue;
++      if (!StringToProto(potentials[i].protocol().c_str(), pvalue))
++        continue;
++      if (pvalue == proto) {
++        candidates.push_back(potentials[i]);
++      }
++    }
++  }
++  if (!candidates.empty()) {
++    SignalCandidatesReady(this, candidates);
++  }
++}
++
++void BasicPortAllocatorSession::OnPortDestroyed(Port* port) {
++  assert(Thread::Current() == network_thread_);
++  std::vector<PortData>::iterator iter =
++      find(ports_.begin(), ports_.end(), port);
++  assert(iter != ports_.end());
++  ports_.erase(iter);
++
++  LOG(INFO) << "Removed port from allocator: "
++            << static_cast<int>(ports_.size()) << " remaining";
++}
++
++void BasicPortAllocatorSession::OnConnectionCreated(Port* port, Connection* conn) {
++  conn->SignalStateChange.connect(this, &BasicPortAllocatorSession::OnConnectionStateChange);
++}
++
++void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) {
++  if (conn->write_state() == Connection::STATE_WRITABLE)
++    allocator_->AddWritablePhase(LocalCandidateToPhase(conn->local_candidate()));
++}
++
++void BasicPortAllocatorSession::OnShake() {
++  LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
++
++  std::vector<Port*> ports;
++  std::vector<Connection*> connections;
++
++  for (size_t i = 0; i < ports_.size(); ++i) {
++    if (ports_[i].ready)
++      ports.push_back(ports_[i].port);
++  }
++
++  for (size_t i = 0; i < ports.size(); ++i) {
++    Port::AddressMap::const_iterator iter;
++    for (iter = ports[i]->connections().begin();
++         iter != ports[i]->connections().end();
++         ++iter) {
++      connections.push_back(iter->second);
++    }
++  }
++
++  LOG(INFO) << ">>>>> Destroying " << (int)ports.size() << " ports and "
++            << (int)connections.size() << " connections";
++
++  for (size_t i = 0; i < connections.size(); ++i)
++    connections[i]->Destroy();
++
++  if (running_ || (ports.size() > 0) || (connections.size() > 0))
++    network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
++}
++
++// AllocationSequence
++
++AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
++                                       Network* network,
++                                       PortConfiguration* config)
++  : session_(session), network_(network), ip_(network->ip()), config_(config),
++    running_(false), step_(0) {
++
++  // All of the phases up until the best-writable phase so far run in step 0.
++  // The other phases follow sequentially in the steps after that.  If there is
++  // no best-writable so far, then only phase 0 occurs in step 0.
++  int last_phase_in_step_zero =
++      _max(0, session->allocator()->best_writable_phase());
++  for (int phase = 0; phase < kNumPhases; ++phase)
++    step_of_phase_[phase] = _max(0, phase - last_phase_in_step_zero);
++
++  // Immediately perform phase 0.
++  OnMessage(NULL);
++}
++
++AllocationSequence::~AllocationSequence() {
++  session_->network_thread()->Clear(this);
++}
++
++bool AllocationSequence::IsEquivalent(Network* network) {
++  return (network == network_) && (ip_ == network->ip());
++}
++
++void AllocationSequence::Start() {
++  running_ = true;
++  session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
++                                          this,
++                                          MSG_ALLOCATION_PHASE);
++}
++
++void AllocationSequence::Stop() {
++  running_ = false;
++  session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
++}
++
++void AllocationSequence::OnMessage(Message* msg) {
++  assert(Thread::Current() == session_->network_thread());
++  if (msg)
++    assert(msg->message_id == MSG_ALLOCATION_PHASE);
++
++  // Perform all of the phases in the current step.
++  for (int phase = 0; phase < kNumPhases; phase++) {
++    if (step_of_phase_[phase] != step_)
++      continue;
++
++    switch (phase) {
++    case PHASE_UDP:
++      LOG(INFO) << "Phase=UDP Step=" << step_;
++      CreateUDPPorts();
++      CreateStunPorts();
++      EnableProtocol(PROTO_UDP);
++      break;
++
++    case PHASE_RELAY:
++      LOG(INFO) << "Phase=RELAY Step=" << step_;
++      CreateRelayPorts();
++      break;
++
++    case PHASE_TCP:
++      LOG(INFO) << "Phase=TCP Step=" << step_;
++      CreateTCPPorts();
++      EnableProtocol(PROTO_TCP);
++      break;
++
++    case PHASE_SSLTCP:
++      LOG(INFO) << "Phase=SSLTCP Step=" << step_;
++      EnableProtocol(PROTO_SSLTCP);
++      break;
++
++    default:
++      // Nothing else we can do.
++      return;
++    }
++  }
++
++  // TODO: use different delays for each stage
++  step_ += 1;
++  if (running_) {
++    session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
++                                            this,
++                                            MSG_ALLOCATION_PHASE);
++  }
++}
++
++void AllocationSequence::EnableProtocol(ProtocolType proto) {
++  if (!ProtocolEnabled(proto)) {
++    protocols_.push_back(proto);
++    session_->OnProtocolEnabled(this, proto);
++  }
++}
++
++bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
++  for (ProtocolList::const_iterator it = protocols_.begin(); it != protocols_.end(); ++it) {
++    if (*it == proto)
++      return true;
++  }
++  return false;
++}
++
++void AllocationSequence::CreateUDPPorts() {
++  if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_UDP)
++    return;
++
++  Port* port = new UDPPort(session_->network_thread(), NULL, network_,
++                           SocketAddress(ip_, 0));
++  session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP);
++}
++
++void AllocationSequence::CreateTCPPorts() {
++  if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_TCP)
++    return;
++
++  Port* port = new TCPPort(session_->network_thread(), NULL, network_,
++                           SocketAddress(ip_, 0));
++  session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP); 
++}
++
++void AllocationSequence::CreateStunPorts() {
++  if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_STUN)
++    return;
++
++  if (!config_ || config_->stun_address.IsAny())
++    return;
++
++  Port* port = new StunPort(session_->network_thread(), NULL, network_,
++                            SocketAddress(ip_, 0), config_->stun_address);
++  session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN); 
++}
++
++void AllocationSequence::CreateRelayPorts() {
++  if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY)
++    return;
++
++  if (!config_)
++    return;
++
++  PortConfiguration::RelayList::const_iterator relay;
++  for (relay = config_->relays.begin();
++       relay != config_->relays.end();
++       ++relay) {
++
++    RelayPort *port = new RelayPort(session_->network_thread(), NULL, network_,
++                                    SocketAddress(ip_, 0),
++                                    config_->username, config_->password,
++                                    config_->magic_cookie);
++    // Note: We must add the allocated port before we add addresses because
++    //       the latter will create candidates that need name and preference
++    //       settings.  However, we also can't prepare the address (normally
++    //       done by AddAllocatedPort) until we have these addresses.  So we
++    //       wait to do that until below.
++    session_->AddAllocatedPort(port, this, PREF_RELAY + relay->pref_modifier, false);
++
++    // Add the addresses of this protocol.
++    PortConfiguration::PortList::const_iterator relay_port;
++    for (relay_port = relay->ports.begin();
++          relay_port != relay->ports.end();
++          ++relay_port) {
++      port->AddServerAddress(*relay_port);
++      port->AddExternalAddress(*relay_port);
++    }
++
++    // Start fetching an address for this port.
++    port->PrepareAddress();
++  }
++}
++
++// PortConfiguration
++
++PortConfiguration::PortConfiguration(const SocketAddress& sa,
++                                     const std::string& un,
++                                     const std::string& pw,
++                                     const std::string& mc)
++  : stun_address(sa), username(un), password(pw), magic_cookie(mc) {
++}
++
++void PortConfiguration::AddRelay(const PortList& ports, float pref_modifier) {
++  RelayServer relay;
++  relay.ports = ports;
++  relay.pref_modifier = pref_modifier;
++  relays.push_back(relay);
++}
++
++bool PortConfiguration::SupportsProtocol(
++    const PortConfiguration::RelayServer& relay, ProtocolType type) {
++  PortConfiguration::PortList::const_iterator relay_port;
++  for (relay_port = relay.ports.begin();
++        relay_port != relay.ports.end();
++        ++relay_port) {
++    if (relay_port->proto == type)
++      return true;
++  }
++  return false;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h	(revision 586398)
+@@ -0,0 +1,172 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _BASICPORTALLOCATOR_H_
++#define _BASICPORTALLOCATOR_H_
++
++#include "talk/base/thread.h"
++#include "talk/base/messagequeue.h"
++#include "talk/base/network.h"
++#include "talk/p2p/base/portallocator.h"
++#include <string>
++#include <vector>
++
++namespace cricket {
++
++class BasicPortAllocator: public PortAllocator {
++public:
++  BasicPortAllocator(NetworkManager* network_manager);
++  BasicPortAllocator(NetworkManager* network_manager, SocketAddress *stun_server, SocketAddress *relay_server);
++  virtual ~BasicPortAllocator();
++
++  NetworkManager* network_manager() { return network_manager_; }
++
++  // Returns the best (highest preference) phase that has produced a port that
++  // produced a writable connection.  If no writable connections have been
++  // produced, this returns -1.
++  int best_writable_phase() const;
++
++  virtual PortAllocatorSession *CreateSession(const std::string &name);
++
++  // Called whenever a connection becomes writable with the argument being the
++  // phase that the corresponding port was created in.
++  void AddWritablePhase(int phase);
++
++private:
++  NetworkManager* network_manager_;
++  SocketAddress* stun_address_;
++  SocketAddress* relay_address_;
++  int best_writable_phase_;
++};
++
++struct PortConfiguration;
++class AllocationSequence;
++
++class BasicPortAllocatorSession: public PortAllocatorSession, public MessageHandler {
++public:
++  BasicPortAllocatorSession(BasicPortAllocator *allocator,
++			    const std::string &name);
++  BasicPortAllocatorSession(BasicPortAllocator *allocator,
++                            const std::string &name,
++			    SocketAddress *stun_address,
++			    SocketAddress *relay_address);
++  ~BasicPortAllocatorSession();
++
++  BasicPortAllocator* allocator() { return allocator_; }
++  const std::string& name() const { return name_; }
++  Thread* network_thread() { return network_thread_; }
++
++  Thread* config_thread() { return config_thread_; }
++  void set_config_thread(Thread* thread) { config_thread_ = thread; }
++
++  virtual void GetInitialPorts();
++  virtual void StartGetAllPorts();
++  virtual void StopGetAllPorts();
++  virtual bool IsGettingAllPorts() { return running_; }
++
++protected:
++  // Starts the process of getting the port configurations.
++  virtual void GetPortConfigurations();
++
++  // Adds a port configuration that is now ready.  Once we have one for each
++  // network (or a timeout occurs), we will start allocating ports.
++  void ConfigReady(PortConfiguration* config);
++
++  // MessageHandler.  Can be overriden if message IDs do not conflict.
++  virtual void OnMessage(Message *message);
++
++private:
++  void OnConfigReady(PortConfiguration* config);
++  void OnConfigTimeout();
++  void AllocatePorts();
++  void OnAllocate();
++  bool HasEquivalentSequence(Network* network);
++  void AddAllocatedPort(Port* port, AllocationSequence * seq, float pref, bool prepare_address = true);
++  void OnAddressReady(Port *port);
++  void OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto);
++  void OnPortDestroyed(Port* port);
++  void OnConnectionCreated(Port* port, Connection* conn);
++  void OnConnectionStateChange(Connection* conn);
++  void OnShake();
++
++  BasicPortAllocator *allocator_;
++  std::string name_;
++  Thread* network_thread_;
++  Thread* config_thread_;
++  bool configuration_done_;
++  bool allocation_started_;
++  bool running_; // set when StartGetAllPorts is called
++  std::vector<PortConfiguration*> configs_;
++  std::vector<AllocationSequence*> sequences_;
++  SocketAddress *stun_address_;
++  SocketAddress *relay_address_;
++
++  struct PortData {
++    Port * port;
++    AllocationSequence * sequence;
++    bool ready;
++
++    bool operator==(Port * rhs) const { return (port == rhs); }
++  };
++  std::vector<PortData> ports_;
++
++  friend class AllocationSequence;
++};
++
++// Records configuration information useful in creating ports.
++struct PortConfiguration: public MessageData {
++  SocketAddress stun_address;
++  std::string username;
++  std::string password;
++  std::string magic_cookie;
++
++  typedef std::vector<ProtocolAddress> PortList;
++  struct RelayServer {
++    PortList ports;
++    float pref_modifier; // added to the protocol modifier to get the
++                         // preference for this particular server
++  };
++
++  typedef std::vector<RelayServer> RelayList;
++  RelayList relays;
++
++  PortConfiguration(const SocketAddress& stun_address,
++                    const std::string& username,
++                    const std::string& password,
++                    const std::string& magic_cookie);
++
++  // Adds another relay server, with the given ports and modifier, to the list.
++  void AddRelay(const PortList& ports, float pref_modifier);
++
++  // Determines whether the given relay server supports the given protocol.
++  static bool SupportsProtocol(const PortConfiguration::RelayServer& relay,
++                               ProtocolType type);
++};
++
++} // namespace cricket
++
++#endif // _BASICPORTALLOCATOR_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h	(revision 586398)
+@@ -0,0 +1,111 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CRICKET_PHONE_SESSIONSENDTASK_H_
++#define _CRICKET_PHONE_SESSIONSENDTASK_H_
++
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmpptask.h"
++#include "talk/p2p/client/sessionclient.h"
++
++namespace cricket {
++
++// The job of this task is to send an IQ stanza out (after stamping it with
++// an ID attribute) and then wait for a response.  If not response happens
++// within 5 seconds, it will signal failure on a SessionClient.  If an error
++// happens it will also signal failure.  If, however, the send succeeds this
++// task will quietly go away.
++
++// It is safe for this to hold on to the session client.  In the case where
++// the xmpp client goes away, this task will automatically be aborted.  The
++// session_client is guaranteed to outlive the xmpp session.
++class SessionSendTask : public buzz::XmppTask {
++public:
++  SessionSendTask(Task *parent, SessionClient *session_client)
++    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
++      session_client_(session_client),
++      timed_out_(false) {
++  }
++
++  void Send(const buzz::XmlElement* stanza) {
++    assert(stanza_.get() == NULL);
++    stanza_.reset(new buzz::XmlElement(*stanza));
++    stanza_->SetAttr(buzz::QN_ID, task_id());
++  }
++
++protected:
++  // This gets called by the task runner every 500 msec
++  virtual void Poll() {
++    if (ElapsedTime() > (15 * 1000 * 10000)) {  // 15 secs
++      timed_out_ = true;
++      Wake();
++    }
++  }
++
++  virtual int ProcessStart() {
++    SendStanza(stanza_.get());
++    return STATE_RESPONSE;
++  }
++
++  virtual int ProcessResponse() {
++    if (timed_out_) {
++      session_client_->OnFailedSend(stanza_.get(), NULL);
++      return STATE_DONE;
++    }
++
++    const buzz::XmlElement* next = NextStanza();
++    if (next == NULL)
++      return STATE_BLOCKED;
++
++    if (next->Attr(buzz::QN_TYPE) == "result") {
++      return STATE_DONE;
++    } else {
++      session_client_->OnFailedSend(stanza_.get(), next);
++      return STATE_DONE;
++    }
++  }
++
++  virtual bool HandleStanza(const buzz::XmlElement *stanza) {
++    if (!MatchResponseIq(stanza, buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id()))
++      return false;
++    if (stanza->Attr(buzz::QN_TYPE) == "result" ||
++        stanza->Attr(buzz::QN_TYPE) == "error") {
++      QueueStanza(stanza);
++      return true;
++    }
++    return false;
++  }
++
++private:
++  SessionClient *session_client_;
++  buzz::scoped_ptr<buzz::XmlElement> stanza_;
++  bool timed_out_;
++};
++
++}
++
++#endif // _CRICKET_PHONE_SESSIONSENDTASK_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am	(revision 586398)
+@@ -0,0 +1,3 @@
++noinst_HEADERS = receiver.h sessionsendtask.h 
++SUBDIRS = phone
++				    
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc	(revision 586398)
+@@ -0,0 +1,331 @@
++#include <portaudio.h>
++#include <ortp/ortp.h>
++#include <speex.h>
++
++// Socket stuff
++#ifndef _WIN32
++#ifdef INET6
++#include <netdb.h>
++#endif
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <fcntl.h>
++#else
++#include <winsock32.h>
++#endif
++
++#include "talk/session/phone/mediaengine.h"
++#include "talk/session/phone/portaudiomediaengine.h"
++
++// Engine settings
++#define ENGINE_BUFFER_SIZE 2048
++
++// PortAudio settings
++#define FRAMES_PER_BUFFER 256
++#define SAMPLE_RATE 1
++
++// Speex settings
++//#define SPEEX_QUALITY 8
++
++// ORTP settings
++#define MAX_RTP_SIZE 1500 // From mediastreamer
++
++
++// -----------------------------------------------------------------------------
++
++static int portAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *channel_p )
++{
++	PortAudioMediaChannel* channel = (PortAudioMediaChannel*) channel_p;
++	channel->readOutput((float*) outputBuffer, framesPerBuffer);
++	channel->writeInput((float*) inputBuffer, framesPerBuffer);
++	return 0;
++}
++
++// -----------------------------------------------------------------------------
++
++PortAudioMediaChannel::PortAudioMediaChannel() : mute_(false), play_(false), stream_(NULL), out_buffer_(NULL), in_buffer_(NULL), speex_frame_(NULL)
++{
++	// Initialize buffers
++	out_buffer_ = new float[ENGINE_BUFFER_SIZE];
++	out_buffer_read_ = out_buffer_write_ = (float*) out_buffer_;
++	out_buffer_end_ = (float*) out_buffer_ + ENGINE_BUFFER_SIZE;
++	in_buffer_ = new float[ENGINE_BUFFER_SIZE];
++	in_buffer_read_ = in_buffer_write_ = (float*) in_buffer_;
++	in_buffer_end_ = (float*) in_buffer_ + ENGINE_BUFFER_SIZE;
++
++	// Initialize PortAudio
++	int err = Pa_OpenDefaultStream(&stream_, 1, 1, paFloat32, SAMPLE_RATE, FRAMES_PER_BUFFER, 0, portAudioCallback, this );
++	if (err != paNoError) 
++		fprintf(stderr, "Error creating a PortAudio stream: %s\n", Pa_GetErrorText(err));
++
++	// Initialize Speex
++	speex_bits_init(&speex_bits_);
++	speex_enc_state_ = speex_encoder_init(&speex_nb_mode);
++	speex_dec_state_ = speex_decoder_init(&speex_nb_mode);
++	speex_decoder_ctl(speex_dec_state_, SPEEX_GET_FRAME_SIZE, &speex_frame_size_);
++	speex_frame_ = new float[speex_frame_size_];
++	
++	// int quality = SPEEX_QUALITY;
++	// speex_encoder_ctl(state, SPEEX_SET_QUALITY, &quality);
++
++	// Initialize ORTP socket
++	struct sockaddr_in sockaddr;
++	sockaddr.sin_family = AF_INET;
++	sockaddr.sin_addr.s_addr = INADDR_ANY;
++	sockaddr.sin_port = htons(3000);
++	rtp_socket_ = socket(PF_INET, SOCK_DGRAM, 0);
++	fcntl(rtp_socket_, F_SETFL, 0, O_NONBLOCK);
++	bind (rtp_socket_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
++
++	// Initialize ORTP Session
++	rtp_session_ = rtp_session_new(RTP_SESSION_SENDRECV);
++	rtp_session_max_buf_size_set(rtp_session_, MAX_RTP_SIZE);
++	rtp_session_set_profile(rtp_session_, &av_profile);
++	rtp_session_set_local_addr(rtp_session_, "127.0.0.1", 2000);
++	rtp_session_set_remote_addr(rtp_session_, "127.0.0.1", 3000);
++	rtp_session_set_scheduling_mode(rtp_session_, 0);
++	rtp_session_set_blocking_mode(rtp_session_, 0);
++	rtp_session_set_payload_type(rtp_session_, 110);
++	rtp_session_set_jitter_compensation(rtp_session_, 250);
++	rtp_session_enable_adaptive_jitter_compensation(rtp_session_, TRUE);
++	rtp_timestamp_ = 0;
++	//rtp_session_signal_connect(rtp_session_, "telephone-event", (RtpCallback) ortpTelephoneCallback,this);
++}
++
++PortAudioMediaChannel::~PortAudioMediaChannel()
++{
++	if (stream_) {
++		Pa_CloseStream(stream_);
++	}
++
++	// Clean up other allocated pointers
++
++	close(rtp_socket_);
++}
++
++void PortAudioMediaChannel::SetCodec(const char *codec)
++{
++	if (strcmp(codec, "speex"))
++		printf("Unsupported codec: %s\n", codec);
++}
++
++void PortAudioMediaChannel::OnPacketReceived(const void *data, int len)
++{
++	struct sockaddr_in sockaddr;
++	sockaddr.sin_family = AF_INET;
++	struct hostent *host = gethostbyname("localhost");
++	memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
++	sockaddr.sin_port = htons(2000);
++
++	char buf[2048];
++	memcpy(buf, data, len);
++
++	// Pass packet on to ORTP
++	if (play_) {
++		sendto(rtp_socket_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
++	}
++}
++
++void PortAudioMediaChannel::SetPlayout(bool playout)
++{
++	if (!stream_) 
++		return;
++
++	if (play_ && !playout) {
++		int err = Pa_StopStream(stream_);
++		if (err != paNoError) {
++			fprintf(stderr, "Error stopping PortAudio stream: %s\n", Pa_GetErrorText(err));
++			return;
++		}
++		play_ = false;
++	}
++	else if (!play_ && playout) {
++		int err = Pa_StartStream(stream_);
++		if (err != paNoError) {
++			fprintf(stderr, "Error starting PortAudio stream: %s\n", Pa_GetErrorText(err));
++			return;
++		}
++		play_ = true;
++	}
++}
++
++void PortAudioMediaChannel::SetSend(bool send)
++{
++	mute_ = !send;
++}
++
++
++float PortAudioMediaChannel::GetCurrentQuality()
++{
++	return 0;
++}
++
++int PortAudioMediaChannel::GetOutputLevel()
++{
++	return 0;
++}
++
++void PortAudioMediaChannel::readOutput(float* buf, int len)
++{
++	//readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
++
++	// Receive a packet (if there is one)
++	mblk_t *mp;
++	mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
++	while (mp != NULL) {
++		gint in_len = mp->b_cont->b_wptr-mp->b_cont->b_rptr;
++
++		// Decode speex stream
++		speex_bits_read_from(&speex_bits_,mp->b_cont->b_rptr, in_len);
++		speex_decode(speex_dec_state_, &speex_bits_, speex_frame_);
++		writeBuffer(out_buffer_, out_buffer_read_, &out_buffer_write_, out_buffer_end_, speex_frame_, speex_frame_size_);
++		rtp_timestamp_++;
++		mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
++	}
++
++	// Read output
++	readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
++}
++
++void PortAudioMediaChannel::writeInput(float* buf, int len)
++{
++	//writeBuffer(in_buffer_, in_buffer_read_, &in_buffer_write_, in_buffer_end_, buf, len);
++}
++	
++
++void PortAudioMediaChannel::readBuffer(float* buffer, float** buffer_read_p, float*buffer_write, float* buffer_end, float* target_buffer, int target_len)
++{
++	float *end, *tmp, *buffer_read = *buffer_read_p;
++	int remaining;
++	
++	// First phase
++	tmp = buffer_read + target_len;
++	if (buffer_write < buffer_read && tmp > buffer_end) {
++		end = buffer_end;
++		remaining = tmp - buffer_end;
++	}
++	else {
++		end = (tmp > buffer_write ? buffer_write : tmp);
++		remaining = 0;
++	}
++
++	while (buffer_read < end) {
++		*target_buffer++ = *buffer_read++;
++	}
++
++	// Second phase
++	if (remaining > 0) {
++		buffer_read = buffer;
++		tmp = buffer_read + remaining;
++		end = (tmp > buffer_write ? buffer_write : tmp);
++		while (buffer_read < end) {
++			*target_buffer++ = *buffer_read++;
++		}
++	}
++
++	// Finish up
++	*buffer_read_p = buffer_read;
++}
++
++void PortAudioMediaChannel::writeBuffer(float* buffer, float* buffer_read, float**buffer_write_p, float* buffer_end, float* source_buffer, int source_len)
++{
++	float *end, *tmp, *buffer_write = *buffer_write_p;
++	int remaining;
++
++	// First phase
++	tmp = buffer_write + source_len;
++	if (buffer_write > buffer_read) {
++		if (tmp > buffer_end) {
++			end = buffer_end;
++			remaining = tmp - buffer_end;
++		}
++		else {
++			end = tmp;
++			remaining = 0;
++		}
++	}
++	else {
++		if (tmp > buffer_read) {
++			printf("Warning: Dropping frame(s)\n");
++			end = buffer_read;
++			remaining = 0;
++		}
++		else {
++			end = tmp;
++			remaining = 0;
++		}
++	}
++	
++	while (buffer_write < end) {
++		*buffer_write++ = *source_buffer++;
++	}
++
++	// Second phase
++	if (remaining > 0) {
++		buffer_write = buffer;
++		tmp = buffer_write + remaining;
++		if (tmp > buffer_read) {
++			printf("Warning: Dropping frame(s)\n");
++			end = buffer_read;
++		}
++		else {
++			end = tmp;
++		}
++		while (buffer_write < end) {
++			*buffer_write++ = *source_buffer++;
++		}
++	}
++
++	// Finish up
++	*buffer_write_p = buffer_write;
++}
++
++// -----------------------------------------------------------------------------
++
++PortAudioMediaEngine::PortAudioMediaEngine()
++{
++}
++
++PortAudioMediaEngine::~PortAudioMediaEngine()
++{
++	Pa_Terminate();
++}
++
++bool PortAudioMediaEngine::Init()
++{
++	ortp_init();
++
++	int err = Pa_Initialize();
++	if (err != paNoError) {
++		fprintf(stderr,"Error initializing PortAudio: %s\n",Pa_GetErrorText(err));
++		return false;
++	}
++
++	// Speex
++	rtp_profile_set_payload(&av_profile, 110, &speex_wb);
++	codecs_.push_back(Codec(110, "speex", 8));
++	
++	return true;
++}
++
++void PortAudioMediaEngine::Terminate()
++{
++}
++
++
++cricket::MediaChannel* PortAudioMediaEngine::CreateChannel()
++{
++	return new PortAudioMediaChannel();
++}
++
++int PortAudioMediaEngine::SetAudioOptions(int options)
++{
++}
++
++int PortAudioMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device)
++{
++}
++
++int PortAudioMediaEngine::GetInputLevel()
++{
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc	(revision 586398)
+@@ -0,0 +1,331 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/session/phone/voicechannel.h"
++#include "talk/session/phone/channelmanager.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/base/logging.h"
++#include <cassert>
++#undef SetPort
++
++namespace {
++
++// Delay before quality estimate is meaningful.
++uint32 kQualityDelay = 5000; // in ms
++
++}
++
++namespace cricket {
++
++VoiceChannel::VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel) {
++  channel_manager_ = manager;
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  channel_ = channel;
++  session_ = session;
++  socket_monitor_ = NULL;
++  audio_monitor_ = NULL;
++  socket_ = session_->CreateSocket("rtp");
++  socket_->SignalState.connect(this, &VoiceChannel::OnSocketState);
++  socket_->SignalReadPacket.connect(this, &VoiceChannel::OnSocketRead);
++  channel->SetInterface(this);
++  enabled_ = false;
++  paused_ = false;
++  socket_writable_ = false;
++  muted_ = false;
++  LOG(INFO) << "Created voice channel";
++  start_time_ = 0xFFFFFFFF - kQualityDelay;
++
++  session->SignalState.connect(this, &VoiceChannel::OnSessionState);
++  OnSessionState(session, session->state());
++}
++
++VoiceChannel::~VoiceChannel() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  enabled_ = false;
++  ChangeState();
++  delete socket_monitor_;
++  delete audio_monitor_;
++  Thread::Current()->Clear(this);
++  if (socket_ != NULL)
++    session_->DestroySocket(socket_);
++  LOG(INFO) << "Destroyed voice channel";
++}
++
++void VoiceChannel::OnMessage(Message *pmsg) {
++  switch (pmsg->message_id) {
++  case MSG_ENABLE:
++    EnableMedia_w();
++    break;
++
++  case MSG_DISABLE:
++    DisableMedia_w();
++    break;
++
++  case MSG_MUTE:
++    MuteMedia_w();
++    break;
++
++  case MSG_UNMUTE:
++    UnmuteMedia_w();
++    break;
++
++  case MSG_SETSENDCODEC:
++    SetSendCodec_w();
++    break;
++  }
++}
++
++void VoiceChannel::Enable(bool enable) {
++  // Can be called from thread other than worker thread
++  channel_manager_->worker_thread()->Post(this, enable ? MSG_ENABLE : MSG_DISABLE);
++}
++
++void VoiceChannel::Mute(bool mute) {
++  // Can be called from thread other than worker thread
++  channel_manager_->worker_thread()->Post(this, mute ? MSG_MUTE : MSG_UNMUTE);
++}
++
++MediaChannel * VoiceChannel::channel() {
++  return channel_;
++}
++
++void VoiceChannel::OnSessionState(Session* session, Session::State state) {
++  if ((state == Session::STATE_RECEIVEDACCEPT) ||
++      (state == Session::STATE_RECEIVEDINITIATE)) {
++    channel_manager_->worker_thread()->Post(this, MSG_SETSENDCODEC);
++  }
++}
++
++void VoiceChannel::SetSendCodec_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++
++  const PhoneSessionDescription* desc =
++      static_cast<const PhoneSessionDescription*>(session()->remote_description());
++
++  const char *codec = NULL;
++
++  if (desc->codecs().size() > 0)
++   PhoneSessionClient::FindMediaCodec(channel_manager_->media_engine(), desc, &codec);
++
++  // The other client should have returned one of the codecs that we offered.
++  // If they could not, they should have rejected the session.  So, if we get
++  // into this state, we're dealing with a bad client, so we may as well just
++  // pick the mostt common format there is: payload type zero.
++  if (codec == NULL)
++    codec = "PCMU";
++
++  channel_->SetCodec(codec);
++}
++
++void VoiceChannel::OnSocketState(P2PSocket *socket, P2PSocket::State state) {
++  switch (state) {
++  case P2PSocket::STATE_WRITABLE:
++    SocketWritable_w();
++    break;
++
++  default:
++    SocketNotWritable_w();
++    break;
++  }
++}
++
++void VoiceChannel::OnSocketRead(P2PSocket *socket, const char *data, size_t len) {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  // OnSocketRead gets called from P2PSocket; now pass data to MediaEngine
++  channel_->OnPacketReceived(data, (int)len);
++}
++
++void VoiceChannel::SendPacket(const void *data, size_t len) {
++  // SendPacket gets called from MediaEngine; send to socket
++  // MediaEngine will call us on a random thread.  The Send operation on the socket is
++  // special in that it can handle this.
++  socket_->Send(static_cast<const char *>(data), len);
++}
++
++void VoiceChannel::ChangeState() {
++  if (paused_ || !enabled_ || !socket_writable_) {
++    channel_->SetPlayout(false);
++    channel_->SetSend(false);
++  } else {
++    if (muted_) {
++      channel_->SetSend(false);
++      channel_->SetPlayout(true);
++    } else {
++      channel_->SetSend(true);
++      channel_->SetPlayout(true);
++    }
++  }
++}
++
++void VoiceChannel::PauseMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  assert(!paused_);
++
++  LOG(INFO) << "Voice channel paused";
++  paused_ = true;
++  ChangeState();
++}
++
++void VoiceChannel::UnpauseMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  assert(paused_);
++
++  LOG(INFO) << "Voice channel unpaused";
++  paused_ = false;
++  ChangeState();
++}
++
++void VoiceChannel::EnableMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (enabled_)
++    return;
++
++  LOG(INFO) << "Voice channel enabled";
++  enabled_ = true;
++  start_time_ = Time();
++  ChangeState();
++}
++
++void VoiceChannel::DisableMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (!enabled_)
++    return;
++
++  LOG(INFO) << "Voice channel disabled";
++  enabled_ = false;
++  ChangeState();
++}
++
++void VoiceChannel::MuteMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (muted_)
++    return;
++
++  LOG(INFO) << "Voice channel muted";
++  muted_ = true;
++  ChangeState();
++}
++
++void VoiceChannel::UnmuteMedia_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (!muted_)
++    return;
++
++  LOG(INFO) << "Voice channel unmuted";
++  muted_ = false;
++  ChangeState();
++}
++
++void VoiceChannel::SocketWritable_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (socket_writable_)
++    return;
++
++  LOG(INFO) << "Voice channel socket writable";
++  socket_writable_ = true;
++  ChangeState();
++}
++
++void VoiceChannel::SocketNotWritable_w() {
++  assert(channel_manager_->worker_thread() == Thread::Current());
++  if (!socket_writable_)
++    return;
++
++  LOG(INFO) << "Voice channel socket not writable";
++  socket_writable_ = false;
++  ChangeState();
++}
++
++void VoiceChannel::StartConnectionMonitor(int cms) {
++  delete socket_monitor_;
++  socket_monitor_ = new SocketMonitor(socket_, Thread::Current());
++  socket_monitor_
++    ->SignalUpdate.connect(this, &VoiceChannel::OnConnectionMonitorUpdate);
++  socket_monitor_->Start(cms);
++}
++
++void VoiceChannel::StopConnectionMonitor() {
++  if (socket_monitor_ != NULL) {
++    socket_monitor_->Stop();
++    socket_monitor_->SignalUpdate.disconnect(this);
++    delete socket_monitor_;
++    socket_monitor_ = NULL;
++  }
++}
++
++void VoiceChannel::OnConnectionMonitorUpdate(SocketMonitor *monitor,
++                      const std::vector<ConnectionInfo> &infos) {
++  SignalConnectionMonitor(this, infos);
++}
++
++void VoiceChannel::StartAudioMonitor(int cms) {
++  delete audio_monitor_;
++  audio_monitor_ = new AudioMonitor(this, Thread::Current());
++  audio_monitor_
++    ->SignalUpdate.connect(this, &VoiceChannel::OnAudioMonitorUpdate);
++  audio_monitor_->Start(cms);
++}
++
++void VoiceChannel::StopAudioMonitor() {
++  if (audio_monitor_ != NULL) {
++    audio_monitor_ ->Stop();
++    audio_monitor_ ->SignalUpdate.disconnect(this);
++    delete audio_monitor_ ;
++    audio_monitor_  = NULL;
++  }
++}
++
++void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor *monitor,
++                                        const AudioInfo& info) {
++  SignalAudioMonitor(this, info);
++}
++
++Session *VoiceChannel::session() {
++  return session_;
++}
++
++bool VoiceChannel::HasQuality() {
++  return Time() >= start_time_ + kQualityDelay;
++}
++
++float VoiceChannel::GetCurrentQuality() {
++  return channel_->GetCurrentQuality();
++}
++
++int VoiceChannel::GetInputLevel_w() {
++  return channel_manager_->media_engine()->GetInputLevel();
++}
++
++int VoiceChannel::GetOutputLevel_w() {
++  return channel_->GetOutputLevel();
++}
++
++Thread* VoiceChannel::worker_thread() {
++  return channel_manager_->worker_thread();
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h	(revision 586398)
+@@ -0,0 +1,69 @@
++#ifndef PORTAUDIOMEDIAENGINE_H
++#define PORTAUDIOMEDIAENGINE_H
++
++#include <portaudio.h>
++#include <speex.h>
++#include <ortp/ortp.h>
++
++#include "talk/session/phone/mediaengine.h"
++
++class PortAudioMediaChannel : public cricket::MediaChannel 
++{
++public:
++	PortAudioMediaChannel();
++	virtual ~PortAudioMediaChannel();
++	virtual void SetCodec(const char *codec);
++	virtual void OnPacketReceived(const void *data, int len);
++
++	virtual void SetPlayout(bool playout);
++	virtual void SetSend(bool send);
++
++	virtual float GetCurrentQuality();
++	virtual int GetOutputLevel();
++
++	void readOutput(float*, int);
++	void writeInput(float*, int);
++
++protected:
++	void readBuffer(float*, float**, float*, float*, float*, int);
++	void writeBuffer(float*, float*, float**, float*, float*, int);
++
++private:
++	bool mute_;
++	bool play_;
++	PortAudioStream* stream_;
++
++	// Buffers
++	float *out_buffer_, *out_buffer_read_, *out_buffer_write_, *out_buffer_end_;
++	float *in_buffer_, *in_buffer_read_, *in_buffer_write_, *in_buffer_end_;
++
++	// Speex
++	SpeexBits speex_bits_;
++	void *speex_enc_state_, *speex_dec_state_;
++	float *speex_frame_;
++	int speex_frame_size_;
++
++	// ORTP
++	int rtp_socket_;
++	RtpSession* rtp_session_;
++	int rtp_timestamp_;
++};
++
++
++class PortAudioMediaEngine : public cricket::MediaEngine 
++{
++public:
++	PortAudioMediaEngine();
++	~PortAudioMediaEngine();
++	virtual bool Init();
++	virtual void Terminate();
++
++	virtual cricket::MediaChannel *CreateChannel();
++
++	virtual int SetAudioOptions(int options);
++	virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
++
++	virtual int GetInputLevel();
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h	(revision 586398)
+@@ -0,0 +1,129 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _VOICECHANNEL_H_
++#define _VOICECHANNEL_H_
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/network.h"
++#include "talk/base/sigslot.h"
++#include "talk/p2p/client/socketmonitor.h"
++#include "talk/p2p/base/p2psocket.h"
++#include "talk/p2p/base/session.h"
++#include "talk/session/phone/audiomonitor.h"
++#include "talk/session/phone/mediaengine.h"
++
++namespace cricket {
++
++const uint32 MSG_ENABLE = 1;
++const uint32 MSG_DISABLE = 2;
++const uint32 MSG_MUTE = 3;
++const uint32 MSG_UNMUTE = 4;
++const uint32 MSG_SETSENDCODEC = 5;
++
++class ChannelManager;
++
++class VoiceChannel
++  : public MessageHandler, public sigslot::has_slots<>,
++    public NetworkSession, public MediaChannel::NetworkInterface {
++ public:
++  VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel);
++  ~VoiceChannel();
++
++  void Enable(bool enable);
++  void Mute(bool mute);
++  MediaChannel *channel();
++  Session *session();
++
++  // Monitoring
++
++  void StartConnectionMonitor(int cms);
++  void StopConnectionMonitor();
++  sigslot::signal2<VoiceChannel *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
++
++  void StartAudioMonitor(int cms);
++  void StopAudioMonitor();
++  sigslot::signal2<VoiceChannel *, const AudioInfo&> SignalAudioMonitor;
++  Thread* worker_thread();
++
++  // Pausing so that the ChannelManager can change the audio devices.  These
++  // should only be called from the worker thread
++  void PauseMedia_w();
++  void UnpauseMedia_w();
++
++  int GetInputLevel_w();
++  int GetOutputLevel_w();
++
++  // Gives a quality estimate to the network quality manager.
++  virtual bool HasQuality();
++  virtual float GetCurrentQuality();
++
++  // MediaEngine calls this
++  virtual void SendPacket(const void *data, size_t len);
++
++private:
++  void ChangeState();
++  void EnableMedia_w();
++  void DisableMedia_w();
++  void MuteMedia_w();
++  void UnmuteMedia_w();
++  void SocketWritable_w();
++  void SocketNotWritable_w();
++
++  void OnConnectionMonitorUpdate(SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos);
++  void OnAudioMonitorUpdate(AudioMonitor *monitor, const AudioInfo& info);
++
++  // From MessageHandler
++
++  void OnMessage(Message *pmsg);
++
++  // Setting the send codec based on the remote description.
++  void OnSessionState(Session* session, Session::State state);
++  void SetSendCodec_w();
++
++  // From P2PSocket
++
++  void OnSocketState(P2PSocket *socket, P2PSocket::State state);
++  void OnSocketRead(P2PSocket *socket, const char *data, size_t len);
++  
++
++  bool enabled_;
++  bool paused_;
++  bool socket_writable_;
++  bool muted_;
++  MediaChannel *channel_;
++  Session *session_;
++  P2PSocket *socket_;
++  ChannelManager *channel_manager_;
++  SocketMonitor *socket_monitor_;
++  AudioMonitor *audio_monitor_;
++  uint32 start_time_;
++};
++
++}
++
++#endif // _VOICECHANNEL_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc	(revision 586398)
+@@ -0,0 +1,170 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ * 
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++// LinphoneMediaEngine is a Linphone implementation of MediaEngine
++extern "C" {
++#include "talk/third_party/mediastreamer/mediastream.h"
++#ifdef HAVE_ILBC
++#include "talk/third_party/mediastreamer/msilbcdec.h"
++#endif
++#ifdef HAVE_SPEEX
++#include "talk/third_party/mediastreamer/msspeexdec.h"
++#endif
++}
++#include <ortp/ortp.h>
++#include <netdb.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <iostream>
++#include "talk/session/phone/linphonemediaengine.h"
++
++using namespace cricket;
++
++void *thread_function(void *data)
++{
++  LinphoneMediaChannel *mc =(LinphoneMediaChannel*) data;
++  while (mc->dying() == false) {
++    MediaChannel::NetworkInterface *iface = mc->network_interface();
++    char *buf[2048];
++    int len;
++    len = read(mc->fd(), buf, sizeof(buf));
++    if (iface && (mc->mute()==FALSE))
++      iface->SendPacket(buf, len);
++  }
++}
++
++LinphoneMediaChannel::LinphoneMediaChannel() {
++  pt_ = 102;
++  dying_ = false;
++  pthread_attr_t attr;
++  audio_stream_ = NULL;
++
++  struct sockaddr_in sockaddr;
++  sockaddr.sin_family = AF_INET;
++  sockaddr.sin_addr.s_addr = INADDR_ANY;
++  sockaddr.sin_port = htons(3000);
++  fd_ = socket(PF_INET, SOCK_DGRAM, 0);
++  fcntl(fd_, F_SETFL, 0, O_NONBLOCK);
++  bind (fd_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
++  
++  pthread_attr_init(&attr);
++  pthread_create(&thread_, &attr, &thread_function, this);
++}
++
++LinphoneMediaChannel::~LinphoneMediaChannel() {
++  dying_ = true;
++  pthread_join(thread_, NULL);
++  audio_stream_stop(audio_stream_);
++  close(fd_);
++}
++
++void LinphoneMediaChannel::SetCodec(const char *codec) {
++  if (!strcmp(codec, "iLBC"))
++    pt_ = 102;
++  else if (!strcmp(codec, "speex"))
++    pt_ = 110; 
++  else
++    pt_ = 0;
++  if (audio_stream_)
++    audio_stream_stop(audio_stream_);
++  audio_stream_ = audio_stream_start(&av_profile, 2000, "127.0.0.1", 3000, pt_, 250);
++}
++
++void LinphoneMediaChannel::OnPacketReceived(const void *data, int len) {
++  struct sockaddr_in sockaddr;
++  sockaddr.sin_family = AF_INET;
++  struct hostent *host = gethostbyname("localhost");
++  memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
++  sockaddr.sin_port = htons(2000);
++  
++  char buf[2048];
++  memcpy(buf, data, len);
++  
++  if (buf[1] == pt_) {
++  } else if (buf[1] == 13) {
++  } else if (buf[1] == 102) {
++    SetCodec("iLBC");
++  } else if (buf[1] == 110) {
++    SetCodec("speex");
++  } else if (buf[1] == 0) {
++    SetCodec("PCMU");
++  }
++  
++  if (play_ && buf[1] != 13)
++    sendto(fd_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
++}
++
++void LinphoneMediaChannel::SetPlayout(bool playout) {
++  play_ = playout;
++}
++
++void LinphoneMediaChannel::SetSend(bool send) {
++  mute_ = !send;
++}
++
++float LinphoneMediaChannel::GetCurrentQuality() {}
++int LinphoneMediaChannel::GetOutputLevel() {}
++
++LinphoneMediaEngine::LinphoneMediaEngine() {}
++LinphoneMediaEngine::~LinphoneMediaEngine() {}
++
++static void null_log_handler(const gchar *log_domain,
++	     		     GLogLevelFlags log_level,
++			     const gchar *message,
++			     gpointer user_data) {
++}
++
++bool LinphoneMediaEngine::Init() {
++  g_log_set_handler("MediaStreamer", G_LOG_LEVEL_MASK, null_log_handler, NULL);
++  g_log_set_handler("oRTP", G_LOG_LEVEL_MASK, null_log_handler, NULL);
++  g_log_set_handler("oRTP-stats", G_LOG_LEVEL_MASK, null_log_handler, NULL);
++  ortp_init();
++  ms_init();
++ 
++#ifdef HAVE_SPEEX
++  ms_speex_codec_init();
++  rtp_profile_set_payload(&av_profile, 110, &speex_wb);
++  codecs_.push_back(Codec(110, "speex", 8));
++#endif
++
++#ifdef HAVE_ILBC
++  ms_ilbc_codec_init();
++  rtp_profile_set_payload(&av_profile, 102, &payload_type_ilbc);
++  codecs_.push_back(Codec(102, "iLBC", 4));
++#endif
++
++  rtp_profile_set_payload(&av_profile, 0, &pcmu8000);
++  codecs_.push_back(Codec(0, "PCMU", 2));
++  
++return true;
++}
++
++void LinphoneMediaEngine::Terminate() {
++ 
++}
++  
++MediaChannel *LinphoneMediaEngine::CreateChannel() {
++  return new LinphoneMediaChannel();
++}
++
++int LinphoneMediaEngine::SetAudioOptions(int options) {}
++int LinphoneMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device) {}
++
++float LinphoneMediaEngine::GetCurrentQuality() {}
++int LinphoneMediaEngine::GetInputLevel() {}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc	(revision 586398)
+@@ -0,0 +1,203 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef HAVE_GIPS
++#include "talk/session/phone/gipsmediaengine.h"
++#else
++#include "talk/session/phone/linphonemediaengine.h"
++#endif
++#include "channelmanager.h"
++#include <cassert>
++#include <iostream>
++namespace cricket {
++
++const uint32 MSG_CREATEVOICECHANNEL = 1;
++const uint32 MSG_DESTROYVOICECHANNEL = 2;
++const uint32 MSG_SETAUDIOOPTIONS = 3;
++
++ChannelManager::ChannelManager(Thread *worker_thread) {
++#ifdef HAVE_GIPS
++  media_engine_ = new GipsMediaEngine();
++#else
++  media_engine_ = new LinphoneMediaEngine();
++#endif
++  worker_thread_ = worker_thread;
++  initialized_ = false;
++  Init();
++}
++
++ChannelManager::~ChannelManager() {
++  Exit();
++}
++
++MediaEngine *ChannelManager::media_engine() {
++  return media_engine_;
++}
++
++bool ChannelManager::Init() {
++  initialized_ =  media_engine_->Init();
++  return initialized_;
++}
++
++void ChannelManager::Exit() {
++  if (!initialized_)
++    return;
++
++  // Need to destroy the voice channels
++
++  while (true) {
++    crit_.Enter();
++    VoiceChannel *channel = NULL;
++    if (channels_.begin() != channels_.end())
++      channel = channels_[0];
++    crit_.Leave();
++    if (channel == NULL)
++      break;
++   delete channel;
++  }
++  media_engine_->Terminate();
++}
++
++struct CreateParams {
++  Session *session;
++  VoiceChannel *channel;
++};
++
++VoiceChannel *ChannelManager::CreateVoiceChannel(Session *session) {
++  CreateParams params;
++  params.session = session;
++  params.channel = NULL;
++  TypedMessageData<CreateParams *> data(&params);
++  worker_thread_->Send(this, MSG_CREATEVOICECHANNEL, &data);
++  return params.channel;
++}
++
++VoiceChannel *ChannelManager::CreateVoiceChannel_w(Session *session) {
++  CritScope cs(&crit_);
++
++  // This is ok to alloc from a thread other than the worker thread
++  assert(initialized_);
++  MediaChannel *channel = media_engine_->CreateChannel();
++  if (channel == NULL)
++    return NULL;
++
++  VoiceChannel *voice_channel = new VoiceChannel(this, session, channel);
++  channels_.push_back(voice_channel);
++  return voice_channel;
++}
++
++void ChannelManager::DestroyVoiceChannel(VoiceChannel *voice_channel) {
++  TypedMessageData<VoiceChannel *> data(voice_channel);
++  worker_thread_->Send(this, MSG_DESTROYVOICECHANNEL, &data);
++}
++
++void ChannelManager::DestroyVoiceChannel_w(VoiceChannel *voice_channel) {
++  CritScope cs(&crit_);
++  // Destroy voice channel.
++  assert(initialized_);
++  std::vector<VoiceChannel *>::iterator it = std::find(channels_.begin(),
++      channels_.end(), voice_channel);
++  assert(it != channels_.end());
++  if (it == channels_.end())
++    return;
++ 
++  channels_.erase(it);
++  MediaChannel *channel = voice_channel->channel();
++  delete voice_channel;
++  delete channel;
++}
++
++void ChannelManager::SetAudioOptions(bool auto_gain_control, int wave_in_device,
++                                     int wave_out_device) {
++  AudioOptions options;
++  options.auto_gain_control = auto_gain_control;
++  options.wave_in_device = wave_in_device;
++  options.wave_out_device = wave_out_device;
++  TypedMessageData<AudioOptions> data(options);
++  worker_thread_->Send(this, MSG_SETAUDIOOPTIONS, &data);
++}
++
++void ChannelManager::SetAudioOptions_w(AudioOptions options) {
++  assert(worker_thread_ == Thread::Current());
++
++  // Set auto gain control on
++  if (media_engine_->SetAudioOptions(options.auto_gain_control?MediaEngine::AUTO_GAIN_CONTROL:0) != 0) {
++    // TODO: We need to log these failures.
++  }
++
++  // Set the audio devices
++  // This will fail if audio is already playing.  Stop all of the media
++  // start it up again after changing the setting.
++  {
++    CritScope cs(&crit_);
++    for (VoiceChannels::iterator it = channels_.begin();
++         it < channels_.end();
++         ++it) {
++      (*it)->PauseMedia_w();
++    }
++
++    if (media_engine_->SetSoundDevices(options.wave_in_device, options.wave_out_device) == -1) {
++      // TODO: We need to log these failures.
++    }
++
++    for (VoiceChannels::iterator it = channels_.begin();
++         it < channels_.end();
++         ++it) {
++      (*it)->UnpauseMedia_w();
++    }
++  }
++}
++
++Thread *ChannelManager::worker_thread() {
++  return worker_thread_;
++}
++
++void ChannelManager::OnMessage(Message *message) {
++  switch (message->message_id) {
++  case MSG_CREATEVOICECHANNEL:
++    {
++      TypedMessageData<CreateParams *> *data = static_cast<TypedMessageData<CreateParams *> *>(message->pdata);
++      data->data()->channel = CreateVoiceChannel_w(data->data()->session);
++    }
++    break;
++
++  case MSG_DESTROYVOICECHANNEL:
++    {
++      TypedMessageData<VoiceChannel *> *data = static_cast<TypedMessageData<VoiceChannel *> *>(message->pdata);
++      DestroyVoiceChannel_w(data->data());
++    }
++    break;
++  case MSG_SETAUDIOOPTIONS:
++    {
++      TypedMessageData<AudioOptions> *data = static_cast<TypedMessageData<AudioOptions> *>(message->pdata);
++      SetAudioOptions_w(data->data());
++    }
++    break;
++  }
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h	(revision 586398)
+@@ -0,0 +1,75 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ * 
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++// LinphoneMediaEngine is a Linphone implementation of MediaEngine
++
++#ifndef TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
++#define TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
++
++extern "C" {
++#include "talk/third_party/mediastreamer/mediastream.h"
++}
++#include "talk/session/phone/mediaengine.h"
++
++namespace cricket {
++
++class LinphoneMediaChannel : public MediaChannel {
++ public:
++  LinphoneMediaChannel();
++  virtual ~LinphoneMediaChannel();
++  virtual void SetCodec(const char *codec);
++  virtual void OnPacketReceived(const void *data, int len);
++
++  virtual void SetPlayout(bool playout);
++  virtual void SetSend(bool send);
++
++  virtual float GetCurrentQuality();
++  virtual int GetOutputLevel();
++  int fd() {return fd_;}
++  bool mute() {return mute_;}
++  bool dying() {return dying_;}
++ private:
++  AudioStream *audio_stream_;
++  pthread_t thread_;
++  int fd_;
++  int pt_;
++  bool dying_;
++  bool mute_;
++  bool play_;
++};
++
++class LinphoneMediaEngine : public MediaEngine {
++ public:
++  LinphoneMediaEngine();
++  ~LinphoneMediaEngine();
++  virtual bool Init();
++  virtual void Terminate();
++  
++  virtual MediaChannel *CreateChannel();
++
++  virtual int SetAudioOptions(int options);
++  virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
++
++  virtual float GetCurrentQuality();
++  virtual int GetInputLevel();
++};
++
++}  // namespace cricket
++
++#endif  // TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CHANNELMANAGER_H_
++#define _CHANNELMANAGER_H_
++
++#include "talk/base/thread.h"
++#include "talk/base/criticalsection.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/p2psocket.h"
++#include "talk/session/phone/voicechannel.h"
++#include "talk/session/phone/mediaengine.h"
++#include <vector>
++
++namespace cricket {
++
++class VoiceChannel;
++
++class ChannelManager : public MessageHandler {
++public:
++  ChannelManager(Thread *worker_thread);
++  ~ChannelManager();
++
++  VoiceChannel *CreateVoiceChannel(Session *session);
++  void DestroyVoiceChannel(VoiceChannel *voice_channel);
++  void SetAudioOptions(bool auto_gain_control, int wave_in_device,
++                       int wave_out_device);
++
++  MediaEngine *media_engine();
++  Thread *worker_thread();
++
++private:
++  VoiceChannel *CreateVoiceChannel_w(Session *session);
++  void DestroyVoiceChannel_w(VoiceChannel *voice_channel);
++  void OnMessage(Message *message);
++  bool Init();
++  void Exit();
++
++  struct AudioOptions {
++    bool auto_gain_control;
++    int wave_in_device;
++    int wave_out_device;
++  };
++  void SetAudioOptions_w(AudioOptions options);
++
++  Thread *worker_thread_;
++  MediaEngine *media_engine_;
++  bool initialized_;
++  CriticalSection crit_;
++
++  typedef std::vector<VoiceChannel*> VoiceChannels;
++  VoiceChannels channels_;
++};
++
++}
++
++#endif // _CHANNELMANAGER_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h	(revision 586398)
+@@ -0,0 +1,95 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++// MediaEngine is an abstraction of a media engine which can be subclassed
++// to support different media componentry backends.
++
++#ifndef TALK_SESSION_PHONE_MEDIAENGINE_H_
++#define TALK_SESSION_PHONE_MEDIAENGINE_H_
++
++#include <string>
++#include <vector>
++#include "mediachannel.h"
++
++namespace cricket {
++
++class MediaEngine {
++ public: 
++  
++  struct Codec {
++    int id;
++    std::string name;
++    int preference;
++    // Creates a codec with the given parameters.
++    Codec(int pt, const std::string& nm, int pr) : id(pt), name(nm), preference(pr) {}
++    // Ranks codecs by their preferences.
++    bool operator <(const Codec& c) const { return preference > c.preference; }
++  };
++  
++  // Bitmask flags for options that may be supported by the media engine implementation
++  enum MediaEngineOptions {
++     AUTO_GAIN_CONTROL = 1 << 1,
++  };
++
++  MediaEngine() {}
++
++  // Initialize 
++  virtual bool Init() = 0;
++  virtual void Terminate() = 0;
++  virtual MediaChannel *CreateChannel() = 0;
++ 
++  virtual int SetAudioOptions(int options) = 0;
++  virtual int SetSoundDevices(int wave_in_device, int wave_out_device) = 0;
++  virtual int GetInputLevel() = 0;
++
++  std::vector<Codec> &codecs() { return codecs_; }
++
++  bool FindCodec(const char* codec) {
++    for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
++      if ((*i).name == codec)
++	return true;
++    }
++    return false;
++  }
++  
++  bool GetCodecPreference (const char *codec, int & preference) {
++    for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
++      if ((*i).name == codec) {
++	preference = (*i).preference;
++	return true;
++      }
++    }
++    return false;
++  }
++
++ protected:
++  std::vector<Codec> codecs_;
++};  
++
++}  // namespace cricket
++
++#endif  // TALK_SESSION_PHONE_MEDIAENGINE_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc	(revision 586398)
+@@ -0,0 +1,119 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/session/phone/audiomonitor.h"
++#include "talk/session/phone/voicechannel.h"
++#include <cassert>
++
++namespace cricket {
++
++const uint32 MSG_MONITOR_POLL = 1;
++const uint32 MSG_MONITOR_START = 2;
++const uint32 MSG_MONITOR_STOP = 3;
++const uint32 MSG_MONITOR_SIGNAL = 4;
++
++AudioMonitor::AudioMonitor(VoiceChannel *voice_channel, Thread *monitor_thread) {
++  voice_channel_ = voice_channel;
++  monitoring_thread_ = monitor_thread;
++  monitoring_ = false;
++}
++
++AudioMonitor::~AudioMonitor() {
++  voice_channel_->worker_thread()->Clear(this);
++  monitoring_thread_->Clear(this);
++}
++
++void AudioMonitor::Start(int milliseconds) {
++  rate_ = milliseconds;
++  if (rate_ < 100)
++    rate_ = 100;
++  voice_channel_->worker_thread()->Post(this, MSG_MONITOR_START);
++}
++
++void AudioMonitor::Stop() {
++  voice_channel_->worker_thread()->Post(this, MSG_MONITOR_STOP);
++}
++
++void AudioMonitor::OnMessage(Message *message) {
++  CritScope cs(&crit_);
++
++  switch (message->message_id) {
++  case MSG_MONITOR_START:
++    assert(Thread::Current() == voice_channel_->worker_thread());
++    if (!monitoring_) {
++      monitoring_ = true;
++      PollVoiceChannel();
++    }
++    break;
++
++  case MSG_MONITOR_STOP:
++    assert(Thread::Current() == voice_channel_->worker_thread());
++    if (monitoring_) {
++      monitoring_ = false;
++      voice_channel_->worker_thread()->Clear(this);
++    }
++    break;
++
++  case MSG_MONITOR_POLL:
++    assert(Thread::Current() == voice_channel_->worker_thread());
++    PollVoiceChannel();
++    break;
++
++  case MSG_MONITOR_SIGNAL:
++    {
++      assert(Thread::Current() == monitoring_thread_);
++      AudioInfo info = audio_info_;
++      crit_.Leave();
++      SignalUpdate(this, audio_info_);
++      crit_.Enter();
++    }
++    break;
++  }
++}
++
++void AudioMonitor::PollVoiceChannel() {
++  CritScope cs(&crit_);
++  assert(Thread::Current() == voice_channel_->worker_thread());
++
++  // Gather connection infos
++  audio_info_.input_level = voice_channel_->GetInputLevel_w();
++  audio_info_.output_level = voice_channel_->GetOutputLevel_w();
++
++  // Signal the monitoring thread, start another poll timer
++  monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
++  voice_channel_->worker_thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL);
++}
++
++VoiceChannel *AudioMonitor::voice_channel() {
++  return voice_channel_;
++}
++
++Thread *AudioMonitor::monitor_thread() {
++  return monitoring_thread_;
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h	(revision 586398)
+@@ -0,0 +1,55 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_
++#define TALK_SESSION_PHONE_MEDIACHANNEL_H_
++
++namespace cricket {
++
++class MediaChannel {
++ public:
++  class NetworkInterface {
++  public:
++    virtual void SendPacket(const void *data, size_t len) = 0;
++  };
++  MediaChannel() {network_interface_ = NULL;}
++  virtual ~MediaChannel() {};
++  void SetInterface(NetworkInterface *iface) {network_interface_ = iface;}
++  virtual void SetCodec(const char *codec) = 0;
++  virtual void OnPacketReceived(const void *data, int len) = 0;
++  virtual void SetPlayout(bool playout) = 0;
++  virtual void SetSend(bool send) = 0;
++  virtual float GetCurrentQuality() = 0;
++  virtual int GetOutputLevel() = 0;
++  NetworkInterface *network_interface() {return network_interface_;}
++ protected:
++  NetworkInterface *network_interface_;
++};
++
++};  // namespace cricket
++
++#endif  // TALK_SESSION_PHONE_MEDIACHANNEL_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc	(revision 586398)
+@@ -0,0 +1,258 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/thread.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/session/phone/call.h"
++
++namespace cricket {
++
++const uint32 MSG_CHECKAUTODESTROY = 1;
++
++Call::Call(PhoneSessionClient *session_client) : muted_(false) {
++  session_client_ = session_client;
++  id_ = CreateRandomId();
++}
++
++Call::~Call() {
++  while (sessions_.begin() != sessions_.end()) {
++    Session *session = sessions_[0];
++    RemoveSession(session);
++    session_client_->session_manager()->DestroySession(session);
++  }
++  Thread::Current()->Clear(this);
++}
++
++Session *Call::InitiateSession(const buzz::Jid &jid) {
++  Session *session = session_client_->CreateSession(this);
++  AddSession(session);
++  session->Initiate(jid.Str(), session_client_->CreateOfferSessionDescription());
++  return session;
++}
++
++void Call::AcceptSession(Session *session) {
++  std::vector<Session *>::iterator it;
++  it = std::find(sessions_.begin(), sessions_.end(), session);
++  assert(it != sessions_.end());
++  if (it != sessions_.end())
++    session->Accept(session_client_->CreateAcceptSessionDescription(session->remote_description()));
++}
++
++void Call::RedirectSession(Session *session, const buzz::Jid &to) {
++  std::vector<Session *>::iterator it;
++  it = std::find(sessions_.begin(), sessions_.end(), session);
++  assert(it != sessions_.end());
++  if (it != sessions_.end())
++    session->Redirect(to.Str());
++}
++
++void Call::RejectSession(Session *session) {
++  std::vector<Session *>::iterator it;
++  it = std::find(sessions_.begin(), sessions_.end(), session);
++  assert(it != sessions_.end());
++  if (it != sessions_.end())
++    session->Reject();
++}
++
++void Call::TerminateSession(Session *session) {
++  assert(std::find(sessions_.begin(), sessions_.end(), session) != sessions_.end());
++  std::vector<Session *>::iterator it;
++  it = std::find(sessions_.begin(), sessions_.end(), session);
++  if (it != sessions_.end())
++    (*it)->Terminate();
++}
++
++void Call::Terminate() {
++  // There may be more than one session to terminate
++  std::vector<Session *>::iterator it = sessions_.begin();
++  for (it = sessions_.begin(); it != sessions_.end(); it++)
++    TerminateSession(*it);
++}
++
++void Call::OnMessage(Message *message) {
++  switch (message->message_id) {
++  case MSG_CHECKAUTODESTROY:
++    // If no more sessions for this call, delete it
++    if (sessions_.size() == 0)
++      session_client_->DestroyCall(this);
++    break;
++  }
++}
++
++const std::vector<Session *> &Call::sessions() {
++  return sessions_;
++}
++
++void Call::AddSession(Session *session) {
++  // Add session to list, create voice channel for this session
++  sessions_.push_back(session);
++  session->SignalState.connect(this, &Call::OnSessionState);
++  session->SignalError.connect(this, &Call::OnSessionError);
++
++  VoiceChannel *channel = session_client_->channel_manager()->CreateVoiceChannel(session);
++  channel_map_[session->id()] = channel;
++
++  // If this call has the focus, enable this channel
++  if (session_client_->GetFocus() == this)
++    channel->Enable(true);
++
++  // Signal client
++  SignalAddSession(this, session);
++}
++
++void Call::RemoveSession(Session *session) {
++  // Remove session from list
++  std::vector<Session *>::iterator it_session;
++  it_session = std::find(sessions_.begin(), sessions_.end(), session);
++  if (it_session == sessions_.end())
++    return;
++  sessions_.erase(it_session);
++
++  // Destroy session channel
++  std::map<SessionID, VoiceChannel *>::iterator it_channel;
++  it_channel = channel_map_.find(session->id());
++  if (it_channel != channel_map_.end()) {
++    VoiceChannel *channel = it_channel->second;
++    channel_map_.erase(it_channel);
++    session_client_->channel_manager()->DestroyVoiceChannel(channel);
++  }
++
++  // Signal client
++  SignalRemoveSession(this, session);
++
++  // The call auto destroys when the lass session is removed
++  Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
++}
++
++VoiceChannel* Call::GetChannel(Session* session) {
++  std::map<SessionID, VoiceChannel *>::iterator it = channel_map_.find(session->id());
++  assert(it != channel_map_.end());
++  return it->second;
++}
++
++void Call::EnableChannels(bool enable) {
++  std::vector<Session *>::iterator it;
++  for (it = sessions_.begin(); it != sessions_.end(); it++) {
++    VoiceChannel *channel = channel_map_[(*it)->id()];
++    if (channel != NULL)
++      channel->Enable(enable);
++  }
++}
++
++void Call::Mute(bool mute) {
++  muted_ = mute;
++  std::vector<Session *>::iterator it;
++  for (it = sessions_.begin(); it != sessions_.end(); it++) {
++    VoiceChannel *channel = channel_map_[(*it)->id()];
++    if (channel != NULL)
++      channel->Mute(mute);
++  }
++}
++
++void Call::Join(Call *call, bool enable) {
++  while (call->sessions_.size() != 0) {
++    // Move session
++    Session *session = call->sessions_[0];
++    call->sessions_.erase(call->sessions_.begin());
++    sessions_.push_back(session);
++    session->SignalState.connect(this, &Call::OnSessionState);
++    session->SignalError.connect(this, &Call::OnSessionError);
++
++    // Move channel
++    std::map<SessionID, VoiceChannel *>::iterator it_channel;
++    it_channel = call->channel_map_.find(session->id());
++    if (it_channel != call->channel_map_.end()) {
++      VoiceChannel *channel = (*it_channel).second;
++      call->channel_map_.erase(it_channel);
++      channel_map_[session->id()] = channel;
++      channel->Enable(enable);
++    }
++  }
++}
++
++void Call::StartConnectionMonitor(Session *session, int cms) {
++  std::map<SessionID, VoiceChannel *>::iterator it_channel;
++  it_channel = channel_map_.find(session->id());
++  if (it_channel != channel_map_.end()) {
++    VoiceChannel *channel = (*it_channel).second;
++    channel->SignalConnectionMonitor.connect(this, &Call::OnConnectionMonitor);
++    channel->StartConnectionMonitor(cms);
++  }
++}
++
++void Call::StopConnectionMonitor(Session *session) {
++  std::map<SessionID, VoiceChannel *>::iterator it_channel;
++  it_channel = channel_map_.find(session->id());
++  if (it_channel != channel_map_.end()) {
++    VoiceChannel *channel = (*it_channel).second;
++    channel->StopConnectionMonitor();
++    channel->SignalConnectionMonitor.disconnect(this);
++  }
++}
++
++void Call::StartAudioMonitor(Session *session, int cms) {
++  std::map<SessionID, VoiceChannel *>::iterator it_channel;
++  it_channel = channel_map_.find(session->id());
++  if (it_channel != channel_map_.end()) {
++    VoiceChannel *channel = (*it_channel).second;
++    channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
++    channel->StartAudioMonitor(cms);
++  }
++}
++
++void Call::StopAudioMonitor(Session *session) {
++  std::map<SessionID, VoiceChannel *>::iterator it_channel;
++  it_channel = channel_map_.find(session->id());
++  if (it_channel != channel_map_.end()) {
++    VoiceChannel *channel = (*it_channel).second;
++    channel->StopAudioMonitor();
++    channel->SignalAudioMonitor.disconnect(this);
++  }
++}
++
++
++void Call::OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos) {
++  SignalConnectionMonitor(this, channel->session(), infos);
++}
++
++void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
++  SignalAudioMonitor(this, channel->session(), info);
++}
++
++uint32 Call::id() {
++  return id_;
++}
++
++void Call::OnSessionState(Session *session, Session::State state) {
++  SignalSessionState(this, session, state);
++}
++
++void Call::OnSessionError(Session *session, Session::Error error) {
++  SignalSessionError(this, session, error);
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CRICKET_PHONE_AUDIOMONITOR_H_
++#define _CRICKET_PHONE_AUDIOMONITOR_H_
++
++#include "talk/base/thread.h"
++#include "talk/base/sigslot.h"
++#include "talk/p2p/base/port.h"
++#include <vector>
++
++namespace cricket {
++
++class VoiceChannel;
++
++
++struct AudioInfo {
++  int input_level;
++  int output_level;
++};
++
++class AudioMonitor : public MessageHandler, public sigslot::has_slots<> {
++public:
++  AudioMonitor(VoiceChannel* voice_channel, Thread *monitor_thread);
++  ~AudioMonitor();
++
++  void Start(int cms);
++  void Stop();
++
++  VoiceChannel* voice_channel();
++  Thread *monitor_thread();
++
++  sigslot::signal2<AudioMonitor*, const AudioInfo&> SignalUpdate;
++
++protected:
++  void OnMessage(Message *message);
++  void PollVoiceChannel();
++
++  AudioInfo audio_info_;
++  VoiceChannel* voice_channel_;
++  Thread* monitoring_thread_;
++  CriticalSection crit_;
++  uint32 rate_;
++  bool monitoring_;
++};
++
++}
++
++#endif // _CRICKET_PHONE_AUDIOMONITOR_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc	(revision 586398)
+@@ -0,0 +1,267 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/logging.h"
++#include "talk/session/receiver.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/xmllite/qname.h"
++namespace {
++
++const std::string NS_PHONE("http://www.google.com/session/phone");
++const std::string NS_EMPTY("");
++
++const buzz::QName QN_PHONE_DESCRIPTION(true, NS_PHONE, "description");
++const buzz::QName QN_PHONE_PAYLOADTYPE(true, NS_PHONE, "payload-type");
++const buzz::QName QN_PHONE_PAYLOADTYPE_ID(true, NS_EMPTY, "id");
++const buzz::QName QN_PHONE_PAYLOADTYPE_NAME(true, NS_EMPTY, "name");
++
++}
++
++namespace cricket {
++
++PhoneSessionClient::PhoneSessionClient(const buzz::Jid& jid, 
++    SessionManager *manager) : jid_(jid), SessionClient(manager) {
++
++  // No call to start, and certainly no call with focus
++  focus_call_ = NULL;
++
++  // Start up the channel manager on a worker thread
++  channel_manager_ = new ChannelManager(session_manager_->worker_thread());
++}
++
++PhoneSessionClient::~PhoneSessionClient() {
++  // Destroy all calls
++  std::map<uint32, Call *>::iterator it;
++  while (calls_.begin() != calls_.end()) {
++    std::map<uint32, Call *>::iterator it = calls_.begin();
++    DestroyCall((*it).second);
++  }
++
++  // Delete channel manager. This will wait for the channels to exit
++  delete channel_manager_;
++}
++
++const std::string &PhoneSessionClient::GetSessionDescriptionName() {
++  return NS_PHONE;
++}
++
++PhoneSessionDescription* PhoneSessionClient::CreateOfferSessionDescription() {
++  PhoneSessionDescription* session_desc = new PhoneSessionDescription();
++
++  MediaEngine *me = channel_manager_->media_engine();
++  std::vector<MediaEngine::Codec> codecs = me->codecs();
++  std::vector<MediaEngine::Codec>::iterator i;
++  for (i = codecs.begin(); i < codecs.end(); i++) 
++    session_desc->AddCodec(*i);
++  
++  session_desc->Sort();
++  return session_desc;
++}
++
++PhoneSessionDescription* PhoneSessionClient::CreateAcceptSessionDescription(const SessionDescription* offer) {
++  const PhoneSessionDescription* offer_desc =
++      static_cast<const PhoneSessionDescription*>(offer);
++  PhoneSessionDescription* accept_desc = new PhoneSessionDescription();
++  std::vector<MediaEngine::Codec> codecs = channel_manager_->media_engine()->codecs();
++  std::vector<MediaEngine::Codec>::iterator iter;
++  for (unsigned int i = 0; i < offer_desc->codecs().size(); ++i) {
++    for (iter = codecs.begin(); iter < codecs.end(); iter++) { 
++      if ((*iter).name == offer_desc->codecs()[i].name)
++        accept_desc->AddCodec(*iter); 
++    }
++  }
++
++  accept_desc->Sort();
++  return accept_desc;
++}
++
++bool PhoneSessionClient::FindMediaCodec(MediaEngine* me,
++                                       const PhoneSessionDescription* desc,
++                                       const char** codec) {
++  for (size_t i = 0; i < desc->codecs().size(); ++i) {
++    if (me->FindCodec(desc->codecs()[i].name.c_str()))
++      *codec = desc->codecs()[i].name.c_str();
++      return true;
++  }
++
++  return false;
++}
++
++const SessionDescription *PhoneSessionClient::CreateSessionDescription(const buzz::XmlElement *element) {
++  PhoneSessionDescription* desc = new PhoneSessionDescription();
++
++  const buzz::XmlElement* payload_type = element->FirstNamed(QN_PHONE_PAYLOADTYPE);
++  int num_payload_types = 0;
++
++  while (payload_type) {
++    if (payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_ID) &&
++        payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_NAME)) {
++      int id = atoi(payload_type->Attr(QN_PHONE_PAYLOADTYPE_ID).c_str());
++      int pref = 0;
++      std::string name = payload_type->Attr(QN_PHONE_PAYLOADTYPE_NAME);
++      desc->AddCodec(MediaEngine::Codec(id, name, 0));
++    }
++
++    payload_type = payload_type->NextNamed(QN_PHONE_PAYLOADTYPE);
++    num_payload_types += 1;
++  }
++
++  // For backward compatability, we can assume the other client is (an old
++  // version of Talk) if it has no payload types at all.
++  if (num_payload_types == 0) {
++    desc->AddCodec(MediaEngine::Codec(103, "ISAC", 1));
++    desc->AddCodec(MediaEngine::Codec(0, "PCMU", 0));
++  }
++
++  return desc;
++}
++
++buzz::XmlElement *PhoneSessionClient::TranslateSessionDescription(const SessionDescription *_session_desc) {
++  const PhoneSessionDescription* session_desc =
++      static_cast<const PhoneSessionDescription*>(_session_desc);
++  buzz::XmlElement* description = new buzz::XmlElement(QN_PHONE_DESCRIPTION, true);
++
++  for (size_t i = 0; i < session_desc->codecs().size(); ++i) {
++    buzz::XmlElement* payload_type = new buzz::XmlElement(QN_PHONE_PAYLOADTYPE, true);
++
++    char buf[32];
++    sprintf(buf, "%d", session_desc->codecs()[i].id);
++    payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_ID, buf);
++
++    payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_NAME,
++                          session_desc->codecs()[i].name.c_str());
++
++    description->AddElement(payload_type);
++  }
++
++  return description;
++}
++
++Call *PhoneSessionClient::CreateCall() {
++  Call *call = new Call(this);
++  calls_[call->id()] = call;
++  SignalCallCreate(call);
++  return call;
++}
++
++void PhoneSessionClient::OnSessionCreate(Session *session, bool received_initiate) {
++  if (received_initiate) {
++    session->SignalState.connect(this, &PhoneSessionClient::OnSessionState);
++
++    Call *call = CreateCall();
++    session_map_[session->id()] = call;
++    call->AddSession(session);
++  }
++}
++
++void PhoneSessionClient::OnSessionState(Session *session, Session::State state) {
++  if (state == Session::STATE_RECEIVEDINITIATE) {
++    // If our accept would have no codecs, then we must reject this call.
++    PhoneSessionDescription* accept_desc =
++        CreateAcceptSessionDescription(session->remote_description());
++    if (accept_desc->codecs().size() == 0) {
++      // TODO: include an error description with the rejection.
++      session->Reject();
++    }
++    delete accept_desc;
++  }
++}
++
++void PhoneSessionClient::DestroyCall(Call *call) {
++  // Change focus away, signal destruction
++
++  if (call == focus_call_)
++    SetFocus(NULL);
++  SignalCallDestroy(call);
++
++  // Remove it from calls_ map and delete
++
++  std::map<uint32, Call *>::iterator it = calls_.find(call->id());
++  if (it != calls_.end())
++    calls_.erase(it);
++
++  delete call;
++}
++
++void PhoneSessionClient::OnSessionDestroy(Session *session) {
++  // Find the call this session is in, remove it
++
++  std::map<SessionID, Call *>::iterator it = session_map_.find(session->id());
++  assert(it != session_map_.end());
++  if (it != session_map_.end()) {
++    Call *call = (*it).second;
++    session_map_.erase(it);
++    call->RemoveSession(session);
++  }
++}
++
++Call *PhoneSessionClient::GetFocus() {
++  return focus_call_;
++}
++
++void PhoneSessionClient::SetFocus(Call *call) {
++  Call *old_focus_call = focus_call_;
++  if (focus_call_ != call) {
++    if (focus_call_ != NULL)
++      focus_call_->EnableChannels(false);
++    focus_call_ = call;
++    if (focus_call_ != NULL)
++      focus_call_->EnableChannels(true);
++    SignalFocus(focus_call_, old_focus_call);
++  }
++}
++
++void PhoneSessionClient::JoinCalls(Call *call_to_join, Call *call) {
++  // Move all sessions from call to call_to_join, delete call.
++  // If call_to_join has focus, added sessions should have enabled channels.
++
++  if (focus_call_ == call)
++    SetFocus(NULL);
++  call_to_join->Join(call, focus_call_ == call_to_join);
++  DestroyCall(call);
++}
++
++Session *PhoneSessionClient::CreateSession(Call *call) {
++  Session *session = session_manager_->CreateSession(
++      GetSessionDescriptionName(), jid().Str());
++  session_map_[session->id()] = call;
++  return session;
++}
++
++ChannelManager *PhoneSessionClient::channel_manager() {
++  return channel_manager_;
++}
++
++const buzz::Jid &PhoneSessionClient::jid() const {
++  return jid_;
++}
++
++const buzz::Jid &PhoneSessionClient::GetJid() const {
++  return jid_;
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h	(revision 586398)
+@@ -0,0 +1,97 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CALL_H_
++#define _CALL_H_
++
++#include "talk/base/messagequeue.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/client/socketmonitor.h"
++#include "talk/xmpp/jid.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/session/phone/voicechannel.h"
++#include "talk/session/phone/audiomonitor.h"
++
++#include <map>
++#include <vector>
++
++namespace cricket {
++
++class PhoneSessionClient;
++
++class Call : public MessageHandler, public sigslot::has_slots<> {
++public:
++  Call(PhoneSessionClient *session_client);
++  ~Call();
++
++  Session *InitiateSession(const buzz::Jid &jid);
++  void AcceptSession(Session *session);
++  void RedirectSession(Session *session, const buzz::Jid &to);
++  void RejectSession(Session *session);
++  void TerminateSession(Session *session);
++  void Terminate();
++  void StartConnectionMonitor(Session *session, int cms);
++  void StopConnectionMonitor(Session *session);
++  void StartAudioMonitor(Session *session, int cms);
++  void StopAudioMonitor(Session *session);
++  void Mute(bool mute);
++
++  const std::vector<Session *> &sessions();
++  uint32 id();
++  bool muted() const { return muted_; }
++
++  sigslot::signal2<Call *, Session *> SignalAddSession;
++  sigslot::signal2<Call *, Session *> SignalRemoveSession;
++  sigslot::signal3<Call *, Session *, Session::State> SignalSessionState;
++  sigslot::signal3<Call *, Session *, Session::Error> SignalSessionError;
++  sigslot::signal3<Call *, Session *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
++  sigslot::signal3<Call *, Session *, const AudioInfo&> SignalAudioMonitor;
++
++private:
++  void OnMessage(Message *message);
++  void OnSessionState(Session *session, Session::State state);
++  void OnSessionError(Session *session, Session::Error error);
++  void AddSession(Session *session);
++  void RemoveSession(Session *session);
++  void EnableChannels(bool enable);
++  void Join(Call *call, bool enable);
++  void OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos);
++  void OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info);
++  VoiceChannel* GetChannel(Session* session);
++
++  uint32 id_;
++  PhoneSessionClient *session_client_;
++  std::vector<Session *> sessions_;
++  std::map<SessionID, VoiceChannel *> channel_map_;
++  bool muted_;
++
++  friend class PhoneSessionClient;
++};
++
++}
++
++#endif // _CALL_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h	(revision 586398)
+@@ -0,0 +1,122 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _PHONESESSIONCLIENT_H_
++#define _PHONESESSIONCLIENT_H_
++
++#include "talk/session/phone/call.h"
++#include "talk/session/phone/channelmanager.h"
++#include "talk/base/sigslot.h"
++#include "talk/base/messagequeue.h"
++#include "talk/base/thread.h"
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/sessiondescription.h"
++#include "talk/xmpp/xmppclient.h"
++#include <map>
++
++namespace cricket {
++
++class Call;
++class PhoneSessionDescription;
++
++class PhoneSessionClient : public SessionClient {
++public:
++  PhoneSessionClient(const buzz::Jid& jid, SessionManager *manager);
++  ~PhoneSessionClient();
++
++  const buzz::Jid &jid() const;
++
++  Call *CreateCall();
++  void DestroyCall(Call *call);
++
++  Call *GetFocus();
++  void SetFocus(Call *call);
++
++  void JoinCalls(Call *call_to_join, Call *call);
++
++  void SetAudioOptions(bool auto_gain_control, int wave_in_device,
++                       int wave_out_device) {
++    if (channel_manager_)
++      channel_manager_->SetAudioOptions(auto_gain_control, wave_in_device,
++                                        wave_out_device);
++  }
++
++  sigslot::signal2<Call *, Call *> SignalFocus;
++  sigslot::signal1<Call *> SignalCallCreate;
++  sigslot::signal1<Call *> SignalCallDestroy;
++
++  PhoneSessionDescription* CreateOfferSessionDescription();
++  PhoneSessionDescription* CreateAcceptSessionDescription(const SessionDescription* offer);
++
++  // Returns our preference for the given codec.
++  static int GetMediaCodecPreference(const char* name);
++
++  // Returns the name of the first codec in the description that
++  // is found.  Return value is false if none was found.
++  static bool FindMediaCodec(MediaEngine* gips,
++                            const PhoneSessionDescription* desc,
++                            const char **codec);
++
++private:
++  void OnSessionCreate(Session *session, bool received_initiate);
++  void OnSessionState(Session *session, Session::State state);
++  void OnSessionDestroy(Session *session);
++  const SessionDescription *CreateSessionDescription(const buzz::XmlElement *element);
++  buzz::XmlElement *TranslateSessionDescription(const SessionDescription *description);
++  const std::string &GetSessionDescriptionName();
++  const buzz::Jid &GetJid() const;
++  Session *CreateSession(Call *call);
++  ChannelManager *channel_manager();
++
++  buzz::Jid jid_;
++  Call *focus_call_;
++  ChannelManager *channel_manager_;
++  std::map<uint32, Call *> calls_;
++  std::map<SessionID, Call *> session_map_;
++
++  friend class Call;
++};
++
++class PhoneSessionDescription: public SessionDescription {
++public:
++  // Returns the list of codecs sorted by our preference.
++  const std::vector<MediaEngine::Codec>& codecs() const { return codecs_; }
++
++  // Adds another codec to the list.
++  void AddCodec(const MediaEngine::Codec& codec) { codecs_.push_back(codec); }
++  // Sorts the list of codecs by preference.
++  void Sort() { /* std::stable_sort(codecs_.begin(), codecs_.end());*/ }
++
++private:
++  std::vector<MediaEngine::Codec> codecs_;
++};
++
++}
++
++#endif // _PHONESESSIONCLIENT_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am	(revision 586398)
+@@ -0,0 +1,18 @@
++libcricketsessionphone_la_SOURCES = audiomonitor.cc \
++				    channelmanager.cc \
++				    voicechannel.cc \
++				    call.cc \
++				    phonesessionclient.cc \
++				    linphonemediaengine.cc 
++
++noinst_HEADERS =                    audiomonitor.h \
++				    channelmanager.h \
++				    linphonemediaengine.h \
++				    mediaengine.h \
++				    phonesessionclient.h \
++				    voicechannel.h \
++                                    call.h \
++				    mediachannel.h 
++
++AM_CPPFLAGS = -DPOSIX $(ORTP_CFLAGS) $(ILBC_CFLAGS) -I$(srcdir)/../../../talk/third_party/mediastreamer -I$(srcdir)/../../.. $(GLIB_CFLAGS) $(SPEEX_CFLAGS)
++noinst_LTLIBRARIES = libcricketsessionphone.la
+--- kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _RECEIVER_H_
++#define _RECEIVER_H_
++
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmpptask.h"
++#include "talk/p2p/client/sessionclient.h"
++
++namespace cricket {
++
++class Receiver : public buzz::XmppTask {
++public:
++  Receiver(Task *parent, SessionClient *session_client)
++    : buzz::XmppTask(parent, buzz::XmppEngine::HL_TYPE) {
++    session_client_ = session_client;
++  }
++
++  virtual int ProcessStart() {
++    const buzz::XmlElement *stanza = NextStanza();
++    if (stanza == NULL)
++      return STATE_BLOCKED;
++    session_client_->OnIncomingStanza(stanza);
++
++    // Respond right away to the sender to let them know that we received
++    // this IQ
++    buzz::XmlElement * result = MakeIqResult(stanza);
++    SendStanza(result);
++
++    return STATE_START;
++  }
++
++protected:
++  virtual bool HandleStanza(const buzz::XmlElement *stanza) {
++    if (!session_client_->IsClientStanza(stanza))
++      return false;
++    QueueStanza(stanza);
++    return true;
++  }
++
++private:
++  SessionClient *session_client_;
++};
++
++}
++
++#endif // _RECEIVER_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc	(revision 586398)
+@@ -0,0 +1,480 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#define TRACK_ARRAY_ALLOC_PROBLEM
++
++#include <vector>
++#include <sstream>
++#include <algorithm>
++#include "talk/xmllite/xmlelement.h"
++#include "talk/base/common.h"
++#include "talk/xmpp/xmppengineimpl.h"
++#include "talk/xmpp/xmpplogintask.h"
++#include "talk/xmpp/constants.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/xmpp/saslhandler.h"
++// #include "buzz/saslmechanism.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++static const std::string XMPP_CLIENT_NAMESPACES[] = {
++  "stream", "http://etherx.jabber.org/streams",
++  "", "jabber:client",
++};
++
++static const size_t XMPP_CLIENT_NAMESPACES_LEN = 4;
++
++XmppEngine * XmppEngine::Create() {
++  return new XmppEngineImpl();
++}
++
++
++XmppEngineImpl::XmppEngineImpl() :
++    stanzaParseHandler_(this),
++    stanzaParser_(&stanzaParseHandler_),
++    engine_entered_(0),
++    user_jid_(JID_EMPTY),
++    password_(),
++    requested_resource_(STR_EMPTY),
++    tls_needed_(true),
++    login_task_(new XmppLoginTask(this)),
++    next_id_(0),
++    bound_jid_(JID_EMPTY),
++    state_(STATE_START),
++    encrypted_(false),
++    error_code_(ERROR_NONE),
++    stream_error_(NULL),
++    raised_reset_(false),
++    output_handler_(NULL),
++    session_handler_(NULL),
++    iq_entries_(new IqEntryVector()),
++    output_(new std::stringstream()),
++    sasl_handler_(NULL) {
++  for (int i = 0; i < HL_COUNT; i+= 1) {
++    stanza_handlers_[i].reset(new StanzaHandlerVector());
++  }
++}
++
++XmppEngineImpl::~XmppEngineImpl() {
++  DeleteIqCookies();
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetOutputHandler(XmppOutputHandler* output_handler) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  output_handler_ = output_handler;
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetSessionHandler(XmppSessionHandler* session_handler) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  session_handler_ = session_handler;
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::HandleInput(const char * bytes, size_t len) {
++  if (state_ < STATE_OPENING || state_ > STATE_OPEN)
++    return XMPP_RETURN_BADSTATE;
++
++  EnterExit ee(this);
++
++  stanzaParser_.Parse(bytes, len, false);
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::ConnectionClosed() {
++  if (state_ != STATE_CLOSED) {
++    EnterExit ee(this);
++    // If told that connection closed and not already closed,
++    // then connection was unpexectedly dropped.
++    SignalError(ERROR_CONNECTION_CLOSED);
++  }
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetUseTls(bool useTls) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  tls_needed_ = useTls;
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetTlsServerDomain(const std::string & tls_server_domain) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  tls_server_domain_= tls_server_domain;
++
++  return XMPP_RETURN_OK;
++}
++
++bool
++XmppEngineImpl::GetUseTls() {
++  return tls_needed_;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetUser(const Jid & jid) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  user_jid_ = jid;
++
++  return XMPP_RETURN_OK;
++}
++
++const Jid &
++XmppEngineImpl::GetUser() {
++  return user_jid_;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetSaslHandler(SaslHandler * sasl_handler) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  sasl_handler_.reset(sasl_handler);
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SetRequestedResource(const std::string & resource) {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  requested_resource_ = resource;
++
++  return XMPP_RETURN_OK;
++}
++
++const std::string &
++XmppEngineImpl::GetRequestedResource() {
++  return requested_resource_;
++}
++
++XmppReturnStatus
++XmppEngineImpl::AddStanzaHandler(XmppStanzaHandler * stanza_handler,
++                                 XmppEngine::HandlerLevel level) {
++  if (state_ == STATE_CLOSED)
++    return XMPP_RETURN_BADSTATE;
++
++  stanza_handlers_[level]->push_back(stanza_handler);
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::RemoveStanzaHandler(XmppStanzaHandler * stanza_handler) {
++
++  bool found = false;
++
++  for (int level = 0; level < HL_COUNT; level += 1) {
++    StanzaHandlerVector::iterator new_end =
++      std::remove(stanza_handlers_[level]->begin(),
++      stanza_handlers_[level]->end(),
++      stanza_handler);
++
++    if (new_end != stanza_handlers_[level]->end()) {
++      stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
++      found = true;
++    }
++  }
++
++  if (!found) {
++    return XMPP_RETURN_BADARGUMENT;
++  }
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::Connect() {
++  if (state_ != STATE_START)
++    return XMPP_RETURN_BADSTATE;
++
++  EnterExit ee(this);
++
++  // get the login task started
++  state_ = STATE_OPENING;
++  if (login_task_.get()) {
++    login_task_->IncomingStanza(NULL, false);
++    if (login_task_->IsDone())
++      login_task_.reset();
++  }
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SendStanza(const XmlElement * element) {
++  if (state_ == STATE_CLOSED)
++    return XMPP_RETURN_BADSTATE;
++
++  EnterExit ee(this);
++
++  if (login_task_.get()) {
++    // still handshaking - then outbound stanzas are queued
++    login_task_->OutgoingStanza(element);
++  } else {
++    // handshake done - send straight through
++    InternalSendStanza(element);
++  }
++
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++XmppEngineImpl::SendRaw(const std::string & text) {
++  if (state_ == STATE_CLOSED || login_task_.get())
++    return XMPP_RETURN_BADSTATE;
++
++  EnterExit ee(this);
++
++  (*output_) << text;
++
++  return XMPP_RETURN_OK;
++}
++
++std::string
++XmppEngineImpl::NextId() {
++  std::stringstream ss;
++  ss << next_id_++;
++  return ss.str();
++}
++
++XmppReturnStatus
++XmppEngineImpl::Disconnect() {
++
++  if (state_ != STATE_CLOSED) {
++    EnterExit ee(this);
++    if (state_ == STATE_OPEN)
++      *output_ << "</stream:stream>";
++    state_ = STATE_CLOSED;
++  }
++
++  return XMPP_RETURN_OK;
++}
++
++void
++XmppEngineImpl::IncomingStart(const XmlElement * pelStart) {
++  if (HasError() || raised_reset_)
++    return;
++
++  if (login_task_.get()) {
++    // start-stream should go to login task
++    login_task_->IncomingStanza(pelStart, true);
++    if (login_task_->IsDone())
++      login_task_.reset();
++  }
++  else {
++    // if not logging in, it's an error to see a start
++    SignalError(ERROR_XML);
++  }
++}
++
++void
++XmppEngineImpl::IncomingStanza(const XmlElement * stanza) {
++  if (HasError() || raised_reset_)
++    return;
++
++  if (stanza->Name() == QN_STREAM_ERROR) {
++    // Explicit XMPP stream error
++    SignalStreamError(stanza);
++  } else if (login_task_.get()) {
++    // Handle login handshake
++    login_task_->IncomingStanza(stanza, false);
++    if (login_task_->IsDone())
++      login_task_.reset();
++  } else if (HandleIqResponse(stanza)) {
++    // iq is handled by above call
++  } else {
++    // give every "peek" handler a shot at all stanzas
++    for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
++      (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
++    }
++
++    // give other handlers a shot in precedence order, stopping after handled
++    for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
++      for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
++        if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
++          goto Handled;
++      }
++    }
++
++    // If nobody wants to handle a stanza then send back an error.
++    // Only do this for IQ stanzas as messages should probably just be dropped
++    // and presence stanzas should certainly be dropped.
++    std::string type = stanza->Attr(QN_TYPE);
++    if (stanza->Name() == QN_IQ && 
++        !(type == "error" || type == "result")) {
++      SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
++    }
++  }
++  Handled:
++    ; // handled - we're done
++}
++
++void
++XmppEngineImpl::IncomingEnd(bool isError) {
++  if (HasError() || raised_reset_)
++    return;
++
++  SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED);
++}
++
++void
++XmppEngineImpl::InternalSendStart(const std::string & to) {
++  // send stream-beginning
++  // note, we put a \r\n at tne end fo the first line to cause non-XMPP
++  // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
++  *output_ << "<stream:stream to=\"" << to << "\" version=\"1.0\" "
++              "xmlns:stream=\"http://etherx.jabber.org/streams\" "
++              "xmlns=\"jabber:client\">\r\n";
++}
++
++void
++XmppEngineImpl::InternalSendStanza(const XmlElement * element) {
++  // It should really never be necessary to set a FROM attribute on a stanza.
++  // It is implied by the bind on the stream and if you get it wrong
++  // (by flipping from/to on a message?) the server will close the stream.
++  ASSERT(!element->HasAttr(QN_FROM));
++
++  // TODO: consider caching the XmlPrinter
++  XmlPrinter::PrintXml(output_.get(), element,
++            XMPP_CLIENT_NAMESPACES, XMPP_CLIENT_NAMESPACES_LEN);
++}
++
++std::string
++XmppEngineImpl::ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
++  return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
++}
++
++SaslMechanism *
++XmppEngineImpl::GetSaslMechanism(const std::string & name) {
++  return sasl_handler_->CreateSaslMechanism(name);
++}
++
++void
++XmppEngineImpl::SignalBound(const Jid & fullJid) {
++  if (state_ == STATE_OPENING) {
++    bound_jid_ = fullJid;
++    state_ = STATE_OPEN;
++  }
++}
++
++void
++XmppEngineImpl::SignalStreamError(const XmlElement * pelStreamError) {
++  if (state_ != STATE_CLOSED) {
++    stream_error_.reset(new XmlElement(*pelStreamError));
++    SignalError(ERROR_STREAM);
++  }
++}
++
++void
++XmppEngineImpl::SignalError(Error errorCode) {
++  if (state_ != STATE_CLOSED) {
++    error_code_ = errorCode;
++    state_ = STATE_CLOSED;
++  }
++}
++
++bool
++XmppEngineImpl::HasError() {
++  return error_code_ != ERROR_NONE;
++}
++
++void
++XmppEngineImpl::StartTls(const std::string & domain) {
++  if (output_handler_) {
++    output_handler_->StartTls(
++      tls_server_domain_.empty() ? domain : tls_server_domain_);
++    encrypted_ = true;
++  }
++}
++
++XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
++  : engine_(engine),
++  state_(engine->state_),
++  error_(engine->error_code_) {
++  engine->engine_entered_ += 1;
++}
++
++XmppEngineImpl::EnterExit::~EnterExit()  {
++ XmppEngineImpl* engine = engine_;
++
++ engine->engine_entered_ -= 1;
++
++ bool closing = (engine->state_ != state_ &&
++       engine->state_ == STATE_CLOSED);
++ bool flushing = closing || (engine->engine_entered_ == 0);
++
++ if (engine->output_handler_ && flushing) {
++   std::string output = engine->output_->str();
++   if (output.length() > 0)
++     engine->output_handler_->WriteOutput(output.c_str(), output.length());
++   engine->output_->str("");
++
++   if (closing) {
++     engine->output_handler_->CloseConnection();
++     engine->output_handler_ = 0;
++   }
++ }
++
++ if (engine->engine_entered_)
++   return;
++
++ if (engine->raised_reset_) {
++   engine->stanzaParser_.Reset();
++   engine->raised_reset_ = false;
++ }
++
++ if (engine->session_handler_) {
++   if (engine->state_ != state_)
++     engine->session_handler_->OnStateChange(engine->state_);
++     // Note: Handling of OnStateChange(CLOSED) should allow for the
++     // deletion of the engine, so no members should be accessed
++     // after this line.
++ }
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h	(revision 586398)
+@@ -0,0 +1,262 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmppengineimpl_h_
++#define _xmppengineimpl_h_
++
++#include <sstream>
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmppstanzaparser.h"
++
++namespace buzz {
++
++class XmppLoginTask;
++class XmppEngine;
++class XmppIqEntry;
++class SaslHandler;
++class SaslMechanism;
++
++
++//! The XMPP connection engine.
++//! This engine implements the client side of the 'core' XMPP protocol.
++//! To use it, register an XmppOutputHandler to handle socket output
++//! and pass socket input to HandleInput.  Then application code can
++//! set up the connection with a user, password, and other settings,
++//! and then call Connect() to initiate the connection.
++//! An application can listen for events and receive stanzas by
++//! registering an XmppStanzaHandler via AddStanzaHandler().
++class XmppEngineImpl : public XmppEngine {
++public:
++  XmppEngineImpl();
++  virtual ~XmppEngineImpl();
++
++  // SOCKET INPUT AND OUTPUT ------------------------------------------------
++
++  //! Registers the handler for socket output
++  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
++
++  //! Provides socket input to the engine
++  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len);
++
++  //! Advises the engine that the socket has closed
++  virtual XmppReturnStatus ConnectionClosed();
++
++  // SESSION SETUP ---------------------------------------------------------
++
++  //! Indicates the (bare) JID for the user to use.
++  virtual XmppReturnStatus SetUser(const Jid & jid);
++
++  //! Get the login (bare) JID.
++  virtual const Jid & GetUser();
++
++  //! Indicates the autentication to use.  Takes ownership of the object.
++  virtual XmppReturnStatus SetSaslHandler(SaslHandler * sasl_handler);
++
++  //! Sets whether TLS will be used within the connection (default true).
++  virtual XmppReturnStatus SetUseTls(bool useTls);
++
++  //! Sets an alternate domain from which we allows TLS certificates.
++  //! This is for use in the case where a we want to allow a proxy to
++  //! serve up its own certificate rather than one owned by the underlying
++  //! domain.
++  virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain);
++
++  //! Gets whether TLS will be used within the connection.
++  virtual bool GetUseTls();
++
++  //! Sets the request resource name, if any (optional).
++  //! Note that the resource name may be overridden by the server; after
++  //! binding, the actual resource name is available as part of FullJid().
++  virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
++
++  //! Gets the request resource name.
++  virtual const std::string & GetRequestedResource();
++
++  // SESSION MANAGEMENT ---------------------------------------------------
++
++  //! Set callback for state changes.
++  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
++
++  //! Initiates the XMPP connection.
++  //! After supplying connection settings, call this once to initiate,
++  //! (optionally) encrypt, authenticate, and bind the connection.
++  virtual XmppReturnStatus Connect();
++
++  //! The current engine state.
++  virtual State GetState() { return state_; }
++
++  //! Returns true if the connection is encrypted (under TLS)
++  virtual bool IsEncrypted() { return encrypted_; }
++
++  //! The error code.
++  //! Consult this after XmppOutputHandler.OnClose().
++  virtual Error GetError() { return error_code_; }
++
++  //! The stream:error stanza, when the error is XMPP_ERROR_STREAM.
++  //! Notice the stanza returned is owned by the XmppEngine and
++  //! is deleted when the engine is destroyed.
++  virtual const XmlElement * GetStreamError() { return stream_error_.get(); }
++
++  //! Closes down the connection.
++  //! Sends CloseConnection to output, and disconnects and registered
++  //! session handlers.  After Disconnect completes, it is guaranteed
++  //! that no further callbacks will be made.
++  virtual XmppReturnStatus Disconnect();
++
++  // APPLICATION USE -------------------------------------------------------
++
++  //! Adds a listener for session events.
++  //! Stanza delivery is chained to session handlers; the first to
++  //! return 'true' is the last to get each stanza.
++  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
++                                            XmppEngine::HandlerLevel level);
++
++  //! Removes a listener for session events.
++  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
++
++  //! Sends a stanza to the server.
++  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza);
++
++  //! Sends raw text to the server
++  virtual XmppReturnStatus SendRaw(const std::string & text);
++
++  //! Sends an iq to the server, and registers a callback for the result.
++  //! Returns the cookie passed to the result handler.
++  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
++                                  XmppIqHandler* iq_handler,
++                                  XmppIqCookie* cookie);
++
++  //! Unregisters an iq callback handler given its cookie.
++  //! No callback will come to this handler after it's unregistered.
++  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
++                                      XmppIqHandler** iq_handler);
++
++  //! Forms and sends an error in response to the given stanza.
++  //! Swaps to and from, sets type to "error", and adds error information
++  //! based on the passed code.  Text is optional and may be STR_EMPTY.
++  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
++                                           XmppStanzaError code,
++                                           const std::string & text);
++
++  //! The fullly bound JID.
++  //! This JID is only valid after binding has succeeded.  If the value
++  //! is JID_NULL, the binding has not succeeded.
++  virtual const Jid & FullJid() { return bound_jid_; }
++
++  //! The next unused iq id for this connection.
++  //! Call this when building iq stanzas, to ensure that each iq
++  //! gets its own unique id.
++  virtual std::string NextId();
++
++private:
++  friend class XmppLoginTask;
++  friend class XmppIqEntry;
++
++  void IncomingStanza(const XmlElement *pelStanza);
++  void IncomingStart(const XmlElement *pelStanza);
++  void IncomingEnd(bool isError);
++
++  void InternalSendStart(const std::string & domainName);
++  void InternalSendStanza(const XmlElement * pelStanza);
++  std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted);
++  SaslMechanism * GetSaslMechanism(const std::string & name);
++  void SignalBound(const Jid & fullJid);
++  void SignalStreamError(const XmlElement * pelStreamError);
++  void SignalError(Error errorCode);
++  bool HasError();
++  void DeleteIqCookies();
++  bool HandleIqResponse(const XmlElement * element);
++  void StartTls(const std::string & domain);
++  void RaiseReset() { raised_reset_ = true; }
++
++  class StanzaParseHandler : public XmppStanzaParseHandler {
++  public:
++    StanzaParseHandler(XmppEngineImpl * outer) : outer_(outer) {}
++    virtual void StartStream(const XmlElement * pelStream)
++      { outer_->IncomingStart(pelStream); }
++    virtual void Stanza(const XmlElement * pelStanza)
++      { outer_->IncomingStanza(pelStanza); }
++    virtual void EndStream()
++      { outer_->IncomingEnd(false); }
++    virtual void XmlError()
++      { outer_->IncomingEnd(true); }
++  private:
++    XmppEngineImpl * const outer_;
++  };
++
++  class EnterExit {
++   public:
++    EnterExit(XmppEngineImpl* engine);
++    ~EnterExit();
++   private:
++    XmppEngineImpl* engine_;
++    State state_;
++    Error error_;  
++    
++  };
++
++  friend class StanzaParseHandler;
++  friend class EnterExit;
++
++  StanzaParseHandler stanzaParseHandler_;
++  XmppStanzaParser stanzaParser_;
++
++
++  // state
++  int engine_entered_;
++  Jid user_jid_;
++  std::string password_;
++  std::string requested_resource_;
++  bool tls_needed_;
++  std::string tls_server_domain_;
++  scoped_ptr<XmppLoginTask> login_task_;
++
++  int next_id_;
++  Jid bound_jid_;
++  State state_;
++  bool encrypted_;
++  Error error_code_;
++  scoped_ptr<XmlElement> stream_error_;
++  bool raised_reset_;
++  XmppOutputHandler* output_handler_;
++  XmppSessionHandler* session_handler_;
++
++  typedef STD_VECTOR(XmppStanzaHandler*) StanzaHandlerVector;
++  scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
++
++  typedef STD_VECTOR(XmppIqEntry*) IqEntryVector;
++  scoped_ptr<IqEntryVector> iq_entries_;
++
++  scoped_ptr<SaslHandler> sasl_handler_;
++
++  scoped_ptr<std::stringstream> output_;
++};
++
++}
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc	(revision 586398)
+@@ -0,0 +1,357 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <string>
++#include <vector>
++#include <iostream>
++#include "talk/xmpp/jid.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/base/common.h"
++#include "talk/xmpp/xmppengineimpl.h"
++#include "talk/xmpp/constants.h"
++#include "talk/base/base64.h"
++#include "talk/xmpp/xmpplogintask.h"
++#include "talk/xmpp/saslmechanism.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
++  pctx_(pctx),
++  authNeeded_(true),
++  state_(LOGINSTATE_INIT),
++  pelStanza_(NULL),
++  isStart_(false),
++  iqId_(STR_EMPTY),
++  pelFeatures_(NULL),
++  fullJid_(STR_EMPTY),
++  streamId_(STR_EMPTY),
++  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
++  sasl_mech_(NULL) {
++}
++
++XmppLoginTask::~XmppLoginTask() {
++  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
++    delete (*pvecQueuedStanzas_)[i];
++}
++
++void
++XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
++  pelStanza_ = element;
++  isStart_ = isStart;
++  Advance();
++  pelStanza_ = NULL;
++  isStart_ = false;
++}
++
++const XmlElement *
++XmppLoginTask::NextStanza() {
++  const XmlElement * result = pelStanza_;
++  pelStanza_ = NULL;
++  return result;
++}
++
++bool
++XmppLoginTask::Advance() {
++
++  for (;;) {
++
++    const XmlElement * element = NULL;
++
++    switch (state_) {
++
++      case LOGINSTATE_INIT: {
++        pctx_->RaiseReset();
++        pelFeatures_.reset(NULL);
++
++        pctx_->InternalSendStart(pctx_->user_jid_.domain());
++        state_ = LOGINSTATE_STREAMSTART_SENT;
++        break;
++      }
++
++      case LOGINSTATE_STREAMSTART_SENT: {
++        if (NULL == (element = NextStanza()))
++          return true;
++
++        if (!isStart_ || !HandleStartStream(element))
++          return Failure(XmppEngine::ERROR_VERSION);
++
++        state_ = LOGINSTATE_STARTED_XMPP;
++        return true;
++      }
++
++      case LOGINSTATE_STARTED_XMPP: {
++        if (NULL == (element = NextStanza()))
++          return true;
++
++        if (!HandleFeatures(element))
++          return Failure(XmppEngine::ERROR_VERSION);
++
++        if (pctx_->tls_needed_) {
++          state_ = LOGINSTATE_TLS_INIT;
++          continue;
++        }
++
++        if (authNeeded_) {
++          state_ = LOGINSTATE_AUTH_INIT;
++          continue;
++        }
++
++        state_ = LOGINSTATE_BIND_INIT;
++        continue;
++      }
++
++      case LOGINSTATE_TLS_INIT: {
++        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
++        if (!pelTls)
++          return Failure(XmppEngine::ERROR_TLS);
++
++        XmlElement el(QN_TLS_STARTTLS, true);
++        pctx_->InternalSendStanza(&el);
++        state_ = LOGINSTATE_TLS_REQUESTED;
++        continue;
++      }
++
++      case LOGINSTATE_TLS_REQUESTED: {
++        if (NULL == (element = NextStanza()))
++          return true;
++        if (element->Name() != QN_TLS_PROCEED)
++          return Failure(XmppEngine::ERROR_TLS);
++
++        // The proper domain to verify against is the real underlying
++        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
++        // also allows matching against a proxy domain instead, if it is told
++        // to do so - see the implementation of XmppEngineImpl::StartTls and
++        // XmppEngine::SetTlsServerDomain to see how you can use that feature
++        pctx_->StartTls(pctx_->user_jid_.domain());
++        pctx_->tls_needed_ = false;
++        state_ = LOGINSTATE_INIT;
++        continue;
++      }
++
++      case LOGINSTATE_AUTH_INIT: {
++        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
++        if (!pelSaslAuth) {
++          return Failure(XmppEngine::ERROR_AUTH);
++        }
++
++        // Collect together the SASL auth mechanisms presented by the server
++        std::vector<std::string> mechanisms;
++        for (const XmlElement * pelMech =
++             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
++             pelMech;
++             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
++
++          mechanisms.push_back(pelMech->BodyText());
++        }
++
++        // Given all the mechanisms, choose the best
++        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
++        if (choice.empty()) {
++          return Failure(XmppEngine::ERROR_AUTH);
++        }
++
++        // No recognized auth mechanism - that's an error
++        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
++        if (sasl_mech_.get() == NULL) {
++          return Failure(XmppEngine::ERROR_AUTH);
++        }
++
++        // OK, let's start it.
++        XmlElement * auth = sasl_mech_->StartSaslAuth();
++        if (auth == NULL) {
++          return Failure(XmppEngine::ERROR_AUTH);
++        }
++
++        pctx_->InternalSendStanza(auth);
++        delete auth;
++        state_ = LOGINSTATE_SASL_RUNNING;
++        continue;
++      }
++        
++      case LOGINSTATE_SASL_RUNNING: {
++        if (NULL == (element = NextStanza()))
++          return true;
++        if (element->Name().Namespace() != NS_SASL)
++          return Failure(XmppEngine::ERROR_AUTH);
++        if (element->Name() == QN_SASL_CHALLENGE) {
++          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
++          if (response == NULL) {
++            return Failure(XmppEngine::ERROR_AUTH);
++          }
++          pctx_->InternalSendStanza(response);
++          delete response;
++          state_ = LOGINSTATE_SASL_RUNNING;
++          continue;
++        }
++        if (element->Name() != QN_SASL_SUCCESS) {
++          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
++        }
++
++        // Authenticated!
++        authNeeded_ = false;
++        state_ = LOGINSTATE_INIT;
++        continue;
++      }
++
++      case LOGINSTATE_BIND_INIT: {
++        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
++        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
++        if (!pelBindFeature || !pelSessionFeature)
++          return Failure(XmppEngine::ERROR_BIND);
++
++        XmlElement iq(QN_IQ);
++        iq.AddAttr(QN_TYPE, "set");
++
++        iqId_ = pctx_->NextId();
++        iq.AddAttr(QN_ID, iqId_);
++        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
++
++        if (pctx_->requested_resource_ != STR_EMPTY) {
++          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
++          iq.AddText(pctx_->requested_resource_, 2);
++        }
++        pctx_->InternalSendStanza(&iq);
++        state_ = LOGINSTATE_BIND_REQUESTED;
++        continue;
++      }
++
++      case LOGINSTATE_BIND_REQUESTED: {
++        if (NULL == (element = NextStanza()))
++          return true;
++
++        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
++            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
++          return true;
++
++        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
++            element->FirstElement()->Name() != QN_BIND_BIND)
++          return Failure(XmppEngine::ERROR_BIND);
++
++        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
++        if (!fullJid_.IsFull()) {
++          return Failure(XmppEngine::ERROR_BIND);
++        }
++
++        if (pctx_->user_jid_.domain() != STR_DEFAULT_DOMAIN &&
++            fullJid_.BareJid() != pctx_->user_jid_) {
++          return Failure(XmppEngine::ERROR_BIND);
++        }
++
++        // now request session
++        XmlElement iq(QN_IQ);
++        iq.AddAttr(QN_TYPE, "set");
++
++        iqId_ = pctx_->NextId();
++        iq.AddAttr(QN_ID, iqId_);
++        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
++        pctx_->InternalSendStanza(&iq);
++
++        state_ = LOGINSTATE_SESSION_REQUESTED;
++        continue;
++      }
++
++      case LOGINSTATE_SESSION_REQUESTED: {
++        if (NULL == (element = NextStanza()))
++          return true;
++        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
++            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
++          return false;
++
++        if (element->Attr(QN_TYPE) != "result")
++          return Failure(XmppEngine::ERROR_BIND);
++
++        pctx_->SignalBound(fullJid_);
++        FlushQueuedStanzas();
++        state_ = LOGINSTATE_DONE;
++        return true;
++      }
++
++      case LOGINSTATE_DONE:
++        return false;
++    }
++  }
++}
++
++bool
++XmppLoginTask::HandleStartStream(const XmlElement *element) {
++
++  if (element->Name() != QN_STREAM_STREAM)
++    return false;
++
++  if (element->Attr(QN_XMLNS) != "jabber:client")
++    return false;
++
++  if (element->Attr(QN_VERSION) != "1.0")
++    return false;
++
++  if (!element->HasAttr(QN_ID))
++    return false;
++  
++  streamId_ = element->Attr(QN_ID);
++
++  return true;
++}
++
++bool
++XmppLoginTask::HandleFeatures(const XmlElement *element) {
++  if (element->Name() != QN_STREAM_FEATURES)
++    return false;
++
++  pelFeatures_.reset(new XmlElement(*element));
++  return true;
++}
++
++const XmlElement *
++XmppLoginTask::GetFeature(const QName & name) {
++  return pelFeatures_->FirstNamed(name);
++}
++
++bool
++XmppLoginTask::Failure(XmppEngine::Error reason) {
++  state_ = LOGINSTATE_DONE;
++  pctx_->SignalError(reason);
++  return false;
++}
++
++void
++XmppLoginTask::OutgoingStanza(const XmlElement * element) {
++  XmlElement * pelCopy = new XmlElement(*element);
++  pvecQueuedStanzas_->push_back(pelCopy);
++}
++
++void
++XmppLoginTask::FlushQueuedStanzas() {
++  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
++    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
++    delete (*pvecQueuedStanzas_)[i];
++  }
++  pvecQueuedStanzas_->clear();
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h	(revision 586398)
+@@ -0,0 +1,59 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SASLHANDLER_H_
++#define _SASLHANDLER_H_
++
++#include <string>
++
++namespace buzz {
++
++class XmlElement;
++class SaslMechanism;
++
++// Creates mechanisms to deal with a given mechanism
++class SaslHandler {
++
++public:
++  
++  // Intended to be subclassed
++  virtual ~SaslHandler() {}
++
++  // Should pick the best method according to this handler
++  // returns the empty string if none are suitable
++  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
++
++  // Creates a SaslMechanism for the given mechanism name (you own it
++  // once you get it).
++  // If not handled, return NULL.
++  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
++};
++
++}
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h	(revision 586398)
+@@ -0,0 +1,95 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _logintask_h_
++#define _logintask_h_
++
++#include <string>
++#include "talk/xmpp/jid.h"
++#include "talk/base/scoped_ptr.h"
++#include "talk/xmpp/xmppengine.h"
++#include "talk/base/stl_decl.h"
++
++namespace buzz {
++
++class XmlElement;
++class XmppEngineImpl;
++class SaslMechanism;
++
++
++class XmppLoginTask {
++
++public:
++  XmppLoginTask(XmppEngineImpl *pctx);
++  ~XmppLoginTask();
++
++  bool IsDone()
++    { return state_ == LOGINSTATE_DONE; }
++  void IncomingStanza(const XmlElement * element, bool isStart);
++  void OutgoingStanza(const XmlElement *element);
++
++private:
++  enum LoginTaskState {
++    LOGINSTATE_INIT = 0,
++    LOGINSTATE_STREAMSTART_SENT,
++    LOGINSTATE_STARTED_XMPP,
++    LOGINSTATE_TLS_INIT,
++    LOGINSTATE_AUTH_INIT,
++    LOGINSTATE_BIND_INIT,
++    LOGINSTATE_TLS_REQUESTED,
++    LOGINSTATE_SASL_RUNNING,
++    LOGINSTATE_BIND_REQUESTED,
++    LOGINSTATE_SESSION_REQUESTED,
++    LOGINSTATE_DONE,
++  };
++
++  const XmlElement * NextStanza();
++  bool Advance();
++  bool HandleStartStream(const XmlElement * element);
++  bool HandleFeatures(const XmlElement * element);
++  const XmlElement * GetFeature(const QName & name);
++  bool Failure(XmppEngine::Error reason);
++  void FlushQueuedStanzas();
++
++  XmppEngineImpl * pctx_;
++  bool authNeeded_;
++  LoginTaskState state_;
++  const XmlElement * pelStanza_;
++  bool isStart_;
++  std::string iqId_;
++  scoped_ptr<XmlElement> pelFeatures_;
++  Jid fullJid_;
++  std::string streamId_;
++  scoped_ptr<std::vector<XmlElement *,
++          std::allocator<XmlElement *> > > pvecQueuedStanzas_;
++  
++  scoped_ptr<SaslMechanism> sasl_mech_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h	(revision 586398)
+@@ -0,0 +1,94 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPCLIENTSETTINGS_H_
++#define _XMPPCLIENTSETTINGS_H_
++
++#include "talk/p2p/base/port.h"
++#include "talk/xmpp/xmpppassword.h"
++
++namespace buzz {
++
++class XmppClientSettings {
++public:
++  XmppClientSettings() :
++    use_tls_(false), use_cookie_auth_(false), protocol_(cricket::PROTO_TCP),
++    proxy_(cricket::PROXY_NONE), proxy_port_(80), use_proxy_auth_(false) {}
++
++  void set_user(const std::string & user) { user_ = user; }
++  void set_host(const std::string & host) { host_ = host; }
++  void set_pass(const XmppPassword & pass) { pass_ = pass; }
++  void set_auth_cookie(const std::string & cookie) { auth_cookie_ = cookie; }
++  void set_resource(const std::string & resource) { resource_ = resource; }
++  void set_use_tls(bool use_tls) { use_tls_ = use_tls; }
++  void set_server(const cricket::SocketAddress & server) { 
++      server_ = server; 
++  }
++  void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
++  void set_proxy(cricket::ProxyType f) { proxy_ = f; }
++  void set_proxy_host(const std::string & host) { proxy_host_ = host; }
++  void set_proxy_port(int port) { proxy_port_ = port; };
++  void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
++  void set_proxy_user(const std::string & user) { proxy_user_ = user; }
++  void set_proxy_pass(const XmppPassword & pass) { proxy_pass_ = pass; }
++
++  const std::string & user() const { return user_; }
++  const std::string & host() const { return host_; }
++  const XmppPassword & pass() const { return pass_; }
++  const std::string & auth_cookie() const { return auth_cookie_; }
++  const std::string & resource() const { return resource_; }
++  bool use_tls() const { return use_tls_; }
++  const cricket::SocketAddress & server() const { return server_; }
++  cricket::ProtocolType protocol() const { return protocol_; }
++  cricket::ProxyType proxy() const { return proxy_; }
++  const std::string & proxy_host() const { return proxy_host_; }
++  int proxy_port() const { return proxy_port_; }
++  bool use_proxy_auth() const { return use_proxy_auth_; }
++  const std::string & proxy_user() const { return proxy_user_; }
++  const XmppPassword & proxy_pass() const { return proxy_pass_; }
++
++private:
++  std::string user_;
++  std::string host_;
++  XmppPassword pass_;
++  std::string auth_cookie_;
++  std::string resource_;
++  bool use_tls_;
++  bool use_cookie_auth_;
++  cricket::SocketAddress server_;
++  cricket::ProtocolType protocol_;
++  cricket::ProxyType proxy_;
++  std::string proxy_host_;
++  int proxy_port_;
++  bool use_proxy_auth_;
++  std::string proxy_user_;
++  XmppPassword proxy_pass_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc	(revision 586398)
+@@ -0,0 +1,477 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++extern "C" {
++#include <ctype.h>
++}
++#include <string>
++#include "talk/xmpp/jid.h"
++#include "talk/xmpp/constants.h"
++#include "talk/base/common.h"
++#include <algorithm>
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++static int AsciiToLower(int x) {
++  return (x <= 'Z' && x >= 'A') ? (x + ('a' - 'A')) : x;
++}
++
++Jid::Jid() : data_(NULL) {
++}
++
++Jid::Jid(bool is_special, const std::string & special) {
++  data_ = is_special ? new Data(special, STR_EMPTY, STR_EMPTY) : NULL;
++}
++
++Jid::Jid(const std::string & jid_string) {
++  if (jid_string == STR_EMPTY) {
++    data_ = NULL;
++    return;
++  }
++
++  // First find the slash and slice of that part
++  size_t slash = jid_string.find('/');
++  std::string resource_name = (slash == std::string::npos ? STR_EMPTY :
++                    jid_string.substr(slash + 1));
++
++  // Now look for the node
++  std::string node_name;
++  size_t at = jid_string.find('@');
++  size_t domain_begin;
++  if (at < slash && at != std::string::npos) {
++    node_name = jid_string.substr(0, at);
++    domain_begin = at + 1;
++  } else {
++    domain_begin = 0;
++  }
++
++  // Now take what is left as the domain
++  size_t domain_length =
++    (  slash == std::string::npos
++     ? jid_string.length() - domain_begin
++     : slash - domain_begin);
++
++  // avoid allocating these constants repeatedly
++  std::string domain_name;
++
++  if (domain_length == 9  && jid_string.find("gmail.com", domain_begin) == domain_begin) {
++    domain_name = STR_GMAIL_COM;
++  }
++  else if (domain_length == 14 && jid_string.find("googlemail.com", domain_begin) == domain_begin) {
++    domain_name = STR_GOOGLEMAIL_COM;
++  }
++  else if (domain_length == 10 && jid_string.find("google.com", domain_begin) == domain_begin) {
++    domain_name = STR_GOOGLE_COM;
++  }
++  else {
++    domain_name = jid_string.substr(domain_begin, domain_length);
++  }
++
++  // If the domain is empty we have a non-valid jid and we should empty
++  // everything else out
++  if (domain_name.empty()) {
++    data_ = NULL;
++    return;
++  }
++  
++  bool valid_node;
++  std::string validated_node = prepNode(node_name, 
++      node_name.begin(), node_name.end(), &valid_node);
++  bool valid_domain;
++  std::string validated_domain = prepDomain(domain_name,
++      domain_name.begin(), domain_name.end(), &valid_domain);
++  bool valid_resource;
++  std::string validated_resource = prepResource(resource_name,
++      resource_name.begin(), resource_name.end(), &valid_resource);
++
++  if (!valid_node || !valid_domain || !valid_resource) {
++    data_ = NULL;
++    return;
++  }
++
++  data_ = new Data(validated_node, validated_domain, validated_resource);
++}
++
++Jid::Jid(const std::string & node_name,
++         const std::string & domain_name,
++         const std::string & resource_name) {
++  if (domain_name.empty()) {
++    data_ = NULL;
++    return;
++  }
++
++  bool valid_node;
++  std::string validated_node = prepNode(node_name, 
++      node_name.begin(), node_name.end(), &valid_node);
++  bool valid_domain;
++  std::string validated_domain = prepDomain(domain_name,
++      domain_name.begin(), domain_name.end(), &valid_domain);
++  bool valid_resource;
++  std::string validated_resource = prepResource(resource_name,
++      resource_name.begin(), resource_name.end(), &valid_resource);
++
++  if (!valid_node || !valid_domain || !valid_resource) {
++    data_ = NULL;
++    return;
++  }
++
++  data_ = new Data(validated_node, validated_domain, validated_resource);
++}
++
++std::string Jid::Str() const {
++  if (!IsValid())
++    return STR_EMPTY;
++
++  std::string ret;
++
++  if (!data_->node_name_.empty())
++    ret = data_->node_name_ + "@";
++
++  ASSERT(data_->domain_name_ != STR_EMPTY);
++  ret += data_->domain_name_;
++
++  if (!data_->resource_name_.empty())
++    ret += "/" + data_->resource_name_;
++
++  return ret;
++}
++
++bool
++Jid::IsValid() const {
++  return data_ != NULL && !data_->domain_name_.empty();
++}
++
++bool
++Jid::IsBare() const {
++  return IsValid() &&
++         data_->resource_name_.empty();
++}
++
++bool
++Jid::IsFull() const {
++  return IsValid() &&
++         !data_->resource_name_.empty();
++}
++
++Jid
++Jid::BareJid() const {
++  if (!IsValid())
++    return Jid();
++  if (!IsFull())
++    return *this;
++  return Jid(data_->node_name_, data_->domain_name_, STR_EMPTY);
++}
++
++#if 0
++void
++Jid::set_node(const std::string & node_name) {
++    data_->node_name_ = node_name;
++}
++void
++Jid::set_domain(const std::string & domain_name) {
++    data_->domain_name_ = domain_name;
++}
++void
++Jid::set_resource(const std::string & res_name) {
++    data_->resource_name_ = res_name;
++}
++#endif
++
++bool
++Jid::BareEquals(const Jid & other) const {
++  return (other.data_ == data_ ||
++          data_ != NULL &&
++          other.data_ != NULL &&
++          other.data_->node_name_ == data_->node_name_ &&
++          other.data_->domain_name_ == data_->domain_name_);
++}
++
++bool
++Jid::operator==(const Jid & other) const {
++  return (other.data_ == data_ ||
++          data_ != NULL &&
++          other.data_ != NULL &&
++          other.data_->node_name_ == data_->node_name_ &&
++          other.data_->domain_name_ == data_->domain_name_ &&
++          other.data_->resource_name_ == data_->resource_name_);
++}
++
++int
++Jid::Compare(const Jid & other) const {
++  if (other.data_ == data_)
++    return 0;
++  if (data_ == NULL)
++    return -1;
++  if (other.data_ == NULL)
++    return 1;
++  
++  int compare_result;
++  compare_result = data_->node_name_.compare(other.data_->node_name_);
++  if (0 != compare_result)
++    return compare_result;
++  compare_result = data_->domain_name_.compare(other.data_->domain_name_);
++  if (0 != compare_result)
++    return compare_result;
++  compare_result = data_->resource_name_.compare(other.data_->resource_name_);
++  return compare_result;
++}
++
++
++// --- JID parsing code: ---
++
++// Checks and normalizes the node part of a JID.
++std::string
++Jid::prepNode(const std::string str, std::string::const_iterator start, 
++    std::string::const_iterator end, bool *valid) {
++  *valid = false;
++  std::string result;
++
++  for (std::string::const_iterator i = start; i < end; i++) {
++    bool char_valid = true;
++    char ch = *i;
++    if (ch <= 0x7F) {
++      result += prepNodeAscii(ch, &char_valid);
++    }
++    else {
++      // TODO: implement the correct stringprep protocol for these
++      result += tolower(ch);
++    }
++    if (!char_valid) {
++      return STR_EMPTY;
++    }
++  }
++
++  if (result.length() > 1023) {
++    return STR_EMPTY;
++  }
++  *valid = true;
++  return result;
++}
++
++
++// Returns the appropriate mapping for an ASCII character in a node.
++char
++Jid::prepNodeAscii(char ch, bool *valid) {
++  *valid = true;
++  switch (ch) {
++    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
++    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
++    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
++    case 'V': case 'W': case 'X': case 'Y': case 'Z':
++      return (char)(ch + ('a' - 'A'));
++
++    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
++    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
++    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
++    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
++    case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
++    case '\"': case '\'':
++    case 0x7F:
++      *valid = false;
++      return 0;
++
++    default:
++      return ch;
++  }
++}
++
++
++// Checks and normalizes the resource part of a JID.
++std::string
++Jid::prepResource(const std::string str, std::string::const_iterator start, 
++    std::string::const_iterator end, bool *valid) {
++  *valid = false;
++  std::string result;
++
++  for (std::string::const_iterator i = start; i < end; i++) {
++    bool char_valid = true;
++    char ch = *i;
++    if (ch <= 0x7F) {
++      result += prepResourceAscii(ch, &char_valid);
++    }
++    else {
++      // TODO: implement the correct stringprep protocol for these
++      result += ch;
++    }
++  }
++
++  if (result.length() > 1023) {
++    return STR_EMPTY;
++  }
++  *valid = true;
++  return result;
++}
++
++// Returns the appropriate mapping for an ASCII character in a resource.
++char
++Jid::prepResourceAscii(char ch, bool *valid) {
++  *valid = true;
++  switch (ch) {
++    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
++    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
++    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
++    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
++    case 0x7F:
++      *valid = false;
++      return 0;
++
++    default:
++      return ch;
++  }
++}
++
++// Checks and normalizes the domain part of a JID.
++std::string 
++Jid::prepDomain(const std::string str, std::string::const_iterator start, 
++    std::string::const_iterator end, bool *valid) {
++  *valid = false;
++  std::string result;
++
++  // TODO: if the domain contains a ':', then we should parse it
++  // as an IPv6 address rather than giving an error about illegal domain.
++  prepDomain(str, start, end, &result, valid);
++  if (!*valid) {
++    return STR_EMPTY;
++  }
++
++  if (result.length() > 1023) {
++    return STR_EMPTY;
++  }
++  *valid = true;
++  return result;
++}
++
++
++// Checks and normalizes an IDNA domain.
++void
++Jid::prepDomain(const std::string str, std::string::const_iterator start, 
++    std::string::const_iterator end, std::string *buf, bool *valid) {
++  *valid = false;
++  std::string::const_iterator last = start;
++  for (std::string::const_iterator i = start; i < end; i++) {
++    bool label_valid = true;
++    char ch = *i;
++    switch (ch) {
++      case 0x002E:
++#if 0 // FIX: This isn't UTF-8-aware.
++      case 0x3002:
++      case 0xFF0E:
++      case 0xFF61:
++#endif
++        prepDomainLabel(str, last, i, buf, &label_valid);
++        *buf += '.';
++        last = i + 1;
++        break;
++    }
++    if (!label_valid) {
++      return;
++    }
++  }
++  prepDomainLabel(str, last, end, buf, valid);
++}
++
++// Checks and normalizes a domain label.
++void
++Jid::prepDomainLabel(const std::string str, std::string::const_iterator start, 
++    std::string::const_iterator end, std::string *buf, bool *valid) {
++  *valid = false;
++
++  int startLen = buf->length();
++  for (std::string::const_iterator i = start; i < end; i++) {
++    bool char_valid = true;
++    char ch = *i;
++    if (ch <= 0x7F) {
++      *buf += prepDomainLabelAscii(ch, &char_valid);
++    }
++    else {
++      // TODO: implement ToASCII for these
++      *buf += ch;
++    }
++    if (!char_valid) {
++      return;
++    }
++  }
++
++  int count = buf->length() - startLen;
++  if (count == 0) {
++    return;
++  }
++  else if (count > 63) {
++    return;
++  }
++
++  // Is this check needed? See comment in prepDomainLabelAscii.
++  if ((*buf)[startLen] == '-') {
++    return;
++  }
++  if ((*buf)[buf->length() - 1] == '-') {
++    return;
++  }
++  *valid = true;
++}
++
++
++// Returns the appropriate mapping for an ASCII character in a domain label.
++char
++Jid::prepDomainLabelAscii(char ch, bool *valid) {
++  *valid = true;
++  // TODO: A literal reading of the spec seems to say that we do
++  // not need to check for these illegal characters (an "internationalized
++  // domain label" runs ToASCII with UseSTD3... set to false).  But that
++  // can't be right.  We should at least be checking that there are no '/'
++  // or '@' characters in the domain.  Perhaps we should see what others
++  // do in this case.
++
++  switch (ch) {
++    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
++    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
++    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
++    case 'V': case 'W': case 'X': case 'Y': case 'Z':
++      return (char)(ch + ('a' - 'A'));
++
++    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
++    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
++    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
++    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
++    case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
++    case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
++    case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
++    case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
++    case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
++    case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
++    case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
++      *valid = false;
++      return 0;
++
++    default:
++      return ch;
++  }
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc	(revision 586398)
+@@ -0,0 +1,168 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/xmpp/xmpptask.h"
++#include "talk/xmpp/xmppclient.h"
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/constants.h"
++
++namespace buzz {
++
++XmppTask::XmppTask(Task * parent, XmppEngine::HandlerLevel level)
++ : Task(parent), client_(NULL) {
++  XmppClient * client = (XmppClient*)parent->GetParent(XMPP_CLIENT_TASK_CODE);
++  client_ = client;
++  id_ = client->NextId();
++  client->AddXmppTask(this, level);
++  client->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
++}
++
++XmppTask::~XmppTask() {
++  StopImpl();
++}
++
++void
++XmppTask::StopImpl() {
++  while (NextStanza() != NULL) {}
++  if (client_) {
++    client_->RemoveXmppTask(this);
++    client_->SignalDisconnected.disconnect(this);
++    client_ = NULL;
++  }
++}
++
++XmppReturnStatus
++XmppTask::SendStanza(const XmlElement * stanza) {
++  if (client_ == NULL)
++    return XMPP_RETURN_BADSTATE;
++  return client_->SendStanza(stanza);
++}
++
++XmppReturnStatus
++XmppTask::SendStanzaError(const XmlElement * element_original,
++                                XmppStanzaError code,
++                                const std::string & text) {
++  if (client_ == NULL)
++    return XMPP_RETURN_BADSTATE;
++  return client_->SendStanzaError(element_original, code, text);
++}
++
++void
++XmppTask::Stop() {
++  StopImpl();
++  Task::Stop();
++}
++
++void
++XmppTask::OnDisconnect() {
++  Error();
++}
++
++void
++XmppTask::QueueStanza(const XmlElement * stanza) {
++  stanza_queue_.push_back(new XmlElement(*stanza));
++  Wake();
++}
++
++const XmlElement *
++XmppTask::NextStanza() {
++  XmlElement * result = NULL;
++  if (!stanza_queue_.empty()) {
++    result = stanza_queue_.front();
++    stanza_queue_.pop_front();
++  }
++  next_stanza_.reset(result);
++  return result;
++}
++
++XmlElement *
++XmppTask::MakeIq(const std::string & type,
++  const buzz::Jid & to, const std::string id) {
++  XmlElement * result = new XmlElement(QN_IQ);
++  if (!type.empty())
++    result->AddAttr(QN_TYPE, type);
++  if (to != JID_EMPTY)
++    result->AddAttr(QN_TO, to.Str());
++  if (!id.empty())
++    result->AddAttr(QN_ID, id);
++  return result;
++}
++
++XmlElement *
++XmppTask::MakeIqResult(const XmlElement * query) {
++  XmlElement * result = new XmlElement(QN_IQ);
++  result->AddAttr(QN_TYPE, STR_RESULT);
++  if (query->HasAttr(QN_FROM)) {
++    result->AddAttr(QN_TO, query->Attr(QN_FROM));
++  }
++  result->AddAttr(QN_ID, query->Attr(QN_ID));
++  return result;
++}
++
++bool
++XmppTask::MatchResponseIq(const XmlElement * stanza,
++    const Jid & to, const std::string & id) {
++  if (stanza->Name() != QN_IQ)
++    return false;
++
++  if (stanza->Attr(QN_ID) != id)
++    return false;
++
++  Jid from(stanza->Attr(QN_FROM));
++  if (from != to) {
++    Jid me = client_->jid();
++    // we address the server as "", but it is legal for the server
++    // to identify itself with "domain" or "myself at domain"
++    if (to != JID_EMPTY) {
++      return false;
++    }
++
++    if (from != Jid(me.domain()) && from != me.BareJid()) {
++      return false;
++    }
++  }
++
++
++  return true;
++}
++
++bool
++XmppTask::MatchRequestIq(const XmlElement * stanza,
++    const std::string & type, const QName & qn) {
++  if (stanza->Name() != QN_IQ)
++    return false;
++
++  if (stanza->Attr(QN_TYPE) != type)
++    return false;
++
++  if (stanza->FirstNamed(qn) == NULL)
++    return false;
++
++  return true;
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h	(revision 586398)
+@@ -0,0 +1,144 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef _jid_h_
++#define _jid_h_
++
++#include <string>
++#include "talk/xmllite/xmlconstants.h"
++
++namespace buzz {
++
++//! The Jid class encapsulates and provides parsing help for Jids
++//! A Jid consists of three parts. The node, the domain and the resource.
++//!
++//! node at domain/resource
++//!
++//! The node and resource are both optional.  A valid jid is defined to have
++//! a domain.  A bare jid is defined to not have a resource and a full jid
++//! *does* have a resource.
++class Jid {
++public:
++  explicit Jid();
++  explicit Jid(const std::string & jid_string);
++  explicit Jid(const std::string & node_name,
++               const std::string & domain_name,
++               const std::string & resource_name);
++  explicit Jid(bool special, const std::string & special_string);
++  Jid(const Jid & jid) : data_(jid.data_) {
++    if (data_ != NULL) {
++      data_->AddRef();
++    }
++  }
++  Jid & operator=(const Jid & jid) {
++    if (jid.data_ != NULL) {
++      jid.data_->AddRef();
++    }
++    if (data_ != NULL) {
++      data_->Release();
++    }
++    data_ = jid.data_;
++    return *this;
++  }
++  ~Jid() {
++    if (data_ != NULL) {
++      data_->Release();
++    }
++  }
++  
++
++  const std::string & node() const { return !data_ ? STR_EMPTY : data_->node_name_; }
++  // void set_node(const std::string & node_name);
++  const std::string & domain() const { return !data_ ? STR_EMPTY : data_->domain_name_; }
++  // void set_domain(const std::string & domain_name);
++  const std::string & resource() const { return !data_ ? STR_EMPTY : data_->resource_name_; }
++  // void set_resource(const std::string & res_name);
++
++  std::string Str() const;
++  Jid BareJid() const;
++
++  bool IsValid() const;
++  bool IsBare() const;
++  bool IsFull() const;
++
++  bool BareEquals(const Jid & other) const;
++
++  bool operator==(const Jid & other) const;
++  bool operator!=(const Jid & other) const { return !operator==(other); }
++
++  bool operator<(const Jid & other) const { return Compare(other) < 0; };
++  bool operator>(const Jid & other) const { return Compare(other) > 0; };
++  
++  int Compare(const Jid & other) const;
++
++
++private:
++
++  static std::string prepNode(const std::string str, 
++      std::string::const_iterator start, std::string::const_iterator end, 
++      bool *valid);
++  static char prepNodeAscii(char ch, bool *valid);
++  static std::string prepResource(const std::string str, 
++      std::string::const_iterator start, std::string::const_iterator end, 
++      bool *valid);
++  static char prepResourceAscii(char ch, bool *valid);
++  static std::string prepDomain(const std::string str, 
++      std::string::const_iterator start,  std::string::const_iterator end, 
++      bool *valid);
++  static void prepDomain(const std::string str, 
++      std::string::const_iterator start, std::string::const_iterator end, 
++      std::string *buf, bool *valid);
++  static void prepDomainLabel(const std::string str, 
++      std::string::const_iterator start, std::string::const_iterator end, 
++      std::string *buf, bool *valid);
++  static char prepDomainLabelAscii(char ch, bool *valid);
++
++  class Data {
++  public:
++    Data() : refcount_(1) {}
++    Data(const std::string & node, const std::string &domain, const std::string & resource) :
++      node_name_(node),
++      domain_name_(domain),
++      resource_name_(resource),
++      refcount_(1) {}
++    const std::string node_name_;
++    const std::string domain_name_;
++    const std::string resource_name_;
++
++    void AddRef() { refcount_++; }
++    void Release() { if (!--refcount_) delete this; }
++  private:
++    int refcount_;
++  };
++
++  Data * data_;
++};
++
++}
++
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h	(revision 586398)
+@@ -0,0 +1,163 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPPASSWORD_H_
++#define _XMPPPASSWORD_H_
++
++#include "talk/base/linked_ptr.h"
++#include "talk/base/scoped_ptr.h"
++
++namespace buzz {
++
++class XmppPasswordImpl {
++public:
++  virtual ~XmppPasswordImpl() {}
++  virtual size_t GetLength() const = 0;
++  virtual void CopyTo(char * dest, bool nullterminate) const = 0;
++  virtual std::string UrlEncode() const = 0;
++  virtual XmppPasswordImpl * Copy() const = 0;
++};
++
++class EmptyXmppPasswordImpl : public XmppPasswordImpl {
++public:
++  virtual ~EmptyXmppPasswordImpl() {}
++  virtual size_t GetLength() const { return 0; }
++  virtual void CopyTo(char * dest, bool nullterminate) const {
++    if (nullterminate) {
++      *dest = '\0';
++    }
++  }
++  virtual std::string UrlEncode() const { return ""; }
++  virtual XmppPasswordImpl * Copy() const { return new EmptyXmppPasswordImpl(); }
++};
++
++class XmppPassword {
++public:
++  XmppPassword() : impl_(new EmptyXmppPasswordImpl()) {}
++  size_t GetLength() const { return impl_->GetLength(); }
++  void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
++  XmppPassword(const XmppPassword & other) : impl_(other.impl_->Copy()) {}
++  explicit XmppPassword(const XmppPasswordImpl & impl) : impl_(impl.Copy()) {}
++  XmppPassword & operator=(const XmppPassword & other) {
++    if (this != &other) {
++      impl_.reset(other.impl_->Copy());
++    }
++    return *this;
++  }
++  void Clear() { impl_.reset(new EmptyXmppPasswordImpl()); }
++  std::string UrlEncode() const { return impl_->UrlEncode(); }
++  
++private:
++  scoped_ptr<const XmppPasswordImpl> impl_;
++};
++
++
++// Used for constructing strings where a password is involved and we
++// need to ensure that we zero memory afterwards
++class FormatXmppPassword {
++public:
++  FormatXmppPassword() {
++    storage_ = new char[32];
++    capacity_ = 32;
++    length_ = 0;
++    storage_[0] = 0;
++  }
++  
++  void Append(const std::string & text) {
++    Append(text.data(), text.length());
++  }
++
++  void Append(const char * data, size_t length) {
++    EnsureStorage(length_ + length + 1);
++    memcpy(storage_ + length_, data, length);
++    length_ += length;
++    storage_[length_] = '\0';
++  }
++  
++  void Append(const XmppPassword * password) {
++    size_t len = password->GetLength();
++    EnsureStorage(length_ + len + 1);
++    password->CopyTo(storage_ + length_, true);
++    length_ += len;
++  }
++
++  size_t GetLength() {
++    return length_;
++  }
++
++  const char * GetData() {
++    return storage_;
++  }
++
++
++  // Ensures storage of at least n bytes
++  void EnsureStorage(size_t n) {
++    if (capacity_ >= n) {
++      return;
++    }
++
++    size_t old_capacity = capacity_;
++    char * old_storage = storage_;
++
++    for (;;) {
++      capacity_ *= 2;
++      if (capacity_ >= n)
++        break;
++    }
++
++    storage_ = new char[capacity_];
++
++    if (old_capacity) {
++      memcpy(storage_, old_storage, length_);
++    
++      // zero memory in a way that an optimizer won't optimize it out
++      old_storage[0] = 0;
++      for (size_t i = 1; i < old_capacity; i++) {
++        old_storage[i] = old_storage[i - 1];
++      }
++      delete[] old_storage;
++    }
++  }  
++
++  ~FormatXmppPassword() {
++    if (capacity_) {
++      storage_[0] = 0;
++      for (size_t i = 1; i < capacity_; i++) {
++        storage_[i] = storage_[i - 1];
++      }
++    }
++    delete[] storage_;
++  }
++private:
++  char * storage_;
++  size_t capacity_;
++  size_t length_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h	(revision 586398)
+@@ -0,0 +1,113 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPTASK_H_
++#define _XMPPTASK_H_
++
++#include <string>
++#include <deque>
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/xmppengine.h"
++#include "talk/base/task.h"
++
++namespace buzz {
++
++/////////////////////////////////////////////////////////////////////
++//
++// XMPPTASK
++//
++/////////////////////////////////////////////////////////////////////
++//
++// See Task and XmppClient first.
++//
++// XmppTask is a task that is designed to go underneath XmppClient and be
++// useful there.  It has a way of finding its XmppClient parent so you
++// can have it nested arbitrarily deep under an XmppClient and it can
++// still find the XMPP services.
++//
++// Tasks register themselves to listen to particular kinds of stanzas
++// that are sent out by the client.  Rather than processing stanzas
++// right away, they should decide if they own the sent stanza,
++// and if so, queue it and Wake() the task, or if a stanza does not belong
++// to you, return false right away so the next XmppTask can take a crack.
++// This technique (synchronous recognize, but asynchronous processing)
++// allows you to have arbitrary logic for recognizing stanzas yet still,
++// for example, disconnect a client while processing a stanza -
++// without reentrancy problems.
++//
++/////////////////////////////////////////////////////////////////////
++
++class XmppClient;
++
++class XmppTask :
++  public Task,
++  public XmppStanzaHandler,
++  public sigslot::has_slots<>
++{
++public:
++  XmppTask(Task * parent, XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
++  virtual ~XmppTask();
++
++  virtual XmppClient * GetClient() const { return client_; }
++  std::string task_id() const { return id_; }
++
++protected:
++  friend class XmppClient;
++  
++  XmppReturnStatus SendStanza(const XmlElement * stanza);
++  XmppReturnStatus SetResult(const std::string & code);
++  XmppReturnStatus SendStanzaError(const XmlElement * element_original,
++                                XmppStanzaError code,
++                                const std::string & text);
++
++  virtual void Stop();
++  virtual bool HandleStanza(const XmlElement * stanza) { return false; }
++  virtual void OnDisconnect();
++  virtual int ProcessReponse() { return STATE_DONE; }
++
++  void QueueStanza(const XmlElement * stanza);
++  const XmlElement * NextStanza();
++
++  bool MatchResponseIq(const XmlElement * stanza, const Jid & to, const std::string & task_id);
++  bool MatchRequestIq(const XmlElement * stanza, const std::string & type, const QName & qn);
++  XmlElement *MakeIqResult(const XmlElement * query);
++  XmlElement *MakeIq(const std::string & type,
++    const Jid & to, const std::string task_id);
++
++private:
++  void StopImpl();
++  
++  XmppClient * client_;
++  std::deque<XmlElement *> stanza_queue_;
++  scoped_ptr<XmlElement> next_stanza_;
++  std::string id_;
++  
++};   
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc	(revision 586398)
+@@ -0,0 +1,331 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <string>
++#include "talk/base/basicdefs.h"
++#include "talk/xmllite/xmlconstants.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/qname.h"
++#include "talk/xmpp/jid.h"
++#include "talk/xmpp/constants.h"
++namespace buzz {
++
++const Jid JID_EMPTY(STR_EMPTY);
++
++const std::string & Constants::ns_client() {
++  static const std::string ns_client_("jabber:client");
++  return ns_client_;
++}
++
++const std::string & Constants::ns_server() {
++  static const std::string ns_server_("jabber:server");
++  return ns_server_;
++}
++
++const std::string & Constants::ns_stream() {
++  static const std::string ns_stream_("http://etherx.jabber.org/streams");
++  return ns_stream_;
++}
++
++const std::string & Constants::ns_xstream() {
++  static const std::string ns_xstream_("urn:ietf:params:xml:ns:xmpp-streams");
++  return ns_xstream_;
++}
++
++const std::string & Constants::ns_tls() {
++  static const std::string ns_tls_("urn:ietf:params:xml:ns:xmpp-tls");
++  return ns_tls_;
++}
++
++const std::string & Constants::ns_sasl() {
++  static const std::string ns_sasl_("urn:ietf:params:xml:ns:xmpp-sasl");
++  return ns_sasl_;
++}
++
++const std::string & Constants::ns_bind() {
++  static const std::string ns_bind_("urn:ietf:params:xml:ns:xmpp-bind");
++  return ns_bind_;
++}
++
++const std::string & Constants::ns_dialback() {
++  static const std::string ns_dialback_("jabber:server:dialback");
++  return ns_dialback_;
++}
++
++const std::string & Constants::ns_session() {
++  static const std::string ns_session_("urn:ietf:params:xml:ns:xmpp-session");
++  return ns_session_;
++}
++
++const std::string & Constants::ns_stanza() {
++  static const std::string ns_stanza_("urn:ietf:params:xml:ns:xmpp-stanzas");
++  return ns_stanza_;
++}
++
++const std::string & Constants::ns_privacy() {
++  static const std::string ns_privacy_("jabber:iq:privacy");
++  return ns_privacy_;
++}
++
++const std::string & Constants::ns_roster() {
++  static const std::string ns_roster_("jabber:iq:roster");
++  return ns_roster_;
++}
++
++const std::string & Constants::ns_vcard() {
++  static const std::string ns_vcard_("vcard-temp");
++  return ns_vcard_;
++}
++
++const std::string & Constants::str_client() {
++  static const std::string str_client_("client");
++  return str_client_;
++}
++
++const std::string & Constants::str_server() {
++  static const std::string str_server_("server");
++  return str_server_;
++}
++
++const std::string & Constants::str_stream() {
++  static const std::string str_stream_("stream");
++  return str_stream_;
++}
++
++const std::string STR_GET("get");
++const std::string STR_SET("set");
++const std::string STR_RESULT("result");
++const std::string STR_ERROR("error");
++
++const std::string STR_FROM("from");
++const std::string STR_TO("to");
++const std::string STR_BOTH("both");
++const std::string STR_REMOVE("remove");
++
++const std::string STR_UNAVAILABLE("unavailable");
++const std::string STR_INVISIBLE("invisible");
++
++const std::string STR_GOOGLE_COM("google.com");
++const std::string STR_GMAIL_COM("gmail.com");
++const std::string STR_GOOGLEMAIL_COM("googlemail.com");
++const std::string STR_DEFAULT_DOMAIN("default.talk.google.com");
++const std::string STR_X("x");
++
++const QName QN_STREAM_STREAM(true, NS_STREAM, STR_STREAM);
++const QName QN_STREAM_FEATURES(true, NS_STREAM, "features");
++const QName QN_STREAM_ERROR(true, NS_STREAM, "error");
++
++const QName QN_XSTREAM_BAD_FORMAT(true, NS_XSTREAM, "bad-format");
++const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX(true, NS_XSTREAM, "bad-namespace-prefix");
++const QName QN_XSTREAM_CONFLICT(true, NS_XSTREAM, "conflict");
++const QName QN_XSTREAM_CONNECTION_TIMEOUT(true, NS_XSTREAM, "connection-timeout");
++const QName QN_XSTREAM_HOST_GONE(true, NS_XSTREAM, "host-gone");
++const QName QN_XSTREAM_HOST_UNKNOWN(true, NS_XSTREAM, "host-unknown");
++const QName QN_XSTREAM_IMPROPER_ADDRESSIING(true, NS_XSTREAM, "improper-addressing");
++const QName QN_XSTREAM_INTERNAL_SERVER_ERROR(true, NS_XSTREAM, "internal-server-error");
++const QName QN_XSTREAM_INVALID_FROM(true, NS_XSTREAM, "invalid-from");
++const QName QN_XSTREAM_INVALID_ID(true, NS_XSTREAM, "invalid-id");
++const QName QN_XSTREAM_INVALID_NAMESPACE(true, NS_XSTREAM, "invalid-namespace");
++const QName QN_XSTREAM_INVALID_XML(true, NS_XSTREAM, "invalid-xml");
++const QName QN_XSTREAM_NOT_AUTHORIZED(true, NS_XSTREAM, "not-authorized");
++const QName QN_XSTREAM_POLICY_VIOLATION(true, NS_XSTREAM, "policy-violation");
++const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED(true, NS_XSTREAM, "remote-connection-failed");
++const QName QN_XSTREAM_RESOURCE_CONSTRAINT(true, NS_XSTREAM, "resource-constraint");
++const QName QN_XSTREAM_RESTRICTED_XML(true, NS_XSTREAM, "restricted-xml");
++const QName QN_XSTREAM_SEE_OTHER_HOST(true, NS_XSTREAM, "see-other-host");
++const QName QN_XSTREAM_SYSTEM_SHUTDOWN(true, NS_XSTREAM, "system-shutdown");
++const QName QN_XSTREAM_UNDEFINED_CONDITION(true, NS_XSTREAM, "undefined-condition");
++const QName QN_XSTREAM_UNSUPPORTED_ENCODING(true, NS_XSTREAM, "unsupported-encoding");
++const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE(true, NS_XSTREAM, "unsupported-stanza-type");
++const QName QN_XSTREAM_UNSUPPORTED_VERSION(true, NS_XSTREAM, "unsupported-version");
++const QName QN_XSTREAM_XML_NOT_WELL_FORMED(true, NS_XSTREAM, "xml-not-well-formed");
++const QName QN_XSTREAM_TEXT(true, NS_XSTREAM, "text");
++
++const QName QN_TLS_STARTTLS(true, NS_TLS, "starttls");
++const QName QN_TLS_REQUIRED(true, NS_TLS, "required");
++const QName QN_TLS_PROCEED(true, NS_TLS, "proceed");
++const QName QN_TLS_FAILURE(true, NS_TLS, "failure");
++
++const QName QN_SASL_MECHANISMS(true, NS_SASL, "mechanisms");
++const QName QN_SASL_MECHANISM(true, NS_SASL, "mechanism");
++const QName QN_SASL_AUTH(true, NS_SASL, "auth");
++const QName QN_SASL_CHALLENGE(true, NS_SASL, "challenge");
++const QName QN_SASL_RESPONSE(true, NS_SASL, "response");
++const QName QN_SASL_ABORT(true, NS_SASL, "abort");
++const QName QN_SASL_SUCCESS(true, NS_SASL, "success");
++const QName QN_SASL_FAILURE(true, NS_SASL, "failure");
++const QName QN_SASL_ABORTED(true, NS_SASL, "aborted");
++const QName QN_SASL_INCORRECT_ENCODING(true, NS_SASL, "incorrect-encoding");
++const QName QN_SASL_INVALID_AUTHZID(true, NS_SASL, "invalid-authzid");
++const QName QN_SASL_INVALID_MECHANISM(true, NS_SASL, "invalid-mechanism");
++const QName QN_SASL_MECHANISM_TOO_WEAK(true, NS_SASL, "mechanism-too-weak");
++const QName QN_SASL_NOT_AUTHORIZED(true, NS_SASL, "not-authorized");
++const QName QN_SASL_TEMPORARY_AUTH_FAILURE(true, NS_SASL, "temporary-auth-failure");
++
++const QName QN_DIALBACK_RESULT(true, NS_DIALBACK, "result");
++const QName QN_DIALBACK_VERIFY(true, NS_DIALBACK, "verify");
++
++const QName QN_STANZA_BAD_REQUEST(true, NS_STANZA, "bad-request");
++const QName QN_STANZA_CONFLICT(true, NS_STANZA, "conflict");
++const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED(true, NS_STANZA, "feature-not-implemented");
++const QName QN_STANZA_FORBIDDEN(true, NS_STANZA, "forbidden");
++const QName QN_STANZA_GONE(true, NS_STANZA, "gone");
++const QName QN_STANZA_INTERNAL_SERVER_ERROR(true, NS_STANZA, "internal-server-error");
++const QName QN_STANZA_ITEM_NOT_FOUND(true, NS_STANZA, "item-not-found");
++const QName QN_STANZA_JID_MALFORMED(true, NS_STANZA, "jid-malformed");
++const QName QN_STANZA_NOT_ACCEPTABLE(true, NS_STANZA, "not-acceptable");
++const QName QN_STANZA_NOT_ALLOWED(true, NS_STANZA, "not-allowed");
++const QName QN_STANZA_PAYMENT_REQUIRED(true, NS_STANZA, "payment-required");
++const QName QN_STANZA_RECIPIENT_UNAVAILABLE(true, NS_STANZA, "recipient-unavailable");
++const QName QN_STANZA_REDIRECT(true, NS_STANZA, "redirect");
++const QName QN_STANZA_REGISTRATION_REQUIRED(true, NS_STANZA, "registration-required");
++const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND(true, NS_STANZA, "remote-server-not-found");
++const QName QN_STANZA_REMOTE_SERVER_TIMEOUT(true, NS_STANZA, "remote-server-timeout");
++const QName QN_STANZA_RESOURCE_CONSTRAINT(true, NS_STANZA, "resource-constraint");
++const QName QN_STANZA_SERVICE_UNAVAILABLE(true, NS_STANZA, "service-unavailable");
++const QName QN_STANZA_SUBSCRIPTION_REQUIRED(true, NS_STANZA, "subscription-required");
++const QName QN_STANZA_UNDEFINED_CONDITION(true, NS_STANZA, "undefined-condition");
++const QName QN_STANZA_UNEXPECTED_REQUEST(true, NS_STANZA, "unexpected-request");
++const QName QN_STANZA_TEXT(true, NS_STANZA, "text");
++
++const QName QN_BIND_BIND(true, NS_BIND, "bind");
++const QName QN_BIND_RESOURCE(true, NS_BIND, "resource");
++const QName QN_BIND_JID(true, NS_BIND, "jid");
++
++const QName QN_MESSAGE(true, NS_CLIENT, "message");
++const QName QN_BODY(true, NS_CLIENT, "body");
++const QName QN_SUBJECT(true, NS_CLIENT, "subject");
++const QName QN_THREAD(true, NS_CLIENT, "thread");
++const QName QN_PRESENCE(true, NS_CLIENT, "presence");
++const QName QN_SHOW(true, NS_CLIENT, "show");
++const QName QN_STATUS(true, NS_CLIENT, "status");
++const QName QN_LANG(true, NS_CLIENT, "lang");
++const QName QN_PRIORITY(true, NS_CLIENT, "priority");
++const QName QN_IQ(true, NS_CLIENT, "iq");
++const QName QN_ERROR(true, NS_CLIENT, "error");
++
++const QName QN_SERVER_MESSAGE(true, NS_SERVER, "message");
++const QName QN_SERVER_BODY(true, NS_SERVER, "body");
++const QName QN_SERVER_SUBJECT(true, NS_SERVER, "subject");
++const QName QN_SERVER_THREAD(true, NS_SERVER, "thread");
++const QName QN_SERVER_PRESENCE(true, NS_SERVER, "presence");
++const QName QN_SERVER_SHOW(true, NS_SERVER, "show");
++const QName QN_SERVER_STATUS(true, NS_SERVER, "status");
++const QName QN_SERVER_LANG(true, NS_SERVER, "lang");
++const QName QN_SERVER_PRIORITY(true, NS_SERVER, "priority");
++const QName QN_SERVER_IQ(true, NS_SERVER, "iq");
++const QName QN_SERVER_ERROR(true, NS_SERVER, "error");
++
++const QName QN_SESSION_SESSION(true, NS_SESSION, "session");
++
++const QName QN_PRIVACY_QUERY(true, NS_PRIVACY, "query");
++const QName QN_PRIVACY_ACTIVE(true, NS_PRIVACY, "active");
++const QName QN_PRIVACY_DEFAULT(true, NS_PRIVACY, "default");
++const QName QN_PRIVACY_LIST(true, NS_PRIVACY, "list");
++const QName QN_PRIVACY_ITEM(true, NS_PRIVACY, "item");
++const QName QN_PRIVACY_IQ(true, NS_PRIVACY, "iq");
++const QName QN_PRIVACY_MESSAGE(true, NS_PRIVACY, "message");
++const QName QN_PRIVACY_PRESENCE_IN(true, NS_PRIVACY, "presence-in");
++const QName QN_PRIVACY_PRESENCE_OUT(true, NS_PRIVACY, "presence-out");
++
++const QName QN_ROSTER_QUERY(true, NS_ROSTER, "query");
++const QName QN_ROSTER_ITEM(true, NS_ROSTER, "item");
++const QName QN_ROSTER_GROUP(true, NS_ROSTER, "group");
++
++const QName QN_VCARD_QUERY(true, NS_VCARD, "vCard");
++const QName QN_VCARD_FN(true, NS_VCARD, "FN");
++
++const QName QN_XML_LANG(true, NS_XML, "lang");
++
++const std::string STR_TYPE("type");
++const std::string STR_ID("id");
++const std::string STR_NAME("name");
++const std::string STR_JID("jid");
++const std::string STR_SUBSCRIPTION("subscription");
++const std::string STR_ASK("ask");
++
++const QName QN_ENCODING(true, STR_EMPTY, STR_ENCODING);
++const QName QN_VERSION(true, STR_EMPTY, STR_VERSION);
++const QName QN_TO(true, STR_EMPTY, "to");
++const QName QN_FROM(true, STR_EMPTY, "from");
++const QName QN_TYPE(true, STR_EMPTY, "type");
++const QName QN_ID(true, STR_EMPTY, "id");
++const QName QN_CODE(true, STR_EMPTY, "code");
++const QName QN_NAME(true, STR_EMPTY, "name");
++const QName QN_VALUE(true, STR_EMPTY, "value");
++const QName QN_ACTION(true, STR_EMPTY, "action");
++const QName QN_ORDER(true, STR_EMPTY, "order");
++const QName QN_MECHANISM(true, STR_EMPTY, "mechanism");
++const QName QN_ASK(true, STR_EMPTY, "ask");
++const QName QN_JID(true, STR_EMPTY, "jid");
++const QName QN_SUBSCRIPTION(true, STR_EMPTY, "subscription");
++const QName QN_SOURCE(true, STR_EMPTY, "source");
++
++const QName QN_XMLNS_CLIENT(true, NS_XMLNS, STR_CLIENT);
++const QName QN_XMLNS_SERVER(true, NS_XMLNS, STR_SERVER);
++const QName QN_XMLNS_STREAM(true, NS_XMLNS, STR_STREAM);
++
++// Presence
++const std::string STR_SHOW_AWAY("away");
++const std::string STR_SHOW_CHAT("chat");
++const std::string STR_SHOW_DND("dnd");
++const std::string STR_SHOW_XA("xa");
++
++// Subscription
++const std::string STR_SUBSCRIBE("subscribe");
++const std::string STR_SUBSCRIBED("subscribed");
++const std::string STR_UNSUBSCRIBE("unsubscribe");
++const std::string STR_UNSUBSCRIBED("unsubscribed");
++
++
++// JEP 0030
++const QName QN_NODE(true, STR_EMPTY, "node");
++const QName QN_CATEGORY(true, STR_EMPTY, "category");
++const QName QN_VAR(true, STR_EMPTY, "var");
++const std::string NS_DISCO_INFO("http://jabber.org/protocol/disco#info");
++const std::string NS_DISCO_ITEMS("http://jabber.org/protocol/disco#items");
++const QName QN_DISCO_INFO_QUERY(true, NS_DISCO_INFO, "query");
++const QName QN_DISCO_IDENTITY(true, NS_DISCO_INFO, "identity");
++const QName QN_DISCO_FEATURE(true, NS_DISCO_INFO, "feature");
++
++const QName QN_DISCO_ITEMS_QUERY(true, NS_DISCO_ITEMS, "query");
++const QName QN_DISCO_ITEM(true, NS_DISCO_ITEMS, "item");
++
++
++// JEP 0115
++const std::string NS_CAPS("http://jabber.org/protocol/caps");
++const QName QN_CAPS_C(true, NS_CAPS, "c");
++const QName QN_VER(true, STR_EMPTY, "ver");
++const QName QN_EXT(true, STR_EMPTY, "ext");
++
++// JEP 0091 Delayed Delivery
++const std::string kNSDelay("jabber:x:delay");
++const QName kQnDelayX(true, kNSDelay, "x");
++const QName kQnStamp(true, STR_EMPTY, "stamp");
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h	(revision 586398)
+@@ -0,0 +1,332 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmppengine_h_
++#define _xmppengine_h_
++
++// also part of the API
++#include "talk/xmpp/jid.h"
++#include "talk/xmllite/qname.h"
++#include "talk/xmllite/xmlelement.h"
++
++
++namespace buzz {
++
++class XmppEngine;
++class SaslHandler;
++typedef void * XmppIqCookie;
++
++//! XMPP stanza error codes.
++//! Used in XmppEngine.SendStanzaError().
++enum XmppStanzaError {
++  XSE_BAD_REQUEST,
++  XSE_CONFLICT,
++  XSE_FEATURE_NOT_IMPLEMENTED,
++  XSE_FORBIDDEN,
++  XSE_GONE,
++  XSE_INTERNAL_SERVER_ERROR,
++  XSE_ITEM_NOT_FOUND,
++  XSE_JID_MALFORMED,
++  XSE_NOT_ACCEPTABLE,
++  XSE_NOT_ALLOWED,
++  XSE_PAYMENT_REQUIRED,
++  XSE_RECIPIENT_UNAVAILABLE,
++  XSE_REDIRECT,
++  XSE_REGISTRATION_REQUIRED,
++  XSE_SERVER_NOT_FOUND,
++  XSE_SERVER_TIMEOUT,
++  XSE_RESOURCE_CONSTRAINT,
++  XSE_SERVICE_UNAVAILABLE,
++  XSE_SUBSCRIPTION_REQUIRED,
++  XSE_UNDEFINED_CONDITION,
++  XSE_UNEXPECTED_REQUEST,
++};
++
++// XmppReturnStatus
++//    This is used by API functions to synchronously return status.
++enum XmppReturnStatus {
++  XMPP_RETURN_OK,
++  XMPP_RETURN_BADARGUMENT,
++  XMPP_RETURN_BADSTATE,
++  XMPP_RETURN_PENDING,
++  XMPP_RETURN_UNEXPECTED,
++  XMPP_RETURN_NOTYETIMPLEMENTED,
++};
++
++//! Callback for socket output for an XmppEngine connection.
++//! Register via XmppEngine.SetOutputHandler.  An XmppEngine
++//! can call back to this handler while it is processing
++//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
++class XmppOutputHandler {
++public:
++
++  //! Deliver the specified bytes to the XMPP socket.
++  virtual void WriteOutput(const char * bytes, size_t len) = 0;
++
++  //! Initiate TLS encryption on the socket.
++  //! The implementation must verify that the SSL
++  //! certificate matches the given domainname.
++  virtual void StartTls(const std::string & domainname) = 0;
++
++  //! Called when engine wants the connecton closed.
++  virtual void CloseConnection() = 0;
++};
++
++//! Callback to deliver engine state change notifications
++//! to the object managing the engine.
++class XmppSessionHandler {
++public:
++  //! Called when engine changes state. Argument is new state.
++  virtual void OnStateChange(int state) = 0;
++};
++
++//! Callback to deliver stanzas to an Xmpp application module.
++//! Register via XmppEngine.SetDefaultSessionHandler or via
++//! XmppEngine.AddSessionHAndler.  
++class XmppStanzaHandler {
++public:
++
++  //! Process the given stanza.
++  //! The handler must return true if it has handled the stanza.
++  //! A false return value causes the stanza to be passed on to
++  //! the next registered handler.
++  virtual bool HandleStanza(const XmlElement * stanza) = 0;
++};
++
++//! Callback to deliver iq responses (results and errors).
++//! Register while sending an iq via XmppEngine.SendIq.
++//! Iq responses are routed to matching XmppIqHandlers in preference
++//! to sending to any registered SessionHandlers.
++class XmppIqHandler {
++public:
++  //! Called to handle the iq response.
++  //! The response may be either a result or an error, and will have
++  //! an 'id' that matches the request and a 'from' that matches the
++  //! 'to' of the request.  Called no more than once; once this is
++  //! called, the handler is automatically unregistered.
++  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
++};
++
++//! The XMPP connection engine.
++//! This engine implements the client side of the 'core' XMPP protocol.
++//! To use it, register an XmppOutputHandler to handle socket output
++//! and pass socket input to HandleInput.  Then application code can
++//! set up the connection with a user, password, and other settings,
++//! and then call Connect() to initiate the connection.
++//! An application can listen for events and receive stanzas by
++//! registering an XmppStanzaHandler via AddStanzaHandler().
++class XmppEngine {
++public:
++  static XmppEngine * Create();
++  virtual ~XmppEngine() {}
++
++  //! Error codes. See GetError().
++  enum Error {
++    ERROR_NONE = 0,         //!< No error
++    ERROR_XML,              //!< Malformed XML or encoding error
++    ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
++    ERROR_VERSION,          //!< XMPP version error
++    ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
++    ERROR_TLS,              //!< TLS could not be negotiated
++    ERROR_AUTH,             //!< Authentication could not be negotiated
++    ERROR_BIND,             //!< Resource or session binding could not be negotiated
++    ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
++    ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
++    ERROR_SOCKET,           //!< Socket error
++  };
++
++  //! States.  See GetState().
++  enum State {
++    STATE_NONE = 0,        //!< Nonexistent state
++    STATE_START,           //!< Initial state.
++    STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
++    STATE_OPEN,            //!< Authenticated and bound.
++    STATE_CLOSED,          //!< Session closed, possibly due to error.
++  };
++
++  // SOCKET INPUT AND OUTPUT ------------------------------------------------
++
++  //! Registers the handler for socket output
++  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
++
++  //! Provides socket input to the engine
++  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
++
++  //! Advises the engine that the socket has closed
++  virtual XmppReturnStatus ConnectionClosed() = 0;
++
++  // SESSION SETUP ---------------------------------------------------------
++
++  //! Indicates the (bare) JID for the user to use.
++  virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
++
++  //! Get the login (bare) JID.
++  virtual const Jid & GetUser() = 0;
++
++  //! Provides different methods for credentials for login.
++  //! Takes ownership of this object; deletes when login is done
++  virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
++
++  //! Sets whether TLS will be used within the connection (default true).
++  virtual XmppReturnStatus SetUseTls(bool useTls) = 0;
++
++  //! Sets an alternate domain from which we allows TLS certificates.
++  //! This is for use in the case where a we want to allow a proxy to
++  //! serve up its own certificate rather than one owned by the underlying
++  //! domain.
++  virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain) = 0;
++
++  //! Gets whether TLS will be used within the connection.
++  virtual bool GetUseTls() = 0;
++
++  //! Sets the request resource name, if any (optional).
++  //! Note that the resource name may be overridden by the server; after
++  //! binding, the actual resource name is available as part of FullJid().
++  virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
++
++  //! Gets the request resource name.
++  virtual const std::string & GetRequestedResource() = 0;
++
++  // SESSION MANAGEMENT ---------------------------------------------------
++
++  //! Set callback for state changes.
++  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
++
++  //! Initiates the XMPP connection.
++  //! After supplying connection settings, call this once to initiate,
++  //! (optionally) encrypt, authenticate, and bind the connection.
++  virtual XmppReturnStatus Connect() = 0;
++
++  //! The current engine state.
++  virtual State GetState() = 0;
++
++  //! Returns true if the connection is encrypted (under TLS)
++  virtual bool IsEncrypted() = 0;
++
++  //! The error code.
++  //! Consult this after XmppOutputHandler.OnClose().
++  virtual Error GetError() = 0;
++
++  //! The stream:error stanza, when the error is XMPP_ERROR_STREAM.
++  //! Notice the stanza returned is owned by the XmppEngine and
++  //! is deleted when the engine is destroyed.
++  virtual const XmlElement * GetStreamError() = 0;
++
++  //! Closes down the connection.
++  //! Sends CloseConnection to output, and disconnects and registered
++  //! session handlers.  After Disconnect completes, it is guaranteed
++  //! that no further callbacks will be made.
++  virtual XmppReturnStatus Disconnect() = 0;
++
++  // APPLICATION USE -------------------------------------------------------
++
++  enum HandlerLevel {
++    HL_NONE = 0,
++    HL_PEEK,   //!< Sees messages before all other processing; cannot abort
++    HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
++    HL_SENDER, //!< Watches for a type of message from a specific sender
++    HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
++    HL_ALL,    //!< Watches all messages - gets last shot
++    HL_COUNT,  //!< Count of handler levels
++  };
++  
++  //! Adds a listener for session events.
++  //! Stanza delivery is chained to session handlers; the first to
++  //! return 'true' is the last to get each stanza.
++  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
++
++  //! Removes a listener for session events.
++  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
++
++  //! Sends a stanza to the server.
++  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
++
++  //! Sends raw text to the server
++  virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
++
++  //! Sends an iq to the server, and registers a callback for the result.
++  //! Returns the cookie passed to the result handler.
++  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
++                                  XmppIqHandler* iq_handler,
++                                  XmppIqCookie* cookie) = 0;
++
++  //! Unregisters an iq callback handler given its cookie.
++  //! No callback will come to this handler after it's unregistered.
++  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
++                                      XmppIqHandler** iq_handler) = 0;
++
++
++  //! Forms and sends an error in response to the given stanza.
++  //! Swaps to and from, sets type to "error", and adds error information
++  //! based on the passed code.  Text is optional and may be STR_EMPTY.
++  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
++                                           XmppStanzaError code,
++                                           const std::string & text) = 0;
++
++  //! The fullly bound JID.
++  //! This JID is only valid after binding has succeeded.  If the value
++  //! is JID_NULL, the binding has not succeeded.
++  virtual const Jid & FullJid() = 0;
++
++  //! The next unused iq id for this connection.
++  //! Call this when building iq stanzas, to ensure that each iq
++  //! gets its own unique id.
++  virtual std::string NextId() = 0;
++
++};
++
++}
++
++
++// Move these to a better location
++
++#define XMPP_FAILED(x)                      \
++  ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
++
++
++#define XMPP_SUCCEEDED(x)                   \
++  ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
++
++#define IFR(x)                        \
++  do {                                \
++    xmpp_status = (x);                \
++    if (XMPP_FAILED(xmpp_status)) {   \
++      return xmpp_status;             \
++    }                                 \
++  } while (false)                     \
++
++
++#define IFC(x)                        \
++  do {                                \
++    xmpp_status = (x);                \
++    if (XMPP_FAILED(xmpp_status)) {   \
++      goto Cleanup;                   \
++    }                                 \
++  } while (false)                     \
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h	(revision 586398)
+@@ -0,0 +1,65 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SASLPLAINMECHANISM_H_
++#define _SASLPLAINMECHANISM_H_
++
++#include "talk/xmpp/saslmechanism.h"
++#include "talk/xmpp/xmpppassword.h"
++
++namespace buzz {
++
++class SaslPlainMechanism : public SaslMechanism {
++
++public:
++  SaslPlainMechanism(const buzz::Jid user_jid, const XmppPassword & password) :
++    user_jid_(user_jid), password_(password) {}
++
++  virtual std::string GetMechanismName() { return "PLAIN"; }
++    
++  virtual XmlElement * StartSaslAuth() {
++    // send initial request
++    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
++    el->AddAttr(QN_MECHANISM, "PLAIN");
++
++    FormatXmppPassword credential;
++    credential.Append("\0", 1);
++    credential.Append(user_jid_.Str());
++    credential.Append("\0", 1);
++    credential.Append(&password_);
++    el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
++    return el;
++  }
++  
++private:
++  Jid user_jid_;
++  XmppPassword password_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h	(revision 586398)
+@@ -0,0 +1,300 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
++#define _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
++
++#include <string>
++#include "talk/xmllite/qname.h"
++#include "talk/xmpp/jid.h"
++
++
++#define NS_CLIENT Constants::ns_client()
++#define NS_SERVER Constants::ns_server()
++#define NS_STREAM Constants::ns_stream()
++#define NS_XSTREAM Constants::ns_xstream()
++#define NS_TLS Constants::ns_tls()
++#define NS_SASL Constants::ns_sasl()
++#define NS_BIND Constants::ns_bind()
++#define NS_DIALBACK Constants::ns_dialback()
++#define NS_SESSION Constants::ns_session()
++#define NS_STANZA Constants::ns_stanza()
++#define NS_PRIVACY Constants::ns_privacy()
++#define NS_ROSTER Constants::ns_roster()
++#define NS_VCARD Constants::ns_vcard()
++#define STR_CLIENT Constants::str_client()
++#define STR_SERVER Constants::str_server()
++#define STR_STREAM Constants::str_stream()
++
++namespace buzz {
++
++extern const Jid JID_EMPTY;
++
++class Constants {
++ public:
++  static const std::string & ns_client();
++  static const std::string & ns_server();
++  static const std::string & ns_stream();
++  static const std::string & ns_xstream();
++  static const std::string & ns_tls();
++  static const std::string & ns_sasl();
++  static const std::string & ns_bind();
++  static const std::string & ns_dialback();
++  static const std::string & ns_session();
++  static const std::string & ns_stanza();
++  static const std::string & ns_privacy();
++  static const std::string & ns_roster();
++  static const std::string & ns_vcard();
++  
++  static const std::string & str_client();
++  static const std::string & str_server();
++  static const std::string & str_stream();
++};
++
++extern const std::string STR_GET;
++extern const std::string STR_SET;
++extern const std::string STR_RESULT;
++extern const std::string STR_ERROR;
++
++extern const std::string STR_FROM;
++extern const std::string STR_TO;
++extern const std::string STR_BOTH;
++extern const std::string STR_REMOVE;
++
++extern const std::string STR_MESSAGE;
++extern const std::string STR_BODY;
++extern const std::string STR_PRESENCE;
++extern const std::string STR_STATUS;
++extern const std::string STR_SHOW;
++extern const std::string STR_PRIOIRTY;
++extern const std::string STR_IQ;
++
++extern const std::string STR_TYPE;
++extern const std::string STR_NAME;
++extern const std::string STR_ID;
++extern const std::string STR_JID;
++extern const std::string STR_SUBSCRIPTION;
++extern const std::string STR_ASK;
++extern const std::string STR_X;
++extern const std::string STR_GOOGLE_COM;
++extern const std::string STR_GMAIL_COM;
++extern const std::string STR_GOOGLEMAIL_COM;
++extern const std::string STR_DEFAULT_DOMAIN;
++
++extern const std::string STR_UNAVAILABLE;
++extern const std::string STR_INVISIBLE;
++
++extern const QName QN_STREAM_STREAM;
++extern const QName QN_STREAM_FEATURES;
++extern const QName QN_STREAM_ERROR;
++
++extern const QName QN_XSTREAM_BAD_FORMAT;
++extern const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
++extern const QName QN_XSTREAM_CONFLICT;
++extern const QName QN_XSTREAM_CONNECTION_TIMEOUT;
++extern const QName QN_XSTREAM_HOST_GONE;
++extern const QName QN_XSTREAM_HOST_UNKNOWN;
++extern const QName QN_XSTREAM_IMPROPER_ADDRESSIING;
++extern const QName QN_XSTREAM_INTERNAL_SERVER_ERROR;
++extern const QName QN_XSTREAM_INVALID_FROM;
++extern const QName QN_XSTREAM_INVALID_ID;
++extern const QName QN_XSTREAM_INVALID_NAMESPACE;
++extern const QName QN_XSTREAM_INVALID_XML;
++extern const QName QN_XSTREAM_NOT_AUTHORIZED;
++extern const QName QN_XSTREAM_POLICY_VIOLATION;
++extern const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
++extern const QName QN_XSTREAM_RESOURCE_CONSTRAINT;
++extern const QName QN_XSTREAM_RESTRICTED_XML;
++extern const QName QN_XSTREAM_SEE_OTHER_HOST;
++extern const QName QN_XSTREAM_SYSTEM_SHUTDOWN;
++extern const QName QN_XSTREAM_UNDEFINED_CONDITION;
++extern const QName QN_XSTREAM_UNSUPPORTED_ENCODING;
++extern const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
++extern const QName QN_XSTREAM_UNSUPPORTED_VERSION;
++extern const QName QN_XSTREAM_XML_NOT_WELL_FORMED;
++extern const QName QN_XSTREAM_TEXT;
++
++extern const QName QN_TLS_STARTTLS;
++extern const QName QN_TLS_REQUIRED;
++extern const QName QN_TLS_PROCEED;
++extern const QName QN_TLS_FAILURE;
++
++extern const QName QN_SASL_MECHANISMS;
++extern const QName QN_SASL_MECHANISM;
++extern const QName QN_SASL_AUTH;
++extern const QName QN_SASL_CHALLENGE;
++extern const QName QN_SASL_RESPONSE;
++extern const QName QN_SASL_ABORT;
++extern const QName QN_SASL_SUCCESS;
++extern const QName QN_SASL_FAILURE;
++extern const QName QN_SASL_ABORTED;
++extern const QName QN_SASL_INCORRECT_ENCODING;
++extern const QName QN_SASL_INVALID_AUTHZID;
++extern const QName QN_SASL_INVALID_MECHANISM;
++extern const QName QN_SASL_MECHANISM_TOO_WEAK;
++extern const QName QN_SASL_NOT_AUTHORIZED;
++extern const QName QN_SASL_TEMPORARY_AUTH_FAILURE;
++
++extern const QName QN_DIALBACK_RESULT;
++extern const QName QN_DIALBACK_VERIFY;
++
++extern const QName QN_STANZA_BAD_REQUEST;
++extern const QName QN_STANZA_CONFLICT;
++extern const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
++extern const QName QN_STANZA_FORBIDDEN;
++extern const QName QN_STANZA_GONE;
++extern const QName QN_STANZA_INTERNAL_SERVER_ERROR;
++extern const QName QN_STANZA_ITEM_NOT_FOUND;
++extern const QName QN_STANZA_JID_MALFORMED;
++extern const QName QN_STANZA_NOT_ACCEPTABLE;
++extern const QName QN_STANZA_NOT_ALLOWED;
++extern const QName QN_STANZA_PAYMENT_REQUIRED;
++extern const QName QN_STANZA_RECIPIENT_UNAVAILABLE;
++extern const QName QN_STANZA_REDIRECT;
++extern const QName QN_STANZA_REGISTRATION_REQUIRED;
++extern const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
++extern const QName QN_STANZA_REMOTE_SERVER_TIMEOUT;
++extern const QName QN_STANZA_RESOURCE_CONSTRAINT;
++extern const QName QN_STANZA_SERVICE_UNAVAILABLE;
++extern const QName QN_STANZA_SUBSCRIPTION_REQUIRED;
++extern const QName QN_STANZA_UNDEFINED_CONDITION;
++extern const QName QN_STANZA_UNEXPECTED_REQUEST;
++extern const QName QN_STANZA_TEXT;
++
++extern const QName QN_BIND_BIND;
++extern const QName QN_BIND_RESOURCE;
++extern const QName QN_BIND_JID;
++
++extern const QName QN_MESSAGE;
++extern const QName QN_BODY;
++extern const QName QN_SUBJECT;
++extern const QName QN_THREAD;
++extern const QName QN_PRESENCE;
++extern const QName QN_SHOW;
++extern const QName QN_STATUS;
++extern const QName QN_LANG;
++extern const QName QN_PRIORITY;
++extern const QName QN_IQ;
++extern const QName QN_ERROR;
++
++extern const QName QN_SERVER_MESSAGE;
++extern const QName QN_SERVER_BODY;
++extern const QName QN_SERVER_SUBJECT;
++extern const QName QN_SERVER_THREAD;
++extern const QName QN_SERVER_PRESENCE;
++extern const QName QN_SERVER_SHOW;
++extern const QName QN_SERVER_STATUS;
++extern const QName QN_SERVER_LANG;
++extern const QName QN_SERVER_PRIORITY;
++extern const QName QN_SERVER_IQ;
++extern const QName QN_SERVER_ERROR;
++
++extern const QName QN_SESSION_SESSION;
++
++extern const QName QN_PRIVACY_QUERY;
++extern const QName QN_PRIVACY_ACTIVE;
++extern const QName QN_PRIVACY_DEFAULT;
++extern const QName QN_PRIVACY_LIST;
++extern const QName QN_PRIVACY_ITEM;
++extern const QName QN_PRIVACY_IQ;
++extern const QName QN_PRIVACY_MESSAGE;
++extern const QName QN_PRIVACY_PRESENCE_IN;
++extern const QName QN_PRIVACY_PRESENCE_OUT;
++
++extern const QName QN_ROSTER_QUERY;
++extern const QName QN_ROSTER_ITEM;
++extern const QName QN_ROSTER_GROUP;
++
++extern const QName QN_VCARD_QUERY;
++extern const QName QN_VCARD_FN;
++
++extern const QName QN_XML_LANG;
++
++extern const QName QN_ENCODING;
++extern const QName QN_VERSION;
++extern const QName QN_TO;
++extern const QName QN_FROM;
++extern const QName QN_TYPE;
++extern const QName QN_ID;
++extern const QName QN_CODE;
++extern const QName QN_NAME;
++extern const QName QN_VALUE;
++extern const QName QN_ACTION;
++extern const QName QN_ORDER;
++extern const QName QN_MECHANISM;
++extern const QName QN_ASK;
++extern const QName QN_JID;
++extern const QName QN_SUBSCRIPTION;
++
++
++extern const QName QN_XMLNS_CLIENT;
++extern const QName QN_XMLNS_SERVER;
++extern const QName QN_XMLNS_STREAM;
++
++// Presence
++extern const std::string STR_SHOW_AWAY;
++extern const std::string STR_SHOW_CHAT;
++extern const std::string STR_SHOW_DND;
++extern const std::string STR_SHOW_XA;
++
++// Subscription
++extern const std::string STR_SUBSCRIBE;
++extern const std::string STR_SUBSCRIBED;
++extern const std::string STR_UNSUBSCRIBE;
++extern const std::string STR_UNSUBSCRIBED;
++
++
++// JEP 0030
++extern const QName QN_NODE;
++extern const QName QN_CATEGORY;
++extern const QName QN_VAR;
++extern const std::string NS_DISCO_INFO;
++extern const std::string NS_DISCO_ITEMS;
++
++extern const QName QN_DISCO_INFO_QUERY;
++extern const QName QN_DISCO_IDENTITY;
++extern const QName QN_DISCO_FEATURE;
++
++extern const QName QN_DISCO_ITEMS_QUERY;
++extern const QName QN_DISCO_ITEM;
++
++
++// JEP 0115
++extern const std::string NS_CAPS;
++extern const QName QN_CAPS_C;
++extern const QName QN_VER;
++extern const QName QN_EXT;
++
++
++// JEP 0091 Delayed Delivery
++extern const std::string kNSDelay;
++extern const QName kQnDelayX;
++extern const QName kQnStamp;
++
++}
++
++#endif // _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _PREXMPPAUTH_H_
++#define _PREXMPPAUTH_H_
++
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/saslhandler.h"
++#include "talk/xmpp/xmpppassword.h"
++
++namespace cricket {
++  class SocketAddress;
++}
++
++namespace buzz {
++
++class Jid;
++class SaslMechanism;
++
++class CaptchaChallenge {
++ public:
++  CaptchaChallenge() : captcha_needed_(false) {}
++  CaptchaChallenge(const std::string& token, const std::string& url) 
++    : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
++  }
++
++  bool captcha_needed() const { return captcha_needed_; }
++  const std::string& captcha_token() const { return captcha_token_; }
++
++  // This url is relative to the gaia server.  Once we have better tools
++  // for cracking URLs, we should probably make this a full URL
++  const std::string& captcha_image_url() const { return captcha_image_url_; }
++
++ private:
++  bool captcha_needed_;
++  std::string captcha_token_;
++  std::string captcha_image_url_;
++};
++
++class PreXmppAuth : public SaslHandler {
++public:
++  virtual ~PreXmppAuth() {}
++  
++  virtual void StartPreXmppAuth(
++    const Jid & jid,
++    const cricket::SocketAddress & server,
++    const XmppPassword & pass,
++    const std::string & auth_cookie) = 0;
++  
++  sigslot::signal0<> SignalAuthDone;
++  
++  virtual bool IsAuthDone() = 0;
++  virtual bool IsAuthorized() = 0;
++  virtual bool HadError() = 0;
++  virtual CaptchaChallenge GetCaptchaChallenge() = 0;
++  virtual std::string GetAuthCookie() = 0;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc	(revision 586398)
+@@ -0,0 +1,104 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <expat.h>
++#include "talk/xmllite/xmlelement.h"
++#include "talk/base/common.h"
++#include "talk/xmpp/xmppstanzaparser.h"
++#include "talk/xmpp/constants.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) :
++  psph_(psph),
++  innerHandler_(this),
++  parser_(&innerHandler_),
++  depth_(0),
++  builder_() {
++}
++
++void
++XmppStanzaParser::Reset() {
++  parser_.Reset();
++  depth_ = 0;
++  builder_.Reset();
++}
++
++void
++XmppStanzaParser::IncomingStartElement(
++    XmlParseContext * pctx, const char * name, const char ** atts) {
++  if (depth_++ == 0) {
++    XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts);
++    if (pelStream == NULL) {
++      pctx->RaiseError(XML_ERROR_SYNTAX);
++      return;
++    }
++    psph_->StartStream(pelStream);
++    delete pelStream;
++    return;
++  }
++
++  builder_.StartElement(pctx, name, atts);
++}
++
++void
++XmppStanzaParser::IncomingCharacterData(
++    XmlParseContext * pctx, const char * text, int len) {
++  if (depth_ > 1) {
++    builder_.CharacterData(pctx, text, len);
++  }
++}
++
++void
++XmppStanzaParser::IncomingEndElement(
++    XmlParseContext * pctx, const char * name) {
++  if (--depth_ == 0) {
++    psph_->EndStream();
++    return;
++  }
++
++  builder_.EndElement(pctx, name);
++
++  if (depth_ == 1) {
++    XmlElement *element = builder_.CreateElement();
++    psph_->Stanza(element);
++    delete element;
++  }
++}
++
++void
++XmppStanzaParser::IncomingError(
++    XmlParseContext * pctx, XML_Error errCode) {
++  UNUSED(pctx);
++  UNUSED(errCode);
++  psph_->XmlError();
++}
++
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc	(revision 586398)
+@@ -0,0 +1,372 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "xmppclient.h"
++#include "xmpptask.h"
++#include "talk/xmpp/constants.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/saslplainmechanism.h"
++#include "talk/xmpp/prexmppauth.h"
++#include "talk/base/scoped_ptr.h"
++#include "talk/xmpp/plainsaslhandler.h"
++
++namespace buzz {
++
++Task *
++XmppClient::GetParent(int code) {
++  if (code == XMPP_CLIENT_TASK_CODE)
++    return this;
++  else
++    return Task::GetParent(code);
++}
++
++class XmppClient::Private :
++    public sigslot::has_slots<>,
++    public XmppSessionHandler,
++    public XmppOutputHandler {
++public:
++
++  Private(XmppClient * client) :
++    client_(client),
++    socket_(NULL),
++    engine_(NULL),
++    proxy_port_(0),
++    pre_engine_error_(XmppEngine::ERROR_NONE),
++    signal_closed_(false) {}
++
++  // the owner
++  XmppClient * const client_;
++
++  // the two main objects
++  scoped_ptr<AsyncSocket> socket_;
++  scoped_ptr<XmppEngine> engine_;
++  scoped_ptr<PreXmppAuth> pre_auth_;
++  XmppPassword pass_;
++  std::string auth_cookie_;
++  cricket::SocketAddress server_;
++  std::string proxy_host_;
++  int proxy_port_;
++  XmppEngine::Error pre_engine_error_;
++  CaptchaChallenge captcha_challenge_;
++  bool signal_closed_;
++
++  // implementations of interfaces
++  void OnStateChange(int state);
++  void WriteOutput(const char * bytes, size_t len);
++  void StartTls(const std::string & domainname);
++  void CloseConnection();
++
++  // slots for socket signals
++  void OnSocketConnected();
++  void OnSocketRead();
++  void OnSocketClosed();
++};
++
++XmppReturnStatus
++XmppClient::Connect(const XmppClientSettings & settings, AsyncSocket * socket, PreXmppAuth * pre_auth) {
++  if (socket == NULL)
++    return XMPP_RETURN_BADARGUMENT;
++  if (d_->socket_.get() != NULL)
++    return XMPP_RETURN_BADSTATE;
++
++  d_->socket_.reset(socket);
++
++  d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
++  d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
++  d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
++
++  d_->engine_.reset(XmppEngine::Create());
++  d_->engine_->SetSessionHandler(d_.get());
++  d_->engine_->SetOutputHandler(d_.get());
++  d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
++  if (!settings.resource().empty()) {
++    d_->engine_->SetRequestedResource(settings.resource());
++  }
++  d_->engine_->SetUseTls(settings.use_tls());
++
++
++  d_->pass_ = settings.pass();
++  d_->auth_cookie_ = settings.auth_cookie();
++  d_->server_ = settings.server();
++  d_->proxy_host_ = settings.proxy_host();
++  d_->proxy_port_ = settings.proxy_port();
++  d_->pre_auth_.reset(pre_auth);
++
++  return XMPP_RETURN_OK;
++}
++
++XmppEngine::State
++XmppClient::GetState() {
++  if (d_->engine_.get() == NULL)
++    return XmppEngine::STATE_NONE;
++  return d_->engine_->GetState();
++}
++
++XmppEngine::Error
++XmppClient::GetError() {
++  if (d_->engine_.get() == NULL)
++    return XmppEngine::ERROR_NONE;
++  if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE)
++    return d_->pre_engine_error_;
++  return d_->engine_->GetError();
++}
++
++CaptchaChallenge XmppClient::GetCaptchaChallenge() {
++  if (d_->engine_.get() == NULL)
++    return CaptchaChallenge();
++  return d_->captcha_challenge_;
++}
++
++std::string
++XmppClient::GetAuthCookie() {
++  if (d_->engine_.get() == NULL)
++    return "";
++  return d_->auth_cookie_;
++}
++
++static void
++ForgetPassword(std::string & to_erase) {
++  size_t len = to_erase.size();
++  for (size_t i = 0; i < len; i++) {
++    // get rid of characters
++    to_erase[i] = 'x';
++  }
++  // get rid of length
++  to_erase.erase();
++}
++
++int
++XmppClient::ProcessStart() {
++  if (d_->pre_auth_.get()) {
++    d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
++    d_->pre_auth_->StartPreXmppAuth(
++        d_->engine_->GetUser(), d_->server_, d_->pass_, d_->auth_cookie_);
++    d_->pass_.Clear(); // done with this;
++    return STATE_PRE_XMPP_LOGIN;
++  }
++  else {
++    d_->engine_->SetSaslHandler(new PlainSaslHandler(
++              d_->engine_->GetUser(), d_->pass_));
++    d_->pass_.Clear(); // done with this;
++    return STATE_START_XMPP_LOGIN;
++  }
++}
++
++void
++XmppClient::OnAuthDone() {
++  Wake();
++}
++
++int
++XmppClient::ProcessCookieLogin() {
++  // Don't know how this could happen, but crash reports show it as NULL
++  if (!d_->pre_auth_.get()) {
++    d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
++    EnsureClosed();
++    return STATE_ERROR;
++  }
++
++  // Wait until pre authentication is done is done
++  if (!d_->pre_auth_->IsAuthDone())
++    return STATE_BLOCKED;
++
++  if (!d_->pre_auth_->IsAuthorized()) {
++    // maybe split out a case when gaia is down?
++    if (d_->pre_auth_->HadError()) {
++      d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
++    }
++    else {
++      d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
++      d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
++    }
++    d_->pre_auth_.reset(NULL); // done with this
++    EnsureClosed();
++    return STATE_ERROR;
++  }
++
++  // Save auth cookie as a result
++  d_->auth_cookie_ = d_->pre_auth_->GetAuthCookie();
++
++  // transfer ownership of pre_auth_ to engine
++  d_->engine_->SetSaslHandler(d_->pre_auth_.release());
++  
++  return STATE_START_XMPP_LOGIN;
++}
++
++int
++XmppClient::ProcessStartXmppLogin() {
++  // Done with pre-connect tasks - connect!
++  if (!d_->socket_->Connect(d_->server_)) {
++    EnsureClosed();
++    return STATE_ERROR;
++  }
++  
++  return STATE_RESPONSE;
++}
++
++int
++XmppClient::ProcessResponse() {
++  // Hang around while we are connected.
++  if (!delivering_signal_ && (d_->engine_.get() == NULL ||
++    d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
++    return STATE_DONE;
++  return STATE_BLOCKED;
++}
++
++XmppReturnStatus
++XmppClient::Disconnect() {
++  if (d_->socket_.get() == NULL)
++    return XMPP_RETURN_BADSTATE;
++  d_->engine_->Disconnect();
++  return XMPP_RETURN_OK;
++}
++
++XmppClient::XmppClient(Task * parent) : Task(parent), 
++    delivering_signal_(false) {
++  d_.reset(new Private(this));
++}
++
++XmppClient::~XmppClient() {}
++
++const Jid &
++XmppClient::jid() {
++  return d_->engine_->FullJid();
++}
++
++
++std::string
++XmppClient::NextId() {
++  return d_->engine_->NextId();
++}
++
++XmppReturnStatus
++XmppClient::SendStanza(const XmlElement * stanza) {
++  return d_->engine_->SendStanza(stanza);
++}
++
++XmppReturnStatus
++XmppClient::SendStanzaError(const XmlElement * old_stanza, XmppStanzaError xse, const std::string & message) {
++  return d_->engine_->SendStanzaError(old_stanza, xse, message);
++}
++
++XmppReturnStatus
++XmppClient::SendRaw(const std::string & text) {
++  return d_->engine_->SendRaw(text);
++}
++
++XmppEngine*
++XmppClient::engine() {
++  return d_->engine_.get();
++}
++
++void
++XmppClient::Private::OnSocketConnected() {
++  engine_->Connect();
++}
++
++void
++XmppClient::Private::OnSocketRead() {
++  char bytes[4096];
++  size_t bytes_read;
++  for (;;) {
++    if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
++      // TODO: deal with error information
++      return;
++    }
++
++    if (bytes_read == 0)
++      return;
++
++//#ifdef _DEBUG
++    client_->SignalLogInput(bytes, bytes_read);
++//#endif
++
++    engine_->HandleInput(bytes, bytes_read);
++  }
++}
++
++void
++XmppClient::Private::OnSocketClosed() {
++  engine_->ConnectionClosed();
++}
++
++void
++XmppClient::Private::OnStateChange(int state) {
++  if (state == XmppEngine::STATE_CLOSED) {
++    client_->EnsureClosed();
++  }
++  else {
++    client_->SignalStateChange((XmppEngine::State)state);
++  }
++  client_->Wake();
++}
++
++void
++XmppClient::Private::WriteOutput(const char * bytes, size_t len) {
++
++//#ifdef _DEBUG
++  client_->SignalLogOutput(bytes, len);
++//#endif
++
++  socket_->Write(bytes, len);
++  // TODO: deal with error information
++}
++
++void
++XmppClient::Private::StartTls(const std::string & domain) {
++#if defined(FEATURE_ENABLE_SSL)
++  socket_->StartTls(domain);
++#endif
++}
++
++void
++XmppClient::Private::CloseConnection() {
++  socket_->Close();
++}
++
++void
++XmppClient::AddXmppTask(XmppTask * task, XmppEngine::HandlerLevel level) {
++  d_->engine_->AddStanzaHandler(task, level);
++}
++
++void
++XmppClient::RemoveXmppTask(XmppTask * task) {
++  d_->engine_->RemoveStanzaHandler(task);
++}
++
++void
++XmppClient::EnsureClosed() {
++  if (!d_->signal_closed_) {
++    d_->signal_closed_ = true;
++    delivering_signal_ = true;
++    SignalStateChange(XmppEngine::STATE_CLOSED);
++    delivering_signal_ = false;
++  }
++}
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h	(revision 586398)
+@@ -0,0 +1,67 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SASLCOOKIEMECHANISM_H_
++#define _SASLCOOKIEMECHANISM_H_
++
++#include "talk/xmpp/saslmechanism.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmpp/constants.h"
++
++namespace buzz {
++
++class SaslCookieMechanism : public SaslMechanism {
++
++public:
++  SaslCookieMechanism(const std::string & mechanism, const std::string & username, const std::string & cookie) :
++    mechanism_(mechanism), username_(username), cookie_(cookie) {}
++
++  virtual std::string GetMechanismName() { return mechanism_; }
++    
++  virtual XmlElement * StartSaslAuth() {
++    // send initial request
++    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
++    el->AddAttr(QN_MECHANISM, mechanism_);
++    
++    std::string credential;
++    credential.append("\0", 1);
++    credential.append(username_);
++    credential.append("\0", 1);
++    credential.append(cookie_);
++    el->AddText(Base64Encode(credential));
++    return el;
++  }
++  
++private:
++  std::string mechanism_;
++  std::string username_;
++  std::string cookie_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h	(revision 586398)
+@@ -0,0 +1,96 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmppstanzaparser_h_
++#define _xmppstanzaparser_h_
++
++#include "talk/xmllite/xmlparser.h"
++#include "talk/xmllite/xmlbuilder.h"
++
++
++namespace buzz {
++
++class XmlElement;
++
++class XmppStanzaParseHandler {
++public:
++  virtual void StartStream(const XmlElement * pelStream) = 0;
++  virtual void Stanza(const XmlElement * pelStanza) = 0;
++  virtual void EndStream() = 0;
++  virtual void XmlError() = 0;
++};
++
++class XmppStanzaParser {
++public:
++  XmppStanzaParser(XmppStanzaParseHandler *psph);
++  bool Parse(const char * data, size_t len, bool isFinal)
++    { return parser_.Parse(data, len, isFinal); }
++  void Reset();
++
++private:
++  class ParseHandler : public XmlParseHandler {
++  public:
++    ParseHandler(XmppStanzaParser * outer) : outer_(outer) {}
++    virtual void StartElement(XmlParseContext * pctx,
++               const char * name, const char ** atts)
++      { outer_->IncomingStartElement(pctx, name, atts); }
++    virtual void EndElement(XmlParseContext * pctx,
++               const char * name)
++      { outer_->IncomingEndElement(pctx, name); }
++    virtual void CharacterData(XmlParseContext * pctx,
++               const char * text, int len)
++      { outer_->IncomingCharacterData(pctx, text, len); }
++    virtual void Error(XmlParseContext * pctx,
++               XML_Error errCode)
++      { outer_->IncomingError(pctx, errCode); }
++  private:
++    XmppStanzaParser * const outer_;
++  };
++
++  friend class ParseHandler;
++
++  void IncomingStartElement(XmlParseContext * pctx,
++               const char * name, const char ** atts);
++  void IncomingEndElement(XmlParseContext * pctx,
++               const char * name);
++  void IncomingCharacterData(XmlParseContext * pctx,
++               const char * text, int len);
++  void IncomingError(XmlParseContext * pctx,
++               XML_Error errCode);
++
++  XmppStanzaParseHandler * psph_;
++  ParseHandler innerHandler_;
++  XmlParser parser_;
++  int depth_;
++  XmlBuilder builder_;
++
++ };
++
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h	(revision 586398)
+@@ -0,0 +1,157 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPCLIENT_H_
++#define _XMPPCLIENT_H_
++
++#include <string>
++#include "talk/base/basicdefs.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/asyncsocket.h"
++#include "talk/xmpp/xmppclientsettings.h"
++#include "talk/base/task.h"
++
++namespace buzz {
++
++class XmppTask;
++class PreXmppAuth;
++class CaptchaChallenge;
++
++// Just some non-colliding number.  Could have picked "1".
++#define XMPP_CLIENT_TASK_CODE 0x366c1e47
++
++/////////////////////////////////////////////////////////////////////
++//
++// XMPPCLIENT
++//
++/////////////////////////////////////////////////////////////////////
++//
++// See Task first.  XmppClient is a parent task for XmppTasks.
++//
++// XmppClient is a task which is designed to be the parent task for
++// all tasks that depend on a single Xmpp connection.  If you want to,
++// for example, listen for subscription requests forever, then your
++// listener should be a task that is a child of the XmppClient that owns
++// the connection you are using.  XmppClient has all the utility methods
++// that basically drill through to XmppEngine.
++// 
++// XmppClient is just a wrapper for XmppEngine, and if I were writing it
++// all over again, I would make XmppClient == XmppEngine.  Why?
++// XmppEngine needs tasks too, for example it has an XmppLoginTask which
++// should just be the same kind of Task instead of an XmppEngine specific
++// thing.  It would help do certain things like GAIA auth cleaner.
++//
++/////////////////////////////////////////////////////////////////////
++
++class XmppClient : public Task, public sigslot::has_slots<>
++{
++public:
++  XmppClient(Task * parent);
++  ~XmppClient();
++
++  XmppReturnStatus Connect(const XmppClientSettings & settings,
++                           AsyncSocket * socket,
++                           PreXmppAuth * preauth);
++  
++  virtual Task * GetParent(int code);
++  virtual int ProcessStart();
++  virtual int ProcessResponse();
++  XmppReturnStatus Disconnect();
++  const Jid & jid();
++  
++  sigslot::signal1<XmppEngine::State> SignalStateChange;
++  XmppEngine::State GetState();
++  XmppEngine::Error GetError();
++
++  // When there is an authentication error, we may have captcha info
++  // that the user can use to unlock their account
++  CaptchaChallenge GetCaptchaChallenge();
++
++  // When authentication is successful, this returns the service cookie
++  // (if we used GAIA authentication)
++  std::string GetAuthCookie();
++
++  std::string NextId();
++  XmppReturnStatus SendStanza(const XmlElement *stanza);
++  XmppReturnStatus SendRaw(const std::string & text);
++  XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
++                       XmppStanzaError code,
++                       const std::string & text);
++
++  XmppEngine* engine();
++
++  sigslot::signal2<const char *, int> SignalLogInput;
++  sigslot::signal2<const char *, int> SignalLogOutput;
++
++private:
++  friend class XmppTask;
++
++  void OnAuthDone();
++
++  // managed tasks and dispatching
++  void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
++  void RemoveXmppTask(XmppTask *);
++
++  sigslot::signal0<> SignalDisconnected;
++
++private:
++  // Internal state management
++  enum {
++    STATE_PRE_XMPP_LOGIN = STATE_NEXT,
++    STATE_START_XMPP_LOGIN   = STATE_NEXT + 1,
++  };
++  int Process(int state) {
++    switch (state) {
++      case STATE_PRE_XMPP_LOGIN: return ProcessCookieLogin();
++      case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
++      default: return Task::Process(state);
++    }
++  }
++
++  std::string GetStateName(int state) const {
++    switch (state) {
++      case STATE_PRE_XMPP_LOGIN:      return "PRE_XMPP_LOGIN";
++      case STATE_START_XMPP_LOGIN:  return "START_XMPP_LOGIN";
++      default: return Task::GetStateName(state);
++    }
++  }
++
++  int ProcessCookieLogin();
++  int ProcessStartXmppLogin();
++  void EnsureClosed();
++  
++  class Private;
++  friend class Private;
++  scoped_ptr<Private> d_;
++  
++  bool delivering_signal_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am	(revision 586398)
+@@ -0,0 +1,31 @@
++libcricketxmpp_la_SOURCES = constants.cc \
++			    jid.cc \
++			    saslmechanism.cc \
++			    xmppclient.cc \
++			    xmppengineimpl.cc \
++			    xmppengineimpl_iq.cc \
++			    xmpplogintask.cc \
++			    xmppstanzaparser.cc \
++			    xmpptask.cc
++
++noinst_HEADERS = asyncsocket.h \
++			    prexmppauth.h \
++		    	    saslhandler.h \
++		      	    xmpplogintask.h \
++			    jid.h \
++		    	    saslmechanism.h \
++		      	    xmppclient.h \
++		   	    xmpppassword.h \
++                            constants.h \
++		    	    saslplainmechanism.h \
++			    xmppclientsettings.h \
++			    xmppstanzaparser.h \
++		 	    xmppengine.h \
++		   	    xmpptask.h \
++			    plainsaslhandler.h \
++			    saslcookiemechanism.h \
++		     	    xmppengineimpl.h
++
++
++AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../..
++noinst_LTLIBRARIES = libcricketxmpp.la
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc	(revision 586398)
+@@ -0,0 +1,279 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <vector>
++#include <algorithm>
++#include "talk/base/common.h"
++#include "talk/xmpp/xmppengineimpl.h"
++#include "talk/xmpp/constants.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++class XmppIqEntry {
++  XmppIqEntry(const std::string & id, const std::string & to,
++               XmppEngine * pxce, XmppIqHandler * iq_handler) :
++    id_(id),
++    to_(to),
++    engine_(pxce),
++    iq_handler_(iq_handler) {
++  }
++
++private:
++  friend class XmppEngineImpl;
++
++  const std::string id_;
++  const std::string to_;
++  XmppEngine * const engine_;
++  XmppIqHandler * const iq_handler_;
++};
++
++
++XmppReturnStatus
++XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler,
++  XmppIqCookie* cookie) {
++  if (state_ == STATE_CLOSED)
++    return XMPP_RETURN_BADSTATE;
++  if (NULL == iq_handler)
++    return XMPP_RETURN_BADARGUMENT;
++  if (!element || element->Name() != QN_IQ)
++    return XMPP_RETURN_BADARGUMENT;
++
++  const std::string& type = element->Attr(QN_TYPE);
++  if (type != "get" && type != "set")
++    return XMPP_RETURN_BADARGUMENT;
++
++  if (!element->HasAttr(QN_ID))
++    return XMPP_RETURN_BADARGUMENT;
++  const std::string& id = element->Attr(QN_ID);
++
++  XmppIqEntry * iq_entry = new XmppIqEntry(id,
++                                              element->Attr(QN_TO),
++                                              this, iq_handler);
++  iq_entries_->push_back(iq_entry);
++  SendStanza(element);
++
++  if (cookie)
++    *cookie = iq_entry;
++
++  return XMPP_RETURN_OK;
++}
++
++
++XmppReturnStatus
++XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie,
++    XmppIqHandler ** iq_handler) {
++
++  std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos;
++
++  pos = std::find(iq_entries_->begin(),
++                  iq_entries_->end(),
++                  reinterpret_cast<XmppIqEntry*>(cookie));
++
++  if (pos == iq_entries_->end())
++    return XMPP_RETURN_BADARGUMENT;
++
++  XmppIqEntry* entry = *pos;
++  iq_entries_->erase(pos);
++  if (iq_handler)
++    *iq_handler = entry->iq_handler_;
++  delete entry;
++
++  return XMPP_RETURN_OK;
++}
++
++void
++XmppEngineImpl::DeleteIqCookies() {
++  for (size_t i = 0; i < iq_entries_->size(); i += 1) {
++    XmppIqEntry * iq_entry_ = (*iq_entries_)[i];
++    (*iq_entries_)[i] = NULL;
++    delete iq_entry_;
++  }
++  iq_entries_->clear();
++}
++
++static void
++AecImpl(XmlElement * error_element, const QName & name,
++        const char * type, const char * code) {
++  error_element->AddElement(new XmlElement(QN_ERROR));
++  error_element->AddAttr(QN_CODE, code, 1);
++  error_element->AddAttr(QN_TYPE, type, 1);
++  error_element->AddElement(new XmlElement(name, true), 1);
++}
++
++
++static void
++AddErrorCode(XmlElement * error_element, XmppStanzaError code) {
++  switch (code) {
++    case XSE_BAD_REQUEST:
++      AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400");
++      break;
++    case XSE_CONFLICT:
++      AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409");
++      break;
++    case XSE_FEATURE_NOT_IMPLEMENTED:
++      AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED,
++              "cancel", "501");
++      break;
++    case XSE_FORBIDDEN:
++      AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403");
++      break;
++    case XSE_GONE:
++      AecImpl(error_element, QN_STANZA_GONE, "modify", "302");
++      break;
++    case XSE_INTERNAL_SERVER_ERROR:
++      AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500");
++      break;
++    case XSE_ITEM_NOT_FOUND:
++      AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404");
++      break;
++    case XSE_JID_MALFORMED:
++      AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400");
++      break;
++    case XSE_NOT_ACCEPTABLE:
++      AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406");
++      break;
++    case XSE_NOT_ALLOWED:
++      AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405");
++      break;
++    case XSE_PAYMENT_REQUIRED:
++      AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402");
++      break;
++    case XSE_RECIPIENT_UNAVAILABLE:
++      AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404");
++      break;
++    case XSE_REDIRECT:
++      AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302");
++      break;
++    case XSE_REGISTRATION_REQUIRED:
++      AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407");
++      break;
++    case XSE_SERVER_NOT_FOUND:
++      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND,
++              "cancel", "404");
++      break;
++    case XSE_SERVER_TIMEOUT:
++      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502");
++      break;
++    case XSE_RESOURCE_CONSTRAINT:
++      AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500");
++      break;
++    case XSE_SERVICE_UNAVAILABLE:
++      AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503");
++      break;
++    case XSE_SUBSCRIPTION_REQUIRED:
++      AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407");
++      break;
++    case XSE_UNDEFINED_CONDITION:
++      AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500");
++      break;
++    case XSE_UNEXPECTED_REQUEST:
++      AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400");
++      break;
++  }
++}
++
++
++XmppReturnStatus
++XmppEngineImpl::SendStanzaError(const XmlElement * element_original,
++                                XmppStanzaError code,
++                                const std::string & text) {
++
++  if (state_ == STATE_CLOSED)
++    return XMPP_RETURN_BADSTATE;
++
++  XmlElement error_element(element_original->Name());
++  error_element.AddAttr(QN_TYPE, "error");
++
++  // copy attrs, copy 'from' to 'to' and strip 'from'
++  for (const XmlAttr * attribute = element_original->FirstAttr();
++       attribute; attribute = attribute->NextAttr()) {
++    QName name = attribute->Name();
++    if (name == QN_TO)
++      continue; // no need to put a from attr.  Server will stamp stanza
++    else if (name == QN_FROM)
++      name = QN_TO;
++    else if (name == QN_TYPE)
++      continue;
++    error_element.AddAttr(name, attribute->Value());
++  }
++
++  // copy children
++  for (const XmlChild * child = element_original->FirstChild();
++       child;
++       child = child->NextChild()) {
++    if (child->IsText()) {
++      error_element.AddText(child->AsText()->Text());
++    } else {
++      error_element.AddElement(new XmlElement(*(child->AsElement())));
++    }
++  }
++
++  // add error information
++  AddErrorCode(&error_element, code);
++  if (text != STR_EMPTY) {
++    XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true);
++    text_element->AddText(text);
++    error_element.AddElement(text_element);
++  }
++
++  SendStanza(&error_element);
++
++  return XMPP_RETURN_OK;
++}
++
++
++bool
++XmppEngineImpl::HandleIqResponse(const XmlElement * element) {
++  if (iq_entries_->empty())
++    return false;
++  if (element->Name() != QN_IQ)
++    return false;
++  std::string type = element->Attr(QN_TYPE);
++  if (type != "result" && type != "error")
++    return false;
++  if (!element->HasAttr(QN_ID))
++    return false;
++  std::string id = element->Attr(QN_ID);
++  std::string from = element->Attr(QN_FROM);
++
++  for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin();
++       it != iq_entries_->end(); it += 1) {
++    XmppIqEntry * iq_entry = *it;
++    if (iq_entry->id_ == id && iq_entry->to_ == from) {
++      iq_entries_->erase(it);
++      iq_entry->iq_handler_->IqResponse(iq_entry, element);
++      delete iq_entry;
++      return true;
++    }
++  }
++
++  return false;
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _PLAINSASLHANDLER_H_
++#define _PLAINSASLHANDLER_H_
++
++#include "talk/xmpp/saslhandler.h"
++#include <algorithm>
++
++namespace buzz {
++
++class PlainSaslHandler : public SaslHandler {
++public:
++  PlainSaslHandler(const Jid & jid, const XmppPassword & password) :
++    jid_(jid), password_(password) {}
++    
++  virtual ~PlainSaslHandler() {}
++
++  // Should pick the best method according to this handler
++  // returns the empty string if none are suitable
++  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
++  
++    // Do not send @google.com passwords unencrypted
++    if (!encrypted && jid_.domain() == "google.com") {
++      return "";
++    }
++    
++    std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
++    if (it == mechanisms.end()) {
++      return "";
++    }
++    else {
++      return "PLAIN";
++    }
++  }
++
++  // Creates a SaslMechanism for the given mechanism name (you own it
++  // once you get it).  If not handled, return NULL.
++  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
++    if (mechanism == "PLAIN") {
++      return new SaslPlainMechanism(jid_, password_);
++    }
++    return NULL;
++  }
++  
++private:
++  Jid jid_;
++  XmppPassword password_;
++
++};
++
++
++}
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc	(revision 586398)
+@@ -0,0 +1,68 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/base64.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmpp/constants.h"
++#include "talk/xmpp/saslmechanism.h"
++
++namespace buzz {
++
++XmlElement *
++SaslMechanism::StartSaslAuth() {
++  return new XmlElement(QN_SASL_AUTH, true);
++}
++
++XmlElement *
++SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
++  return new XmlElement(QN_SASL_ABORT, true);
++}
++
++void
++SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
++}
++
++void
++SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
++}
++
++std::string
++SaslMechanism::Base64Encode(const std::string & plain) {
++  return Base64::encode(plain);
++}
++
++std::string
++SaslMechanism::Base64Decode(const std::string & encoded) {
++  return Base64::decode(encoded);
++}
++
++std::string
++SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
++  return Base64::encodeFromArray(plain, length);
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _ASYNCSOCKET_H_
++#define _ASYNCSOCKET_H_
++
++#include "talk/base/sigslot.h"
++
++namespace cricket {
++  class SocketAddress;
++}
++
++namespace buzz {
++
++class AsyncSocket {
++public:
++  enum State {
++    STATE_CLOSED = 0,      //!< Socket is not open.
++    STATE_CLOSING,         //!< Socket is closing but can have buffered data
++    STATE_CONNECTING,      //!< In the process of
++    STATE_OPEN,            //!< Socket is connected
++#if defined(FEATURE_ENABLE_SSL)
++    STATE_TLS_CONNECTING,  //!< Establishing TLS connection
++    STATE_TLS_OPEN,        //!< TLS connected
++#endif
++  };
++
++  enum Error {
++    ERROR_NONE = 0,         //!< No error
++    ERROR_WINSOCK,          //!< Winsock error
++    ERROR_DNS,              //!< Couldn't resolve host name
++    ERROR_WRONGSTATE,       //!< Call made while socket is in the wrong state
++#if defined(FEATURE_ENABLE_SSL)
++    ERROR_SSL,              //!< Something went wrong with OpenSSL
++#endif
++  };
++
++  virtual ~AsyncSocket() {}
++  virtual State state() = 0;
++  virtual Error error() = 0;
++
++  virtual bool Connect(const cricket::SocketAddress& addr) = 0;
++  virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
++  virtual bool Write(const char * data, size_t len) = 0;
++  virtual bool Close() = 0;
++#if defined(FEATURE_ENABLE_SSL)
++  // We allow matching any passed domain.
++  // If both names are passed as empty, we do not require a match.
++  virtual bool StartTls(const std::string & domainname) = 0;
++#endif
++
++  sigslot::signal0<> SignalConnected;
++  sigslot::signal0<> SignalSSLConnected;
++  sigslot::signal0<> SignalClosed;
++  sigslot::signal0<> SignalRead;
++  sigslot::signal0<> SignalError;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h	(revision 586398)
+@@ -0,0 +1,74 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _SASLMECHANISM_H_
++#define _SASLMECHANISM_H_
++
++#include <string>
++
++namespace buzz {
++
++class XmlElement;
++
++
++// Defines a mechnanism to do SASL authentication.
++// Subclass instances should have a self-contained way to present
++// credentials.
++class SaslMechanism {
++
++public:
++  
++  // Intended to be subclassed
++  virtual ~SaslMechanism() {}
++
++  // Should return the name of the SASL mechanism, e.g., "PLAIN"
++  virtual std::string GetMechanismName() = 0;
++
++  // Should generate the initial "auth" request.  Default is just <auth/>.
++  virtual XmlElement * StartSaslAuth();
++
++  // Should respond to a SASL "<challenge>" request.  Default is
++  // to abort (for mechanisms that do not do challenge-response)
++  virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
++
++  // Notification of a SASL "<success>".  Sometimes information
++  // is passed on success.
++  virtual void HandleSaslSuccess(const XmlElement * success);
++
++  // Notification of a SASL "<failure>".  Sometimes information
++  // for the user is passed on failure.
++  virtual void HandleSaslFailure(const XmlElement * failure);
++
++protected:
++  static std::string Base64Encode(const std::string & plain);
++  static std::string Base64Decode(const std::string & encoded);
++  static std::string Base64EncodeFromArray(const char * plain, size_t length);
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS=base p2p xmllite xmpp session third_party 
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c	(revision 586398)
+@@ -0,0 +1,244 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <config.h>
++
++#ifdef HAVE_ILBC
++
++#include <stdlib.h>
++#include <stdio.h>
++#include "msilbcenc.h"
++
++
++extern MSCodecInfo ilbc_info;
++
++/* The return value of each of these calls is the same as that
++   returned by fread/fwrite, which should be the number of samples
++   successfully read/written, not the number of bytes. */
++
++int
++ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n)
++{
++    int i;
++
++    /* Convert 16 bit integer samples to floating point values in the
++       range [-1,+1]. */
++
++    for (i = 0; i < n; i++) {
++        speech[i] = int16samples[i];
++    }
++
++    return (n);
++}
++
++
++
++int
++ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n)
++{
++	int i;
++	float real_sample;
++
++	/* Convert floating point samples in range [-1,+1] to 16 bit
++	   integers. */
++	for (i = 0; i < n; i++) {
++		float dtmp=speech[i]; 
++		if (dtmp<MIN_SAMPLE) 
++			dtmp=MIN_SAMPLE; 
++		else if (dtmp>MAX_SAMPLE) 
++			dtmp=MAX_SAMPLE; 
++		int16samples[i] = (short) dtmp; 
++	}
++	return (n);
++}
++
++/*
++
++Write the bits in bits[0] through bits[len-1] to file f, in "packed"
++format.
++
++bits is expected to be an array of len integer values, where each
++integer is 0 to represent a 0 bit, and any other value represents a 1
++bit.  This bit string is written to the file f in the form of several
++8 bit characters.  If len is not a multiple of 8, then the last
++character is padded with 0 bits -- the padding is in the least
++significant bits of the last byte.  The 8 bit characters are "filled"
++in order from most significant bit to least significant.
++
++*/
++
++void
++ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes)
++{
++	memcpy(data, bits, nbytes);
++}
++
++
++
++/*
++
++Read bits from file f into bits[0] through bits[len-1], in "packed"
++format.
++
++*/
++
++int
++ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes)
++{
++
++	memcpy(bits, data, nbytes);
++
++	return (nbytes);
++}
++
++
++
++
++static MSILBCEncoderClass *ms_ilbc_encoder_class=NULL;
++
++MSFilter * ms_ilbc_encoder_new(void)
++{
++	MSILBCEncoder *r;
++	
++	r=g_new(MSILBCEncoder,1);
++	ms_ilbc_encoder_init(r);
++	if (ms_ilbc_encoder_class==NULL)
++	{
++		ms_ilbc_encoder_class=g_new(MSILBCEncoderClass,1);
++		ms_ilbc_encoder_class_init(ms_ilbc_encoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_encoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++int ms_ilbc_encoder_set_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FMTP:
++			if (value == NULL) return 0;
++			if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
++			else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
++			else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
++		break;
++	}
++	return 0;
++}
++
++
++int ms_ilbc_encoder_get_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FMTP:
++			if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
++			if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
++		break;
++	}
++	return 0;
++}
++
++void ms_ilbc_encoder_setup(MSILBCEncoder *r) 
++{
++	MSFilterClass *klass = NULL;
++	switch (r->ms_per_frame) {
++	case 20:
++		r->samples_per_frame = BLOCKL_20MS;
++		r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
++		break;
++	case 30:
++		r->samples_per_frame = BLOCKL_30MS;
++		r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
++		break;
++	default:
++		g_error("Bad bitrate value (%i) for ilbc encoder!", r->ms_per_frame);
++		break;
++	}
++	MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
++	g_message("Using ilbc encoder with %i ms frames mode.",r->ms_per_frame);
++	initEncode(&r->ilbc_enc, r->ms_per_frame /* ms frames */);
++}
++
++/* FOR INTERNAL USE*/
++void ms_ilbc_encoder_init(MSILBCEncoder *r)
++{
++	/* default bitrate */
++	r->bitrate = 15200;
++	r->ms_per_frame = 20;
++	r->samples_per_frame = BLOCKL_20MS;
++	r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
++
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outqueues=r->q_outputs;
++	MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
++	memset(r->q_outputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
++}
++
++void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCEnc");
++	MS_FILTER_CLASS(klass)->max_finputs=MSILBCENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_qoutputs=MSILBCENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=ILBC_MAX_SAMPLES_PER_FRAME*2;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_encoder_set_property;
++	MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_encoder_get_property;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_encoder_setup;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_encoder_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_encoder_process;
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
++}
++	
++void ms_ilbc_encoder_process(MSILBCEncoder *r)
++{
++	MSFifo *fi;
++	MSQueue *qo;
++	MSMessage *m;
++	void *src=NULL;
++	float speech[ILBC_MAX_SAMPLES_PER_FRAME];
++	
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	qo=r->q_outputs[0];
++	fi=r->f_inputs[0];
++	ms_fifo_get_read_ptr(fi,r->samples_per_frame*2,&src);
++	if (src==NULL) {
++		g_warning( "src=%p\n", src);
++		return;
++	}
++	m=ms_message_new(r->bytes_per_compressed_frame);
++
++	ilbc_read_16bit_samples((gint16*)src, speech, r->samples_per_frame);
++	iLBC_encode((unsigned char *)m->data, speech, &r->ilbc_enc);
++	ms_queue_put(qo,m);
++}
++
++void ms_ilbc_encoder_uninit(MSILBCEncoder *obj)
++{
++}
++
++void ms_ilbc_encoder_destroy( MSILBCEncoder *obj)
++{
++	ms_ilbc_encoder_uninit(obj);
++	g_free(obj);
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h	(revision 586398)
+@@ -0,0 +1,84 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSILBCENCODER_H
++#define MSILBCENCODER_H
++
++#include "mscodec.h"
++#include <iLBC_encode.h>
++
++#define ILBC_BITS_IN_COMPRESSED_FRAME 400
++
++int
++ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n);
++
++int
++ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n);
++
++void
++ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes);
++
++int
++ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes);
++
++
++/*this is the class that implements a ILBCencoder filter*/
++
++#define MSILBCENCODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSILBCEncoder
++{
++     /* the MSILBCEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCEncoder object
++       in order to the object mechanism to work*/
++     MSFilter filter;
++     MSFifo *f_inputs[MSILBCENCODER_MAX_INPUTS];
++     MSQueue *q_outputs[MSILBCENCODER_MAX_INPUTS];
++     iLBC_Enc_Inst_t ilbc_enc;
++     int ilbc_encoded_bytes;
++     int bitrate;
++     int ms_per_frame;
++     int samples_per_frame;
++     int bytes_per_compressed_frame;
++} MSILBCEncoder;
++
++typedef struct _MSILBCEncoderClass
++{
++	/* the MSILBCEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCEncoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSILBCEncoderClass;
++
++/* PUBLIC */
++#define MS_ILBCENCODER(filter) ((MSILBCEncoder*)(filter))
++#define MS_ILBCENCODER_CLASS(klass) ((MSILBCEncoderClass*)(klass))
++MSFilter * ms_ilbc_encoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_ilbc_encoder_init(MSILBCEncoder *r);
++void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass);
++void ms_ilbc_encoder_destroy( MSILBCEncoder *obj);
++void ms_ilbc_encoder_process(MSILBCEncoder *r);
++
++#define ILBC_MAX_BYTES_PER_COMPRESSED_FRAME NO_OF_BYTES_30MS
++#define ILBC_MAX_SAMPLES_PER_FRAME BLOCKL_30MS
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSUTILS_H
++#define MSUTILS_H
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#ifdef HAVE_GLIB
++#include <glib.h>
++#else
++#include <uglib.h>
++#endif
++#include <errno.h>
++
++#ifndef ENODATA
++/* this is for freeBSD .*/
++#define ENODATA EWOULDBLOCK	
++#endif
++
++#ifdef MS_DEBUG
++
++#define ms_trace g_message
++
++#else
++
++#define ms_trace(...)
++#endif
++
++#define ms_warning g_warning
++#define ms_error g_error
++
++#define VIDEO_SIZE_CIF_W 352
++#define VIDEO_SIZE_CIF_H 288
++#define VIDEO_SIZE_QCIF_W 176
++#define VIDEO_SIZE_QCIF_H 144
++#define VIDEO_SIZE_4CIF_W 704
++#define VIDEO_SIZE_4CIF_H 576
++#define VIDEO_SIZE_MAX_W VIDEO_SIZE_4CIF_W
++#define VIDEO_SIZE_MAX_H VIDEO_SIZE_4CIF_H
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms	(revision 586398)
+@@ -0,0 +1,34 @@
++
++OBJEXT=o
++AR = ar
++RANLIB = ranlib
++DEFS= -DG_LOG_DOMAIN=\"MediaStreamer\"
++INCLUDES=-I/usr/local/include/glib-2.0   -I/usr/local/lib/glib-2.0/include/ \
++                  -I../gsmlib/   -I../lpc10-1.5  -I../oRTP
++COMPILE= gcc $(DEFS)   $(INCLUDES)
++LIBTOOL=libtool
++LDFLAGS=-L/usr/local/lib/ -lglib-1.3 -lgthread-1.3 -lpthread
++LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
++
++libmediastreamer_a_OBJECTS =  msfilter.$(OBJEXT) msbuffer.$(OBJEXT) \
++msqueue.$(OBJEXT) msfifo.$(OBJEXT) ms.$(OBJEXT) mssync.$(OBJEXT) \
++msnosync.$(OBJEXT) msread.$(OBJEXT) mswrite.$(OBJEXT) mscopy.$(OBJEXT) \
++msv4lsource.$(OBJEXT) msoss.$(OBJEXT) msosswrite.$(OBJEXT) \
++msossread.$(OBJEXT) msringplayer.$(OBJEXT) msGSMencoder.$(OBJEXT) \
++msGSMdecoder.$(OBJEXT) msLPC10encoder.$(OBJEXT) \
++msLPC10decoder.$(OBJEXT)
++
++all:  libmediastreamer.a mstest
++
++
++.c.o:
++	$(COMPILE) -c $<
++
++libmediastreamer.a: $(libmediastreamer_a_OBJECTS)
++	-rm -f libmediastreamer.a
++	$(AR) cru libmediastreamer.a $(libmediastreamer_a_OBJECTS)
++	$(RANLIB) libmediastreamer.a
++
++
++mstest:	test.o libmediastreamer.a
++	gcc -o mstest test.o libmediastreamer.a $(LDFLAGS) -Wl,-rpath /usr/local/lib
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c	(revision 586398)
+@@ -0,0 +1,182 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msread.h"
++#include "mssync.h"
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <string.h>
++#include <errno.h>
++
++static MSReadClass *ms_read_class=NULL;
++
++MSFilter * ms_read_new(char *name)
++{
++	MSRead *r;
++	int fd=-1;
++	
++	r=g_new(MSRead,1);
++	ms_read_init(r);
++	if (ms_read_class==NULL)
++	{
++		ms_read_class=g_new(MSReadClass,1);
++		ms_read_class_init(ms_read_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_read_class);
++	r->fd=-1;
++	if (name!=NULL) ms_read_open(r,name);
++	return(MS_FILTER(r));
++}
++	
++
++
++gint ms_read_open(MSRead *r, gchar *name)
++{
++	gint fd;
++	fd=open(name,O_RDONLY);
++	if (fd<0) {
++		r->fd=-1;
++		g_warning("ms_read_new: cannot open %s : %s",name,strerror(errno));
++		return -1;
++	}
++	r->fd=fd;
++	if (strstr(name,".wav")!=NULL){
++		/* skip the header */
++		lseek(fd,20,SEEK_SET);
++#ifdef WORDS_BIGENDIAN
++		r->need_swap=1;	
++#else
++		r->need_swap=0;
++#endif
++	}
++	r->state=MS_READ_STATE_STARTED;
++	return 0;
++}
++
++/* FOR INTERNAL USE*/
++void ms_read_init(MSRead *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->outfifos=r->foutputs;
++	MS_FILTER(r)->outqueues=r->qoutputs;
++	memset(r->foutputs,0,sizeof(MSFifo*)*MSREAD_MAX_OUTPUTS);
++	memset(r->qoutputs,0,sizeof(MSQueue*)*MSREAD_MAX_OUTPUTS);
++	r->fd=-1;
++	r->gran=320;
++	r->state=MS_READ_STATE_STOPPED;
++	r->need_swap=0;
++	r->rate=8000;
++}
++
++gint ms_read_set_property(MSRead *f,MSFilterProperty prop, void *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			f->rate=((gint*)value)[0];
++		break;
++	}
++	return 0;
++}
++
++void ms_read_class_init(MSReadClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskreader");
++	ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
++	MS_FILTER_CLASS(klass)->max_foutputs=MSREAD_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->max_qoutputs=MSREAD_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->w_maxgran=MSREAD_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_read_destroy;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_read_setup;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_read_process;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_read_set_property;
++}
++
++void ms_read_process(MSRead *r)
++{
++	MSFifo *f;
++	MSQueue *q;
++	MSMessage *msg=NULL;
++	int err;
++	gint gran=r->gran;
++	void *p;
++	
++	f=r->foutputs[0];
++	if ((f!=NULL) && (r->state==MS_READ_STATE_STARTED))
++	{
++		ms_fifo_get_write_ptr(f,gran,&p);
++		if (p!=NULL)
++		{
++			err=read(r->fd,p,gran);
++			if (err<0)
++			{
++				/* temp: */
++				g_warning("ms_read_process: failed to read: %s.\n",strerror(errno));
++			}
++			else if (err<gran){
++				ms_trace("ms_read_process: end of file.");
++				ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
++				r->state=MS_READ_STATE_STOPPED;
++				close(r->fd);
++				r->fd=-1;
++			}
++			if (r->need_swap) swap_buffer(p,gran);
++		}
++	}
++	/* process output queues*/
++	q=r->qoutputs[0];
++	if ((q!=NULL) && (r->fd>0))
++	{
++		msg=ms_message_new(r->gran);
++		err=read(r->fd,msg->data,r->gran);
++		if (err>0){
++			msg->size=err;
++			ms_queue_put(q,msg);
++			if (r->need_swap) swap_buffer(msg->data,r->gran);
++		}else{
++			ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
++			ms_trace("End of file reached.");
++			r->state=MS_READ_STATE_STOPPED;
++		}				
++	}	
++}
++
++void ms_read_destroy( MSRead *obj)
++{
++	if (obj->fd!=0) close(obj->fd);
++	g_free(obj);
++}
++
++gint ms_read_close(MSRead *obj)
++{
++	if (obj->fd!=0) {
++		close(obj->fd);
++		obj->fd=-1;
++		obj->state=MS_READ_STATE_STOPPED;
++	}
++}
++
++
++void ms_read_setup(MSRead *r, MSSync *sync)
++{
++	r->sync=sync;
++	r->gran=(r->rate*sync->interval/1000)*2;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c	(revision 586398)
+@@ -0,0 +1,250 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "mscodec.h"
++#include "msMUlawdec.h"
++
++#ifdef TRUESPEECH
++extern MSCodecInfo TrueSpeechinfo;
++#endif
++
++#ifdef VIDEO_ENABLED
++extern void ms_AVCodec_init();
++#endif
++
++#define UDP_HDR_SZ 8
++#define RTP_HDR_SZ 12
++#define IP4_HDR_SZ 20   /*20 is the minimum, but there may be some options*/
++
++
++
++
++/* register all statically linked codecs */
++void ms_codec_register_all()
++{
++/*//	ms_filter_register(MS_FILTER_INFO(&GSMinfo));
++	//	ms_filter_register(MS_FILTER_INFO(&LPC10info));*/
++	ms_filter_register(MS_FILTER_INFO(&MULAWinfo));
++#ifdef TRUESPEECH
++        ms_filter_register(MS_FILTER_INFO(&TrueSpeechinfo));
++#endif
++#ifdef VIDEO_ENABLED
++	ms_AVCodec_init();
++#endif
++	
++}
++
++/* returns a list of MSCodecInfo */
++GList * ms_codec_get_all_audio()
++{
++	GList *audio_codecs=NULL;
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if (info->type==MS_FILTER_AUDIO_CODEC){
++			audio_codecs=g_list_append(audio_codecs,info);
++		}
++		elem=g_list_next(elem);
++	}
++	return audio_codecs;
++}
++
++
++MSCodecInfo * ms_audio_codec_info_get(gchar *name)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ( (info->type==MS_FILTER_AUDIO_CODEC) ){
++			MSCodecInfo *codinfo=(MSCodecInfo *)info;
++			if (strcmp(codinfo->description,name)==0){
++				return MS_CODEC_INFO(info);
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSCodecInfo * ms_video_codec_info_get(gchar *name)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ( (info->type==MS_FILTER_VIDEO_CODEC) ){
++			MSCodecInfo *codinfo=(MSCodecInfo *)info;
++			if (strcmp(codinfo->description,name)==0){
++				return MS_CODEC_INFO(info);
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++/* returns a list of MSCodecInfo */
++GList * ms_codec_get_all_video()
++{
++	GList *video_codecs=NULL;
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if (info->type==MS_FILTER_VIDEO_CODEC){
++			video_codecs=g_list_append(video_codecs,info);
++		}
++		elem=g_list_next(elem);
++	}
++	return video_codecs;
++}
++
++MSFilter * ms_encoder_new(gchar *name)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (strcmp(info->name,name)==0){
++				return codinfo->encoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSFilter * ms_decoder_new(gchar *name)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (strcmp(info->name,name)==0){
++				return codinfo->decoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSFilter * ms_encoder_new_with_pt(gint pt)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (codinfo->pt==pt){
++				return codinfo->encoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSFilter * ms_decoder_new_with_pt(gint pt)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (codinfo->pt==pt){
++				return codinfo->decoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSFilter * ms_decoder_new_with_string_id(gchar *id)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (strcasecmp(codinfo->description,id)==0){
++				return codinfo->decoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++
++MSFilter * ms_encoder_new_with_string_id(gchar *id)
++{
++	GList *elem=filter_list;
++	MSFilterInfo *info;
++	while (elem!=NULL)
++	{
++		info=(MSFilterInfo *)elem->data;
++		if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
++			MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
++			if (strcasecmp(codinfo->description,id)==0){
++				return codinfo->encoder();
++			}
++		}
++		elem=g_list_next(elem);
++	}
++	return NULL;
++}
++/* return 0 if codec can be used with bandwidth, -1 else*/
++int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth)
++{
++	double codec_band;
++	double npacket;
++	double packet_size;
++	
++	if (((MSFilterInfo*)codec)->type==MS_FILTER_AUDIO_CODEC)
++	{
++		/* calculate the total bandwdith needed by codec (including headers for rtp, udp, ip)*/		
++		/* number of packet per second*/
++		npacket=2.0*(double)(codec->rate)/(double)(codec->fr_size);
++		packet_size=(double)(codec->dt_size)+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
++		codec_band=packet_size*8.0*npacket;
++	}
++	else return -1;
++	return(codec_band<bandwidth);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c	(revision 586398)
+@@ -0,0 +1,209 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "sndcard.h"
++#include "msfilter.h"
++
++void snd_card_init(SndCard *obj)
++{
++	memset(obj,0,sizeof(SndCard));
++}
++
++void snd_card_uninit(SndCard *obj)
++{
++	if (obj->card_name!=NULL) g_free(obj->card_name);
++}
++
++const gchar *snd_card_get_identifier(SndCard *obj)
++{
++	return obj->card_name;
++}
++
++int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate)
++{
++	g_return_val_if_fail(obj->_open_r!=NULL,-1);
++	g_message("Opening sound card [%s] in capture mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
++	return obj->_open_r(obj,bits,stereo,rate);
++}
++int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate)
++{
++	g_return_val_if_fail(obj->_open_w!=NULL,-1);
++	g_message("Opening sound card [%s] in playback mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
++	return obj->_open_w(obj,bits,stereo,rate); 
++}
++
++gboolean snd_card_can_read(SndCard *obj){
++	g_return_val_if_fail(obj->_can_read!=NULL,-1);
++	return obj->_can_read(obj);
++}
++
++void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno){
++	g_return_if_fail(obj->_set_blocking_mode!=NULL);
++	obj->_set_blocking_mode(obj,yesno);
++}
++
++int snd_card_read(SndCard *obj,char *buffer,int size)
++{
++	g_return_val_if_fail(obj->_read!=NULL,-1);
++	return obj->_read(obj,buffer,size);
++}
++int snd_card_write(SndCard *obj,char *buffer,int size)
++{
++	g_return_val_if_fail(obj->_write!=NULL,-1);
++	return obj->_write(obj,buffer,size);
++}
++
++int snd_card_get_bsize(SndCard *obj)
++{
++	if (obj->flags & SND_CARD_FLAGS_OPENED){
++		return obj->bsize;
++	}
++	return -1;
++}
++
++void snd_card_close_r(SndCard *obj)
++{
++	g_return_if_fail(obj->_close_r!=NULL);
++	g_message("Closing reading channel of soundcard.");
++	obj->_close_r(obj);
++}
++
++void snd_card_close_w(SndCard *obj)
++{
++	g_return_if_fail(obj->_close_w!=NULL);
++	g_message("Closing writing channel of soundcard.");
++	obj->_close_w(obj);
++}
++
++gint snd_card_probe(SndCard *obj,int bits, int stereo, int rate)
++{
++	g_return_val_if_fail(obj->_probe!=NULL,-1);
++	return obj->_probe(obj,bits,stereo,rate);
++}
++
++void snd_card_set_rec_source(SndCard *obj, int source)
++{
++	g_return_if_fail(obj->_set_rec_source!=NULL);
++	obj->_set_rec_source(obj,source);
++}
++
++void snd_card_set_level(SndCard *obj, int way, int level)
++{
++	g_return_if_fail(obj->_set_level!=NULL);
++	obj->_set_level(obj,way,level);
++}
++
++gint snd_card_get_level(SndCard *obj,int way)
++{
++	g_return_val_if_fail(obj->_get_level!=NULL,-1);
++	return obj->_get_level(obj,way);
++}
++
++
++MSFilter * snd_card_create_read_filter(SndCard *obj)
++{
++	g_return_val_if_fail(obj->_create_read_filter!=NULL,NULL);
++	return obj->_create_read_filter(obj);
++}
++MSFilter * snd_card_create_write_filter(SndCard *obj)
++{
++	g_return_val_if_fail(obj->_create_write_filter!=NULL,NULL);
++	return obj->_create_write_filter(obj);
++}
++
++
++#ifdef HAVE_SYS_AUDIO_H
++gint sys_audio_manager_init(SndCardManager *manager, gint index)
++{
++	/* this is a quick shortcut, as multiple soundcards on HPUX does not happen
++	very often... */
++	manager->cards[index]=hpux_snd_card_new("/dev/audio","/dev/audio");
++	return 1;
++}
++
++#endif
++
++#include "osscard.h"
++#include "alsacard.h"
++#include "jackcard.h"
++
++void snd_card_manager_init(SndCardManager *manager)
++{
++	gint index=0;
++	gint tmp=0;
++	memset(manager,0,sizeof(SndCardManager));
++	#ifdef HAVE_SYS_SOUNDCARD_H
++	tmp=oss_card_manager_init(manager,index);
++	index+=tmp;
++	if (index>=MAX_SND_CARDS) return;
++	#endif
++	#ifdef __ALSA_ENABLED__
++	tmp=alsa_card_manager_init(manager,index);
++	index+=tmp;
++	if (index>=MAX_SND_CARDS) return;
++	#endif
++	#ifdef __JACK_ENABLED__
++	tmp=jack_card_manager_init(manager,index);
++	index+=tmp;
++	if (index>=MAX_SND_CARDS) return;
++	#endif
++	#ifdef HAVE_PORTAUDIO
++	tmp=portaudio_card_manager_init(manager,index);
++	index+=tmp;
++	if (index>=MAX_SND_CARDS) return;
++	#endif
++	#ifdef HAVE_SYS_AUDIO_H
++	tmp=sys_audio_manager_init(manager,index);
++	index+=tmp;
++	#endif
++}
++
++
++
++
++
++SndCard * snd_card_manager_get_card(SndCardManager *manager,int index)
++{
++	g_return_val_if_fail(index>=0,NULL);
++	g_return_val_if_fail(index<MAX_SND_CARDS,NULL);
++	if (index>MAX_SND_CARDS) return NULL;
++	return manager->cards[index];	
++}
++
++SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index)
++{
++	int i;
++	for (i=0;i<MAX_SND_CARDS;i++){
++		gchar *card_name;
++		if (manager->cards[i]==NULL) continue;
++		card_name=manager->cards[i]->card_name;
++		if (card_name==NULL) continue;
++		if (strcmp(card_name,cardname)==0){
++			*index=i;
++			return manager->cards[i];
++		}
++	}
++	g_warning("No card %s found.",cardname);
++	return NULL;
++}
++
++SndCardManager _snd_card_manager;
++SndCardManager *snd_card_manager=&_snd_card_manager;
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c	(revision 586398)
+@@ -0,0 +1,247 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msosswrite.h"
++#include "mssync.h"
++#include <unistd.h>
++#include <math.h>
++
++MSFilterInfo oss_write_info={
++	"OSS write",
++	0,
++	MS_FILTER_OTHER,
++	ms_oss_write_new,
++	NULL
++};
++
++
++static MSOssWriteClass *msosswriteclass=NULL;
++
++MSFilter * ms_oss_write_new()
++{
++	MSOssWrite *w;
++	
++  if (msosswriteclass==NULL)
++	{
++		msosswriteclass=g_new(MSOssWriteClass,1);
++		ms_oss_write_class_init( msosswriteclass );
++	}
++	w=g_new(MSOssWrite,1);
++	MS_FILTER(w)->klass=MS_FILTER_CLASS(msosswriteclass);
++	ms_oss_write_init(w);
++	return(MS_FILTER(w));
++}
++
++/* FOR INTERNAL USE*/
++void ms_oss_write_init(MSOssWrite *w)
++{
++	ms_sound_write_init(MS_SOUND_WRITE(w));
++	MS_FILTER(w)->infifos=w->f_inputs;
++	MS_FILTER(w)->infifos[0]=NULL;
++	MS_FILTER(w)->r_mingran=512;  /* very few cards can do that...*/
++	w->devid=0;
++	w->sndcard=NULL;
++	w->freq=8000;
++	w->channels=1;
++	w->dtmf_time=-1;
++}
++	
++gint ms_oss_write_set_property(MSOssWrite *f,MSFilterProperty prop, void *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			f->freq=((gint*)value)[0];
++		break;
++		case MS_FILTER_PROPERTY_CHANNELS:
++			f->channels=((gint*)value)[0];
++		break;
++	}
++	return 0;
++}
++
++void ms_oss_write_class_init(MSOssWriteClass *klass)
++{
++	ms_sound_write_class_init(MS_SOUND_WRITE_CLASS(klass));
++	MS_FILTER_CLASS(klass)->max_finputs=1;  /* one fifo input only */
++	MS_FILTER_CLASS(klass)->r_maxgran=MS_OSS_WRITE_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_write_process;
++	MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_write_destroy;
++	MS_FILTER_CLASS(klass)->setup= (MSFilterSetupFunc)ms_oss_write_setup;
++	MS_FILTER_CLASS(klass)->unsetup= (MSFilterSetupFunc)ms_oss_write_stop;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_write_set_property;
++	MS_FILTER_CLASS(klass)->info=&oss_write_info;
++	MS_SOUND_WRITE_CLASS(klass)->set_device=(gint (*)(MSSoundWrite*,gint))ms_oss_write_set_device;
++	MS_SOUND_WRITE_CLASS(klass)->start=(void (*)(MSSoundWrite*))ms_oss_write_start;
++	MS_SOUND_WRITE_CLASS(klass)->stop=(void (*)(MSSoundWrite*))ms_oss_write_stop;
++	MS_SOUND_WRITE_CLASS(klass)->set_level=(void (*)(MSSoundWrite*, gint))ms_oss_write_set_level;
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssWrite");
++}
++
++void ms_oss_write_destroy( MSOssWrite *obj)
++{
++	
++	g_free(obj);
++}
++
++void ms_oss_write_process(MSOssWrite *f)
++{
++	MSFifo *fifo;
++	void *p;
++	int i;
++	gint gran=ms_filter_get_mingran(MS_FILTER(f));
++	
++	/* always consume something */
++	fifo=f->f_inputs[0];
++	ms_fifo_get_read_ptr(fifo,gran,&p);
++	if (p==NULL) {
++		g_warning("Not enough data: gran=%i.",gran);
++		return;
++	}
++	g_return_if_fail(f->sndcard!=NULL);
++	if (f->dtmf_time!=-1){
++		gint16 *buf=(gint16*)p;
++		/* generate a DTMF*/
++		for(i=0;i<gran/2;i++){
++			buf[i]=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->lowfreq));
++			buf[i]+=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->highfreq));
++			f->dtmf_time++;
++			/* //printf("buf[%i]=%i\n",i,buf[i]); */
++		}
++		if (f->dtmf_time>f->dtmf_duration) f->dtmf_time=-1; /*finished*/
++	}
++	snd_card_write(f->sndcard,p,gran);
++}
++
++void ms_oss_write_start(MSOssWrite *w)
++{
++	gint bsize;
++	g_return_if_fail(w->devid!=-1);
++	w->sndcard=snd_card_manager_get_card(snd_card_manager,w->devid);
++	g_return_if_fail(w->sndcard!=NULL);
++	/* open the device for an audio telephony signal with minimum latency */
++	snd_card_open_w(w->sndcard,16,w->channels==2,w->freq);
++	w->bsize=snd_card_get_bsize(w->sndcard);
++	/* //MS_FILTER(w)->r_mingran=w->bsize; */
++	/* //ms_sync_set_samples_per_tick(MS_FILTER(w)->sync,bsize); */
++}
++
++void ms_oss_write_stop(MSOssWrite *w)
++{
++	g_return_if_fail(w->devid!=-1);
++	g_return_if_fail(w->sndcard!=NULL);
++	snd_card_close_w(w->sndcard);
++	w->sndcard=NULL;
++}
++
++void ms_oss_write_set_level(MSOssWrite *w,gint a)
++{
++	
++}
++
++gint ms_oss_write_set_device(MSOssWrite *w, gint devid)
++{
++	w->devid=devid;
++	return 0;
++}
++
++void ms_oss_write_setup(MSOssWrite *r)
++{
++	/* //g_message("starting MSOssWrite.."); */
++	ms_oss_write_start(r);
++}
++
++
++
++void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf){
++	
++	w->dtmf_duration=0.1*w->freq;
++	switch(dtmf){
++		case '0':
++			w->lowfreq=941;
++			w->highfreq=1336;
++			break;
++		case '1':
++			w->lowfreq=697;
++			w->highfreq=1209;
++			break;
++		case '2':
++			w->lowfreq=697;
++			w->highfreq=1336;
++			break;
++		case '3':
++			w->lowfreq=697;
++			w->highfreq=1477;
++			break;
++		case '4':
++			w->lowfreq=770;
++			w->highfreq=1209;
++			break;
++		case '5':
++			w->lowfreq=770;
++			w->highfreq=1336;
++			break;
++		case '6':
++			w->lowfreq=770;
++			w->highfreq=1477;
++			break;
++		case '7':
++			w->lowfreq=852;
++			w->highfreq=1209;
++			break;
++		case '8':
++			w->lowfreq=852;
++			w->highfreq=1336;
++			break;
++		case '9':
++			w->lowfreq=852;
++			w->highfreq=1477;
++			break;
++		case '*':
++			w->lowfreq=941;
++			w->highfreq=1209;
++			break;
++		case '#':
++			w->lowfreq=941;
++			w->highfreq=1477;
++			break;
++		case 'A':
++			w->lowfreq=697;
++			w->highfreq=1633;
++			break;
++		case 'B':
++			w->lowfreq=770;
++			w->highfreq=1633;
++			break;
++		case 'C':
++			w->lowfreq=852;
++			w->highfreq=1633;
++			break;
++		case 'D':
++			w->lowfreq=941;
++			w->highfreq=1633;
++			break;	
++		default:
++			g_warning("Not a dtmf key.");
++			return;
++	}
++	w->lowfreq=w->lowfreq/w->freq;
++	w->highfreq=w->highfreq/w->freq;
++	w->dtmf_time=0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSREAD_H
++#define MSREAD_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++/*this is the class that implements file reading source filter*/
++
++#define MSREAD_MAX_OUTPUTS  1 /* max output per filter*/
++
++#define MSREAD_DEF_GRAN 640 /* the default granularity*/
++
++typedef enum{
++	MS_READ_STATE_STARTED,
++	MS_READ_STATE_STOPPED,
++	MS_READ_STATE_EOF
++}MSReadState;
++
++typedef struct _MSRead
++{
++    /* the MSRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSRead object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *foutputs[MSREAD_MAX_OUTPUTS];
++    MSQueue *qoutputs[MSREAD_MAX_OUTPUTS];
++	MSSync *sync;
++	gint rate;
++    gint fd;  /* the file descriptor of the file being read*/
++    gint gran;  /*granularity*/  /* for use with queues */
++	gint need_swap;
++	gint state;
++} MSRead;
++
++typedef struct _MSReadClass
++{
++	/* the MSRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSRead class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSReadClass;
++
++/* PUBLIC */
++#define MS_READ(filter) ((MSRead*)(filter))
++#define MS_READ_CLASS(klass) ((MSReadClass*)(klass))
++MSFilter * ms_read_new(char *name);
++/* set the granularity for reading file on disk */
++#define ms_read_set_bufsize(filter,sz) (filter)->gran=(sz)
++
++/* FOR INTERNAL USE*/
++void ms_read_init(MSRead *r);
++void ms_read_class_init(MSReadClass *klass);
++void ms_read_destroy( MSRead *obj);
++void ms_read_process(MSRead *r);
++void ms_read_setup(MSRead *r, MSSync *sync);
++
++typedef enum{
++	MS_READ_EVENT_EOF	/* end of file */
++} MSReadEvent;
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h	(revision 586398)
+@@ -0,0 +1,67 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSCODEC_H
++#define MSCODEC_H
++
++#include "msfilter.h"
++
++struct _MSCodecInfo
++{
++	MSFilterInfo info;
++	MSFilterNewFunc encoder;
++	MSFilterNewFunc decoder;
++	gint fr_size; /* size in char of the uncompressed frame */
++	gint dt_size;	/* size in char of the compressed frame */
++	gint bitrate;  /* the minimum bit rate in bits/second */
++	gint rate;		/*frequency */
++	gint pt;			/* the payload type number associated with this codec*/
++	gchar *description;		/* a rtpmap field to describe the codec */
++	guint is_usable:1; /* linphone set this flag to remember if it can use this codec considering the total bandwidth*/
++	guint is_selected:1; /* linphone (user) set this flag if he allows this codec to be used*/
++};
++
++typedef struct _MSCodecInfo MSCodecInfo;
++
++MSFilter * ms_encoder_new(gchar *name);
++MSFilter * ms_decoder_new(gchar *name);
++
++MSFilter * ms_encoder_new_with_pt(gint pt);
++MSFilter * ms_decoder_new_with_pt(gint pt);
++
++MSFilter * ms_encoder_new_with_string_id(gchar *id);
++MSFilter * ms_decoder_new_with_string_id(gchar *id);
++
++/* return 0 if codec can be used with bandwidth, -1 else*/
++int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth);
++
++GList * ms_codec_get_all_audio();
++
++GList * ms_codec_get_all_video();
++
++MSCodecInfo * ms_audio_codec_info_get(gchar *name);
++MSCodecInfo * ms_video_codec_info_get(gchar *name);
++
++/* register all statically linked codecs */
++void ms_codec_register_all();
++
++#define MS_CODEC_INFO(codinfo)	((MSCodecInfo*)codinfo)
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c	(revision 586398)
+@@ -0,0 +1,301 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "sndcard.h"
++#include "osscard.h"
++
++#ifdef HAVE_SYS_AUDIO_H
++#include <sys/audio.h>
++
++
++#include "msossread.h"
++#include "msosswrite.h"
++
++#include <errno.h>
++#include <fcntl.h>
++
++
++int hpuxsnd_open(HpuxSndCard *obj, int bits,int stereo, int rate)
++{
++	int fd;
++	int p=0,cond=0;
++	int i=0;
++	int min_size=0,blocksize=512;
++	/* do a quick non blocking open to be sure that we are not going to be blocked here
++		for the eternity */
++	fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
++	if (fd<0) return -EWOULDBLOCK;
++	close(fd);
++	/* open the device */
++	fd=open(obj->dev_name,O_RDWR);
++
++	g_return_val_if_fail(fd>0,-errno);
++
++	ioctl(fd,AUDIO_RESET,0);
++	ioctl(fd,AUDIO_SET_SAMPLE_RATE,rate);
++	ioctl(fd,AUDIO_SET_CHANNELS,stereo);
++	p=AUDIO_FORMAT_LINEAR16BIT;
++	ioctl(fd,AUDIO_SET_DATA_FORMAT,p); 
++	/* ioctl(fd,AUDIO_GET_RXBUFSIZE,&min_size); does not work ? */
++	min_size=2048;
++
++	g_message("dsp blocksize is %i.",min_size);
++	obj->fd=fd;
++	obj->readpos=0;
++	obj->writepos=0;
++	SND_CARD(obj)->bits=bits;
++	SND_CARD(obj)->stereo=stereo;
++	SND_CARD(obj)->rate=rate;
++	SND_CARD(obj)->bsize=min_size;
++	return fd;
++}
++
++int hpux_snd_card_probe(HpuxSndCard *obj,int bits,int stereo,int rate)
++{
++	return 2048;
++}
++
++
++int hpux_snd_card_open(HpuxSndCard *obj,int bits,int stereo,int rate)
++{
++	int fd;
++	obj->ref++;
++	if (obj->fd==0){
++		fd=hpuxsnd_open(obj,bits,stereo,rate);
++		if (fd<0) {
++			obj->fd=0;
++			obj->ref--;
++			return -1;
++		}
++	}
++	SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
++	return 0;
++}
++
++void hpux_snd_card_close(HpuxSndCard *obj)
++{
++	int i;
++	obj->ref--;
++	if (obj->ref==0) {
++		close(obj->fd);
++		obj->fd=0;
++		SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
++		
++	}
++}
++
++void hpux_snd_card_destroy(HpuxSndCard *obj)
++{
++	snd_card_uninit(SND_CARD(obj));
++	g_free(obj->dev_name);
++	g_free(obj->mixdev_name);
++}
++
++gboolean hpux_snd_card_can_read(HpuxSndCard *obj)
++{
++	struct timeval tout={0,0};
++	int err;
++	fd_set fdset;
++	FD_ZERO(&fdset);
++	FD_SET(obj->fd,&fdset);
++	err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
++	if (err>0) return TRUE;
++	else return FALSE;
++}
++
++int hpux_snd_card_read(HpuxSndCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	if (size<bsize){
++		gint canread=MIN(bsize-obj->readpos,size);
++		if (obj->readbuf==NULL) obj->readbuf=g_malloc0(bsize);
++		if (obj->readpos==0){
++			err=read(obj->fd,obj->readbuf,bsize);
++			if (err<0) {
++				g_warning("hpux_snd_card_read: read() failed:%s.",strerror(errno));
++				return -1;
++			}
++		}
++			
++		memcpy(buf,&obj->readbuf[obj->readpos],canread);
++		obj->readpos+=canread;
++		if (obj->readpos>=bsize) obj->readpos=0;
++		return canread;
++	}else{
++		err=read(obj->fd,buf,size);
++		if (err<0) {
++			g_warning("hpux_snd_card_read: read-2() failed:%s.",strerror(errno));
++		}
++		return err;
++	}
++	
++}
++
++int hpux_snd_card_write(HpuxSndCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	if (size<bsize){
++		gint canwrite=MIN(bsize-obj->writepos,size);
++		if (obj->writebuf==NULL) obj->writebuf=g_malloc0(bsize);
++		
++		memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
++		obj->writepos+=canwrite;
++		if (obj->writepos>=bsize){
++			err=write(obj->fd,obj->writebuf,bsize);
++		}
++		return canwrite;
++	}else{
++		return write(obj->fd,buf,bsize);
++	}
++}
++
++#define SND_CARD_LEVEL_TO_HPUX_LEVEL(a)	 (((a)*2) - 100)
++#define HPUX_LEVEL_TO_SND_CARD_LEVEL(a)		(((a)+200)/2)
++void hpux_snd_card_set_level(HpuxSndCard *obj,gint way,gint a)
++{
++	struct audio_gain gain;
++	int error,mix_fd;
++		
++	g_return_if_fail(obj->mixdev_name!=NULL);
++	memset(&gain,0,sizeof(struct audio_gain));
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			gain.cgain[0].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++			gain.cgain[1].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			gain.cgain[0].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++			gain.cgain[1].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			gain.cgain[0].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++			gain.cgain[1].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
++		break;
++		default:
++			g_warning("hpux_snd_card_set_level: unsupported command.");
++			return;
++	}
++	gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
++	mix_fd = open(obj->mixdev_name, O_WRONLY);
++	g_return_if_fail(mix_fd>0);
++	error=ioctl(mix_fd,AUDIO_SET_GAINS,&gain);
++  	if (error<0){
++    	g_warning("hpux_snd_card_set_level: Could not set gains: %s",strerror(errno));
++	}
++	close(mix_fd);
++}
++
++gint hpux_snd_card_get_level(HpuxSndCard *obj,gint way)
++{
++	struct audio_gain gain;
++	int p=0,mix_fd,error;
++	g_return_if_fail(obj->mixdev_name!=NULL);
++	
++	gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
++	mix_fd = open(obj->mixdev_name, O_RDONLY);
++	g_return_if_fail(mix_fd>0);
++	error=ioctl(mix_fd,AUDIO_GET_GAINS,&gain);
++  	if (error<0){
++    	g_warning("hpux_snd_card_set_level: Could not get gains: %s",strerror(errno));
++	}
++	close(mix_fd);
++	
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			p=gain.cgain[0].monitor_gain;
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			p=gain.cgain[0].receive_gain;
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			p=gain.cgain[0].transmit_gain;
++		break;
++		default:
++			g_warning("hpux_snd_card_get_level: unsupported command.");
++			return -1;
++	}
++	return HPUX_LEVEL_TO_SND_CARD_LEVEL(p);
++}
++
++void hpux_snd_card_set_source(HpuxSndCard *obj,int source)
++{
++	gint p=0;
++	gint mix_fd;
++	gint error=0;
++	g_return_if_fail(obj->mixdev_name!=NULL);
++	
++	mix_fd=open("/dev/audio",O_WRONLY);
++	g_return_if_fail(mix_fd>0);
++	switch(source){
++		case 'm':
++			error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE);
++		break;
++		case 'l':
++			error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_LINE);
++		break;
++		default:
++			g_warning("hpux_snd_card_set_source: unsupported source.");
++	}
++	close(mix_fd);
++}
++
++MSFilter *hpux_snd_card_create_read_filter(HpuxSndCard *card)
++{
++	MSFilter *f=ms_oss_read_new();
++	ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
++	return f;
++}
++
++MSFilter *hpux_snd_card_create_write_filter(HpuxSndCard *card)
++{
++	MSFilter *f=ms_oss_write_new();
++	ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
++	return f;
++}
++
++
++SndCard * hpux_snd_card_new(char *devname, char *mixdev_name)
++{
++	HpuxSndCard * obj= g_new0(HpuxSndCard,1);
++	SndCard *base= SND_CARD(obj);
++	snd_card_init(base);
++	obj->dev_name=g_strdup(devname);
++	obj->mixdev_name=g_strdup( mixdev_name);
++	base->card_name=g_strdup(devname);
++	base->_probe=(SndCardOpenFunc)hpux_snd_card_probe;
++	base->_open_r=(SndCardOpenFunc)hpux_snd_card_open;
++	base->_open_w=(SndCardOpenFunc)hpux_snd_card_open;
++	base->_can_read=(SndCardPollFunc)hpux_snd_card_can_read;
++	base->_read=(SndCardIOFunc)hpux_snd_card_read;
++	base->_write=(SndCardIOFunc)hpux_snd_card_write;
++	base->_close_r=(SndCardCloseFunc)hpux_snd_card_close;
++	base->_close_w=(SndCardCloseFunc)hpux_snd_card_close;
++	base->_set_rec_source=(SndCardMixerSetRecSourceFunc)hpux_snd_card_set_source;
++	base->_set_level=(SndCardMixerSetLevelFunc)hpux_snd_card_set_level;
++	base->_get_level=(SndCardMixerGetLevelFunc)hpux_snd_card_get_level;
++	base->_destroy=(SndCardDestroyFunc)hpux_snd_card_destroy;
++	base->_create_read_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_read_filter;
++	base->_create_write_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_write_filter;
++	return base;
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h	(revision 586398)
+@@ -0,0 +1,143 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++
++#ifndef SNDCARD_H
++#define SNDCARD_H
++
++#undef PACKAGE
++#undef VERSION
++#include <config.h>
++#undef PACKAGE
++#undef VERSION
++
++#ifdef HAVE_GLIB
++#include <glib.h>
++#else
++#include <uglib.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++	
++/* the base class for all soundcards: SndCard */
++struct _SndCard;
++	
++typedef int (*SndCardOpenFunc)(struct _SndCard*,int, int, int);
++typedef void (*SndCardSetBlockingModeFunc)(struct _SndCard*, gboolean );
++typedef void (*SndCardCloseFunc)(struct _SndCard*);
++typedef gint (*SndCardIOFunc)(struct _SndCard*,char *,int);
++typedef void (*SndCardDestroyFunc)(struct _SndCard*);
++typedef gboolean (*SndCardPollFunc)(struct _SndCard*);
++typedef gint (*SndCardMixerGetLevelFunc)(struct _SndCard*,gint);
++typedef void (*SndCardMixerSetRecSourceFunc)(struct _SndCard*,gint);	
++typedef void (*SndCardMixerSetLevelFunc)(struct _SndCard*,gint ,gint);
++typedef struct _MSFilter * (*SndCardCreateFilterFunc)(struct _SndCard *);	
++
++struct _SndCard
++{
++	gchar *card_name;          /* SB16 PCI for example */
++	gint index;
++	gint bsize;
++	gint rate;
++	gint stereo;
++	gint bits;
++	gint flags;
++#define SND_CARD_FLAGS_OPENED 1
++	SndCardOpenFunc _probe;
++	SndCardOpenFunc _open_r;
++	SndCardOpenFunc _open_w;
++	SndCardSetBlockingModeFunc _set_blocking_mode;
++	SndCardPollFunc _can_read;
++	SndCardIOFunc _read;
++	SndCardIOFunc _write;
++	SndCardCloseFunc _close_r;
++	SndCardCloseFunc _close_w;
++	SndCardMixerGetLevelFunc _get_level;
++	SndCardMixerSetLevelFunc _set_level;
++	SndCardMixerSetRecSourceFunc _set_rec_source;
++	SndCardCreateFilterFunc _create_read_filter;
++	SndCardCreateFilterFunc _create_write_filter;
++	SndCardDestroyFunc _destroy;
++};
++
++
++typedef struct _SndCard SndCard;
++	
++void snd_card_init(SndCard *obj);
++void snd_card_uninit(SndCard *obj);
++gint snd_card_probe(SndCard *obj, int bits, int stereo, int rate);
++int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate);
++int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate);
++int snd_card_get_bsize(SndCard *obj);
++gboolean snd_card_can_read(SndCard *obj);
++int snd_card_read(SndCard *obj,char *buffer,int size);
++int snd_card_write(SndCard *obj,char *buffer,int size);
++void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno);
++void snd_card_close_r(SndCard *obj);
++void snd_card_close_w(SndCard *obj);
++
++void snd_card_set_rec_source(SndCard *obj, int source); /* source='l' or 'm'*/
++void snd_card_set_level(SndCard *obj, int way, int level);
++gint snd_card_get_level(SndCard *obj,int way);
++
++const gchar *snd_card_get_identifier(SndCard *obj);
++
++struct _MSFilter * snd_card_create_read_filter(SndCard *sndcard);
++struct _MSFilter * snd_card_create_write_filter(SndCard *sndcard);
++
++
++#define SND_CARD_LEVEL_GENERAL 1
++#define SND_CARD_LEVEL_INPUT   2
++#define SND_CARD_LEVEL_OUTPUT  3
++
++
++int snd_card_destroy(SndCard *obj);
++
++#define SND_CARD(obj) ((SndCard*)(obj))
++
++
++
++
++/* SndCardManager */
++
++#define MAX_SND_CARDS 20
++
++
++struct _SndCardManager
++{
++	SndCard *cards[MAX_SND_CARDS];
++};
++
++typedef struct _SndCardManager SndCardManager;
++
++void snd_card_manager_init(SndCardManager *manager);
++SndCard * snd_card_manager_get_card(SndCardManager *manager,int index);
++SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index);
++
++extern SndCardManager *snd_card_manager;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c	(revision 586398)
+@@ -0,0 +1,39 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation
++  
++  */
++  
++#include "mssoundread.h"
++
++
++void ms_sound_read_init(MSSoundRead *w)
++{
++	ms_filter_init(MS_FILTER(w));
++	
++}
++
++void ms_sound_read_class_init(MSSoundReadClass *klass)
++{
++	int i;
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	MS_FILTER_CLASS(klass)->max_foutputs=1;  /* one fifo output only */
++	
++	ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h	(revision 586398)
+@@ -0,0 +1,78 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSOSSWRITE_H
++#define MSOSSWRITE_H
++
++#include "mssoundwrite.h"
++#include "sndcard.h"
++
++/*this is the class that implements oss writing sink filter*/
++
++#define MS_OSS_WRITE_MAX_INPUTS  1 /* max output per filter*/
++
++#define MS_OSS_WRITE_DEF_GRAN (512*2) /* the default granularity*/
++
++struct _MSOssWrite
++{
++	/* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite object MUST be the first of the MSOssWrite object
++       in order to the object mechanism to work*/
++	MSSoundWrite filter;
++	MSFifo *f_inputs[MS_OSS_WRITE_MAX_INPUTS];
++	gint devid;  /* the sound device id it depends on*/
++	SndCard *sndcard;
++	gint bsize;
++	gint freq;
++	gint channels;
++	gdouble lowfreq;
++	gdouble highfreq;
++	gint dtmf_time;
++	gint dtmf_duration;
++};
++
++typedef struct _MSOssWrite MSOssWrite;
++
++struct _MSOssWriteClass
++{
++	/* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite class MUST be the first of the MSOssWrite class
++       in order to the class mechanism to work*/
++	MSSoundWriteClass parent_class;
++};
++
++typedef struct _MSOssWriteClass MSOssWriteClass;
++
++/* PUBLIC */
++#define MS_OSS_WRITE(filter) ((MSOssWrite*)(filter))
++#define MS_OSS_WRITE_CLASS(klass) ((MSOssWriteClass*)(klass))
++MSFilter * ms_oss_write_new(void);
++gint ms_oss_write_set_device(MSOssWrite *w,gint devid);
++void ms_oss_write_start(MSOssWrite *w);
++void ms_oss_write_stop(MSOssWrite *w);
++void ms_oss_write_set_level(MSOssWrite *w, gint level);
++void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf);
++
++/* FOR INTERNAL USE*/
++void ms_oss_write_init(MSOssWrite *r);
++void ms_oss_write_setup(MSOssWrite *r);
++void ms_oss_write_class_init(MSOssWriteClass *klass);
++void ms_oss_write_destroy( MSOssWrite *obj);
++void ms_oss_write_process(MSOssWrite *f);
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h	(revision 586398)
+@@ -0,0 +1,74 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSLPC10ENCODER_H
++#define MSLPC10ENCODER_H
++
++#include "mscodec.h"
++
++
++int
++read_16bit_samples(gint16 int16samples[], float speech[], int n);
++
++int
++write_16bit_samples(gint16 int16samples[], float speech[], int n);
++
++void
++write_bits(unsigned char *data, gint32 *bits, int len);
++
++int
++read_bits(unsigned char *data, gint32 *bits, int len);
++
++
++/*this is the class that implements a LPC10encoder filter*/
++
++#define MSLPC10ENCODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSLPC10Encoder
++{
++    /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Encoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSLPC10ENCODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSLPC10ENCODER_MAX_INPUTS];
++    struct lpc10_encoder_state *lpc10_enc;
++} MSLPC10Encoder;
++
++typedef struct _MSLPC10EncoderClass
++{
++	/* the MSLPC10Encoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Encoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSLPC10EncoderClass;
++
++/* PUBLIC */
++#define MS_LPC10ENCODER(filter) ((MSLPC10Encoder*)(filter))
++#define MS_LPC10ENCODER_CLASS(klass) ((MSLPC10EncoderClass*)(klass))
++MSFilter * ms_LPC10encoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_LPC10encoder_init(MSLPC10Encoder *r);
++void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass);
++void ms_LPC10encoder_destroy( MSLPC10Encoder *obj);
++void ms_LPC10encoder_process(MSLPC10Encoder *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c	(revision 586398)
+@@ -0,0 +1,194 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <config.h>
++
++#ifdef HAVE_ILBC
++
++
++#include "msilbcdec.h"
++#include "msilbcenc.h"
++#include "mscodec.h"
++#include <stdlib.h>
++#include <stdio.h>
++
++
++
++extern MSFilter * ms_ilbc_encoder_new(void);
++
++MSCodecInfo ilbc_info={
++	{
++		"iLBC codec",
++		0,
++		MS_FILTER_AUDIO_CODEC,
++		ms_ilbc_encoder_new,
++		"A speech codec suitable for robust voice communication over IP"
++	},
++	ms_ilbc_encoder_new,
++	ms_ilbc_decoder_new,
++	0,	/* not applicable, 2 modes */
++	0, /* not applicable, 2 modes */
++	15200,
++	8000,
++	97,
++	"iLBC",
++	1,
++	1,
++};
++
++
++void ms_ilbc_codec_init()
++{
++	ms_filter_register(MS_FILTER_INFO(&ilbc_info));
++}
++
++
++
++static MSILBCDecoderClass *ms_ilbc_decoder_class=NULL;
++
++MSFilter * ms_ilbc_decoder_new(void)
++{
++	MSILBCDecoder *r;
++	
++	r=g_new(MSILBCDecoder,1);
++	ms_ilbc_decoder_init(r);
++	if (ms_ilbc_decoder_class==NULL)
++	{
++		ms_ilbc_decoder_class=g_new(MSILBCDecoderClass,1);
++		ms_ilbc_decoder_class_init(ms_ilbc_decoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_decoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++int ms_ilbc_decoder_set_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FMTP:
++			if (value == NULL) return 0;
++			if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
++			else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
++			else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
++		break;
++	}
++	return 0;
++}
++int ms_ilbc_decoder_get_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FMTP:
++			if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
++			if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
++		break;
++	}
++	return 0;
++}
++
++void ms_ilbc_decoder_setup(MSILBCDecoder *r) 
++{
++	MSFilterClass *klass = NULL;
++	switch (r->ms_per_frame) {
++	case 20:
++		r->samples_per_frame = BLOCKL_20MS;
++		r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
++		break;
++	case 30:
++		r->samples_per_frame = BLOCKL_30MS;
++		r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
++		break;
++	default:
++		g_error("ms_ilbc_decoder_setup: Bad value for ptime (%i)",r->ms_per_frame);
++	}
++	g_message("Using ilbc decoder with %i ms frames mode.",r->ms_per_frame);
++	initDecode(&r->ilbc_dec, r->ms_per_frame /* ms frames */, /* user enhancer */ 0);
++}
++
++
++/* FOR INTERNAL USE*/
++void ms_ilbc_decoder_init(MSILBCDecoder *r)
++{
++	/* default bitrate */
++	r->bitrate = 15200;
++	r->ms_per_frame = 30;
++	r->samples_per_frame = BLOCKL_20MS;
++	r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
++
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->inqueues=r->q_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	memset(r->q_inputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
++}
++
++void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCDec");
++	MS_FILTER_CLASS(klass)->max_qinputs=MSILBCDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSILBCDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->w_maxgran= ILBC_MAX_SAMPLES_PER_FRAME*2;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_decoder_destroy;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_decoder_set_property;
++	MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_decoder_get_property;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_decoder_setup;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_decoder_process;
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
++}
++	
++void ms_ilbc_decoder_process(MSILBCDecoder *r)
++{
++	MSFifo *fo;
++	MSQueue *qi;
++	int err1;
++	void *dst=NULL;
++	float speech[ILBC_MAX_SAMPLES_PER_FRAME];
++	MSMessage *m;
++
++	qi=r->q_inputs[0];
++	fo=r->f_outputs[0];
++	m=ms_queue_get(qi);
++	
++	ms_fifo_get_write_ptr(fo, r->samples_per_frame*2, &dst);
++	if (dst!=NULL){
++		if (m->data!=NULL){
++			if (m->size<r->bytes_per_compressed_frame) {
++				g_warning("Invalid ilbc frame ?");
++			}
++			iLBC_decode(speech, m->data, &r->ilbc_dec, /* mode */1);
++		}else{
++			iLBC_decode(speech,NULL, &r->ilbc_dec,0);
++		}
++		ilbc_write_16bit_samples((gint16*)dst, speech, r->samples_per_frame);
++	}
++	ms_message_destroy(m);
++}
++
++void ms_ilbc_decoder_uninit(MSILBCDecoder *obj)
++{
++}
++
++void ms_ilbc_decoder_destroy( MSILBCDecoder *obj)
++{
++	ms_ilbc_decoder_uninit(obj);
++	g_free(obj);
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSSOUNDREAD_H
++#define MSSOUNDREAD_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++
++
++struct _MSSoundRead
++{
++	/* the MSOssRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssRead object
++       in order to the object mechanism to work*/
++	MSFilter filter;
++};
++
++typedef struct _MSSoundRead MSSoundRead;
++
++struct _MSSoundReadClass
++{
++	/* the MSOssRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssRead class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++	gint (*set_device)(MSSoundRead *, gint devid);
++	void (*start)(MSSoundRead *);
++	void (*stop)(MSSoundRead*);
++	void (*set_level)(MSSoundRead *, gint a);
++};
++
++typedef struct _MSSoundReadClass MSSoundReadClass;
++
++/* PUBLIC */
++#define MS_SOUND_READ(filter) ((MSSoundRead*)(filter))
++#define MS_SOUND_READ_CLASS(klass) ((MSSoundReadClass*)(klass))
++
++static inline int ms_sound_read_set_device(MSSoundRead *r,gint devid)
++{
++	return MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
++}
++
++static inline void ms_sound_read_start(MSSoundRead *r)
++{
++	MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->start(r);
++}
++
++static inline void ms_sound_read_stop(MSSoundRead *w)
++{
++	MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->stop(w);
++}
++
++static inline void ms_sound_read_set_level(MSSoundRead *w,gint a)
++{
++	MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
++}
++
++/* FOR INTERNAL USE*/
++void ms_sound_read_init(MSSoundRead *r);
++void ms_sound_read_class_init(MSSoundReadClass *klass);
++
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h	(revision 586398)
+@@ -0,0 +1,72 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSILBCDECODER_H
++#define MSILBCDECODER_H
++
++#include <msfilter.h>
++#include <mscodec.h>
++#include <iLBC_decode.h>
++
++/*this is the class that implements a ILBCdecoder filter*/
++
++#define MSILBCDECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSILBCDecoder
++{
++     /* the MSILBCDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCDecoder object
++	in order to the object mechanism to work*/
++     MSFilter filter;
++     MSQueue *q_inputs[MSILBCDECODER_MAX_INPUTS];
++     MSFifo *f_outputs[MSILBCDECODER_MAX_INPUTS];
++     iLBC_Dec_Inst_t ilbc_dec;
++     int bitrate;
++     int ms_per_frame;
++     int samples_per_frame;
++     int bytes_per_compressed_frame;
++} MSILBCDecoder;
++
++typedef struct _MSILBCDecoderClass
++{
++	/* the MSILBCDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCDecoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSILBCDecoderClass;
++
++/* PUBLIC */
++
++/* call this before if don't load the plugin dynamically */
++void ms_ilbc_codec_init();
++
++#define MS_ILBCDECODER(filter) ((MSILBCDecoder*)(filter))
++#define MS_ILBCDECODER_CLASS(klass) ((MSILBCDecoderClass*)(klass))
++MSFilter * ms_ilbc_decoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_ilbc_decoder_init(MSILBCDecoder *r);
++void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass);
++void ms_ilbc_decoder_destroy( MSILBCDecoder *obj);
++void ms_ilbc_decoder_process(MSILBCDecoder *r);
++
++extern MSCodecInfo ilbc_info;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c	(revision 586398)
+@@ -0,0 +1,94 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a dispatcher of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msfdispatcher.h"
++
++static MSFdispatcherClass *ms_fdispatcher_class=NULL;
++
++MSFilter * ms_fdispatcher_new(void)
++{
++	MSFdispatcher *obj;
++	obj=g_malloc(sizeof(MSFdispatcher));
++	if (ms_fdispatcher_class==NULL){
++		ms_fdispatcher_class=g_malloc(sizeof(MSFdispatcherClass));
++		ms_fdispatcher_class_init(ms_fdispatcher_class);
++	}
++	MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_fdispatcher_class);
++	ms_fdispatcher_init(obj);
++	return MS_FILTER(obj);
++}
++
++
++void ms_fdispatcher_init(MSFdispatcher *obj)
++{
++	ms_filter_init(MS_FILTER(obj));
++	MS_FILTER(obj)->infifos=obj->f_inputs;
++	MS_FILTER(obj)->outfifos=obj->f_outputs;
++	MS_FILTER(obj)->r_mingran=MS_FDISPATCHER_DEF_GRAN;
++	memset(obj->f_inputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_INPUTS);
++	memset(obj->f_outputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_OUTPUTS);
++}
++
++
++
++void ms_fdispatcher_class_init(MSFdispatcherClass *klass)
++{
++	MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
++	ms_filter_class_init(parent_class);
++	ms_filter_class_set_name(parent_class,"fdispatcher");
++	parent_class->max_finputs=MS_FDISPATCHER_MAX_INPUTS;
++	parent_class->max_foutputs=MS_FDISPATCHER_MAX_OUTPUTS;
++	parent_class->r_maxgran=MS_FDISPATCHER_DEF_GRAN;
++	parent_class->w_maxgran=MS_FDISPATCHER_DEF_GRAN;
++	parent_class->destroy=(MSFilterDestroyFunc)ms_fdispatcher_destroy;
++	parent_class->process=(MSFilterProcessFunc)ms_fdispatcher_process;
++}
++
++
++void ms_fdispatcher_destroy( MSFdispatcher *obj)
++{
++	g_free(obj);
++}
++
++void ms_fdispatcher_process(MSFdispatcher *obj)
++{
++	gint i;
++	MSFifo *inf=obj->f_inputs[0];
++	
++	
++	if (inf!=NULL){
++		void *s,*d;
++		/* dispatch fifos */
++		while ( ms_fifo_get_read_ptr(inf,MS_FDISPATCHER_DEF_GRAN,&s) >0 ){
++			for (i=0;i<MS_FDISPATCHER_MAX_OUTPUTS;i++){
++				MSFifo *outf=obj->f_outputs[i];
++			
++				if (outf!=NULL)
++				{
++					ms_fifo_get_write_ptr(outf,MS_FDISPATCHER_DEF_GRAN,&d);
++					if (d!=NULL) memcpy(d,s,MS_FDISPATCHER_DEF_GRAN);
++				}
++			}	
++		}
++	}
++}
++
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a dispatcher of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSFDISPATCHER_H
++#define MSFDISPATCHER_H
++
++#include "msfilter.h"
++
++
++/*this is the class that implements a fdispatcher filter*/
++
++#define MS_FDISPATCHER_MAX_INPUTS  1
++#define MS_FDISPATCHER_MAX_OUTPUTS 5 
++#define MS_FDISPATCHER_DEF_GRAN 64 /* the default granularity*/
++
++typedef struct _MSFdispatcher
++{
++    /* the MSFdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSFdispatcher object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MS_FDISPATCHER_MAX_INPUTS];
++    MSFifo *f_outputs[MS_FDISPATCHER_MAX_OUTPUTS];
++} MSFdispatcher;
++
++typedef struct _MSFdispatcherClass
++{
++	/* the MSFdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSFdispatcher class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSFdispatcherClass;
++
++/* PUBLIC */
++#define MS_FDISPATCHER(filter) ((MSFdispatcher*)(filter))
++#define MS_FDISPATCHER_CLASS(klass) ((MSFdispatcherClass*)(klass))
++MSFilter * ms_fdispatcher_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_fdispatcher_init(MSFdispatcher *r);
++void ms_fdispatcher_class_init(MSFdispatcherClass *klass);
++void ms_fdispatcher_destroy( MSFdispatcher *obj);
++void ms_fdispatcher_process(MSFdispatcher *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c	(revision 586398)
+@@ -0,0 +1,91 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a dispatcher of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msqdispatcher.h"
++
++static MSQdispatcherClass *ms_qdispatcher_class=NULL;
++
++MSFilter * ms_qdispatcher_new(void)
++{
++	MSQdispatcher *obj;
++	obj=g_malloc(sizeof(MSQdispatcher));
++	if (ms_qdispatcher_class==NULL){
++		ms_qdispatcher_class=g_malloc0(sizeof(MSQdispatcherClass));
++		ms_qdispatcher_class_init(ms_qdispatcher_class);
++	}
++	MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_qdispatcher_class);
++	ms_qdispatcher_init(obj);
++	return MS_FILTER(obj);
++}
++
++
++void ms_qdispatcher_init(MSQdispatcher *obj)
++{
++	ms_filter_init(MS_FILTER(obj));
++	
++	MS_FILTER(obj)->inqueues=obj->q_inputs;
++	MS_FILTER(obj)->outqueues=obj->q_outputs;
++	memset(obj->q_inputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_INPUTS);
++	memset(obj->q_outputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_OUTPUTS);
++}
++
++
++
++void ms_qdispatcher_class_init(MSQdispatcherClass *klass)
++{
++	MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
++	ms_filter_class_init(parent_class);
++	ms_filter_class_set_name(parent_class,"qdispatcher");
++	parent_class->max_qinputs=MS_QDISPATCHER_MAX_INPUTS;
++	parent_class->max_qoutputs=MS_QDISPATCHER_MAX_OUTPUTS;
++	
++	parent_class->destroy=(MSFilterDestroyFunc)ms_qdispatcher_destroy;
++	parent_class->process=(MSFilterProcessFunc)ms_qdispatcher_process;
++}
++
++
++void ms_qdispatcher_destroy( MSQdispatcher *obj)
++{
++	g_free(obj);
++}
++
++void ms_qdispatcher_process(MSQdispatcher *obj)
++{
++	gint i;
++	MSQueue *inq=obj->q_inputs[0];
++	
++	if (inq!=NULL){
++		MSQueue *outq;
++		MSMessage *m1,*m2;
++		while ( (m1=ms_queue_get(inq))!=NULL){
++			/* dispatch incoming messages to output queues */
++			for (i=0;i<MS_QDISPATCHER_MAX_OUTPUTS;i++){
++				outq=obj->q_outputs[i];
++				if (outq!=NULL){
++					m2=ms_message_dup(m1);
++					ms_queue_put(outq,m2);
++				}
++			}
++			ms_message_destroy(m1);
++		}
++	}
++	
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c	(revision 586398)
+@@ -0,0 +1,96 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "mscopy.h"
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <string.h>
++#include <errno.h>
++
++static MSCopyClass *ms_copy_class=NULL;
++
++MSFilter * ms_copy_new(void)
++{
++	MSCopy *r;
++	
++	r=g_new(MSCopy,1);
++	ms_copy_init(r);
++	if (ms_copy_class==NULL)
++	{
++		ms_copy_class=g_new(MSCopyClass,1);
++		ms_copy_class_init(ms_copy_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_copy_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_copy_init(MSCopy *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->r_mingran=MSCOPY_DEF_GRAN;
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
++}
++
++void ms_copy_class_init(MSCopyClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"fifocopier");
++	MS_FILTER_CLASS(klass)->max_finputs=MSCOPY_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSCOPY_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=MSCOPY_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->w_maxgran=MSCOPY_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_copy_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_copy_process;
++}
++	
++void ms_copy_process(MSCopy *r)
++{
++	MSFifo *fi,*fo;
++	int err1;
++	gint gran=MS_FILTER(r)->klass->r_maxgran;
++	void *s,*d;
++	
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	fi=r->f_inputs[0];
++	fo=r->f_outputs[0];
++	if (fi!=NULL)
++	{
++		err1=ms_fifo_get_read_ptr(fi,gran,&s);
++		if (err1>0) err1=ms_fifo_get_write_ptr(fo,gran,&d);
++		if (err1>0)
++		{
++			memcpy(d,s,gran);
++		}
++	}
++}
++
++void ms_copy_destroy( MSCopy *obj)
++{
++	g_free(obj);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c	(revision 586398)
+@@ -0,0 +1,640 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "alsacard.h"
++
++#ifdef HAVE_ALSA_ASOUNDLIB_H
++
++static gchar *over_pcmdev=NULL;
++
++#include "msossread.h"
++#include "msosswrite.h"
++
++#include <signal.h>
++
++int __alsa_card_write(AlsaCard *obj,char *buf,int size);
++
++int alsa_set_params(AlsaCard *obj, int rw, int bits, int stereo, int rate)
++{
++	snd_pcm_hw_params_t *hwparams=NULL;
++	snd_pcm_sw_params_t *swparams=NULL;
++	snd_pcm_t *pcm_handle;
++	gint dir,exact_value;
++	gint channels;
++	gint fsize=0;
++	gint periods=8;
++	gint periodsize=256;
++	gint err;
++	int format;
++	
++	if (rw) {
++		pcm_handle=obj->write_handle;
++	}
++	else pcm_handle=obj->read_handle;
++	
++	/* Allocate the snd_pcm_hw_params_t structure on the stack. */
++    snd_pcm_hw_params_alloca(&hwparams);
++	
++	/* Init hwparams with full configuration space */
++    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
++		g_warning("alsa_set_params: Cannot configure this PCM device.\n");
++		return(-1);
++    }
++	
++	if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
++      g_warning("alsa_set_params: Error setting access.\n");
++      return(-1);
++    }
++	/* Set sample format */
++#ifdef WORDS_BIGENDIAN
++	format=SND_PCM_FORMAT_S16_BE;
++#else
++	format=SND_PCM_FORMAT_S16_LE;
++#endif
++    if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
++      g_warning("alsa_set_params: Error setting format.\n");
++      return(-1);
++    }
++	/* Set number of channels */
++	if (stereo) channels=2;
++	else channels=1;
++    if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
++      g_warning("alsa_set_params: Error setting channels.\n");
++      return(-1);
++    }
++	/* Set sample rate. If the exact rate is not supported */
++    /* by the hardware, use nearest possible rate.         */ 
++	exact_value=rate;
++	dir=0;
++    if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_value, &dir))<0){
++		g_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));
++ 		return -1;
++	}
++    if (dir != 0) {
++      g_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "
++		"==> Using %d Hz instead.\n", rate, exact_value);
++    }
++	/* choose greater period size when rate is high */
++	periodsize=periodsize*(rate/8000);	
++	
++	/* Set buffer size (in frames). The resulting latency is given by */
++    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
++	/*
++	fsize=periodsize * periods;
++	exact_value=fsize;
++    if ((err=snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,&exact_value)) < 0) {
++      g_warning("alsa_set_params: Error setting buffer size:%s",snd_strerror(err));
++      return(-1);
++    }
++	if (fsize!= exact_value) {
++      g_warning("alsa_set_params: The buffer size %d is not supported by your hardware.\n "
++		"==> Using %d instead.\n", fsize, exact_value);
++    }
++	*/
++	/* set period size */
++	exact_value=periodsize;
++	dir=0;
++    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
++      g_warning("alsa_set_params: Error setting period size.\n");
++      return(-1);
++    }
++	if (dir != 0) {
++      g_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "
++		"==> Using %d instead.\n", periodsize, exact_value);
++    }
++	periodsize=exact_value;
++	/* Set number of periods. Periods used to be called fragments. */ 
++	exact_value=periods;
++	dir=0;
++    if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
++      g_warning("alsa_set_params: Error setting periods.\n");
++      return(-1);
++    }
++	if (dir != 0) {
++      g_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "
++		"==> Using %d instead.\n", periods, exact_value);
++    }
++	/* Apply HW parameter settings to */
++    /* PCM device and prepare device  */
++    if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
++      g_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));
++      return(-1);
++    }
++	/*prepare sw params */
++	if (rw){
++		snd_pcm_sw_params_alloca(&swparams);
++		snd_pcm_sw_params_current(pcm_handle, swparams);
++		if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){
++			g_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));
++			return -1;
++		}
++		if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){
++			g_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));
++			return(-1);
++		}
++	}
++	obj->frame_size=channels*(bits/8);
++	SND_CARD(obj)->bsize=periodsize*obj->frame_size;
++	/* //SND_CARD(obj)->bsize=4096; */
++	obj->frames=periodsize;
++	g_message("alsa_set_params:  blocksize=%i.",SND_CARD(obj)->bsize);
++	return SND_CARD(obj)->bsize;	
++}
++
++int alsa_card_open_r(AlsaCard *obj,int bits,int stereo,int rate)
++{
++	int bsize;
++	int err;
++	snd_pcm_t *pcm_handle;
++	gchar *pcmdev;
++	if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
++	else pcmdev=obj->pcmdev;
++	
++	if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {
++		g_warning("alsa_card_open_r: Error opening PCM device %s\n",obj->pcmdev );
++		return -1;
++	}
++	g_return_val_if_fail(pcm_handle!=NULL,-1);
++	obj->read_handle=pcm_handle;
++	if ((bsize=alsa_set_params(obj,0,bits,stereo,rate))<0){
++		snd_pcm_close(pcm_handle);
++		obj->read_handle=NULL;
++		return -1;
++	}
++	obj->readbuf=g_malloc0(bsize);
++	
++	err=snd_pcm_start(obj->read_handle);
++	if (err<0){
++		g_warning("Cannot start read pcm: %s", snd_strerror(err));
++	}
++	obj->readpos=0;
++	SND_CARD(obj)->bsize=bsize;
++	SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
++	return 0;
++}
++
++int alsa_card_open_w(AlsaCard *obj,int bits,int stereo,int rate)
++{
++	int err,bsize;
++	snd_pcm_t *pcm_handle;
++	gchar *pcmdev;
++	if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
++	else pcmdev=obj->pcmdev;
++	
++	if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
++      g_warning("alsa_card_open_w: Error opening PCM device %s\n", obj->pcmdev);
++      return -1;
++    }
++	obj->write_handle=pcm_handle;
++	if ((bsize=alsa_set_params(obj,1,bits,stereo,rate))<0){
++		snd_pcm_close(pcm_handle);
++		obj->write_handle=NULL;
++		return -1;
++	}
++	obj->writebuf=g_malloc0(bsize);
++	
++	obj->writepos=0;
++	SND_CARD(obj)->bsize=bsize;
++	SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
++	return 0;
++}
++
++
++void alsa_card_set_blocking_mode(AlsaCard *obj, gboolean yesno){
++	if (obj->read_handle!=NULL) snd_pcm_nonblock(obj->read_handle,!yesno);
++	if (obj->write_handle!=NULL) snd_pcm_nonblock(obj->write_handle,!yesno);
++}
++
++void alsa_card_close_r(AlsaCard *obj)
++{
++	if (obj->read_handle!=NULL){
++		snd_pcm_close(obj->read_handle);
++		obj->read_handle=NULL;
++		g_free(obj->readbuf);
++		obj->readbuf=NULL;
++	}
++}
++
++void alsa_card_close_w(AlsaCard *obj)
++{
++	if (obj->write_handle!=NULL){
++		snd_pcm_close(obj->write_handle);
++		obj->write_handle=NULL;
++		g_free(obj->writebuf);
++		obj->writebuf=NULL;
++	}
++}
++
++int alsa_card_probe(AlsaCard *obj,int bits,int stereo,int rate)
++{
++	int ret;
++	ret=alsa_card_open_w(obj,bits,stereo,rate);
++	if (ret<0) return -1;
++	ret=SND_CARD(obj)->bsize;
++	alsa_card_close_w(obj);
++	return ret;
++}
++
++
++void alsa_card_destroy(AlsaCard *obj)
++{
++	snd_card_uninit(SND_CARD(obj));
++	g_free(obj->pcmdev);
++	if (obj->readbuf!=0) g_free(obj->readbuf);
++	if (obj->writebuf!=0) g_free(obj->writebuf);	
++}
++
++gboolean alsa_card_can_read(AlsaCard *obj)
++{
++	int frames;
++	g_return_val_if_fail(obj->read_handle!=NULL,0);
++	if (obj->readpos!=0) return TRUE;
++	if ( frames=snd_pcm_avail_update(obj->read_handle)>=obj->frames) return 1;
++	/* //g_message("frames=%i",frames); */
++	return 0;
++}
++
++
++
++int __alsa_card_read(AlsaCard *obj,char *buf,int bsize)
++{
++	int err;
++	sigset_t set;
++	sigemptyset(&set);
++	sigaddset(&set,SIGALRM);
++	sigprocmask(SIG_BLOCK,&set,NULL);
++	err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
++	if (err<0) {
++		if (err!=-EPIPE){
++			g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
++		}
++		snd_pcm_prepare(obj->read_handle);
++		err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
++		if (err<0) g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
++	}
++	sigprocmask(SIG_UNBLOCK,&set,NULL);
++	return err*obj->frame_size;
++}
++
++int alsa_card_read(AlsaCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	g_return_val_if_fail(obj->read_handle!=NULL,-1);
++	if (size<bsize){
++		gint canread=MIN(bsize-obj->readpos,size);
++		
++		if (obj->readpos==0){
++			err=__alsa_card_read(obj,obj->readbuf,bsize);
++		}
++			
++		memcpy(buf,&obj->readbuf[obj->readpos],canread);
++		obj->readpos+=canread;
++		if (obj->readpos>=bsize) obj->readpos=0;
++		return canread;
++	}else{
++		err=__alsa_card_read(obj,buf,size);
++		return err;
++	}
++	
++}
++
++int __alsa_card_write(AlsaCard *obj,char *buf,int size)
++{
++	int err;
++	sigset_t set;
++	sigemptyset(&set);
++	sigaddset(&set,SIGALRM);
++	sigprocmask(SIG_BLOCK,&set,NULL);
++	if ((err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size))<0){
++		if (err!=-EPIPE){
++			g_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));
++		}
++		snd_pcm_prepare(obj->write_handle);
++		err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size);
++		if (err<0) g_warning("alsa_card_write: Error writing sound buffer (size=%i):%s",size,snd_strerror(err));
++		
++	}
++	sigprocmask(SIG_UNBLOCK,&set,NULL);
++	return err;
++}
++
++int alsa_card_write(AlsaCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	g_return_val_if_fail(obj->write_handle!=NULL,-1);
++	if (size<bsize){
++		gint canwrite;
++		
++		canwrite=MIN(bsize-obj->writepos,size);
++		memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
++		obj->writepos+=canwrite;
++		if (obj->writepos>=bsize){
++			err=__alsa_card_write(obj,obj->writebuf,bsize);
++			obj->writepos=0;
++		}
++		return canwrite;
++	}else{
++		return __alsa_card_write(obj,buf,bsize);
++	}
++}
++
++snd_mixer_t *alsa_mixer_open(AlsaCard *obj){
++	snd_mixer_t *mixer=NULL;
++	int err;
++	err=snd_mixer_open(&mixer,0);
++	if (err<0){
++		g_warning("Could not open alsa mixer: %s",snd_strerror(err));
++		return NULL;
++	}
++	if ((err = snd_mixer_attach (mixer, obj->mixdev)) < 0){
++		g_warning("Could not attach mixer to card: %s",snd_strerror(err));
++		snd_mixer_close(mixer);
++		return NULL;
++	}
++	if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){
++		g_warning("snd_mixer_selem_register: %s",snd_strerror(err));
++		snd_mixer_close(mixer);
++		return NULL;
++	}
++	if ((err = snd_mixer_load (mixer)) < 0){
++		g_warning("snd_mixer_load: %s",snd_strerror(err));
++		snd_mixer_close(mixer);
++		return NULL;
++	}
++	obj->mixer=mixer;
++	return mixer;
++}
++
++void alsa_mixer_close(AlsaCard *obj){
++	snd_mixer_close(obj->mixer);
++	obj->mixer=NULL;
++}
++
++typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;
++
++static gint get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){
++	long value=0;
++	const char *elemname;
++	snd_mixer_elem_t *elem;
++	int err;
++	long sndMixerPMin;
++	long sndMixerPMax;
++	long newvol;
++	elem=snd_mixer_first_elem(mixer);
++	while (elem!=NULL){
++		elemname=snd_mixer_selem_get_name(elem);
++		/* //g_message("Found alsa mixer element %s.",elemname); */
++		if (strcmp(elemname,name)==0){
++			switch (action){
++				case CAPTURE:
++				if (snd_mixer_selem_has_capture_volume(elem)){
++					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
++					err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);
++					newvol-=sndMixerPMin;
++					value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
++					if (err<0) g_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));
++					/* //else g_message("Succesfully get capture level for %s.",elemname); */
++					break;
++				}
++				break;
++				case PLAYBACK:
++				if (snd_mixer_selem_has_playback_volume(elem)){
++					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
++					err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);
++					newvol-=sndMixerPMin;
++					value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
++					if (err<0) g_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));
++					/* //else g_message("Succesfully get playback level for %s.",elemname); */
++					break;
++				}
++				break;
++				case CAPTURE_SWITCH:
++				
++				break;
++			}
++		}
++		elem=snd_mixer_elem_next(elem);
++	}
++	
++	return value;
++}
++
++
++static void set_mixer_element(snd_mixer_t *mixer,const char *name, gint level,MixerAction action){
++	const char *elemname;
++	snd_mixer_elem_t *elem;
++	int tmp;
++	long sndMixerPMin;
++	long sndMixerPMax;
++	long newvol;
++	
++	elem=snd_mixer_first_elem(mixer);
++	
++	while (elem!=NULL){
++		elemname=snd_mixer_selem_get_name(elem);
++		/* //g_message("Found alsa mixer element %s.",elemname); */
++		if (strcmp(elemname,name)==0){
++			switch(action){
++				case CAPTURE:
++				if (snd_mixer_selem_has_capture_volume(elem)){
++					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
++					newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
++					snd_mixer_selem_set_capture_volume_all(elem,newvol);
++					/* //g_message("Succesfully set capture level for %s.",elemname); */
++					return;
++				}
++				break;
++				case PLAYBACK:
++				if (snd_mixer_selem_has_playback_volume(elem)){
++					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
++					newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
++					snd_mixer_selem_set_playback_volume_all(elem,newvol);
++					/* //g_message("Succesfully set playback level for %s.",elemname); */
++					return;
++				}
++				break;
++				case CAPTURE_SWITCH:
++				if (snd_mixer_selem_has_capture_switch(elem)){
++					snd_mixer_selem_set_capture_switch_all(elem,level);
++					/* //g_message("Succesfully set capture switch for %s.",elemname); */
++				}
++				break;
++				case PLAYBACK_SWITCH:
++				if (snd_mixer_selem_has_playback_switch(elem)){
++					snd_mixer_selem_set_playback_switch_all(elem,level);
++					/* //g_message("Succesfully set capture switch for %s.",elemname); */
++				}
++				break;
++
++			}
++		}
++		elem=snd_mixer_elem_next(elem);
++	}
++
++	return ;
++}
++
++
++void alsa_card_set_level(AlsaCard *obj,gint way,gint a)
++{	
++	snd_mixer_t *mixer;
++	mixer=alsa_mixer_open(obj);
++	if (mixer==NULL) return ;
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			set_mixer_element(mixer,"Master",a,PLAYBACK);
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			set_mixer_element(mixer,"Capture",a,CAPTURE);
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			set_mixer_element(mixer,"PCM",a,PLAYBACK);
++		break;
++		default:
++			g_warning("oss_card_set_level: unsupported command.");
++	}
++	alsa_mixer_close(obj);
++}
++
++gint alsa_card_get_level(AlsaCard *obj,gint way)
++{
++	snd_mixer_t *mixer;
++	gint value;
++	mixer=alsa_mixer_open(obj);
++	if (mixer==NULL) return 0;
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			value=get_mixer_element(mixer,"Master",PLAYBACK);
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			value=get_mixer_element(mixer,"Capture",CAPTURE);
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			value=get_mixer_element(mixer,"PCM",PLAYBACK);
++		break;
++		default:
++			g_warning("oss_card_set_level: unsupported command.");
++	}
++	alsa_mixer_close(obj);
++	return value;
++}
++
++void alsa_card_set_source(AlsaCard *obj,int source)
++{
++	snd_mixer_t *mixer;
++	mixer=alsa_mixer_open(obj);
++	if (mixer==NULL) return;
++	switch (source){
++		case 'm':
++			set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);
++			set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
++			break;
++		case 'l':
++			set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);
++			set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
++			break;
++	}
++}
++
++MSFilter *alsa_card_create_read_filter(AlsaCard *card)
++{
++	MSFilter *f=ms_oss_read_new();
++	ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
++	return f;
++}
++
++MSFilter *alsa_card_create_write_filter(AlsaCard *card)
++{
++	MSFilter *f=ms_oss_write_new();
++	ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
++	return f;
++}
++
++
++SndCard * alsa_card_new(gint devid)
++{
++	AlsaCard * obj;
++	SndCard *base;
++	int err;
++	gchar *name=NULL;
++	
++	/* carefull: this is an alsalib call despite its name! */
++	err=snd_card_get_name(devid,&name);
++	if (err<0) {
++		return NULL;
++	}
++	obj= g_new0(AlsaCard,1);
++	base= SND_CARD(obj);
++	snd_card_init(base);
++	
++	base->card_name=g_strdup_printf("%s (Advanced Linux Sound Architecture)",name);
++	base->_probe=(SndCardOpenFunc)alsa_card_probe;
++	base->_open_r=(SndCardOpenFunc)alsa_card_open_r;
++	base->_open_w=(SndCardOpenFunc)alsa_card_open_w;
++	base->_can_read=(SndCardPollFunc)alsa_card_can_read;
++	base->_set_blocking_mode=(SndCardSetBlockingModeFunc)alsa_card_set_blocking_mode;
++	base->_read=(SndCardIOFunc)alsa_card_read;
++	base->_write=(SndCardIOFunc)alsa_card_write;
++	base->_close_r=(SndCardCloseFunc)alsa_card_close_r;
++	base->_close_w=(SndCardCloseFunc)alsa_card_close_w;
++	base->_set_rec_source=(SndCardMixerSetRecSourceFunc)alsa_card_set_source;
++	base->_set_level=(SndCardMixerSetLevelFunc)alsa_card_set_level;
++	base->_get_level=(SndCardMixerGetLevelFunc)alsa_card_get_level;
++	base->_destroy=(SndCardDestroyFunc)alsa_card_destroy;
++	base->_create_read_filter=(SndCardCreateFilterFunc)alsa_card_create_read_filter;
++	base->_create_write_filter=(SndCardCreateFilterFunc)alsa_card_create_write_filter;
++	
++	
++	obj->pcmdev=g_strdup_printf("plughw:%i,0",devid);
++	obj->mixdev=g_strdup_printf("hw:%i",devid);
++	obj->readbuf=NULL;
++	obj->writebuf=NULL;
++	return base;
++}
++
++
++gint alsa_card_manager_init(SndCardManager *m, gint index)
++{
++	gint devindex;
++	gint i;
++	gint found=0;
++	gchar *name=NULL;
++	for(devindex=0;index<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
++		if (snd_card_get_name(devindex,&name)==0){
++			g_message("Found ALSA device: %s",name);
++			m->cards[index]=alsa_card_new(devindex);
++			m->cards[index]->index=index;
++			found++;
++			index++;
++		}
++	}
++	return found;
++}
++
++void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev){
++	if (over_pcmdev!=NULL){
++		g_free(over_pcmdev);	
++	}
++	over_pcmdev=g_strdup(pcmdev);
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c	(revision 586398)
+@@ -0,0 +1,124 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msAlawenc.h"
++#include "g711common.h"
++
++extern MSCodecInfo ALAWinfo;
++
++static MSALAWEncoderClass *ms_ALAWencoder_class=NULL;
++
++MSFilter * ms_ALAWencoder_new(void)
++{
++	MSALAWEncoder *r;
++	
++	r=g_new(MSALAWEncoder,1);
++	ms_ALAWencoder_init(r);
++	if (ms_ALAWencoder_class==NULL)
++	{
++		ms_ALAWencoder_class=g_new(MSALAWEncoderClass,1);
++		ms_ALAWencoder_class_init(ms_ALAWencoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWencoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_ALAWencoder_init(MSALAWEncoder *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->r_mingran=ALAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
++	something to process */
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
++	
++}
++
++void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWEncoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
++	MS_FILTER_CLASS(klass)->max_finputs=MSALAWENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSALAWENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=ALAW_ENCODER_RMAXGRAN;
++	MS_FILTER_CLASS(klass)->w_maxgran=ALAW_ENCODER_WMAXGRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWencoder_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWencoder_process;
++}
++	
++void ms_ALAWencoder_process(MSALAWEncoder *r)
++{
++	MSFifo *fi,*fo;
++	int inlen,outlen;
++	gchar *s,*d;
++	int i;
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	/* this is the sophisticated design of the process function:
++	Here the filter declares that it can be called as soon as there is something
++	to read on the input fifo by setting r_mingran=0.
++	Then it ask for the fifo to get as many data as possible by calling:
++	inlen=ms_fifo_get_read_ptr(fi,0,(void**)&s);
++	This avoid multiple call to the process function to process all data available
++	on the input fifo... but the writing of the process function is a bit
++	more difficult, because althoug ms_fifo_get_read_ptr() returns N bytes,
++	we cannot ask ms_fifo_get_write_ptr to return N bytes if
++	N>MS_FILTER_CLASS(klass)->w_maxgran. This is forbidden by the MSFifo
++	mechanism.
++	This is an open issue.
++	For the moment what is done here is that ms_fifo_get_write_ptr() is called
++	several time with its maximum granularity in order to try to write the output.
++	...
++	One solution:
++	-create a new function ms_fifo_get_rw_ptr(fifo1,p1, fifo2,p2) to
++		return the number of bytes able to being processed according to the input
++		and output fifo, and their respective data pointers
++	*/
++	
++	
++	fi=r->f_inputs[0];
++	fo=r->f_outputs[0];
++	
++ 	inlen=ms_fifo_get_read_ptr(fi,ALAW_ENCODER_RMAXGRAN,(void**)&s);
++	if (s==NULL) return;
++ 	outlen=ms_fifo_get_write_ptr(fo,ALAW_ENCODER_WMAXGRAN,(void**)&d);
++ 	if (d!=NULL)
++ 	{
++ 		for(i=0;i<ALAW_ENCODER_WMAXGRAN;i++)
++ 		{
++ 			d[i]=s16_to_alaw( *((gint16*)s) );
++ 			s+=2;
++ 		}
++ 	}
++ 	else g_warning("MSALAWDecoder: Discarding samples !!");
++	
++}
++
++
++
++void ms_ALAWencoder_destroy( MSALAWEncoder *obj)
++{
++	g_free(obj);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSLPC10DECODER_H
++#define MSLPC10DECODER_H
++
++#include <msfilter.h>
++#include <mscodec.h>
++#include <lpc10.h>
++
++/*this is the class that implements a LPC10decoder filter*/
++
++#define MSLPC10DECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSLPC10Decoder
++{
++    /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Decoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSLPC10DECODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSLPC10DECODER_MAX_INPUTS];
++    struct lpc10_decoder_state *lpc10_dec;
++} MSLPC10Decoder;
++
++typedef struct _MSLPC10DecoderClass
++{
++	/* the MSLPC10Decoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Decoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSLPC10DecoderClass;
++
++/* PUBLIC */
++#define MS_LPC10DECODER(filter) ((MSLPC10Decoder*)(filter))
++#define MS_LPC10DECODER_CLASS(klass) ((MSLPC10DecoderClass*)(klass))
++MSFilter * ms_LPC10decoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_LPC10decoder_init(MSLPC10Decoder *r);
++void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass);
++void ms_LPC10decoder_destroy( MSLPC10Decoder *obj);
++void ms_LPC10decoder_process(MSLPC10Decoder *r);
++
++extern MSCodecInfo LPC10info;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c	(revision 586398)
+@@ -0,0 +1,192 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <config.h>
++
++#ifdef HAVE_SPEEX
++
++#include "msspeexenc.h"
++#include "ms.h"
++extern MSCodecInfo speex_info;
++
++static MSSpeexEncClass * ms_speex_enc_class=NULL;
++
++MSFilter * ms_speex_enc_new()
++{
++	MSSpeexEnc *obj=g_new(MSSpeexEnc,1);
++	
++	if (ms_speex_enc_class==NULL){
++		ms_speex_enc_class=g_new(MSSpeexEncClass,1);
++		ms_speex_enc_class_init(ms_speex_enc_class);
++	}
++	MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_enc_class);
++	ms_speex_enc_init(MS_SPEEX_ENC(obj));
++	return MS_FILTER(obj);
++}
++
++void ms_speex_enc_init(MSSpeexEnc *obj)
++{
++	ms_filter_init(MS_FILTER(obj));
++	MS_FILTER(obj)->infifos=obj->inf;
++	MS_FILTER(obj)->outqueues=obj->outq;
++	obj->inf[0]=NULL;
++	obj->outq[0]=NULL;
++	obj->frequency=8000;
++	obj->bitrate=30000;
++  obj->initialized=0;
++}
++
++void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint bitrate)
++{
++	int proc_type, proc_speed;
++	gchar *proc_vendor;
++	int tmp;
++	int frame_size;
++	
++	obj->speex_state=speex_encoder_init(mode);
++	speex_bits_init(&obj->bits);
++	
++	if (bitrate>0) {
++		bitrate++;
++		speex_encoder_ctl(obj->speex_state, SPEEX_SET_BITRATE, &bitrate);
++		g_message("Setting speex output bitrate less or equal than %i",bitrate-1);
++	}
++
++	proc_speed=ms_proc_get_speed();
++	proc_vendor=ms_proc_get_param("vendor_id");
++	if (proc_speed<0 || proc_vendor==NULL){
++		g_warning("Can't guess processor features: setting speex encoder to its lowest complexity.");
++		tmp=1;
++		speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
++	}else if ((proc_speed!=-1) && (proc_speed<200)){
++		g_warning("A cpu speed less than 200 Mhz is not enough: let's reduce the complexity of the speex codec.");
++		tmp=1;
++		speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
++	}else if (proc_vendor!=NULL) {
++		if (strncmp(proc_vendor,"GenuineIntel",strlen("GenuineIntel"))==0){
++			proc_type=ms_proc_get_type();
++			if (proc_type==5){
++				g_warning("A pentium I is not enough fast for speex codec in normal mode: let's reduce its complexity.");
++				tmp=1;
++				speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
++			}
++		}
++		g_free(proc_vendor);
++	}
++	/* guess the used input frame size */
++	speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
++	MS_FILTER(obj)->r_mingran=frame_size*2;
++	ms_trace("ms_speex_init: using frame size of %i.",MS_FILTER(obj)->r_mingran);
++	
++	obj->initialized=1;
++}
++
++/* must be called before the encoder is running*/
++int ms_speex_enc_set_property(MSSpeexEnc *obj,int property,int *value)
++{
++	if (obj->initialized){
++		/* we are called when speex is running !! forbid that! */
++		ms_warning("ms_speex_enc_set_property: cannot call this function when running!");
++		return -1;
++	}
++	switch(property){
++		case MS_FILTER_PROPERTY_FREQ:
++			obj->frequency=value[0];
++		break;
++		case MS_FILTER_PROPERTY_BITRATE: /* to specify max bitrate */
++			obj->bitrate=value[0];
++		break;
++	}
++	return 0;
++}
++
++void ms_speex_enc_setup(MSSpeexEnc *obj)
++{
++	const SpeexMode *mode;
++	int quality;
++	g_message("Speex encoder setup: freq=%i",obj->frequency);
++	if ( obj->frequency< 16000) mode=&speex_nb_mode;
++	else mode=&speex_wb_mode;
++	ms_speex_enc_init_core(obj,mode,obj->bitrate);
++	
++}
++
++void ms_speex_enc_unsetup(MSSpeexEnc *obj)
++{
++	ms_speex_enc_uninit_core(obj);
++}
++
++void ms_speex_enc_class_init(MSSpeexEncClass *klass)
++{
++	gint frame_size=0;
++	
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	/* we take the larger (wb) frame size */
++	speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_enc_process;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_enc_destroy;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_enc_setup;
++	MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_enc_unsetup;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_enc_set_property;
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexEncoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
++	MS_FILTER_CLASS(klass)->max_finputs=1;
++	MS_FILTER_CLASS(klass)->max_qoutputs=1;
++	MS_FILTER_CLASS(klass)->r_maxgran=frame_size*2;
++	ms_trace("ms_speex_enc_class_init: r_maxgran is %i.",MS_FILTER_CLASS(klass)->r_maxgran);
++}
++
++void ms_speex_enc_uninit_core(MSSpeexEnc *obj)
++{
++	if (obj->initialized){
++		speex_encoder_destroy(obj->speex_state);
++		obj->initialized=0;
++	}
++}
++
++void ms_speex_enc_destroy(MSSpeexEnc *obj)
++{
++	ms_speex_enc_uninit_core(obj);
++	g_free(obj);
++}
++
++void ms_speex_enc_process(MSSpeexEnc *obj)
++{
++	MSFifo *inf=obj->inf[0];
++	MSQueue *outq=obj->outq[0];
++	gint16 *input;
++	gint gran=MS_FILTER(obj)->r_mingran;
++	gint i;
++	MSMessage *m;
++	
++	g_return_if_fail(inf!=NULL);
++	g_return_if_fail(outq!=NULL);
++	
++	ms_fifo_get_read_ptr(inf,gran,(void**)&input);
++	g_return_if_fail(input!=NULL);
++	/* encode */
++	speex_bits_reset(&obj->bits);
++	speex_encode_int(obj->speex_state,(short*)input,&obj->bits);
++	m=ms_message_new(speex_bits_nbytes(&obj->bits));
++	m->size=speex_bits_write(&obj->bits,m->data,m->size);
++	ms_queue_put(outq,m);
++}
++
++#endif  /* HAVE_SPEEX */
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c	(revision 586398)
+@@ -0,0 +1,99 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msMUlawenc.h"
++#include "g711common.h"
++
++extern MSCodecInfo MULAWinfo;
++
++static MSMULAWEncoderClass *ms_MULAWencoder_class=NULL;
++
++MSFilter * ms_MULAWencoder_new(void)
++{
++	MSMULAWEncoder *r;
++	
++	r=g_new(MSMULAWEncoder,1);
++	ms_MULAWencoder_init(r);
++	if (ms_MULAWencoder_class==NULL)
++	{
++		ms_MULAWencoder_class=g_new(MSMULAWEncoderClass,1);
++		ms_MULAWencoder_class_init(ms_MULAWencoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWencoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_MULAWencoder_init(MSMULAWEncoder *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->r_mingran=MULAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
++	something to process */
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
++	
++}
++
++void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWEncoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
++	MS_FILTER_CLASS(klass)->max_finputs=MSMULAWENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWENCODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=MULAW_ENCODER_RMAXGRAN;
++	MS_FILTER_CLASS(klass)->w_maxgran=MULAW_ENCODER_WMAXGRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWencoder_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWencoder_process;
++}
++	
++void ms_MULAWencoder_process(MSMULAWEncoder *r)
++{
++	MSFifo *fi,*fo;
++	int inlen,outlen;
++	gchar *s,*d;
++	int i;
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	fi=r->f_inputs[0];
++	fo=r->f_outputs[0];
++	inlen=ms_fifo_get_read_ptr(fi,MULAW_ENCODER_RMAXGRAN,(void**)&s);
++ 	outlen=ms_fifo_get_write_ptr(fo,MULAW_ENCODER_WMAXGRAN,(void**)&d);
++ 	if (d!=NULL)
++ 	{
++ 		for(i=0;i<MULAW_ENCODER_WMAXGRAN;i++)
++ 		{
++ 			d[i]=s16_to_ulaw( *((gint16*)s) );
++ 			s+=2;
++ 		}
++ 	}
++ 	else g_warning("MSMULAWDecoder: Discarding samples !!");
++}
++
++
++
++void ms_MULAWencoder_destroy( MSMULAWEncoder *obj)
++{
++	g_free(obj);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h	(revision 586398)
+@@ -0,0 +1,60 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a dispatcher of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSQDISPATCHER_H
++#define MSQDISPATCHER_H
++
++#include "msfilter.h"
++
++
++/*this is the class that implements a qdispatcher filter*/
++
++#define MS_QDISPATCHER_MAX_INPUTS  1
++#define MS_QDISPATCHER_MAX_OUTPUTS 5 
++
++typedef struct _MSQdispatcher
++{
++    /* the MSQdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSQdispatcher object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++	MSQueue *q_inputs[MS_QDISPATCHER_MAX_INPUTS];
++	MSQueue *q_outputs[MS_QDISPATCHER_MAX_OUTPUTS];
++} MSQdispatcher;
++
++typedef struct _MSQdispatcherClass
++{
++	/* the MSQdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSQdispatcher class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSQdispatcherClass;
++
++/* PUBLIC */
++#define MS_QDISPATCHER(filter) ((MSQdispatcher*)(filter))
++#define MS_QDISPATCHER_CLASS(klass) ((MSQdispatcherClass*)(klass))
++MSFilter * ms_qdispatcher_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_qdispatcher_init(MSQdispatcher *r);
++void ms_qdispatcher_class_init(MSQdispatcherClass *klass);
++void ms_qdispatcher_destroy( MSQdispatcher *obj);
++void ms_qdispatcher_process(MSQdispatcher *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h	(revision 586398)
+@@ -0,0 +1,62 @@
++/*
++  Copyright (C) 2003  Robert W. Brewer <rbrewer at op.net>
++  
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSTRUESPEECHENCODER_H
++#define MSTRUESPEECHENCODER_H
++
++#include "msfilter.h"
++#include <win32codec.h>
++
++
++#define MS_TRUESPEECH_CODEC_MAX_IN_OUT  1 /* max inputs/outputs per filter*/
++
++#define TRUESPEECH_FORMAT_TAG 0x22
++#define TRUESPEECH_DLL "tssoft32.acm"
++
++typedef struct _MSTrueSpeechEncoder
++{
++    /* the MSTrueSpeechEncoder derives from MSFilter, so the MSFilter
++       object MUST be the first of the MSTrueSpeechEncoder object
++       in order for the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
++    MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
++    Win32Codec* codec;
++} MSTrueSpeechEncoder;
++
++typedef struct _MSTrueSpeechEncoderClass
++{
++	/* the MSTrueSpeechEncoder derives from MSFilter,
++           so the MSFilter class MUST be the first of the MSTrueSpechEncoder
++           class
++           in order for the class mechanism to work*/
++  MSFilterClass parent_class;
++  Win32CodecDriver* driver;
++} MSTrueSpeechEncoderClass;
++
++/* PUBLIC */
++#define MS_TRUESPEECHENCODER(filter) ((MSTrueSpechMEncoder*)(filter))
++#define MS_TRUESPEECHENCODER_CLASS(klass) ((MSTrueSpeechEncoderClass*)(klass))
++MSFilter * ms_truespeechencoder_new(void);
++
++/* for internal use only */
++WAVEFORMATEX* ms_truespeechencoder_wf_create();
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSALAWENCODER_H
++#define MSALAWENCODER_H
++
++#include "mscodec.h"
++
++
++/*this is the class that implements a ALAWencoder filter*/
++
++#define MSALAWENCODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSALAWEncoder
++{
++    /* the MSALAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWEncoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSALAWENCODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSALAWENCODER_MAX_INPUTS];
++} MSALAWEncoder;
++
++typedef struct _MSALAWEncoderClass
++{
++	/* the MSALAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWEncoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSALAWEncoderClass;
++
++/* PUBLIC */
++#define MS_ALAWENCODER(filter) ((MSALAWEncoder*)(filter))
++#define MS_ALAWENCODER_CLASS(klass) ((MSALAWEncoderClass*)(klass))
++MSFilter * ms_ALAWencoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_ALAWencoder_init(MSALAWEncoder *r);
++void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass);
++void ms_ALAWencoder_destroy( MSALAWEncoder *obj);
++void ms_ALAWencoder_process(MSALAWEncoder *r);
++
++/* tuning parameters :*/
++#define ALAW_ENCODER_WMAXGRAN 160
++#define ALAW_ENCODER_RMAXGRAN 320
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSSPEEXENC_H
++#define MSSPEEXENC_H
++
++#include <mscodec.h>
++#include <speex.h>
++
++struct _MSSpeexEnc
++{
++	MSFilter parent;
++	MSFifo *inf[1];
++	MSQueue *outq[1];	/* speex has an output q because it can be variable bit rate */
++	void *speex_state;
++	SpeexBits bits;
++	int frequency;
++	int bitrate;
++	int initialized;
++};
++
++typedef struct _MSSpeexEnc MSSpeexEnc;
++	
++
++struct _MSSpeexEncClass
++{
++	MSFilterClass parent;
++};
++
++typedef struct _MSSpeexEncClass MSSpeexEncClass;
++
++
++#define MS_SPEEX_ENC(o)	((MSSpeexEnc*)(o))
++#define MS_SPEEX_ENC_CLASS(o)	((MSSpeexEncClass*)(o))
++
++/* generic constructor */
++MSFilter * ms_speex_enc_new();
++
++void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint quality);
++void ms_speex_enc_uninit_core(MSSpeexEnc *obj);
++void ms_speex_enc_init(MSSpeexEnc *obj);
++void ms_speex_enc_class_init(MSSpeexEncClass *klass);
++
++
++void ms_speex_enc_process(MSSpeexEnc *obj);
++void ms_speex_enc_destroy(MSSpeexEnc *obj);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSCOPY_H
++#define MSCOPY_H
++
++#include "msfilter.h"
++
++
++/*this is the class that implements a copy filter*/
++
++#define MSCOPY_MAX_INPUTS  1 /* max output per filter*/
++
++#define MSCOPY_DEF_GRAN 64 /* the default granularity*/
++
++typedef struct _MSCopy
++{
++    /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSCOPY_MAX_INPUTS];
++    MSFifo *f_outputs[MSCOPY_MAX_INPUTS];
++} MSCopy;
++
++typedef struct _MSCopyClass
++{
++	/* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSCopyClass;
++
++/* PUBLIC */
++#define MS_COPY(filter) ((MSCopy*)(filter))
++#define MS_COPY_CLASS(klass) ((MSCopyClass*)(klass))
++MSFilter * ms_copy_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_copy_init(MSCopy *r);
++void ms_copy_class_init(MSCopyClass *klass);
++void ms_copy_destroy( MSCopy *obj);
++void ms_copy_process(MSCopy *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <config.h>
++
++#ifdef HAVE_ALSA_ASOUNDLIB_H
++
++#include "sndcard.h"
++#define ALSA_PCM_NEW_HW_PARAMS_API
++#include <alsa/asoundlib.h>
++struct _AlsaCard
++{
++	SndCard parent;
++	gchar *pcmdev;
++	gchar *mixdev;
++	snd_pcm_t *read_handle;
++	snd_pcm_t *write_handle;
++	gint frame_size;
++	gint frames;
++	gchar *readbuf;
++	gint readpos;
++	gchar *writebuf;
++	gint writepos; 
++	snd_mixer_t *mixer;
++};
++
++typedef struct _AlsaCard AlsaCard;
++
++SndCard *alsa_card_new(gint dev_id);
++gint alsa_card_manager_init(SndCardManager *m, gint index);
++void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSMULAWENCODER_H
++#define MSMULAWENCODER_H
++
++#include "mscodec.h"
++
++
++/*this is the class that implements a MULAWencoder filter*/
++
++#define MSMULAWENCODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSMULAWEncoder
++{
++    /* the MSMULAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWEncoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSMULAWENCODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSMULAWENCODER_MAX_INPUTS];
++} MSMULAWEncoder;
++
++typedef struct _MSMULAWEncoderClass
++{
++	/* the MSMULAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWEncoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSMULAWEncoderClass;
++
++/* PUBLIC */
++#define MS_MULAWENCODER(filter) ((MSMULAWEncoder*)(filter))
++#define MS_MULAWENCODER_CLASS(klass) ((MSMULAWEncoderClass*)(klass))
++MSFilter * ms_MULAWencoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_MULAWencoder_init(MSMULAWEncoder *r);
++void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass);
++void ms_MULAWencoder_destroy( MSMULAWEncoder *obj);
++void ms_MULAWencoder_process(MSMULAWEncoder *r);
++
++/* tuning parameters :*/
++#define MULAW_ENCODER_WMAXGRAN 160
++#define MULAW_ENCODER_RMAXGRAN 320
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c	(revision 586398)
+@@ -0,0 +1,168 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <errno.h>
++#include <string.h>
++#include "msutils.h"
++#include "msfifo.h"
++
++MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset)
++{
++	MSFifo *fifo;
++	gint saved_offset=MAX(r_gran+r_offset,w_offset);
++	
++	g_return_val_if_fail(saved_offset<=(buf->size),NULL);
++	fifo=g_malloc(sizeof(MSFifo));
++	fifo->buffer=buf;
++	fifo->r_gran=r_gran;
++	fifo->w_gran=w_gran;
++	fifo->begin=fifo->wr_ptr=fifo->rd_ptr=buf->buffer+saved_offset;
++	fifo->readsize=0;
++	fifo->size=fifo->writesize=buf->size-saved_offset;
++	fifo->saved_offset= saved_offset;
++	fifo->r_end=fifo->w_end=buf->buffer+buf->size;
++	fifo->pre_end=fifo->w_end-saved_offset;
++	buf->ref_count++;
++	fifo->prev_data=NULL;
++	fifo->next_data=NULL;
++	ms_trace("fifo base=%x, begin=%x, end=%x, saved_offset=%i, size=%i"
++			,fifo->buffer->buffer,fifo->begin,fifo->w_end,fifo->saved_offset,fifo->size);
++	return(fifo);
++}
++
++MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset,
++																 gint min_fifo_size)
++{
++	MSFifo *fifo;
++	MSBuffer *buf;
++	gint saved_offset=MAX(r_gran+r_offset,w_offset);
++	gint fifo_size;
++	gint tmp;
++	if (min_fifo_size==0) min_fifo_size=w_gran;
++	
++	/* we must allocate a fifo with a size multiple of min_fifo_size,
++	with a saved_offset */
++	if (min_fifo_size>MS_BUFFER_LARGE)
++		fifo_size=(min_fifo_size) + saved_offset;
++	else fifo_size=(6*min_fifo_size) + saved_offset;
++	buf=ms_buffer_new(fifo_size);
++	fifo=ms_fifo_new(buf,r_gran,w_gran,r_offset,w_offset);
++	ms_trace("fifo_size=%i",fifo_size);
++	return(fifo);
++}
++
++void ms_fifo_destroy( MSFifo *fifo)
++{
++	g_free(fifo);
++}
++
++void ms_fifo_destroy_with_buffer(MSFifo *fifo)
++{
++	ms_buffer_destroy(fifo->buffer);
++	ms_fifo_destroy(fifo);
++}
++
++gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
++{
++	gchar *rnext;
++	
++	*ret_ptr=NULL;
++	/*	//ms_trace("ms_fifo_get_read_ptr: entering.");*/
++	g_return_val_if_fail(bsize<=fifo->r_gran,-EINVAL);
++	
++	if (bsize>fifo->readsize)
++	{
++		ms_trace("Not enough data: bsize=%i, readsize=%i",bsize,fifo->readsize);
++		return (-ENODATA);
++	}
++	
++	rnext=fifo->rd_ptr+bsize;
++	if (rnext<=fifo->r_end){
++		
++		*ret_ptr=fifo->rd_ptr;
++		fifo->rd_ptr=rnext;
++	}else{
++		int unread=fifo->r_end-fifo->rd_ptr;
++		*ret_ptr=fifo->begin-unread;
++		memcpy(fifo->buffer->buffer,fifo->r_end-fifo->saved_offset,fifo->saved_offset);
++		fifo->rd_ptr=(char*)(*ret_ptr) + bsize;
++		fifo->r_end=fifo->w_end;	/* this is important ! */
++		ms_trace("moving read ptr to %x",fifo->rd_ptr);
++		
++	}
++	/* update write size*/
++	fifo->writesize+=bsize;
++	fifo->readsize-=bsize;
++	return bsize;
++}
++
++
++void ms_fifo_update_write_ptr(MSFifo *fifo, gint written){
++	gint reserved=fifo->wr_ptr-fifo->prev_wr_ptr;
++	gint unwritten;
++	g_return_if_fail(reserved>=0);
++	unwritten=reserved-written;
++	g_return_if_fail(unwritten>=0);
++	/* fix readsize and writesize */
++	fifo->readsize-=unwritten;
++	fifo->writesize+=unwritten;
++	fifo->wr_ptr+=written;
++}
++
++gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
++{
++	gchar *wnext;
++
++	*ret_ptr=NULL;
++	/*	//ms_trace("ms_fifo_get_write_ptr: Entering.");*/
++	g_return_val_if_fail(bsize<=fifo->w_gran,-EINVAL);
++	if (bsize>fifo->writesize)
++	{
++		ms_trace("Not enough space: bsize=%i, writesize=%i",bsize,fifo->writesize);
++		*ret_ptr=NULL;
++		return(-ENODATA);
++	}
++	wnext=fifo->wr_ptr+bsize;
++	if (wnext<=fifo->w_end){
++		*ret_ptr=fifo->wr_ptr;
++		fifo->wr_ptr=wnext;
++	}else{
++		*ret_ptr=fifo->begin;
++		fifo->r_end=fifo->wr_ptr;
++		fifo->wr_ptr=fifo->begin+bsize;
++		ms_trace("moving write ptr to %x",fifo->wr_ptr);
++	}
++	fifo->prev_wr_ptr=*ret_ptr;
++	/* update readsize*/
++	fifo->readsize+=bsize;
++	fifo->writesize-=bsize;
++	/*	//ms_trace("ms_fifo_get_write_ptr: readsize=%i, writesize=%i",fifo->readsize,fifo->writesize);*/
++	return bsize;
++}
++
++gint ms_fifo_get_rw_ptr(MSFifo *f1,void **p1,gint minsize1,
++												MSFifo *f2,void **p2,gint minsize2)
++{
++	gint rbsize,wbsize;
++	
++	rbsize=MIN(f1->readsize,(f1->pre_end-f1->rd_ptr));
++	wbsize=MIN(f2->writesize,(f2->w_end-f2->wr_ptr));	
++	return 0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c	(revision 586398)
+@@ -0,0 +1,163 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msrtprecv.h"
++
++
++/* some utilities to convert mblk_t to MSMessage and vice-versa */
++MSMessage *msgb_2_ms_message(mblk_t* mp){
++	MSMessage *msg;
++	MSBuffer *msbuf;
++	if (mp->b_datap->ref_count!=1) return NULL; /* cannot handle properly non-unique buffers*/
++	/* create a MSBuffer using the mblk_t buffer */
++	msg=ms_message_alloc();
++	msbuf=ms_buffer_alloc(0);
++	msbuf->buffer=mp->b_datap->db_base;
++	msbuf->size=(char*)mp->b_datap->db_lim-(char*)mp->b_datap->db_base;
++	ms_message_set_buf(msg,msbuf);
++	msg->size=mp->b_wptr-mp->b_rptr;
++	msg->data=mp->b_rptr;
++	/* free the mblk_t */
++	g_free(mp->b_datap);
++	g_free(mp);
++	return msg;
++}
++
++
++static MSRtpRecvClass *ms_rtp_recv_class=NULL;
++
++MSFilter * ms_rtp_recv_new(void)
++{
++	MSRtpRecv *r;
++	
++	r=g_new(MSRtpRecv,1);
++	ms_rtp_recv_init(r);
++	if (ms_rtp_recv_class==NULL)
++	{
++		ms_rtp_recv_class=g_new0(MSRtpRecvClass,1);
++		ms_rtp_recv_class_init(ms_rtp_recv_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_recv_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_rtp_recv_init(MSRtpRecv *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->outqueues=r->q_outputs;
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
++	memset(r->q_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
++	r->rtpsession=NULL;
++	r->stream_started=0;
++}
++
++void ms_rtp_recv_class_init(MSRtpRecvClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPRecv");
++	MS_FILTER_CLASS(klass)->max_qoutputs=MSRTPRECV_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSRTPRECV_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->w_maxgran=MSRTPRECV_DEF_GRAN;
++	ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_recv_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_recv_process;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_recv_setup;
++}
++	
++void ms_rtp_recv_process(MSRtpRecv *r)
++{
++	MSFifo *fo;
++	MSQueue *qo;
++	MSSync *sync= r->sync;
++	void *d;
++	mblk_t *mp;
++	gint len;
++	gint gran=ms_sync_get_samples_per_tick(MS_SYNC(sync));
++	
++	if (r->rtpsession==NULL) return;
++	/* process output fifo and output queue*/
++	fo=r->f_outputs[0];
++	if (fo!=NULL)
++	{
++		while( (mp=rtp_session_recvm_with_ts(r->rtpsession,r->prev_ts))!=NULL) {
++			/* try to get rtp packets and paste them to the output fifo */
++			r->stream_started=1;
++			len=mp->b_cont->b_wptr-mp->b_cont->b_rptr;
++			ms_fifo_get_write_ptr(fo,len,&d);
++			if (d!=NULL){
++				memcpy(d,mp->b_cont->b_rptr,len);
++			}else ms_warning("ms_rtp_recv_process: no space on output fifo !");
++			freemsg(mp);
++		}
++		r->prev_ts+=gran; 
++				
++	}
++	qo=r->q_outputs[0];
++	if (qo!=NULL)
++	{
++		guint32 clock;
++		gint got=0;
++		/* we are connected with queues (surely for video)*/
++		/* use the sync system time to compute a timestamp */
++		PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
++		if (pt==NULL) {
++			ms_warning("ms_rtp_recv_process(): NULL RtpPayload- skipping.");
++			return;
++		}
++		clock=(guint32)(((double)sync->time*(double)pt->clock_rate)/1000.0);
++		/*g_message("Querying packet with timestamp %u",clock);*/
++		/* get rtp packet, and send them through the output queue */
++		while ( (mp=rtp_session_recvm_with_ts(r->rtpsession,clock))!=NULL ){
++			MSMessage *msg;
++			mblk_t *mdata;
++			/*g_message("Got packet with timestamp %u",clock);*/
++			got++;
++			r->stream_started=1;
++			mdata=mp->b_cont;
++			freeb(mp);
++			msg=msgb_2_ms_message(mdata);
++			ms_queue_put(qo,msg);
++		}
++	}
++}
++
++void ms_rtp_recv_destroy( MSRtpRecv *obj)
++{
++	g_free(obj);
++}
++
++RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session)
++{
++	RtpSession *old=obj->rtpsession;
++	obj->rtpsession=session;
++	obj->prev_ts=0;
++	return old;
++}
++
++
++void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync)
++{
++	r->sync=sync;
++	r->stream_started=0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c	(revision 586398)
+@@ -0,0 +1,537 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include <errno.h>
++#include "msfilter.h"
++
++
++
++void ms_filter_init(MSFilter *filter)
++{
++	filter->finputs=0;
++	filter->foutputs=0;
++	filter->qinputs=0;
++	filter->qoutputs=0;
++	filter->infifos=NULL;
++	filter->outfifos=NULL;
++	filter->inqueues=NULL;
++	filter->outqueues=NULL;
++	filter->lock=g_mutex_new();
++	filter->min_fifo_size=0x7fff;
++	filter->notify_event=NULL;
++	filter->userdata=NULL;
++}
++
++void ms_filter_uninit(MSFilter *filter)
++{
++	g_mutex_free(filter->lock);
++}
++
++void ms_filter_class_init(MSFilterClass *filterclass)
++{
++	filterclass->name=NULL;
++	filterclass->max_finputs=0;
++	filterclass->max_foutputs=0;
++	filterclass->max_qinputs=0;
++	filterclass->max_qoutputs=0;
++	filterclass->r_maxgran=0;
++	filterclass->w_maxgran=0;
++	filterclass->r_offset=0;
++	filterclass->w_offset=0;
++	filterclass->set_property=NULL;
++	filterclass->get_property=NULL;
++	filterclass->setup=NULL;
++	filterclass->unsetup=NULL;
++	filterclass->process=NULL;
++	filterclass->destroy=NULL;
++	filterclass->attributes=0;
++	filterclass->ref_count=0;
++}
++
++/* find output queue */
++gint find_oq(MSFilter *m1,MSQueue *oq)
++{
++	gint i;
++	
++	for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++){
++			if (m1->outqueues[i]==oq) return i;
++	}
++	
++	return -1;
++}
++
++/* find input queue */
++gint find_iq(MSFilter *m1,MSQueue *iq)
++{
++	gint i;
++	for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qinputs;i++){
++		if (m1->inqueues[i]==iq) return i;
++	}
++	return -1;
++}
++
++/* find output fifo */
++gint find_of(MSFilter *m1,MSFifo *of)
++{
++	gint i;
++	for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++){
++		if (m1->outfifos[i]==of) return i;
++	}
++	
++	return -1;
++}
++
++/* find input fifo */
++gint find_if(MSFilter *m1,MSFifo *inf)
++{
++	gint i;
++	
++	for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_finputs;i++){
++		if (m1->infifos[i]==inf) return i;
++	}
++	
++	return -1;
++}
++
++#define find_free_iq(_m1)	find_iq(_m1,NULL)
++#define find_free_oq(_m1)	find_oq(_m1,NULL)
++#define find_free_if(_m1)	find_if(_m1,NULL)
++#define find_free_of(_m1)	find_of(_m1,NULL)
++
++int ms_filter_add_link(MSFilter *m1, MSFilter *m2)
++{
++	gint m1_q=-1;
++	gint m1_f=-1;
++	gint m2_q=-1;
++	gint m2_f=-1;
++	/* determine the type of link we can add */
++	m1_q=find_free_oq(m1);
++	m1_f=find_free_of(m1);
++	m2_q=find_free_iq(m2);
++	m2_f=find_free_if(m2);
++	if ((m1_q!=-1) && (m2_q!=-1)){
++		/* link with queues */
++		ms_trace("m1_q=%i , m2_q=%i",m1_q,m2_q);
++		return ms_filter_link(m1,m1_q,m2,m2_q,LINK_QUEUE);
++	}
++	if ((m1_f!=-1) && (m2_f!=-1)){
++		/* link with queues */
++		ms_trace("m1_f=%i , m2_f=%i",m1_f,m2_f);
++		return ms_filter_link(m1,m1_f,m2,m2_f,LINK_FIFO);
++	}
++	g_warning("ms_filter_add_link: could not link.");
++	return -1;
++}
++/**
++ * ms_filter_link:
++ * @m1:  A #MSFilter object.
++ * @pin1:  The pin number on @m1.
++ * @m2:  A #MSFilter object.
++ * @pin2: The pin number on @m2.
++ * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
++ *
++ * This function links two MSFilter object between them. It must be used to make chains of filters.
++ * All data outgoing from pin1 of m1 will go to the input pin2 of m2.
++ * The way to communicate can be fifos or queues, depending of the nature of the filters. Filters can have
++ * multiple queue pins and multiple fifo pins, but most of them have only one queue input/output or only one
++ * fifo input/output. Fifos are usally used by filters doing audio processing, while queues are used by filters doing
++ * video processing.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, int linktype)
++{
++	MSQueue *q;
++	MSFifo *fifo;
++	
++	g_message("ms_filter_add_link: %s,%i -> %s,%i",m1->klass->name,pin1,m2->klass->name,pin2);
++	switch(linktype)
++	{
++	case LINK_QUEUE:
++		/* Are filter m1 and m2 able to accept more queues connections ?*/
++		g_return_val_if_fail(m1->qoutputs<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EMLINK);
++		g_return_val_if_fail(m2->qinputs<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EMLINK);
++		/* Are filter m1 and m2 valid with their inputs and outputs ?*/
++		g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
++		g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
++		/* are the requested pins exists ?*/
++		g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
++		g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
++		/* are the requested pins free ?*/
++		g_return_val_if_fail(m1->outqueues[pin1]==NULL,-EBUSY);
++		g_return_val_if_fail(m2->inqueues[pin2]==NULL,-EBUSY);
++		
++		q=ms_queue_new();
++		m1->outqueues[pin1]=m2->inqueues[pin2]=q;
++		m1->qoutputs++;
++		m2->qinputs++;
++		q->prev_data=(void*)m1;
++		q->next_data=(void*)m2;
++		break;
++	case LINK_FIFO:
++		/* Are filter m1 and m2 able to accept more fifo connections ?*/
++		g_return_val_if_fail(m1->foutputs<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EMLINK);
++		g_return_val_if_fail(m2->finputs<MS_FILTER_GET_CLASS(m2)->max_finputs,-EMLINK);
++		/* Are filter m1 and m2 valid with their inputs and outputs ?*/
++		g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
++		g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
++		/* are the requested pins exists ?*/
++		g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
++		g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
++		/* are the requested pins free ?*/
++		g_return_val_if_fail(m1->outfifos[pin1]==NULL,-EBUSY);
++		g_return_val_if_fail(m2->infifos[pin2]==NULL,-EBUSY);
++		
++		if (MS_FILTER_GET_CLASS(m1)->attributes & FILTER_IS_SOURCE)
++		{
++			/* configure min_fifo_size */
++			fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
++										MS_FILTER_GET_CLASS(m1)->w_maxgran,
++										MS_FILTER_GET_CLASS(m2)->r_offset,
++										MS_FILTER_GET_CLASS(m1)->w_offset,
++										MS_FILTER_GET_CLASS(m1)->w_maxgran);
++			m2->min_fifo_size=MS_FILTER_GET_CLASS(m1)->w_maxgran;
++		}
++		else
++		{
++			gint next_size;
++			ms_trace("ms_filter_add_link: min_fifo_size=%i",m1->min_fifo_size);
++			fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
++										MS_FILTER_GET_CLASS(m1)->w_maxgran,
++										MS_FILTER_GET_CLASS(m2)->r_offset,
++										MS_FILTER_GET_CLASS(m1)->w_offset,
++										m1->min_fifo_size);
++			if (MS_FILTER_GET_CLASS(m2)->r_maxgran>0){
++				next_size=(m1->min_fifo_size*
++										(MS_FILTER_GET_CLASS(m2)->w_maxgran)) /
++										(MS_FILTER_GET_CLASS(m2)->r_maxgran);
++			}else next_size=m1->min_fifo_size;
++			ms_trace("ms_filter_add_link: next_size=%i",next_size);
++			m2->min_fifo_size=next_size;
++		}
++		
++		
++		m1->outfifos[pin1]=m2->infifos[pin2]=fifo;						
++		m1->foutputs++;
++		m2->finputs++;							
++		fifo->prev_data=(void*)m1;
++		fifo->next_data=(void*)m2;
++		break;
++	}
++	return 0;
++}
++/**
++ * ms_filter_unlink:
++ * @m1:  A #MSFilter object.
++ * @pin1:  The pin number on @m1.
++ * @m2:  A #MSFilter object.
++ * @pin2: The pin number on @m2.
++ * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
++ *
++ * Unlink @pin1 of filter @m1 from @pin2 of filter @m2. @linktype specifies what type of connection is removed.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype)
++{
++	switch(linktype)
++	{
++	case LINK_QUEUE:
++		/* Are filter m1 and m2 valid with their inputs and outputs ?*/
++		g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
++		g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
++		/* are the requested pins exists ?*/
++		g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
++		g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
++		/* are the requested pins busy ?*/
++		g_return_val_if_fail(m1->outqueues[pin1]!=NULL,-ENOENT);
++		g_return_val_if_fail(m2->inqueues[pin2]!=NULL,-ENOENT);
++		/* are the two pins connected together ?*/
++		g_return_val_if_fail(m1->outqueues[pin1]==m2->inqueues[pin2],-EINVAL);
++		
++		ms_queue_destroy(m1->outqueues[pin1]);
++		m1->outqueues[pin1]=m2->inqueues[pin2]=NULL;
++		m1->qoutputs--;
++		m2->qinputs--;
++		
++		break;
++	case LINK_FIFO:
++		/* Are filter m1 and m2 valid with their inputs and outputs ?*/
++		g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
++		g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
++		/* are the requested pins exists ?*/
++		g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
++		g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
++		/* are the requested pins busy ?*/
++		g_return_val_if_fail(m1->outfifos[pin1]!=NULL,-ENOENT);
++		g_return_val_if_fail(m2->infifos[pin2]!=NULL,-ENOENT);
++		/* are the two pins connected together ?*/
++		g_return_val_if_fail(m1->outfifos[pin1]==m2->infifos[pin2],-EINVAL);
++		ms_fifo_destroy_with_buffer(m1->outfifos[pin1]);
++		m1->outfifos[pin1]=m2->infifos[pin2]=NULL;			
++		m1->foutputs--;
++		m2->finputs--;								
++		break;
++	}
++	return 0;
++}
++
++/**
++ *ms_filter_remove_links:
++ *@m1: a filter
++ *@m2: another filter.
++ *
++ * Removes all links between m1 and m2.
++ *
++ *Returns: 0 if one more link have been removed, -1 if not.
++**/
++gint ms_filter_remove_links(MSFilter *m1, MSFilter *m2)
++{
++	int i,j;
++	int removed=-1;
++	MSQueue *qo;
++	MSFifo *fo;
++	/* takes all outputs of m1, and removes the one that goes to m2 */
++	if (m1->outqueues!=NULL){
++		for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++)
++		{
++			qo=m1->outqueues[i];
++			if (qo!=NULL){
++				MSFilter *rmf;
++				/* test if the queue connects to m2 */
++				rmf=(MSFilter*)qo->next_data;
++				if (rmf==m2){
++					j=find_iq(rmf,qo);
++					if (j==-1) g_error("Could not find input queue: impossible case.");
++					ms_filter_unlink(m1,i,m2,j,LINK_QUEUE);
++					removed=0;
++				}
++			}
++		}
++	}
++	if (m1->outfifos!=NULL){
++		for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++)
++		{
++			fo=m1->outfifos[i];
++			if (fo!=NULL){
++				MSFilter *rmf;
++				/* test if the queue connects to m2 */
++				rmf=(MSFilter*)fo->next_data;
++				if (rmf==m2){
++					j=find_if(rmf,fo);
++					if (j==-1) g_error("Could not find input fifo: impossible case.");
++					ms_filter_unlink(m1,i,m2,j,LINK_FIFO);
++					removed=0;
++				}
++			}
++		}
++	}
++	return removed;
++}
++
++/**
++ * ms_filter_fifos_have_data:
++ * @f: a #MSFilter object.
++ *
++ * Tells if the filter has enough data in its input fifos in order to be executed succesfully.
++ *
++ * Returns: 1 if it can be executed, 0 else.
++ */
++gint ms_filter_fifos_have_data(MSFilter *f)
++{
++	gint i,j;
++	gint max_inputs=f->klass->max_finputs;
++	gint con_inputs=f->finputs;
++	MSFifo *fifo;
++	/* test fifos */
++	for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
++	{
++		fifo=f->infifos[i];
++		if (fifo!=NULL)
++		{
++			j++;
++    		if (fifo->readsize==0) return 0;
++			if (fifo->readsize>=f->r_mingran) return 1;
++		}
++	}
++	return 0;  
++}
++
++/**
++ * ms_filter_queues_have_data:
++ * @f: a #MSFilter object.
++ *
++ * Tells if the filter has enough data in its input queues in order to be executed succesfully.
++ *
++ * Returns: 1 if it can be executed, 0 else.
++ */
++gint ms_filter_queues_have_data(MSFilter *f)
++{
++	gint i,j;
++	gint max_inputs=f->klass->max_qinputs;
++	gint con_inputs=f->qinputs;
++	MSQueue *q;
++	/* test queues */
++	for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
++	{
++		q=f->inqueues[i];
++		if (q!=NULL)
++		{
++			j++;
++			if (ms_queue_can_get(q)) return 1;
++		}
++	}
++	return 0;  
++}
++
++
++
++void ms_filter_destroy(MSFilter *f)
++{
++	/* first check if the filter is disconnected from any others */
++	g_return_if_fail(f->finputs==0);
++	g_return_if_fail(f->foutputs==0);
++	g_return_if_fail(f->qinputs==0);
++	g_return_if_fail(f->qoutputs==0);
++	f->klass->destroy(f);
++}
++
++GList *filter_list=NULL;
++
++void ms_filter_register(MSFilterInfo *info)
++{
++	gpointer tmp;
++	tmp=g_list_find(filter_list,info);
++	if (tmp==NULL) filter_list=g_list_append(filter_list,(gpointer)info);
++}
++
++void ms_filter_unregister(MSFilterInfo *info)
++{
++	filter_list=g_list_remove(filter_list,(gpointer)info);
++}
++
++static gint compare_names(gpointer info, gpointer name)
++{
++	MSFilterInfo *i=(MSFilterInfo*) info;
++	return (strcmp(i->name,name));
++}
++
++MSFilterInfo * ms_filter_get_by_name(const gchar *name)
++{
++	GList *elem=g_list_find_custom(filter_list,
++						(gpointer)name,(GCompareFunc)compare_names);
++	if (elem!=NULL){
++		return (MSFilterInfo*)elem->data;
++	}
++	return NULL;
++}
++
++
++
++MSFilter * ms_filter_new_with_name(const gchar *name)
++{
++	MSFilterInfo *info=ms_filter_get_by_name(name);
++	if (info!=NULL) return info->constructor();
++	g_warning("ms_filter_new_with_name: no filter named %s found.",name);
++	return NULL;
++}
++
++
++/* find the first codec in the left part of the stream */
++MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type)
++{
++	MSFilter *tmp=f;
++	MSFilterInfo *info;
++	
++	if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)){
++		tmp=(MSFilter*) tmp->infifos[0]->prev_data;
++		while(1){
++			info=MS_FILTER_GET_CLASS(tmp)->info;
++			if (info!=NULL){
++				if ( (info->type==type) ){
++					return tmp;
++				}
++			}
++			if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL))
++				tmp=(MSFilter*) tmp->infifos[0]->prev_data;
++			else break;
++		}
++	}
++	tmp=f;
++	if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)){
++		tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
++		while(1){
++		
++			info=MS_FILTER_GET_CLASS(tmp)->info;
++			if (info!=NULL){
++				if ( (info->type==type)){
++					return tmp;
++				}
++			}else g_warning("ms_filter_search_upstream_by_type: filter %s has no info."
++							,MS_FILTER_GET_CLASS(tmp)->name);
++			if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL))
++				tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
++			else break;
++		}	
++	}
++	return NULL;
++}
++
++
++int ms_filter_set_property(MSFilter *f, MSFilterProperty prop,void *value)
++{
++	if (f->klass->set_property!=NULL){
++		return f->klass->set_property(f,prop,value);
++	}
++	return 0;
++}
++
++int ms_filter_get_property(MSFilter *f, MSFilterProperty prop,void *value)
++{
++	if (f->klass->get_property!=NULL){
++		return f->klass->get_property(f,prop,value);
++	}
++	return -1;
++}
++
++void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata)
++{
++	filter->notify_event=func;
++	filter->userdata=userdata;
++}
++
++void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg)
++{
++	if (filter->notify_event!=NULL){
++		filter->notify_event(filter,event,arg,filter->userdata);
++	}
++}
++
++void swap_buffer(gchar *buffer, gint len)
++{
++	int i;
++	gchar tmp;
++	for (i=0;i<len;i+=2){
++		tmp=buffer[i];
++		buffer[i]=buffer[i+1];
++		buffer[i+1]=tmp;
++	}
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifdef HAVE_GLIB
++#include <glib.h>
++#else
++#include "glist.h"
++#endif
++#include "msbuffer.h"
++
++typedef struct _MSFifo
++{
++	gint r_gran;  					/*maximum granularity for reading*/
++	gint w_gran;						/*maximum granularity for writing*/
++	gchar * rd_ptr;        /* read pointer on the position where there is something to read on the MSBuffer */
++	guint32 readsize;
++	gchar * wr_ptr;
++	gchar * prev_wr_ptr;
++	guint32 writesize;      /* write pointer on the position where it is possible to write on the MSBuffer */
++	gchar * begin;  /* rd_ptr et wr_ptr must all be >=begin*/
++	guint32 size;        /* the length of the fifo, but this may not be equal to buffer->size*/
++	guint32 saved_offset;
++	gchar * pre_end;  /* the end of the buffer that is copied at the begginning when we wrap around*/
++	gchar * w_end;    /* when a wr ptr is expected to exceed end_offset,
++											it must be wrapped around to go at the beginning of the buffer. This is the end of the buffer*/
++	gchar * r_end;    /* this is the last position written at the end of the fifo. If a read ptr is expected to
++											exceed this pointer, it must be put at the begginning of the buffer */
++	void *prev_data;   /*user data, usually the writing MSFilter*/
++	void *next_data;   /* user data, usually the reading MSFilter */
++	MSBuffer *buffer;
++} MSFifo;
++
++/* constructor*/
++/* r_gran: max granularity for reading (in number of bytes)*/
++/* w_gran: max granularity for writing (in number of bytes)*/
++/* r_offset: number of bytes that are kept available behind read pointer (for recursive filters)*/
++/* w_offset: number of bytes that are kept available behind write pointer (for recursive filters)*/
++/* buf is a MSBuffer that should be compatible with the above parameter*/
++MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset);
++
++/*does the same that ms_fifo_new(), but also allocate a compatible buffer automatically*/
++MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, gint min_buffer_size);
++
++void ms_fifo_destroy( MSFifo *fifo);
++
++void ms_fifo_destroy_with_buffer(MSFifo *fifo);
++
++/* get data to read */
++gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
++
++/* get a buffer to write*/
++gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
++
++/* in case the buffer got by ms_fifo_get_write_ptr() could not be filled completely, you must
++tell it by using this function */
++void ms_fifo_update_write_ptr(MSFifo *fifo, gint written);
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSRTPRECV_H
++#define MSRTPRECV_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++/* because of a conflict between config.h from oRTP and config.h from linphone:*/
++#undef PACKAGE
++#undef VERSION                                                
++#include <ortp/ortp.h>
++
++/*this is the class that implements a copy filter*/
++
++#define MSRTPRECV_MAX_OUTPUTS  1 /* max output per filter*/
++
++#define MSRTPRECV_DEF_GRAN 4096 /* the default granularity*/
++
++struct _MSRtpRecv
++{
++    /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_outputs[MSRTPRECV_MAX_OUTPUTS];
++	MSQueue *q_outputs[MSRTPRECV_MAX_OUTPUTS];
++	MSSync *sync;
++	RtpSession *rtpsession;
++	guint32 prev_ts;
++	gint stream_started;
++};
++
++typedef struct _MSRtpRecv MSRtpRecv;
++
++struct _MSRtpRecvClass
++{
++	/* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSRtpRecvClass MSRtpRecvClass;
++
++/* PUBLIC */
++#define MS_RTP_RECV(filter) ((MSRtpRecv*)(filter))
++#define MS_RTP_RECV_CLASS(klass) ((MSRtpRecvClass*)(klass))
++MSFilter * ms_rtp_recv_new(void);
++RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session);
++#define ms_rtp_recv_unset_session(obj) (ms_rtp_recv_set_session((obj),NULL))
++#define ms_rtp_recv_get_session(obj) ((obj)->rtpsession)
++
++
++
++/* FOR INTERNAL USE*/
++void ms_rtp_recv_init(MSRtpRecv *r);
++void ms_rtp_recv_class_init(MSRtpRecvClass *klass);
++void ms_rtp_recv_destroy( MSRtpRecv *obj);
++void ms_rtp_recv_process(MSRtpRecv *r);
++void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h	(revision 586398)
+@@ -0,0 +1,201 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSFILTER_H
++#define MSFILTER_H
++
++#include <config.h>
++
++#ifdef HAVE_GLIB
++#include <glib.h>
++#include <gmodule.h>
++#else
++#undef VERSION
++#undef PACKAGE
++#include <uglib.h>
++#endif
++
++#include <string.h>
++#include "msutils.h"
++#include "msfifo.h"
++#include "msqueue.h"
++
++struct _MSFilter;
++/*this is the abstract object and class for all filter types*/
++typedef gint (*MSFilterNotifyFunc)(struct _MSFilter*, gint event, gpointer arg, gpointer userdata);
++
++struct _MSFilter
++{
++	struct _MSFilterClass *klass;
++	GMutex *lock;
++	guchar finputs;   /* number of connected fifo inputs*/
++	guchar foutputs;  /* number of connected fifo outputs*/
++	guchar qinputs;   /* number of connected queue inputs*/
++	guchar qoutputs;  /* number of connected queue outputs*/
++	gint min_fifo_size; /* set when linking*/
++	gint r_mingran;				/* read minimum granularity (for fifos).
++					It can be zero so that the filter can accept any size of reading data*/
++	MSFifo **infifos; /*pointer to a table of pointer to input fifos*/
++	MSFifo **outfifos;  /*pointer to a table of pointer to output fifos*/
++	MSQueue **inqueues;  /*pointer to a table of pointer to input queues*/
++	MSQueue **outqueues;  /*pointer to a table of pointer to output queues*/
++	MSFilterNotifyFunc notify_event;
++	gpointer userdata;
++};
++
++typedef struct _MSFilter MSFilter;
++
++typedef enum{
++	MS_FILTER_PROPERTY_FREQ,	/* value is int */
++	MS_FILTER_PROPERTY_BITRATE, /*value is int */
++	MS_FILTER_PROPERTY_CHANNELS,/*value is int */
++	MS_FILTER_PROPERTY_FMTP    /* value is string */
++}MSFilterProperty;
++
++#define MS_FILTER_PROPERTY_STRING_MAX_SIZE 256
++
++typedef MSFilter * (*MSFilterNewFunc)(void);
++typedef  void (*MSFilterProcessFunc)(MSFilter *);
++typedef  void (*MSFilterDestroyFunc)(MSFilter *);
++typedef  int (*MSFilterPropertyFunc)(MSFilter *,int ,void*);
++typedef  void (*MSFilterSetupFunc)(MSFilter *, void *);  /*2nd arg is the sync */
++
++typedef struct _MSFilterClass
++{
++	struct _MSFilterInfo *info;	/*pointer to a filter_info */
++	gchar *name;
++	guchar max_finputs;   /* maximum number of fifo inputs*/
++	guchar max_foutputs;  /* maximum number of fifo outputs*/
++	guchar max_qinputs;   /* maximum number of queue inputs*/
++	guchar max_qoutputs;  /* maximum number of queue outputs*/
++	gint r_maxgran;       /* read maximum granularity (for fifos)*/
++	gint w_maxgran;				/* write maximum granularity (for fifos)*/
++	gint r_offset;				/* size of kept samples behind read pointer (for fifos)*/
++	gint w_offset;				/* size of kept samples behind write pointer (for fifos)*/
++	MSFilterPropertyFunc set_property;
++	MSFilterPropertyFunc get_property;
++	MSFilterSetupFunc setup;	/* called when attaching to sync */
++	void (*process)(MSFilter *filter);
++	MSFilterSetupFunc unsetup;	/* called when detaching from sync */
++	void (*destroy)(MSFilter *filter);
++	guint attributes;
++#define FILTER_HAS_FIFOS (0x0001)
++#define FILTER_HAS_QUEUES (0x0001<<1)
++#define FILTER_IS_SOURCE (0x0001<<2)
++#define FILTER_IS_SINK (0x0001<<3)
++#define FILTER_CAN_SYNC (0x0001<<4)
++	guint ref_count; /*number of object using the class*/
++} MSFilterClass;
++
++
++
++#define MS_FILTER(obj) ((MSFilter*)obj)
++#define MS_FILTER_CLASS(klass) ((MSFilterClass*)klass)
++#define MS_FILTER_GET_CLASS(obj) ((MSFilterClass*)((MS_FILTER(obj)->klass)))
++
++void ms_filter_class_init(MSFilterClass *filterclass);
++void ms_filter_init(MSFilter *filter);
++
++#define ms_filter_class_set_attr(filter,flag) ((filter)->attributes|=(flag))
++#define ms_filter_class_unset_attr(filter,flag) ((filter)->attributes&=~(flag))
++
++#define ms_filter_class_set_name(__klass,__name)  (__klass)->name=g_strdup((__name))
++#define ms_filter_class_set_info(_klass,_info)	(_klass)->info=(_info)
++/* public*/
++
++#define  ms_filter_process(filter) ((filter)->klass->process((filter)))
++
++#define ms_filter_lock(filter)		g_mutex_lock((filter)->lock)
++#define ms_filter_unlock(filter)	g_mutex_unlock((filter)->lock)
++/* low level connect functions */
++int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, gint linktype);
++int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype);
++
++/* high level connect functions */
++int ms_filter_add_link(MSFilter *m1, MSFilter *m2);
++int ms_filter_remove_links(MSFilter *m1, MSFilter *m2);
++
++void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata);
++void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg);
++
++int ms_filter_set_property(MSFilter *f,MSFilterProperty property, void *value);
++int ms_filter_get_property(MSFilter *f,MSFilterProperty property, void *value);
++
++
++gint ms_filter_fifos_have_data(MSFilter *f);
++gint ms_filter_queues_have_data(MSFilter *f);
++
++void ms_filter_uninit(MSFilter *obj);
++void ms_filter_destroy(MSFilter *f);
++
++#define ms_filter_get_mingran(f) ((f)->r_mingran)
++#define ms_filter_set_mingran(f,gran) ((f)->r_mingran=(gran))
++
++#define LINK_DEFAULT 0
++#define LINK_FIFO 1
++#define LINK_QUEUE 2
++
++
++#define MSFILTER_VERSION(a,b,c) (((a)<<2)|((b)<<1)|(c))
++
++enum _MSFilterType
++{
++	MS_FILTER_DISK_IO,
++	MS_FILTER_AUDIO_CODEC,
++	MS_FILTER_VIDEO_CODEC,
++	MS_FILTER_NET_IO,
++	MS_FILTER_VIDEO_IO,
++	MS_FILTER_AUDIO_IO,
++	MS_FILTER_OTHER
++};
++
++typedef enum _MSFilterType MSFilterType;
++
++
++/* find the first codec in the left part of the stream */
++MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type);
++
++struct _MSFilterInfo
++{
++	gchar *name;
++	gint version;
++	MSFilterType type;
++	MSFilterNewFunc constructor;
++	char *description;  /*some textual information*/
++};
++
++typedef struct _MSFilterInfo MSFilterInfo;
++
++void ms_filter_register(MSFilterInfo *finfo);
++void ms_filter_unregister(MSFilterInfo *finfo);
++MSFilterInfo * ms_filter_get_by_name(const gchar *name);
++
++MSFilter * ms_filter_new_with_name(const gchar *name);
++
++
++
++extern GList *filter_list;
++#define MS_FILTER_INFO(obj)	((MSFilterInfo*)obj)
++
++void swap_buffer(gchar *buffer, gint len);
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c	(revision 586398)
+@@ -0,0 +1,121 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "mswrite.h"
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <string.h>
++#include <errno.h>
++
++static MSWriteClass *ms_write_class=NULL;
++
++MSFilter * ms_write_new(char *name)
++{
++	MSWrite *r;
++	int fd=-1;
++	
++	r=g_new(MSWrite,1);
++	ms_write_init(r);
++	if (ms_write_class==NULL)
++	{
++		ms_write_class=g_new(MSWriteClass,1);
++		ms_write_class_init(ms_write_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_write_class);
++	if ((name!=NULL) && (strlen(name)!=0))
++	{
++		fd=open(name,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
++		if (fd<0) g_error("ms_write_new: failed to open %s.\n",name);
++	}
++	r->fd=fd;
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_write_init(MSWrite *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->inqueues=r->q_inputs;
++	MS_FILTER(r)->r_mingran=MSWRITE_MIN_GRAN;
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSWRITE_MAX_INPUTS);
++	memset(r->q_inputs,0,sizeof(MSQueue*)*MSWRITE_MAX_INPUTS);
++	r->fd=-1;
++}
++
++void ms_write_class_init(MSWriteClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskwriter");
++	MS_FILTER_CLASS(klass)->max_finputs=MSWRITE_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_qinputs=MSWRITE_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=MSWRITE_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_write_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_write_process;
++}
++	
++void ms_write_process(MSWrite *r)
++{
++	MSFifo *f;
++	MSQueue *q;
++	MSMessage *buf=NULL;
++	int i,j,err1,err2;
++	gint gran=ms_filter_get_mingran(MS_FILTER(r));
++	void *p;
++	
++	/* process output fifos*/
++	for (i=0,j=0;(i<MS_FILTER(r)->klass->max_finputs)&&(j<MS_FILTER(r)->finputs);i++)
++	{
++		f=r->f_inputs[i];
++		if (f!=NULL)
++		{
++			if ( (err1=ms_fifo_get_read_ptr(f,gran,&p))>0 )
++			{
++			
++				err2=write(r->fd,p,gran);
++				if (err2<0) g_warning("ms_write_process: failed to write: %s.\n",strerror(errno));
++			}
++			j++;
++		}
++	}
++	/* process output queues*/
++	for (i=0,j=0;(i<MS_FILTER(r)->klass->max_qinputs)&&(j<MS_FILTER(r)->qinputs);i++)
++	{
++		q=r->q_inputs[i];
++		if (q!=NULL)
++		{
++			while ( (buf=ms_queue_get(q))!=NULL ){
++				write(r->fd,buf->data,buf->size);
++				j++;	
++				ms_message_destroy(buf);
++			}
++		}				
++	}	
++}
++
++void ms_write_destroy( MSWrite *obj)
++{
++	if (obj->fd!=0) close(obj->fd);
++	g_free(obj);
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c	(revision 586398)
+@@ -0,0 +1,495 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "osscard.h"
++
++#include "msossread.h"
++#include "msosswrite.h"
++
++#ifdef HAVE_SYS_SOUNDCARD_H
++#include <sys/soundcard.h>
++
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/time.h>
++
++#if 0
++void * oss_thread(OssCard *obj)
++{
++	gint i;
++	gint err;
++	g_message("oss_thread: starting **********");
++	while(1){
++		for(i=0;i<OSS_CARD_BUFFERS;i++){
++			g_mutex_lock(obj->lock);
++			if (obj->ref==0){
++				g_cond_signal(obj->cond);
++				g_mutex_unlock(obj->lock);
++				g_thread_exit(NULL);
++			}
++			g_mutex_unlock(obj->lock);
++			obj->readindex=i;
++			
++			err=read(obj->fd,obj->readbuf[i],SND_CARD(obj)->bsize);
++			if (err<0) g_warning("oss_thread: read() error:%s.",strerror(errno));
++			obj->writeindex=i;
++			write(obj->fd,obj->writebuf[i],SND_CARD(obj)->bsize);
++			memset(obj->writebuf[i],0,SND_CARD(obj)->bsize);
++		}
++	}
++}
++#endif
++int oss_open(OssCard *obj, int bits,int stereo, int rate)
++{
++	int fd;
++	int p=0,cond=0;
++	int i=0;
++	int min_size=0,blocksize=512;
++	int err;
++	
++	//g_message("opening sound device");
++	fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
++	if (fd<0) return -EWOULDBLOCK;
++	/* unset nonblocking mode */
++	/* We wanted non blocking open but now put it back to normal ; thanks Xine !*/
++	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK);
++
++	/* reset is maybe not needed but takes time*/
++	/*ioctl(fd, SNDCTL_DSP_RESET, 0); */
++
++	
++#ifdef WORDS_BIGENDIAN
++	p=AFMT_U16_BE;
++#else
++	p=AFMT_U16_LE;
++#endif
++	
++	err=ioctl(fd,SNDCTL_DSP_SETFMT,&p);
++	if (err<0){
++		g_warning("oss_open: can't set sample format:%s.",strerror(errno));
++	}
++
++	
++	p =  bits;  /* 16 bits */
++	err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
++	if (err<0){
++		g_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno));
++	}
++
++	p =  rate;  /* rate in khz*/
++	err=ioctl(fd, SNDCTL_DSP_SPEED, &p);
++	if (err<0){
++		g_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno));
++	}
++	
++	p =  stereo;  /* stereo or not */
++	err=ioctl(fd, SNDCTL_DSP_STEREO, &p);
++	if (err<0){
++		g_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno));
++	}
++	
++	if (rate==16000) blocksize=4096;	/* oss emulation is not very good at 16khz */
++	else blocksize=blocksize*(rate/8000);
++	ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
++
++	/* try to subdivide BLKSIZE to reach blocksize if necessary */
++	if (min_size>blocksize)
++  {
++		cond=1;
++    	p=min_size/blocksize;
++    	while(cond)
++    	{
++			i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
++			//printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
++     	if ((i==0) || (p==1)) cond=0;
++     	else p=p/2;
++     }
++	}
++	ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
++	if (min_size>blocksize)
++	{
++		g_warning("dsp block size set to %i.",min_size);
++	}else{
++		/* no need to access the card with less latency than needed*/
++		min_size=blocksize;
++	}
++
++	g_message("dsp blocksize is %i.",min_size);
++	
++	/* start recording !!! Alex */
++    {
++      int fl,res;
++
++      fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT;
++      res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl);
++      if (res<0) g_warning("OSS_TRIGGER: %s",strerror(errno));
++    } 
++	
++	obj->fd=fd;
++	obj->readpos=0;
++	obj->writepos=0;
++	SND_CARD(obj)->bits=bits;
++	SND_CARD(obj)->stereo=stereo;
++	SND_CARD(obj)->rate=rate;
++	SND_CARD(obj)->bsize=min_size;
++	return fd;
++}
++
++int oss_card_probe(OssCard *obj,int bits,int stereo,int rate)
++{
++	
++	int fd;
++	int p=0,cond=0;
++	int i=0;
++	int min_size=0,blocksize=512;
++	
++	if (obj->fd>0) return SND_CARD(obj)->bsize;
++	fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
++	if (fd<0) {
++		g_warning("oss_card_probe: can't open %s: %s.",obj->dev_name,strerror(errno));
++		return -1;
++	}
++	ioctl(fd, SNDCTL_DSP_RESET, 0);
++
++	p =  bits;  /* 16 bits */
++	ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
++
++	p =  stereo;  /* number of channels */
++	ioctl(fd, SNDCTL_DSP_CHANNELS, &p);
++
++	p =  rate;  /* rate in khz*/
++	ioctl(fd, SNDCTL_DSP_SPEED, &p);
++
++	ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
++
++	/* try to subdivide BLKSIZE to reach blocksize if necessary */
++	if (min_size>blocksize)
++  {
++		cond=1;
++    	p=min_size/blocksize;
++    	while(cond)
++    	{
++			i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
++			//printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
++     	if ((i==0) || (p==1)) cond=0;
++     	else p=p/2;
++     }
++	}
++	ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
++	if (min_size>blocksize)
++	{
++		g_warning("dsp block size set to %i.",min_size);
++	}else{
++		/* no need to access the card with less latency than needed*/
++		min_size=blocksize;
++	}
++	close(fd);
++	return min_size;
++}
++
++
++int oss_card_open(OssCard *obj,int bits,int stereo,int rate)
++{
++	int fd;
++	obj->ref++;
++	if (obj->fd==0){
++		fd=oss_open(obj,bits,stereo,rate);
++		if (fd<0) {
++			obj->fd=0;
++			obj->ref--;
++			return -1;
++		}
++	}
++	
++	obj->readbuf=g_malloc0(SND_CARD(obj)->bsize);
++	obj->writebuf=g_malloc0(SND_CARD(obj)->bsize);
++	
++	SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
++	return 0;
++}
++
++void oss_card_close(OssCard *obj)
++{
++	int i;
++	obj->ref--;
++	if (obj->ref==0) {
++		close(obj->fd);
++		obj->fd=0;
++		SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
++		g_free(obj->readbuf);
++		obj->readbuf=NULL;
++		g_free(obj->writebuf);
++		obj->writebuf=NULL;
++		
++	}
++}
++
++void oss_card_destroy(OssCard *obj)
++{
++	snd_card_uninit(SND_CARD(obj));
++	g_free(obj->dev_name);
++	g_free(obj->mixdev_name);
++	if (obj->readbuf!=NULL) g_free(obj->readbuf);
++	if (obj->writebuf!=NULL) g_free(obj->writebuf);
++}
++
++gboolean oss_card_can_read(OssCard *obj)
++{
++	struct timeval tout={0,0};
++	int err;
++	fd_set fdset;
++	if (obj->readpos!=0) return TRUE;
++	FD_ZERO(&fdset);
++	FD_SET(obj->fd,&fdset);
++	err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
++	if (err>0) return TRUE;
++	else return FALSE;
++}
++
++int oss_card_read(OssCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	if (size<bsize){
++		gint canread=MIN(bsize-obj->readpos,size);
++		if (obj->readpos==0){
++			err=read(obj->fd,obj->readbuf,bsize);
++			if (err<0) {
++				g_warning("oss_card_read: read() failed:%s.",strerror(errno));
++				return -1;
++			}
++		}
++			
++		memcpy(buf,&obj->readbuf[obj->readpos],canread);
++		obj->readpos+=canread;
++		if (obj->readpos>=bsize) obj->readpos=0;
++		return canread;
++	}else{
++		err=read(obj->fd,buf,size);
++		if (err<0) {
++			g_warning("oss_card_read: read-2() failed:%s.",strerror(errno));
++		}
++		return err;
++	}
++	
++}
++
++int oss_card_write(OssCard *obj,char *buf,int size)
++{
++	int err;
++	gint bsize=SND_CARD(obj)->bsize;
++	
++	if (size<bsize){
++		gint canwrite;
++		canwrite=MIN(bsize-obj->writepos,size);
++		memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
++		obj->writepos+=canwrite;
++		if (obj->writepos>=bsize){
++			err=write(obj->fd,obj->writebuf,bsize);
++			obj->writepos=0;
++		}
++		return canwrite;
++	}else{
++		return write(obj->fd,buf,bsize);
++	}
++}
++
++void oss_card_set_level(OssCard *obj,gint way,gint a)
++{
++	int p,mix_fd;
++	int osscmd;
++	g_return_if_fail(obj->mixdev_name!=NULL);
++#ifdef HAVE_SYS_SOUNDCARD_H
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			osscmd=SOUND_MIXER_VOLUME;
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			osscmd=SOUND_MIXER_IGAIN;
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			osscmd=SOUND_MIXER_PCM;
++		break;
++		default:
++			g_warning("oss_card_set_level: unsupported command.");
++			return;
++	}
++	p=(((int)a)<<8 | (int)a);
++	mix_fd = open(obj->mixdev_name, O_WRONLY);
++	ioctl(mix_fd,MIXER_WRITE(osscmd), &p);
++	close(mix_fd);
++#endif
++}
++
++gint oss_card_get_level(OssCard *obj,gint way)
++{
++	int p=0,mix_fd;
++	int osscmd;
++	g_return_if_fail(obj->mixdev_name!=NULL);
++#ifdef HAVE_SYS_SOUNDCARD_H
++	switch(way){
++		case SND_CARD_LEVEL_GENERAL:
++			osscmd=SOUND_MIXER_VOLUME;
++		break;
++		case SND_CARD_LEVEL_INPUT:
++			osscmd=SOUND_MIXER_IGAIN;
++		break;
++		case SND_CARD_LEVEL_OUTPUT:
++			osscmd=SOUND_MIXER_PCM;
++		break;
++		default:
++			g_warning("oss_card_get_level: unsupported command.");
++			return -1;
++	}
++	mix_fd = open(obj->mixdev_name, O_RDONLY);
++	ioctl(mix_fd,MIXER_READ(SOUND_MIXER_VOLUME), &p);
++	close(mix_fd);
++#endif
++	return p>>8;
++}
++
++void oss_card_set_source(OssCard *obj,int source)
++{
++	gint p=0;
++	gint mix_fd;
++	g_return_if_fail(obj->mixdev_name!=NULL);
++#ifdef HAVE_SYS_SOUNDCARD_H	
++	if (source == 'c')
++		p = 1 << SOUND_MIXER_CD;
++	if (source == 'l')
++		p = 1 << SOUND_MIXER_LINE;
++	if (source == 'm')
++		p = 1 << SOUND_MIXER_MIC;
++
++	
++	mix_fd = open(obj->mixdev_name, O_WRONLY);
++	ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p);
++	close(mix_fd);
++#endif
++}
++
++MSFilter *oss_card_create_read_filter(OssCard *card)
++{
++	MSFilter *f=ms_oss_read_new();
++	ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
++	return f;
++}
++
++MSFilter *oss_card_create_write_filter(OssCard *card)
++{
++	MSFilter *f=ms_oss_write_new();
++	ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
++	return f;
++}
++
++
++SndCard * oss_card_new(char *devname, char *mixdev_name)
++{
++	OssCard * obj= g_new0(OssCard,1);
++	SndCard *base= SND_CARD(obj);
++	snd_card_init(base);
++	obj->dev_name=g_strdup(devname);
++	obj->mixdev_name=g_strdup( mixdev_name);
++#ifdef HAVE_GLIB
++	base->card_name=g_strdup_printf("%s (Open Sound System)",devname);
++#else
++	base->card_name=malloc(100);
++	snprintf(base->card_name, 100, "%s (Open Sound System)",devname);
++#endif
++	base->_probe=(SndCardOpenFunc)oss_card_probe;
++	base->_open_r=(SndCardOpenFunc)oss_card_open;
++	base->_open_w=(SndCardOpenFunc)oss_card_open;
++	base->_can_read=(SndCardPollFunc)oss_card_can_read;
++	base->_read=(SndCardIOFunc)oss_card_read;
++	base->_write=(SndCardIOFunc)oss_card_write;
++	base->_close_r=(SndCardCloseFunc)oss_card_close;
++	base->_close_w=(SndCardCloseFunc)oss_card_close;
++	base->_set_rec_source=(SndCardMixerSetRecSourceFunc)oss_card_set_source;
++	base->_set_level=(SndCardMixerSetLevelFunc)oss_card_set_level;
++	base->_get_level=(SndCardMixerGetLevelFunc)oss_card_get_level;
++	base->_destroy=(SndCardDestroyFunc)oss_card_destroy;
++	base->_create_read_filter=(SndCardCreateFilterFunc)oss_card_create_read_filter;
++	base->_create_write_filter=(SndCardCreateFilterFunc)oss_card_create_write_filter;
++	return base;
++}
++
++#define DSP_NAME "/dev/dsp"
++#define MIXER_NAME "/dev/mixer"
++
++gint oss_card_manager_init(SndCardManager *manager, gint tabindex)
++{
++	gchar *devname;
++	gchar *mixername;
++	gint devindex=0;
++	gint found=0;
++
++	/* search for /dev/dsp and /dev/mixer */
++#ifdef HAVE_GLIB
++	if (g_file_test(DSP_NAME,G_FILE_TEST_EXISTS)){
++		tabindex++;
++		devindex++;
++		manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
++		manager->cards[0]->index=0;
++		found++;
++		g_message("Found /dev/dsp.");
++	}
++	for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
++		devname=g_strdup_printf("%s%i",DSP_NAME,devindex);
++		mixername=g_strdup_printf("%s%i",MIXER_NAME,devindex);
++		if (g_file_test(devname,G_FILE_TEST_EXISTS)){
++			manager->cards[tabindex]=oss_card_new(devname,mixername);
++			manager->cards[tabindex]->index=tabindex;
++			tabindex++;
++			found++;
++		}
++		g_free(devname);
++		g_free(mixername);
++	}
++#else
++	if (access(DSP_NAME,F_OK)==0){
++		tabindex++;
++		devindex++;
++		manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
++		manager->cards[0]->index=0;
++		found++;
++		g_message("Found /dev/dsp.");
++	}
++	for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
++		devname=malloc(100);
++		snprintf(devname, 100, "%s%i",DSP_NAME,devindex);
++		mixername=malloc(100);
++		snprintf(mixername, 100, "%s%i",MIXER_NAME,devindex);
++
++		if (access(devname,F_OK)==0){
++			manager->cards[tabindex]=oss_card_new(devname,mixername);
++			manager->cards[tabindex]->index=tabindex;
++			tabindex++;
++			found++;
++		}
++		g_free(devname);
++		g_free(mixername);
++	}
++#endif
++	if (tabindex==0) g_warning("No sound cards found !");
++	return found;
++}
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSWRITE_H
++#define MSWRITE_H
++
++#include "msfilter.h"
++
++
++/*this is the class that implements writing reading sink filter*/
++
++#define MSWRITE_MAX_INPUTS  1 /* max output per filter*/
++
++#define MSWRITE_DEF_GRAN 512 /* the default granularity*/
++#define MSWRITE_MIN_GRAN 64
++
++typedef struct _MSWrite
++{
++    /* the MSWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSWrite object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSWRITE_MAX_INPUTS];
++    MSQueue *q_inputs[MSWRITE_MAX_INPUTS];
++    gint fd;  /* the file descriptor of the file being written*/
++} MSWrite;
++
++typedef struct _MSWriteClass
++{
++	/* the MSWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSWrite class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSWriteClass;
++
++/* PUBLIC */
++#define MS_WRITE(filter) ((MSWrite*)(filter))
++#define MS_WRITE_CLASS(klass) ((MSWriteClass*)(klass))
++MSFilter * ms_write_new(char *name);
++
++/* FOR INTERNAL USE*/
++void ms_write_init(MSWrite *r);
++void ms_write_class_init(MSWriteClass *klass);
++void ms_write_destroy( MSWrite *obj);
++void ms_write_process(MSWrite *r);
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c	(revision 586398)
+@@ -0,0 +1,148 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msossread.h"
++#include "mssync.h"
++#include <unistd.h>
++#include <errno.h>
++#include <sys/time.h>
++#include <sys/types.h>
++
++MSFilterInfo oss_read_info={
++	"OSS read",
++	0,
++	MS_FILTER_AUDIO_IO,
++	ms_oss_read_new,
++	NULL
++};
++
++static MSOssReadClass *msossreadclass=NULL;
++
++MSFilter * ms_oss_read_new()
++{
++	MSOssRead *w;
++	
++	if (msossreadclass==NULL)
++	{
++		msossreadclass=g_new(MSOssReadClass,1);
++		ms_oss_read_class_init( msossreadclass );
++	}
++	
++	w=g_new(MSOssRead,1);
++	MS_FILTER(w)->klass=MS_FILTER_CLASS(msossreadclass);
++	ms_oss_read_init(w);
++	
++	return(MS_FILTER(w));
++}
++
++/* FOR INTERNAL USE*/
++void ms_oss_read_init(MSOssRead *w)
++{
++	ms_sound_read_init(MS_SOUND_READ(w));
++	MS_FILTER(w)->outfifos=w->f_outputs;
++	MS_FILTER(w)->outfifos[0]=NULL;
++	w->devid=0;
++	w->sndcard=NULL;
++	w->freq=8000;
++}
++	
++gint ms_oss_read_set_property(MSOssRead *f,MSFilterProperty prop, void *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			f->freq=((gint*)value)[0];
++		break;
++	}
++	return 0;
++}
++void ms_oss_read_class_init(MSOssReadClass *klass)
++{
++	ms_sound_read_class_init(MS_SOUND_READ_CLASS(klass));
++	MS_FILTER_CLASS(klass)->max_foutputs=1;  /* one fifo output only */
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_oss_read_setup;
++	MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_oss_read_stop;
++	MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_read_process;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_read_set_property;
++	MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_read_destroy;
++	MS_FILTER_CLASS(klass)->w_maxgran=MS_OSS_READ_MAX_GRAN;
++	MS_FILTER_CLASS(klass)->info=&oss_read_info;
++	MS_SOUND_READ_CLASS(klass)->set_device=(gint (*)(MSSoundRead*,gint))ms_oss_read_set_device;
++	MS_SOUND_READ_CLASS(klass)->start=(void (*)(MSSoundRead*))ms_oss_read_start;
++	MS_SOUND_READ_CLASS(klass)->stop=(void (*)(MSSoundRead*))ms_oss_read_stop;
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssRead");
++	/* //ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_CAN_SYNC|FILTER_IS_SOURCE);	 */
++}
++
++void ms_oss_read_destroy( MSOssRead *obj)
++{
++	g_free(obj);
++}
++
++void ms_oss_read_process(MSOssRead *f)
++{
++	MSFifo *fifo;
++	char *p;
++	fifo=f->f_outputs[0];
++	
++	g_return_if_fail(f->sndcard!=NULL);
++	g_return_if_fail(f->gran>0);
++	
++	if (snd_card_can_read(f->sndcard)){
++		int got;
++		ms_fifo_get_write_ptr(fifo,f->gran,(void**)&p);
++		g_return_if_fail(p!=NULL);
++		got=snd_card_read(f->sndcard,p,f->gran);
++		if (got>=0 && got!=f->gran) ms_fifo_update_write_ptr(fifo,got);
++	}		
++}
++
++
++void ms_oss_read_start(MSOssRead *r)
++{
++	g_return_if_fail(r->devid!=-1);
++	r->sndcard=snd_card_manager_get_card(snd_card_manager,r->devid);
++	g_return_if_fail(r->sndcard!=NULL);
++	/* open the device for an audio telephony signal with minimum latency */
++	snd_card_open_r(r->sndcard,16,0,r->freq);
++	r->gran=(512*r->freq)/8000;
++	
++}
++
++void ms_oss_read_stop(MSOssRead *w)
++{
++	g_return_if_fail(w->devid!=-1);
++	g_return_if_fail(w->sndcard!=NULL);
++	snd_card_close_r(w->sndcard);
++	w->sndcard=NULL;
++}
++
++
++void ms_oss_read_setup(MSOssRead *f, MSSync *sync)
++{
++	f->sync=sync;
++	ms_oss_read_start(f);
++}
++
++
++gint ms_oss_read_set_device(MSOssRead *r,gint devid)
++{
++	r->devid=devid;
++	return 0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c	(revision 586398)
+@@ -0,0 +1,132 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include <msAlawdec.h>
++#include <g711common.h>
++
++extern MSFilter * ms_ALAWencoder_new(void);
++
++MSCodecInfo ALAWinfo={
++	{
++		"ALAW codec",
++		0,
++		MS_FILTER_AUDIO_CODEC,
++		ms_ALAWencoder_new,
++		"This is the classic A-law codec. Good quality, but only usable with high speed network connections."
++	},
++	ms_ALAWencoder_new,
++	ms_ALAWdecoder_new,
++	320,
++	160,
++	64000,
++	8000,
++	8,
++	"PCMA",
++	1,
++	1,
++};
++
++static MSALAWDecoderClass *ms_ALAWdecoder_class=NULL;
++
++MSFilter * ms_ALAWdecoder_new(void)
++{
++	MSALAWDecoder *r;
++	
++	r=g_new(MSALAWDecoder,1);
++	ms_ALAWdecoder_init(r);
++	if (ms_ALAWdecoder_class==NULL)
++	{
++		ms_ALAWdecoder_class=g_new(MSALAWDecoderClass,1);
++		ms_ALAWdecoder_class_init(ms_ALAWdecoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWdecoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_ALAWdecoder_init(MSALAWDecoder *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->r_mingran=ALAW_DECODER_RMAXGRAN;
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
++	
++}
++
++void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWDecoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
++	MS_FILTER_CLASS(klass)->max_finputs=MSALAWDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSALAWDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=ALAW_DECODER_RMAXGRAN;
++	MS_FILTER_CLASS(klass)->w_maxgran=ALAW_DECODER_WMAXGRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWdecoder_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWdecoder_process;
++}
++	
++void ms_ALAWdecoder_process(MSALAWDecoder *r)
++{
++	MSFifo *fi,*fo;
++	int inlen,outlen;
++	gchar *s,*d;
++	int i;
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	/* this is the simplest process function design:
++	the filter declares a r_mingran of ALAW_DECODER_RMAXGRAN, so the mediastreamer's
++	scheduler will call the process function each time there is ALAW_DECODER_RMAXGRAN
++	bytes to read in the input fifo. If there is more, then it will call it several
++	time in order to the fifo to be completetly processed.
++	This is very simple, but not very efficient because of the multiple call function
++	of MSFilterProcessFunc that may happen.
++	The MSAlawEncoder implements another design; see it.
++	*/
++	
++	fi=r->f_inputs[0];
++	fo=r->f_outputs[0];
++	g_return_if_fail(fi!=NULL);
++	g_return_if_fail(fo!=NULL);
++	
++ 	inlen=ms_fifo_get_read_ptr(fi,ALAW_DECODER_RMAXGRAN,(void**)&s);
++	if (s==NULL) return;
++ 	outlen=ms_fifo_get_write_ptr(fo,ALAW_DECODER_WMAXGRAN,(void**)&d);
++ 	if (d!=NULL)
++ 	{
++ 		for(i=0;i<ALAW_DECODER_RMAXGRAN;i++)
++ 		{
++ 			((gint16*)d)[i]=alaw_to_s16( (unsigned char) s[i]);
++ 		}
++ 	}
++ 	else g_warning("MSALAWDecoder: Discarding samples !!");
++	
++}
++
++
++
++void ms_ALAWdecoder_destroy( MSALAWDecoder *obj)
++{
++	g_free(obj);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c	(revision 586398)
+@@ -0,0 +1,218 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <config.h>
++
++#ifdef HAVE_SPEEX
++
++#include "msspeexdec.h"
++
++#ifdef HAVE_GLIB
++#include <gmodule.h>
++#endif
++
++extern MSFilter * ms_speex_enc_new();
++
++MSCodecInfo speex_info=
++{
++	{
++		"Speex codec",
++		0,
++		MS_FILTER_AUDIO_CODEC,
++		ms_speex_dec_new,
++		"A high quality variable bit-rate codec from Jean Marc Valin and David Rowe."
++	},
++	ms_speex_enc_new,
++	ms_speex_dec_new,
++	0,		/*frame size */
++	0,
++	8000, /*minimal bitrate */
++	-1,	/* sampling frequency */
++	110,		/* payload type */
++	"speex",
++	1,
++	1
++};
++
++
++
++void ms_speex_codec_init()
++{
++
++	ms_filter_register(MS_FILTER_INFO(&speex_info));
++	/* //ms_filter_register(MS_FILTER_INFO(&speex_lbr_info)); */
++}
++
++#ifdef HAVE_GLIB
++gchar * g_module_check_init(GModule *module)
++{
++	ms_speex_codec_init();
++	
++	return NULL;
++}
++#else
++gchar * g_module_check_init()
++{
++	ms_speex_codec_init();
++	
++	return NULL;
++}
++#endif
++
++static MSSpeexDecClass * ms_speex_dec_class=NULL;
++/* //static MSSpeexDecClass * ms_speexnb_dec_class=NULL; */
++
++MSFilter * ms_speex_dec_new()
++{
++	MSSpeexDec *obj=g_new(MSSpeexDec,1);
++	
++	if (ms_speex_dec_class==NULL){
++		ms_speex_dec_class=g_new(MSSpeexDecClass,1);
++		ms_speex_dec_class_init(ms_speex_dec_class);
++	}
++	MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_dec_class);
++
++	ms_speex_dec_init(obj);
++	return MS_FILTER(obj);
++}
++
++void ms_speex_dec_init(MSSpeexDec *obj)
++{
++	ms_filter_init(MS_FILTER(obj));
++	obj->initialized=0;
++	MS_FILTER(obj)->outfifos=obj->outf;
++	MS_FILTER(obj)->inqueues=obj->inq;
++	obj->outf[0]=NULL;
++	obj->inq[0]=NULL;
++	obj->frequency=8000; /*default value */
++	
++}
++
++void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode)
++{
++	int pf=1;
++	
++	obj->speex_state=speex_decoder_init(mode);
++	speex_bits_init(&obj->bits);
++	/* enable the perceptual post filter */
++	speex_decoder_ctl(obj->speex_state,SPEEX_SET_PF, &pf);
++	
++	speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &obj->frame_size);
++	
++	obj->initialized=1;
++}
++
++int ms_speex_dec_set_property(MSSpeexDec *obj, MSFilterProperty prop, int *value)
++{
++	if (obj->initialized){
++		/* we are called when speex is running !! forbid that! */
++		ms_warning("ms_speex_dec_set_property: cannot call this function when running!");
++		return -1;
++	}
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			obj->frequency=value[0];
++		break;
++	}
++	return 0;
++}
++
++void ms_speex_dec_setup(MSSpeexDec *obj)
++{
++	const SpeexMode *mode;
++	g_message("Speex decoder setup: freq=%i",obj->frequency);
++	if ( obj->frequency< 16000) mode=&speex_nb_mode;
++	else mode=&speex_wb_mode;
++	ms_speex_dec_init_core(obj,mode);
++}
++
++void ms_speex_dec_unsetup(MSSpeexDec *obj)
++{
++	ms_speex_dec_uninit_core(obj);
++}
++
++void ms_speex_dec_class_init(MSSpeexDecClass *klass)
++{
++	gint frame_size=0;
++	
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	/* use the largest frame size to configure fifos */
++	speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_dec_process;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_dec_setup;
++	MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_dec_unsetup;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_dec_destroy;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_dec_set_property;
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexDecoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
++	MS_FILTER_CLASS(klass)->max_foutputs=1;
++	MS_FILTER_CLASS(klass)->max_qinputs=1;
++	MS_FILTER_CLASS(klass)->w_maxgran=frame_size*2;
++	ms_trace("ms_speex_dec_class_init: w_maxgran is %i.",MS_FILTER_CLASS(klass)->w_maxgran);
++}
++
++void ms_speex_dec_uninit_core(MSSpeexDec *obj)
++{
++	speex_decoder_destroy(obj->speex_state);
++	obj->initialized=0;
++}
++
++void ms_speex_dec_uninit(MSSpeexDec *obj)
++{
++	
++}
++
++void ms_speex_dec_destroy(MSSpeexDec *obj)
++{
++	ms_speex_dec_uninit(obj);
++	g_free(obj);
++}
++
++void ms_speex_dec_process(MSSpeexDec *obj)
++{
++	MSFifo *outf=obj->outf[0];
++	MSQueue *inq=obj->inq[0];
++	gint16 *output;
++	gint gran=obj->frame_size*2;
++	gint i;
++	MSMessage *m;
++	
++	g_return_if_fail(inq!=NULL);
++	g_return_if_fail(outf!=NULL);
++	
++	m=ms_queue_get(inq);
++	g_return_if_fail(m!=NULL);
++	speex_bits_reset(&obj->bits);
++	ms_fifo_get_write_ptr(outf,gran,(void**)&output);
++	g_return_if_fail(output!=NULL);
++	if (m->data!=NULL){
++		
++		speex_bits_read_from(&obj->bits,m->data,m->size);
++		/* decode */
++		speex_decode_int(obj->speex_state,&obj->bits,(short*)output);
++	}else{
++		/* we have a missing packet */
++		speex_decode_int(obj->speex_state,NULL,(short*)output);
++	}
++	ms_message_destroy(m);
++	
++}
++
++#endif  /* HAVE_SPEEX */
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c	(revision 586398)
+@@ -0,0 +1,315 @@
++/*
++  Copyright (C) 2005 Remko Troncon
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <stdio.h>
++#include <portaudio.h>
++#include <stdlib.h>
++
++#include "portaudiocard.h"
++#include "msossread.h"
++#include "msosswrite.h"
++
++// Settings
++#define BUFFER_SIZE 2048
++
++// PortAudio settings
++#define FRAMES_PER_BUFFER 256
++
++
++// -----------------------------------------------------------------------------
++
++int readBuffer(char* buffer, char** buffer_read_p, char*buffer_write, char* buffer_end, char* target_buffer, int target_len)
++{
++	char *end, *tmp, *buffer_read = *buffer_read_p;
++	size_t remaining, len;
++	int read = 0;
++	
++	// First phase
++	tmp = buffer_read + target_len;
++	if (buffer_write < buffer_read) {
++		if (tmp > buffer_end) {
++			end = buffer_end;
++			remaining = tmp - buffer_end;
++		}
++		else {
++			end = tmp;
++			remaining = 0;
++		}
++	}
++	else {
++		end = (tmp >= buffer_write ? buffer_write : tmp);
++		remaining = 0;
++	}
++	//printf("end: %p\n",end);
++
++	// Copy the data
++	len = end - buffer_read;
++	memcpy(target_buffer, buffer_read, len);
++	buffer_read += len;
++	target_buffer += len;
++	read += len;
++
++	// Second phase
++	if (remaining > 0) {
++		buffer_read = buffer;
++		tmp = buffer_read + remaining;
++		len = (tmp > buffer_write ? buffer_write : tmp) - buffer_read;
++		memcpy(target_buffer, buffer_read, len);
++		buffer_read += len;
++		read += len;
++	}
++
++	// Finish up
++	*buffer_read_p = buffer_read;
++
++	return read;
++}
++
++int writeBuffer(char* buffer, char* buffer_read, char** buffer_write_p, char* buffer_end, char* source_buffer, int source_len)
++{
++	char *end, *tmp, *buffer_write = *buffer_write_p;
++	size_t remaining, len;
++	int written = 0;
++
++	// First phase
++	tmp = buffer_write + source_len;
++	if (buffer_write >= buffer_read) {
++		if (tmp > buffer_end) {
++			end = buffer_end;
++			remaining = tmp - buffer_end;
++		}
++		else {
++			end = tmp;
++			remaining = 0;
++		}
++	}
++	else {
++		if (tmp > buffer_read) {
++			printf("Warning: Dropping frame(s) %p %p\n", tmp, buffer_read);
++			end = buffer_read;
++			remaining = 0;
++		}
++		else {
++			end = tmp;
++			remaining = 0;
++		}
++	}
++	
++	len = end - buffer_write;
++	memcpy(buffer_write, source_buffer, len);
++	buffer_write += len;
++	source_buffer += len;
++	written += len;
++	
++	// Second phase
++	if (remaining > 0) {
++		buffer_write = buffer;
++		tmp = buffer_write + remaining;
++		if (tmp > buffer_read) {
++			printf("Warning: Dropping frame(s) %p %p\n", tmp, buffer_read);
++			end = buffer_read;
++		}
++		else {
++			end = tmp;
++		}
++		
++		len = end - buffer_write;
++		memcpy(buffer_write, source_buffer, len);
++		buffer_write += len;
++		written += len;
++	}
++
++	// Finish up
++	*buffer_write_p = buffer_write;
++	return written;
++}
++
++// -----------------------------------------------------------------------------
++
++static int portAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *card_p )
++{
++	PortAudioCard* card = (PortAudioCard*) card_p;
++
++	size_t len = framesPerBuffer * Pa_GetSampleSize(paInt16); 
++	//printf("PA::readBuffer begin %p %p %p %p %d\n",card->out_buffer,card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, len);
++	readBuffer(card->out_buffer,&card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, outputBuffer, len);
++	//printf("PA::readBuffer end %p %p %p %p %d\n",card->out_buffer,card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, len);
++	writeBuffer(card->in_buffer,card->in_buffer_read,&card->in_buffer_write,card->in_buffer_end, inputBuffer, len);
++	return 0;
++}
++
++// -----------------------------------------------------------------------------
++
++int portaudio_card_probe(PortAudioCard *obj, int bits, int stereo, int rate)
++{
++	return FRAMES_PER_BUFFER * (SND_CARD(obj)->stereo ? 2 : 1) * Pa_GetSampleSize(paInt16);
++}
++
++
++int portaudio_card_open_r(PortAudioCard *obj,int bits,int stereo,int rate)
++{
++	fprintf(stderr,"Opening PortAudio card\n");
++
++	int err;
++	err = Pa_OpenDefaultStream(&obj->stream, 1, 1, paInt16, rate, FRAMES_PER_BUFFER, 0, portAudioCallback, obj);
++	if (err != paNoError) {
++		fprintf(stderr, "Error creating a PortAudio stream: %s\n", Pa_GetErrorText(err));
++		return -1;
++	}
++
++	err = Pa_StartStream(obj->stream);
++	if (err != paNoError) {
++		fprintf(stderr, "Error starting PortAudio stream: %s\n", Pa_GetErrorText(err));
++		Pa_CloseStream(obj->stream);
++		obj->stream = NULL;
++		return -1;
++	}
++
++	SND_CARD(obj)->bits = 16;
++	SND_CARD(obj)->stereo = 0;
++	SND_CARD(obj)->rate = rate;
++	// Should this be multiplied by Pa_GetMinNumBuffers(FRAMES_PER_BUFFER,sampleRate) ?
++	SND_CARD(obj)->bsize = FRAMES_PER_BUFFER * (SND_CARD(obj)->stereo ? 2 : 1) * Pa_GetSampleSize(paInt16);
++
++	return 0;
++
++}
++
++void portaudio_card_close_r(PortAudioCard *obj)
++{
++	fprintf(stderr, "Closing PortAudio card\n");
++	if (obj->stream) {
++		Pa_StopStream(obj->stream);
++		Pa_CloseStream(obj->stream);
++		obj->stream = NULL;
++	}
++}
++
++int portaudio_card_open_w(PortAudioCard *obj,int bits,int stereo,int rate)
++{
++}
++
++void portaudio_card_close_w(PortAudioCard *obj)
++{
++}
++
++void portaudio_card_destroy(PortAudioCard *obj)
++{
++	snd_card_uninit(SND_CARD(obj));
++	free(obj->in_buffer);
++	free(obj->out_buffer);
++}
++
++gboolean portaudio_card_can_read(PortAudioCard *obj)
++{
++	return obj->in_buffer_read != obj->in_buffer_write;
++}
++
++int portaudio_card_read(PortAudioCard *obj,char *buf,int size)
++{
++	//printf("read begin %p %p %p %p %d\n",obj->in_buffer,obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, size);
++	return readBuffer(obj->in_buffer,&obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, buf, size);
++	//printf("read end %p %p %p %p %d\n",obj->in_buffer,obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, size);
++}
++
++int portaudio_card_write(PortAudioCard *obj,char *buf,int size)
++{
++	//printf("writeBuffer begin %p %p %p %p %d\n",obj->out_buffer,obj->out_buffer_read,obj->out_buffer_write,obj->out_buffer_end, size);
++	return writeBuffer(obj->out_buffer,obj->out_buffer_read,&obj->out_buffer_write,obj->out_buffer_end, buf, size);
++	//printf("writeBuffer end %p %p %p %p %d\n",obj->out_buffer,obj->out_buffer_read,obj->out_buffer_write,obj->out_buffer_end, size);
++}
++
++void portaudio_card_set_level(PortAudioCard *obj,gint way,gint a)
++{
++}
++
++gint portaudio_card_get_level(PortAudioCard *obj,gint way)
++{
++	return 0;
++}
++
++void portaudio_card_set_source(PortAudioCard *obj,int source)
++{
++}
++
++MSFilter *portaudio_card_create_read_filter(PortAudioCard *card)
++{
++	MSFilter *f=ms_oss_read_new();
++	ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
++	return f;
++}
++
++MSFilter *portaudio_card_create_write_filter(PortAudioCard *card)
++{
++	MSFilter *f=ms_oss_write_new();
++	ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
++	return f;
++}
++
++
++SndCard* portaudio_card_new()
++{
++	// Basic stuff
++	PortAudioCard* obj= g_new0(PortAudioCard,1);
++	SndCard* base= SND_CARD(obj);
++	snd_card_init(base);
++	base->card_name=g_strdup_printf("PortAudio Card");
++	base->_probe=(SndCardOpenFunc)portaudio_card_probe;
++	base->_open_r=(SndCardOpenFunc)portaudio_card_open_r;
++	base->_open_w=(SndCardOpenFunc)portaudio_card_open_w;
++	base->_can_read=(SndCardPollFunc)portaudio_card_can_read;
++	base->_read=(SndCardIOFunc)portaudio_card_read;
++	base->_write=(SndCardIOFunc)portaudio_card_write;
++	base->_close_r=(SndCardCloseFunc)portaudio_card_close_r;
++	base->_close_w=(SndCardCloseFunc)portaudio_card_close_w;
++	base->_set_rec_source=(SndCardMixerSetRecSourceFunc)portaudio_card_set_source;
++	base->_set_level=(SndCardMixerSetLevelFunc)portaudio_card_set_level;
++	base->_get_level=(SndCardMixerGetLevelFunc)portaudio_card_get_level;
++	base->_destroy=(SndCardDestroyFunc)portaudio_card_destroy;
++	base->_create_read_filter=(SndCardCreateFilterFunc)portaudio_card_create_read_filter;
++	base->_create_write_filter=(SndCardCreateFilterFunc)portaudio_card_create_write_filter;
++
++	// Initialize stream
++	obj->stream = NULL;
++	
++	// Initialize buffers
++	obj->out_buffer = (char*) malloc(sizeof(char)*BUFFER_SIZE);
++	obj->out_buffer_read = obj->out_buffer_write = obj->out_buffer;
++	obj->out_buffer_end = obj->out_buffer + BUFFER_SIZE;
++	obj->in_buffer = (char*) malloc(sizeof(char)*BUFFER_SIZE);
++	obj->in_buffer_read = obj->in_buffer_write = obj->in_buffer;
++	obj->in_buffer_end = obj->in_buffer + BUFFER_SIZE;
++
++	return base;
++}
++
++gint portaudio_card_manager_init(SndCardManager *manager, gint tabindex)
++{
++	// Initialize portaudio lib
++	int err = Pa_Initialize();
++	if (err != paNoError) {
++		fprintf(stderr,"Error initializing PortAudio: %s\n",Pa_GetErrorText(err));
++		return 0;
++	}
++	
++	// Create new card
++	manager->cards[0]=portaudio_card_new();
++	manager->cards[0]->index=0;
++	
++	return 1;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c	(revision 586398)
+@@ -0,0 +1,130 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include <msMUlawdec.h>
++#include <g711common.h>
++
++extern MSFilter * ms_MULAWencoder_new(void);
++
++MSCodecInfo MULAWinfo={
++	{
++		"MULAW codec",
++		0,
++		MS_FILTER_AUDIO_CODEC,
++		ms_MULAWencoder_new,
++		"This is the classic Mu-law codec. Good quality, but only usable with high speed network connections."
++	},
++	ms_MULAWencoder_new,
++	ms_MULAWdecoder_new,
++	320,
++	160,
++	64000,
++	8000,
++	0,
++	"PCMU",
++	1,
++	1
++};
++
++static MSMULAWDecoderClass *ms_MULAWdecoder_class=NULL;
++
++MSFilter * ms_MULAWdecoder_new(void)
++{
++	MSMULAWDecoder *r;
++	
++	r=g_new(MSMULAWDecoder,1);
++	ms_MULAWdecoder_init(r);
++	if (ms_MULAWdecoder_class==NULL)
++	{
++		ms_MULAWdecoder_class=g_new(MSMULAWDecoderClass,1);
++		ms_MULAWdecoder_class_init(ms_MULAWdecoder_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWdecoder_class);
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_MULAWdecoder_init(MSMULAWDecoder *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->outfifos=r->f_outputs;
++	MS_FILTER(r)->r_mingran=MULAW_DECODER_RMAXGRAN;
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
++	memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
++	
++}
++
++void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWDecoder");
++	MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
++	MS_FILTER_CLASS(klass)->max_finputs=MSMULAWDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWDECODER_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=MULAW_DECODER_RMAXGRAN;
++	MS_FILTER_CLASS(klass)->w_maxgran=MULAW_DECODER_WMAXGRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWdecoder_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWdecoder_process;
++}
++	
++void ms_MULAWdecoder_process(MSMULAWDecoder *r)
++{
++	MSFifo *fi,*fo;
++	int inlen,outlen;
++	gchar *s,*d;
++	int i;
++	/* process output fifos, but there is only one for this class of filter*/
++	
++	/* this is the simplest process function design:
++	the filter declares a r_mingran of MULAW_DECODER_RMAXGRAN, so the mediastreamer's
++	scheduler will call the process function each time there is MULAW_DECODER_RMAXGRAN
++	bytes to read in the input fifo. If there is more, then it will call it several
++	time in order to the fifo to be completetly processed.
++	This is very simple, but not very efficient because of the multiple call function
++	of MSFilterProcessFunc that may happen.
++	The MSAlawEncoder implements another design; see it.
++	*/
++	
++	fi=r->f_inputs[0];
++	fo=r->f_outputs[0];
++	
++ 	inlen=ms_fifo_get_read_ptr(fi,MULAW_DECODER_RMAXGRAN,(void**)&s);
++	if (s==NULL) g_error("ms_MULAWdecoder_process: internal error.");
++ 	outlen=ms_fifo_get_write_ptr(fo,MULAW_DECODER_WMAXGRAN,(void**)&d);
++ 	if (d!=NULL)
++ 	{
++ 		for(i=0;i<MULAW_DECODER_RMAXGRAN;i++)
++ 		{
++ 			*((gint16*)d)=ulaw_to_s16( (unsigned char) s[i]);
++ 			d+=2;
++ 		}
++ 	}
++ 	else g_warning("MSMULAWDecoder: Discarding samples !!");
++}
++
++
++
++void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj)
++{
++	g_free(obj);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c	(revision 586398)
+@@ -0,0 +1,574 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++  JACK support
++  Copyright (C) 2004  Tobias Gehrig tobias at gehrig.tk
++*/
++
++#include "jackcard.h"
++
++#ifdef __JACK_ENABLED__
++
++#include "msossread.h"
++#include "msosswrite.h"
++
++#include <signal.h>
++
++#define READBUFFERSIZE 524288
++#define WRITEBUFFERSIZE 524288
++#define BSIZE 512
++
++/**
++ * jack_shutdown:
++ * @arg: 
++ * 
++ * This is the shutdown callback for this JACK application.
++ * It is called by JACK if the server ever shuts down or
++ * decides to disconnect the client.
++ * 
++ */
++void
++jack_shutdown (void *arg)
++{
++  JackCard* obj = (JackCard*) arg;
++
++  obj->jack_running = FALSE;
++  obj->jack_active = FALSE;
++  obj->read.port = NULL;
++  if (obj->read.open)
++    obj->read.init = TRUE;
++  obj->write.port = NULL;
++  if (obj->write.open)
++    obj->write.init = TRUE;
++}
++
++int samplerate(jack_nframes_t rate, void *arg)
++{
++  JackCard* obj = (JackCard*) arg;
++  int error;
++
++  obj->rate = rate;
++  if (obj->read.open) {
++    obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate;
++    obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
++    g_free(obj->read.data.data_in);
++    obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
++    if (obj->read.src_state)
++      if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0)
++	g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
++  }
++  if (obj->write.open) {
++    obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate;
++    obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
++    g_free(obj->write.data.data_out);
++    obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
++    if (obj->write.src_state) 
++      if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0)
++	g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
++  }
++  return 0;
++}
++
++/*
++ * The process callback for this JACK application.
++ * It is called by JACK at the appropriate times.
++ * @nframes : 
++ * @arg :
++ */
++int
++process (jack_nframes_t nframes, void *arg)
++{
++  JackCard* obj = (JackCard*) arg;
++  sample_t *out;
++  sample_t *in;
++  
++  if (obj->clear && !obj->write.can_process) {
++    out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
++    memset (out, 0, nframes * sizeof(sample_t));
++    obj->clear = FALSE;
++  }
++  
++  if (!obj->can_process)
++    return 0;
++
++  if(obj->read.can_process) {
++    in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes);
++    jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes);
++  }
++
++  if (obj->write.can_process) {
++    out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
++    memset (out, 0, nframes * sizeof(sample_t));
++    if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) {
++      obj->write.can_process = FALSE;
++      if (!obj->read.open)
++	obj->can_process = FALSE;
++      obj->clear = FALSE;
++      return 0;
++    }
++    jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes);
++  }
++  return 0;      
++}
++
++int jack_init(JackCard* obj)
++{
++  char* client_name;
++  int error;
++
++  if (!obj->jack_running) {
++    obj->client = NULL;
++    client_name = g_strdup_printf("linphone-%u", g_random_int());
++    if ((obj->client = jack_client_new (client_name)) == NULL) {
++      g_warning("cannot create jack client");
++      g_free(client_name);
++      return -1;
++    }
++    g_message("Found Jack Daemon");
++    g_free(client_name);
++    
++    /* tell the JACK server to call `process()' whenever
++       there is work to be done.
++    */
++    jack_set_process_callback (obj->client, process, obj);
++
++    /* tell the JACK server to call `jack_shutdown()' if
++       it ever shuts down, either entirely, or if it
++       just decides to stop calling us.
++    */
++    jack_on_shutdown (obj->client, jack_shutdown, obj);
++    jack_set_sample_rate_callback (obj->client, samplerate, obj);
++    obj->rate = jack_get_sample_rate (obj->client);
++    if (obj->rate == 0) {
++      g_warning ("rate is 0???");
++      if (jack_client_close(obj->client) != 0)
++	g_warning("could not close client");
++      return -1;
++    }
++    obj->buffer_size = jack_get_buffer_size(obj->client);
++    obj->jack_running = TRUE;
++  }
++
++  if (!obj->jack_active) {
++    if (jack_activate (obj->client)) {
++      g_warning("cannot activate jack client");
++      return -1;
++    } else obj->jack_active = TRUE;
++  }
++
++  if (obj->read.init) {
++    if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) {
++      g_warning("error while trying to register input port");
++      return -1;
++    }
++    if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
++      g_warning("Cannot find any physical capture ports\n");
++      jack_port_unregister(obj->client, obj->read.port);
++      obj->read.port = NULL;
++      return -1;
++    }
++    if (!jack_port_connected(obj->read.port))
++      if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) {
++	g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]);
++	if (error == EEXIST) g_warning("connection already made");
++	else {
++	  jack_port_unregister(obj->client, obj->read.port);
++	  obj->read.port = NULL;
++	  return -1;
++	}
++      }
++    obj->read.init = FALSE;
++  }
++
++  if (obj->write.init) {
++    if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) {
++      g_warning("error while trying to register output port");
++      return -1;
++    }
++    if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
++      g_warning("Cannot find any physical playback ports\n");
++      jack_port_unregister(obj->client, obj->write.port);
++      obj->write.port = NULL;
++      return -1;
++    }
++    if (!jack_port_connected(obj->write.port)) {
++      if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) {
++	g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]);
++	if (error == EEXIST) g_warning("connection already made");
++	else {
++	  jack_port_unregister(obj->client, obj->write.port);
++	  obj->write.port = NULL;
++	  return -1;
++	}
++      }
++      if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) {
++	g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]);
++	if (error == EEXIST) g_warning("connection already made");
++	else {
++	  jack_port_unregister(obj->client, obj->write.port);
++	  obj->write.port = NULL;
++	  return -1;
++	}
++      }
++    }
++    obj->write.init = FALSE;
++  }
++  return 0;
++}
++
++int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate)
++{
++  int channels = stereo + 1, bsize, error;
++  obj->read.init = TRUE;
++  if (jack_init(obj) != 0) return -1;
++
++  obj->read.rate = rate;
++  obj->sample_size = bits / 8;
++  obj->frame_size = channels * obj->sample_size;
++  bsize = BSIZE;
++  obj->read.frames = bsize / 2;
++  SND_CARD(obj)->bsize = bsize;
++  SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
++  obj->read.channels = channels;
++  if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL)
++    g_warning("Error while initializing the samplerate converter: %s", src_strerror(error));
++  obj->read.data.src_ratio = (double)rate / (double)obj->rate;
++  obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
++  obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
++  obj->read.data.data_out = malloc(obj->read.frames*sizeof(float));
++  obj->read.data.end_of_input = 0;
++  if (!obj->read.buffer)
++    obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE);
++  obj->read.can_process = TRUE;
++  obj->can_process = TRUE;
++  obj->read.open = TRUE;
++  obj->read.init = FALSE;
++  return 0;
++}
++
++int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate)
++{
++  int channels = stereo + 1, bsize, err;
++  obj->write.init = TRUE;
++  if (jack_init(obj) != 0) return -1;
++
++  obj->write.rate = rate;
++  obj->sample_size = bits / 8;
++  obj->frame_size = channels * obj->sample_size;
++  bsize = BSIZE;
++  obj->write.frames = bsize / 2;
++  SND_CARD(obj)->bsize = bsize;
++  SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
++  obj->write.channels = channels;
++  if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL)
++    g_warning("Error while initializing the samplerate converter: %s", src_strerror(err));
++  obj->write.data.src_ratio = (double)obj->rate / (double)rate;
++  obj->write.data.data_in = malloc(obj->write.frames*sizeof(float));
++  obj->write.data.end_of_input = 0;
++  obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
++  obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
++  if (!obj->write.buffer)
++    obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE);
++  obj->write.can_process = TRUE;
++  obj->can_process = TRUE;
++  obj->write.open = TRUE;
++  obj->write.init = FALSE;
++  return 0;
++}
++
++void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno)
++{
++}
++
++void jack_card_close_r(JackCard *obj)
++{
++  obj->read.open = FALSE;
++  obj->read.init = FALSE;
++  obj->read.can_process = FALSE;
++  if (!obj->write.open)
++    obj->can_process = FALSE;
++  if (obj->read.src_state)
++    obj->read.src_state = src_delete (obj->read.src_state);
++  g_free(obj->read.data.data_in);
++  g_free(obj->read.data.data_out);
++}
++
++void jack_card_close_w(JackCard *obj)
++{
++  obj->write.open = FALSE;
++  obj->write.init = FALSE;
++  obj->clear = TRUE;
++  if (!obj->jack_running) {
++    obj->write.can_process = FALSE;
++    obj->can_process = FALSE;
++  }
++  if (obj->write.src_state)
++    obj->write.src_state = src_delete (obj->write.src_state);
++  g_free(obj->write.data.data_in);
++  g_free(obj->write.data.data_out);
++}
++
++int jack_card_probe(JackCard *obj,int bits,int stereo,int rate)
++{
++  if (obj->jack_running) return BSIZE;
++  else if (jack_init(obj) == 0) return BSIZE;
++  else return -1;
++}
++
++void jack_card_destroy(JackCard *obj)
++{
++  if (obj->jack_running) jack_client_close (obj->client);
++  snd_card_uninit(SND_CARD(obj));
++  if (obj->read.buffer) {
++    jack_ringbuffer_free(obj->read.buffer);
++    obj->read.buffer = NULL;
++  }
++  if (obj->write.buffer) {
++    jack_ringbuffer_free(obj->write.buffer);
++    obj->write.buffer = NULL;
++  }
++  if (obj->read.phys_ports) {
++    g_free(obj->read.phys_ports);
++    obj->read.phys_ports = NULL;
++  }
++  if (obj->write.phys_ports) {
++    g_free(obj->write.phys_ports);
++    obj->write.phys_ports = NULL;
++  }
++}
++
++gboolean jack_card_can_read(JackCard *obj)
++{
++  g_return_val_if_fail(obj->read.buffer!=NULL,0);
++  if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE;
++  else return FALSE;
++}
++
++int jack_card_read(JackCard *obj,char *buf,int size)
++{
++  size_t bytes, can_read, i;
++  int error;
++  float norm, value;
++
++  g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1);
++  if (jack_init(obj) != 0) return -1;
++  size /= 2;
++  can_read = MIN(size, obj->read.frames);
++  //  can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer));
++  can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t);
++  obj->read.can_process = FALSE;
++  bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read);
++  obj->read.can_process = TRUE;
++  obj->read.data.input_frames = bytes / sizeof(sample_t);
++  can_read = MIN(size, obj->read.frames);
++  obj->read.data.output_frames = can_read;
++  if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0)
++    g_warning("error while samplerate conversion. error: %s", src_strerror(error));
++  norm = obj->read.level*obj->level*(float)0x8000;
++  for (i=0; i < obj->read.data.output_frames_gen; i++) {
++    value = obj->read.data.data_out[i]*norm;
++    if (value >= 32767.0) 
++      ((short*)buf)[i] = 32767;
++    else if (value <= -32768.0)
++      ((short*)buf)[i] = -32768;
++    else
++      ((short*)buf)[i] = (short)value;
++  }
++  bytes = obj->read.data.output_frames_gen * 2;
++  return bytes;
++}
++
++int jack_card_write(JackCard *obj,char *buf,int size)
++{
++  size_t bytes, can_write, i;
++  int error;
++  float norm;
++
++  g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1);
++  if (jack_init(obj) != 0) return -1;
++  size /= 2;
++  can_write = MIN(size, obj->write.frames);
++  norm = obj->write.level*obj->level/(float)0x8000;
++  for (i=0; i<can_write; i++) {
++    obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm;
++  }
++  obj->write.data.input_frames = can_write;
++  if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0)
++    g_warning("error while samplerate conversion. error: %s", src_strerror(error));
++  obj->write.can_process = FALSE;
++  bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen);
++  obj->write.can_process = TRUE;
++  return bytes;
++}
++
++void jack_card_set_level(JackCard *obj,gint way,gint a)
++{
++  switch(way){
++  case SND_CARD_LEVEL_GENERAL:
++    obj->level = (float)a / 100.0;
++    break;
++  case SND_CARD_LEVEL_INPUT:
++    obj->read.level = (float)a / 100.0;
++    break;
++  case SND_CARD_LEVEL_OUTPUT:
++    obj->write.level = (float)a / 100.0;
++    break;
++  default:
++    g_warning("jack_card_set_level: unsupported command.");
++  }
++}
++
++gint jack_card_get_level(JackCard *obj,gint way)
++{
++  gint value = 0;
++
++  switch(way){
++  case SND_CARD_LEVEL_GENERAL:
++    value = (gint)(obj->level*100.0);
++    break;
++  case SND_CARD_LEVEL_INPUT:
++    value = (gint)(obj->read.level*100.0);
++    break;
++  case SND_CARD_LEVEL_OUTPUT:
++    value = (gint)(obj->write.level*100.0);
++    break;
++  default:
++    g_warning("jack_card_get_level: unsupported command.");
++  }
++  return value;
++}
++
++void jack_card_set_source(JackCard *obj,int source)
++{
++}
++
++MSFilter *jack_card_create_read_filter(JackCard *card)
++{
++	MSFilter *f=ms_oss_read_new();
++	ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
++	return f;
++}
++
++MSFilter *jack_card_create_write_filter(JackCard *card)
++{
++	MSFilter *f=ms_oss_write_new();
++	ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
++	return f;
++}
++SndCard * jack_card_new(jack_client_t *client)
++{
++	JackCard * obj;
++	SndCard *base;
++
++	obj= g_new0(JackCard,1);
++
++	if (!client) return NULL;
++	obj->client = client;
++	obj->jack_running = TRUE;
++	obj->jack_active = FALSE;
++	obj->can_process = FALSE;
++	obj->clear = TRUE;
++	obj->write.can_process = FALSE;
++	obj->write.open = FALSE;
++	obj->write.init = TRUE;
++	obj->write.port = NULL;
++	obj->write.phys_ports = NULL;
++	obj->write.buffer = NULL;
++	obj->read.can_process = FALSE;
++	obj->read.open = FALSE;
++	obj->read.init = TRUE;
++	obj->read.port = NULL;
++	obj->read.phys_ports = NULL;
++	obj->read.buffer = NULL;
++
++	/* tell the JACK server to call `process()' whenever
++           there is work to be done.
++        */
++        jack_set_process_callback (client, process, obj);
++
++        /* tell the JACK server to call `jack_shutdown()' if
++           it ever shuts down, either entirely, or if it
++           just decides to stop calling us.
++        */
++        jack_on_shutdown (client, jack_shutdown, obj);
++
++	jack_set_sample_rate_callback (client, samplerate, obj);
++
++	obj->rate = jack_get_sample_rate (client);
++	obj->buffer_size = jack_get_buffer_size(obj->client);
++
++	jack_init(obj);
++	
++	base= SND_CARD(obj);
++	snd_card_init(base);
++	
++#ifdef HAVE_GLIB
++	base->card_name=g_strdup_printf("JACK client");
++#else
++	base->card_name=malloc(100);
++	snprintf(base->card_name, 100, "JACK client");
++#endif
++
++	base->_probe=(SndCardOpenFunc)jack_card_probe;
++	base->_open_r=(SndCardOpenFunc)jack_card_open_r;
++	base->_open_w=(SndCardOpenFunc)jack_card_open_w;
++	base->_can_read=(SndCardPollFunc)jack_card_can_read;
++	base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode;
++	base->_read=(SndCardIOFunc)jack_card_read;
++	base->_write=(SndCardIOFunc)jack_card_write;
++	base->_close_r=(SndCardCloseFunc)jack_card_close_r;
++	base->_close_w=(SndCardCloseFunc)jack_card_close_w;
++	base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source;
++	base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level;
++	base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level;
++	base->_destroy=(SndCardDestroyFunc)jack_card_destroy;
++	base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter;
++	base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter;
++	
++	obj->read.buffer=NULL;
++	obj->write.buffer=NULL;
++	obj->buffer_size = 0;
++	obj->level = 1.0;
++	obj->write.level = 1.0;
++	obj->read.level = 1.0;
++
++	return base;
++}
++
++
++gint jack_card_manager_init(SndCardManager *m, gint index)
++{
++  jack_client_t *client = NULL;
++  char* client_name;
++
++  client_name=g_strdup_printf("linphone-%u", g_random_int());
++  if ((client = jack_client_new (client_name))!= NULL)
++    {
++      g_message("Found Jack Daemon");
++      g_free(client_name);
++      m->cards[index]=jack_card_new(client);
++      m->cards[index]->index=index;
++      return 1;
++    } else {
++      g_free(client_name);
++      return 0;
++    }
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h	(revision 586398)
+@@ -0,0 +1,55 @@
++/*
++  Copyright (C) 2003  Robert W. Brewer <rbrewer at op.net>
++  
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSTRUESPEECHDECODER_H
++#define MSTRUESPEECHDECODER_H
++
++#include "msfilter.h"
++#include "mstruespeechencoder.h"
++
++
++
++typedef struct _MSTrueSpeechDecoder
++{
++    /* the MSTrueSpeechDecoder derives from MSFilter, so the MSFilter
++       object MUST be the first of the MSTrueSpeechDecoder object
++       in order for the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
++    MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
++    Win32Codec* codec;
++} MSTrueSpeechDecoder;
++
++typedef struct _MSTrueSpeechDecoderClass
++{
++	/* the MSTrueSpeechDecoder derives from MSFilter,
++           so the MSFilter class MUST be the first of the MSTrueSpechDecoder
++           class
++           in order for the class mechanism to work*/
++  MSFilterClass parent_class;
++  Win32CodecDriver* driver;
++} MSTrueSpeechDecoderClass;
++
++/* PUBLIC */
++#define MS_TRUESPEECHDECODER(filter) ((MSTrueSpechMDecoder*)(filter))
++#define MS_TRUESPEECHDECODER_CLASS(klass) ((MSTrueSpeechDecoderClass*)(klass))
++MSFilter * ms_truespeechdecoder_new(void);
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h	(revision 586398)
+@@ -0,0 +1,47 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++/* An implementation of SndCard : the OssCard */
++
++#ifndef OSS_CARD_H
++#define OSS_CARD_H
++
++#include "sndcard.h"
++
++#define OSS_CARD_BUFFERS 3
++struct _OssCard
++{
++	SndCard parent;
++	gchar *dev_name;            /* /dev/dsp0 for example */
++	gchar *mixdev_name;         /* /dev/mixer0 for example */
++	gint fd;   /* the file descriptor of the open soundcard, 0 if not open*/
++	gint ref;
++	gchar *readbuf;
++	gint readpos;
++	gchar *writebuf;
++	gint writepos; 
++};
++
++typedef struct _OssCard OssCard;
++	
++SndCard * oss_card_new(char *devname, char *mixdev_name);
++
++typedef OssCard HpuxSndCard;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h	(revision 586398)
+@@ -0,0 +1,77 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSOSSREAD_H
++#define MSOSSREAD_H
++
++#include "mssoundread.h"
++#include "sndcard.h"
++#include "mssync.h"
++
++
++/*this is the class that implements oss writing sink filter*/
++
++#define MS_OSS_READ_MAX_INPUTS  1 /* max output per filter*/
++
++#define MS_OSS_READ_MAX_GRAN (512*2) /* the maximum granularity*/
++
++struct _MSOssRead
++{
++	/* the MSOssRead derivates from MSSoundRead so the MSSoundRead object MUST be the first of the MSOssRead object
++       in order to the object mechanism to work*/
++	MSSoundRead filter;
++	MSFifo *f_outputs[MS_OSS_READ_MAX_INPUTS];
++	MSSync *sync;
++	SndCard *sndcard;
++	gint freq;
++	gint devid;  /* the sound device id it depends on*/
++	gint gran;
++	gint flags;
++#define START_REQUESTED 1
++#define STOP_REQUESTED  2
++};
++
++typedef struct _MSOssRead MSOssRead;
++
++struct _MSOssReadClass
++{
++	/* the MSOssRead derivates from MSSoundRead, so the MSSoundRead class MUST be the first of the MSOssRead class
++       in order to the class mechanism to work*/
++	MSSoundReadClass parent_class;
++};
++
++typedef struct _MSOssReadClass MSOssReadClass;
++
++/* PUBLIC */
++#define MS_OSS_READ(filter) ((MSOssRead*)(filter))
++#define MS_OSS_READ_CLASS(klass) ((MSOssReadClass*)(klass))
++MSFilter * ms_oss_read_new(void);
++gint ms_oss_read_set_device(MSOssRead *w,gint devid);
++void ms_oss_read_start(MSOssRead *w);
++void ms_oss_read_stop(MSOssRead *w);
++
++/* FOR INTERNAL USE*/
++void ms_oss_read_init(MSOssRead *r);
++void ms_oss_read_class_init(MSOssReadClass *klass);
++void ms_oss_read_destroy( MSOssRead *obj);
++void ms_oss_read_process(MSOssRead *f);
++void ms_oss_read_setup(MSOssRead *f, MSSync *sync);
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h	(revision 586398)
+@@ -0,0 +1,65 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSALAWDECODER_H
++#define MSALAWDECODER_H
++
++#include <msfilter.h>
++#include <mscodec.h>
++
++/*this is the class that implements a ALAWdecoder filter*/
++
++#define MSALAWDECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSALAWDecoder
++{
++    /* the MSALAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWDecoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSALAWDECODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSALAWDECODER_MAX_INPUTS];
++} MSALAWDecoder;
++
++typedef struct _MSALAWDecoderClass
++{
++	/* the MSALAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWDecoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSALAWDecoderClass;
++
++/* PUBLIC */
++#define MS_ALAWDECODER(filter) ((MSALAWDecoder*)(filter))
++#define MS_ALAWDECODER_CLASS(klass) ((MSALAWDecoderClass*)(klass))
++MSFilter * ms_ALAWdecoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_ALAWdecoder_init(MSALAWDecoder *r);
++void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass);
++void ms_ALAWdecoder_destroy( MSALAWDecoder *obj);
++void ms_ALAWdecoder_process(MSALAWDecoder *r);
++
++/* tuning parameters :*/
++#define ALAW_DECODER_WMAXGRAN 320
++#define ALAW_DECODER_RMAXGRAN 160
++
++extern MSCodecInfo ALAWinfo;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h	(revision 586398)
+@@ -0,0 +1,69 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSSPEEXDEC_H
++#define MSSPEEXDEC_H
++
++#include <mscodec.h>
++#include <speex.h>
++
++struct _MSSpeexDec
++{
++	MSFilter parent;
++	MSQueue *inq[1]; /* speex has an input q because it can be variable bit rate */
++	MSFifo *outf[1];	
++	void *speex_state;
++	SpeexBits bits;
++	int frequency;
++	int frame_size;
++	int initialized;
++};
++
++typedef struct _MSSpeexDec MSSpeexDec;
++	
++
++struct _MSSpeexDecClass
++{
++	MSFilterClass parent;
++};
++
++typedef struct _MSSpeexDecClass MSSpeexDecClass;
++
++
++#define MS_SPEEX_DEC(o)	((MSSpeexDec*)(o))
++#define MS_SPEEX_DEC_CLASS(o)	((MSSpeexDecClass*)(o))
++
++/* call this before if don't load the plugin dynamically */
++void ms_speex_codec_init();
++
++/* mediastreamer compliant constructor */
++MSFilter * ms_speex_dec_new();
++
++void ms_speex_dec_init(MSSpeexDec *obj);
++void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode);
++void ms_speex_dec_class_init(MSSpeexDecClass *klass);
++void ms_speex_dec_uninit(MSSpeexDec *obj);
++void ms_speex_dec_uninit_core(MSSpeexDec *obj);
++
++void ms_speex_dec_process(MSSpeexDec *obj);
++void ms_speex_dec_destroy(MSSpeexDec *obj);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h	(revision 586398)
+@@ -0,0 +1,35 @@
++/*
++  Copyright (C) 2005 Remko Troncon
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++/* An implementation of SndCard : the OssCard */
++
++#ifndef PORTAUDIO_CARD_H
++#define PORTAUDIO_CARD_H
++
++#include "sndcard.h"
++
++typedef struct _PortAudioCard
++{
++	SndCard parent;
++	PortAudioStream* stream;
++	char *out_buffer, *out_buffer_read, *out_buffer_write, *out_buffer_end;
++	char *in_buffer, *in_buffer_read, *in_buffer_write, *in_buffer_end;
++} PortAudioCard;
++
++gint portaudio_card_manager_init(SndCardManager *manager, gint tabindex);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSMULAWDECODER_H
++#define MSMULAWDECODER_H
++
++#include <msfilter.h>
++#include <mscodec.h>
++
++/*this is the class that implements a MULAWdecoder filter*/
++
++#define MSMULAWDECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSMULAWDecoder
++{
++    /* the MSMULAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWDecoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSMULAWDECODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSMULAWDECODER_MAX_INPUTS];
++} MSMULAWDecoder;
++
++typedef struct _MSMULAWDecoderClass
++{
++	/* the MSMULAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWDecoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSMULAWDecoderClass;
++
++/* PUBLIC */
++#define MS_MULAWDECODER(filter) ((MSMULAWDecoder*)(filter))
++#define MS_MULAWDECODER_CLASS(klass) ((MSMULAWDecoderClass*)(klass))
++MSFilter * ms_MULAWdecoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_MULAWdecoder_init(MSMULAWDecoder *r);
++void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass);
++void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj);
++void ms_MULAWdecoder_process(MSMULAWDecoder *r);
++
++/* tuning parameters :*/
++#define MULAW_DECODER_WMAXGRAN 320
++#define MULAW_DECODER_RMAXGRAN 160
++
++extern MSCodecInfo MULAWinfo;
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++  JACK support
++  Copyright (C) 2004  Tobias Gehrig tobias at gehrig.tk
++*/
++
++#ifndef JACK_CARD_H
++#define JACK_CARD_H
++
++#include <config.h>
++
++#ifdef __JACK_ENABLED__
++
++#include "sndcard.h"
++
++#include <jack/jack.h>
++#include <jack/ringbuffer.h>
++
++#include <samplerate.h>
++
++typedef jack_default_audio_sample_t sample_t;
++
++typedef struct {
++  jack_port_t *port;
++  const char **phys_ports;
++  float level;
++  jack_ringbuffer_t *buffer;
++  gint channels;
++  gint rate;
++  SRC_STATE* src_state;
++  SRC_DATA data;
++  size_t frames;
++  gboolean can_process;
++  gboolean open;
++  gboolean init;
++} jackcard_mode_t;
++
++struct _JackCard
++{
++  SndCard parent;
++
++  jack_client_t *client;
++  gboolean jack_running;
++  gboolean jack_active;
++  float level;
++  jack_nframes_t buffer_size;
++  gint sample_size;
++  gint frame_size;
++  gint rate;
++  gboolean can_process;
++  gboolean clear;
++
++  jackcard_mode_t read, write;
++};
++
++typedef struct _JackCard JackCard;
++
++SndCard * jack_card_new(jack_client_t *client);
++
++gint jack_card_manager_init(SndCardManager *m, gint index);
++
++#endif
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c	(revision 586398)
+@@ -0,0 +1,82 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "msnosync.h"
++
++static MSNoSyncClass *ms_nosync_class=NULL;
++
++void ms_nosync_init(MSNoSync *sync)
++{
++	ms_sync_init(MS_SYNC(sync));
++	MS_SYNC(sync)->attached_filters=sync->filters;
++	memset(sync->filters,0,MSNOSYNC_MAX_FILTERS*sizeof(MSFilter*));
++	MS_SYNC(sync)->samples_per_tick=160;
++	sync->started=0;
++}
++
++void ms_nosync_class_init(MSNoSyncClass *klass)
++{
++	ms_sync_class_init(MS_SYNC_CLASS(klass));
++	MS_SYNC_CLASS(klass)->max_filters=MSNOSYNC_MAX_FILTERS;
++	MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_nosync_synchronize;
++	MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_nosync_destroy;
++	/* no need to overload these function*/
++	MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
++	MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
++}
++
++void ms_nosync_destroy(MSNoSync *nosync)
++{
++	g_free(nosync);
++}
++
++/* the synchronization function that does nothing*/
++void ms_nosync_synchronize(MSNoSync *nosync)
++{
++	gint32 time;
++	if (nosync->started==0){
++		gettimeofday(&nosync->start,NULL);
++		nosync->started=1;
++	}
++	gettimeofday(&nosync->current,NULL);
++	MS_SYNC(nosync)->ticks++;
++	/* update the time, we are supposed to work at 8000 Hz */
++	time=((nosync->current.tv_sec-nosync->start.tv_sec)*1000) + 
++		((nosync->current.tv_usec-nosync->start.tv_usec)/1000);
++	MS_SYNC(nosync)->time=time;
++	return;
++}
++
++
++MSSync *ms_nosync_new()
++{
++	MSNoSync *nosync;
++	
++	nosync=g_malloc(sizeof(MSNoSync));
++	ms_nosync_init(nosync);
++	if (ms_nosync_class==NULL)
++	{
++		ms_nosync_class=g_new(MSNoSyncClass,1);
++		ms_nosync_class_init(ms_nosync_class);
++	}
++	MS_SYNC(nosync)->klass=MS_SYNC_CLASS(ms_nosync_class);
++	return(MS_SYNC(nosync));
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h	(revision 586398)
+@@ -0,0 +1,90 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSAVENCODER_H
++#define MSAVENCODER_H
++
++#include "msfilter.h"
++#include "mscodec.h"
++#include <avcodec.h>
++
++/*this is the class that implements a AVencoder filter*/
++
++#define MSAVENCODER_MAX_INPUTS  1 /* max output per filter*/
++#define MSAVENCODER_MAX_OUTPUTS 2
++
++struct _MSAVEncoder
++{
++    /* the MSAVEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVEncoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSQueue *q_inputs[MSAVENCODER_MAX_INPUTS];
++    MSQueue *q_outputs[MSAVENCODER_MAX_OUTPUTS];
++	AVCodec *av_codec;  /*the AVCodec from which this MSFilter is related */
++	AVCodecContext av_context;  /* the context of the AVCodec */
++	gint input_pix_fmt;
++	gint av_opened;
++	MSBuffer *comp_buf;
++	MSBuffer *yuv_buf;
++};
++
++typedef struct _MSAVEncoder MSAVEncoder;
++/* MSAVEncoder always outputs planar YUV and accept any incoming format you should setup using
++ ms_AVencoder_set_format() 
++q_outputs[0] is the compressed video stream output
++q_outputs[1] is a YUV planar buffer of the image it receives in input.
++*/
++
++
++struct _MSAVEncoderClass
++{
++	/* the MSAVEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVEncoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSAVEncoderClass MSAVEncoderClass;
++
++/* PUBLIC */
++#define MS_AVENCODER(filter) ((MSAVEncoder*)(filter))
++#define MS_AVENCODER_CLASS(klass) ((MSAVEncoderClass*)(klass))
++
++MSFilter *ms_h263_encoder_new();
++MSFilter *ms_mpeg_encoder_new();
++MSFilter *ms_mpeg4_encoder_new();
++MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info);
++
++gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt);
++
++#define ms_AVencoder_set_width(av,w)	(av)->av_context.width=(w)
++#define ms_AVencoder_set_height(av,h)	(av)->av_context.height=(h)
++#define ms_AVencoder_set_bit_rate(av,r)		(av)->av_context.bit_rate=(r)
++
++void ms_AVencoder_set_frame_rate(MSAVEncoder *enc, gint frame_rate, gint frame_rate_base);
++
++/* FOR INTERNAL USE*/
++void ms_AVencoder_init(MSAVEncoder *r, AVCodec *codec);
++void ms_AVencoder_uninit(MSAVEncoder *enc);
++void ms_AVencoder_class_init(MSAVEncoderClass *klass);
++void ms_AVencoder_destroy( MSAVEncoder *obj);
++void ms_AVencoder_process(MSAVEncoder *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c	(revision 586398)
+@@ -0,0 +1,246 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msringplayer.h"
++#include "mssync.h"
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <string.h>
++#include <errno.h>
++
++#include "waveheader.h"
++
++#define WAVE_HEADER_OFFSET sizeof(wave_header_t)
++
++enum { PLAY_RING, PLAY_SILENCE};
++
++static int supported_freq[6]={8000,11025,16000,22050,32000,44100};
++
++gint freq_is_supported(gint freq){
++	int i;
++	for (i=0;i<6;i++){
++		if (abs(supported_freq[i]-freq)<50) return supported_freq[i];
++	}
++	return 0;
++}
++
++static MSRingPlayerClass *ms_ring_player_class=NULL;
++
++/**
++ * ms_ring_player_new:
++ * @name:  The path to the 16-bit 8khz raw file to be played as a ring.
++ * @seconds: The number of seconds that separates two rings.
++ *
++ * Allocates a new MSRingPlayer object.
++ *
++ *
++ * Returns: a pointer the the object, NULL if name could not be open.
++ */
++MSFilter * ms_ring_player_new(char *name, gint seconds)
++{
++	MSRingPlayer *r;
++	int fd=-1;
++	
++	if ((name!=NULL) && (strlen(name)!=0))
++	{
++		fd=open(name,O_RDONLY);
++		if (fd<0) 
++		{
++			g_warning("ms_ring_player_new: failed to open %s.\n",name);
++			return NULL;
++		}
++		
++	}else {
++		g_warning("ms_ring_player_new: Bad file name");
++		return NULL;
++	}
++	
++	r=g_new(MSRingPlayer,1);
++	ms_ring_player_init(r);
++	if (ms_ring_player_class==NULL)
++	{
++		ms_ring_player_class=g_new(MSRingPlayerClass,1);
++		ms_ring_player_class_init(ms_ring_player_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ring_player_class);
++	
++	r->fd=fd;
++	r->silence=seconds;
++	r->freq=8000;
++	if (strstr(name,".wav")!=NULL){
++		wave_header_t header;
++		int freq,freq2;
++		/* read the header */
++		read(fd,&header,sizeof(wave_header_t));
++		freq=wave_header_get_rate(&header);
++		if ((freq2=freq_is_supported(freq))>0){
++			r->freq=freq2;
++		}else {
++			g_warning("Unsupported sampling rate %i",freq);
++			r->freq=8000;
++		}
++		r->channel=wave_header_get_channel(&header);
++		lseek(fd,WAVE_HEADER_OFFSET,SEEK_SET);
++#ifdef WORDS_BIGENDIAN
++		r->need_swap=1;	
++#else
++		r->need_swap=0;
++#endif
++	}
++	ms_ring_player_set_property(r, MS_FILTER_PROPERTY_FREQ,&r->freq);
++	r->state=PLAY_RING;
++	return(MS_FILTER(r));
++}
++	
++
++/* FOR INTERNAL USE*/
++void ms_ring_player_init(MSRingPlayer *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->outfifos=r->foutputs;
++	MS_FILTER(r)->outqueues=r->qoutputs;
++	memset(r->foutputs,0,sizeof(MSFifo*)*MS_RING_PLAYER_MAX_OUTPUTS);
++	memset(r->qoutputs,0,sizeof(MSQueue*)*MS_RING_PLAYER_MAX_OUTPUTS);
++	r->fd=-1;
++	r->current_pos=0;
++	r->need_swap=0;
++	r->sync=NULL;
++}
++
++gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			f->rate=((gint*)value)[0]*2;
++			f->silence_bytes=f->silence*f->rate;
++			if (f->sync!=NULL)
++				f->gran=(f->rate*f->sync->interval/1000)*2;
++		break;
++	}
++	return 0;
++}
++
++gint ms_ring_player_get_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
++{
++	switch(prop){
++		case MS_FILTER_PROPERTY_FREQ:
++			((gint*)value)[0]=f->freq;
++			
++		break;
++		case MS_FILTER_PROPERTY_CHANNELS:
++			((gint*)value)[0]=f->channel;
++		break;
++	}
++	return 0;
++}
++
++gint ms_ring_player_get_sample_freq(MSRingPlayer *obj){
++	return obj->freq;
++}
++
++
++void ms_ring_player_class_init(MSRingPlayerClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ringplay");
++	ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
++	MS_FILTER_CLASS(klass)->max_foutputs=MS_RING_PLAYER_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->max_qoutputs=MS_RING_PLAYER_MAX_OUTPUTS;
++	MS_FILTER_CLASS(klass)->w_maxgran=MS_RING_PLAYER_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ring_player_setup;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ring_player_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ring_player_process;
++	MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ring_player_set_property;
++	MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ring_player_get_property;
++}
++	
++void ms_ring_player_process(MSRingPlayer *r)
++{
++	MSFifo *f;
++	gint err;
++	gint processed=0;
++	gint gran=r->gran;
++	char *p;
++	
++	g_return_if_fail(gran>0);
++	/* process output fifos*/
++	
++	f=r->foutputs[0];
++	ms_fifo_get_write_ptr(f,gran,(void**)&p);
++	g_return_if_fail(p!=NULL);
++	for (processed=0;processed<gran;){
++		switch(r->state){
++			case PLAY_RING:
++				err=read(r->fd,&p[processed],gran-processed);
++				if (err<0)
++				{
++					memset(&p[processed],0,gran-processed);
++					processed=gran;
++					g_warning("ms_ring_player_process: failed to read: %s.\n",strerror(errno));
++					return;
++				}
++				else if (err<gran)
++				{/* end of file */
++					
++					r->current_pos=r->silence_bytes;
++					lseek(r->fd,WAVE_HEADER_OFFSET,SEEK_SET);
++					r->state=PLAY_SILENCE;
++          ms_filter_notify_event(MS_FILTER(r),MS_RING_PLAYER_END_OF_RING_EVENT,NULL);
++				}
++				if (r->need_swap) swap_buffer(&p[processed],err);
++				processed+=err;
++			break;
++			case PLAY_SILENCE:
++				err=gran-processed;
++				if  (r->current_pos>err){
++					memset(&p[processed],0,err);
++					r->current_pos-=gran;
++					processed=gran;
++				}else{
++					memset(&p[processed],0,r->current_pos);
++					processed+=r->current_pos;
++					r->state=PLAY_RING;
++				}
++			break;
++		}
++	}
++}
++
++/**
++ * ms_ring_player_destroy:
++ * @obj: A valid MSRingPlayer object.
++ *
++ * Destroy a MSRingPlayer object.
++ *
++ *
++ */
++
++void ms_ring_player_destroy( MSRingPlayer *obj)
++{
++	if (obj->fd!=0) close(obj->fd);
++	g_free(obj);
++}
++
++void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync)
++{
++	r->sync=sync;
++	r->gran=(r->rate*r->sync->interval/1000)*r->channel;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h	(revision 586398)
+@@ -0,0 +1,60 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "mssync.h"
++
++#include <sys/time.h>
++#define MSNOSYNC_MAX_FILTERS 10
++
++/* MSNoSync derivates from MSSync base class*/
++
++typedef struct _MSNoSync
++{
++	/* the MSSync must be the first field of the object in order to the object mechanism to work*/
++	MSSync  sync;
++	MSFilter *filters[MSNOSYNC_MAX_FILTERS];
++	int started;
++	struct timeval start,current;
++} MSNoSync;
++
++
++typedef struct _MSNoSyncClass
++{
++	/* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
++	MSSyncClass parent_class;
++} MSNoSyncClass;
++
++
++/*private*/
++
++void ms_nosync_init(MSNoSync *sync);
++void ms_nosync_class_init(MSNoSyncClass *sync);
++
++void ms_nosync_destroy(MSNoSync *nosync);
++void ms_nosync_synchronize(MSNoSync *nosync);
++
++/*public*/
++
++/* casts a MSSync object into a MSNoSync */
++#define MS_NOSYNC(sync) ((MSNoSync*)(sync))
++/* casts a MSSync class into a MSNoSync class */
++#define MS_NOSYNC_CLASS(klass) ((MSNoSyncClass*)(klass))
++
++MSSync *ms_nosync_new();
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c	(revision 586398)
+@@ -0,0 +1,342 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include "ms.h"
++#include "sndcard.h"
++#include "mscodec.h"
++
++#include <sys/types.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#ifdef VIDEO_ENABLED
++extern void ms_video_source_register_all();
++#endif
++#ifdef HAVE_ILBC
++extern void ms_ilbc_codec_init();
++#endif
++
++/**
++ * ms_init:
++ *
++ *
++ * Initialize the mediastreamer. This must be the first function called in a program
++ * using the mediastreamer library.
++ *
++ *
++ */
++void ms_init()
++{
++	if (!g_thread_supported()) g_thread_init (NULL);
++#ifdef HAVE_GLIB
++	if (!g_module_supported()){
++		g_error("GModule is not supported.");
++	}
++#endif
++	/* initialize the oss subsystem */
++	snd_card_manager_init(snd_card_manager);
++	/* register the statically linked codecs */
++	ms_codec_register_all();
++#ifdef VIDEO_ENABLED
++	ms_video_source_register_all();
++#endif
++#ifdef HAVE_ILBC
++	ms_ilbc_codec_init();
++#endif
++}
++
++
++static gint compare(gconstpointer a, gconstpointer b)
++{
++	MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b;
++	if (f1->klass<f2->klass) return -1;
++	if (f1->klass==f2->klass) return 0;
++	/* if f1->klass>f2->klass ....*/
++	return 1;
++}
++
++static GList *g_list_append_if_new(GList *l,gpointer data)
++{
++	GList *res=l;
++	if (g_list_find(res,data)==NULL)
++		res=g_list_append(res,data);
++	return(res);
++}
++
++static GList *get_nexts(MSFilter *f,GList *l)
++{
++	int i;
++	MSFifo *fifo;
++	MSQueue *q;
++	GList *res=l;
++	
++	/* check fifos*/
++	for (i=0;i	<f->klass->max_foutputs;i++)
++	{
++		fifo=f->outfifos[i];
++		if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data);
++	}
++	/* check queues*/
++	for (i=0;i	<f->klass->max_qoutputs;i++)
++	{
++		q=f->outqueues[i];
++		if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data);
++	}
++	return(res);
++}
++	
++/* compile graphs attached to a sync source*/
++int ms_compile(MSSync *sync)
++{
++	int i;
++	GList *list1=NULL,*list2=NULL,*elem;
++	GList *proc_chain=NULL;
++	MSFilter *f;
++	
++	/* first free the old list if we are just updating*/
++	if (sync->execution_list!=NULL) g_list_free(sync->execution_list);
++	/* get the list of filters attached to this sync*/
++	for (i=0;i<sync->filters;i++)
++	{
++		/* //printf("found filter !\n"); */
++		list1=g_list_append(list1,sync->attached_filters[i]);
++	}
++	/* find the processing chain */
++	while (list1!=NULL)
++	{
++		list2=NULL;
++		/* sort the list by types of filter*/
++		list1=g_list_sort(list1,compare);
++		/* save into the processing chain list*/
++		/* //printf("list1 :%i elements\n",g_list_length(list1)); */
++		proc_chain=g_list_concat(proc_chain,list1);
++		/* get all following filters. They are appended to list2*/
++		elem=list1;
++		while (elem!=NULL)
++		{
++			f=(MSFilter*)(elem->data);
++			/* check if filter 's status */
++			if (f->klass->attributes & FILTER_CAN_SYNC)
++			{
++				sync->samples_per_tick=0;
++			}
++			list2=get_nexts(f,list2);
++			elem=g_list_next(elem);
++		}
++		list1=list2;
++	}
++	sync->execution_list=proc_chain;
++	sync->flags&=~MS_SYNC_NEED_UPDATE;
++	ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list));
++	return 0;
++}
++
++/*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/
++void *ms_thread_run(void *sync_ptr)
++{
++	MSSync *sync=(MSSync*) sync_ptr;
++	GList *filter;
++	MSFilter *f;
++	
++	
++	ms_sync_lock(sync);  
++	while(sync->run)
++	{
++		/* //g_message("sync->run=%i",sync->run); */
++		if (sync->samples_per_tick==0) ms_sync_suspend(sync);
++		if (sync->flags & MS_SYNC_NEED_UPDATE){
++			ms_compile(sync);
++			ms_sync_setup(sync);
++		}
++		filter=sync->execution_list;
++		ms_sync_unlock(sync);
++		/* //ms_trace("Calling synchronisation"); */
++		ms_sync_synchronize(sync);
++		while(filter!=NULL)
++		{
++			f=(MSFilter*)filter->data;
++			if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE)
++			{
++				/* execute it once */
++				ms_trace("Running source filter %s.",f->klass->name);
++				ms_filter_process(f);
++			}
++			else
++			{
++				/* make the filter process its input data until it has no more */
++				while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) )
++				{
++					ms_trace("Running filter %s.",f->klass->name);
++					ms_filter_process(f);
++				}
++			}
++			filter=g_list_next(filter);
++		}
++		ms_sync_lock(sync);  
++	}
++	g_cond_signal(sync->stop_cond);	/* signal that the sync thread has finished */
++	ms_sync_unlock(sync);
++	g_message("Mediastreamer processing thread is exiting.");
++	return NULL;
++}
++
++/* stop the processing chain attached to a sync source.*/
++void ms_thread_stop(MSSync *sync)
++{
++	if (sync->thread!=NULL)
++	{
++		if (sync->samples_per_tick==0)
++		{
++			/* to wakeup the thread */
++			/* //g_cond_signal(sync->thread_cond); */
++		}
++		g_mutex_lock(sync->lock);
++		sync->run=0;
++		sync->thread=NULL;
++		g_cond_wait(sync->stop_cond,sync->lock);
++		g_mutex_unlock(sync->lock);
++	}
++	/* //g_message("ms_thread_stop() finished."); */
++}
++
++/**
++ * ms_start:
++ * @sync: A synchronisation source to be started.
++ *
++ * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
++ *
++ *
++ */
++void ms_start(MSSync *sync)
++{
++	if (sync->run==1) return; /*already running*/
++	ms_compile(sync);  
++	ms_sync_setup(sync);
++	/* this is to avoid race conditions, for example:
++							ms_start(sync);
++							ms_oss_write_start(ossw);
++							here tge ossw filter need to be compiled to run ms_oss_write_start()
++							*/
++	ms_trace("ms_start: creating new thread.");
++	sync->run=1;
++	sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL);
++	if (sync->thread==NULL){
++		g_warning("Could not create thread !");
++	}
++}
++
++/**
++ * ms_stop:
++ * @sync: A synchronisation source to be stopped.
++ *
++ * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
++ * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
++ *
++ *
++ */
++void ms_stop(MSSync *sync)
++{
++	ms_thread_stop(sync);
++	ms_sync_unsetup(sync);
++}
++
++
++gint ms_load_plugin(gchar *path)
++{
++#ifdef HAVE_GLIB
++	g_module_open(path,0);
++#endif
++	return 0;
++}
++
++gchar * ms_proc_get_param(gchar *parameter)
++{
++	gchar *file;
++	int fd;
++	int err,len;
++	gchar *p,*begin,*end;
++	gchar *ret;
++	fd=open("/proc/cpuinfo",O_RDONLY);
++	if (fd<0){
++		g_warning("Could not open /proc/cpuinfo.");
++		return NULL;
++	}
++	file=g_malloc(1024);
++	err=read(fd,file,1024);
++	file[err-1]='\0';
++	/* find the parameter */
++	p=strstr(file,parameter);
++	if (p==NULL){
++		/* parameter not found */
++		g_free(file);
++		return NULL;		
++	}
++	/* find the following ':' */
++	p=strchr(p,':');
++	if (p==NULL){
++		g_free(file);
++		return NULL;
++	}
++	/* find the value*/
++	begin=p+2;
++	end=strchr(begin,'\n');
++	if (end==NULL) end=strchr(begin,'\0');
++	len=end-begin+1;
++	ret=g_malloc(len+1);
++	snprintf(ret,len,"%s",begin);
++	/* //printf("%s=%s\n",parameter,ret); */
++	g_free(file);
++	return ret;
++}
++
++gint ms_proc_get_type()
++{
++	static int proc_type=0;
++	gchar *value;
++	if (proc_type==0){
++		value=ms_proc_get_param("cpu family");
++		if (value!=NULL) {
++			proc_type=atoi(value);
++			g_free(value);
++		}else return -1;
++	}
++	return proc_type;
++}
++
++gint ms_proc_get_speed()
++{
++	char *value;
++	static int proc_speed=0;
++	if (proc_speed==0){
++		value=ms_proc_get_param("cpu MHz");
++		if (value!=NULL){
++			proc_speed=atoi(value);
++			g_free(value);
++		}else return -1;
++	}
++	/* //printf("proc_speed=%i\n",proc_speed); */
++	return proc_speed;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h	(revision 586398)
+@@ -0,0 +1,111 @@
++/*
++linphone
++Copyright (C) 2000  Simon MORLAT (simon.morlat at free.fr)
++
++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.
++
++This program is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this program; if not, write to the Free Software
++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++*/
++
++/* the following code was taken from a free software utility that I don't remember the name. */
++/* sorry */
++
++
++
++#include <ms.h>
++#ifndef waveheader_h
++#define waveheader_h
++
++typedef struct uint16scheme
++{
++    unsigned char lo_byte;
++    unsigned char hi_byte;
++} uint16scheme_t;
++
++typedef struct uint32scheme
++{
++    guint16 lo_int;
++    guint16 hi_int;
++} uint32scheme_t;
++
++
++/* all integer in wav header must be read in least endian order */
++inline guint16 _readuint16(guint16 a)
++{
++    guint16 res;
++    uint16scheme_t *tmp1=(uint16scheme_t*)&a;
++
++    ((uint16scheme_t *)(&res))->lo_byte=tmp1->hi_byte;
++    ((uint16scheme_t *)(&res))->hi_byte=tmp1->lo_byte;
++    return res;
++}
++
++inline guint32 _readuint32(guint32 a)
++{
++    guint32 res;
++    uint32scheme_t *tmp1=(uint32scheme_t*)&a;
++
++    ((uint32scheme_t *)(&res))->lo_int=_readuint16(tmp1->hi_int);
++    ((uint32scheme_t *)(&res))->hi_int=_readuint16(tmp1->lo_int);
++    return res;
++}
++
++#ifdef WORDS_BIGENDIAN
++#define le_uint32(a) (_readuint32((a)))
++#define le_uint16(a) (_readuint16((a)))
++#define le_int16(a) ( (gint16) _readuint16((guint16)((a))) )
++#else
++#define le_uint32(a) (a)
++#define le_uint16(a) (a)
++#define le_int16(a) (a)
++#endif
++
++typedef struct _riff_t {
++	char riff[4] ;	/* "RIFF" (ASCII characters) */
++	guint32  len ;	/* Length of package (binary, little endian) */
++	char wave[4] ;	/* "WAVE" (ASCII characters) */
++} riff_t;
++
++/* The FORMAT chunk */
++
++typedef struct _format_t {
++	char  fmt[4] ;	/* "fmt_" (ASCII characters) */
++	guint32   len ;	/* length of FORMAT chunk (always 0x10) */
++	guint16 que ;	/* Always 0x01 */
++	guint16 channel ;	/* Channel numbers (0x01 = mono, 0x02 = stereo) */
++	guint32   rate ;	/* Sample rate (binary, in Hz) */
++	guint32   bps ;	/* Bytes Per Second */
++	guint16 bpsmpl ;	/* bytes per sample: 1 = 8 bit Mono,
++					     2 = 8 bit Stereo/16 bit Mono,
++					     4 = 16 bit Stereo */
++	guint16 bitpspl ;	/* bits per sample */
++} format_t;
++
++/* The DATA chunk */
++
++typedef struct _data_t {
++	char data[4] ;	/* "data" (ASCII characters) */
++	int  len ;	/* length of data */
++} data_t;
++
++typedef struct _wave_header_t
++{
++	riff_t riff_chunk;
++	format_t format_chunk;
++	data_t data_chunk;
++} wave_header_t;
++
++#define wave_header_get_rate(header)		le_uint32((header)->format_chunk.rate)
++#define wave_header_get_channel(header)		le_uint16((header)->format_chunk.channel)
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSRINGPLAYER_H
++#define MSRINGPLAYER_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++
++/*this is the class that implements file reading source filter*/
++
++#define MS_RING_PLAYER_MAX_OUTPUTS  1 /* max output per filter*/
++
++#define MS_RING_PLAYER_DEF_GRAN 8192 /* the default granularity*/
++
++#define MS_RING_PLAYER_END_OF_RING_EVENT 1
++
++struct _MSRingPlayer
++{
++	/* the MSRingPlayer derivates from MSFilter, so the MSFilter object MUST be the first of the MSRingPlayer object
++	in order to the object mechanism to work*/
++	MSFilter filter;
++	MSFifo *foutputs[MS_RING_PLAYER_MAX_OUTPUTS];
++	MSQueue *qoutputs[MS_RING_PLAYER_MAX_OUTPUTS];\
++	MSSync *sync;
++	gint gran;
++	gint freq;
++	gint rate;
++	gint channel;	/* number of interleaved channels */
++	gint silence;	/* silence time between each ring, in seconds */
++	gint state;
++	gint fd;  /* the file descriptor of the file being read*/
++	gint silence_bytes; /*silence in number of bytes between each ring */
++	gint current_pos;
++	gint need_swap;
++};
++
++typedef struct _MSRingPlayer MSRingPlayer;
++
++struct _MSRingPlayerClass
++{
++	/* the MSRingPlayer derivates from MSFilter, so the MSFilter class MUST be the first of the MSRingPlayer class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSRingPlayerClass MSRingPlayerClass;
++
++/* PUBLIC */
++#define MS_RING_PLAYER(filter) ((MSRingPlayer*)(filter))
++#define MS_RING_PLAYER_CLASS(klass) ((MSRingPlayerClass*)(klass))
++MSFilter * ms_ring_player_new(char *name, gint seconds);
++gint ms_ring_player_get_sample_freq(MSRingPlayer *obj);
++
++
++/* FOR INTERNAL USE*/
++void ms_ring_player_init(MSRingPlayer *r);
++void ms_ring_player_class_init(MSRingPlayerClass *klass);
++void ms_ring_player_destroy( MSRingPlayer *obj);
++void ms_ring_player_process(MSRingPlayer *r);
++#define ms_ring_player_set_bufsize(filter,sz) (filter)->gran=(sz)
++void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync);
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++
++#ifndef MS_H
++#define MS_H
++#include "msfilter.h"
++#include "mssync.h"
++
++
++void ms_init();
++
++/* compile graphs attached to a sync source*/
++int ms_compile(MSSync *source);
++
++
++/* stop the processing chain attached to a sync source.*/
++void ms_thread_stop(MSSync *sync);
++
++
++/**
++ * function_name:ms_thread_run
++ * @sync:  The synchronization source for all the set of graphs to run.
++ *
++ * Execute the processing chain attached to a sync source. This function loops indefinitely.
++ * The media streamer programmer can choose to execute this function directly, or to call ms_start(),
++ * that will start a thread for the synchronisation source.
++ *
++ * Returns: no return value.
++ */
++void *ms_thread_run(void *sync);
++
++
++/**
++ * function_name:ms_start
++ * @sync: A synchronisation source to be started.
++ *
++ * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
++ *
++ * Returns: no return value.
++ */
++void ms_start(MSSync *sync);
++
++
++/**
++ * function_name:ms_stop
++ * @sync: A synchronisation source to be stopped.
++ *
++ * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
++ * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
++ *
++ * Returns: no return value.
++ */
++void ms_stop(MSSync *sync);
++
++
++gchar * ms_proc_get_param(gchar *parameter);
++gint ms_proc_get_type();
++gint ms_proc_get_speed();
++
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSGSMENCODER_H
++#define MSGSMENCODER_H
++
++#include "msfilter.h"
++#include <gsm.h>
++
++/*this is the class that implements a GSMencoder filter*/
++
++#define MSGSMENCODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSGSMEncoder
++{
++    /* the MSGSMEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMEncoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSGSMENCODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSGSMENCODER_MAX_INPUTS];
++    gsm gsm_handle;
++} MSGSMEncoder;
++
++typedef struct _MSGSMEncoderClass
++{
++	/* the MSGSMEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMEncoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSGSMEncoderClass;
++
++/* PUBLIC */
++#define MS_GSMENCODER(filter) ((MSGSMEncoder*)(filter))
++#define MS_GSMENCODER_CLASS(klass) ((MSGSMEncoderClass*)(klass))
++MSFilter * ms_GSMencoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_GSMencoder_init(MSGSMEncoder *r);
++void ms_GSMencoder_class_init(MSGSMEncoderClass *klass);
++void ms_GSMencoder_destroy( MSGSMEncoder *obj);
++void ms_GSMencoder_process(MSGSMEncoder *r);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h	(revision 586398)
+@@ -0,0 +1,74 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSVIDEOSOURCE_H
++#define MSVIDEOSOURCE_H
++
++
++#include "msfilter.h"
++
++/* this is the video input abstract class */
++
++#define MSVIDEOSOURCE_MAX_OUTPUTS  1 /* max output per filter*/
++
++typedef struct _MSVideoSource
++{
++    /* the MSVideoSource derivates from MSFilter, so the MSFilter object MUST be the first of the MSVideoSource object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSQueue *outputs[MSVIDEOSOURCE_MAX_OUTPUTS];
++    gchar *dev_name;
++	gint width, height;
++	gchar *format;
++	gint frame_rate;
++	gint frame_rate_base;
++} MSVideoSource;
++
++typedef struct _MSVideoSourceClass
++{
++	/* the MSVideoSource derivates from MSFilter, so the MSFilter class MUST be the first of the MSVideoSource class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++	gint (*set_device)(MSVideoSource *s, const gchar *name);
++	void (*start)(MSVideoSource *s);
++	void (*stop)(MSVideoSource *s);
++	void (*set_size)(MSVideoSource *s, gint width, gint height);
++	void (*set_frame_rate)(MSVideoSource *s, gint frame_rate, gint frame_rate_base);
++} MSVideoSourceClass;
++
++/* PUBLIC */
++void ms_video_source_register_all();
++int ms_video_source_set_device(MSVideoSource *f, const gchar *device);
++gchar* ms_video_source_get_device_name(MSVideoSource *f);
++void ms_video_source_start(MSVideoSource *f);
++void ms_video_source_stop(MSVideoSource *f);
++void ms_video_source_set_size(MSVideoSource *f, gint width, gint height);
++void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base);
++gchar* ms_video_source_get_format(MSVideoSource *f);
++
++#define MS_VIDEO_SOURCE(obj)		((MSVideoSource*)(obj))
++#define MS_VIDEO_SOURCE_CLASS(klass)		((MSVideoSourceClass*)(klass))
++
++
++/* FOR INTERNAL USE*/
++void ms_video_source_init(MSVideoSource *f);
++void ms_video_source_class_init(MSVideoSourceClass *klass);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h	(revision 586398)
+@@ -0,0 +1,43 @@
++/*
++ * affine.h -- Affine Transforms for 2d objects
++ * Copyright (C) 2002 Charles Yates <charles.yates at pandora.be>
++ * Portions Copyright (C) 2003 Dan Dennedy <dan at dennedy.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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#ifndef _AFFINE_H
++#define _AFFINE_H
++
++#include <math.h>
++
++/** Affine transforms for 2d image manipulation. Current provides shearing and 
++	rotating support.
++*/
++
++typedef struct {
++	double matrix[2][2];
++} affine_transform_t;
++
++void affine_transform_init( affine_transform_t *this );
++void affine_transform_rotate( affine_transform_t *this, double angle );
++void affine_transform_shear( affine_transform_t *this, double shear );
++void affine_transform_scale( affine_transform_t *this, double sx, double sy );
++double affine_transform_mapx( affine_transform_t *this, int x, int y );
++double affine_transform_mapy( affine_transform_t *this, int x, int y );
++void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp );
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h	(revision 586398)
+@@ -0,0 +1,130 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MEDIASTREAM_H
++#define MEDIASTREAM_H
++
++#include "msrtprecv.h"
++#include "msrtpsend.h"
++#include "ms.h"
++#include "msosswrite.h"
++#include "msossread.h"
++#include "msread.h"
++#include "mswrite.h"
++#include "mstimer.h"
++#include "mscodec.h"
++#ifdef HAVE_SPEEX
++#include "msspeexdec.h"
++#endif
++#include "msringplayer.h"
++
++
++struct _AudioStream
++{
++	MSSync *timer;
++	RtpSession *send_session;
++	RtpSession *recv_session;
++	MSFilter *soundread;
++	MSFilter *soundwrite;
++	MSFilter *encoder;
++	MSFilter *decoder;
++	MSFilter *rtprecv;
++	MSFilter *rtpsend;
++};
++
++
++typedef struct _AudioStream AudioStream;
++
++struct _RingStream
++{
++	MSSync *timer;
++	MSFilter *source;
++	MSFilter *sndwrite;
++};
++
++typedef struct _RingStream RingStream;
++
++/* start a thread that does sampling->encoding->rtp_sending|rtp_receiving->decoding->playing */
++AudioStream *audio_stream_start (RtpProfile * prof, int locport, char *remip,
++				 int remport, int profile, int jitt_comp);
++
++AudioStream *audio_stream_start_with_sndcards(RtpProfile * prof, int locport, char *remip4,
++				 int remport, int profile, int jitt_comp, SndCard *playcard, SndCard *captcard);
++
++AudioStream *audio_stream_start_with_files (RtpProfile * prof, int locport,
++					    char *remip4, int remport,
++					    int profile, int jitt_comp,
++					    gchar * infile, gchar * outfile);
++void audio_stream_set_rtcp_information(AudioStream *st, const char *cname);
++
++
++/* stop the above process*/
++void audio_stream_stop (AudioStream * stream);
++
++RingStream *ring_start (gchar * file, gint interval, SndCard *sndcard);
++RingStream *ring_start_with_cb(gchar * file, gint interval, SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data);
++void ring_stop (RingStream * stream);
++
++/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
++gint test_audio_dev (int dev_id);
++
++/* send a dtmf */
++gint audio_stream_send_dtmf (AudioStream * stream, gchar dtmf);
++
++void audio_stream_set_default_card(int cardindex);
++
++
++#ifdef VIDEO_ENABLED
++
++/*****************
++  Video Support
++ *****************/
++
++
++
++struct _VideoStream
++{
++	MSSync *timer;
++	RtpSession *send_session;
++	RtpSession *recv_session;
++	MSFilter *source;
++	MSFilter *output;
++	MSFilter *encoder;
++	MSFilter *decoder;
++	MSFilter *rtprecv;
++	MSFilter *rtpsend;
++	gboolean show_local;
++};
++
++
++typedef struct _VideoStream VideoStream;
++
++VideoStream *video_stream_start(RtpProfile *profile, int locport, char *remip4, int remport,
++				      int payload, int jitt_comp, gboolean show_local, const gchar *source, const gchar *device);
++void video_stream_set_rtcp_information(VideoStream *st, const char *cname);
++void video_stream_stop (VideoStream * stream);
++
++VideoStream * video_preview_start(const gchar *source, const gchar *device);
++void video_preview_stop(VideoStream *stream);
++
++#endif
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h	(revision 586398)
+@@ -0,0 +1,87 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSAVDECODER_H
++#define MSAVDECODER_H
++
++#include "msfilter.h"
++
++
++#include <avcodec.h>
++
++/*this is the class that implements a AVdecoder filter*/
++
++#define MSAVDECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++struct _MSAVDecoder
++{
++    /* the MSAVDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVDecoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSQueue *q_inputs[MSAVDECODER_MAX_INPUTS];
++    MSQueue *q_outputs[MSAVDECODER_MAX_INPUTS];
++	AVCodec *av_codec;  /*the AVCodec from which this MSFilter is related */
++	AVCodecContext av_context;  /* the context of the AVCodec */
++	gint av_opened;
++	int output_pix_fmt;
++	int width;
++	int height;
++	int skip_gob;
++	unsigned char buf_compressed[100000];
++	int buf_size;
++	MSBuffer *obufwrap;		/* alternate buffer, when format change is needed*/
++};
++
++typedef struct _MSAVDecoder MSAVDecoder;
++
++struct _MSAVDecoderClass
++{
++	/* the MSAVDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVDecoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSAVDecoderClass MSAVDecoderClass;
++
++/* PUBLIC */
++#define MS_AVDECODER(filter) ((MSAVDecoder*)(filter))
++#define MS_AVDECODER_CLASS(klass) ((MSAVDecoderClass*)(klass))
++
++MSFilter *ms_h263_decoder_new();
++MSFilter *ms_mpeg_decoder_new();
++MSFilter *ms_mpeg4_decoder_new();
++MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id);
++
++gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt);
++void ms_AVdecoder_set_width(MSAVDecoder *av,gint w);
++void ms_AVdecoder_set_height(MSAVDecoder *av,gint h);
++
++/* FOR INTERNAL USE*/
++void ms_AVdecoder_init(MSAVDecoder *r, AVCodec *codec);
++void ms_AVdecoder_uninit(MSAVDecoder *enc);
++void ms_AVdecoder_class_init(MSAVDecoderClass *klass);
++void ms_AVdecoder_destroy( MSAVDecoder *obj);
++void ms_AVdecoder_process(MSAVDecoder *r);
++
++void ms_AVCodec_init();
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c	(revision 586398)
+@@ -0,0 +1,39 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation
++  
++  */
++  
++#include "mssoundwrite.h"
++
++
++void ms_sound_write_init(MSSoundWrite *w)
++{
++	ms_filter_init(MS_FILTER(w));
++	
++}
++
++void ms_sound_write_class_init(MSSoundWriteClass *klass)
++{
++	int i;
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	MS_FILTER_CLASS(klass)->max_finputs=1;  /* one fifo output only */
++	
++	ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SINK);
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSSOUNDWRITE_H
++#define MSSOUNDWRITE_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++
++
++struct _MSSoundWrite
++{
++	/* the MSOssWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssWrite object
++       in order to the object mechanism to work*/
++	MSFilter filter;
++};
++
++typedef struct _MSSoundWrite MSSoundWrite;
++
++struct _MSSoundWriteClass
++{
++	/* the MSOssWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssWrite class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++	gint (*set_device)(MSSoundWrite *, gint devid);
++	void (*start)(MSSoundWrite *);
++	void (*stop)(MSSoundWrite*);
++	void (*set_level)(MSSoundWrite *, gint a);
++};
++
++typedef struct _MSSoundWriteClass MSSoundWriteClass;
++
++/* PUBLIC */
++#define MS_SOUND_WRITE(filter) ((MSSoundWrite*)(filter))
++#define MS_SOUND_WRITE_CLASS(klass) ((MSSoundWriteClass*)(klass))
++
++static inline int ms_sound_write_set_device(MSSoundWrite *r,gint devid)
++{
++	return MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
++}
++
++static inline void ms_sound_write_start(MSSoundWrite *r)
++{
++	MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->start(r);
++}
++
++static inline void ms_sound_write_stop(MSSoundWrite *w)
++{
++	MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->stop(w);
++}
++
++static inline void ms_sound_write_set_level(MSSoundWrite *w,gint a)
++{
++	MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
++}
++
++/* FOR INTERNAL USE*/
++void ms_sound_write_init(MSSoundWrite *r);
++void ms_sound_write_class_init(MSSoundWriteClass *klass);
++
++
++#endif
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c	(revision 586398)
+@@ -0,0 +1,94 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msbuffer.h"
++#include "msutils.h"
++#include <string.h>
++
++
++
++MSBuffer * ms_buffer_new(guint32 size)
++{
++	MSBuffer *buf;
++	buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)+size);
++	buf->ref_count=0;
++	buf->size=size;
++	ms_trace("ms_buffer_new: Allocating buffer of %i bytes.",size);
++	/* allocate the data buffer: there is a lot of optmisation that can be done by using a pool of cached buffers*/
++	buf->buffer=((char*)(buf))+sizeof(MSBuffer); /* to avoid to do two allocations,
++					buffer info and buffer are contigous.*/
++	buf->flags=MS_BUFFER_CONTIGUOUS;
++	return(buf);
++}
++
++MSBuffer *ms_buffer_alloc(gint flags)
++{
++	MSBuffer *buf;
++	buf=(MSBuffer*)g_malloc(sizeof(MSBuffer));
++	buf->ref_count=0;
++	buf->size=0;
++	buf->buffer=NULL;
++	buf->flags=0;
++	return(buf);
++}
++
++
++void ms_buffer_destroy(MSBuffer *buf)
++{
++	if (buf->flags & MS_BUFFER_CONTIGUOUS){
++		g_free(buf);
++	}
++	else {
++		g_free(buf->buffer);
++		g_free(buf);
++	}
++}
++
++MSMessage *ms_message_alloc()
++{
++   MSMessage *m=g_malloc(sizeof(MSMessage));
++   memset(m,0,sizeof(MSMessage));
++   return m;
++}
++
++MSMessage *ms_message_new(gint size)
++{
++   MSMessage *m=ms_message_alloc();
++   MSBuffer *buf=ms_buffer_new(size);
++   ms_message_set_buf(m,buf);
++   return m;
++}
++
++void ms_message_destroy(MSMessage *m)
++{
++	/* the buffer  is freed if its ref_count goes to zero */
++	if (m->buffer!=NULL){
++		m->buffer->ref_count--;
++		if (m->buffer->ref_count==0) ms_buffer_destroy(m->buffer);
++	}
++	g_free(m);
++}
++
++MSMessage * ms_message_dup(MSMessage *m)
++{
++   MSMessage *msg=ms_message_alloc();
++   ms_message_set_buf(msg,m->buffer);
++   return msg;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h	(revision 586398)
+@@ -0,0 +1,96 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSV4L_H
++#define MSV4L_H
++
++#include <msvideosource.h>
++#include <sys/types.h>
++#include <linux/videodev.h>
++
++struct _MSV4l
++{
++	MSVideoSource parent;
++	int fd;
++	char *device;
++	struct video_capability cap;
++	struct video_channel channel;
++	struct video_window win;
++	struct video_picture pict;
++	struct video_mmap vmap;
++	struct video_mbuf vmbuf;
++	struct video_capture vcap;
++	gint bsize;
++	gint use_mmap;
++	gint frame;
++	guint query_frame;
++	gchar *mmapdbuf; /* the mmap'd buffer */
++	MSBuffer img[VIDEO_MAX_FRAME];	/* the buffer wrappers used for mmaps */
++	gint width; /* the capture image size - can be cropped to output size */
++	gint height;
++	MSBuffer *allocdbuf; /* the buffer allocated for read() and mire */
++	gint count;
++	MSBuffer *image_grabbed;
++	GCond *cond;
++	GCond *stopcond;
++	GThread *v4lthread;
++	gboolean grab_image;
++	gboolean thread_run;
++	gboolean thread_exited;
++};
++
++typedef struct _MSV4l MSV4l;
++
++
++struct _MSV4lClass
++{
++	MSVideoSourceClass parent_class;
++	
++};
++
++typedef struct _MSV4lClass MSV4lClass;
++
++
++/* PUBLIC API */
++#define MS_V4L(v)		((MSV4l*)(v))
++#define MS_V4L_CLASS(k)		((MSV4lClass*)(k))
++MSFilter * ms_v4l_new();
++
++void ms_v4l_start(MSV4l *obj);
++void ms_v4l_stop(MSV4l *obj);
++int ms_v4l_set_device(MSV4l *f, const gchar *device);
++gint ms_v4l_get_width(MSV4l *v4l);
++gint ms_v4l_get_height(MSV4l *v4l);
++void ms_v4l_set_size(MSV4l *v4l, gint w, gint h);
++
++/* PRIVATE API */
++void ms_v4l_init(MSV4l *obj);
++void ms_v4l_class_init(MSV4lClass *klass);
++int v4l_configure(MSV4l *f);
++
++void v4l_process(MSV4l *obj);
++
++void ms_v4l_uninit(MSV4l *obj);
++
++void ms_v4l_destroy(MSV4l *obj);
++
++extern MSFilterInfo v4l_info;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README	(revision 586398)
+@@ -0,0 +1,3 @@
++Mediastreamer is the library that handle all media operations: rtp streaming
++from file, from soundcard, with codec transcoding, and vice-versa;-).
++And also video streaming in the future.
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c	(revision 586398)
+@@ -0,0 +1,193 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "mssync.h"
++#include <errno.h>
++
++/* TODO:
++	-define an uninit function that free the mutex
++*/
++
++/**
++ * function_name:ms_sync_get_bytes_per_tick
++ * @sync:  A #MSSync object.
++ *
++ * Returns the number of bytes per tick. This is a usefull information for sources, so
++ * that they can know how much data they must deliver each time they are called.
++ *
++ */
++
++/* private */
++void ms_sync_init(MSSync *sync)
++{	
++	sync->klass=NULL;  
++	sync->lock=g_mutex_new();
++	sync->thread_cond=g_cond_new();
++	sync->stop_cond=g_cond_new();
++	sync->attached_filters=NULL;
++	sync->execution_list=NULL;
++	sync->filters=0;
++	sync->run=0;
++	sync->flags=0;
++	sync->samples_per_tick=0;
++	sync->ticks=0;
++	sync->time=0;
++	sync->thread=NULL;
++}
++
++void ms_sync_class_init(MSSyncClass *klass)
++{
++	klass->max_filters=0;
++	klass->synchronize=NULL;
++	klass->attach=ms_sync_attach_generic;
++	klass->detach=ms_sync_detach_generic;
++	klass->destroy=NULL;
++}
++
++/* public*/
++
++
++/**
++ * ms_sync_attach:
++ * @sync:  A #MSSync object.
++ * @f:  A #MSFilter object.
++ *
++ * Attach a chain of filters to a synchronisation source @sync. Filter @f must be the first filter of the processing chain.
++ *  In order to be run, each chain of filter must be attached to a synchronisation source, that will be responsible for scheduling
++ *  the processing. Multiple chains can be attached to a single synchronisation.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_sync_attach(MSSync *sync,MSFilter *f)
++{
++	gint err;
++	ms_sync_lock(sync);
++	err=sync->klass->attach(sync,f);
++	ms_sync_update(sync);
++	ms_sync_unlock(sync);
++	return(err);
++}
++
++int ms_sync_attach_generic(MSSync *sync,MSFilter *f)
++{
++	int i;
++	/* //printf("attr: %i\n",f->klass->attributes); */
++	g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
++	g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
++	
++
++	/* find a free place to attach*/
++	for (i=0;i<sync->klass->max_filters;i++)
++	{
++		if (sync->attached_filters[i]==NULL)
++		{
++			sync->attached_filters[i]=f;
++			sync->filters++;
++			ms_trace("Filter succesfully attached to sync.");
++			return 0;
++		}
++	}
++	g_warning("No more link on sync !");
++	return(-EMLINK);
++}
++
++/**
++ * ms_sync_detach:
++ * @sync:  A #MSSync object.
++ * @f:  A #MSFilter object.
++ *
++ * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
++ * The processing chain will no more be executed.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_sync_detach(MSSync *sync,MSFilter *f)
++{	
++	gint err;
++	ms_sync_lock(sync);
++	err=sync->klass->detach(sync,f);
++	ms_sync_update(sync);
++	ms_sync_unlock(sync);
++	return(err);
++}
++
++int ms_sync_detach_generic(MSSync *sync,MSFilter *f)
++{
++	int i;
++	g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
++	g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
++	for (i=0;i<sync->filters;i++)
++	{
++		if (sync->attached_filters[i]==f)
++		{
++			sync->attached_filters[i]=NULL;
++			sync->filters--;
++			return 0;
++		}
++	}
++	return(-EMLINK);
++}
++
++void ms_sync_set_samples_per_tick(MSSync *sync,gint size)
++{
++	if (sync->samples_per_tick==0)
++	{
++		sync->samples_per_tick=size;
++		g_cond_signal(sync->thread_cond);
++	}
++	else sync->samples_per_tick=size;
++}
++
++/* call the setup func of each filter attached to the graph */
++void ms_sync_setup(MSSync *sync)
++{
++	GList *elem=sync->execution_list;
++	MSFilter *f;
++	while(elem!=NULL){
++		f=(MSFilter*)elem->data;
++		if (f->klass->setup!=NULL){
++			f->klass->setup(f,sync);
++		}
++		elem=g_list_next(elem);
++	}
++}
++
++/* call the unsetup func of each filter attached to the graph */
++void ms_sync_unsetup(MSSync *sync)
++{
++	GList *elem=sync->execution_list;
++	MSFilter *f;
++	while(elem!=NULL){
++		f=(MSFilter*)elem->data;
++		if (f->klass->unsetup!=NULL){
++			f->klass->unsetup(f,sync);
++		}
++		elem=g_list_next(elem);
++	}
++}
++
++
++int ms_sync_uninit(MSSync *sync)
++{
++	g_mutex_free(sync->lock);
++	g_cond_free(sync->thread_cond);
++	g_cond_free(sync->stop_cond);
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c	(revision 586398)
+@@ -0,0 +1,343 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "mediastream.h"
++#ifdef INET6
++	#include <sys/types.h>
++	#include <sys/socket.h>
++	#include <netdb.h>
++#endif
++
++
++#define MAX_RTP_SIZE	1500
++
++/* this code is not part of the library itself, it is part of the mediastream program */
++void audio_stream_free(AudioStream *stream)
++{
++	RtpSession *s;
++	RtpSession *destroyed=NULL;
++	if (stream->rtprecv!=NULL) {
++		s=ms_rtp_recv_get_session(MS_RTP_RECV(stream->rtprecv));
++		if (s!=NULL){
++			destroyed=s;
++			rtp_session_destroy(s);
++		}
++		ms_filter_destroy(stream->rtprecv);
++	}
++	if (stream->rtpsend!=NULL) {
++		s=ms_rtp_send_get_session(MS_RTP_SEND(stream->rtpsend));
++		if (s!=NULL){
++			if (s!=destroyed)
++				rtp_session_destroy(s);
++		}
++		ms_filter_destroy(stream->rtpsend);
++	}
++	if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
++	if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
++	if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
++	if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
++	if (stream->timer!=NULL) ms_sync_destroy(stream->timer);
++	g_free(stream);
++}
++
++static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
++
++static void on_dtmf_received(RtpSession *s,gint dtmf,gpointer user_data)
++{
++	AudioStream *stream=(AudioStream*)user_data;
++	if (dtmf>15){
++		g_warning("Unsupported telephone-event type.");
++		return;
++	}
++	g_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
++	if (stream!=NULL){
++		if (strcmp(stream->soundwrite->klass->name,"OssWrite")==0)
++			ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf_tab[dtmf]);
++	}
++}
++
++static void on_timestamp_jump(RtpSession *s,guint32* ts, gpointer user_data)
++{
++	g_warning("The remote sip-phone has send data with a future timestamp: %u,"
++			"resynchronising session.",*ts);
++	rtp_session_reset(s);
++}
++
++static const char *ip4local="0.0.0.0";
++static const char *ip6local="::";
++
++const char *get_local_addr_for(const char *remote)
++{
++	const char *ret;
++#ifdef INET6
++	char num[8];
++	struct addrinfo hints, *res0;
++	int err;
++	memset(&hints, 0, sizeof(hints));
++	hints.ai_family = PF_UNSPEC;
++	hints.ai_socktype = SOCK_DGRAM;
++	err = getaddrinfo(remote,"8000", &hints, &res0);
++	if (err!=0) {
++		g_warning ("get_local_addr_for: %s", gai_strerror(err));
++		return ip4local;
++	}
++	ret=(res0->ai_addr->sa_family==AF_INET6) ? ip6local : ip4local; 
++	freeaddrinfo(res0);
++#else
++	ret=ip4local;
++#endif
++	return ret;
++}
++
++void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport,
++				int payload,int jitt_comp,
++			RtpSession **recvsend){
++	RtpSession *rtpr;
++	rtpr=rtp_session_new(RTP_SESSION_SENDRECV);
++	rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
++	rtp_session_set_profile(rtpr,profile);
++	rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport);
++	if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport);
++	rtp_session_set_scheduling_mode(rtpr,0);
++	rtp_session_set_blocking_mode(rtpr,0);
++	rtp_session_set_payload_type(rtpr,payload);
++	rtp_session_set_jitter_compensation(rtpr,jitt_comp);
++	rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE);
++	/*rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);*/
++	*recvsend=rtpr;
++}
++
++void create_rtp_sessions(RtpProfile *profile, int locport,char *remip,int remport,
++				int payload,int jitt_comp,
++			RtpSession **recv, RtpSession **send){
++	RtpSession *rtps,*rtpr;
++	PayloadType *pt;
++	/* creates two rtp filters to recv send streams (remote part)*/
++	
++	rtps=rtp_session_new(RTP_SESSION_SENDONLY);
++	rtp_session_max_buf_size_set(rtps,MAX_RTP_SIZE);
++	rtp_session_set_profile(rtps,profile);
++#ifdef INET6
++	rtp_session_set_local_addr(rtps,"::",locport+2);
++#else
++	rtp_session_set_local_addr(rtps,"0.0.0.0",locport+2);
++#endif
++	rtp_session_set_remote_addr(rtps,remip,remport);
++	rtp_session_set_scheduling_mode(rtps,0);
++	rtp_session_set_blocking_mode(rtps,0);
++	rtp_session_set_payload_type(rtps,payload);
++	rtp_session_set_jitter_compensation(rtps,jitt_comp);
++	
++	rtpr=rtp_session_new(RTP_SESSION_RECVONLY);
++	rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
++	rtp_session_set_profile(rtpr,profile);
++#ifdef INET6
++	rtp_session_set_local_addr(rtpr,"::",locport);
++#else
++	rtp_session_set_local_addr(rtpr,"0.0.0.0",locport);
++#endif
++	rtp_session_set_scheduling_mode(rtpr,0);
++	rtp_session_set_blocking_mode(rtpr,0);
++	rtp_session_set_payload_type(rtpr,payload);
++	rtp_session_set_jitter_compensation(rtpr,jitt_comp);
++	rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,NULL);
++	rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);
++	*recv=rtpr;
++	*send=rtps;
++	
++}
++
++
++AudioStream * audio_stream_start_full(RtpProfile *profile, int locport,char *remip,int remport,
++				int payload,int jitt_comp, gchar *infile, gchar *outfile, SndCard *playcard, SndCard *captcard)
++{
++	AudioStream *stream=g_new0(AudioStream,1);
++	RtpSession *rtps,*rtpr;
++	PayloadType *pt;
++	
++	/* //create_rtp_sessions(profile,locport,remip,remport,payload,jitt_comp,&rtpr,&rtps); */
++	
++	create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr);
++	rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,(gpointer)stream);
++	rtps=rtpr;
++	
++	stream->recv_session = rtpr;
++	stream->send_session = rtps;
++	stream->rtpsend=ms_rtp_send_new();
++	ms_rtp_send_set_session(MS_RTP_SEND(stream->rtpsend),rtps);
++	stream->rtprecv=ms_rtp_recv_new();
++	ms_rtp_recv_set_session(MS_RTP_RECV(stream->rtprecv),rtpr);
++	
++	
++	/* creates the local part */
++	if (infile==NULL) stream->soundread=snd_card_create_read_filter(captcard);
++	else stream->soundread=ms_read_new(infile);
++	if (outfile==NULL) stream->soundwrite=snd_card_create_write_filter(playcard);
++	else stream->soundwrite=ms_write_new(outfile);
++	
++	/* creates the couple of encoder/decoder */
++	pt=rtp_profile_get_payload(profile,payload);
++	if (pt==NULL){
++		g_error("audiostream.c: undefined payload type.");
++		return NULL;
++	}
++	stream->encoder=ms_encoder_new_with_string_id(pt->mime_type);
++	stream->decoder=ms_decoder_new_with_string_id(pt->mime_type);
++	if ((stream->encoder==NULL) || (stream->decoder==NULL)){
++		/* big problem: we have not a registered codec for this payload...*/
++		audio_stream_free(stream);
++		g_error("mediastream.c: No decoder available for payload %i.",payload);
++		return NULL;
++	}
++	/* give the sound filters some properties */
++	ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
++	ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
++	
++	/* give the encoder/decoder some parameters*/
++	ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
++	ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
++	ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
++	ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
++	
++	ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->fmtp);
++	ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->fmtp);
++	/* create the synchronisation source */
++	stream->timer=ms_timer_new();
++	
++	/* and then connect all */
++	ms_filter_add_link(stream->soundread,stream->encoder);
++	ms_filter_add_link(stream->encoder,stream->rtpsend);
++	ms_filter_add_link(stream->rtprecv,stream->decoder);
++	ms_filter_add_link(stream->decoder,stream->soundwrite);
++	
++	ms_sync_attach(stream->timer,stream->soundread);
++	ms_sync_attach(stream->timer,stream->rtprecv);
++	
++	/* and start */
++	ms_start(stream->timer);
++	
++	return stream;
++}
++
++static int defcard=0;
++
++void audio_stream_set_default_card(int cardindex){
++	defcard=cardindex;
++}
++
++AudioStream * audio_stream_start_with_files(RtpProfile *prof,int locport,char *remip,
++		int remport,int profile,int jitt_comp,gchar *infile, gchar*outfile)
++{
++	return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,infile,outfile,NULL,NULL);
++}
++
++AudioStream * audio_stream_start(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp)
++{
++	SndCard *sndcard;
++	sndcard=snd_card_manager_get_card(snd_card_manager,defcard);
++	return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,sndcard,sndcard);
++}
++
++AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp,SndCard *playcard, SndCard *captcard)
++{
++	g_return_val_if_fail(playcard!=NULL,NULL);
++	g_return_val_if_fail(captcard!=NULL,NULL);
++	return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,playcard,captcard);
++}
++
++void audio_stream_set_rtcp_information(AudioStream *st, const char *cname){
++	if (st->send_session!=NULL){
++		rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL, NULL,"linphone",
++											"This is free software (GPL) !");
++	}
++}
++
++void audio_stream_stop(AudioStream * stream)
++{
++	
++	ms_stop(stream->timer);
++	ortp_global_stats_display();
++	ms_sync_detach(stream->timer,stream->soundread);
++	ms_sync_detach(stream->timer,stream->rtprecv);
++	
++	ms_filter_remove_links(stream->soundread,stream->encoder);
++	ms_filter_remove_links(stream->encoder,stream->rtpsend);
++	ms_filter_remove_links(stream->rtprecv,stream->decoder);
++	ms_filter_remove_links(stream->decoder,stream->soundwrite);
++	
++	audio_stream_free(stream);
++}
++
++RingStream * ring_start(gchar *file,gint interval,SndCard *sndcard)
++{
++   return ring_start_with_cb(file,interval,sndcard,NULL,NULL);
++}
++
++RingStream * ring_start_with_cb(gchar *file,gint interval,SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data)
++{
++	RingStream *stream;
++	int tmp;
++	g_return_val_if_fail(sndcard!=NULL,NULL);
++	stream=g_new0(RingStream,1);
++	stream->source=ms_ring_player_new(file,interval);
++	if (stream->source==NULL) {
++		g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file);
++		return NULL;
++	}
++  if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data);
++	stream->sndwrite=snd_card_create_write_filter(sndcard);
++	ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp);
++	ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp);
++	ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_CHANNELS,&tmp);
++	ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_CHANNELS,&tmp);
++	stream->timer=ms_timer_new();
++	ms_filter_add_link(stream->source,stream->sndwrite);
++	ms_sync_attach(stream->timer,stream->source);
++	ms_start(stream->timer);
++	return stream;
++}
++
++void ring_stop(RingStream *stream)
++{
++	ms_stop(stream->timer);
++	ms_sync_detach(stream->timer,stream->source);
++	ms_sync_destroy(stream->timer);
++	ms_filter_remove_links(stream->source,stream->sndwrite);
++	ms_filter_destroy(stream->source);
++	ms_filter_destroy(stream->sndwrite);
++	g_free(stream);
++}
++
++/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
++gint test_audio_dev(int dev_id)
++{
++	gint err;
++	SndCard *sndcard=snd_card_manager_get_card(snd_card_manager,dev_id);
++	if (sndcard==NULL) return -1;
++	err=snd_card_probe(sndcard,16,0,8000);
++	return err;  /* return latency in number of sample */
++}
++
++gint audio_stream_send_dtmf(AudioStream *stream, gchar dtmf)
++{
++	ms_rtp_send_dtmf(MS_RTP_SEND(stream->rtpsend), dtmf);
++	ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h	(revision 586398)
+@@ -0,0 +1,75 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSBUFFER_H
++#define MSBUFFER_H
++#include <config.h>
++
++#ifdef HAVE_GLIB
++#include <glib.h>
++#else
++#include <uglib.h>
++#endif
++
++
++#define MS_BUFFER_LARGE 4092
++
++
++typedef struct _MSBuffer
++{
++    gchar *buffer;
++    guint32 size;
++    guint16 ref_count;
++    guint16 flags;
++#define MS_BUFFER_CONTIGUOUS (1)
++}MSBuffer;
++
++MSBuffer * ms_buffer_new(guint32 size);
++void ms_buffer_destroy(MSBuffer *buf);
++
++struct _MSMessage
++{
++   MSBuffer *buffer; /* points to a MSBuffer */
++   void *data;          /*points to buffer->buffer  */
++   guint32 size;   /* the size of the buffer to read in data. It may not be the
++   								physical size (I mean buffer->buffer->size */
++   struct _MSMessage *next;
++   struct _MSMessage *prev;  /* MSMessage are queued into MSQueues */
++};
++
++typedef struct _MSMessage MSMessage;
++
++
++MSBuffer *ms_buffer_alloc(gint flags);
++MSMessage *ms_message_new(gint size);
++
++#define ms_message_set_buf(m,b) do { (b)->ref_count++; (m)->buffer=(b); (m)->data=(b)->buffer; (m)->size=(b)->size; }while(0)
++#define ms_message_unset_buf(m) do { (m)->buffer->ref_count--; (m)->buffer=NULL; (m)->size=0; (m)->data=NULL; } while(0)
++
++#define ms_message_size(m)		(m)->size
++void ms_message_destroy(MSMessage *m);
++
++MSMessage * ms_message_dup(MSMessage *m);
++
++/* allocate a single message without buffer */
++MSMessage *ms_message_alloc();
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/***************************************************************************
++ *            mssdlout.h
++ *
++ *  Mon Jul 11 16:18:55 2005
++ *  Copyright  2005  Simon Morlat
++ *  Email simon dot morlat at linphone dot org
++ ****************************************************************************/
++
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef mssdlout_h
++#define mssdlout_h
++
++#include "msfilter.h"
++
++#include <SDL/SDL.h>
++#include <SDL/SDL_video.h>
++
++struct _MSSdlOut
++{
++	MSFilter parent;
++	MSQueue *input[2];
++	gint width,height;
++	const gchar *format;
++	SDL_Surface *screen;
++	SDL_Overlay *overlay;
++	MSMessage *oldinm1;
++	gboolean use_yuv;
++};
++
++
++typedef struct _MSSdlOut MSSdlOut;
++	
++struct _MSSdlOutClass
++{
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSSdlOutClass MSSdlOutClass;
++	
++MSFilter * ms_sdl_out_new(void);
++void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt);
++
++#define MS_SDL_OUT(obj) ((MSSdlOut*)obj)
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c	(revision 586398)
+@@ -0,0 +1,211 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msrtpsend.h"
++#include <ortp/telephonyevents.h>
++#include "mssync.h"
++#include "mscodec.h"
++
++
++
++static MSRtpSendClass *ms_rtp_send_class=NULL;
++
++MSFilter * ms_rtp_send_new(void)
++{
++	MSRtpSend *r;
++	
++	r=g_new(MSRtpSend,1);
++	
++	if (ms_rtp_send_class==NULL)
++	{
++		ms_rtp_send_class=g_new(MSRtpSendClass,1);
++		ms_rtp_send_class_init(ms_rtp_send_class);
++	}
++	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_send_class);
++	ms_rtp_send_init(r);
++	return(MS_FILTER(r));
++}
++	
++
++void ms_rtp_send_init(MSRtpSend *r)
++{
++	ms_filter_init(MS_FILTER(r));
++	MS_FILTER(r)->infifos=r->f_inputs;
++	MS_FILTER(r)->inqueues=r->q_inputs;
++	MS_FILTER(r)->r_mingran=MSRTPSEND_DEF_GRAN;
++	memset(r->f_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
++	memset(r->q_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
++	r->rtpsession=NULL;
++	r->ts=0;
++	r->ts_inc=0;
++	r->flags=0;
++	r->delay=0;
++}
++
++void ms_rtp_send_class_init(MSRtpSendClass *klass)
++{
++	ms_filter_class_init(MS_FILTER_CLASS(klass));
++	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPSend");
++	MS_FILTER_CLASS(klass)->max_qinputs=MSRTPSEND_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->max_finputs=MSRTPSEND_MAX_INPUTS;
++	MS_FILTER_CLASS(klass)->r_maxgran=MSRTPSEND_DEF_GRAN;
++	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_send_destroy;
++	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_send_process;
++	MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_send_setup;
++}
++
++void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size)
++{
++	r->ts_inc=ts_inc;
++	r->packet_size=payload_size;
++	if (r->ts_inc!=0) r->flags|=RTPSEND_CONFIGURED;
++	else r->flags&=~RTPSEND_CONFIGURED;
++	MS_FILTER(r)->r_mingran=payload_size;	
++	/*g_message("ms_rtp_send_set_timing: ts_inc=%i",ts_inc);*/
++}
++
++guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime)
++{
++	guint32 clockts;
++	/* use the sync system time to compute a timestamp */
++	PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
++	g_return_val_if_fail(pt!=NULL,0);
++	clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0);
++	ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts);
++	if (r->flags & RTPSEND_CONFIGURED){
++		if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){
++			r->ts=clockts;
++		}
++		else r->ts+=r->ts_inc;
++	}else{
++		r->ts=clockts;
++	}
++	return r->ts;
++}
++
++
++void ms_rtp_send_process(MSRtpSend *r)
++{
++	MSFifo *fi;
++	MSQueue *qi;
++	MSSync *sync= r->sync;
++	int gran=ms_sync_get_samples_per_tick(sync);
++	guint32 ts;
++	void *s;
++	guint skip;
++	guint32 synctime=sync->time;
++	
++	g_return_if_fail(gran>0);
++	if (r->rtpsession==NULL) return;
++
++	ms_filter_lock(MS_FILTER(r));
++	skip=r->delay!=0;
++	if (skip) r->delay--;
++	/* process output fifo and output queue*/
++	fi=r->f_inputs[0];
++	if (fi!=NULL)
++	{
++		ts=get_new_timestamp(r,synctime);
++		/* try to read r->packet_size bytes and send them in a rtp packet*/
++		ms_fifo_get_read_ptr(fi,r->packet_size,&s);
++		if (!skip){
++			rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts);
++			ms_trace("len=%i, ts=%i ",r->packet_size,ts);
++		}
++	}
++	qi=r->q_inputs[0];
++	if (qi!=NULL)
++	{
++		MSMessage *msg;
++		/* read a MSMessage and send it through the network*/
++		while ( (msg=ms_queue_get(qi))!=NULL){
++			ts=get_new_timestamp(r,synctime);
++			if (!skip) {
++				/*g_message("Sending packet with ts=%u",ts);*/
++				rtp_session_send_with_ts(r->rtpsession,msg->data,msg->size,ts);
++				
++			}
++			ms_message_destroy(msg);
++		}
++	}
++	ms_filter_unlock(MS_FILTER(r));
++}
++
++void ms_rtp_send_destroy( MSRtpSend *obj)
++{
++	g_free(obj);
++}
++
++RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session)
++{
++	RtpSession *old=obj->rtpsession;
++	obj->rtpsession=session;
++	obj->ts=0;
++	obj->ts_inc=0;
++	return old;
++}
++
++void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync)
++{
++	MSFilter *codec;
++	MSCodecInfo *info;
++	r->sync=sync;
++	codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_AUDIO_CODEC);
++	if (codec==NULL) codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_VIDEO_CODEC);
++	if (codec==NULL){
++		g_warning("ms_rtp_send_setup: could not find upstream codec.");
++		return;
++	}
++	info=MS_CODEC_INFO(codec->klass->info);
++	if (info->info.type==MS_FILTER_AUDIO_CODEC){
++		int ts_inc=info->fr_size/2;
++		int psize=info->dt_size;
++		if (ts_inc==0){
++			/* dont'use the normal frame size: this is a variable frame size codec */
++			/* use the MS_FILTER(codec)->r_mingran */
++			ts_inc=MS_FILTER(codec)->r_mingran/2;
++			psize=0;
++		}
++		ms_rtp_send_set_timing(r,ts_inc,psize);
++	}
++}
++
++gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf)
++{
++	gint res;
++
++	if (r->rtpsession==NULL) return -1;
++	if (rtp_session_telephone_events_supported(r->rtpsession)==-1){
++		g_warning("ERROR : telephone events not supported.\n");
++ 		return -1;
++	}
++
++	ms_filter_lock(MS_FILTER(r));
++	g_message("Sending DTMF.");
++	res=rtp_session_send_dtmf(r->rtpsession, dtmf, r->ts);
++	if (res==0){
++		/* //r->ts+=r->ts_inc; */
++		r->delay+=2;
++	}else g_warning("Could not send dtmf.");
++
++	ms_filter_unlock(MS_FILTER(r));
++
++	return res;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c	(revision 586398)
+@@ -0,0 +1,114 @@
++ /*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#include "mstimer.h"
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <signal.h>
++
++static MSTimerClass *ms_timer_class=NULL;
++
++
++void ms_timer_init(MSTimer *sync)
++{
++	ms_sync_init(MS_SYNC(sync));
++	MS_SYNC(sync)->attached_filters=sync->filters;
++	memset(sync->filters,0,MSTIMER_MAX_FILTERS*sizeof(MSFilter*));
++	MS_SYNC(sync)->samples_per_tick=160;
++	ms_timer_set_interval(sync,20);
++	sync->state=MS_TIMER_STOPPED;
++}
++
++void ms_timer_class_init(MSTimerClass *klass)
++{
++	ms_sync_class_init(MS_SYNC_CLASS(klass));
++	MS_SYNC_CLASS(klass)->max_filters=MSTIMER_MAX_FILTERS;
++	MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_timer_synchronize;
++	MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_timer_destroy;
++	/* no need to overload these function*/
++	MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
++	MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
++}
++
++void ms_timer_destroy(MSTimer *timer)
++{
++	g_free(timer);
++}
++
++
++void ms_timer_synchronize(MSTimer *timer)
++{
++	/* //printf("ticks=%i \n",MS_SYNC(timer)->ticks); */
++	if (timer->state==MS_TIMER_STOPPED){
++		timer->state=MS_TIMER_RUNNING;
++		gettimeofday(&timer->orig,NULL);
++		timer->sync.time=0;
++	}
++	else {
++		gint32 diff,time;
++		struct timeval tv,cur;
++	
++		gettimeofday(&cur,NULL);
++		time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
++		if ( (diff=time-timer->sync.time)>50){
++			g_warning("Must catchup %i miliseconds.",diff);
++		}
++		while((diff = timer->sync.time-time) > 0)
++		{
++			tv.tv_sec = diff/1000;
++			tv.tv_usec = (diff%1000)*1000;
++			select(0,NULL,NULL,NULL,&tv);
++			gettimeofday(&cur,NULL);
++			time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
++		}
++	}
++	timer->sync.time+=timer->milisec;
++	return;
++}
++
++
++MSSync *ms_timer_new()
++{
++	MSTimer *timer;
++	
++	timer=g_malloc(sizeof(MSTimer));
++	ms_timer_init(timer);
++	if (ms_timer_class==NULL)
++	{
++		ms_timer_class=g_new(MSTimerClass,1);
++		ms_timer_class_init(ms_timer_class);
++	}
++	MS_SYNC(timer)->klass=MS_SYNC_CLASS(ms_timer_class);
++	return(MS_SYNC(timer));
++}
++
++void ms_timer_set_interval(MSTimer *timer, int milisec)
++{
++	
++	MS_SYNC(timer)->ticks=0;
++	MS_SYNC(timer)->interval=milisec;
++	timer->interval.tv_sec=milisec/1000;
++	timer->interval.tv_usec=(milisec % 1000)*1000;
++	timer->milisec=milisec;
++	
++	
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSGSMDECODER_H
++#define MSGSMDECODER_H
++
++#include <msfilter.h>
++#include <mscodec.h>
++#include <gsm.h>
++
++/*this is the class that implements a GSMdecoder filter*/
++
++#define MSGSMDECODER_MAX_INPUTS  1 /* max output per filter*/
++
++
++typedef struct _MSGSMDecoder
++{
++    /* the MSGSMDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMDecoder object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSGSMDECODER_MAX_INPUTS];
++    MSFifo *f_outputs[MSGSMDECODER_MAX_INPUTS];
++    gsm gsm_handle;
++} MSGSMDecoder;
++
++typedef struct _MSGSMDecoderClass
++{
++	/* the MSGSMDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMDecoder class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++} MSGSMDecoderClass;
++
++/* PUBLIC */
++#define MS_GSMDECODER(filter) ((MSGSMDecoder*)(filter))
++#define MS_GSMDECODER_CLASS(klass) ((MSGSMDecoderClass*)(klass))
++MSFilter * ms_GSMdecoder_new(void);
++
++/* FOR INTERNAL USE*/
++void ms_GSMdecoder_init(MSGSMDecoder *r);
++void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass);
++void ms_GSMdecoder_destroy( MSGSMDecoder *obj);
++void ms_GSMdecoder_process(MSGSMDecoder *r);
++
++extern MSCodecInfo GSMinfo;
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h	(revision 586398)
+@@ -0,0 +1,136 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MS_SYNC_H
++#define MS_SYNC_H
++
++
++#include "msfilter.h"
++
++struct _MSSync
++{
++	struct _MSSyncClass *klass;
++	GMutex *lock;
++	MSFilter **attached_filters; /* pointer to a table of pointer of filters*/
++	GList *execution_list;     /* the list of filters to be executed. This is filled with compilation */
++	gint filters;   /*number of filters attached to the sync */
++	gint run;       /* flag to indicate whether the sync must be run or not */
++	GThread * thread;   /* the thread ressource if this sync is run by a thread*/
++	GCond *thread_cond;
++	GCond *stop_cond;
++	guint32 flags;
++	gint interval; /* in miliseconds*/
++#define MS_SYNC_NEED_UPDATE (0x0001)  /* a modification has occured in the processing chains
++							attached to this sync; so the execution list has to be updated */
++	guint samples_per_tick; /* number of bytes produced by sources of the processing chains*/
++	guint32 ticks;
++	guint32 time;	/* a time since the start of the sync expressed in milisec*/
++};
++
++typedef struct _MSSync MSSync;
++
++typedef void (*MSSyncDestroyFunc)(MSSync*);
++typedef void (*MSSyncSyncFunc)(MSSync*);
++typedef int (*MSSyncAttachFunc)(MSSync*,MSFilter*);
++typedef int (*MSSyncDetachFunc)(MSSync*,MSFilter*);
++
++typedef struct _MSSyncClass
++{
++	gint max_filters;  /* the maximum number of filters that can be attached to this sync*/
++	MSSyncSyncFunc synchronize;
++	MSSyncDestroyFunc destroy;
++	MSSyncAttachFunc attach;
++	MSSyncDetachFunc detach;
++} MSSyncClass;
++
++/* private */
++void ms_sync_init(MSSync *sync);
++void ms_sync_class_init(MSSyncClass *klass);
++
++int ms_sync_attach_generic(MSSync *sync,MSFilter *f);
++int ms_sync_detach_generic(MSSync *sync,MSFilter *f);
++
++/* public*/
++
++#define MS_SYNC(sync) ((MSSync*)(sync))
++#define MS_SYNC_CLASS(klass) ((MSSyncClass*)(klass))
++
++#define ms_sync_synchronize(_sync) \
++do       \
++{         \
++	MSSync *__sync=_sync; \
++	__sync->ticks++;       \
++	((__sync)->klass->synchronize((__sync))); \
++}while(0)
++
++void ms_sync_setup(MSSync *sync);
++
++void ms_sync_unsetup(MSSync *sync);
++
++#define ms_sync_update(sync) (sync)->flags|=MS_SYNC_NEED_UPDATE
++
++#define ms_sync_get_samples_per_tick(sync) ((sync)->samples_per_tick)
++
++void ms_sync_set_samples_per_tick(MSSync *sync,gint size);
++
++#define ms_sync_get_tick_count(sync)  ((sync)->ticks)
++
++#define ms_sync_suspend(sync) g_cond_wait((sync)->thread_cond,(sync)->lock)
++
++#define ms_sync_lock(sync) g_mutex_lock((sync)->lock)
++
++#define ms_sync_unlock(sync) g_mutex_unlock((sync)->lock)
++
++#define ms_sync_trylock(sync) g_mutex_trylock((sync)->lock)
++
++/**
++ * function_name:ms_sync_attach
++ * @sync:  A #MSSync object.
++ * @f:  A #MSFilter object.
++ *
++ * Attach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_sync_attach(MSSync *sync,MSFilter *f);
++
++/**
++ * ms_sync_detach:
++ * @sync:  A #MSSync object.
++ * @f:  A #MSFilter object.
++ *
++ * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
++ * The processing chain will no more be executed.
++ *
++ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
++ */
++int ms_sync_detach(MSSync *sync,MSFilter *f);
++
++int ms_sync_uninit(MSSync *sync);
++
++#define ms_sync_start(sync)	ms_start((sync))
++#define ms_sync_stop(sync)	ms_stop((sync))
++
++
++/*destroy*/
++#define ms_sync_destroy(sync)     (sync)->klass->destroy((sync))
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++
++#ifndef MSRTPSEND_H
++#define MSRTPSEND_H
++
++#include "msfilter.h"
++#include "mssync.h"
++
++#undef PACKAGE
++#undef VERSION
++#include <ortp/ortp.h>
++
++
++/*this is the class that implements a sending through rtp filter*/
++
++#define MSRTPSEND_MAX_INPUTS  1 /* max input per filter*/
++
++#define MSRTPSEND_DEF_GRAN  4096/* the default granularity*/
++
++struct _MSRtpSend
++{
++    /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
++       in order to the object mechanism to work*/
++    MSFilter filter;
++    MSFifo *f_inputs[MSRTPSEND_MAX_INPUTS];
++	MSQueue *q_inputs[MSRTPSEND_MAX_INPUTS];
++	MSSync *sync;
++	RtpSession *rtpsession;
++	guint32 ts;
++	guint32 ts_inc;	/* the timestamp increment */
++	gint packet_size;
++	guint flags;
++        guint delay; /* number of _proccess call which must be skipped */
++#define RTPSEND_CONFIGURED (1)
++};
++
++typedef struct _MSRtpSend MSRtpSend;
++
++struct _MSRtpSendClass
++{
++	/* the MSRtpSend derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
++       in order to the class mechanism to work*/
++	MSFilterClass parent_class;
++};
++
++typedef struct _MSRtpSendClass MSRtpSendClass;
++
++/* PUBLIC */
++#define MS_RTP_SEND(filter) ((MSRtpSend*)(filter))
++#define MS_RTP_SEND_CLASS(klass) ((MSRtpSendClass*)(klass))
++MSFilter * ms_rtp_send_new(void);
++RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session);
++#define ms_rtp_send_unset_session(obj) (ms_rtp_send_set_session((obj),NULL))
++#define ms_rtp_send_get_session(obj) ((obj)->rtpsession)
++void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size);
++gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf);
++
++
++/* FOR INTERNAL USE*/
++void ms_rtp_send_init(MSRtpSend *r);
++void ms_rtp_send_class_init(MSRtpSendClass *klass);
++void ms_rtp_send_destroy( MSRtpSend *obj);
++void ms_rtp_send_process(MSRtpSend *r);
++void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync);
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c	(revision 586398)
+@@ -0,0 +1,56 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include "msqueue.h"
++#include <string.h>
++
++MSQueue * ms_queue_new()
++{
++   MSQueue *q=g_malloc(sizeof(MSQueue));
++   memset(q,0,sizeof(MSQueue));
++   return q;
++}
++
++MSMessage *ms_queue_get(MSQueue *q)
++{
++	MSMessage *b=q->last;
++	if (b==NULL) return NULL;
++	q->last=b->prev;
++	if (b->prev==NULL) q->first=NULL; /* it was the only element of the queue*/
++     q->size--;
++     b->next=b->prev=NULL;
++	return(b);
++}
++
++void ms_queue_put(MSQueue *q, MSMessage *m)
++{
++   MSMessage *mtmp=q->first;
++   g_return_if_fail(m!=NULL);
++   q->first=m;
++   m->next=mtmp;
++   if (mtmp!=NULL)
++   {
++      mtmp->prev=m;
++   }
++   else q->last=m; /* it was the first element of the q */
++   q->size++;
++}
++
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h	(revision 586398)
+@@ -0,0 +1,68 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++#ifndef MSTIMER_H
++#define MSTIMER_H
++
++#include "mssync.h"
++#include <sys/time.h>
++
++#define MSTIMER_MAX_FILTERS 10
++
++/* MSTimer derivates from MSSync base class*/
++
++typedef struct _MSTimer
++{
++	/* the MSSync must be the first field of the object in order to the object mechanism to work*/
++	MSSync  sync;
++	MSFilter *filters[MSTIMER_MAX_FILTERS];
++	gint milisec; /* the interval */
++	struct timeval interval;
++	struct timeval orig;
++	gint state;
++} MSTimer;
++
++
++typedef struct _MSTimerClass
++{
++	/* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
++	MSSyncClass parent_class;
++} MSTimerClass;
++
++
++/*private*/
++#define MS_TIMER_RUNNING 1
++#define MS_TIMER_STOPPED 0
++void ms_timer_init(MSTimer *sync);
++void ms_timer_class_init(MSTimerClass *sync);
++
++void ms_timer_destroy(MSTimer *timer);
++void ms_timer_synchronize(MSTimer *timer);
++
++/*public*/
++void ms_timer_set_interval(MSTimer *timer, gint milisec);
++
++/* casts a MSSync object into a MSTimer */
++#define MS_TIMER(sync) ((MSTimer*)(sync))
++/* casts a MSSync class into a MSTimer class */
++#define MS_TIMER_CLASS(klass) ((MSTimerClass*)(klass))
++
++MSSync *ms_timer_new();
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am	(revision 586398)
+@@ -0,0 +1,92 @@
++EXTRA_DIST=Makefile.ms 
++noinst_LTLIBRARIES = libmediastreamer.la
++libmediastreamer_la_SOURCES=msfilter.c msfilter.h msutils.h waveheader.h\
++							mscodec.c mscodec.h \
++							mssoundread.c mssoundread.h \
++							mssoundwrite.c mssoundwrite.h \
++							msbuffer.c msbuffer.h  \
++							msqueue.c msqueue.h \
++							msfifo.c msfifo.h \
++							ms.c ms.h\
++							mssync.c mssync.h \
++							msnosync.c msnosync.h \
++							msread.c msread.h \
++							mswrite.c mswrite.h \
++							mscopy.c mscopy.h \
++							msosswrite.c msosswrite.h  \
++							msossread.c msossread.h \
++							msringplayer.c msringplayer.h \
++							msrtprecv.c msrtprecv.h   \
++							msrtpsend.c msrtpsend.h	\
++							msAlawenc.c msAlawenc.h g711common.h \
++							msAlawdec.c msAlawdec.h g711common.h \
++							msMUlawenc.c msMUlawenc.h g711common.h \
++							msMUlawdec.c msMUlawdec.h g711common.h \
++							mstimer.c mstimer.h \
++							msqdispatcher.c msqdispatcher.h \
++							msfdispatcher.c msfdispatcher.h \
++							sndcard.c sndcard.h \
++							osscard.c osscard.h\
++							hpuxsndcard.c \
++							alsacard.c alsacard.h \
++							jackcard.c jackcard.h \
++							audiostream.c mediastream.h \
++							msspeexenc.c msspeexenc.h msspeexdec.c msspeexdec.h \
++							msilbcdec.c msilbcdec.h msilbcenc.c msilbcenc.h 
++
++noinst_HEADERS = affine.h \
++			      msAlawenc.h \
++			      msfdispatcher.h \
++			      msilbcdec.h \
++			      msnosync.h \
++			      msringplayer.h \
++			      msspeexdec.h \
++		    	      msutils.h \
++		       	      waveheader.h \
++			      alsacard.h \
++			      msavdecoder.h \
++			      msfifo.h \
++		      	      msilbcenc.h \
++			      msossread.h \
++			      msrtprecv.h \
++			      msspeexenc.h \
++		    	      msv4l.h \
++			      g711common.h \
++			      msavencoder.h \
++			      msfilter.h \
++			      msLPC10decoder.h \
++			      msosswrite.h \
++			      msrtpsend.h \
++			      mssync.h \
++			      msvideosource.h \
++                              jackcard.h \
++			      msbuffer.h \
++			      msGSMdecoder.h \
++			      msLPC10encoder.h \
++			      msqdispatcher.h \
++			      mssdlout.h \
++			      mstimer.h \
++		 	      mswrite.h \
++	                      mediastream.h \
++			      mscodec.h \
++			      msGSMencoder.h \
++			      msMUlawdec.h \
++			      msqueue.h \
++		       	      mssoundread.h \
++			      mstruespeechdecoder.h \
++			      osscard.h \
++                              msAlawdec.h \
++			      mscopy.h \
++			      ms.h \
++		  	      msMUlawenc.h \
++			      msread.h \
++		      	      mssoundwrite.h \
++			      mstruespeechencoder.h \
++			      sndcard.h
++
++
++libmediastreamer_la_LIBADD= $(GLIB_LIBS) $(ORTP_LIBS) $(SPEEX_LIBS)
++
++AM_CFLAGS=$(GLIB_CFLAGS) -DG_LOG_DOMAIN=\"MediaStreamer\" $(ORTP_CFLAGS) $(IPV6_CFLAGS) $(ILBC_CFLAGS) $(SPEEX_CFLAGS)
++
++INCLUDES=  -I$(srcdir)/../../.. $(ORTP_CFLAGS)
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h	(revision 586398)
+@@ -0,0 +1,49 @@
++/*
++  The mediastreamer library aims at providing modular media processing and I/O
++	for linphone, but also for any telephony application.
++  Copyright (C) 2001  Simon MORLAT simon.morlat at linphone.org
++  										
++  This library is free software; you can redistribute it and/or
++  modify it under the terms of the GNU Lesser General Public
++  License as published by the Free Software Foundation; either
++  version 2.1 of the License, or (at your option) any later version.
++
++  This library is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public
++  License along with this library; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef MSQUEUE_H
++#define MSQUEUE_H
++
++#include "msbuffer.h"
++
++/* for the moment these are stupid queues limited to one element*/
++
++typedef struct _MSQueue
++{
++	MSMessage *first;
++	MSMessage *last;
++	gint size;
++	void *prev_data; /*user data, usually the writting filter*/
++	void *next_data; /* user data, usually the reading filter*/
++}MSQueue;
++
++
++MSQueue * ms_queue_new();
++
++MSMessage *ms_queue_get(MSQueue *q);
++
++void ms_queue_put(MSQueue *q, MSMessage *m);
++
++#define ms_queue_can_get(q) ( (q)->size!=0 )
++
++#define ms_queue_destroy(q) g_free(q)
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h	(revision 586398)
+@@ -0,0 +1,171 @@
++/*
++ *  PCM - A-Law conversion
++ *  Copyright (c) 2000 by Abramo Bagnara <abramo at alsa-project.org>
++ *
++ *  Wrapper for linphone Codec class by Simon Morlat <simon.morlat at free.fr>
++ */
++
++static inline int val_seg(int val)
++{
++	int r = 0;
++	val >>= 7;
++	if (val & 0xf0) {
++		val >>= 4;
++		r += 4;
++	}
++	if (val & 0x0c) {
++		val >>= 2;
++		r += 2;
++	}
++	if (val & 0x02)
++		r += 1;
++	return r;
++}
++
++/*
++ * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
++ *
++ * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
++ *
++ *		Linear Input Code	Compressed Code
++ *	------------------------	---------------
++ *	0000000wxyza			000wxyz
++ *	0000001wxyza			001wxyz
++ *	000001wxyzab			010wxyz
++ *	00001wxyzabc			011wxyz
++ *	0001wxyzabcd			100wxyz
++ *	001wxyzabcde			101wxyz
++ *	01wxyzabcdef			110wxyz
++ *	1wxyzabcdefg			111wxyz
++ *
++ * For further information see John C. Bellamy's Digital Telephony, 1982,
++ * John Wiley & Sons, pps 98-111 and 472-476.
++ */
++
++static inline unsigned char s16_to_alaw(int pcm_val)
++{
++	int		mask;
++	int		seg;
++	unsigned char	aval;
++
++	if (pcm_val >= 0) {
++		mask = 0xD5;
++	} else {
++		mask = 0x55;
++		pcm_val = -pcm_val;
++		if (pcm_val > 0x7fff)
++			pcm_val = 0x7fff;
++	}
++
++	if (pcm_val < 256)
++		aval = pcm_val >> 4;
++	else {
++		/* Convert the scaled magnitude to segment number. */
++		seg = val_seg(pcm_val);
++		aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
++	}
++	return aval ^ mask;
++}
++
++/*
++ * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
++ *
++ */
++static inline int alaw_to_s16(unsigned char a_val)
++{
++	int		t;
++	int		seg;
++
++	a_val ^= 0x55;
++	t = a_val & 0x7f;
++	if (t < 16)
++		t = (t << 4) + 8;
++	else {
++		seg = (t >> 4) & 0x07;
++		t = ((t & 0x0f) << 4) + 0x108;
++		t <<= seg -1;
++	}
++	return ((a_val & 0x80) ? t : -t);
++}
++/*
++ * s16_to_ulaw() - Convert a linear PCM value to u-law
++ *
++ * In order to simplify the encoding process, the original linear magnitude
++ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
++ * (33 - 8191). The result can be seen in the following encoding table:
++ *
++ *	Biased Linear Input Code	Compressed Code
++ *	------------------------	---------------
++ *	00000001wxyza			000wxyz
++ *	0000001wxyzab			001wxyz
++ *	000001wxyzabc			010wxyz
++ *	00001wxyzabcd			011wxyz
++ *	0001wxyzabcde			100wxyz
++ *	001wxyzabcdef			101wxyz
++ *	01wxyzabcdefg			110wxyz
++ *	1wxyzabcdefgh			111wxyz
++ *
++ * Each biased linear code has a leading 1 which identifies the segment
++ * number. The value of the segment number is equal to 7 minus the number
++ * of leading 0's. The quantization interval is directly available as the
++ * four bits wxyz.  * The trailing bits (a - h) are ignored.
++ *
++ * Ordinarily the complement of the resulting code word is used for
++ * transmission, and so the code word is complemented before it is returned.
++ *
++ * For further information see John C. Bellamy's Digital Telephony, 1982,
++ * John Wiley & Sons, pps 98-111 and 472-476.
++ */
++
++static inline unsigned char s16_to_ulaw(int pcm_val)	/* 2's complement (16-bit range) */
++{
++	int mask;
++	int seg;
++	unsigned char uval;
++
++	if (pcm_val < 0) {
++		pcm_val = 0x84 - pcm_val;
++		mask = 0x7f;
++	} else {
++		pcm_val += 0x84;
++		mask = 0xff;
++	}
++	if (pcm_val > 0x7fff)
++		pcm_val = 0x7fff;
++
++	/* Convert the scaled magnitude to segment number. */
++	seg = val_seg(pcm_val);
++
++	/*
++	 * Combine the sign, segment, quantization bits;
++	 * and complement the code word.
++	 */
++	uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
++	return uval ^ mask;
++}
++
++/*
++ * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
++ *
++ * First, a biased linear code is derived from the code word. An unbiased
++ * output can then be obtained by subtracting 33 from the biased code.
++ *
++ * Note that this function expects to be passed the complement of the
++ * original code word. This is in keeping with ISDN conventions.
++ */
++static inline int ulaw_to_s16(unsigned char u_val)
++{
++	int t;
++
++	/* Complement to obtain normal u-law value. */
++	u_val = ~u_val;
++
++	/*
++	 * Extract and bias the quantization bits. Then
++	 * shift up by the segment number and subtract out the bias.
++	 */
++	t = ((u_val & 0x0f) << 3) + 0x84;
++	t <<= (u_val & 0x70) >> 4;
++
++	return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS=mediastreamer
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc	(revision 586398)
+@@ -0,0 +1,92 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "taskrunner.h"
++#include "task.h"
++#include <algorithm>
++
++
++namespace buzz {
++
++TaskRunner::~TaskRunner() {
++  // this kills and deletes children silently!
++  AbortAllChildren();
++  RunTasks();
++}
++
++void
++TaskRunner::StartTask(Task * task) {
++  tasks_.push_back(task);
++  WakeTasks();
++}
++
++void
++TaskRunner::RunTasks() {
++  // Running continues until all tasks are Blocked (ok for a small # of tasks)
++  if (tasks_running_) {
++    return; // don't reenter
++  }
++
++  tasks_running_ = true;
++
++  int did_run = true;
++  while (did_run) {
++    did_run = false;
++    // use indexing instead of iterators because tasks_ may grow
++    for (size_t i = 0; i < tasks_.size(); ++i) {
++      while (!tasks_[i]->Blocked()) {
++        tasks_[i]->Step();
++        did_run = true;
++      }
++    }
++  }
++  // Tasks are deleted when running has paused
++  for (size_t i = 0; i < tasks_.size(); ++i) {
++    if (tasks_[i]->IsDone()) {
++      Task* task = tasks_[i];
++      delete task;
++      tasks_[i] = NULL;
++    }
++  }
++  // Finally, remove nulls
++  tasks_.erase(std::remove(tasks_.begin(), tasks_.end(), (Task *)NULL), tasks_.end());
++
++  tasks_running_ = false;
++}
++
++void
++TaskRunner::PollTasks() {
++  // every task gets hit once with a poll - they wake if needed
++  for (size_t i = 0; i < tasks_.size(); ++i) {
++    if (!tasks_[i]->IsDone()) {
++      tasks_[i]->Poll();
++    }
++  }
++}
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h	(revision 586398)
+@@ -0,0 +1,138 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * linked_ptr - simple reference linked pointer
++ * (like reference counting, just using a linked list of the references
++ * instead of their count.)
++ *
++ * The implementation stores three pointers for every linked_ptr, but
++ * does not allocate anything on the free store.
++ */
++
++#ifndef _LINKED_PTR_H_
++#define _LINKED_PTR_H_
++
++/* For ANSI-challenged compilers, you may want to #define
++ * NO_MEMBER_TEMPLATES, explicit or mutable */
++#define NO_MEMBER_TEMPLATES
++
++template <class X> class linked_ptr
++{
++public:
++
++#ifndef NO_MEMBER_TEMPLATES
++#   define TEMPLATE_FUNCTION template <class Y>
++    TEMPLATE_FUNCTION friend class linked_ptr<Y>;
++#else
++#   define TEMPLATE_FUNCTION
++    typedef X Y;
++#endif
++
++    typedef X element_type;
++
++    explicit linked_ptr(X* p = 0) throw()
++        : itsPtr(p) {itsPrev = itsNext = this;}
++    ~linked_ptr()
++        {release();}
++    linked_ptr(const linked_ptr& r) throw()
++        {acquire(r);}
++    linked_ptr& operator=(const linked_ptr& r)
++    {
++        if (this != &r) {
++            release();
++            acquire(r);
++        }
++        return *this;
++    }
++
++#ifndef NO_MEMBER_TEMPLATES
++    template <class Y> friend class linked_ptr<Y>;
++    template <class Y> linked_ptr(const linked_ptr<Y>& r) throw()
++        {acquire(r);}
++    template <class Y> linked_ptr& operator=(const linked_ptr<Y>& r)
++    {
++        if (this != &r) {
++            release();
++            acquire(r);
++        }
++        return *this;
++    }
++#endif // NO_MEMBER_TEMPLATES
++
++    X& operator*()  const throw()   {return *itsPtr;}
++    X* operator->() const throw()   {return itsPtr;}
++    X* get()        const throw()   {return itsPtr;}
++    bool unique()   const throw()   {return itsPrev ? itsPrev==this : true;}
++
++private:
++    X*                          itsPtr;
++    mutable const linked_ptr*   itsPrev;
++    mutable const linked_ptr*   itsNext;
++
++    void acquire(const linked_ptr& r) throw()
++    { // insert this to the list
++        itsPtr = r.itsPtr;
++        itsNext = r.itsNext;
++        itsNext->itsPrev = this;
++        itsPrev = &r;
++#ifndef mutable
++        r.itsNext = this;
++#else // for ANSI-challenged compilers
++        (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
++#endif
++    }
++
++#ifndef NO_MEMBER_TEMPLATES
++    template <class Y> void acquire(const linked_ptr<Y>& r) throw()
++    { // insert this to the list
++        itsPtr = r.itsPtr;
++        itsNext = r.itsNext;
++        itsNext->itsPrev = this;
++        itsPrev = &r;
++#ifndef mutable
++        r.itsNext = this;
++#else // for ANSI-challenged compilers
++        (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
++#endif
++    }
++#endif // NO_MEMBER_TEMPLATES
++
++    void release()
++    { // erase this from the list, delete if unique
++        if (unique()) delete itsPtr;
++        else {
++            itsPrev->itsNext = itsNext;
++            itsNext->itsPrev = itsPrev;
++            itsPrev = itsNext = 0;
++        }
++        itsPtr = 0;
++    }
++};
++
++#endif // LINKED_PTR_H
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc	(revision 586398)
+@@ -0,0 +1,267 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/socketaddress.h"
++#include "talk/base/byteorder.h"
++#include "talk/base/logging.h"
++#include <cstring>
++#include <sstream>
++#include <cassert>
++
++#ifdef WIN32
++#undef SetPort
++int inet_aton(const char * cp, struct in_addr * inp) {
++  inp->s_addr = inet_addr(cp);
++  return (inp->s_addr == INADDR_NONE) ? 0 : 1;
++}
++#endif // WIN32
++
++#ifdef POSIX
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#endif
++
++#ifdef _DEBUG
++#define DISABLE_DNS 0
++#else // !_DEBUG
++#define DISABLE_DNS 0
++#endif // !_DEBUG
++
++namespace cricket {
++
++SocketAddress::SocketAddress() {
++  Zero();
++}
++
++SocketAddress::SocketAddress(const std::string& hostname, int port, bool use_dns) {
++  Zero();
++  SetIP(hostname, use_dns);
++  SetPort(port);
++}
++
++SocketAddress::SocketAddress(uint32 ip, int port) {
++  Zero();
++  SetIP(ip);
++  SetPort(port);
++}
++
++SocketAddress::SocketAddress(const SocketAddress& addr) {
++  Zero();
++  this->operator=(addr);
++}
++
++void SocketAddress::Zero() {
++  ip_ = 0;
++  port_ = 0;
++}
++
++SocketAddress& SocketAddress::operator =(const SocketAddress& addr) {
++  hostname_ = addr.hostname_;
++  ip_ = addr.ip_;
++  port_ = addr.port_;
++  return *this;
++}
++
++void SocketAddress::SetIP(uint32 ip) {
++  hostname_.clear();
++  ip_ = ip;
++}
++
++bool SocketAddress::SetIP(const std::string& hostname, bool use_dns) {
++  hostname_ = hostname;
++  ip_ = 0;
++  return Resolve(true, use_dns);
++}
++
++void SocketAddress::SetResolvedIP(uint32 ip) {
++  ip_ = ip;
++}
++
++void SocketAddress::SetPort(int port) {
++  assert((0 <= port) && (port < 65536));
++  port_ = port;
++}
++
++uint32 SocketAddress::ip() const {
++  return ip_;
++}
++
++uint16 SocketAddress::port() const {
++  return port_;
++}
++
++std::string SocketAddress::IPAsString() const {
++  if (!hostname_.empty())
++    return hostname_;
++  return IPToString(ip_);
++}
++
++std::string SocketAddress::PortAsString() const {
++  std::ostringstream ost;
++  ost << port_;
++  return ost.str();
++}
++
++std::string SocketAddress::ToString() const {
++  std::ostringstream ost;
++  ost << IPAsString();
++  ost << ":";
++  ost << port();
++  return ost.str();
++}
++
++bool SocketAddress::IsAny() const {
++  return (ip_ == 0);
++}
++
++bool SocketAddress::IsLocalIP() const {
++  return (ip_ >> 24) == 127;
++}
++
++bool SocketAddress::IsPrivateIP() const {
++  return ((ip_ >> 24) == 127) ||
++         ((ip_ >> 24) == 10) ||
++         ((ip_ >> 20) == ((172 << 4) | 1)) ||
++         ((ip_ >> 16) == ((192 << 8) | 168));
++}
++
++bool SocketAddress::IsUnresolved() const {
++  return IsAny() && !hostname_.empty();
++}
++
++bool SocketAddress::Resolve(bool force, bool use_dns) {
++  if (hostname_.empty()) {
++    // nothing to resolve
++  } else if (!force && !IsAny()) {
++    // already resolved
++  } else if (uint32 ip = StringToIP(hostname_, use_dns)) {
++    ip_ = ip;
++  } else {
++    return false;
++  }
++  return true;
++}
++
++bool SocketAddress::operator ==(const SocketAddress& addr) const {
++  return EqualIPs(addr) && EqualPorts(addr);
++}
++
++bool SocketAddress::operator <(const SocketAddress& addr) const {
++  if (ip_ < addr.ip_)
++    return true;
++  else if (addr.ip_ < ip_)
++    return false;
++
++  // We only check hostnames if both IPs are zero.  This matches EqualIPs()
++  if (addr.ip_ == 0) {
++    if (hostname_ < addr.hostname_)
++      return true;
++    else if (addr.hostname_ < hostname_)
++      return false;
++  }
++
++  return port_ < addr.port_;
++}
++
++bool SocketAddress::EqualIPs(const SocketAddress& addr) const {
++  return (ip_ == addr.ip_) && ((ip_ != 0) || (hostname_ == addr.hostname_));
++}
++
++bool SocketAddress::EqualPorts(const SocketAddress& addr) const {
++  return (port_ == addr.port_);
++}
++
++size_t SocketAddress::Hash() const {
++  size_t h = 0;
++  h ^= ip_;
++  h ^= port_ | (port_ << 16);
++  return h;
++}
++
++size_t SocketAddress::Size_() const {
++  return sizeof(ip_) + sizeof(port_);
++}
++
++void SocketAddress::Write_(char* buf, int len) const {
++  // TODO: Depending on how this is used, we may want/need to write hostname
++  assert((size_t)len >= Size_());
++  reinterpret_cast<uint32*>(buf)[0] = ip_;
++  buf += sizeof(ip_);
++  reinterpret_cast<uint16*>(buf)[0] = port_;
++}
++
++void SocketAddress::Read_(const char* buf, int len) {
++  assert((size_t)len >= Size_());
++  ip_ = reinterpret_cast<const uint32*>(buf)[0];
++  buf += sizeof(ip_);
++  port_ = reinterpret_cast<const uint16*>(buf)[0];
++}
++
++std::string SocketAddress::IPToString(uint32 ip) {
++  std::ostringstream ost;
++  ost << ((ip >> 24) & 0xff);
++  ost << '.';
++  ost << ((ip >> 16) & 0xff);
++  ost << '.';
++  ost << ((ip >> 8) & 0xff);
++  ost << '.';
++  ost << ((ip >> 0) & 0xff);
++  return ost.str();
++}
++
++uint32 SocketAddress::StringToIP(const std::string& hostname, bool use_dns) {
++  uint32 ip = 0;
++  in_addr addr;
++  if (inet_aton(hostname.c_str(), &addr) != 0) {
++    ip = NetworkToHost32(addr.s_addr);
++  } else if (use_dns) {
++    // Note: this is here so we can spot spurious DNS resolutions for a while
++    LOG(INFO) << "=== DNS RESOLUTION (" << hostname << ") ===";
++#if DISABLE_DNS
++    LOG(WARNING) << "*** DNS DISABLED ***";
++#if WIN32
++    WSASetLastError(WSAHOST_NOT_FOUND);
++#endif // WIN32
++#endif // DISABLE_DNS
++    if (hostent * pHost = gethostbyname(hostname.c_str())) {
++      ip = NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[0]));
++    } else {
++#if WIN32
++      LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError();
++#else
++      LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno);
++#endif
++    }
++    LOG(INFO) << hostname << " resolved to " << IPToString(ip);
++  }
++  return ip;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc	(revision 586398)
+@@ -0,0 +1,83 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/logging.h"
++#include <cassert>
++#include <cstring>
++#include <iostream>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++const int BUF_SIZE = 64 * 1024;
++
++AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket) {
++  size_ = BUF_SIZE;
++  buf_ = new char[size_];
++
++  assert(socket_);
++  // The socket should start out readable but not writable.
++  socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
++}
++
++AsyncUDPSocket::~AsyncUDPSocket() {
++  delete [] buf_;
++}
++
++void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
++  assert(socket == socket_);
++
++  SocketAddress remote_addr;
++  int len = socket_->RecvFrom(buf_, size_, &remote_addr);
++  if (len < 0) {
++    // TODO: Do something better like forwarding the error to the user.
++    PLOG(LS_ERROR, socket_->GetError()) << "recvfrom";
++    return;
++  }
++
++  // TODO: Make sure that we got all of the packet.  If we did not, then we
++  // should resize our buffer to be large enough.
++
++  SignalReadPacket(buf_, (size_t)len, remote_addr, this);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h	(revision 586398)
+@@ -0,0 +1,59 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __ASYNCUDPSOCKET_H__
++#define __ASYNCUDPSOCKET_H__
++
++#include "talk/base/asyncpacketsocket.h"
++#include "talk/base/socketfactory.h"
++
++namespace cricket {
++
++// Provides the ability to receive packets asynchronously.  Sends are not
++// buffered since it is acceptable to drop packets under high load.
++class AsyncUDPSocket : public AsyncPacketSocket {
++public:
++  AsyncUDPSocket(AsyncSocket* socket);
++  virtual ~AsyncUDPSocket();
++
++private:
++  char* buf_;
++  size_t size_;
++
++  // Called when the underlying socket is ready to be read from.
++  void OnReadEvent(AsyncSocket* socket);
++};
++
++// Creates a new socket for sending asynchronous UDP packets using an
++// asynchronous socket from the given factory.
++inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) {
++  return new AsyncUDPSocket(factory->CreateAsyncSocket(SOCK_DGRAM));
++}
++
++} // namespace cricket
++
++#endif // __ASYNCSUDPOCKET_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __BYTEORDER_H__
++#define __BYTEORDER_H__
++
++#include "talk/base/basictypes.h"
++
++#ifdef POSIX
++extern "C" {
++#include <arpa/inet.h>
++}
++#endif
++
++#ifdef WIN32
++#include <winsock2.h>
++#endif
++
++namespace cricket {
++
++inline uint16 HostToNetwork16(uint16 n) {
++  return htons(n);
++}
++
++inline uint32 HostToNetwork32(uint32 n) {
++  return htonl(n);
++}
++
++inline uint16 NetworkToHost16(uint16 n) {
++  return ntohs(n);
++}
++
++inline uint32 NetworkToHost32(uint32 n) {
++  return ntohl(n);
++}
++
++} // namespace cricket
++
++#endif // __BYTEORDER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc	(revision 586398)
+@@ -0,0 +1,238 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "task.h"
++#include "taskrunner.h"
++
++#include <algorithm>
++
++namespace buzz {
++
++Task::Task(Task * parent) :
++    state_(STATE_INIT),
++    parent_(parent),
++    blocked_(false),
++    done_(false),
++    aborted_(false),
++    busy_(false),
++    error_(false),
++    child_error_(false),
++    start_time_(0) {
++  runner_ = ((parent == NULL) ? (TaskRunner *)this : parent->GetRunner());
++  if (parent_ != NULL) {
++    parent_->AddChild(this);
++  }
++}
++
++unsigned long long
++Task::CurrentTime() {
++  return runner_->CurrentTime();
++}
++
++unsigned long long
++Task::ElapsedTime() {
++  return CurrentTime() - start_time_;
++}
++
++void
++Task::Start() {
++  if (state_ != STATE_INIT)
++    return;
++  GetRunner()->StartTask(this);
++  start_time_ = CurrentTime();
++}
++
++void
++Task::Step() {
++  if (done_) {
++#ifdef DEBUG
++    // we do not know how !blocked_ happens when done_ - should be impossible.
++    // But it causes problems, so in retail build, we force blocked_, and
++    // under debug we assert.
++    assert(blocked_);
++#else
++    blocked_ = true;
++#endif
++    return;
++  }
++
++  // Async Error() was called
++  if (error_) {
++    done_ = true;
++    state_ = STATE_ERROR;
++    blocked_ = true;
++//   obsolete - an errored task is not considered done now
++//   SignalDone();
++    Stop();
++    return;
++  }
++
++  busy_ = true;
++  int new_state = Process(state_);
++  busy_ = false;
++
++  if (aborted_) {
++    Abort(true); // no need to wake because we're awake
++    return;
++  }
++  
++  if (new_state == STATE_BLOCKED) {
++    blocked_ = true;
++  }
++  else {
++    state_ = new_state;
++    blocked_ = false;
++  }
++  
++  if (new_state == STATE_DONE) {
++    done_ = true;
++  }
++  else if (new_state == STATE_ERROR) {
++    done_ = true;
++    error_ = true;
++  }
++
++  if (done_) {
++//  obsolete - call this yourself
++//    SignalDone();
++    Stop();
++    blocked_ = true;
++  }
++}
++
++void
++Task::Abort(bool nowake) {
++  if (aborted_ || done_)
++    return;
++  aborted_ = true;
++  if (!busy_) {
++    done_ = true;
++    blocked_ = true;
++    error_ = true;
++    Stop();
++    if (!nowake)
++      Wake(); // to self-delete
++  }
++}
++
++void
++Task::Wake() {
++  if (done_)
++    return;
++  if (blocked_) {
++    blocked_ = false;
++    GetRunner()->WakeTasks();
++  }
++}
++
++void
++Task::Error() {
++  if (error_ || done_)
++    return;
++  error_ = true;
++  Wake();
++}
++
++std::string
++Task::GetStateName(int state) const {
++  static const std::string STR_BLOCKED("BLOCKED");
++  static const std::string STR_INIT("INIT");
++  static const std::string STR_START("START");
++  static const std::string STR_DONE("DONE");
++  static const std::string STR_ERROR("ERROR");
++  static const std::string STR_RESPONSE("RESPONSE");
++  static const std::string STR_HUH("??");
++  switch (state) {
++    case STATE_BLOCKED: return STR_BLOCKED;
++    case STATE_INIT: return STR_INIT;
++    case STATE_START: return STR_START;
++    case STATE_DONE: return STR_DONE;
++    case STATE_ERROR: return STR_ERROR;
++    case STATE_RESPONSE: return STR_RESPONSE;
++  }
++  return STR_HUH;
++}
++
++int Task::Process(int state) {
++  switch (state) {
++    case STATE_INIT:
++      return STATE_START;
++    case STATE_START:
++      return ProcessStart();
++    case STATE_RESPONSE:
++      return ProcessResponse();
++    case STATE_DONE:
++    case STATE_ERROR:
++      return STATE_BLOCKED;
++  }
++  return STATE_ERROR;
++}
++
++void
++Task::AddChild(Task * child) {
++  children_.insert(child);
++}
++
++bool
++Task::AllChildrenDone() {
++  for (ChildSet::iterator it = children_.begin(); it != children_.end(); ++it) {
++    if (!(*it)->IsDone())
++      return false;
++  }
++  return true;
++}
++
++bool
++Task::AnyChildError() {
++  return child_error_;
++}
++
++void
++Task::AbortAllChildren() {
++  if (children_.size() > 0) {
++    ChildSet copy = children_;
++    for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) {
++      (*it)->Abort(true); // Note we do not wake
++    }
++  }
++}
++
++void
++Task::Stop() {
++  AbortAllChildren(); // No need to wake because we're either awake or in abort
++  parent_->OnChildStopped(this);
++}
++
++void
++Task::OnChildStopped(Task * child) {
++  if (child->HasError())
++    child_error_ = true;
++  children_.erase(child);
++}
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h	(revision 586398)
+@@ -0,0 +1,259 @@
++#ifndef SCOPED_PTR_H
++#define SCOPED_PTR_H
++
++//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
++//  Copyright (c) 2001, 2002 Peter Dimov
++//
++//  Permission to copy, use, modify, sell and distribute this software
++//  is granted provided this copyright notice appears in all copies.
++//  This software is provided "as is" without express or implied
++//  warranty, and with no claim as to its suitability for any purpose.
++//
++//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
++//
++
++//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
++//  of the object pointed to, either on destruction of the scoped_ptr or via
++//  an explicit reset(). scoped_ptr is a simple solution for simple needs;
++//  use shared_ptr or std::auto_ptr if your needs are more complex.
++
++//  scoped_ptr_malloc added in by Google.  When one of
++//  these goes out of scope, instead of doing a delete or delete[], it
++//  calls free().  scoped_ptr_malloc<char> is likely to see much more
++//  use than any other specializations.
++
++//  release() added in by Google. Use this to conditionally
++//  transfer ownership of a heap-allocated object to the caller, usually on
++//  method success.
++
++#include <cstddef>            // for std::ptrdiff_t
++#include <assert.h>           // for assert
++#include <stdlib.h>           // for free() decl
++
++#ifdef _WIN32
++namespace std { using ::ptrdiff_t; };
++#endif // _WIN32
++
++namespace buzz {
++
++template <typename T>
++class scoped_ptr {
++ private:
++
++  T* ptr;
++
++  scoped_ptr(scoped_ptr const &);
++  scoped_ptr & operator=(scoped_ptr const &);
++
++ public:
++
++  typedef T element_type;
++
++  explicit scoped_ptr(T* p = 0): ptr(p) {}
++
++  ~scoped_ptr() {
++    typedef char type_must_be_complete[sizeof(T)];
++    delete ptr;
++  }
++
++  void reset(T* p = 0) {
++    typedef char type_must_be_complete[sizeof(T)];
++
++    if (ptr != p) {
++      delete ptr;
++      ptr = p;
++    }
++  }
++
++  T& operator*() const {
++    assert(ptr != 0);
++    return *ptr;
++  }
++
++  T* operator->() const  {
++    assert(ptr != 0);
++    return ptr;
++  }
++
++  T* get() const  {
++    return ptr;
++  }
++
++  void swap(scoped_ptr & b) {
++    T* tmp = b.ptr;
++    b.ptr = ptr;
++    ptr = tmp;
++  }
++
++  T* release() {
++    T* tmp = ptr;
++    ptr = 0;
++    return tmp;
++  }
++  
++  T** accept() {
++    if (ptr) {
++      delete ptr;
++      ptr = 0;
++    }
++    return &ptr;
++  }
++
++  T** use() {
++    return &ptr;
++  }
++};
++
++template<typename T> inline
++void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
++  a.swap(b);
++}
++
++
++
++
++//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
++//  is guaranteed, either on destruction of the scoped_array or via an explicit
++//  reset(). Use shared_array or std::vector if your needs are more complex.
++
++template<typename T>
++class scoped_array {
++ private:
++
++  T* ptr;
++
++  scoped_array(scoped_array const &);
++  scoped_array & operator=(scoped_array const &);
++
++ public:
++
++  typedef T element_type;
++
++  explicit scoped_array(T* p = 0) : ptr(p) {}
++
++  ~scoped_array() {
++    typedef char type_must_be_complete[sizeof(T)];
++    delete[] ptr;
++  }
++
++  void reset(T* p = 0) {
++    typedef char type_must_be_complete[sizeof(T)];
++
++    if (ptr != p) {
++      delete [] ptr;
++      ptr = p;
++    }
++  }
++
++  T& operator[](std::ptrdiff_t i) const {
++    assert(ptr != 0);
++    assert(i >= 0);
++    return ptr[i];
++  }
++
++  T* get() const {
++    return ptr;
++  }
++
++  void swap(scoped_array & b) {
++    T* tmp = b.ptr;
++    b.ptr = ptr;
++    ptr = tmp;
++  }
++
++  T* release() {
++    T* tmp = ptr;
++    ptr = 0;
++    return tmp;
++  }
++
++  T** accept() {
++    if (ptr) {
++      delete [] ptr;
++      ptr = 0;
++    }
++    return &ptr;
++  }
++};
++
++template<class T> inline
++void swap(scoped_array<T>& a, scoped_array<T>& b) {
++  a.swap(b);
++}
++
++// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
++// second template argument, the function used to free the object.
++
++template<typename T, void (*FF)(void*) = free> class scoped_ptr_malloc {
++ private:
++
++  T* ptr;
++
++  scoped_ptr_malloc(scoped_ptr_malloc const &);
++  scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
++
++ public:
++
++  typedef T element_type;
++
++  explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
++
++  ~scoped_ptr_malloc() {
++    typedef char type_must_be_complete[sizeof(T)];
++    FF(static_cast<void*>(ptr));
++  }
++
++  void reset(T* p = 0) {
++    typedef char type_must_be_complete[sizeof(T)];
++
++    if (ptr != p) {
++      FF(static_cast<void*>(ptr));
++      ptr = p;
++    }
++  }
++
++  T& operator*() const {
++    assert(ptr != 0);
++    return *ptr;
++  }
++
++  T* operator->() const {
++    assert(ptr != 0);
++    return ptr;
++  }
++
++  T* get() const {
++    return ptr;
++  }
++
++  void swap(scoped_ptr_malloc & b) {
++    T* tmp = b.ptr;
++    b.ptr = ptr;
++    ptr = tmp;
++  }
++
++  T* release() {
++    T* tmp = ptr;
++    ptr = 0;
++    return tmp;
++  }
++
++  T** accept() {
++    if (ptr) {
++      FF(static_cast<void*>(ptr));
++      ptr = 0;
++    }
++    return &ptr;
++  }
++};
++
++template<typename T, void (*FF)(void*)> inline
++void swap(scoped_ptr_malloc<T,FF>& a, scoped_ptr_malloc<T,FF>& b) {
++  a.swap(b);
++}
++
++}
++
++using buzz::scoped_ptr;
++
++#endif  // #ifndef SCOPED_PTR_H
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __BASICTYPES_H__
++#define __BASICTYPES_H__
++
++#ifdef COMPILER_MSVC
++typedef __int64 int64;
++#else
++typedef long long int64;
++#endif /* COMPILER_MSVC */
++typedef long int32;
++typedef short int16;
++typedef char int8;
++
++#ifdef COMPILER_MSVC
++typedef unsigned __int64 uint64;
++typedef __int64 int64;
++#else
++typedef unsigned long long uint64;
++typedef long long int64;
++#endif /* COMPILER_MSVC */
++typedef unsigned long uint32;
++typedef unsigned short uint16;
++typedef unsigned char uint8;
++
++#ifdef WIN32
++typedef int socklen_t;
++#endif
++
++namespace cricket {
++  template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
++  template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
++}
++
++// A macro to disallow the evil copy constructor and operator= functions
++// This should be used in the private: declarations for a class
++#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
++  TypeName(const TypeName&);                    \
++  void operator=(const TypeName&)
++
++// A macro to disallow all the implicit constructors, namely the
++// default constructor, copy constructor and operator= functions.
++//
++// This should be used in the private: declarations for a class
++// that wants to prevent anyone from instantiating it. This is
++// especially useful for classes containing only static methods.
++#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
++  TypeName();                                    \
++  DISALLOW_EVIL_CONSTRUCTORS(TypeName)
++
++#ifndef UNUSED
++#define UNUSED(x) Unused(static_cast<const void *>(&x))
++#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
++#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
++#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
++#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
++inline void Unused(const void *) { }
++#endif // UNUSED
++
++#endif // __BASICTYPES_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h	(revision 586398)
+@@ -0,0 +1,47 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __JTIME_H__
++#define __JTIME_H__
++
++#include "talk/base/basictypes.h"
++
++namespace cricket {
++
++// Returns the current time in milliseconds.
++uint32 Time();
++
++// TODO: Delete this old version.
++#define GetMillisecondCount Time
++
++// Comparisons between time values, which can wrap around.
++bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier);
++int32 TimeDiff(uint32 later, uint32 earlier);
++
++} // namespace cricket
++
++#endif // __TIME_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc	(revision 586398)
+@@ -0,0 +1,58 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/socketaddresspair.h"
++
++namespace cricket {
++
++SocketAddressPair::SocketAddressPair(
++    const SocketAddress& src, const SocketAddress& dest)
++    : src_(src), dest_(dest) {
++}
++
++
++bool SocketAddressPair::operator ==(const SocketAddressPair& p) const {
++  return (src_ == p.src_) && (dest_ == p.dest_);
++}
++
++bool SocketAddressPair::operator <(const SocketAddressPair& p) const {
++  if (src_ < p.src_)
++    return true;
++  if (p.src_ < src_)
++    return false;
++  if (dest_ < p.dest_)
++    return true;
++  if (p.dest_ < dest_)
++    return false;
++  return false;
++}
++
++size_t SocketAddressPair::Hash() const {
++  return src_.Hash() ^ dest_.Hash();
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __PHYSICALSOCKETSERVER_H__
++#define __PHYSICALSOCKETSERVER_H__
++
++#include "talk/base/asyncfile.h"
++#include "talk/base/socketserver.h"
++#include "talk/base/criticalsection.h"
++#include <vector>
++
++#ifdef POSIX
++typedef int SOCKET;
++#endif // POSIX
++
++namespace cricket { 
++
++class Dispatcher;
++class Signaler;
++
++// A socket server that provides the real sockets of the underlying OS.
++class PhysicalSocketServer : public SocketServer {
++public:
++  PhysicalSocketServer();
++  virtual ~PhysicalSocketServer();
++
++  // SocketFactory:
++  virtual Socket* CreateSocket(int type);
++  virtual AsyncSocket* CreateAsyncSocket(int type);
++
++  // Internal Factory for Accept
++  AsyncSocket* WrapSocket(SOCKET s);
++
++  // SocketServer:
++  virtual bool Wait(int cms, bool process_io);
++  virtual void WakeUp();
++
++  void Add(Dispatcher* dispatcher);
++  void Remove(Dispatcher* dispatcher);
++
++#ifdef POSIX
++  AsyncFile* CreateFile(int fd);
++#endif
++
++private:
++  std::vector<Dispatcher*> dispatchers_;
++  Signaler* signal_wakeup_;
++  CriticalSection crit_;
++  bool fWait_;
++  uint32 last_tick_tracked_;
++  int last_tick_dispatch_count_;
++};
++
++} // namespace cricket
++
++#endif // __PHYSICALSOCKETSERVER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc	(revision 586398)
+@@ -0,0 +1,83 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/asyncpacketsocket.h"
++
++namespace cricket {
++
++AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) {
++}
++
++AsyncPacketSocket::~AsyncPacketSocket() {
++  delete socket_;
++}
++
++SocketAddress AsyncPacketSocket::GetLocalAddress() const {
++  return socket_->GetLocalAddress();
++}
++
++SocketAddress AsyncPacketSocket::GetRemoteAddress() const {
++  return socket_->GetRemoteAddress();
++}
++
++int AsyncPacketSocket::Bind(const SocketAddress& addr) {
++  return socket_->Bind(addr);
++}
++
++int AsyncPacketSocket::Connect(const SocketAddress& addr) {
++  return socket_->Connect(addr);
++}
++
++int AsyncPacketSocket::Send(const void *pv, size_t cb) {
++  return socket_->Send(pv, cb);
++}
++
++int AsyncPacketSocket::SendTo(
++    const void *pv, size_t cb, const SocketAddress& addr) {
++  return socket_->SendTo(pv, cb, addr);
++}
++
++int AsyncPacketSocket::Close() {
++  return socket_->Close();
++}
++
++int AsyncPacketSocket::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int AsyncPacketSocket::GetError() const {
++  return socket_->GetError();
++}
++
++void AsyncPacketSocket::SetError(int error) {
++  return socket_->SetError(error);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h	(revision 586398)
+@@ -0,0 +1,181 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SOCKETADAPTERS_H__
++#define __SOCKETADAPTERS_H__
++
++#include <map>
++
++#include "talk/base/asyncsocket.h"
++#include "talk/base/logging.h"
++#include "talk/xmpp/xmpppassword.h"  // TODO: move xmpppassword to base
++
++namespace cricket {
++
++///////////////////////////////////////////////////////////////////////////////
++
++class BufferedReadAdapter : public AsyncSocketAdapter {
++public:
++  BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size);
++  virtual ~BufferedReadAdapter();
++
++  virtual int Send(const void *pv, size_t cb);
++  virtual int Recv(void *pv, size_t cb);
++
++protected:
++  int DirectSend(const void *pv, size_t cb) { return AsyncSocketAdapter::Send(pv, cb); }
++
++  void BufferInput(bool on = true);
++  virtual void ProcessInput(char * data, size_t& len) = 0;
++
++  virtual void OnReadEvent(AsyncSocket * socket);
++
++private:
++  char * buffer_;
++  size_t buffer_size_, data_len_;
++  bool buffering_;
++};
++
++///////////////////////////////////////////////////////////////////////////////
++
++class AsyncSSLSocket : public BufferedReadAdapter {
++public:
++  AsyncSSLSocket(AsyncSocket* socket);
++
++  virtual int Connect(const SocketAddress& addr);
++
++protected:
++  virtual void OnConnectEvent(AsyncSocket * socket);
++  virtual void ProcessInput(char * data, size_t& len);
++};
++
++///////////////////////////////////////////////////////////////////////////////
++
++class AsyncHttpsProxySocket : public BufferedReadAdapter {
++public:
++  AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
++    const std::string& username, const buzz::XmppPassword& password);
++  virtual ~AsyncHttpsProxySocket();
++
++  virtual int Connect(const SocketAddress& addr);
++  virtual SocketAddress GetRemoteAddress() const;
++  virtual int Close();
++
++  struct AuthContext {
++    std::string auth_method;
++    AuthContext(const std::string& auth) : auth_method(auth) { }
++    virtual ~AuthContext() { }
++  };
++
++  // 'context' is used by this function to record information between calls.
++  // Start by passing a null pointer, then pass the same pointer each additional
++  // call.  When the authentication attempt is finished, delete the context.
++  enum AuthResult { AR_RESPONSE, AR_IGNORE, AR_CREDENTIALS, AR_ERROR };
++  static AuthResult Authenticate(const char * challenge, size_t len,
++    const SocketAddress& server,
++    const std::string& method, const std::string& uri,
++    const std::string& username, const buzz::XmppPassword& password,
++    AuthContext *& context, std::string& response, std::string& auth_method);
++
++protected:
++  virtual void OnConnectEvent(AsyncSocket * socket);
++  virtual void OnCloseEvent(AsyncSocket * socket, int err);
++  virtual void ProcessInput(char * data, size_t& len);
++
++  void SendRequest();
++  void ProcessLine(char * data, size_t len);
++  void EndResponse();
++  void Error(int error);
++
++  static void ParseAuth(const char * data, size_t len, std::string& method, std::map<std::string,std::string>& args);
++
++private:
++  SocketAddress proxy_, dest_;
++  std::string user_, headers_;
++  buzz::XmppPassword pass_;
++  size_t content_length_;
++  int defer_error_;
++  bool expect_close_;
++  enum ProxyState { PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS, PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR } state_;
++  AuthContext * context_;
++  std::string unknown_mechanisms_;
++};
++
++///////////////////////////////////////////////////////////////////////////////
++
++class AsyncSocksProxySocket : public BufferedReadAdapter {
++public:
++  AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
++    const std::string& username, const buzz::XmppPassword& password);
++
++  virtual int Connect(const SocketAddress& addr);
++  virtual SocketAddress GetRemoteAddress() const;
++
++protected:
++  virtual void OnConnectEvent(AsyncSocket * socket);
++  virtual void ProcessInput(char * data, size_t& len);
++
++  void SendHello();
++  void SendConnect();
++  void SendAuth();
++  void Error(int error);
++
++private:
++  SocketAddress proxy_, dest_;
++  std::string user_;
++  buzz::XmppPassword pass_;
++  enum SocksState { SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR } state_;
++};
++
++///////////////////////////////////////////////////////////////////////////////
++
++class LoggingAdapter : public AsyncSocketAdapter {
++public:
++  LoggingAdapter(AsyncSocket* socket, LoggingSeverity level,
++                 const char * label);
++
++  virtual int Send(const void *pv, size_t cb);
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
++  virtual int Recv(void *pv, size_t cb);
++  virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr);
++
++protected:
++  virtual void OnConnectEvent(AsyncSocket * socket);
++  virtual void OnCloseEvent(AsyncSocket * socket, int err);
++
++private:
++  void LogMultiline(bool input, const char * data, size_t len);
++
++  LoggingSeverity level_;
++  std::string label_;
++};
++
++///////////////////////////////////////////////////////////////////////////////
++
++} // namespace cricket
++
++#endif // __SOCKETADAPTERS_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h	(revision 586398)
+@@ -0,0 +1,53 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SOCKETSERVER_H__
++#define __SOCKETSERVER_H__
++
++#include "talk/base/socketfactory.h"
++
++namespace cricket {
++
++// Provides the ability to wait for activity on a set of sockets.  The Thread
++// class provides a nice wrapper on a socket server.
++//
++// The server is also a socket factory.  The sockets it creates will be
++// notified of asynchronous I/O from this server's Wait method.
++class SocketServer : public SocketFactory {
++public:
++
++  // Performs I/O or sleeps for the given number of milliseconds.
++  // If process_io is false, just sleeps until WakeUp.
++  virtual bool Wait(int cms, bool process_io) = 0;
++
++  // Causes the current wait (if one is in progress) to wake up.
++  virtual void WakeUp() = 0;
++};
++
++} // namespace cricket
++
++#endif // __SOCKETSERVER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc	(revision 586398)
+@@ -0,0 +1,194 @@
++
++//*********************************************************************
++//* Base64 - a simple base64 encoder and decoder.
++//*
++//*     Copyright (c) 1999, Bob Withers - bwit at pobox.com
++//*
++//* This code may be freely used for any purpose, either personal
++//* or commercial, provided the authors copyright notice remains
++//* intact.
++//*
++//* Enhancements by Stanley Yamane:
++//*     o reverse lookup table for the decode function
++//*     o reserve string buffer space in advance
++//*
++//*********************************************************************
++
++#include "talk/base/base64.h"
++
++using namespace std;
++
++static const char          fillchar = '=';
++static const string::size_type np = string::npos;
++
++const string Base64::Base64Table(
++   // 0000000000111111111122222222223333333333444444444455555555556666
++   // 0123456789012345678901234567890123456789012345678901234567890123
++     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
++
++// Decode Table gives the index of any valid base64 character in the Base64 table]
++// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
++
++                                               // 0  1  2  3  4  5  6  7  8  9
++const string::size_type Base64::DecodeTable[] = {
++      np,np,np,np,np,np,np,np,np,np,  // 0 - 9
++      np,np,np,np,np,np,np,np,np,np,  //10 -19
++      np,np,np,np,np,np,np,np,np,np,  //20 -29
++      np,np,np,np,np,np,np,np,np,np,  //30 -39
++      np,np,np,62,np,np,np,63,52,53,  //40 -49
++      54,55,56,57,58,59,60,61,np,np,  //50 -59
++      np,np,np,np,np, 0, 1, 2, 3, 4,  //60 -69
++       5, 6, 7, 8, 9,10,11,12,13,14,  //70 -79
++      15,16,17,18,19,20,21,22,23,24,  //80 -89
++      25,np,np,np,np,np,np,26,27,28,  //90 -99
++      29,30,31,32,33,34,35,36,37,38,  //100 -109
++      39,40,41,42,43,44,45,46,47,48,  //110 -119
++      49,50,51,np,np,np,np,np,np,np,  //120 -129
++      np,np,np,np,np,np,np,np,np,np,  //130 -139
++      np,np,np,np,np,np,np,np,np,np,  //140 -149
++      np,np,np,np,np,np,np,np,np,np,  //150 -159
++      np,np,np,np,np,np,np,np,np,np,  //160 -169
++      np,np,np,np,np,np,np,np,np,np,  //170 -179
++      np,np,np,np,np,np,np,np,np,np,  //180 -189
++      np,np,np,np,np,np,np,np,np,np,  //190 -199
++      np,np,np,np,np,np,np,np,np,np,  //200 -209
++      np,np,np,np,np,np,np,np,np,np,  //210 -219
++      np,np,np,np,np,np,np,np,np,np,  //220 -229
++      np,np,np,np,np,np,np,np,np,np,  //230 -239
++      np,np,np,np,np,np,np,np,np,np,  //240 -249
++      np,np,np,np,np,np               //250 -256
++};
++
++string Base64::encodeFromArray(const char * data, size_t len) {
++    size_t             i;
++    char               c;
++    string             ret;
++
++    ret.reserve(len * 2);
++
++    for (i = 0; i < len; ++i)
++    {
++        c = (data[i] >> 2) & 0x3f;
++        ret.append(1, Base64Table[c]);
++        c = (data[i] << 4) & 0x3f;
++        if (++i < len)
++            c |= (data[i] >> 4) & 0x0f;
++
++        ret.append(1, Base64Table[c]);
++        if (i < len)
++        {
++            c = (data[i] << 2) & 0x3f;
++            if (++i < len)
++                c |= (data[i] >> 6) & 0x03;
++
++            ret.append(1, Base64Table[c]);
++        }
++        else
++        {
++            ++i;
++            ret.append(1, fillchar);
++        }
++
++        if (i < len)
++        {
++            c = data[i] & 0x3f;
++            ret.append(1, Base64Table[c]);
++        }
++        else
++        {
++            ret.append(1, fillchar);
++        }
++    }
++
++    return(ret);
++}
++
++
++string Base64::encode(const string& data)
++{
++    string::size_type  i;
++    char               c;
++    string::size_type  len = data.length();
++    string             ret;
++
++    ret.reserve(len * 2);
++
++    for (i = 0; i < len; ++i)
++    {
++        c = (data[i] >> 2) & 0x3f;
++        ret.append(1, Base64Table[c]);
++        c = (data[i] << 4) & 0x3f;
++        if (++i < len)
++            c |= (data[i] >> 4) & 0x0f;
++
++        ret.append(1, Base64Table[c]);
++        if (i < len)
++        {
++            c = (data[i] << 2) & 0x3f;
++            if (++i < len)
++                c |= (data[i] >> 6) & 0x03;
++
++            ret.append(1, Base64Table[c]);
++        }
++        else
++        {
++            ++i;
++            ret.append(1, fillchar);
++        }
++
++        if (i < len)
++        {
++            c = data[i] & 0x3f;
++            ret.append(1, Base64Table[c]);
++        }
++        else
++        {
++            ret.append(1, fillchar);
++        }
++    }
++
++    return(ret);
++}
++
++string Base64::decode(const string& data)
++{
++    string::size_type  i;
++    char               c;
++    char               c1;
++    string::size_type  len = data.length();
++    string             ret;
++
++    ret.reserve(len);
++
++    for (i = 0; i < len; ++i)
++    {
++        c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
++        ++i;
++        c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
++        c = (c << 2) | ((c1 >> 4) & 0x3);
++        ret.append(1, c);
++        if (++i < len)
++        {
++            c = data[i];
++            if (fillchar == c)
++                break;
++
++            c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
++            c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
++            ret.append(1, c1);
++        }
++
++        if (++i < len)
++        {
++            c1 = data[i];
++            if (fillchar == c1)
++                break;
++
++            c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
++            c = ((c << 6) & 0xc0) | c1;
++            ret.append(1, c);
++        }
++    }
++
++    return(ret);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h	(revision 586398)
+@@ -0,0 +1,45 @@
++/*
++ * This is the header file for the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest.  This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ *
++ */
++
++#ifndef MD5_H
++#define MD5_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef long unsigned int uint32;
++typedef struct MD5Context MD5_CTX;
++
++#define md5byte unsigned char
++
++struct MD5Context {
++  uint32 buf[4];
++  uint32 bits[2];
++  uint32 in[16];
++};
++
++void MD5Init(struct MD5Context *context);
++void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
++void MD5Final(unsigned char digest[16], struct MD5Context *context);
++void MD5Transform(uint32 buf[4], uint32 const in[16]);
++
++#ifdef __cplusplus
++};
++#endif
++
++#endif /* !MD5_H */
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc	(revision 586398)
+@@ -0,0 +1,382 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/host.h"
++#include "talk/base/logging.h"
++#include "talk/base/network.h"
++#include "talk/base/socket.h" // this includes something that makes windows happy
++#include "talk/base/jtime.h"
++#include "talk/base/basicdefs.h"
++
++#include <algorithm>
++#include <cassert>
++#include <cfloat>
++#include <cmath>
++#include <sstream>
++
++#ifdef POSIX
++extern "C" {
++#include <sys/utsname.h>
++#include <sys/ioctl.h>
++#include <net/if.h>
++#include <unistd.h>
++#include <errno.h>
++}
++#endif // POSIX
++
++#ifdef WIN32
++#include <Iphlpapi.h>
++#endif
++
++namespace {
++
++const double kAlpha = 0.5; // weight for data infinitely far in the past
++const double kHalfLife = 2000; // half life of exponential decay (in ms)
++const double kLog2 = 0.693147180559945309417;
++const double kLambda = kLog2 / kHalfLife;
++
++// assume so-so quality unless data says otherwise
++const double kDefaultQuality = cricket::QUALITY_FAIR;
++
++typedef std::map<std::string,std::string> StrMap;
++
++void BuildMap(const StrMap& map, std::string& str) {
++  str.append("{");
++  bool first = true;
++  for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) {
++    if (!first) str.append(",");
++    str.append(i->first);
++    str.append("=");
++    str.append(i->second);
++    first = false;
++  }
++  str.append("}");
++}
++
++void ParseCheck(std::istringstream& ist, char ch) {
++  if (ist.get() != ch)
++    LOG(LERROR) << "Expecting '" << ch << "'";
++}
++
++std::string ParseString(std::istringstream& ist) {
++  std::string str;
++  int count = 0;
++  while (ist) {
++    char ch = ist.peek();
++    if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) {
++      break;
++    } else if (ch == '{') {
++      count += 1;
++    } else if (ch == '}') {
++      count -= 1;
++      if (count < 0)
++        LOG(LERROR) << "mismatched '{' and '}'";
++    }
++    str.append(1, static_cast<char>(ist.get()));
++  }
++  return str;
++}
++
++void ParseMap(const std::string& str, StrMap& map) {
++  if (str.size() == 0)
++    return;
++  std::istringstream ist(str);
++  ParseCheck(ist, '{');
++  for (;;) {
++    std::string key = ParseString(ist);
++    ParseCheck(ist, '=');
++    std::string val = ParseString(ist);
++    map[key] = val;
++    if (ist.peek() == ',')
++      ist.get();
++    else
++      break;
++  }
++  ParseCheck(ist, '}');
++  if (ist.rdbuf()->in_avail() != 0)
++    LOG(LERROR) << "Unexpected characters at end";
++}
++
++#if 0
++const std::string TEST_MAP0_IN = "";
++const std::string TEST_MAP0_OUT = "{}";
++const std::string TEST_MAP1 = "{a=12345}";
++const std::string TEST_MAP2 = "{a=12345,b=67890}";
++const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}";
++const std::string TEST_MAP4 = "{a={d=12345,e=67890}}";
++const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}";
++const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}";
++const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}";
++
++class MyTest {
++public:
++  MyTest() {
++    test(TEST_MAP0_IN, TEST_MAP0_OUT);
++    test(TEST_MAP1, TEST_MAP1);
++    test(TEST_MAP2, TEST_MAP2);
++    test(TEST_MAP3, TEST_MAP3);
++    test(TEST_MAP4, TEST_MAP4);
++    test(TEST_MAP5, TEST_MAP5);
++    test(TEST_MAP6, TEST_MAP6);
++    test(TEST_MAP7, TEST_MAP7);
++  }
++  void test(const std::string& input, const std::string& exp_output) {
++    StrMap map;
++    ParseMap(input, map);
++    std::string output;
++    BuildMap(map, output);
++    LOG(INFO) << "  ********  " << (output == exp_output);
++  }
++};
++
++static MyTest myTest;
++#endif
++
++template <typename T>
++std::string ToString(T val) {
++  std::ostringstream ost;
++  ost << val;
++  return ost.str();
++}
++
++template <typename T>
++T FromString(std::string str) {
++  std::istringstream ist(str);
++  T val;
++  ist >> val;
++  return val;
++}
++
++}
++
++namespace cricket {
++
++#ifdef POSIX
++void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
++  int fd;
++  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
++    PLOG(LERROR, errno) << "socket";
++    return;
++  }
++
++  struct ifconf ifc;
++  ifc.ifc_len = 64 * sizeof(struct ifreq);
++  ifc.ifc_buf = new char[ifc.ifc_len];
++
++  if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
++    PLOG(LERROR, errno) << "ioctl";
++    return;
++  }
++  assert(ifc.ifc_len < static_cast<int>(64 * sizeof(struct ifreq)));
++
++  struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf);
++  struct ifreq* end =
++      reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len);
++
++  while (ptr < end) {
++    struct sockaddr_in* inaddr =
++        reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr);
++    if (inaddr->sin_family == AF_INET) {
++      uint32 ip = ntohl(inaddr->sin_addr.s_addr);
++      networks.push_back(new Network(std::string(ptr->ifr_name), ip));
++    }
++#ifdef _SIZEOF_ADDR_IFREQ
++    ptr = reinterpret_cast<struct ifreq*>(
++        reinterpret_cast<char*>(ptr) + _SIZEOF_ADDR_IFREQ(*ptr));
++#else
++    ptr++;
++#endif
++  }
++
++  delete [] ifc.ifc_buf;
++  close(fd);
++}
++#endif
++
++#ifdef WIN32
++void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
++  IP_ADAPTER_INFO info_temp;
++  ULONG len = 0;
++  
++  if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW)
++    return;
++  IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len];
++  if (GetAdaptersInfo(infos, &len) != NO_ERROR)
++    return;
++
++  int count = 0;
++  for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) {
++    if (info->Type == MIB_IF_TYPE_LOOPBACK)
++      continue;
++    if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0)
++      continue;
++
++    // In production, don't transmit the network name because of
++    // privacy concerns. Transmit a number instead.
++
++    std::string name;
++#if defined(PRODUCTION)
++    std::ostringstream ost;
++    ost << count;
++    name = ost.str();
++    count++;
++#else
++    name = info->Description;
++#endif
++
++    networks.push_back(new Network(name,
++        SocketAddress::StringToIP(info->IpAddressList.IpAddress.String)));
++  }
++
++  delete infos;
++}
++#endif
++
++void NetworkManager::GetNetworks(std::vector<Network*>& result) {
++  std::vector<Network*> list;
++  CreateNetworks(list);
++
++  for (uint32 i = 0; i < list.size(); ++i) {
++    NetworkMap::iterator iter = networks_.find(list[i]->name());
++
++    Network* network;
++    if (iter == networks_.end()) {
++      network = list[i];
++    } else {
++      network = iter->second;
++      network->set_ip(list[i]->ip());
++      delete list[i];
++    }
++
++    networks_[network->name()] = network;
++    result.push_back(network);
++  }
++}
++
++std::string NetworkManager::GetState() {
++  StrMap map;
++  for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i)
++    map[i->first] = i->second->GetState();
++
++  std::string str;
++  BuildMap(map, str);
++  return str;
++}
++
++void NetworkManager::SetState(std::string str) {
++  StrMap map;
++  ParseMap(str, map);
++
++  for (StrMap::iterator i = map.begin(); i != map.end(); ++i) {
++    std::string name = i->first;
++    std::string state = i->second;
++
++    Network* network = new Network(name, 0);
++    network->SetState(state);
++    networks_[name] = network;
++  }
++}
++
++Network::Network(const std::string& name, uint32 ip)
++  : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0),
++    exponential_numerator_(0), exponential_denominator_(0),
++    quality_(kDefaultQuality) {
++
++  last_data_time_ = Time();
++
++  // TODO: seed the historical data with one data point based on the link speed
++  //       metric from XP (4.0 if < 50, 3.0 otherwise).
++}
++
++void Network::StartSession(NetworkSession* session) {
++  assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end());
++  sessions_.push_back(session);
++}
++
++void Network::StopSession(NetworkSession* session) {
++  SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session);
++  if (iter != sessions_.end())
++    sessions_.erase(iter);
++}
++
++void Network::EstimateQuality() {
++  uint32 now = Time();
++
++  // Add new data points for the current time.
++  for (uint32 i = 0; i < sessions_.size(); ++i) {
++    if (sessions_[i]->HasQuality())
++      AddDataPoint(now, sessions_[i]->GetCurrentQuality());
++  }
++
++  // Construct the weighted average using both uniform and exponential weights.
++
++  double exp_shift = exp(-kLambda * (now - last_data_time_));
++  double numerator = uniform_numerator_ + exp_shift * exponential_numerator_;
++  double denominator = uniform_denominator_ + exp_shift * exponential_denominator_;
++
++  if (denominator < DBL_EPSILON)
++    quality_ = kDefaultQuality;
++  else
++    quality_ = numerator / denominator;
++}
++
++void Network::AddDataPoint(uint32 time, double quality) {
++  uniform_numerator_ += kAlpha * quality;
++  uniform_denominator_ += kAlpha;
++
++  double exp_shift = exp(-kLambda * (time - last_data_time_));
++  exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_;
++  exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_;
++
++  last_data_time_ = time;
++}
++
++std::string Network::GetState() {
++  StrMap map;
++  map["lt"] = ToString<uint32>(last_data_time_);
++  map["un"] = ToString<double>(uniform_numerator_);
++  map["ud"] = ToString<double>(uniform_denominator_);
++  map["en"] = ToString<double>(exponential_numerator_);
++  map["ed"] = ToString<double>(exponential_denominator_);
++
++  std::string str;
++  BuildMap(map, str);
++  return str;
++}
++
++void Network::SetState(std::string str) {
++  StrMap map;
++  ParseMap(str, map);
++
++  last_data_time_ = FromString<uint32>(map["lt"]);
++  uniform_numerator_ = FromString<double>(map["un"]);
++  uniform_denominator_ = FromString<double>(map["ud"]);
++  exponential_numerator_ = FromString<double>(map["en"]);
++  exponential_denominator_ = FromString<double>(map["ed"]);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc	(revision 586398)
+@@ -0,0 +1,321 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/messagequeue.h"
++#include "talk/base/physicalsocketserver.h"
++
++#ifdef POSIX
++extern "C" {
++#include <sys/time.h>
++}
++#endif
++
++namespace cricket {
++
++//------------------------------------------------------------------
++// MessageQueueManager
++
++MessageQueueManager* MessageQueueManager::instance_;
++
++MessageQueueManager* MessageQueueManager::Instance() {
++  // Note: This is not thread safe, but it is first called before threads are
++  // spawned.
++  if (!instance_)
++    instance_ = new MessageQueueManager;
++  return instance_;
++}
++
++MessageQueueManager::MessageQueueManager() {
++}
++
++MessageQueueManager::~MessageQueueManager() {
++}
++
++void MessageQueueManager::Add(MessageQueue *message_queue) {
++  CritScope cs(&crit_);
++  message_queues_.push_back(message_queue);
++}
++
++void MessageQueueManager::Remove(MessageQueue *message_queue) {
++  CritScope cs(&crit_);
++  std::vector<MessageQueue *>::iterator iter;
++  iter = std::find(message_queues_.begin(), message_queues_.end(), message_queue);
++  if (iter != message_queues_.end())
++    message_queues_.erase(iter);
++}
++
++void MessageQueueManager::Clear(MessageHandler *handler) {
++  CritScope cs(&crit_);
++  std::vector<MessageQueue *>::iterator iter;
++  for (iter = message_queues_.begin(); iter != message_queues_.end(); iter++)
++    (*iter)->Clear(handler);
++}
++
++//------------------------------------------------------------------
++// MessageQueue
++
++MessageQueue::MessageQueue(SocketServer* ss)
++    : ss_(ss), new_ss(false), fStop_(false), fPeekKeep_(false) {
++  if (!ss_) {
++    new_ss = true;
++    ss_ = new PhysicalSocketServer();
++  }
++  MessageQueueManager::Instance()->Add(this);
++}
++
++MessageQueue::~MessageQueue() {
++  Clear(NULL);
++  if (new_ss)
++    delete ss_;
++  MessageQueueManager::Instance()->Remove(this);
++}
++
++void MessageQueue::set_socketserver(SocketServer* ss) {
++  if (new_ss)
++    delete ss_;
++  new_ss = false;
++  ss_ = ss;
++}
++
++void MessageQueue::Stop() {
++  fStop_ = true;
++  ss_->WakeUp();
++}
++
++bool MessageQueue::IsStopping() {
++  return fStop_;
++}
++
++void MessageQueue::Restart() {
++  fStop_ = false;
++}
++
++bool MessageQueue::Peek(Message *pmsg, int cmsWait) {
++  if (fStop_)
++    return false;
++  if (fPeekKeep_) {
++    *pmsg = msgPeek_;
++    return true;
++  }
++  if (!Get(pmsg, cmsWait))
++    return false;
++  msgPeek_ = *pmsg;
++  fPeekKeep_ = true;
++  return true;
++}
++
++bool MessageQueue::Get(Message *pmsg, int cmsWait) {
++  // Force stopping
++
++  if (fStop_)
++    return false;
++
++  // Return and clear peek if present
++  // Always return the peek if it exists so there is Peek/Get symmetry
++
++  if (fPeekKeep_) {
++    *pmsg = msgPeek_;
++    fPeekKeep_ = false;
++    return true;
++  }
++
++  // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch
++
++  int cmsTotal = cmsWait;
++  int cmsElapsed = 0;
++  uint32 msStart = GetMillisecondCount();
++  uint32 msCurrent = msStart;
++  while (!fStop_) {
++    // Check for sent messages
++
++    ReceiveSends();
++
++    // Check queues
++
++    int cmsDelayNext = -1;
++    {
++      CritScope cs(&crit_);
++
++      // Check for delayed messages that have been triggered
++      // Calc the next trigger too
++
++      while (!dmsgq_.empty()) {
++        if (msCurrent < dmsgq_.top().msTrigger_) {
++          cmsDelayNext = dmsgq_.top().msTrigger_ - msCurrent;
++          break;
++        }
++        msgq_.push(dmsgq_.top().msg_);
++        dmsgq_.pop();
++      }
++
++      // Check for posted events
++
++      if (!msgq_.empty()) {
++        *pmsg = msgq_.front();
++        msgq_.pop();
++        return true;
++      }
++    }
++
++    // Which is shorter, the delay wait or the asked wait?
++
++    int cmsNext;
++    if (cmsWait == -1) {
++      cmsNext = cmsDelayNext;
++    } else {
++      cmsNext = cmsTotal - cmsElapsed;
++      if (cmsNext < 0)
++        cmsNext = 0;
++      if (cmsDelayNext != -1 && cmsDelayNext < cmsNext)
++        cmsNext = cmsDelayNext;
++    }
++
++    // Wait and multiplex in the meantime
++    ss_->Wait(cmsNext, true);
++
++    // If the specified timeout expired, return
++
++    msCurrent = GetMillisecondCount();
++    cmsElapsed = msCurrent - msStart;
++    if (cmsWait != -1) {
++      if (cmsElapsed >= cmsWait)
++        return false;
++    }
++  }
++  return false;
++}
++
++void MessageQueue::ReceiveSends() {
++}
++
++void MessageQueue::Post(MessageHandler *phandler, uint32 id,
++    MessageData *pdata) {
++  // Keep thread safe
++  // Add the message to the end of the queue
++  // Signal for the multiplexer to return
++
++  CritScope cs(&crit_);
++  Message msg;
++  msg.phandler = phandler;
++  msg.message_id = id;
++  msg.pdata = pdata;
++  msgq_.push(msg);
++  ss_->WakeUp();
++}
++
++void MessageQueue::PostDelayed(int cmsDelay, MessageHandler *phandler,
++    uint32 id, MessageData *pdata) {
++  // Keep thread safe
++  // Add to the priority queue. Gets sorted soonest first.
++  // Signal for the multiplexer to return.
++
++  CritScope cs(&crit_);
++  Message msg;
++  msg.phandler = phandler;
++  msg.message_id = id;
++  msg.pdata = pdata;
++  dmsgq_.push(DelayedMessage(cmsDelay, &msg));
++  ss_->WakeUp();
++}
++
++int MessageQueue::GetDelay() {
++  CritScope cs(&crit_);
++
++  if (!msgq_.empty())
++    return 0;
++
++  if (!dmsgq_.empty()) {
++    int delay = dmsgq_.top().msTrigger_ - GetMillisecondCount();
++    if (delay < 0)
++      delay = 0;
++    return delay;
++  }
++
++  return -1;
++}
++
++void MessageQueue::Clear(MessageHandler *phandler, uint32 id) {
++  CritScope cs(&crit_);
++
++  // Remove messages with phandler
++
++  if (fPeekKeep_) {
++    if (phandler == NULL || msgPeek_.phandler == phandler) {
++      if (id == (uint32)-1 || msgPeek_.message_id == id) {
++        delete msgPeek_.pdata;
++        fPeekKeep_ = false;
++      }
++    }
++  }
++
++  // Remove from ordered message queue
++
++  size_t c = msgq_.size();
++  while (c-- != 0) {
++    Message msg = msgq_.front();
++    msgq_.pop();
++    if (phandler != NULL && msg.phandler != phandler) {
++      msgq_.push(msg);
++    } else {
++      if (id == (uint32)-1 || msg.message_id == id) {
++        delete msg.pdata;
++      } else {
++        msgq_.push(msg);
++      }
++    }
++  }
++
++  // Remove from priority queue. Not directly iterable, so use this approach
++
++  std::queue<DelayedMessage> dmsgs;
++  while (!dmsgq_.empty()) {
++    DelayedMessage dmsg = dmsgq_.top();
++    dmsgq_.pop();
++    if (phandler != NULL && dmsg.msg_.phandler != phandler) {
++      dmsgs.push(dmsg);
++    } else {
++      if (id == (uint32)-1 || dmsg.msg_.message_id == id) {
++        delete dmsg.msg_.pdata;
++      } else {
++        dmsgs.push(dmsg);
++      }
++    }
++  }
++  while (!dmsgs.empty()) {
++    dmsgq_.push(dmsgs.front());
++    dmsgs.pop();
++  }
++}
++
++void MessageQueue::Dispatch(Message *pmsg) {
++  pmsg->phandler->OnMessage(pmsg);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h	(revision 586398)
+@@ -0,0 +1,266 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __STRINGUTILS_H__
++#define __STRINGUTILS_H__
++
++#include <cctype>
++#include <cstdarg>
++#include <cstdio>
++#ifdef WIN32
++#include <wchar.h>
++#endif  // WIN32
++
++#include <string>
++
++///////////////////////////////////////////////////////////////////////////////
++// Rename a bunch of common string functions so they are consistent across
++// platforms and between char and wchar_t variants.
++// Here is the full list of functions that are unified:
++//  strlen, strcmp, stricmp, strncmp, strnicmp
++//  strchr, vsnprintf, strtoul, tolowercase
++// tolowercase is like tolower, but not compatible with end-of-file value
++// Note that the wchar_t versions are not available on Linux
++///////////////////////////////////////////////////////////////////////////////
++
++inline char tolowercase(char c) {
++  return static_cast<char>(tolower(c));
++}
++
++#ifdef WIN32
++
++inline size_t strlen(const wchar_t* s) {
++  return wcslen(s);
++}
++inline int strcmp(const wchar_t* s1, const wchar_t* s2) {
++  return wcscmp(s1, s2);
++}
++inline int stricmp(const wchar_t* s1, const wchar_t* s2) {
++  return wcsicmp(s1, s2);
++}
++inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
++  return wcsncmp(s1, s2, n);
++}
++inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
++  return wcsnicmp(s1, s2, n);
++}
++inline const wchar_t* strchr(const wchar_t* s, wchar_t c) {
++  return wcschr(s, c);
++}
++inline int vsnprintf(char* buf, size_t n, const char* fmt, va_list args) {
++  return _vsnprintf(buf, n, fmt, args);
++}
++inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) {
++  return _vsnwprintf(buf, n, fmt, args);
++}
++inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) {
++  return wcstoul(snum, end, base);
++}
++inline wchar_t tolowercase(wchar_t c) {
++  return static_cast<wchar_t>(towlower(c));
++}
++
++#endif  // WIN32
++
++#ifdef POSIX
++
++inline int stricmp(const char* s1, const char* s2) {
++  return strcasecmp(s1, s2);
++}
++inline int strnicmp(const char* s1, const char* s2, size_t n) {
++  return strncasecmp(s1, s2, n);
++}
++
++#endif // POSIX
++
++///////////////////////////////////////////////////////////////////////////////
++// Traits simplifies porting string functions to be CTYPE-agnostic
++///////////////////////////////////////////////////////////////////////////////
++
++namespace cricket {
++
++const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
++
++template<class CTYPE>
++struct Traits {
++  // STL string type
++  //typedef XXX string;
++  // Null-terminated string
++  //inline static const CTYPE* empty_str();
++};
++
++///////////////////////////////////////////////////////////////////////////////
++// String utilities which work with char or wchar_t
++///////////////////////////////////////////////////////////////////////////////
++
++template<class CTYPE>
++inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) {
++  return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
++}
++
++template<class CTYPE>
++const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
++  for (size_t i=0; str[i]; ++i) {
++    for (size_t j=0; chs[j]; ++j) {
++      if (str[i] == chs[j]) {
++        return str + i;
++      }
++    }
++  }
++  return 0;
++}
++
++template<class CTYPE>
++const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
++  for (size_t i=0; i<slen && str[i]; ++i) {
++    if (str[i] == ch) {
++      return str + i;
++    }
++  }
++  return 0;
++}
++
++template<class CTYPE>
++size_t strlenn(const CTYPE* buffer, size_t buflen) {
++  size_t bufpos = 0;
++  while (buffer[bufpos] && (bufpos < buflen)) {
++    ++bufpos;
++  }
++  return bufpos;
++}
++
++template<class CTYPE>
++size_t strcpyn(CTYPE* buffer, size_t buflen,
++               const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
++  if (buflen <= 0)
++    return 0;
++  
++  if (srclen == SIZE_UNKNOWN) {
++    srclen = strlenn(source, buflen - 1);
++  } else if (srclen >= buflen) {
++    srclen = buflen - 1;
++  }
++  memcpy(buffer, source, srclen * sizeof(CTYPE));
++  buffer[srclen] = 0;
++  return srclen;
++}
++
++// Safe versions of snprintf and vsnprintf that always null-terminate
++
++template<class CTYPE>
++size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
++  va_list args;
++  va_start(args, format);
++  size_t len = vsprintfn(buffer, buflen, format, args);
++  va_end(args);
++  return len;
++}
++
++template<class CTYPE>
++size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format,
++                 va_list args) {
++  int len = vsnprintf(buffer, buflen, format, args);
++  if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
++    len = static_cast<int>(buflen - 1);
++    buffer[len] = 0;
++  }
++  return len;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++// Allow safe comparing and copying ascii (not UTF-8) with both wide and
++// non-wide character strings.
++///////////////////////////////////////////////////////////////////////////////
++
++inline int asccmp(const char* s1, const char* s2) {
++  return strcmp(s1, s2);
++}
++inline int ascicmp(const char* s1, const char* s2) {
++  return stricmp(s1, s2);
++}
++inline int ascncmp(const char* s1, const char* s2, size_t n) {
++  return strncmp(s1, s2, n);
++}
++inline int ascnicmp(const char* s1, const char* s2, size_t n) {
++  return strnicmp(s1, s2, n);
++}
++inline size_t asccpyn(char* buffer, size_t buflen,
++                      const char* source, size_t srclen = SIZE_UNKNOWN) {
++  return strcpyn(buffer, buflen, source, srclen);
++}
++
++#ifdef WIN32
++
++typedef wchar_t(*CharacterTransformation)(wchar_t);
++inline wchar_t identity(wchar_t c) { return c; }
++int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
++                         CharacterTransformation transformation);
++
++inline int asccmp(const wchar_t* s1, const char* s2) {
++  return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity);
++}
++inline int ascicmp(const wchar_t* s1, const char* s2) {
++  return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase);
++}
++inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) {
++  return ascii_string_compare(s1, s2, n, identity);
++}
++inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
++  return ascii_string_compare(s1, s2, n, tolowercase);
++}
++size_t asccpyn(wchar_t* buffer, size_t buflen,
++               const char* source, size_t srclen = SIZE_UNKNOWN);
++
++#endif  // WIN32
++
++///////////////////////////////////////////////////////////////////////////////
++// Traits<char> specializations
++///////////////////////////////////////////////////////////////////////////////
++
++template<>
++struct Traits<char> {
++  typedef std::string string;
++  inline static const char* empty_str() { return ""; }
++};
++
++///////////////////////////////////////////////////////////////////////////////
++// Traits<wchar_t> specializations (Windows only, currently)
++///////////////////////////////////////////////////////////////////////////////
++
++#ifdef WIN32
++
++template<>
++struct Traits<wchar_t> {
++  typedef std::wstring string;
++  inline static const wchar_t* Traits<wchar_t>::empty_str() { return L""; }
++};
++
++#endif  // WIN32
++
++}  // namespace cricket
++
++#endif // __STRINGUTILS_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/network.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/network.h	(revision 586398)
+@@ -0,0 +1,136 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __NETWORK_H__
++#define __NETWORK_H__
++
++#include "talk/base/basictypes.h"
++
++#include <deque>
++#include <map>
++#include <string>
++#include <vector>
++
++namespace cricket {
++
++class Network;
++class NetworkSession;
++
++// Keeps track of the available network interfaces over time so that quality
++// information can be aggregated and recorded.
++class NetworkManager {
++public:
++
++  // Updates and returns the current list of networks available on this machine.
++  // This version will make sure that repeated calls return the same object for
++  // a given network, so that quality is tracked appropriately.
++  void GetNetworks(std::vector<Network*>& networks);
++
++  // Reads and writes the state of the quality database in a string format.
++  std::string GetState();
++  void SetState(std::string str);
++
++  // Creates a network object for each network available on the machine.
++  static void CreateNetworks(std::vector<Network*>& networks);
++
++private:
++  typedef std::map<std::string,Network*> NetworkMap;
++
++  NetworkMap networks_;
++};
++
++// Represents a Unix-type network interface, with a name and single address.
++// It also includes the ability to track and estimate quality.
++class Network {
++public:
++  Network(const std::string& name, uint32 ip);
++
++  // Returns the OS name of this network.  This is considered the primary key
++  // that identifies each network.
++  const std::string& name() const { return name_; }
++
++  // Identifies the current IP address used by this network.
++  uint32 ip() const { return ip_; }
++  void set_ip(uint32 ip) { ip_ = ip; }
++
++  // Updates the list of sessions that are ongoing.
++  void StartSession(NetworkSession* session);
++  void StopSession(NetworkSession* session);
++
++  // Re-computes the estimate of near-future quality based on the information
++  // as of this exact moment.
++  void EstimateQuality();
++
++  // Returns the current estimate of the near-future quality of connections
++  // that use this local interface.
++  double quality() { return quality_; }
++
++private:
++  typedef std::vector<NetworkSession*> SessionList;
++
++  std::string name_;
++  uint32 ip_;
++  SessionList sessions_;
++  double uniform_numerator_;
++  double uniform_denominator_;
++  double exponential_numerator_;
++  double exponential_denominator_;
++  uint32 last_data_time_;
++  double quality_;
++
++  // Updates the statistics maintained to include the given estimate.
++  void AddDataPoint(uint32 time, double quality);
++
++  // Converts the internal state to and from a string.  This is used to record
++  // quality information into a permanent store.
++  void SetState(std::string str);
++  std::string GetState();
++
++  friend class NetworkManager;
++};
++
++// Represents a session that is in progress using a particular network and can
++// provide data about the quality of the network at any given moment.
++class NetworkSession {
++public:
++  // Determines whether this session has an estimate at this moment.  We will
++  // only call GetCurrentQuality when this returns true.
++  virtual bool HasQuality() = 0;
++
++  // Returns an estimate of the quality at this exact moment.  The result should
++  // be a MOS (mean opinion score) value.
++  virtual float GetCurrentQuality() = 0;
++
++};
++
++const double QUALITY_BAD  = 3.0;
++const double QUALITY_FAIR = 3.35;
++const double QUALITY_GOOD = 3.7;
++
++} // namespace cricket
++
++#endif // __NETWORK_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h	(revision 586398)
+@@ -0,0 +1,164 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __MESSAGEQUEUE_H__
++#define __MESSAGEQUEUE_H__
++
++#include "talk/base/basictypes.h"
++#include "talk/base/criticalsection.h"
++#include "talk/base/socketserver.h"
++#include "talk/base/jtime.h"
++#include <vector>
++#include <queue>
++#include <algorithm>
++
++namespace cricket {
++
++struct Message;
++class MessageQueue;
++class MessageHandler;
++
++// MessageQueueManager does cleanup of of message queues
++
++class MessageQueueManager {
++public:
++  static MessageQueueManager* Instance();
++
++  void Add(MessageQueue *message_queue);
++  void Remove(MessageQueue *message_queue);
++  void Clear(MessageHandler *handler);
++
++private:
++  MessageQueueManager();
++  ~MessageQueueManager();
++
++  static MessageQueueManager* instance_;
++  std::vector<MessageQueue *> message_queues_;
++  CriticalSection crit_;
++};
++
++// Messages get dispatched to a MessageHandler
++
++class MessageHandler {
++public:
++  virtual ~MessageHandler() {
++    MessageQueueManager::Instance()->Clear(this);
++  }
++
++  virtual void OnMessage(Message *pmsg) = 0;
++};
++
++// Derive from this for specialized data
++// App manages lifetime, except when messages are purged
++
++class MessageData {
++public:
++  MessageData() {}
++  virtual ~MessageData() {}
++};
++
++template <class arg1_type>
++class TypedMessageData : public MessageData {
++public:
++  TypedMessageData(arg1_type data) {
++    data_ = data;
++  }
++  arg1_type data() {
++    return data_;
++  }
++private:
++  arg1_type data_;
++};
++
++// No destructor
++
++struct Message {
++  Message() {
++    memset(this, 0, sizeof(*this));
++  }
++  MessageHandler *phandler;
++  uint32 message_id;
++  MessageData *pdata;
++};
++
++// DelayedMessage goes into a priority queue, sorted by trigger time
++
++class DelayedMessage {
++public:
++  DelayedMessage(int cmsDelay, Message *pmsg) {
++    cmsDelay_ = cmsDelay;
++    msTrigger_ = GetMillisecondCount() + cmsDelay;
++    msg_ = *pmsg;
++  }
++
++  bool operator< (const DelayedMessage& dmsg) const {
++    return dmsg.msTrigger_ < msTrigger_;
++  }
++
++  int cmsDelay_; // for debugging
++  uint32 msTrigger_;
++  Message msg_;
++};
++
++class MessageQueue {
++public:
++  MessageQueue(SocketServer* ss = 0);
++  virtual ~MessageQueue();
++
++  SocketServer* socketserver() { return ss_; }
++  void set_socketserver(SocketServer* ss);
++
++  // Once the queue is stopped, all calls to Get/Peek will return false.
++  virtual void Stop();
++  virtual bool IsStopping();
++  virtual void Restart();
++
++  virtual bool Get(Message *pmsg, int cmsWait = -1);
++  virtual bool Peek(Message *pmsg, int cmsWait = 0);
++  virtual void Post(MessageHandler *phandler, uint32 id = 0,
++      MessageData *pdata = NULL);
++  virtual void PostDelayed(int cmsDelay, MessageHandler *phandler,
++      uint32 id = 0, MessageData *pdata = NULL);
++  virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1);
++  virtual void Dispatch(Message *pmsg);
++  virtual void ReceiveSends();
++  virtual int GetDelay();
++
++protected:
++  SocketServer* ss_;
++  bool new_ss;
++  bool fStop_;
++  bool fPeekKeep_;
++  Message msgPeek_;
++  std::queue<Message> msgq_;
++  std::priority_queue<DelayedMessage> dmsgq_;
++  CriticalSection crit_;
++};
++
++} // namespace cricket 
++
++#endif // __MESSAGEQUEUE_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h	(revision 586398)
+@@ -0,0 +1,85 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _STL_DECL_H
++#define _STL_DECL_H
++
++#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
++#pragma warning(disable:4786)
++#endif
++
++#include <sys/types.h>
++
++namespace std {
++  template <class Key> struct hash;
++  template <class Key> struct equal_to;
++  template <class Key> struct less;
++  template <class T> class allocator;
++  template <class Key, class Val,
++            class Compare,
++            class Alloc> class map;
++  template <class T, class Alloc> class vector;
++  template <class T, class Alloc> class list;
++  template <class T, class Alloc> class slist;
++  template <class T, class Alloc, size_t BufSiz> class deque;
++  template <class T, class Sequence> class stack;
++  template <class T, class Sequence> class queue;
++  template <class T, class Sequence, class Compare> class priority_queue;
++  template <class T1, class T2> struct pair;
++  template <class Key, class Compare, class Alloc> class set;
++}
++
++/////////////////////////////////////////////////////////////////////////////
++// Workaround declaration problem with defaults
++/////////////////////////////////////////////////////////////////////////////
++
++#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
++
++#define STD_MAP(T1, T2) \
++  std::map<T1 , T2, std::less<T1>, std::allocator<T2> > 
++
++#define STD_VECTOR(T1) \
++  std::vector<T1, std::allocator<T1> >
++
++#define STD_SET(T1) \
++  std::set<T1, std::less<T1>, std::allocator<T1> >
++
++#else
++
++#define STD_MAP(T1, T2) \
++  std::map<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2 > > >
++
++#define STD_VECTOR(T1) \
++  std::vector<T1, std::allocator<T1> >
++
++#define STD_SET(T1) \
++  std::set<T1, std::less<T1>, std::allocator<T1> >
++
++#endif
++
++
++#endif // _STL_DECL_H
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc	(revision 586398)
+@@ -0,0 +1,197 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++#include "talk/base/asynctcpsocket.h"
++#include "talk/base/byteorder.h"
++#include "talk/base/common.h"
++#include "talk/base/logging.h"
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++}
++#endif // POSIX
++
++namespace cricket {
++
++const size_t MAX_PACKET_SIZE = 64 * 1024;
++
++typedef uint16 PacketLength;
++const size_t PKT_LEN_SIZE = sizeof(PacketLength);
++
++const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
++
++AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) {
++  inbuf_ = new char[insize_];
++  outbuf_ = new char[outsize_];
++
++  ASSERT(socket_ != NULL);
++  socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent);
++  socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent);
++  socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent);
++  socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent);
++}
++
++AsyncTCPSocket::~AsyncTCPSocket() {
++  delete [] inbuf_;
++  delete [] outbuf_;
++}
++
++int AsyncTCPSocket::Send(const void *pv, size_t cb) {
++  if (cb > MAX_PACKET_SIZE) {
++    socket_->SetError(EMSGSIZE);
++    return -1;
++  }
++
++  // If we are blocking on send, then silently drop this packet
++  if (outpos_)
++    return static_cast<int>(cb);
++
++  PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
++  memcpy(outbuf_, &pkt_len, PKT_LEN_SIZE);
++  memcpy(outbuf_ + PKT_LEN_SIZE, pv, cb);
++  outpos_ = PKT_LEN_SIZE + cb;
++
++  int res = Flush();
++  if (res <= 0) {
++    // drop packet if we made no progress
++    outpos_ = 0; 
++    return res;
++  }
++
++  // We claim to have sent the whole thing, even if we only sent partial
++  return static_cast<int>(cb);
++}
++
++int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
++  if (addr == GetRemoteAddress())
++    return Send(pv, cb);
++
++  ASSERT(false);
++  socket_->SetError(ENOTCONN);
++  return -1;
++}
++
++int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) {
++  if (outpos_ + cb > outsize_) {
++    socket_->SetError(EMSGSIZE);
++    return -1;
++  }
++
++  memcpy(outbuf_ + outpos_, pv, cb);
++  outpos_ += cb;
++
++  return Flush();
++}
++
++void AsyncTCPSocket::ProcessInput(char * data, size_t& len) {
++  SocketAddress remote_addr(GetRemoteAddress());
++
++  while (true) {
++    if (len < PKT_LEN_SIZE)
++      return;
++
++    PacketLength pkt_len;
++    memcpy(&pkt_len, data, PKT_LEN_SIZE);
++    pkt_len = NetworkToHost16(pkt_len);
++
++    if (len < PKT_LEN_SIZE + pkt_len)
++      return;
++
++    SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this);
++
++    len -= PKT_LEN_SIZE + pkt_len;
++    if (len > 0) {
++      memmove(data, data + PKT_LEN_SIZE + pkt_len, len);
++    }
++  }
++}
++
++int AsyncTCPSocket::Flush() {
++  int res = socket_->Send(outbuf_, outpos_);
++  if (res <= 0) {
++    return res;
++  }
++  if (static_cast<size_t>(res) <= outpos_) {
++    outpos_ -= res;
++  } else {
++    ASSERT(false);
++    return -1;
++  }
++  if (outpos_ > 0) {
++    memmove(outbuf_, outbuf_ + res, outpos_);
++  }
++  return res;
++}
++
++void AsyncTCPSocket::OnConnectEvent(AsyncSocket* socket) {
++  SignalConnect(this);
++}
++
++void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
++  ASSERT(socket == socket_);
++
++  int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
++  if (len < 0) {
++    // TODO: Do something better like forwarding the error to the user.
++    LOG(INFO) << "recvfrom: " << errno << " " <<  std::strerror(errno);
++    return;
++  }
++
++  inpos_ += len;
++
++  ProcessInput(inbuf_, inpos_);
++
++  if (inpos_ >= insize_) {
++    LOG(INFO) << "input buffer overflow";
++    ASSERT(false);
++    inpos_ = 0;
++  }
++}
++
++void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) {
++  ASSERT(socket == socket_);
++
++  if (outpos_ > 0) {
++    Flush();
++  }
++}
++
++void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) {
++  SignalClose(this, error);
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc	(revision 586398)
+@@ -0,0 +1,165 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/basictypes.h"
++#include "talk/base/bytebuffer.h"
++#include "talk/base/byteorder.h"
++#include <algorithm>
++#include <cassert>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::memcpy;
++}
++#endif
++
++namespace cricket {
++
++const int DEFAULT_SIZE = 4096;
++
++ByteBuffer::ByteBuffer() {
++  start_ = 0;
++  end_   = 0;
++  size_  = DEFAULT_SIZE;
++  bytes_ = new char[size_];
++}
++
++ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
++  start_ = 0;
++  end_   = len;
++  size_  = len;
++  bytes_ = new char[size_];
++  memcpy(bytes_, bytes, end_);
++}
++
++ByteBuffer::ByteBuffer(const char* bytes) {
++  start_ = 0;
++  end_   = strlen(bytes);
++  size_  = end_;
++  bytes_ = new char[size_];
++  memcpy(bytes_, bytes, end_);
++}
++
++ByteBuffer::~ByteBuffer() {
++  delete bytes_;
++}
++
++bool ByteBuffer::ReadUInt8(uint8& val) {
++  return ReadBytes(reinterpret_cast<char*>(&val), 1);
++}
++
++bool ByteBuffer::ReadUInt16(uint16& val) {
++  uint16 v;
++  if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
++    return false;
++  } else {
++    val = NetworkToHost16(v);
++    return true;
++  }
++}
++
++bool ByteBuffer::ReadUInt32(uint32& val) {
++  uint32 v;
++  if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
++    return false;
++  } else {
++    val = NetworkToHost32(v);
++    return true;
++  }
++}
++
++bool ByteBuffer::ReadString(std::string& val, size_t len) {
++  if (len > Length()) {
++    return false;
++  } else {
++    val.append(bytes_ + start_, len);
++    start_ += len;
++    return true;
++  }
++}
++
++bool ByteBuffer::ReadBytes(char* val, size_t len) {
++  if (len > Length()) {
++    return false;
++  } else {
++    memcpy(val, bytes_ + start_, len);
++    start_ += len;
++    return true;
++  }
++}
++
++void ByteBuffer::WriteUInt8(uint8 val) {
++  WriteBytes(reinterpret_cast<const char*>(&val), 1);
++}
++
++void ByteBuffer::WriteUInt16(uint16 val) {
++  uint16 v = HostToNetwork16(val);
++  WriteBytes(reinterpret_cast<const char*>(&v), 2);
++}
++
++void ByteBuffer::WriteUInt32(uint32 val) {
++  uint32 v = HostToNetwork32(val);
++  WriteBytes(reinterpret_cast<const char*>(&v), 4);
++}
++
++void ByteBuffer::WriteString(const std::string& val) {
++  WriteBytes(val.c_str(), val.size());
++}
++
++void ByteBuffer::WriteBytes(const char* val, size_t len) {
++  if (Length() + len > Capacity())
++    Resize(Length() + len);
++
++  memcpy(bytes_ + end_, val, len);
++  end_ += len;
++}
++
++void ByteBuffer::Resize(size_t size) {
++  if (size > size_)
++    size = _max(size, 3 * size_ / 2);
++
++  size_t len = _min(end_ - start_, size);
++  char* new_bytes = new char[size];
++  memcpy(new_bytes, bytes_ + start_, len);
++  delete [] bytes_;
++
++  start_ = 0;
++  end_   = len;
++  size_  = size;
++  bytes_ = new_bytes;
++}
++
++void ByteBuffer::Shift(size_t size) {
++  if (size > Length())
++    return;
++
++  end_ = Length() - size;
++  memmove(bytes_, bytes_ + start_ + size, end_);
++  start_ = 0;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h	(revision 586398)
+@@ -0,0 +1,64 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _TASKRUNNER_H_
++#define _TASKRUNNER_H_
++
++#include <vector>
++
++#include "talk/base/sigslot.h"
++#include "talk/base/task.h"
++
++
++namespace buzz {
++
++
++class Task;
++
++class TaskRunner : public Task, public sigslot::has_slots<> {
++public:
++  TaskRunner() : Task(NULL), tasks_running_(false) {}
++  virtual ~TaskRunner();
++  
++  virtual void WakeTasks() = 0;
++  virtual unsigned long long CurrentTime() = 0 ;
++
++  void StartTask(Task * task);
++  void RunTasks();
++  void PollTasks();
++
++  // dummy state machine - never run.
++  virtual int ProcessStart() { return STATE_DONE; }
++
++private:
++  std::vector<Task *> tasks_;
++  bool tasks_running_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h	(revision 586398)
+@@ -0,0 +1,68 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __ASYNCTCPSOCKET_H__
++#define __ASYNCTCPSOCKET_H__
++
++#include "talk/base/asyncpacketsocket.h"
++
++namespace cricket {
++
++// Simulates UDP semantics over TCP.  Send and Recv packet sizes
++// are preserved, and drops packets silently on Send, rather than
++// buffer them in user space.
++class AsyncTCPSocket : public AsyncPacketSocket {
++public:
++  AsyncTCPSocket(AsyncSocket* socket);
++  virtual ~AsyncTCPSocket();
++
++  virtual int Send(const void *pv, size_t cb);
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
++
++  sigslot::signal1<AsyncTCPSocket*> SignalConnect;
++  sigslot::signal2<AsyncTCPSocket*,int> SignalClose;
++
++protected:
++  int SendRaw(const void * pv, size_t cb);
++  virtual void ProcessInput(char * data, size_t& len);
++
++private:
++  char* inbuf_, * outbuf_;
++  size_t insize_, inpos_, outsize_, outpos_;
++
++  int Flush();
++
++  // Called by the underlying socket
++  void OnConnectEvent(AsyncSocket* socket);
++  void OnReadEvent(AsyncSocket* socket);
++  void OnWriteEvent(AsyncSocket* socket);
++  void OnCloseEvent(AsyncSocket* socket, int error);
++};
++
++} // namespace cricket
++
++#endif // __ASYNCSTCPOCKET_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h	(revision 586398)
+@@ -0,0 +1,71 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __BYTEBUFFER_H__
++#define __BYTEBUFFER_H__
++
++#include "talk/base/basictypes.h"
++#include <string>
++
++namespace cricket {
++
++class ByteBuffer {
++public:
++  ByteBuffer();
++  ByteBuffer(const char* bytes, size_t len);
++  ByteBuffer(const char* bytes); // uses strlen
++  ~ByteBuffer();
++
++  const char* Data() const { return bytes_ + start_; }
++  size_t Length() { return end_ - start_; }
++  size_t Capacity() { return size_ - start_; }
++
++  bool ReadUInt8(uint8& val);
++  bool ReadUInt16(uint16& val);
++  bool ReadUInt32(uint32& val);
++  bool ReadString(std::string& val, size_t len); // append to val
++  bool ReadBytes(char* val, size_t len);
++
++  void WriteUInt8(uint8 val);
++  void WriteUInt16(uint16 val);
++  void WriteUInt32(uint32 val);
++  void WriteString(const std::string& val);
++  void WriteBytes(const char* val, size_t len);
++
++  void Resize(size_t size);
++  void Shift(size_t size);
++
++private:
++  char* bytes_;
++  size_t size_;
++  size_t start_;
++  size_t end_;
++};
++
++} // namespace cricket
++
++#endif // __BYTEBUFFER_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h	(revision 586398)
+@@ -0,0 +1,52 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __PROXYINFO_H__
++#define __PROXYINFO_H__
++
++#include <string>
++#include "talk/base/socketaddress.h"
++// TODO: move xmpppassword into base
++#include "talk/xmpp/xmpppassword.h"
++
++namespace cricket {
++
++enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN };
++const char * ProxyToString(ProxyType proxy);
++
++struct ProxyInfo {
++  ProxyType type;
++  SocketAddress address;
++  std::string username;
++  buzz::XmppPassword password;
++
++  ProxyInfo() : type(PROXY_NONE) { }
++};
++
++} // namespace cricket
++
++#endif // __PROXYINFO_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h	(revision 586398)
+@@ -0,0 +1,154 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SOCKETADDRESS_H__
++#define __SOCKETADDRESS_H__
++
++#include "talk/base/basictypes.h"
++#include <string>
++#undef SetPort
++
++namespace cricket {
++
++// Records an IP address and port, which are 32 and 16 bit integers,
++// respectively, both in <b>host byte-order</b>.
++class SocketAddress {
++public:
++  // Creates a missing / unknown address.
++  SocketAddress();
++
++  // Creates the address with the given host and port.  If use_dns is true,
++  // the hostname will be immediately resolved to an IP (which may block for
++  // several seconds if DNS is not available).  Alternately, set use_dns to
++  // false, and then call Resolve() to complete resolution later, or use
++  // SetResolvedIP to set the IP explictly.
++  SocketAddress(const std::string& hostname, int port = 0, bool use_dns = true);
++
++  // Creates the address with the given IP and port.
++  SocketAddress(uint32 ip, int port);
++
++  // Creates a copy of the given address.
++  SocketAddress(const SocketAddress& addr);
++
++  // Replaces our address with the given one.
++  SocketAddress& operator =(const SocketAddress& addr);
++
++  // Changes the IP of this address to the given one, and clears the hostname.
++  void SetIP(uint32 ip);
++
++  // Changes the hostname of this address to the given one.
++  // Calls Resolve and returns the result.
++  bool SetIP(const std::string& hostname, bool use_dns = true);
++
++  // Sets the IP address while retaining the hostname.  Useful for bypassing
++  // DNS for a pre-resolved IP.
++  void SetResolvedIP(uint32 ip);
++
++  // Changes the port of this address to the given one.
++  void SetPort(int port);
++
++  // Returns the IP address.
++  uint32 ip() const;
++
++  // Returns the port part of this address.
++  uint16 port() const;
++
++  // Returns the IP address in dotted form.
++  std::string IPAsString() const;
++
++  // Returns the port as a string
++  std::string PortAsString() const;
++
++  // Returns a display version of the IP/port.
++  std::string ToString() const;
++
++  // Determines whether this represents a missing / any address.
++  bool IsAny() const;
++
++  // Synomym for missing / any.
++  bool IsNil() const { return IsAny(); }
++
++  // Determines whether the IP address refers to the local host, i.e. within
++  // the range 127.0.0.0/8.
++  bool IsLocalIP() const;
++
++  // Determines whether the IP address is in one of the private ranges:
++  // 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12.
++  bool IsPrivateIP() const;
++
++  // Determines whether the hostname has been resolved to an IP
++  bool IsUnresolved() const;
++
++  // Attempt to resolve a hostname to IP address.
++  // Returns false if resolution is required but failed.
++  // 'force' will cause re-resolution of hostname.
++  // 
++  bool Resolve(bool force = false, bool use_dns = true);
++
++  // Determines whether this address is identical to the given one.
++  bool operator ==(const SocketAddress& addr) const;
++
++  // Compares based on IP and then port.
++  bool operator <(const SocketAddress& addr) const;
++
++  // Determines whether this address has the same IP as the one given.
++  bool EqualIPs(const SocketAddress& addr) const;
++
++  // Deteremines whether this address has the same port as the one given.
++  bool EqualPorts(const SocketAddress& addr) const;
++
++  // Hashes this address into a small number.
++  size_t Hash() const;
++
++  // Returns the size of this address when written.
++  size_t Size_() const;
++
++  // Writes this address into the given buffer.
++  void Write_(char* buf, int len) const;
++
++  // Reads this address from the given buffer.
++  void Read_(const char* buf, int len);
++
++  // Converts the IP address given in compact form into dotted form.
++  static std::string IPToString(uint32 ip);
++
++  // Converts the IP address given in dotted form into compact form.
++  // Without 'use_dns', only dotted names (A.B.C.D) are resolved.
++  static uint32 StringToIP(const std::string& str, bool use_dns = true);
++
++private:
++  std::string hostname_;
++  uint32 ip_;
++  uint16 port_;
++
++  // Initializes the address to missing / any.
++  void Zero();
++};
++
++} // namespace cricket
++
++#endif // __SOCKETADDRESS_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/task.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/task.h	(revision 586398)
+@@ -0,0 +1,186 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _TASK_H_
++#define _TASK_H_
++
++#include <vector>
++#include <string>
++
++#include "talk/base/sigslot.h"
++
++/////////////////////////////////////////////////////////////////////
++//
++// TASK
++//
++/////////////////////////////////////////////////////////////////////
++//
++// Task is a state machine infrastructure.  States are pushed forward by
++// pushing forwards a TaskRunner that holds on to all Tasks.  The purpose
++// of Task is threefold:
++// 
++// (1) It manages ongoing work on the UI thread.  Multitasking without
++// threads, keeping it easy, keeping it real. :-)  It does this by
++// organizing a set of states for each task.  When you return from your
++// Process*() function, you return an integer for the next state.  You do
++// not go onto the next state yourself.  Every time you enter a state,
++// you check to see if you can do anything yet.  If not, you return
++// STATE_BLOCKED.  If you _could_ do anything, do not return
++// STATE_BLOCKED - even if you end up in the same state, return
++// STATE_mysamestate.  When you are done, return STATE_DONE and then the
++// task will self-delete sometimea afterwards.
++// 
++// (2) It helps you avoid all those reentrancy problems when you chain
++// too many triggers on one thread.  Basically if you want to tell a task
++// to process something for you, you feed your task some information and
++// then you Wake() it.  Don't tell it to process it right away.  If it
++// might be working on something as you send it infomration, you may want
++// to have a queue in the task.
++// 
++// (3) Finally it helps manage parent tasks and children.  If a parent
++// task gets aborted, all the children tasks are too.  The nice thing
++// about this, for example, is if you have one parent task that
++// represents, say, and Xmpp connection, then you can spawn a whole bunch
++// of infinite lifetime child tasks and now worry about cleaning them up.
++//  When the parent task goes to STATE_DONE, the task engine will make
++// sure all those children are aborted and get deleted.
++// 
++// Notice that Task has a few built-in states, e.g.,
++// 
++// STATE_INIT - the task isn't running yet
++// STATE_START - the task is in its first state
++// STATE_RESPONSE - the task is in its second state
++// STATE_DONE - the task is done
++// 
++// STATE_ERROR - indicates an error - we should audit the error code in
++// light of any usage of it to see if it should be improved.  When I
++// first put down the task stuff I didn't have a good sense of what was
++// needed for Abort and Error, and now the subclasses of Task will ground
++// the design in a stronger way.
++// 
++// STATE_NEXT - the first undefined state number.  (like WM_USER) - you
++// can start defining more task states there.
++// 
++// When you define more task states, just override Process(int state) and
++// add your own switch statement.  If you want to delegate to
++// Task::Process, you can effectively delegate to its switch statement.
++// No fancy method pointers or such - this is all just pretty low tech,
++// easy to debug, and fast.
++// 
++
++namespace buzz {
++
++class TaskRunner;
++
++// A task executes a sequence of steps
++
++class Task;
++class RootTask;
++
++class Task {
++public:
++  Task(Task * parent);
++  virtual ~Task() {}
++  
++  void Start();
++  void Step();
++  int GetState() const { return state_; }
++  bool HasError() const { return (GetState() == STATE_ERROR); }
++  bool Blocked() const { return blocked_; }
++  bool IsDone() const { return done_; }
++  unsigned long long ElapsedTime();
++  virtual void Poll() {}
++
++  Task * GetParent() { return parent_; }
++  TaskRunner * GetRunner() { return runner_; }
++  virtual Task * GetParent(int code) { return parent_->GetParent(code); }
++
++  // Called from outside to stop task without any more callbacks
++  void Abort(bool nowake = false);
++  
++  // For managing children
++  bool AllChildrenDone();
++  bool AnyChildError();
++
++
++protected:
++
++  enum {
++    STATE_BLOCKED = -1,
++    STATE_INIT = 0,
++    STATE_START = 1,
++    STATE_DONE = 2,
++    STATE_ERROR = 3,
++    STATE_RESPONSE = 4,
++    STATE_NEXT = 5, // Subclasses which need more states start here and higher
++  };
++
++  // Called inside the task to signal that the task may be unblocked
++  void Wake();
++
++  // Called inside to advise that the task should wake and signal an error
++  void Error();
++
++  unsigned long long CurrentTime();
++  
++  virtual std::string GetStateName(int state) const;
++  virtual int Process(int state);
++  virtual void Stop();
++  virtual int ProcessStart() = 0;
++  virtual int ProcessResponse() { return STATE_DONE; }
++
++  // for managing children (if any)
++  void AddChild(Task * child);
++  void AbortAllChildren();
++
++private:
++  void Done();
++  void OnChildStopped(Task * child);
++  
++  int state_;
++  Task * parent_;
++  TaskRunner * runner_;
++  bool blocked_;
++  bool done_;
++  bool aborted_;
++  bool busy_;
++  bool error_;
++  bool child_error_;
++  unsigned long long start_time_;
++
++  // for managing children
++  typedef std::set<Task *> ChildSet;
++  ChildSet children_;
++  
++};
++
++
++
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc	(revision 586398)
+@@ -0,0 +1,273 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef POSIX
++extern "C" {
++#include <sys/time.h>
++}
++#endif
++
++#include "talk/base/common.h"
++#include "talk/base/logging.h"
++#include "talk/base/thread.h"
++#include "talk/base/jtime.h"
++
++namespace cricket {
++
++ThreadManager g_thmgr;
++
++#ifdef POSIX
++pthread_key_t ThreadManager::key_;
++
++ThreadManager::ThreadManager() {
++  pthread_key_create(&key_, NULL);
++  main_thread_ = new Thread();
++  SetCurrent(main_thread_);
++}
++
++ThreadManager::~ThreadManager() {
++  pthread_key_delete(key_);
++  delete main_thread_;
++}
++
++Thread *ThreadManager::CurrentThread() {
++  return (Thread *)pthread_getspecific(key_);
++}
++
++void ThreadManager::SetCurrent(Thread *thread) {
++  pthread_setspecific(key_, thread);
++}
++#endif
++
++#ifdef WIN32
++DWORD ThreadManager::key_;
++
++ThreadManager::ThreadManager() {
++  key_ = TlsAlloc();
++  main_thread_ = new Thread();
++  SetCurrent(main_thread_);
++}
++
++ThreadManager::~ThreadManager() {
++  TlsFree(key_);
++  delete main_thread_;
++}
++
++Thread *ThreadManager::CurrentThread() {
++  return (Thread *)TlsGetValue(key_);
++}
++
++void ThreadManager::SetCurrent(Thread *thread) {
++  TlsSetValue(key_, thread);
++}
++#endif
++
++void ThreadManager::Add(Thread *thread) {
++  CritScope cs(&crit_);
++  threads_.push_back(thread);
++}
++
++void ThreadManager::Remove(Thread *thread) {
++  CritScope cs(&crit_);
++  threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end());
++}
++
++Thread::Thread(SocketServer* ss) : MessageQueue(ss) {
++  g_thmgr.Add(this);
++  started_ = false;
++  has_sends_ = false;
++}
++
++Thread::~Thread() {
++  Stop();
++  Clear(NULL);
++  g_thmgr.Remove(this);
++}
++
++#ifdef POSIX
++void Thread::Start() {
++  pthread_attr_t attr;
++  pthread_attr_init(&attr);
++  pthread_create(&thread_, &attr, PreLoop, this);
++  started_ = true;
++}
++
++void Thread::Join() {
++  if (started_) {
++    void *pv;
++    pthread_join(thread_, &pv);
++  }
++}
++#endif
++
++#ifdef WIN32
++void Thread::Start() {
++  thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreLoop, this, 0, NULL);
++  started_ = true;
++}
++
++void Thread::Join() {
++  if (started_) {
++    WaitForSingleObject(thread_, INFINITE);
++    CloseHandle(thread_);
++    started_ = false;
++  }
++}
++#endif
++
++void *Thread::PreLoop(void *pv) {
++  Thread *thread = (Thread *)pv;
++  ThreadManager::SetCurrent(thread);
++  thread->Loop();
++  return NULL;
++}
++
++void Thread::Loop(int cmsLoop) {
++  uint32 msEnd;
++  if (cmsLoop != -1)
++    msEnd = GetMillisecondCount() + cmsLoop;
++  int cmsNext = cmsLoop;
++
++  while (true) {
++    Message msg;
++    if (!Get(&msg, cmsNext))
++      return;
++    Dispatch(&msg);
++    
++    if (cmsLoop != -1) {
++      uint32 msCur = GetMillisecondCount();
++      if (msCur >= msEnd)
++        return;
++      cmsNext = msEnd - msCur;
++    }
++  }
++}
++
++void Thread::Stop() {
++  MessageQueue::Stop();
++  Join();
++}
++
++void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) {
++  // Sent messages are sent to the MessageHandler directly, in the context
++  // of "thread", like Win32 SendMessage. If in the right context,
++  // call the handler directly.
++
++  Message msg;
++  msg.phandler = phandler;
++  msg.message_id = id;
++  msg.pdata = pdata;
++  if (IsCurrent()) {
++    phandler->OnMessage(&msg);
++    return;
++  }
++
++  AutoThread thread; 
++  Thread *current_thread = Thread::Current();
++  ASSERT(current_thread != NULL);  // AutoThread ensures this
++
++  crit_.Enter();
++  bool ready = false;
++  _SendMessage smsg;
++  smsg.thread = current_thread;
++  smsg.msg = msg;
++  smsg.ready = &ready;
++  sendlist_.push_back(smsg);
++  has_sends_ = true;
++  crit_.Leave();
++
++  // Wait for a reply
++
++  ss_->WakeUp();
++  while (!ready) {
++    current_thread->ReceiveSends();
++    current_thread->socketserver()->Wait(-1, false);
++  }
++}
++
++void Thread::ReceiveSends() {
++  // Before entering critical section, check boolean.
++
++  if (!has_sends_)
++    return;
++
++  // Receive a sent message. Cleanup scenarios:
++  // - thread sending exits: We don't allow this, since thread can exit
++  //   only via Join, so Send must complete.
++  // - thread receiving exits: Wakeup/set ready in Thread::Clear()
++  // - object target cleared: Wakeup/set ready in Thread::Clear()
++  crit_.Enter();
++  while (!sendlist_.empty()) {
++    _SendMessage smsg = sendlist_.front();
++    sendlist_.pop_front();
++    crit_.Leave();
++    smsg.msg.phandler->OnMessage(&smsg.msg);
++    crit_.Enter();
++    *smsg.ready = true;
++    smsg.thread->socketserver()->WakeUp();
++  }
++  has_sends_ = false;
++  crit_.Leave();
++}
++
++void Thread::Clear(MessageHandler *phandler, uint32 id) {
++  CritScope cs(&crit_);
++
++  // Remove messages on sendlist_ with phandler
++  // Object target cleared: remove from send list, wakeup/set ready
++  // if sender not NULL.
++
++  std::list<_SendMessage>::iterator iter = sendlist_.begin();
++  while (iter != sendlist_.end()) {
++    _SendMessage smsg = *iter;
++    if (phandler == NULL || smsg.msg.phandler == phandler) {
++      if (id == (uint32)-1 || smsg.msg.message_id == id) {
++        iter = sendlist_.erase(iter);
++        *smsg.ready = true;
++        smsg.thread->socketserver()->WakeUp();
++        continue;
++      }
++    }
++    ++iter;
++  }
++
++  MessageQueue::Clear(phandler, id);
++}
++
++AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
++  if (!ThreadManager::CurrentThread()) {
++    ThreadManager::SetCurrent(this);
++  }
++}
++
++AutoThread::~AutoThread() {
++  if (ThreadManager::CurrentThread() == this) {
++    ThreadManager::SetCurrent(NULL);
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc	(revision 586398)
+@@ -0,0 +1,77 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/jtime.h"
++#include <iostream>
++#include <cstdlib>
++#include <cstring>
++
++namespace cricket {
++
++#ifdef POSIX
++#include <sys/time.h>
++uint32 Time() {
++  struct timeval tv;
++  gettimeofday(&tv, 0);
++  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
++}
++#endif
++
++#ifdef WIN32
++#include <windows.h>
++uint32 Time() {
++  return GetTickCount();
++}
++#endif
++
++bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier) {
++  if (earlier <= later) {
++    return ((earlier <= middle) && (middle <= later));
++  } else {
++    return !((later < middle) && (middle < earlier));
++  }
++}
++
++int32 TimeDiff(uint32 later, uint32 earlier) {
++  uint32 LAST = 0xFFFFFFFF;
++  uint32 HALF = 0x80000000;
++  if (TimeIsBetween(earlier + HALF, later, earlier)) {
++    if (earlier <= later) {
++      return static_cast<long>(later - earlier);
++    } else {
++      return static_cast<long>(later + (LAST - earlier) + 1);
++    }
++  } else {
++    if (later <= earlier) {
++      return -static_cast<long>(earlier - later);
++    } else {
++      return -static_cast<long>(earlier + (LAST - later) + 1);
++    }
++  }
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h	(revision 586398)
+@@ -0,0 +1,141 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __THREAD_H__
++#define __THREAD_H__
++
++#include "talk/base/messagequeue.h"
++
++#include <algorithm>
++#include <list>
++#include <vector>
++
++#ifdef POSIX
++#include <pthread.h>
++#endif
++
++#ifdef WIN32
++#include "talk/base/win32.h"
++#endif
++
++namespace cricket {
++
++class Thread;
++
++class ThreadManager {
++public:
++  ThreadManager();
++  ~ThreadManager();
++
++  static Thread *CurrentThread();
++  static void SetCurrent(Thread *thread);
++  void Add(Thread *thread);
++  void Remove(Thread *thread);
++
++private:
++  Thread *main_thread_;
++  std::vector<Thread *> threads_;
++  CriticalSection crit_;
++
++#ifdef POSIX
++  static pthread_key_t key_; 
++#endif
++
++#ifdef WIN32
++  static DWORD key_;
++#endif
++};
++
++class Thread;
++
++struct _SendMessage {
++  _SendMessage() {}
++  Thread *thread;
++  Message msg;
++  bool *ready;
++};
++
++class Thread : public MessageQueue {
++public:
++  Thread(SocketServer* ss = 0);
++  virtual ~Thread();
++
++  static inline Thread* Current() {
++    return ThreadManager::CurrentThread();
++  }
++  inline bool IsCurrent() const {
++    return (ThreadManager::CurrentThread() == this);
++  }
++
++  virtual void Start();
++  virtual void Stop();
++  virtual void Loop(int cms = -1);
++  virtual void Send(MessageHandler *phandler, uint32 id = 0,
++      MessageData *pdata = NULL);
++
++  // From MessageQueue
++  virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1);
++  virtual void ReceiveSends();
++
++#ifdef WIN32
++  HANDLE GetHandle() {
++    return thread_;
++  }
++#endif
++
++private:
++  static void *PreLoop(void *pv);
++  void Join();
++
++  std::list<_SendMessage> sendlist_;
++  bool started_;
++  bool has_sends_;
++
++#ifdef POSIX
++  pthread_t thread_;
++#endif
++
++#ifdef WIN32
++  HANDLE thread_;
++#endif
++
++  friend class ThreadManager;
++};
++
++// AutoThread automatically installs itself at construction
++// uninstalls at destruction, if a Thread object is
++// _not already_ associated with the current OS thread.
++
++class AutoThread : public Thread {
++public:
++  AutoThread(SocketServer* ss = 0);
++  virtual ~AutoThread();
++};
++
++} // namespace cricket
++
++#endif // __THREAD_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc	(revision 586398)
+@@ -0,0 +1,1117 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++
++#include <cassert>
++
++#ifdef POSIX
++extern "C" {
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/time.h>
++#include <unistd.h>
++}
++#endif
++
++#include "talk/base/basictypes.h"
++#include "talk/base/byteorder.h"
++#include "talk/base/common.h"
++#include "talk/base/logging.h"
++#include "talk/base/physicalsocketserver.h"
++#include "talk/base/jtime.h"
++#include "talk/base/winping.h"
++
++#ifdef __linux 
++#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h
++#endif  // __linux
++
++#ifdef WIN32
++#include <winsock2.h>
++#include <ws2tcpip.h>
++#define _WINSOCKAPI_
++#include <windows.h>
++#undef SetPort
++
++#include <algorithm>
++#include <iostream>
++
++class WinsockInitializer {
++public:
++  WinsockInitializer() {
++    WSADATA wsaData;
++    WORD wVersionRequested = MAKEWORD(1, 0);
++    err_ = WSAStartup(wVersionRequested, &wsaData);
++  }
++  ~WinsockInitializer() {
++    WSACleanup();
++  }
++  int error() {
++    return err_;
++  }
++private:
++  int err_;
++};
++WinsockInitializer g_winsockinit;
++#endif
++
++namespace cricket {
++
++const int kfRead  = 0x0001;
++const int kfWrite = 0x0002;
++const int kfConnect = 0x0004;
++const int kfClose = 0x0008;
++
++
++// Standard MTUs
++const uint16 PACKET_MAXIMUMS[] = {
++  65535,    // Theoretical maximum, Hyperchannel
++  32000,    // Nothing
++  17914,    // 16Mb IBM Token Ring
++  8166,     // IEEE 802.4
++  //4464,   // IEEE 802.5 (4Mb max)
++  4352,     // FDDI
++  //2048,   // Wideband Network
++  2002,     // IEEE 802.5 (4Mb recommended)
++  //1536,   // Expermental Ethernet Networks
++  //1500,   // Ethernet, Point-to-Point (default)
++  1492,     // IEEE 802.3
++  1006,     // SLIP, ARPANET
++  //576,    // X.25 Networks
++  //544,    // DEC IP Portal
++  //512,    // NETBIOS
++  508,      // IEEE 802/Source-Rt Bridge, ARCNET
++  296,      // Point-to-Point (low delay)
++  68,       // Official minimum
++  0,        // End of list marker
++};
++
++const uint32 IP_HEADER_SIZE = 20;
++const uint32 ICMP_HEADER_SIZE = 8;
++
++class PhysicalSocket : public AsyncSocket {
++public:
++  PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET)
++    : ss_(ss), s_(s), enabled_events_(0), error_(0),
++      state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED) {
++    if (s != INVALID_SOCKET)
++      enabled_events_ = kfRead | kfWrite;
++  }
++
++  virtual ~PhysicalSocket() {
++    Close();
++  }
++
++  // Creates the underlying OS socket (same as the "socket" function).
++  virtual bool Create(int type) {
++    Close();
++    s_ = ::socket(AF_INET, type, 0);
++    UpdateLastError();
++    enabled_events_ = kfRead | kfWrite;
++    return s_ != INVALID_SOCKET;
++  }
++
++  SocketAddress GetLocalAddress() const {
++    struct sockaddr_in addr;
++    socklen_t addrlen = sizeof(addr);
++    int result = ::getsockname(s_, (struct sockaddr*)&addr, &addrlen);
++    assert(addrlen == sizeof(addr));
++    if (result >= 0) {
++      return SocketAddress(NetworkToHost32(addr.sin_addr.s_addr),
++                           NetworkToHost16(addr.sin_port));
++    } else {
++      return SocketAddress();
++    }
++  }
++
++  SocketAddress GetRemoteAddress() const {
++    struct sockaddr_in addr;
++    socklen_t addrlen = sizeof(addr);
++    int result = ::getpeername(s_, (struct sockaddr*)&addr, &addrlen);
++    assert(addrlen == sizeof(addr));
++    if (result >= 0) {
++      return SocketAddress(
++          NetworkToHost32(addr.sin_addr.s_addr),
++          NetworkToHost16(addr.sin_port));
++    } else {
++      assert(errno == ENOTCONN);
++      return SocketAddress();
++    }
++  }
++
++  int Bind(const SocketAddress& addr) {
++    struct sockaddr_in saddr;
++    IP2SA(&addr, &saddr);
++    int err = ::bind(s_, (struct sockaddr*)&saddr, sizeof(saddr));
++    UpdateLastError();
++    return err;
++  }
++
++  int Connect(const SocketAddress& addr) {
++    // TODO: Implicit creation is required to reconnect...
++    // ...but should we make it more explicit?
++    if ((s_ == INVALID_SOCKET) && !Create(SOCK_STREAM))
++      return SOCKET_ERROR;
++    SocketAddress addr2(addr);
++    if (addr2.IsUnresolved()) {
++      LOG(INFO) << "Resolving addr in PhysicalSocket::Connect";
++      addr2.Resolve(); // TODO: Do this async later?
++    }
++    struct sockaddr_in saddr;
++    IP2SA(&addr2, &saddr);
++    int err = ::connect(s_, (struct sockaddr*)&saddr, sizeof(saddr));
++    UpdateLastError();
++    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_;
++    if (err == 0) {
++      state_ = CS_CONNECTED;
++    } else if (IsBlockingError(error_)) {
++      state_ = CS_CONNECTING;
++      enabled_events_ |= kfConnect;
++    }
++    return err;
++  }
++
++  int GetError() const {
++    return error_;
++  }
++
++  void SetError(int error) {
++    error_ = error;
++  }
++
++  ConnState GetState() const {
++    return state_;
++  }
++
++  int SetOption(Option opt, int value) {
++    assert(opt == OPT_DONTFRAGMENT);
++#ifdef WIN32
++    value = (value == 0) ? 0 : 1;
++    return ::setsockopt(
++        s_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast<char*>(&value),
++        sizeof(value));
++#endif
++#ifdef __linux 
++    value = (value == 0) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO;
++    return ::setsockopt(
++        s_, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value));
++#endif
++#ifdef OSX
++    // This is not possible on OSX.
++    return -1;
++#endif
++  }
++
++  int Send(const void *pv, size_t cb) {
++    int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, 0);
++    UpdateLastError();
++    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_;
++    ASSERT(sent <= static_cast<int>(cb));  // We have seen minidumps where this may be false
++    if ((sent < 0) && IsBlockingError(error_)) {
++      enabled_events_ |= kfWrite;
++    }
++    return sent;
++  }
++
++  int SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
++    struct sockaddr_in saddr;
++    IP2SA(&addr, &saddr);
++    int sent = ::sendto(
++        s_, (const char *)pv, (int)cb, 0, (struct sockaddr*)&saddr,
++        sizeof(saddr));
++    UpdateLastError();
++    ASSERT(sent <= static_cast<int>(cb));  // We have seen minidumps where this may be false
++    if ((sent < 0) && IsBlockingError(error_)) {
++      enabled_events_ |= kfWrite;
++    }
++    return sent;
++  }
++
++  int Recv(void *pv, size_t cb) {
++    int received = ::recv(s_, (char *)pv, (int)cb, 0);
++    UpdateLastError();
++    if ((received >= 0) || IsBlockingError(error_)) {
++      enabled_events_ |= kfRead;
++    }
++    return received;
++  }
++
++  int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
++    struct sockaddr saddr;
++    socklen_t cbAddr = sizeof(saddr);
++    int received = ::recvfrom(s_, (char *)pv, (int)cb, 0, &saddr, &cbAddr);
++    UpdateLastError();
++    if ((received >= 0) && (paddr != NULL))
++      SA2IP(&saddr, paddr);
++    if ((received >= 0) || IsBlockingError(error_)) {
++      enabled_events_ |= kfRead;
++    }
++    return received;
++  }
++
++  int Listen(int backlog) {
++    int err = ::listen(s_, backlog);
++    UpdateLastError();
++    if (err == 0)
++      state_ = CS_CONNECTING;
++    return err;
++  }
++
++  Socket* Accept(SocketAddress *paddr) {
++    struct sockaddr saddr;
++    socklen_t cbAddr = sizeof(saddr);
++    SOCKET s = ::accept(s_, &saddr, &cbAddr);
++    UpdateLastError();
++    if (s == INVALID_SOCKET)
++      return NULL;
++    if (paddr != NULL)
++      SA2IP(&saddr, paddr);
++    return ss_->WrapSocket(s);
++  }
++
++  int Close() {
++    if (s_ == INVALID_SOCKET)
++      return 0;
++    int err = ::closesocket(s_);
++    UpdateLastError();
++    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Close() Ret: " << err << " Error: " << error_;
++    s_ = INVALID_SOCKET;
++    state_ = CS_CLOSED;
++    enabled_events_ = 0;
++    return err;
++  }
++
++  int EstimateMTU(uint16* mtu) {
++    SocketAddress addr = GetRemoteAddress();
++    if (addr.IsAny()) {
++      error_ = ENOTCONN;
++      return -1;
++    }
++
++#ifdef WIN32
++
++    WinPing ping;
++    if (!ping.IsValid()) {
++      error_ = EINVAL; // can't think of a better error ID
++      return -1;
++    }
++
++    for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) {
++      int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
++      if (ping.Ping(addr.ip(), size, 0, 1, false) != WinPing::PING_TOO_LARGE) {
++        *mtu = PACKET_MAXIMUMS[level];
++        return 0;
++      }
++    }
++
++    assert(false);
++    return 0;
++
++#endif // WIN32
++
++#ifdef __linux 
++
++    int value;
++    socklen_t vlen = sizeof(value);
++    int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen);
++    if (err < 0) {
++      UpdateLastError();
++      return err;
++    }
++
++    assert((0 <= value) && (value <= 65536));
++    *mtu = uint16(value);
++    return 0;
++
++#endif   // __linux
++
++    // TODO: OSX support
++  }
++
++  SocketServer* socketserver() { return ss_; }
++ 
++protected:
++  PhysicalSocketServer* ss_;
++  SOCKET s_;
++  uint32 enabled_events_;
++  int error_;
++  ConnState state_;
++
++  void UpdateLastError() {
++#ifdef WIN32
++    error_ = WSAGetLastError();
++#endif
++#ifdef POSIX
++    error_ = errno;
++#endif
++  }
++
++  void IP2SA(const SocketAddress *paddr, struct sockaddr_in *psaddr) {
++    memset(psaddr, 0, sizeof(*psaddr));
++    psaddr->sin_family = AF_INET;
++    psaddr->sin_port = HostToNetwork16(paddr->port());
++    if (paddr->ip() == 0)
++      psaddr->sin_addr.s_addr = INADDR_ANY;
++    else
++      psaddr->sin_addr.s_addr = HostToNetwork32(paddr->ip());
++  }
++
++  void SA2IP(const struct sockaddr *psaddr, SocketAddress *paddr) {
++    const struct sockaddr_in *psaddr_in =
++        reinterpret_cast<const struct sockaddr_in*>(psaddr);
++    paddr->SetIP(NetworkToHost32(psaddr_in->sin_addr.s_addr));
++    paddr->SetPort(NetworkToHost16(psaddr_in->sin_port));
++  }
++};
++
++#ifdef POSIX
++class Dispatcher {
++public:
++  virtual uint32 GetRequestedEvents() = 0;
++  virtual void OnPreEvent(uint32 ff) = 0;    
++  virtual void OnEvent(uint32 ff, int err) = 0;
++  virtual int GetDescriptor() = 0;
++};
++
++class EventDispatcher : public Dispatcher {
++public:
++  EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
++    if (pipe(afd_) < 0)
++      LOG(LERROR) << "pipe failed";
++    ss_->Add(this);
++  }
++
++  virtual ~EventDispatcher() {
++    ss_->Remove(this);
++    close(afd_[0]);
++    close(afd_[1]);
++  }
++  
++  virtual void Signal() {
++    CritScope cs(&crit_);
++    if (!fSignaled_) {
++      uint8 b = 0;
++      if (write(afd_[1], &b, sizeof(b)) < 0)
++        LOG(LERROR) << "write failed";
++      fSignaled_ = true;
++    }
++  }
++  
++  virtual uint32 GetRequestedEvents() {
++    return kfRead;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++    // It is not possible to perfectly emulate an auto-resetting event with
++    // pipes.  This simulates it by resetting before the event is handled.
++  
++    CritScope cs(&crit_);
++    if (fSignaled_) {
++      uint8 b;
++      read(afd_[0], &b, sizeof(b));
++      fSignaled_ = false;
++    }
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++    assert(false);
++  }
++
++  virtual int GetDescriptor() {
++    return afd_[0];
++  }
++
++private:
++  PhysicalSocketServer *ss_;
++  int afd_[2];
++  bool fSignaled_;
++  CriticalSection crit_;
++};
++
++class SocketDispatcher : public Dispatcher, public PhysicalSocket {
++public:
++  SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
++    ss_->Add(this);
++  }
++  SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) {
++    ss_->Add(this);
++  }
++
++  virtual ~SocketDispatcher() {
++    ss_->Remove(this);
++  }
++
++  bool Initialize() {
++    fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK);
++    return true;
++  }
++
++  virtual bool Create(int type) {
++    // Change the socket to be non-blocking.
++    if (!PhysicalSocket::Create(type))
++      return false;
++
++    return Initialize();
++  }
++  
++  virtual int GetDescriptor() {
++    return s_;
++  }
++
++  virtual uint32 GetRequestedEvents() {
++    return enabled_events_;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++    if ((ff & kfRead) != 0) {
++      enabled_events_ &= ~kfRead;
++      SignalReadEvent(this);
++    }
++    if ((ff & kfWrite) != 0) {
++      enabled_events_ &= ~kfWrite;
++      SignalWriteEvent(this);
++    }
++    if ((ff & kfConnect) != 0) {
++      enabled_events_ &= ~kfConnect;
++      SignalConnectEvent(this);
++    }
++    if ((ff & kfClose) != 0)
++      SignalCloseEvent(this, err);
++  }
++};
++
++class FileDispatcher: public Dispatcher, public AsyncFile {
++public:
++  FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) {
++    set_readable(true);
++
++    ss_->Add(this);
++
++    fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK);
++  }
++
++  virtual ~FileDispatcher() {
++    ss_->Remove(this);
++  }
++
++  SocketServer* socketserver() { return ss_; }
++
++  virtual int GetDescriptor() {
++    return fd_;
++  }
++
++  virtual uint32 GetRequestedEvents() {
++    return flags_;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++    if ((ff & kfRead) != 0)
++      SignalReadEvent(this);
++    if ((ff & kfWrite) != 0)
++      SignalWriteEvent(this);
++    if ((ff & kfClose) != 0)
++      SignalCloseEvent(this, err);
++  }
++
++  virtual bool readable() {
++    return (flags_ & kfRead) != 0;
++  }
++
++  virtual void set_readable(bool value) {
++    flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead);
++  }
++
++  virtual bool writable() {
++    return (flags_ & kfWrite) != 0;
++  }
++
++  virtual void set_writable(bool value) {
++    flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite);
++  }
++
++private:
++  PhysicalSocketServer* ss_;
++  int fd_;
++  int flags_;
++};
++
++AsyncFile* PhysicalSocketServer::CreateFile(int fd) {
++  return new FileDispatcher(fd, this);
++}
++
++#endif // POSIX
++
++#ifdef WIN32
++class Dispatcher {
++public:
++  virtual uint32 GetRequestedEvents() = 0;
++  virtual void OnPreEvent(uint32 ff) = 0;  
++  virtual void OnEvent(uint32 ff, int err) = 0;
++  virtual WSAEVENT GetWSAEvent() = 0;
++  virtual SOCKET GetSocket() = 0;
++  virtual bool CheckSignalClose() = 0;
++};
++
++uint32 FlagsToEvents(uint32 events) {
++  uint32 ffFD = FD_CLOSE | FD_ACCEPT;
++  if (events & kfRead)
++    ffFD |= FD_READ;
++  if (events & kfWrite)
++    ffFD |= FD_WRITE;
++  if (events & kfConnect)
++    ffFD |= FD_CONNECT;
++  return ffFD;
++}
++
++class EventDispatcher : public Dispatcher {
++public:
++  EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) {
++    if (hev_ = WSACreateEvent()) {
++      ss_->Add(this);
++    }
++  }
++
++  ~EventDispatcher() {
++    if (hev_ != NULL) {
++      ss_->Remove(this);
++      WSACloseEvent(hev_);
++      hev_ = NULL;
++    }
++  }
++  
++  virtual void Signal() {
++    if (hev_ != NULL)
++      WSASetEvent(hev_);
++  }
++  
++  virtual uint32 GetRequestedEvents() {
++    return 0;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++    WSAResetEvent(hev_);
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++  }
++
++  virtual WSAEVENT GetWSAEvent() {
++    return hev_;
++  }
++
++  virtual SOCKET GetSocket() {
++    return INVALID_SOCKET;
++  }
++
++  virtual bool CheckSignalClose() { return false; }
++
++private:
++  PhysicalSocketServer* ss_;
++  WSAEVENT hev_;
++};
++
++class SocketDispatcher : public Dispatcher, public PhysicalSocket {
++public:
++  static int next_id_;
++  int id_;
++  bool signal_close_;
++  int signal_err_;
++
++  SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) {
++  }
++  SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) {
++  }
++
++  virtual ~SocketDispatcher() {
++    Close();
++  }
++
++  bool Initialize() {
++    assert(s_ != INVALID_SOCKET);
++    // Must be a non-blocking
++    u_long argp = 1;
++    ioctlsocket(s_, FIONBIO, &argp);
++    ss_->Add(this);
++    return true;
++  }
++ 
++  virtual bool Create(int type) {
++    // Create socket
++    if (!PhysicalSocket::Create(type))
++      return false;
++
++    if (!Initialize())
++      return false;
++
++    do { id_ = ++next_id_; } while (id_ == 0);
++    return true;
++  }
++
++  virtual int Close() {
++    if (s_ == INVALID_SOCKET)
++      return 0;
++
++    id_ = 0;
++    signal_close_ = false;
++    ss_->Remove(this);
++    return PhysicalSocket::Close();
++  }
++
++  virtual uint32 GetRequestedEvents() {
++    return enabled_events_;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++    if ((ff & kfConnect) != 0)
++      state_ = CS_CONNECTED;
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++    int cache_id = id_;
++    if ((ff & kfRead) != 0) {
++      enabled_events_ &= ~kfRead;
++      SignalReadEvent(this);
++    }
++    if (((ff & kfWrite) != 0) && (id_ == cache_id)) {
++      enabled_events_ &= ~kfWrite;
++      SignalWriteEvent(this);
++    }
++    if (((ff & kfConnect) != 0) && (id_ == cache_id)) {
++      enabled_events_ &= ~kfConnect;
++      SignalConnectEvent(this);
++    }
++    if (((ff & kfClose) != 0) && (id_ == cache_id)) {
++      //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] OnClose() Error: " << err;
++      signal_close_ = true;
++      signal_err_ = err;
++    }
++  }
++
++  virtual WSAEVENT GetWSAEvent() {
++    return WSA_INVALID_EVENT;
++  }
++
++  virtual SOCKET GetSocket() {
++    return s_;
++  }
++
++  virtual bool CheckSignalClose() {
++    if (!signal_close_)
++      return false;
++
++    char ch;
++    if (recv(s_, &ch, 1, MSG_PEEK) > 0)
++      return false;
++
++    signal_close_ = false;
++    SignalCloseEvent(this, signal_err_);
++    return true;
++  }
++};
++
++int SocketDispatcher::next_id_ = 0;
++
++#endif // WIN32
++
++// Sets the value of a boolean value to false when signaled.
++class Signaler : public EventDispatcher {
++public:
++  Signaler(PhysicalSocketServer* ss, bool* pf)
++      : EventDispatcher(ss), pf_(pf) {
++  }
++  virtual ~Signaler() { }
++
++  void OnEvent(uint32 ff, int err) {
++    if (pf_)
++      *pf_ = false;
++  }
++
++private:
++  bool *pf_;
++};
++
++PhysicalSocketServer::PhysicalSocketServer() : fWait_(false),
++  last_tick_tracked_(0), last_tick_dispatch_count_(0) {
++  signal_wakeup_ = new Signaler(this, &fWait_);
++}
++
++PhysicalSocketServer::~PhysicalSocketServer() {
++  delete signal_wakeup_;
++}
++
++void PhysicalSocketServer::WakeUp() {
++  signal_wakeup_->Signal();
++}
++
++Socket* PhysicalSocketServer::CreateSocket(int type) {
++  PhysicalSocket* socket = new PhysicalSocket(this);
++  if (socket->Create(type)) {
++    return socket;
++  } else {
++    delete socket;
++    return 0;
++  }
++}
++
++AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) {
++  SocketDispatcher* dispatcher = new SocketDispatcher(this);
++  if (dispatcher->Create(type)) {
++    return dispatcher;
++  } else {
++    delete dispatcher;
++    return 0;
++  }
++}
++
++AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) {
++  SocketDispatcher* dispatcher = new SocketDispatcher(s, this);
++  if (dispatcher->Initialize()) {
++    return dispatcher;
++  } else {
++    delete dispatcher;
++    return 0;
++  }
++}
++
++void PhysicalSocketServer::Add(Dispatcher *pdispatcher) {
++  CritScope cs(&crit_);
++  dispatchers_.push_back(pdispatcher);
++}
++
++void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) {
++  CritScope cs(&crit_);
++  dispatchers_.erase(std::remove(dispatchers_.begin(), dispatchers_.end(), pdispatcher), dispatchers_.end());
++}
++
++#ifdef POSIX
++bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
++  // Calculate timing information
++
++  struct timeval *ptvWait = NULL;
++  struct timeval tvWait;
++  struct timeval tvStop;
++  if (cmsWait != -1) {
++    // Calculate wait timeval
++    tvWait.tv_sec = cmsWait / 1000;
++    tvWait.tv_usec = (cmsWait % 1000) * 1000;
++    ptvWait = &tvWait;
++
++    // Calculate when to return in a timeval
++    gettimeofday(&tvStop, NULL);
++    tvStop.tv_sec += tvWait.tv_sec;
++    tvStop.tv_usec += tvWait.tv_usec;
++    if (tvStop.tv_usec >= 1000000) {
++      tvStop.tv_usec -= 1000000;
++      tvStop.tv_sec += 1;
++    }
++  }
++
++  // Zero all fd_sets. Don't need to do this inside the loop since
++  // select() zeros the descriptors not signaled
++  
++  fd_set fdsRead;
++  FD_ZERO(&fdsRead);
++  fd_set fdsWrite;
++  FD_ZERO(&fdsWrite);
++ 
++  fWait_ = true;
++
++  while (fWait_) {
++    int fdmax = -1;
++    {
++      CritScope cr(&crit_);
++      for (unsigned i = 0; i < dispatchers_.size(); i++) {
++        // Query dispatchers for read and write wait state
++      
++        Dispatcher *pdispatcher = dispatchers_[i];
++        assert(pdispatcher);
++        if (!process_io && (pdispatcher != signal_wakeup_))
++          continue;
++        int fd = pdispatcher->GetDescriptor();
++        if (fd > fdmax)
++          fdmax = fd;
++        uint32 ff = pdispatcher->GetRequestedEvents();
++        if (ff & kfRead)
++          FD_SET(fd, &fdsRead);
++        if (ff & (kfWrite | kfConnect))
++          FD_SET(fd, &fdsWrite);
++      }
++    }
++      
++    // Wait then call handlers as appropriate
++    // < 0 means error
++    // 0 means timeout
++    // > 0 means count of descriptors ready
++    int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait);
++    
++    // If error, return error
++    // todo: do something intelligent
++    
++    if (n < 0)
++      return false;
++    
++    // If timeout, return success
++    
++    if (n == 0)
++      return true;
++    
++    // We have signaled descriptors
++   
++    {
++      CritScope cr(&crit_);
++      for (unsigned i = 0; i < dispatchers_.size(); i++) {
++        Dispatcher *pdispatcher = dispatchers_[i];
++        int fd = pdispatcher->GetDescriptor();
++        uint32 ff = 0;
++        if (FD_ISSET(fd, &fdsRead)) {
++          FD_CLR(fd, &fdsRead);
++          ff |= kfRead;
++        }
++        if (FD_ISSET(fd, &fdsWrite)) {
++          FD_CLR(fd, &fdsWrite);
++          if (pdispatcher->GetRequestedEvents() & kfConnect) {
++            ff |= kfConnect;
++          } else {
++            ff |= kfWrite;
++          }
++        }
++        if (ff != 0) {
++          pdispatcher->OnPreEvent(ff);
++          pdispatcher->OnEvent(ff, 0);
++        }
++      }
++    }
++
++    // Recalc the time remaining to wait. Doing it here means it doesn't get
++    // calced twice the first time through the loop
++
++    if (cmsWait != -1) {
++      ptvWait->tv_sec = 0;
++      ptvWait->tv_usec = 0;
++      struct timeval tvT;
++      gettimeofday(&tvT, NULL);
++      if (tvStop.tv_sec >= tvT.tv_sec) {
++        ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
++        ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
++        if (ptvWait->tv_usec < 0) {
++          ptvWait->tv_usec += 1000000;
++          ptvWait->tv_sec -= 1;
++        }
++      }
++    }
++  }
++        
++  return true;
++}
++#endif // POSIX
++
++#ifdef WIN32
++bool PhysicalSocketServer::Wait(int cmsWait, bool process_io)
++{
++  int cmsTotal = cmsWait;
++  int cmsElapsed = 0;
++  uint32 msStart = GetMillisecondCount();
++
++#if LOGGING
++  if (last_tick_dispatch_count_ == 0) {
++    last_tick_tracked_ = msStart;
++  }
++#endif
++
++  WSAEVENT socket_ev = WSACreateEvent();
++  
++  fWait_ = true;
++  while (fWait_) {
++    std::vector<WSAEVENT> events;
++    std::vector<Dispatcher *> event_owners;
++
++    events.push_back(socket_ev);
++
++    {
++      CritScope cr(&crit_);
++      for (size_t i = 0; i < dispatchers_.size(); ++i) {
++        Dispatcher * disp = dispatchers_[i];
++        if (!process_io && (disp != signal_wakeup_))
++          continue;
++        SOCKET s = disp->GetSocket();
++        if (disp->CheckSignalClose()) {
++          // We just signalled close, don't poll this socket
++        } else if (s != INVALID_SOCKET) {
++          WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents()));
++        } else {
++          events.push_back(disp->GetWSAEvent());
++          event_owners.push_back(disp);
++        }
++      }
++    }
++
++    // Which is shorter, the delay wait or the asked wait?
++
++    int cmsNext;
++    if (cmsWait == -1) {
++      cmsNext = cmsWait;
++    } else {
++      cmsNext = cmsTotal - cmsElapsed;
++      if (cmsNext < 0)
++        cmsNext = 0;
++    }
++
++    // Wait for one of the events to signal
++    DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0], false, cmsNext, false);
++
++#if 0  // LOGGING
++    // we track this information purely for logging purposes.
++    last_tick_dispatch_count_++;
++    if (last_tick_dispatch_count_ >= 1000) {
++      uint32 now = GetMillisecondCount();
++      LOG(INFO) << "PhysicalSocketServer took " << TimeDiff(now, last_tick_tracked_) << "ms for 1000 events";
++
++      // If we get more than 1000 events in a second, we are spinning badly
++      // (normally it should take about 8-20 seconds).
++      assert(TimeDiff(now, last_tick_tracked_) > 1000);
++      
++      last_tick_tracked_ = now;
++      last_tick_dispatch_count_ = 0;
++    }
++#endif
++
++    // Failed?
++    // todo: need a better strategy than this!
++
++    if (dw == WSA_WAIT_FAILED) {
++      int error = WSAGetLastError();
++      assert(false);
++      WSACloseEvent(socket_ev);
++      return false;
++    }
++
++    // Timeout?
++
++    if (dw == WSA_WAIT_TIMEOUT) {
++      WSACloseEvent(socket_ev);
++      return true;
++    }
++
++    // Figure out which one it is and call it
++
++    {
++      CritScope cr(&crit_);
++      int index = dw - WSA_WAIT_EVENT_0;
++      if (index > 0) {
++        --index; // The first event is the socket event
++        event_owners[index]->OnPreEvent(0);
++        event_owners[index]->OnEvent(0, 0);
++      } else if (process_io) {
++        for (size_t i = 0; i < dispatchers_.size(); ++i) {
++          Dispatcher * disp = dispatchers_[i];
++          SOCKET s = disp->GetSocket();
++          if (s == INVALID_SOCKET)
++            continue;
++
++          WSANETWORKEVENTS wsaEvents;
++          int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents);
++          if (err == 0) {
++            
++#if LOGGING
++            {
++              if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT];
++              }
++              if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT];
++              }
++              if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT];
++              }
++              if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
++              }
++              if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT];
++              }
++            }
++#endif
++            uint32 ff = 0;
++            int errcode = 0;
++            if (wsaEvents.lNetworkEvents & FD_READ)
++              ff |= kfRead;
++            if (wsaEvents.lNetworkEvents & FD_WRITE)
++              ff |= kfWrite;
++            if (wsaEvents.lNetworkEvents & FD_CONNECT) {
++              if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
++                ff |= kfConnect;
++              } else {
++                // TODO: Decide whether we want to signal connect, but with an error code
++                ff |= kfClose; 
++                errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
++              }
++            }
++            if (wsaEvents.lNetworkEvents & FD_ACCEPT)
++              ff |= kfRead;
++            if (wsaEvents.lNetworkEvents & FD_CLOSE) {
++              ff |= kfClose;
++              errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
++            }
++            if (ff != 0) {
++              disp->OnPreEvent(ff);
++              disp->OnEvent(ff, errcode);
++            }
++          }
++        }
++      }
++
++      // Reset the network event until new activity occurs
++      WSAResetEvent(socket_ev);
++    }
++
++    // Break?
++
++    if (!fWait_)
++      break;
++    cmsElapsed = GetMillisecondCount() - msStart;
++    if (cmsWait != -1) {
++      if (cmsElapsed >= cmsWait)
++        break;
++    }
++  }
++  
++  // Done
++  
++  WSACloseEvent(socket_ev);
++  return true;
++}
++#endif // WIN32
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc	(revision 586398)
+@@ -0,0 +1,1130 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#pragma warning(disable:4786)
++#endif
++
++#include <time.h>
++
++#ifdef WIN32
++#include <winsock2.h>
++#include <ws2tcpip.h>
++#define _WINSOCKAPI_
++#include <windows.h>
++#include <wininet.h>  // HTTP_STATUS_PROXY_AUTH_REQ
++#define SECURITY_WIN32
++#include <security.h>
++#endif
++
++#include <cassert>
++
++#include "talk/base/base64.h"
++#include "talk/base/basicdefs.h"
++#include "talk/base/bytebuffer.h"
++#include "talk/base/common.h"
++#include "talk/base/logging.h"
++#include "talk/base/md5.h"
++#include "talk/base/socketadapters.h"
++#include "talk/base/stringutils.h"
++
++#include <errno.h>
++
++
++#ifdef WIN32
++#include "talk/base/sec_buffer.h"
++#endif // WIN32
++
++namespace cricket {
++
++#ifdef WIN32
++extern const ConstantLabel SECURITY_ERRORS[];
++#endif
++
++BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size)
++  : AsyncSocketAdapter(socket), buffer_size_(buffer_size), data_len_(0), buffering_(false) {
++  buffer_ = new char[buffer_size_];
++}
++
++BufferedReadAdapter::~BufferedReadAdapter() {
++  delete [] buffer_;
++}
++
++int BufferedReadAdapter::Send(const void *pv, size_t cb) {
++  if (buffering_) {
++    // TODO: Spoof error better; Signal Writeable
++    socket_->SetError(EWOULDBLOCK);
++    return -1;
++  }
++  return AsyncSocketAdapter::Send(pv, cb);
++}
++
++int BufferedReadAdapter::Recv(void *pv, size_t cb) {
++  if (buffering_) {
++    socket_->SetError(EWOULDBLOCK);
++    return -1;
++  }
++
++  size_t read = 0;
++
++  if (data_len_) {
++    read = _min(cb, data_len_);
++    memcpy(pv, buffer_, read);
++    data_len_ -= read;
++    if (data_len_ > 0) {
++      memmove(buffer_, buffer_ + read, data_len_);
++    }
++    pv = static_cast<char *>(pv) + read;
++    cb -= read;
++  }
++
++  // FIX: If cb == 0, we won't generate another read event
++
++  int res = AsyncSocketAdapter::Recv(pv, cb);
++  if (res < 0)
++    return res;
++
++  return res + static_cast<int>(read);
++}
++
++void BufferedReadAdapter::BufferInput(bool on) {
++  buffering_ = on;
++}
++
++void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
++  assert(socket == socket_);
++
++  if (!buffering_) {
++    AsyncSocketAdapter::OnReadEvent(socket);
++    return;
++  }
++
++  if (data_len_ >= buffer_size_) {
++    LOG(INFO) << "Input buffer overflow";
++    assert(false);
++    data_len_ = 0;
++  }
++
++  int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_);
++  if (len < 0) {
++    // TODO: Do something better like forwarding the error to the user.
++    LOG(INFO) << "Recv: " << errno << " " <<  std::strerror(errno);
++    return;
++  }
++
++  data_len_ += len;
++
++  ProcessInput(buffer_, data_len_);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++
++const uint8 SSL_SERVER_HELLO[] = {
++  22,3,1,0,74,2,0,0,70,3,1,66,133,69,167,39,169,93,160,
++  179,197,231,83,218,72,43,63,198,90,202,137,193,88,82,
++  161,120,60,91,23,70,0,133,63,32,14,211,6,114,91,91,
++  27,95,21,172,19,249,136,83,157,155,232,61,123,12,48,
++  50,110,56,77,162,117,87,65,108,52,92,0,4,0
++};
++
++const char SSL_CLIENT_HELLO[] = {
++  -128,70,1,3,1,0,45,0,0,0,16,1,0,-128,3,0,-128,7,0,-64,6,0,64,2,0,
++  -128,4,0,-128,0,0,4,0,-2,-1,0,0,10,0,-2,-2,0,0,9,0,0,100,0,0,98,0,
++  0,3,0,0,6,31,23,12,-90,47,0,120,-4,70,85,46,-79,-125,57,-15,-22
++};
++
++AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) : BufferedReadAdapter(socket, 1024) {
++}
++
++int AsyncSSLSocket::Connect(const SocketAddress& addr) {
++  // Begin buffering before we connect, so that there isn't a race condition between
++  // potential senders and receiving the OnConnectEvent signal
++  BufferInput(true);
++  return BufferedReadAdapter::Connect(addr);
++}
++
++void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
++  assert(socket == socket_);
++
++  // TODO: we could buffer output too...
++  int res = DirectSend(SSL_CLIENT_HELLO, sizeof(SSL_CLIENT_HELLO));
++  assert(res == sizeof(SSL_CLIENT_HELLO));
++}
++
++void AsyncSSLSocket::ProcessInput(char * data, size_t& len) {
++  if (len < sizeof(SSL_SERVER_HELLO))
++    return;
++
++  if (memcmp(SSL_SERVER_HELLO, data, sizeof(SSL_SERVER_HELLO)) != 0) {
++    Close();
++    SignalCloseEvent(this, 0); // TODO: error code?
++    return;
++  }
++
++  len -= sizeof(SSL_SERVER_HELLO);
++  if (len > 0) {
++    memmove(data, data + sizeof(SSL_SERVER_HELLO), len);
++  }
++
++  bool remainder = (len > 0);
++  BufferInput(false);
++  SignalConnectEvent(this);
++
++  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
++  if (remainder)
++    SignalReadEvent(this);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++
++#define TEST_DIGEST 0
++#if TEST_DIGEST
++/*
++const char * const DIGEST_CHALLENGE =
++  "Digest realm=\"testrealm at host.com\","
++  " qop=\"auth,auth-int\","
++  " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
++  " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
++const char * const DIGEST_METHOD = "GET";
++const char * const DIGEST_URI =
++  "/dir/index.html";;
++const char * const DIGEST_CNONCE =
++  "0a4f113b";
++const char * const DIGEST_RESPONSE =
++  "6629fae49393a05397450978507c4ef1";
++//user_ = "Mufasa";
++//pass_ = "Circle Of Life";
++*/
++const char * const DIGEST_CHALLENGE =
++  "Digest realm=\"Squid proxy-caching web server\","
++  " nonce=\"Nny4QuC5PwiSDixJ\","
++  " qop=\"auth\","
++  " stale=false";
++const char * const DIGEST_URI =
++  "/";
++const char * const DIGEST_CNONCE =
++  "6501d58e9a21cee1e7b5fec894ded024";
++const char * const DIGEST_RESPONSE =
++  "edffcb0829e755838b073a4a42de06bc";
++#endif
++
++static std::string MD5(const std::string& data) {
++  MD5_CTX ctx;
++  MD5Init(&ctx);
++  MD5Update(&ctx, const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(data.data())), static_cast<unsigned int>(data.size()));
++  unsigned char digest[16];
++  MD5Final(digest, &ctx);
++  std::string hex_digest;
++  const char HEX[] = "0123456789abcdef";
++  for (int i=0; i<16; ++i) {
++    hex_digest += HEX[digest[i] >> 4];
++    hex_digest += HEX[digest[i] & 0xf];
++  }
++  return hex_digest;
++}
++
++static std::string Quote(const std::string& str) {
++  std::string result;
++  result.push_back('"');
++  for (size_t i=0; i<str.size(); ++i) {
++    if ((str[i] == '"') || (str[i] == '\\'))
++      result.push_back('\\');
++    result.push_back(str[i]);
++  }
++  result.push_back('"');
++  return result;
++}
++
++#ifdef WIN32
++struct NegotiateAuthContext : public AsyncHttpsProxySocket::AuthContext {
++  CredHandle cred;
++  CtxtHandle ctx;
++  size_t steps;
++  bool specified_credentials;
++
++  NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
++    : AuthContext(auth), cred(c1), ctx(c2), steps(0), specified_credentials(false) { }
++
++  virtual ~NegotiateAuthContext() {
++    DeleteSecurityContext(&ctx);
++    FreeCredentialsHandle(&cred);
++  }
++};
++#endif // WIN32
++
++AsyncHttpsProxySocket::AuthResult
++AsyncHttpsProxySocket::Authenticate(const char * challenge, size_t len,
++                                    const SocketAddress& server,
++                                    const std::string& method, const std::string& uri,
++                                    const std::string& username, const buzz::XmppPassword& password,
++                                    AuthContext *& context, std::string& response, std::string& auth_method) {
++#if TEST_DIGEST
++  challenge = DIGEST_CHALLENGE;
++  len = strlen(challenge);
++#endif
++
++  std::map<std::string, std::string> args;
++  ParseAuth(challenge, len, auth_method, args);
++
++  if (context && (context->auth_method != auth_method))
++    return AR_IGNORE;
++
++  // BASIC
++  if (stricmp(auth_method.c_str(), "basic") == 0) {
++    if (context)
++      return AR_CREDENTIALS; // Bad credentials
++    if (username.empty())
++      return AR_CREDENTIALS; // Missing credentials
++
++    context = new AuthContext(auth_method);
++
++    // TODO: convert sensitive to a secure buffer that gets securely deleted
++    //std::string decoded = username + ":" + password;
++    size_t len = username.size() + password.GetLength() + 2;
++    char * sensitive = new char[len];
++    size_t pos = strcpyn(sensitive, len, username.data(), username.size());
++    pos += strcpyn(sensitive + pos, len - pos, ":");
++    password.CopyTo(sensitive + pos, true);
++
++    response = auth_method;
++    response.append(" ");
++    // TODO: create a sensitive-source version of Base64::encode
++    response.append(Base64::encode(sensitive));
++    memset(sensitive, 0, len);
++    delete [] sensitive;
++    return AR_RESPONSE;
++  }
++
++  // DIGEST
++  if (stricmp(auth_method.c_str(), "digest") == 0) {
++    if (context)
++      return AR_CREDENTIALS; // Bad credentials
++    if (username.empty())
++      return AR_CREDENTIALS; // Missing credentials
++
++    context = new AuthContext(auth_method);
++
++    std::string cnonce, ncount;
++#if TEST_DIGEST
++    method = DIGEST_METHOD;
++    uri    = DIGEST_URI;
++    cnonce = DIGEST_CNONCE;
++#else
++    char buffer[256];
++    sprintf(buffer, "%d", time(0));
++    cnonce = MD5(buffer);
++#endif
++    ncount = "00000001";
++
++    // TODO: convert sensitive to be secure buffer
++    //std::string A1 = username + ":" + args["realm"] + ":" + password;
++    size_t len = username.size() + args["realm"].size() + password.GetLength() + 3;
++    char * sensitive = new char[len];  // A1
++    size_t pos = strcpyn(sensitive, len, username.data(), username.size());
++    pos += strcpyn(sensitive + pos, len - pos, ":");
++    pos += strcpyn(sensitive + pos, len - pos, args["realm"].c_str());
++    pos += strcpyn(sensitive + pos, len - pos, ":");
++    password.CopyTo(sensitive + pos, true);
++
++    std::string A2 = method + ":" + uri;
++    std::string middle;
++    if (args.find("qop") != args.end()) {
++      args["qop"] = "auth";
++      middle = args["nonce"] + ":" + ncount + ":" + cnonce + ":" + args["qop"];
++    } else {
++      middle = args["nonce"];
++    }
++    std::string HA1 = MD5(sensitive);
++    memset(sensitive, 0, len);
++    delete [] sensitive;
++    std::string HA2 = MD5(A2);
++    std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
++
++#if TEST_DIGEST
++    assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
++#endif
++
++    std::stringstream ss;
++    ss << auth_method;
++    ss << " username=" << Quote(username);
++    ss << ", realm=" << Quote(args["realm"]);
++    ss << ", nonce=" << Quote(args["nonce"]);
++    ss << ", uri=" << Quote(uri);
++    if (args.find("qop") != args.end()) {
++      ss << ", qop=" << args["qop"];
++      ss << ", nc="  << ncount;
++      ss << ", cnonce=" << Quote(cnonce);
++    }
++    ss << ", response=\"" << dig_response << "\"";
++    if (args.find("opaque") != args.end()) {
++      ss << ", opaque=" << Quote(args["opaque"]);
++    }
++    response = ss.str();
++    return AR_RESPONSE;
++  }
++
++#ifdef WIN32
++#if 1
++  bool want_negotiate = (stricmp(auth_method.c_str(), "negotiate") == 0);
++  bool want_ntlm = (stricmp(auth_method.c_str(), "ntlm") == 0);
++  // SPNEGO & NTLM
++  if (want_negotiate || want_ntlm) {
++    const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
++    char out_buf[MAX_MESSAGE], spn[MAX_SPN];
++
++#if 0 // Requires funky windows versions
++    DWORD len = MAX_SPN;
++    if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(), 0, &len, spn) != ERROR_SUCCESS) {
++      LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) - DsMakeSpn failed";
++      return AR_IGNORE;
++    }
++#else
++    sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());
++#endif
++
++    SecBuffer out_sec;
++    out_sec.pvBuffer   = out_buf;
++    out_sec.cbBuffer   = sizeof(out_buf);
++    out_sec.BufferType = SECBUFFER_TOKEN;
++
++    SecBufferDesc out_buf_desc;
++    out_buf_desc.ulVersion = 0;
++    out_buf_desc.cBuffers  = 1;
++    out_buf_desc.pBuffers  = &out_sec;
++
++    const ULONG NEG_FLAGS_DEFAULT =
++      //ISC_REQ_ALLOCATE_MEMORY
++      ISC_REQ_CONFIDENTIALITY
++      //| ISC_REQ_EXTENDED_ERROR
++      //| ISC_REQ_INTEGRITY
++      | ISC_REQ_REPLAY_DETECT
++      | ISC_REQ_SEQUENCE_DETECT
++      //| ISC_REQ_STREAM
++      //| ISC_REQ_USE_SUPPLIED_CREDS
++      ;
++
++    TimeStamp lifetime;
++    SECURITY_STATUS ret = S_OK;
++    ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT;
++
++    bool specify_credentials = !username.empty();
++    size_t steps = 0;
++
++    //uint32 now = cricket::Time();
++
++    NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context);
++    if (neg) {
++      const size_t max_steps = 10;
++      if (++neg->steps >= max_steps) {
++        LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries";
++        return AR_ERROR;
++      }
++      steps = neg->steps;
++
++      std::string decoded_challenge = Base64::decode(args[""]);
++      if (!decoded_challenge.empty()) {
++        SecBuffer in_sec;
++        in_sec.pvBuffer   = const_cast<char *>(decoded_challenge.data());
++        in_sec.cbBuffer   = static_cast<unsigned long>(decoded_challenge.size());
++        in_sec.BufferType = SECBUFFER_TOKEN;
++
++        SecBufferDesc in_buf_desc;
++        in_buf_desc.ulVersion = 0;
++        in_buf_desc.cBuffers  = 1;
++        in_buf_desc.pBuffers  = &in_sec;
++
++        ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
++        //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now);
++        if (FAILED(ret)) {
++          LOG(LS_ERROR) << "InitializeSecurityContext returned: "
++                      << ErrorName(ret, SECURITY_ERRORS);
++          return AR_ERROR;
++        }
++      } else if (neg->specified_credentials) {
++        // Try again with default credentials
++        specify_credentials = false;
++        delete context;
++        context = neg = 0;
++      } else {
++        return AR_CREDENTIALS;
++      }
++    }
++
++    if (!neg) {
++      unsigned char userbuf[256], passbuf[256], domainbuf[16];
++      SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0;
++      if (specify_credentials) {
++        memset(&auth_id, 0, sizeof(auth_id));
++        size_t len = password.GetLength()+1;
++        char * sensitive = new char[len];
++        password.CopyTo(sensitive, true);
++        std::string::size_type pos = username.find('\\');
++        if (pos == std::string::npos) {
++          auth_id.UserLength = static_cast<unsigned long>(
++            _min(sizeof(userbuf) - 1, username.size()));
++          memcpy(userbuf, username.c_str(), auth_id.UserLength);
++          userbuf[auth_id.UserLength] = 0;
++          auth_id.DomainLength = 0;
++          domainbuf[auth_id.DomainLength] = 0;
++          auth_id.PasswordLength = static_cast<unsigned long>(
++            _min(sizeof(passbuf) - 1, password.GetLength()));
++          memcpy(passbuf, sensitive, auth_id.PasswordLength);
++          passbuf[auth_id.PasswordLength] = 0;
++        } else {
++          auth_id.UserLength = static_cast<unsigned long>(
++            _min(sizeof(userbuf) - 1, username.size() - pos - 1));
++          memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength);
++          userbuf[auth_id.UserLength] = 0;
++          auth_id.DomainLength = static_cast<unsigned long>(
++            _min(sizeof(domainbuf) - 1, pos));
++          memcpy(domainbuf, username.c_str(), auth_id.DomainLength);
++          domainbuf[auth_id.DomainLength] = 0;
++          auth_id.PasswordLength = static_cast<unsigned long>(
++            _min(sizeof(passbuf) - 1, password.GetLength()));
++          memcpy(passbuf, sensitive, auth_id.PasswordLength);
++          passbuf[auth_id.PasswordLength] = 0;
++        }
++        memset(sensitive, 0, len);
++        delete [] sensitive;
++        auth_id.User = userbuf;
++        auth_id.Domain = domainbuf;
++        auth_id.Password = passbuf;
++        auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
++        pauth_id = &auth_id;
++        LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials";
++      } else {
++        LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials";
++      }
++
++      CredHandle cred;
++      ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime);
++      //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << cricket::TimeDiff(cricket::Time(), now);
++      if (ret != SEC_E_OK) {
++        LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
++                    << ErrorName(ret, SECURITY_ERRORS);
++        return AR_IGNORE;
++      }
++
++      //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
++
++      CtxtHandle ctx;
++      ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime);
++      //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now);
++      if (FAILED(ret)) {
++        LOG(LS_ERROR) << "InitializeSecurityContext returned: "
++                    << ErrorName(ret, SECURITY_ERRORS);
++        FreeCredentialsHandle(&cred);
++        return AR_IGNORE;
++      }
++
++      assert(!context);
++      context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
++      neg->specified_credentials = specify_credentials;
++      neg->steps = steps;
++    }
++
++    if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
++      ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
++      //LOG(INFO) << "$$$ CompleteAuthToken @ " << cricket::TimeDiff(cricket::Time(), now);
++      LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
++                      << ErrorName(ret, SECURITY_ERRORS);
++      if (FAILED(ret)) {
++        return AR_ERROR;
++      }
++    }
++
++    //LOG(INFO) << "$$$ NEGOTIATE took " << cricket::TimeDiff(cricket::Time(), now) << "ms";
++
++    std::string decoded(out_buf, out_buf + out_sec.cbBuffer);
++    response = auth_method;
++    response.append(" ");
++    response.append(Base64::encode(decoded));
++    return AR_RESPONSE;
++  }
++#endif
++#endif // WIN32
++
++  return AR_IGNORE;
++}
++
++inline bool end_of_name(size_t pos, size_t len, const char * data) {
++  if (pos >= len)
++    return true;
++  if (isspace(data[pos]))
++    return true;
++  // The reason for this complexity is that some non-compliant auth schemes (like Negotiate)
++  // use base64 tokens in the challenge instead of name=value.  This could confuse us when the
++  // base64 ends in equal signs.
++  if ((pos+1 < len) && (data[pos] == '=') && !isspace(data[pos+1]) && (data[pos+1] != '='))
++    return true;
++  return false;
++}
++
++void AsyncHttpsProxySocket::ParseAuth(const char * data, size_t len, std::string& method, std::map<std::string,std::string>& args) {
++  size_t pos = 0;
++  while ((pos < len) && isspace(data[pos])) ++pos;
++  size_t start = pos;
++  while ((pos < len) && !isspace(data[pos])) ++pos;
++  method.assign(data + start, data + pos);
++  while (pos < len) {
++    while ((pos < len) && isspace(data[pos])) ++pos;
++    if (pos >= len)
++      return;
++
++    start = pos;
++    while (!end_of_name(pos, len, data)) ++pos;
++    //while ((pos < len) && !isspace(data[pos]) && (data[pos] != '=')) ++pos;
++    std::string name(data + start, data + pos), value;
++
++    if ((pos < len) && (data[pos] == '=')) {
++      ++pos; // Skip '='
++      // Check if quoted value
++      if ((pos < len) && (data[pos] == '"')) {
++        while (++pos < len) {
++          if (data[pos] == '"') {
++            ++pos;
++            break;
++          }
++          if ((data[pos] == '\\') && (pos + 1 < len))
++            ++pos;
++          value.append(1, data[pos]);
++        }
++      } else {
++        while ((pos < len) && !isspace(data[pos]) && (data[pos] != ','))
++          value.append(1, data[pos++]);
++      }
++    } else {
++      value = name;
++      name.clear();
++    }
++
++    args.insert(std::make_pair(name, value));
++    if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ','
++  }
++}
++
++AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
++                                   const std::string& username, const buzz::XmppPassword& password)
++  : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password),
++    state_(PS_ERROR), context_(0) {
++}
++
++AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
++  delete context_;
++}
++
++int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
++  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect(" << proxy_.ToString() << ")";
++  dest_ = addr;
++  if (dest_.port() != 80) {
++    BufferInput(true);
++  }
++  return BufferedReadAdapter::Connect(proxy_);
++}
++
++SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
++  return dest_;
++}
++
++int AsyncHttpsProxySocket::Close() {
++  headers_.clear();
++  state_ = PS_ERROR;
++  delete context_;
++  context_ = 0;
++  return BufferedReadAdapter::Close();
++}
++
++void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
++  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
++  // TODO: Decide whether tunneling or not should be explicitly set,
++  // or indicated by destination port (as below)
++  if (dest_.port() == 80) {
++    state_ = PS_TUNNEL;
++    BufferedReadAdapter::OnConnectEvent(socket);
++    return;
++  }
++  SendRequest();
++}
++
++void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
++  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
++  if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
++    state_ = PS_ERROR;
++    Connect(dest_);
++  } else {
++    BufferedReadAdapter::OnCloseEvent(socket, err);
++  }
++}
++
++void AsyncHttpsProxySocket::ProcessInput(char * data, size_t& len) {
++  size_t start = 0;
++  for (size_t pos = start; (state_ < PS_TUNNEL) && (pos < len); ) {
++    if (state_ == PS_SKIP_BODY) {
++      size_t consume = _min(len - pos, content_length_);
++      pos += consume;
++      start = pos;
++      content_length_ -= consume;
++      if (content_length_ == 0) {
++        EndResponse();
++      }
++      continue;
++    }
++
++    if (data[pos++] != '\n')
++      continue;
++
++    size_t len = pos - start - 1;
++    if ((len > 0) && (data[start + len - 1] == '\r'))
++      --len;
++
++    data[start + len] = 0;
++    ProcessLine(data + start, len);
++    start = pos;
++  }
++
++  len -= start;
++  if (len > 0) {
++    memmove(data, data + start, len);
++  }
++
++  if (state_ != PS_TUNNEL)
++    return;
++
++  bool remainder = (len > 0);
++  BufferInput(false);
++  SignalConnectEvent(this);
++
++  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
++  if (remainder)
++    SignalReadEvent(this); // TODO: signal this??
++}
++
++void AsyncHttpsProxySocket::SendRequest() {
++  std::stringstream ss;
++  ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
++  ss << "User-Agent: " USERAGENT_STRING "\r\n";
++  ss << "Host: " << dest_.IPAsString() << "\r\n";
++  ss << "Content-Length: 0\r\n";
++  ss << "Proxy-Connection: Keep-Alive\r\n";
++  ss << headers_;
++  ss << "\r\n";
++  std::string str = ss.str();
++  DirectSend(str.c_str(), str.size());
++  state_ = PS_LEADER;
++  expect_close_ = true;
++  content_length_ = 0;
++  headers_.clear();
++
++  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
++}
++
++void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
++  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
++
++  if (len == 0) {
++    if (state_ == PS_TUNNEL_HEADERS) {
++      state_ = PS_TUNNEL;
++    } else if (state_ == PS_ERROR_HEADERS) {
++      Error(defer_error_);
++      return;
++    } else if (state_ == PS_SKIP_HEADERS) {
++      if (content_length_) {
++        state_ = PS_SKIP_BODY;
++      } else {
++        EndResponse();
++        return;
++      }
++    } else {
++      static bool report = false;
++      if (!unknown_mechanisms_.empty() && !report) {
++        report = true;
++        std::string msg(
++          "Unable to connect to the Google Talk service due to an incompatibility "
++          "with your proxy.\r\nPlease help us resolve this issue by submitting the "
++          "following information to us using our technical issue submission form "
++          "at:\r\n\r\n"
++          "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
++          "We apologize for the inconvenience.\r\n\r\n"
++          "Information to submit to Google: "
++          );
++        //std::string msg("Please report the following information to foo at bar.com:\r\nUnknown methods: ");
++        msg.append(unknown_mechanisms_);
++#ifdef WIN32
++        MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
++#endif
++#ifdef POSIX
++        //TODO: Raise a signal or something so the UI can be separated.
++        LOG(LS_ERROR) << "Oops!\n\n" << msg;
++#endif
++      }
++      // Unexpected end of headers
++      Error(0);
++      return;
++    }
++  } else if (state_ == PS_LEADER) {
++    uint32 code;
++    if (sscanf(data, "HTTP/%*lu.%*lu %lu", &code) != 1) {
++      Error(0);
++      return;
++    }
++    switch (code) {
++    case 200:
++      // connection good!
++      state_ = PS_TUNNEL_HEADERS;
++      return;
++#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
++#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
++#endif
++    case 407: // HTTP_STATUS_PROXY_AUTH_REQ
++      state_ = PS_AUTHENTICATE;
++      return;
++    default:
++      defer_error_ = 0;
++      state_ = PS_ERROR_HEADERS;
++      return;
++    }
++  } else if ((state_ == PS_AUTHENTICATE) && (strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
++    std::string response, auth_method;
++    switch (Authenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_, pass_, context_, response, auth_method)) {
++    case AR_IGNORE:
++      LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
++      if (!unknown_mechanisms_.empty())
++        unknown_mechanisms_.append(", ");
++      unknown_mechanisms_.append(auth_method);
++      break;
++    case AR_RESPONSE:
++      headers_ = "Proxy-Authorization: ";
++      headers_.append(response);
++      headers_.append("\r\n");
++      state_ = PS_SKIP_HEADERS;
++      unknown_mechanisms_.clear();
++      break;
++    case AR_CREDENTIALS:
++      defer_error_ = EACCES;
++      state_ = PS_ERROR_HEADERS;
++      unknown_mechanisms_.clear();
++      break;
++    case AR_ERROR:
++      defer_error_ = 0;
++      state_ = PS_ERROR_HEADERS;
++      unknown_mechanisms_.clear();
++      break;
++    }
++  } else if (strnicmp(data, "Content-Length:", 15) == 0) {
++    content_length_ = strtoul(data + 15, 0, 0);
++  } else if (strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) {
++    expect_close_ = false;
++    /*
++  } else if (strnicmp(data, "Connection: close", 17) == 0) {
++    expect_close_ = true;
++    */
++  }
++}
++
++void AsyncHttpsProxySocket::EndResponse() {
++  if (!expect_close_) {
++    SendRequest();
++    return;
++  }
++
++  // No point in waiting for the server to close... let's close now
++  // TODO: Refactor out PS_WAIT_CLOSE
++  state_ = PS_WAIT_CLOSE;
++  BufferedReadAdapter::Close();
++  OnCloseEvent(this, 0);
++}
++
++void AsyncHttpsProxySocket::Error(int error) {
++  BufferInput(false);
++  Close();
++  SetError(error);
++  SignalCloseEvent(this, error);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++
++AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
++                                   const std::string& username, const buzz::XmppPassword& password)
++  : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password),
++    state_(SS_ERROR) {
++}
++
++int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
++  dest_ = addr;
++  BufferInput(true);
++  return BufferedReadAdapter::Connect(proxy_);
++}
++
++SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
++  return dest_;
++}
++
++void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket * socket) {
++  SendHello();
++}
++
++void AsyncSocksProxySocket::ProcessInput(char * data, size_t& len) {
++  assert(state_ < SS_TUNNEL);
++
++  ByteBuffer response(data, len);
++
++  if (state_ == SS_HELLO) {
++    uint8 ver, method;
++    if (!response.ReadUInt8(ver) ||
++        !response.ReadUInt8(method))
++      return;
++
++    if (ver != 5) {
++      Error(0);
++      return;
++    }
++
++    if (method == 0) {
++      SendConnect();
++    } else if (method == 2) {
++      SendAuth();
++    } else {
++      Error(0);
++      return;
++    }
++  } else if (state_ == SS_AUTH) {
++    uint8 ver, status;
++    if (!response.ReadUInt8(ver) ||
++        !response.ReadUInt8(status))
++      return;
++
++    if ((ver != 1) || (status != 0)) {
++      Error(EACCES);
++      return;
++    }
++
++    SendConnect();
++  } else if (state_ == SS_CONNECT) {
++    uint8 ver, rep, rsv, atyp;
++    if (!response.ReadUInt8(ver) ||
++        !response.ReadUInt8(rep) ||
++        !response.ReadUInt8(rsv) ||
++        !response.ReadUInt8(atyp))
++      return;
++
++    if ((ver != 5) || (rep != 0)) {
++      Error(0);
++      return;
++    }
++
++    uint16 port;
++    if (atyp == 1) {
++      uint32 addr;
++      if (!response.ReadUInt32(addr) ||
++          !response.ReadUInt16(port))
++        return;
++      LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
++    } else if (atyp == 3) {
++      uint8 len;
++      std::string addr;
++      if (!response.ReadUInt8(len) ||
++          !response.ReadString(addr, len) ||
++          !response.ReadUInt16(port))
++        return;
++      LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
++    } else if (atyp == 4) {
++      std::string addr;
++      if (!response.ReadString(addr, 16) ||
++          !response.ReadUInt16(port))
++        return;
++      LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
++    } else {
++      Error(0);
++      return;
++    }
++
++    state_ = SS_TUNNEL;
++  }
++
++  // Consume parsed data
++  len = response.Length();
++  memcpy(data, response.Data(), len);
++
++  if (state_ != SS_TUNNEL)
++    return;
++
++  bool remainder = (len > 0);
++  BufferInput(false);
++  SignalConnectEvent(this);
++
++  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
++  if (remainder)
++    SignalReadEvent(this); // TODO: signal this??
++}
++
++void AsyncSocksProxySocket::SendHello() {
++  ByteBuffer request;
++  request.WriteUInt8(5);   // Socks Version
++  if (user_.empty()) {
++    request.WriteUInt8(1); // Authentication Mechanisms
++    request.WriteUInt8(0); // No authentication
++  } else {
++    request.WriteUInt8(2); // Authentication Mechanisms
++    request.WriteUInt8(0); // No authentication
++    request.WriteUInt8(2); // Username/Password
++  }
++  DirectSend(request.Data(), request.Length());
++  state_ = SS_HELLO;
++}
++
++void AsyncSocksProxySocket::SendAuth() {
++  ByteBuffer request;
++  request.WriteUInt8(1);      // Negotiation Version
++  request.WriteUInt8(static_cast<uint8>(user_.size()));
++  request.WriteString(user_); // Username
++  request.WriteUInt8(static_cast<uint8>(pass_.GetLength()));
++  size_t len = pass_.GetLength() + 1;
++  char * sensitive = new char[len];
++  pass_.CopyTo(sensitive, true);
++  request.WriteString(sensitive); // Password
++  memset(sensitive, 0, len);
++  delete [] sensitive;
++  DirectSend(request.Data(), request.Length());
++  state_ = SS_AUTH;
++}
++
++void AsyncSocksProxySocket::SendConnect() {
++  ByteBuffer request;
++  request.WriteUInt8(5);             // Socks Version
++  request.WriteUInt8(1);             // CONNECT
++  request.WriteUInt8(0);             // Reserved
++  if (dest_.IsUnresolved()) {
++    std::string hostname = dest_.IPAsString();
++    request.WriteUInt8(3);           // DOMAINNAME
++    request.WriteUInt8(static_cast<uint8>(hostname.size()));
++    request.WriteString(hostname);   // Destination Hostname
++  } else {
++    request.WriteUInt8(1);           // IPV4
++    request.WriteUInt32(dest_.ip()); // Destination IP
++  }
++  request.WriteUInt16(dest_.port()); // Destination Port
++  DirectSend(request.Data(), request.Length());
++  state_ = SS_CONNECT;
++}
++
++void AsyncSocksProxySocket::Error(int error) {
++  state_ = SS_ERROR;
++  BufferInput(false);
++  Close();
++  SetError(EACCES);
++  SignalCloseEvent(this, error);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++
++LoggingAdapter::LoggingAdapter(AsyncSocket* socket, LoggingSeverity level,
++                               const char * label)
++  : AsyncSocketAdapter(socket), level_(level)
++{
++  label_.append("[");
++  label_.append(label);
++  label_.append("]");
++}
++
++int
++LoggingAdapter::Send(const void *pv, size_t cb) {
++  int res = AsyncSocketAdapter::Send(pv, cb);
++  if (res > 0)
++    LogMultiline(false, static_cast<const char *>(pv), res);
++  return res;
++}
++
++int
++LoggingAdapter::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
++  int res = AsyncSocketAdapter::SendTo(pv, cb, addr);
++  if (res > 0)
++    LogMultiline(false, static_cast<const char *>(pv), res);
++  return res;
++}
++
++int
++LoggingAdapter::Recv(void *pv, size_t cb) {
++  int res = AsyncSocketAdapter::Recv(pv, cb);
++  if (res > 0)
++    LogMultiline(true, static_cast<const char *>(pv), res);
++  return res;
++}
++
++int
++LoggingAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
++  int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
++  if (res > 0)
++    LogMultiline(true, static_cast<const char *>(pv), res);
++  return res;
++}
++
++void
++LoggingAdapter::OnConnectEvent(AsyncSocket * socket) {
++  LOG(level_) << label_ << " Connected";
++  AsyncSocketAdapter::OnConnectEvent(socket);
++}
++
++void
++LoggingAdapter::OnCloseEvent(AsyncSocket * socket, int err) {
++  LOG(level_) << label_ << " Closed with error: " << err;
++  AsyncSocketAdapter::OnCloseEvent(socket, err);
++}
++
++void
++LoggingAdapter::LogMultiline(bool input, const char * data, size_t len) {
++  const char * direction = (input ? " << " : " >> ");
++  std::string str(data, len);
++  while (!str.empty()) {
++    std::string::size_type pos = str.find('\n');
++    std::string substr = str;
++    if (pos == std::string::npos) {
++      substr = str;
++      str.clear();
++    } else if ((pos > 0) && (str[pos-1] == '\r')) {
++      substr = str.substr(0, pos - 1);
++      str = str.substr(pos + 1);
++    } else {
++      substr  = str.substr(0, pos);
++      str = str.substr(pos + 1);
++    }
++
++    // Filter out any private data
++    std::string::size_type pos_private = substr.find("Email");
++    if (pos_private == std::string::npos) {
++      pos_private = substr.find("Passwd");
++    }
++    if (pos_private == std::string::npos) {
++        LOG(level_) << label_ << direction << substr;
++    } else {
++        LOG(level_) << label_ << direction << "## TEXT REMOVED ##";
++    }
++  }
++}
++
++///////////////////////////////////////////////////////////////////////////////
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h	(revision 586398)
+@@ -0,0 +1,58 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SOCKETADDRESSPAIR_H__
++#define __SOCKETADDRESSPAIR_H__
++
++#include "talk/base/socketaddress.h"
++
++namespace cricket {
++
++// Records a pair (source,destination) of socket addresses.  The two addresses
++// identify a connection between two machines.  (For UDP, this "connection" is
++// not maintained explicitly in a socket.)
++class SocketAddressPair {
++public:
++  SocketAddressPair() {}
++  SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest);
++
++  const SocketAddress& source() const { return src_; }
++  const SocketAddress& destination() const { return dest_; }
++
++  bool operator ==(const SocketAddressPair& r) const;
++  bool operator <(const SocketAddressPair& r) const;
++
++  size_t Hash() const;
++
++private:
++  SocketAddress src_;
++  SocketAddress dest_;
++};
++
++} // namespace cricket
++
++#endif // __SOCKETADDRESSPAIR_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc	(revision 586398)
+@@ -0,0 +1,99 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/host.h"
++#include "talk/base/logging.h"
++#include "talk/base/network.h"
++#include "talk/base/socket.h"
++#include <string>
++#include <iostream>
++#include <cassert>
++#include <errno.h>
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++namespace std {
++  using ::strerror;
++  using ::exit;
++}
++#endif
++
++#ifdef POSIX
++extern "C" {
++#include <sys/utsname.h>
++}
++#endif // POSIX
++
++namespace {
++
++void FatalError(const std::string& name, int err) {
++  PLOG(LERROR, err) << name;
++  std::exit(1);
++}
++
++}
++
++namespace cricket {
++
++#ifdef POSIX
++std::string GetHostName() {
++  struct utsname nm;
++  if (uname(&nm) < 0)
++    FatalError("uname", errno);
++  return std::string(nm.nodename);
++}
++#endif
++
++#ifdef WIN32
++std::string GetHostName() {
++  // TODO: fix this
++  return "cricket";
++}
++#endif
++
++// Records information about the local host.
++Host* gLocalHost = 0;
++
++const Host& LocalHost() {
++  if (!gLocalHost) {
++    std::vector<Network*>* networks = new std::vector<Network*>;
++    NetworkManager::CreateNetworks(*networks);
++#ifdef WIN32
++    // This is sort of problematic... one part of the code (the unittests) wants
++    // 127.0.0.1 to be present and another part (port allocators) don't.  Right
++    // now, they use different APIs, so we can have different behavior.  But
++    // there is something wrong with this.
++    networks->push_back(new Network("localhost",
++                                    SocketAddress::StringToIP("127.0.0.1")));
++#endif
++    gLocalHost = new Host(GetHostName(), networks);
++    assert(gLocalHost->networks().size() > 0);
++  }
++
++  return *gLocalHost;
++}
++
++} // namespace cricket
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h	(revision 586398)
+@@ -0,0 +1,101 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _WINPING_H_
++#define _WINPING_H_
++
++#ifdef WIN32
++
++#if _MSC_VER > 1000
++#pragma once
++#endif // _MSC_VER > 1000
++
++#include "talk/base/basictypes.h"
++
++#include <winsock2.h>
++#define _WINSOCKAPI_
++#include <windows.h>
++#undef SetPort
++
++// This class wraps a Win32 API for doing ICMP pinging.  This API, unlike the
++// the normal socket APIs (as implemented on Win9x), will return an error if
++// an ICMP packet with the dont-fragment bit set is too large.  This means this
++// class can be used to detect the MTU to a given address.
++
++typedef struct ip_option_information {
++    UCHAR   Ttl;                // Time To Live
++    UCHAR   Tos;                // Type Of Service
++    UCHAR   Flags;              // IP header flags
++    UCHAR   OptionsSize;        // Size in bytes of options data
++    PUCHAR  OptionsData;        // Pointer to options data
++} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;
++
++typedef HANDLE (WINAPI *PIcmpCreateFile)();
++
++typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle);
++
++typedef DWORD (WINAPI *PIcmpSendEcho)(
++    HANDLE                   IcmpHandle,
++    ULONG                    DestinationAddress,
++    LPVOID                   RequestData,
++    WORD                     RequestSize,
++    PIP_OPTION_INFORMATION   RequestOptions,
++    LPVOID                   ReplyBuffer,
++    DWORD                    ReplySize,
++    DWORD                    Timeout);
++
++class WinPing {
++public:
++    WinPing();
++    ~WinPing();
++
++    // Determines whether the class was initialized correctly.
++    bool IsValid() { return valid_; }
++
++    // Attempts to send a ping with the given parameters.
++    enum PingResult { PING_FAIL, PING_TOO_LARGE, PING_TIMEOUT, PING_SUCCESS };
++    PingResult Ping(
++        uint32 ip, uint32 data_size, uint32 timeout_millis, uint8 ttl,
++        bool allow_fragments);
++
++private:
++    HMODULE dll_;
++    HANDLE hping_;
++    PIcmpCreateFile create_;
++    PIcmpCloseHandle close_;
++    PIcmpSendEcho send_;
++    char* data_;
++    uint32 dlen_;
++    char* reply_;
++    uint32 rlen_;
++    bool valid_;
++};
++
++#endif // WIN32
++
++#endif // _WINPING_H_
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/host.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/host.h	(revision 586398)
+@@ -0,0 +1,59 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __HOST_H__
++#define __HOST_H__
++
++#include "talk/base/network.h"
++#include <string>
++#include <vector>
++
++namespace cricket {
++
++// Provides information about a host in the network.
++class Host {
++public:
++  Host(const std::string& name, std::vector<Network*>* networks)
++      : name_(name), networks_(networks) { }
++
++  const std::string& name() const { return name_; }
++  const std::vector<Network*>& networks() const { return *networks_; }
++
++private:
++  std::string name_;
++  std::vector<Network*>* networks_;
++};
++
++// Returns a reference to the description of the local host.
++const Host& LocalHost();
++
++// Returns the name of the local host.
++std::string GetHostName();
++
++} // namespace cricket
++
++#endif // __HOST_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h	(revision 586398)
+@@ -0,0 +1,56 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef CRICKET_BASE_ASYNCFILEH_H__
++#define CRICKET_BASE_ASYNCFILEH_H__
++
++#include "talk/base/sigslot.h"
++
++namespace cricket {
++
++// Provides the ability to perform file I/O asynchronously.
++// TODO: Create a common base class with AsyncSocket.
++class AsyncFile {
++public:
++  virtual ~AsyncFile() {}
++
++  // Determines whether the file will receive read events.
++  virtual bool readable() = 0;
++  virtual void set_readable(bool value) = 0;
++
++  // Determines whether the file will receive write events.
++  virtual bool writable() = 0;
++  virtual void set_writable(bool value) = 0;
++
++  sigslot::signal1<AsyncFile*> SignalReadEvent;
++  sigslot::signal1<AsyncFile*> SignalWriteEvent;
++  sigslot::signal2<AsyncFile*,int> SignalCloseEvent;
++};
++
++} // namespace cricket
++
++#endif // CRICKET_BASE_ASYNCFILEH_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __ASYNCPACKETSOCKET_H__
++#define __ASYNCPACKETSOCKET_H__
++
++#include "talk/base/asyncsocket.h"
++
++namespace cricket {
++
++// Provides the ability to receive packets asynchronously.  Sends are not
++// buffered since it is acceptable to drop packets under high load.
++class AsyncPacketSocket : public sigslot::has_slots<> {
++public:
++  AsyncPacketSocket(AsyncSocket* socket);
++  virtual ~AsyncPacketSocket();
++
++  // Relevant socket methods:
++  virtual SocketAddress GetLocalAddress() const;
++  virtual SocketAddress GetRemoteAddress() const;
++  virtual int Bind(const SocketAddress& addr);
++  virtual int Connect(const SocketAddress& addr);
++  virtual int Send(const void *pv, size_t cb);
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
++  virtual int Close();
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError() const;
++  virtual void SetError(int error);
++
++  // Emitted each time a packet is read.
++  sigslot::signal4<const char*, size_t, const SocketAddress&, AsyncPacketSocket*> SignalReadPacket;
++
++protected:
++  AsyncSocket* socket_;
++};
++
++} // namespace cricket
++
++#endif // __ASYNCPACKETSOCKET_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h	(revision 586398)
+@@ -0,0 +1,120 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _criticalsection_h_
++#define _criticalsection_h_
++
++#ifdef WIN32
++#include "talk/base/win32.h"
++#endif
++
++#ifdef POSIX
++#include <pthread.h>
++#endif
++
++#ifdef _DEBUG
++#define CS_TRACK_OWNER 1
++#endif  // _DEBUG
++
++#if CS_TRACK_OWNER
++#define TRACK_OWNER(x) x
++#else  // !CS_TRACK_OWNER
++#define TRACK_OWNER(x)
++#endif  // !CS_TRACK_OWNER
++
++namespace cricket {
++
++#ifdef WIN32
++class CriticalSection {
++public:
++  CriticalSection() {
++    InitializeCriticalSection(&crit_);
++    // Windows docs say 0 is not a valid thread id
++    TRACK_OWNER(thread_ = 0);
++  }
++  ~CriticalSection() {
++    DeleteCriticalSection(&crit_);
++  }
++  void Enter() {
++    EnterCriticalSection(&crit_);
++    TRACK_OWNER(thread_ = GetCurrentThreadId());
++  }
++  void Leave() {
++    TRACK_OWNER(thread_ = 0);
++    LeaveCriticalSection(&crit_);
++  }
++
++#if CS_TRACK_OWNER
++  bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
++#endif  // CS_TRACK_OWNER
++
++private:
++  CRITICAL_SECTION crit_;
++  TRACK_OWNER(DWORD thread_);  // The section's owning thread id
++};
++#endif // WIN32
++
++#ifdef POSIX
++class CriticalSection {
++public:
++  CriticalSection() {
++    pthread_mutexattr_t mutex_attribute;
++    pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
++    pthread_mutex_init(&mutex_, &mutex_attribute);
++  }
++  ~CriticalSection() {
++    pthread_mutex_destroy(&mutex_);
++  }
++  void Enter() {
++    pthread_mutex_lock(&mutex_);
++  }
++  void Leave() {
++    pthread_mutex_unlock(&mutex_);
++  }
++private:
++  pthread_mutex_t mutex_;
++};
++#endif // POSIX
++
++// CritScope, for serializing exection through a scope
++
++class CritScope {
++public:
++  CritScope(CriticalSection *pcrit) {
++    pcrit_ = pcrit;
++    pcrit_->Enter();
++  }
++  ~CritScope() {
++    pcrit_->Leave();
++  }
++private:
++  CriticalSection *pcrit_;
++};
++
++} // namespace cricket
++
++#endif // _criticalsection_h_
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h	(revision 586398)
+@@ -0,0 +1,50 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SOCKETFACTORY_H__
++#define __SOCKETFACTORY_H__
++
++#include "talk/base/socket.h"
++#include "talk/base/asyncsocket.h"
++
++namespace cricket {
++
++class SocketFactory {
++public:
++
++  // Returns a new socket for blocking communication.  The type can be
++  // SOCK_DGRAM and SOCK_STREAM.
++  virtual Socket* CreateSocket(int type) = 0;
++
++  // Returns a new socket for nonblocking communication.  The type can be
++  // SOCK_DGRAM and SOCK_STREAM.
++  virtual AsyncSocket* CreateAsyncSocket(int type) = 0;
++};
++
++} // namespace cricket
++
++#endif // __SOCKETFACTORY_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c	(revision 586398)
+@@ -0,0 +1,256 @@
++/*
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest.  This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ *
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ */
++#include <string.h>	/* for memcpy() */
++#include "md5.h"
++
++#ifndef HIGHFIRST
++#define byteReverse(buf, len)	/* Nothing */
++#else
++void byteReverse(unsigned char *buf, unsigned longs);
++
++#ifndef ASM_MD5
++/*
++ * Note: this code is harmless on little-endian machines.
++ */
++void byteReverse(unsigned char *buf, unsigned longs)
++{
++	uint32 t;
++	do {
++		t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
++		            ((unsigned)buf[1]<<8 | buf[0]);
++		*(uint32 *)buf = t;
++		buf += 4;
++	} while (--longs);
++}
++#endif
++#endif
++
++/*
++ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void
++MD5Init(struct MD5Context *ctx)
++{
++	ctx->buf[0] = 0x67452301;
++	ctx->buf[1] = 0xefcdab89;
++	ctx->buf[2] = 0x98badcfe;
++	ctx->buf[3] = 0x10325476;
++
++	ctx->bits[0] = 0;
++	ctx->bits[1] = 0;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void
++MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
++{
++	uint32 t;
++
++	/* Update bitcount */
++
++	t = ctx->bits[0];
++	if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
++		ctx->bits[1]++;	/* Carry from low to high */
++	ctx->bits[1] += len >> 29;
++
++	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
++
++	/* Handle any leading odd-sized chunks */
++
++	if ( t ) {
++		unsigned char *p = (unsigned char *)ctx->in + t;
++
++		t = 64-t;
++		if (len < t) {
++			memcpy(p, buf, len);
++			return;
++		}
++		memcpy(p, buf, t);
++		byteReverse(ctx->in, 16);
++		MD5Transform(ctx->buf, (uint32 *)ctx->in);
++		buf += t;
++		len -= t;
++	}
++
++	/* Process data in 64-byte chunks */
++
++	while (len >= 64) {
++		memcpy(ctx->in, buf, 64);
++		byteReverse(ctx->in, 16);
++		MD5Transform(ctx->buf, (uint32 *)ctx->in);
++		buf += 64;
++		len -= 64;
++	}
++
++	/* Handle any remaining bytes of data. */
++
++	memcpy(ctx->in, buf, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern 
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void
++MD5Final(unsigned char digest[16], struct MD5Context *ctx)
++{
++	unsigned count;
++	unsigned char *p;
++
++	/* Compute number of bytes mod 64 */
++	count = (ctx->bits[0] >> 3) & 0x3F;
++
++	/* Set the first char of padding to 0x80.  This is safe since there is
++	   always at least one byte free */
++	p = (unsigned char*)(ctx->in) + count;
++	*p++ = 0x80;
++
++	/* Bytes of padding needed to make 64 bytes */
++	count = 64 - 1 - count;
++
++	/* Pad out to 56 mod 64 */
++	if (count < 8) {
++		/* Two lots of padding:  Pad the first block to 64 bytes */
++		memset(p, 0, count);
++		byteReverse(ctx->in, 16);
++		MD5Transform(ctx->buf, (uint32 *)ctx->in);
++
++		/* Now fill the next block with 56 bytes */
++		memset(ctx->in, 0, 56);
++	} else {
++		/* Pad block to 56 bytes */
++		memset(p, 0, count-8);
++	}
++	byteReverse(ctx->in, 14);
++
++	/* Append length in bits and transform */
++	((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
++	((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
++
++	MD5Transform(ctx->buf, (uint32 *)ctx->in);
++	byteReverse((unsigned char *)ctx->buf, 4);
++	memcpy(digest, ctx->buf, 16);
++	memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
++}
++
++#ifndef ASM_MD5
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x & y | ~x & z) */
++#define F1(x, y, z) (z ^ (x & (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data.  MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++void
++MD5Transform(uint32 buf[4], uint32 const in[16])
++{
++	register uint32 a, b, c, d;
++
++	a = buf[0];
++	b = buf[1];
++	c = buf[2];
++	d = buf[3];
++
++	MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
++	MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
++	MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
++	MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
++	MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
++	MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
++	MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
++	MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
++	MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
++	MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
++	MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
++	MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
++	MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
++	MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
++	MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
++	MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
++
++	MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
++	MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
++	MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
++	MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
++	MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
++	MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
++	MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
++	MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
++	MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
++	MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
++	MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
++	MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
++	MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
++	MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
++	MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
++	MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
++
++	MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
++	MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
++	MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
++	MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
++	MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
++	MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
++	MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
++	MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
++	MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
++	MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
++	MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
++	MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
++	MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
++	MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
++	MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
++	MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
++
++	MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
++	MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
++	MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
++	MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
++	MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
++	MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
++	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
++	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
++	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
++	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
++	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
++	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
++	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
++	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
++	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
++	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
++
++	buf[0] += a;
++	buf[1] += b;
++	buf[2] += c;
++	buf[3] += d;
++}
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am	(revision 586398)
+@@ -0,0 +1,59 @@
++libcricketbase_la_SOURCES = socketaddress.cc \
++                            jtime.cc \
++                            asyncudpsocket.cc \
++                            messagequeue.cc \
++                            thread.cc \
++                            physicalsocketserver.cc \
++                            bytebuffer.cc \
++                            asyncpacketsocket.cc \
++                            network.cc \
++                            asynctcpsocket.cc \
++                            socketadapters.cc \
++                            md5c.c \
++                            base64.cc \
++                            task.cc \
++                            taskrunner.cc \
++			    host.cc \
++			    socketaddresspair.cc 
++
++noinst_HEADERS =            asyncfile.h \
++                            common.h \
++			    asyncpacketsocket.h \
++		  	    socketfactory.h \
++			    asyncsocket.h \
++	       		    socket.h \
++                            asynctcpsocket.h \
++		     	    linked_ptr.h \
++                            asyncudpsocket.h \
++		     	    logging.h \
++	      		    socketserver.h \
++                            base64.h \
++	     		    md5.h \
++	  		    stl_decl.h \
++                            basicdefs.h \
++		 	    messagequeue.h \
++                            basictypes.h \
++			    stringutils.h \
++                            bytebuffer.h \
++		       	    task.h \
++                            byteorder.h \
++	       		    taskrunner.h \
++                            criticalsection.h \
++		      	    network.h \
++	      		    thread.h \
++		     	    jtime.h \
++			    physicalsocketserver.h \
++	     		    proxyinfo.h \
++                            host.h \
++	   		    scoped_ptr.h \
++		 	    sigslot.h \
++	      		    winping.h \
++		 	    socketadapters.h \
++		     	    socketaddress.h \
++			    host.h \
++			    socketaddresspair.h
++
++AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../.. -I$(top_builddir) $(all_includes)
++noinst_LTLIBRARIES = libcricketbase.la
++DEFAULT_INCLUDES = -I$(srcdir)/../..
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h	(revision 586398)
+@@ -0,0 +1,53 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __BASICDEFS_H__
++#define __BASICDEFS_H__
++
++#if HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++
++// Used in GUI when referring to the product name (& Version Resource Product Name)
++#define PRODUCT_NAME    "Google Talk"   
++
++// Used in GUI when referring to the publisher of the product
++#define COMPANY_NAME    "Google"   
++
++// Used in filenames, directories, registry key names, etc to refer to the product
++#define DIRECTORY_NAME  "Google Talk"
++
++// Used in URLs, registry values, etc, where we prefer not to use a space
++#define PRODUCT_SIGNATURE "googletalk"
++
++// Used whenever we do HTTP
++#define USERAGENT_STRING "Google Talk"
++
++#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
++
++#endif // __BASICDEFS_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h	(revision 586398)
+@@ -0,0 +1,29 @@
++
++//*********************************************************************
++//* C_Base64 - a simple base64 encoder and decoder.
++//*
++//*     Copyright (c) 1999, Bob Withers - bwit at pobox.com
++//*
++//* This code may be freely used for any purpose, either personal
++//* or commercial, provided the authors copyright notice remains
++//* intact.
++//*********************************************************************
++
++#ifndef Base64_H
++#define Base64_H
++
++#include <string>
++using std::string;  // comment if your compiler doesn't use namespaces
++
++class Base64
++{
++public:
++  static string encode(const string & data);
++  static string decode(const string & data);
++  static string encodeFromArray(const char * data, size_t len);
++private:
++  static const string Base64Table;
++  static const string::size_type DecodeTable[];
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h	(revision 586398)
+@@ -0,0 +1,2700 @@
++// sigslot.h: Signal/Slot classes
++// 
++// Written by Sarah Thompson (sarah at telergy.com) 2002.
++//
++// License: Public domain. You are free to use this code however you like, with the proviso that
++//          the author takes on no responsibility or liability for any use.
++//
++// QUICK DOCUMENTATION 
++//		
++//				(see also the full documentation at http://sigslot.sourceforge.net/)
++//
++//		#define switches
++//			SIGSLOT_PURE_ISO			- Define this to force ISO C++ compliance. This also disables
++//										  all of the thread safety support on platforms where it is 
++//										  available.
++//
++//			SIGSLOT_USE_POSIX_THREADS	- Force use of Posix threads when using a C++ compiler other than
++//										  gcc on a platform that supports Posix threads. (When using gcc,
++//										  this is the default - use SIGSLOT_PURE_ISO to disable this if 
++//										  necessary)
++//
++//			SIGSLOT_DEFAULT_MT_POLICY	- Where thread support is enabled, this defaults to multi_threaded_global.
++//										  Otherwise, the default is single_threaded. #define this yourself to
++//										  override the default. In pure ISO mode, anything other than
++//										  single_threaded will cause a compiler error.
++//
++//		PLATFORM NOTES
++//
++//			Win32						- On Win32, the WIN32 symbol must be #defined. Most mainstream
++//										  compilers do this by default, but you may need to define it
++//										  yourself if your build environment is less standard. This causes
++//										  the Win32 thread support to be compiled in and used automatically.
++//
++//			Unix/Linux/BSD, etc.		- If you're using gcc, it is assumed that you have Posix threads
++//										  available, so they are used automatically. You can override this
++//										  (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
++//										  something other than gcc but still want to use Posix threads, you
++//										  need to #define SIGSLOT_USE_POSIX_THREADS.
++//
++//			ISO C++						- If none of the supported platforms are detected, or if
++//										  SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
++//										  along with any code that might cause a pure ISO C++ environment to
++//										  complain. Before you ask, gcc -ansi -pedantic won't compile this 
++//										  library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
++//										  errors that aren't really there. If you feel like investigating this,
++//										  please contact the author.
++//
++//		
++//		THREADING MODES
++//
++//			single_threaded				- Your program is assumed to be single threaded from the point of view
++//										  of signal/slot usage (i.e. all objects using signals and slots are
++//										  created and destroyed from a single thread). Behaviour if objects are
++//										  destroyed concurrently is undefined (i.e. you'll get the occasional
++//										  segmentation fault/memory exception).
++//
++//			multi_threaded_global		- Your program is assumed to be multi threaded. Objects using signals and
++//										  slots can be safely created and destroyed from any thread, even when
++//										  connections exist. In multi_threaded_global mode, this is achieved by a
++//										  single global mutex (actually a critical section on Windows because they
++//										  are faster). This option uses less OS resources, but results in more
++//										  opportunities for contention, possibly resulting in more context switches
++//										  than are strictly necessary.
++//
++//			multi_threaded_local		- Behaviour in this mode is essentially the same as multi_threaded_global,
++//										  except that each signal, and each object that inherits has_slots, all 
++//										  have their own mutex/critical section. In practice, this means that
++//										  mutex collisions (and hence context switches) only happen if they are
++//										  absolutely essential. However, on some platforms, creating a lot of 
++//										  mutexes can slow down the whole OS, so use this option with care.
++//
++//		USING THE LIBRARY
++//
++//			See the full documentation at http://sigslot.sourceforge.net/
++//
++//
++
++#ifndef SIGSLOT_H__
++#define SIGSLOT_H__
++
++#include <set>
++#include <list>
++
++// On our copy of sigslot.h, we force single threading
++#define SIGSLOT_PURE_ISO
++
++#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
++#	define _SIGSLOT_SINGLE_THREADED
++#elif defined(WIN32)
++#	define _SIGSLOT_HAS_WIN32_THREADS
++#	include <windows.h>
++#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
++#	define _SIGSLOT_HAS_POSIX_THREADS
++#	include <pthread.h>
++#else
++#	define _SIGSLOT_SINGLE_THREADED
++#endif
++
++#ifndef SIGSLOT_DEFAULT_MT_POLICY
++#	ifdef _SIGSLOT_SINGLE_THREADED
++#		define SIGSLOT_DEFAULT_MT_POLICY single_threaded
++#	else
++#		define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
++#	endif
++#endif
++
++
++namespace sigslot {
++
++	class single_threaded
++	{
++	public:
++		single_threaded()
++		{
++			;
++		}
++
++		virtual ~single_threaded()
++		{
++			;
++		}
++
++		virtual void lock()
++		{
++			;
++		}
++
++		virtual void unlock()
++		{
++			;
++		}
++	};
++
++#ifdef _SIGSLOT_HAS_WIN32_THREADS
++	// The multi threading policies only get compiled in if they are enabled.
++	class multi_threaded_global
++	{
++	public:
++		multi_threaded_global()
++		{
++			static bool isinitialised = false;
++
++			if(!isinitialised)
++			{
++				InitializeCriticalSection(get_critsec());
++				isinitialised = true;
++			}
++		}
++
++		multi_threaded_global(const multi_threaded_global&)
++		{
++			;
++		}
++
++		virtual ~multi_threaded_global()
++		{
++			;
++		}
++
++		virtual void lock()
++		{
++			EnterCriticalSection(get_critsec());
++		}
++
++		virtual void unlock()
++		{
++			LeaveCriticalSection(get_critsec());
++		}
++
++	private:
++		CRITICAL_SECTION* get_critsec()
++		{
++			static CRITICAL_SECTION g_critsec;
++			return &g_critsec;
++		}
++	};
++
++	class multi_threaded_local
++	{
++	public:
++		multi_threaded_local()
++		{
++			InitializeCriticalSection(&m_critsec);
++		}
++
++		multi_threaded_local(const multi_threaded_local&)
++		{
++			InitializeCriticalSection(&m_critsec);
++		}
++
++		virtual ~multi_threaded_local()
++		{
++			DeleteCriticalSection(&m_critsec);
++		}
++
++		virtual void lock()
++		{
++			EnterCriticalSection(&m_critsec);
++		}
++
++		virtual void unlock()
++		{
++			LeaveCriticalSection(&m_critsec);
++		}
++
++	private:
++		CRITICAL_SECTION m_critsec;
++	};
++#endif // _SIGSLOT_HAS_WIN32_THREADS
++
++#ifdef _SIGSLOT_HAS_POSIX_THREADS
++	// The multi threading policies only get compiled in if they are enabled.
++	class multi_threaded_global
++	{
++	public:
++		multi_threaded_global()
++		{
++			pthread_mutex_init(get_mutex(), NULL);
++		}
++
++		multi_threaded_global(const multi_threaded_global&)
++		{
++			;
++		}
++
++		virtual ~multi_threaded_global()
++		{
++			;
++		}
++
++		virtual void lock()
++		{
++			pthread_mutex_lock(get_mutex());
++		}
++
++		virtual void unlock()
++		{
++			pthread_mutex_unlock(get_mutex());
++		}
++
++	private:
++		pthread_mutex_t* get_mutex()
++		{
++			static pthread_mutex_t g_mutex;
++			return &g_mutex;
++		}
++	};
++
++	class multi_threaded_local
++	{
++	public:
++		multi_threaded_local()
++		{
++			pthread_mutex_init(&m_mutex, NULL);
++		}
++
++		multi_threaded_local(const multi_threaded_local&)
++		{
++			pthread_mutex_init(&m_mutex, NULL);
++		}
++
++		virtual ~multi_threaded_local()
++		{
++			pthread_mutex_destroy(&m_mutex);
++		}
++
++		virtual void lock()
++		{
++			pthread_mutex_lock(&m_mutex);
++		}
++
++		virtual void unlock()
++		{
++			pthread_mutex_unlock(&m_mutex);
++		}
++
++	private:
++		pthread_mutex_t m_mutex;
++	};
++#endif // _SIGSLOT_HAS_POSIX_THREADS
++
++	template<class mt_policy>
++	class lock_block
++	{
++	public:
++		mt_policy *m_mutex;
++
++		lock_block(mt_policy *mtx)
++			: m_mutex(mtx)
++		{
++			m_mutex->lock();
++		}
++
++		~lock_block()
++		{
++			m_mutex->unlock();
++		}
++	};
++
++	template<class mt_policy>
++	class has_slots;
++
++	template<class mt_policy>
++	class _connection_base0
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit() = 0;
++		virtual _connection_base0* clone() = 0;
++		virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class mt_policy>
++	class _connection_base1
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type) = 0;
++		virtual _connection_base1<arg1_type, mt_policy>* clone() = 0;
++		virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class mt_policy>
++	class _connection_base2
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type) = 0;
++		virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;
++		virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
++	class _connection_base3
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type) = 0;
++		virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;
++		virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
++	class _connection_base4
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
++		virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;
++		virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class mt_policy>
++	class _connection_base5
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type) = 0;
++		virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, mt_policy>* clone() = 0;
++		virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class mt_policy>
++	class _connection_base6
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
++			arg6_type) = 0;
++		virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, mt_policy>* clone() = 0;
++		virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class mt_policy>
++	class _connection_base7
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
++			arg6_type, arg7_type) = 0;
++		virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;
++		virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
++	class _connection_base8
++	{
++	public:
++		virtual has_slots<mt_policy>* getdest() const = 0;
++		virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
++			arg6_type, arg7_type, arg8_type) = 0;
++		virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;
++		virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
++	};
++
++	template<class mt_policy>
++	class _signal_base : public mt_policy
++	{
++	public:
++		virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
++		virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0;
++	};
++
++	template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class has_slots : public mt_policy 
++	{
++	private:
++		typedef typename std::set<_signal_base<mt_policy> *> sender_set;
++		typedef typename sender_set::const_iterator const_iterator;
++
++	public:
++		has_slots()
++		{
++			;
++		}
++
++		has_slots(const has_slots& hs)
++			: mt_policy(hs)
++		{
++			lock_block<mt_policy> lock(this);
++			const_iterator it = hs.m_senders.begin();
++			const_iterator itEnd = hs.m_senders.end();
++
++			while(it != itEnd)
++			{
++				(*it)->slot_duplicate(&hs, this);
++				m_senders.insert(*it);
++				++it;
++			}
++		} 
++
++		void signal_connect(_signal_base<mt_policy>* sender)
++		{
++			lock_block<mt_policy> lock(this);
++			m_senders.insert(sender);
++		}
++
++		void signal_disconnect(_signal_base<mt_policy>* sender)
++		{
++			lock_block<mt_policy> lock(this);
++			m_senders.erase(sender);
++		}
++
++		virtual ~has_slots()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			const_iterator it = m_senders.begin();
++			const_iterator itEnd = m_senders.end();
++
++			while(it != itEnd)
++			{
++				(*it)->slot_disconnect(this);
++				++it;
++			}
++
++			m_senders.erase(m_senders.begin(), m_senders.end());
++		}
++
++	private:
++		sender_set m_senders;
++	};
++
++	template<class mt_policy>
++	class _signal_base0 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base0<mt_policy> *>  connections_list;
++
++		_signal_base0()
++		{
++			;
++		}
++
++		_signal_base0(const _signal_base0& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		~_signal_base0()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class mt_policy>
++	class _signal_base1 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base1<arg1_type, mt_policy> *>  connections_list;
++
++		_signal_base1()
++		{
++			;
++		}
++
++		_signal_base1(const _signal_base1<arg1_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base1()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class mt_policy>
++	class _signal_base2 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>
++			connections_list;
++
++		_signal_base2()
++		{
++			;
++		}
++
++		_signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base2()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
++	class _signal_base3 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>
++			connections_list;
++
++		_signal_base3()
++		{
++			;
++		}
++
++		_signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base3()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
++	class _signal_base4 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,
++			arg4_type, mt_policy> *>  connections_list;
++
++		_signal_base4()
++		{
++			;
++		}
++
++		_signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base4()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class mt_policy>
++	class _signal_base5 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,
++			arg4_type, arg5_type, mt_policy> *>  connections_list;
++
++		_signal_base5()
++		{
++			;
++		}
++
++		_signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base5()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class mt_policy>
++	class _signal_base6 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type, 
++			arg4_type, arg5_type, arg6_type, mt_policy> *>  connections_list;
++
++		_signal_base6()
++		{
++			;
++		}
++
++		_signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base6()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class mt_policy>
++	class _signal_base7 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type, 
++			arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *>  connections_list;
++
++		_signal_base7()
++		{
++			;
++		}
++
++		_signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base7()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
++	class _signal_base8 : public _signal_base<mt_policy>
++	{
++	public:
++		typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type, 
++			arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>
++			connections_list;
++
++		_signal_base8()
++		{
++			;
++		}
++
++		_signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
++			: _signal_base<mt_policy>(s)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = s.m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_connect(this);
++				m_connected_slots.push_back((*it)->clone());
++
++				++it;
++			}
++		}
++
++		void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == oldtarget)
++				{
++					m_connected_slots.push_back((*it)->duplicate(newtarget));
++				}
++
++				++it;
++			}
++		}
++
++		~_signal_base8()
++		{
++			disconnect_all();
++		}
++
++		void disconnect_all()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				(*it)->getdest()->signal_disconnect(this);
++				delete *it;
++
++				++it;
++			}
++
++			m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
++		}
++
++#ifdef _DEBUG
++			bool connected(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++				if ((*it)->getdest() == pclass)
++					return true;
++				it = itNext;
++			}
++			return false;
++		}
++#endif
++
++		void disconnect(has_slots<mt_policy>* pclass)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				if((*it)->getdest() == pclass)
++				{
++					delete *it;
++					m_connected_slots.erase(it);
++					pclass->signal_disconnect(this);
++					return;
++				}
++
++				++it;
++			}
++		}
++
++		void slot_disconnect(has_slots<mt_policy>* pslot)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::iterator it = m_connected_slots.begin();
++			typename connections_list::iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				typename connections_list::iterator itNext = it;
++				++itNext;
++
++				if((*it)->getdest() == pslot)
++				{
++					m_connected_slots.erase(it);
++					//			delete *it;
++				}
++
++				it = itNext;
++			}
++		}
++
++	protected:
++		connections_list m_connected_slots;   
++	};
++
++
++	template<class dest_type, class mt_policy>
++	class _connection0 : public _connection_base0<mt_policy>
++	{
++	public:
++		_connection0()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection0(dest_type* pobject, void (dest_type::*pmemfun)())
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base0<mt_policy>* clone()
++		{
++			return new _connection0<dest_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit()
++		{
++			(m_pobject->*m_pmemfun)();
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)();
++	};
++
++	template<class dest_type, class arg1_type, class mt_policy>
++	class _connection1 : public _connection_base1<arg1_type, mt_policy>
++	{
++	public:
++		_connection1()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base1<arg1_type, mt_policy>* clone()
++		{
++			return new _connection1<dest_type, arg1_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1)
++		{
++			(m_pobject->*m_pmemfun)(a1);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class mt_policy>
++	class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>
++	{
++	public:
++		_connection2()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()
++		{
++			return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>
++	class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>
++	{
++	public:
++		_connection3()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()
++		{
++			return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
++	class arg4_type, class mt_policy>
++	class _connection4 : public _connection_base4<arg1_type, arg2_type,
++		arg3_type, arg4_type, mt_policy>
++	{
++	public:
++		_connection4()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()
++		{
++			return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, 
++			arg4_type a4)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3, a4);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,
++			arg4_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
++	class arg4_type, class arg5_type, class mt_policy>
++	class _connection5 : public _connection_base5<arg1_type, arg2_type,
++		arg3_type, arg4_type, arg5_type, mt_policy>
++	{
++	public:
++		_connection5()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, mt_policy>* clone()
++		{
++			return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
++	class arg4_type, class arg5_type, class arg6_type, class mt_policy>
++	class _connection6 : public _connection_base6<arg1_type, arg2_type,
++		arg3_type, arg4_type, arg5_type, arg6_type, mt_policy>
++	{
++	public:
++		_connection6()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, mt_policy>* clone()
++		{
++			return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
++	class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>
++	class _connection7 : public _connection_base7<arg1_type, arg2_type,
++		arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
++	{
++	public:
++		_connection7()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, mt_policy>* clone()
++		{
++			return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, arg7_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type);
++	};
++
++	template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
++	class arg4_type, class arg5_type, class arg6_type, class arg7_type, 
++	class arg8_type, class mt_policy>
++	class _connection8 : public _connection_base8<arg1_type, arg2_type,
++		arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
++	{
++	public:
++		_connection8()
++		{
++			m_pobject = NULL;
++			m_pmemfun = NULL;
++		}
++
++		_connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
++			arg7_type, arg8_type))
++		{
++			m_pobject = pobject;
++			m_pmemfun = pmemfun;
++		}
++
++		virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()
++		{
++			return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);
++		}
++
++		virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
++		{
++			return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
++				arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
++		}
++
++		virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
++		{
++			(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);
++		}
++
++		virtual has_slots<mt_policy>* getdest() const
++		{
++			return m_pobject;
++		}
++
++	private:
++		dest_type* m_pobject;
++		void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type);
++	};
++
++	template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal0 : public _signal_base0<mt_policy>
++	{
++	public:
++		typedef _signal_base0<mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal0()
++		{
++			;
++		}
++
++		signal0(const signal0<mt_policy>& s)
++			: _signal_base0<mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)())
++		{
++			lock_block<mt_policy> lock(this);
++			_connection0<desttype, mt_policy>* conn = 
++				new _connection0<desttype, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit();
++
++				it = itNext;
++			}
++		}
++
++		void operator()()
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit();
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal1 : public _signal_base1<arg1_type, mt_policy>
++	{
++	public:
++		typedef _signal_base1<arg1_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal1()
++		{
++			;
++		}
++
++		signal1(const signal1<arg1_type, mt_policy>& s)
++			: _signal_base1<arg1_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection1<desttype, arg1_type, mt_policy>* conn = 
++				new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>
++	{
++	public:
++		typedef _signal_base2<arg1_type, arg2_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal2()
++		{
++			;
++		}
++
++		signal2(const signal2<arg1_type, arg2_type, mt_policy>& s)
++			: _signal_base2<arg1_type, arg2_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new
++				_connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>
++	{
++	public:
++		typedef _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal3()
++		{
++			;
++		}
++
++		signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
++			: _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn = 
++				new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,
++				pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,
++		arg4_type, mt_policy>
++	{
++	public:
++		typedef _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal4()
++		{
++			;
++		}
++
++		signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
++			: _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*
++				conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,
++				arg4_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,
++		arg4_type, arg5_type, mt_policy>
++	{
++	public:
++		typedef _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal5()
++		{
++			;
++		}
++
++		signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, mt_policy>& s)
++			: _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
++				arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,
++				arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5);
++
++				it = itNext;
++			}
++		}
++	};
++
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,
++		arg4_type, arg5_type, arg6_type, mt_policy>
++	{
++	public:
++		typedef _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal6()
++		{
++			;
++		}
++
++		signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, mt_policy>& s)
++			: _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
++				arg5_type, arg6_type, mt_policy>* conn = 
++				new _connection6<desttype, arg1_type, arg2_type, arg3_type,
++				arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,
++		arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
++	{
++	public:
++		typedef _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal7()
++		{
++			;
++		}
++
++		signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, mt_policy>& s)
++			: _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
++			arg7_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
++				arg5_type, arg6_type, arg7_type, mt_policy>* conn = 
++				new _connection7<desttype, arg1_type, arg2_type, arg3_type,
++				arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6, a7);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6, a7);
++
++				it = itNext;
++			}
++		}
++	};
++
++	template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
++	class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
++	class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,
++		arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
++	{
++	public:
++		typedef _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type, 
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> base;
++		typedef typename base::connections_list connections_list;
++		using base::m_connected_slots;
++
++		signal8()
++		{
++			;
++		}
++
++		signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
++			: _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
++			arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)
++		{
++			;
++		}
++
++		template<class desttype>
++			void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
++			arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
++			arg7_type, arg8_type))
++		{
++			lock_block<mt_policy> lock(this);
++			_connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
++				arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn = 
++				new _connection8<desttype, arg1_type, arg2_type, arg3_type,
++				arg4_type, arg5_type, arg6_type, arg7_type, 
++				arg8_type, mt_policy>(pclass, pmemfun);
++			m_connected_slots.push_back(conn);
++			pclass->signal_connect(this);
++		}
++
++		void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
++
++				it = itNext;
++			}
++		}
++
++		void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
++			arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
++		{
++			lock_block<mt_policy> lock(this);
++			typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
++			typename connections_list::const_iterator itEnd = m_connected_slots.end();
++
++			while(it != itEnd)
++			{
++				itNext = it;
++				++itNext;
++
++				(*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
++
++				it = itNext;
++			}
++		}
++	};
++
++}; // namespace sigslot
++
++#endif // SIGSLOT_H__
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h	(revision 586398)
+@@ -0,0 +1,222 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++//   LOG(...) an ostream target that can be used to send formatted
++// output to a variety of logging targets, such as debugger console, stderr,
++// file, or any StreamInterface.
++//   The severity level passed as the first argument to the the LOGging
++// functions is used as a filter, to limit the verbosity of the logging.
++//   Static members of LogMessage documented below are used to control the
++// verbosity and target of the output.
++//   There are several variations on the LOG macro which facilitate logging
++// of common error conditions, detailed below.
++
++#ifndef TALK_BASE_LOGGING_H__
++#define TALK_BASE_LOGGING_H__
++
++#include <sstream>
++#include "talk/base/basictypes.h"
++class StreamInterface;
++
++///////////////////////////////////////////////////////////////////////////////
++// ConstantLabel can be used to easily generate string names from constant
++// values.  This can be useful for logging descriptive names of error messages.
++// Usage:
++//   const ConstantLabel LIBRARY_ERRORS[] = {
++//     KLABEL(SOME_ERROR),
++//     KLABEL(SOME_OTHER_ERROR),
++//     ...
++//     LASTLABEL
++//   }
++//
++//   int err = LibraryFunc();
++//   LOG(LS_ERROR) << "LibraryFunc returned: "
++//                 << ErrorName(err, LIBRARY_ERRORS);
++
++struct ConstantLabel { int value; const char * label; };
++#define KLABEL(x) { x, #x }
++#define TLABEL(x,y) { x, y }
++#define LASTLABEL { 0, 0 }
++
++const char * FindLabel(int value, const ConstantLabel entries[]);
++std::string ErrorName(int err, const ConstantLabel * err_table);
++
++//////////////////////////////////////////////////////////////////////
++
++// Note that the non-standard LoggingSeverity aliases exist because they are
++// still in broad use.  The meanings of the levels are:
++//  LS_SENSITIVE: Information which should only be logged with the consent
++//   of the user, due to privacy concerns.
++//  LS_VERBOSE: This level is for data which we do not want to appear in the
++//   normal debug log, but should appear in diagnostic logs.
++//  LS_INFO: Chatty level used in debugging for all sorts of things, the default
++//   in debug builds.
++//  LS_WARNING: Something that may warrant investigation.
++//  LS_ERROR: Something that should not have occurred.
++enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR,
++                       INFO = LS_INFO,
++                       WARNING = LS_WARNING,
++                       LERROR = LS_ERROR };
++
++// LogErrorContext assists in interpreting the meaning of an error value.
++//  ERRCTX_ERRNO: the value was read from global 'errno'
++//  ERRCTX_HRESULT: the value is a Windows HRESULT
++enum LogErrorContext { ERRCTX_NONE, ERRCTX_ERRNO, ERRCTX_HRESULT };
++
++// If LOGGING is not explicitly defined, default to enabled in debug mode
++#if !defined(LOGGING)
++#if defined(_DEBUG) && !defined(NDEBUG)
++#define LOGGING 1
++#else
++#define LOGGING 0
++#endif
++#endif  // !defined(LOGGING)
++
++#if LOGGING
++
++#define LOG(sev) \
++  if (LogMessage::Loggable(sev)) \
++    LogMessage(__FILE__, __LINE__, sev).stream()
++
++// PLOG and LOG_ERR attempt to provide a string description of an errno derived
++// error.  LOG_ERR reads errno directly, so care must be taken to call it before
++// errno is reset.
++#define PLOG(sev, err) \
++  if (LogMessage::Loggable(sev)) \
++    LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, err).stream()
++#define LOG_ERR(sev) \
++  if (LogMessage::Loggable(sev)) \
++    LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, errno).stream()
++
++// LOG_GLE(M) attempt to provide a string description of the HRESULT returned
++// by GetLastError.  The second variant allows searching of a dll's string
++// table for the error description.
++#ifdef WIN32
++#define LOG_GLE(sev) \
++  if (LogMessage::Loggable(sev)) \
++    LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError()).stream()
++#define LOG_GLEM(sev, mod) \
++  if (LogMessage::Loggable(sev)) \
++    LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError(), mod) \
++      .stream()
++#endif  // WIN32
++
++// TODO: Add an "assert" wrapper that logs in the same manner.
++
++#else  // !LOGGING
++
++// Hopefully, the compiler will optimize away some of this code.
++// Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++,
++//   converted to "while (false)"
++#define LOG(sev) \
++  while (false) LogMessage(NULL, 0, sev).stream()
++#define PLOG(sev, err) \
++  while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream()
++#define LOG_ERR(sev) \
++  while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream()
++#ifdef WIN32
++#define LOG_GLE(sev) \
++  while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream()
++#define LOG_GLEM(sev, mod) \
++  while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream()
++#endif  // WIN32
++
++#endif  // !LOGGING
++
++class LogMessage {
++ public:
++  LogMessage(const char* file, int line, LoggingSeverity sev,
++             LogErrorContext err_ctx = ERRCTX_NONE, int err = 0,
++             const char* module = NULL);
++  ~LogMessage();
++
++  static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); }
++  std::ostream& stream() { return print_stream_; }
++
++  enum { NO_LOGGING = LS_ERROR + 1 };
++
++  // These are attributes which apply to all logging channels
++  //  LogContext: Display the file and line number of the message
++  static void LogContext(int min_sev);
++  //  LogThreads: Display the thread identifier of the current thread
++  static void LogThreads(bool on = true);
++  //  LogTimestamps: Display the elapsed time of the program
++  static void LogTimestamps(bool on = true);
++
++  // Timestamps begin with program execution, but can be reset with this
++  // function for measuring the duration of an activity, or to synchronize
++  // timestamps between multiple instances.
++  static void ResetTimestamps();
++
++  // These are the available logging channels
++  //  Debug: Debug console on Windows, otherwise stderr
++  static void LogToDebug(int min_sev);
++  static int GetLogToDebug() { return dbg_sev_; }
++  //  Stream: Any non-blocking stream interface.  LogMessage takes ownership of
++  //   the stream.
++  static void LogToStream(StreamInterface* stream, int min_sev);
++  static int GetLogToStream() { return stream_sev_; }
++
++  // Testing against MinLogSeverity allows code to avoid potentially expensive
++  // logging operations by pre-checking the logging level.
++  static int GetMinLogSeverity() { return min_sev_; }
++
++ private:
++  // These assist in formatting some parts of the debug output.
++  static const char* Describe(LoggingSeverity sev);
++  static const char* DescribeFile(const char* file);
++
++  // The ostream that buffers the formatted message before output
++  std::ostringstream print_stream_;
++
++  // The severity level of this message
++  LoggingSeverity severity_;
++
++  // String data generated in the constructor, that should be appended to
++  // the message before output.
++  std::string extra_;
++
++  // dbg_sev_ and stream_sev_ are the thresholds for those output targets
++  // min_sev_ is the minimum (most verbose) of those levels, and is used
++  //  as a short-circuit in the logging macros to identify messages that won't
++  //  be logged.
++  // ctx_sev_ is the minimum level at which file context is displayed
++  static int min_sev_, dbg_sev_, stream_sev_, ctx_sev_;
++
++  // The output stream, if any
++  static StreamInterface * stream_;
++
++  // Flags for formatting options
++  static bool thread_, timestamp_;
++
++  // The timestamp at which logging started.
++  static uint32 start_;
++
++  DISALLOW_EVIL_CONSTRUCTORS(LogMessage);
++};
++
++#endif  // TALK_BASE_LOGGING_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h	(revision 586398)
+@@ -0,0 +1,91 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __ASYNCSOCKET_H__
++#define __ASYNCSOCKET_H__
++
++#include "talk/base/sigslot.h"
++#include "talk/base/socket.h"
++
++namespace cricket {
++
++// Provides the ability to perform socket I/O asynchronously.
++class AsyncSocket : public Socket, public sigslot::has_slots<>  {
++public:
++  virtual ~AsyncSocket() {}
++
++  sigslot::signal1<AsyncSocket*> SignalReadEvent;  // ready to read
++  sigslot::signal1<AsyncSocket*> SignalWriteEvent; // ready to write
++  sigslot::signal1<AsyncSocket*> SignalConnectEvent; // connected
++  sigslot::signal2<AsyncSocket*,int> SignalCloseEvent; // closed
++  // TODO: error
++};
++
++class AsyncSocketAdapter : public AsyncSocket {
++public:
++  AsyncSocketAdapter(Socket * socket) : socket_(socket) {
++  }
++  AsyncSocketAdapter(AsyncSocket * socket) : socket_(socket) {
++    socket->SignalConnectEvent.connect(this, &AsyncSocketAdapter::OnConnectEvent);
++    socket->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent);
++    socket->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent);
++    socket->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent);
++  }
++  virtual ~AsyncSocketAdapter() { delete socket_; }
++
++  virtual SocketAddress GetLocalAddress() const { return socket_->GetLocalAddress(); }
++  virtual SocketAddress GetRemoteAddress() const { return socket_->GetRemoteAddress(); }
++
++  virtual int Bind(const SocketAddress& addr) { return socket_->Bind(addr); }
++  virtual int Connect(const SocketAddress& addr) { return socket_->Connect(addr); }
++  virtual int Send(const void *pv, size_t cb) { return socket_->Send(pv, cb); }
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { return socket_->SendTo(pv, cb, addr); }
++  virtual int Recv(void *pv, size_t cb) { return socket_->Recv(pv, cb); }
++  virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { return socket_->RecvFrom(pv, cb, paddr); }
++  virtual int Listen(int backlog) { return socket_->Listen(backlog); }
++  virtual Socket *Accept(SocketAddress *paddr) { return socket_->Accept(paddr); }
++  virtual int Close() { return socket_->Close(); }
++  virtual int GetError() const { return socket_->GetError(); }
++  virtual void SetError(int error) { return socket_->SetError(error); }
++
++  virtual ConnState GetState() const { return socket_->GetState(); }
++
++  virtual int EstimateMTU(uint16* mtu) { return socket_->EstimateMTU(mtu); }
++  virtual int SetOption(Option opt, int value) { return socket_->SetOption(opt, value); }
++
++protected:
++  virtual void OnConnectEvent(AsyncSocket * socket) { SignalConnectEvent(this); }
++  virtual void OnReadEvent(AsyncSocket * socket) { SignalReadEvent(this); }
++  virtual void OnWriteEvent(AsyncSocket * socket) { SignalWriteEvent(this); }
++  virtual void OnCloseEvent(AsyncSocket * socket, int err) { SignalCloseEvent(this, err); }
++
++  Socket * socket_;
++};
++
++} // namespace cricket
++
++#endif // __ASYNCSOCKET_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/common.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/common.h	(revision 586398)
+@@ -0,0 +1,231 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _common_h_
++#define _common_h_
++
++#if defined(_MSC_VER)
++// warning C4355: 'this' : used in base member initializer list
++#pragma warning(disable:4355)
++#endif
++
++#if defined(ENABLE_DEBUG_MALLOC) && !defined(ENABLE_DEBUG)
++#define ENABLE_DEBUG 1
++#endif
++
++//////////////////////////////////////////////////////////////////////
++// General Utilities
++//////////////////////////////////////////////////////////////////////
++
++#ifndef UNUSED
++#define UNUSED(x) Unused(static_cast<const void *>(&x))
++#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
++#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
++#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
++#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
++inline void Unused(const void *) { }
++#endif // UNUSED
++
++#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
++
++/////////////////////////////////////////////////////////////////////////////
++// std:min/std:max on msvc
++/////////////////////////////////////////////////////////////////////////////
++
++#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
++
++#undef min
++#undef max
++
++namespace std {
++
++
++  /**
++   *  @brief This does what you think it does.
++   *  @param  a  A thing of arbitrary type.
++   *  @param  b  Another thing of arbitrary type.
++   *  @return   The lesser of the parameters.
++   *
++   *  This is the simple classic generic implementation.  It will work on
++   *  temporary expressions, since they are only evaluated once, unlike a
++   *  preprocessor macro.
++  */
++  template<typename _Tp>
++    inline const _Tp&
++    min(const _Tp& __a, const _Tp& __b)
++    {
++      //return __b < __a ? __b : __a;
++      if (__b < __a) return __b; return __a;
++    }
++
++  /**
++   *  @brief This does what you think it does.
++   *  @param  a  A thing of arbitrary type.
++   *  @param  b  Another thing of arbitrary type.
++   *  @return   The greater of the parameters.
++   *
++   *  This is the simple classic generic implementation.  It will work on
++   *  temporary expressions, since they are only evaluated once, unlike a
++   *  preprocessor macro.
++  */
++  template<typename _Tp>
++    inline const _Tp&
++    max(const _Tp& __a, const _Tp& __b)
++    {
++      //return  __a < __b ? __b : __a;
++      if (__a < __b) return __b; return __a;
++    }
++
++  /**
++   *  @brief This does what you think it does.
++   *  @param  a  A thing of arbitrary type.
++   *  @param  b  Another thing of arbitrary type.
++   *  @param  comp  A @link s20_3_3_comparisons comparison functor at endlink.
++   *  @return   The lesser of the parameters.
++   *
++   *  This will work on temporary expressions, since they are only evaluated
++   *  once, unlike a preprocessor macro.
++  */
++  template<typename _Tp, typename _Compare>
++    inline const _Tp&
++    min(const _Tp& __a, const _Tp& __b, _Compare __comp)
++    {
++      //return __comp(__b, __a) ? __b : __a;
++      if (__comp(__b, __a)) return __b; return __a;
++    }
++
++  /**
++   *  @brief This does what you think it does.
++   *  @param  a  A thing of arbitrary type.
++   *  @param  b  Another thing of arbitrary type.
++   *  @param  comp  A @link s20_3_3_comparisons comparison functor at endlink.
++   *  @return   The greater of the parameters.
++   *
++   *  This will work on temporary expressions, since they are only evaluated
++   *  once, unlike a preprocessor macro.
++  */
++  template<typename _Tp, typename _Compare>
++    inline const _Tp&
++    max(const _Tp& __a, const _Tp& __b, _Compare __comp)
++    {
++      //return __comp(__a, __b) ? __b : __a;
++      if (__comp(__a, __b)) return __b; return __a;
++    }
++
++}
++
++#endif // _MSC_VER <= 1200
++
++
++/////////////////////////////////////////////////////////////////////////////
++// Assertions
++/////////////////////////////////////////////////////////////////////////////
++
++#ifdef ENABLE_DEBUG
++
++namespace buzz {
++
++// Break causes the debugger to stop executing, or the program to abort
++void Break();
++
++// LogAssert writes information about an assertion to the log
++void LogAssert(const char * function, const char * file, int line, const char * expression);
++
++inline void Assert(bool result, const char * function, const char * file, int line, const char * expression) {
++  if (!result) {
++    LogAssert(function, file, line, expression);
++    Break();
++  }
++}
++
++}; // namespace buzz
++
++#if defined(_MSC_VER) && _MSC_VER < 1300
++#define __FUNCTION__ ""
++#endif
++
++#define ASSERT(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
++#define VERIFY(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
++
++#else // !ENABLE_DEBUG
++
++#define ASSERT(x) (void)0
++#define VERIFY(x) (void)(x)
++
++#endif // !ENABLE_DEBUG
++
++#define COMPILE_TIME_ASSERT(expr)       char CTA_UNIQUE_NAME[expr]
++#define CTA_UNIQUE_NAME                 MAKE_NAME(__LINE__)
++#define CTA_MAKE_NAME(line)             MAKE_NAME2(line)
++#define CTA_MAKE_NAME2(line)            constraint_ ## line
++
++//////////////////////////////////////////////////////////////////////
++// Memory leak tracking
++//////////////////////////////////////////////////////////////////////
++
++#include <sys/types.h>
++
++#ifdef ENABLE_DEBUG_MALLOC
++
++namespace buzz {
++
++void * DebugAllocate(size_t size, const char * fname = 0, int line = 0);
++void DebugDeallocate(void * ptr, const char * fname = 0, int line = 0);
++bool LeakCheck();
++bool LeakCheckU();
++void LeakMarkBaseline();
++void LeakClearBaseline();
++
++}; // namespace buzz
++
++inline void * operator new(size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); }
++inline void operator delete(void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); }
++
++#if !(defined(TRACK_ARRAY_ALLOC_PROBLEM) && \
++      defined(_MSC_VER) && _MSC_VER <= 1200) // 1200 == VC++ 6.0
++
++inline void * operator new[](size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); }
++inline void operator delete[](void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); }
++
++#endif // TRACK_ARRAY_ALLOC_PROBLEM
++
++
++// If you put "#define new TRACK_NEW" in your .cc file after all includes, it should track the calling function name
++
++#define TRACK_NEW new(__FILE__,__LINE__)
++#define TRACK_DEL delete(__FILE__,__LINE__)
++
++#else // !ENABLE_DEBUG_MALLOC
++
++#define TRACK_NEW new
++#define TRACK_DEL delete
++
++#endif // !ENABLE_DEBUG_MALLOC
++
++//////////////////////////////////////////////////////////////////////
++
++#endif // _common_h_
+--- kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h	(revision 586398)
+@@ -0,0 +1,158 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _socket_h_
++#define _socket_h_
++
++#include "talk/base/basictypes.h"
++#include "talk/base/socketaddress.h"
++
++#ifdef POSIX
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <netinet/in.h>
++#include <errno.h>
++#endif
++
++#ifdef WIN32
++#include "talk/base/win32.h"
++#endif
++
++// Rather than converting errors into a private namespace,
++// Reuse the POSIX socket api errors. Note this depends on
++// Win32 compatibility.
++
++#ifdef WIN32
++#define EWOULDBLOCK WSAEWOULDBLOCK
++#define EINPROGRESS WSAEINPROGRESS
++#define EALREADY WSAEALREADY
++#define ENOTSOCK WSAENOTSOCK
++#define EDESTADDRREQ WSAEDESTADDRREQ
++#define EMSGSIZE WSAEMSGSIZE
++#define EPROTOTYPE WSAEPROTOTYPE
++#define ENOPROTOOPT WSAENOPROTOOPT
++#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
++#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
++#define EOPNOTSUPP WSAEOPNOTSUPP
++#define EPFNOSUPPORT WSAEPFNOSUPPORT
++#define EAFNOSUPPORT WSAEAFNOSUPPORT
++#define EADDRINUSE WSAEADDRINUSE
++#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
++#define ENETDOWN WSAENETDOWN
++#define ENETUNREACH WSAENETUNREACH
++#define ENETRESET WSAENETRESET
++#define ECONNABORTED WSAECONNABORTED
++#define ECONNRESET WSAECONNRESET
++#define ENOBUFS WSAENOBUFS
++#define EISCONN WSAEISCONN
++#define ENOTCONN WSAENOTCONN
++#define ESHUTDOWN WSAESHUTDOWN
++#define ETOOMANYREFS WSAETOOMANYREFS
++#define ETIMEDOUT WSAETIMEDOUT
++#define ECONNREFUSED WSAECONNREFUSED
++#define ELOOP WSAELOOP
++#undef ENAMETOOLONG // remove errno.h's definition
++#define ENAMETOOLONG WSAENAMETOOLONG
++#define EHOSTDOWN WSAEHOSTDOWN
++#define EHOSTUNREACH WSAEHOSTUNREACH
++#undef ENOTEMPTY // remove errno.h's definition
++#define ENOTEMPTY WSAENOTEMPTY
++#define EPROCLIM WSAEPROCLIM
++#define EUSERS WSAEUSERS
++#define EDQUOT WSAEDQUOT
++#define ESTALE WSAESTALE
++#define EREMOTE WSAEREMOTE
++#undef EACCES
++#define EACCES WSAEACCES
++#endif // WIN32
++
++#ifdef POSIX
++#define INVALID_SOCKET (-1)
++#define SOCKET_ERROR (-1)
++#define closesocket(s) close(s)
++#endif // POSIX
++
++namespace cricket {
++
++inline bool IsBlockingError(int e) {
++  return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS);
++}
++
++// General interface for the socket implementations of various networks.  The
++// methods match those of normal UNIX sockets very closely.
++class Socket {
++public:
++  virtual ~Socket() {}
++ 
++  // Returns the address to which the socket is bound.  If the socket is not
++  // bound, then the any-address is returned.
++  virtual SocketAddress GetLocalAddress() const = 0;
++
++  // Returns the address to which the socket is connected.  If the socket is
++  // not connected, then the any-address is returned.
++  virtual SocketAddress GetRemoteAddress() const = 0;
++
++  virtual int Bind(const SocketAddress& addr) = 0;
++  virtual int Connect(const SocketAddress& addr) = 0;
++  virtual int Send(const void *pv, size_t cb) = 0;
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
++  virtual int Recv(void *pv, size_t cb) = 0;
++  virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) = 0;
++  virtual int Listen(int backlog) = 0;
++  virtual Socket *Accept(SocketAddress *paddr) = 0;
++  virtual int Close() = 0;
++  virtual int GetError() const = 0;
++  virtual void SetError(int error) = 0;
++  inline bool IsBlocking() const { return IsBlockingError(GetError()); }
++
++  enum ConnState {
++    CS_CLOSED,
++    CS_CONNECTING,
++    CS_CONNECTED
++  };
++  virtual ConnState GetState() const = 0;
++
++  // Fills in the given uint16 with the current estimate of the MTU along the
++  // path to the address to which this socket is connected.
++  virtual int EstimateMTU(uint16* mtu) = 0;
++
++  enum Option {
++    OPT_DONTFRAGMENT
++  };
++  virtual int SetOption(Option opt, int value) = 0;
++
++protected:
++  Socket() {}
++
++private:
++  DISALLOW_EVIL_CONSTRUCTORS(Socket);
++};
++
++} // namespace cricket
++
++#endif // _socket_h_
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/thread.h"
++#include "talk/xmpp/xmppclientsettings.h"
++#include "talk/examples/login/xmppthread.h"
++#include <iostream>
++
++int main(int argc, char **argv) {
++  printf("Auth Cookie: ");
++  fflush(stdout);
++
++  char auth_cookie[256];
++  scanf("%s", auth_cookie);
++  
++  char username[256];
++  scanf("%s", username);
++
++  // Start xmpp on a different thread
++  XmppThread thread;
++  thread.Start();
++
++  buzz::XmppClientSettings xcs;
++  xcs.set_user(username);
++  xcs.set_host("gmail.com");
++  xcs.set_use_tls(false);
++  xcs.set_auth_cookie(auth_cookie);
++  xcs.set_server(cricket::SocketAddress("talk.google.com", 5222));
++  thread.Login(xcs);
++
++  // Use main thread for console input
++  std::string line;
++  while (std::getline(std::cin, line)) {
++    if (line == "quit")
++      break;
++  }
++  return 0;
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/xmpp/xmppclientsettings.h"
++#include "talk/examples/login/xmppthread.h"
++#include "talk/examples/login/xmppauth.h"
++
++namespace {
++
++const uint32 MSG_LOGIN = 1;
++const uint32 MSG_DISCONNECT = 2;
++
++struct LoginData: public cricket::MessageData {
++  LoginData(const buzz::XmppClientSettings& s) : xcs(s) {}
++  virtual ~LoginData() {}
++
++  buzz::XmppClientSettings xcs;
++};
++
++} // namespace
++
++XmppThread::XmppThread() {
++  pump_ = new XmppPump(this);
++}
++
++XmppThread::~XmppThread() {
++  delete pump_;
++}
++
++void XmppThread::Loop(int cms) {
++  Thread::Loop(cms);
++}
++
++void XmppThread::Login(const buzz::XmppClientSettings& xcs) {
++  Post(this, MSG_LOGIN, new LoginData(xcs));
++}
++
++void XmppThread::Disconnect() {
++  Post(this, MSG_DISCONNECT);
++}
++
++void XmppThread::OnStateChange(buzz::XmppEngine::State state) {
++}
++
++void XmppThread::OnMessage(cricket::Message* pmsg) {
++  if (pmsg->message_id == MSG_LOGIN) {
++    assert(pmsg->pdata);
++    LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata);
++    pump_->DoLogin(data->xcs, new XmppSocket(false), new XmppAuth());
++    delete data;
++  } else if (pmsg->message_id == MSG_DISCONNECT) {
++    pump_->DoDisconnect();
++  } else {
++    assert(false);
++  }
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc	(revision 586398)
+@@ -0,0 +1,144 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <errno.h>
++#include "talk/base/basicdefs.h"
++#include "talk/base/logging.h"
++#include "talk/base/thread.h"
++#ifdef FEATURE_ENABLE_SSL
++#include "talk/base/schanneladapter.h"
++#endif
++#include "xmppsocket.h"
++
++XmppSocket::XmppSocket(bool tls) : tls_(tls) {
++  cricket::Thread* pth = cricket::Thread::Current();
++  cricket::AsyncSocket* socket =
++    pth->socketserver()->CreateAsyncSocket(SOCK_STREAM);
++#ifdef FEATURE_ENABLE_SSL
++  if (tls_)
++    socket = new cricket::SChannelAdapter(socket);
++#endif
++  cricket_socket_ = socket;
++  cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent);
++  cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent);
++  cricket_socket_->SignalConnectEvent.connect(this,
++                                              &XmppSocket::OnConnectEvent);
++  state_ = buzz::AsyncSocket::STATE_CLOSED;
++}
++
++XmppSocket::~XmppSocket() {
++  Close();
++  delete cricket_socket_;
++}
++
++void XmppSocket::OnReadEvent(cricket::AsyncSocket * socket) {
++  SignalRead();
++}
++
++void XmppSocket::OnWriteEvent(cricket::AsyncSocket * socket) {
++  // Write bytes if there are any
++  while (buffer_.Length() != 0) {
++    int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length());
++    if (written > 0) {
++      buffer_.Shift(written);
++      continue;
++    }
++    if (!cricket_socket_->IsBlocking())
++      LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError();
++    return;
++  }
++}
++
++void XmppSocket::OnConnectEvent(cricket::AsyncSocket * socket) {
++#if defined(FEATURE_ENABLE_SSL)
++  if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) {
++    state_ = buzz::AsyncSocket::STATE_TLS_OPEN;
++    SignalSSLConnected();
++    OnWriteEvent(cricket_socket_);
++    return;
++  }
++#endif  // !defined(FEATURE_ENABLE_SSL)
++  state_ = buzz::AsyncSocket::STATE_OPEN;
++  SignalConnected();
++}
++
++buzz::AsyncSocket::State XmppSocket::state() {
++  return state_;
++}
++
++buzz::AsyncSocket::Error XmppSocket::error() {
++  return buzz::AsyncSocket::ERROR_NONE;
++}
++
++bool XmppSocket::Connect(const cricket::SocketAddress& addr) {
++  if (cricket_socket_->Connect(addr) < 0) {
++    return cricket_socket_->IsBlocking();
++  }
++  return true;
++}
++
++bool XmppSocket::Read(char * data, size_t len, size_t* len_read) {
++  int read = cricket_socket_->Recv(data, len);
++  if (read > 0) {
++    *len_read = (size_t)read;
++    return true;
++  }
++  return false;
++}
++
++bool XmppSocket::Write(const char * data, size_t len) {
++  buffer_.WriteBytes(data, len);
++  OnWriteEvent(cricket_socket_);
++  return true;
++}
++
++bool XmppSocket::Close() {
++  if (state_ != buzz::AsyncSocket::STATE_OPEN)
++    return false;
++  if (cricket_socket_->Close() == 0) {
++    state_ = buzz::AsyncSocket::STATE_CLOSED;
++    SignalClosed();
++    return true;
++  }
++  return false;
++}
++
++bool XmppSocket::StartTls(const std::string & domainname) {
++#if defined(FEATURE_ENABLE_SSL)
++  if (!tls_)
++    return false;
++  cricket::SChannelAdapter * ssl =
++    static_cast<cricket::SChannelAdapter *>(cricket_socket_);
++  ssl->set_ignore_bad_cert(true);
++  if (ssl->StartSSL(domainname.c_str(), false) != 0)
++    return false;
++  state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING;
++  return true;
++#else  // !defined(FEATURE_ENABLE_SSL)
++  return false;
++#endif  // !defined(FEATURE_ENABLE_SSL)
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h	(revision 586398)
+@@ -0,0 +1,57 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPTHREAD_H_
++#define _XMPPTHREAD_H_
++
++#include "talk/xmpp/xmppclientsettings.h"
++#include "talk/base/thread.h"
++#include "talk/examples/login/xmpppump.h"
++#include "talk/examples/login/xmppsocket.h"
++#include <iostream>
++
++class XmppThread:
++    public cricket::Thread, XmppPumpNotify, cricket::MessageHandler {
++public:
++  XmppThread();
++  ~XmppThread();
++
++  buzz::XmppClient* client() { return pump_->client(); }
++
++  void Loop(int cms);
++
++  void Login(const buzz::XmppClientSettings & xcs);
++  void Disconnect();
++
++private:
++  XmppPump* pump_;
++
++  void OnStateChange(buzz::XmppEngine::State state);
++  void OnMessage(cricket::Message* pmsg);
++};
++
++#endif // _XMPPTHREAD_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h	(revision 586398)
+@@ -0,0 +1,63 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPSOCKET_H_
++#define _XMPPSOCKET_H_
++
++#include "talk/base/asyncsocket.h"
++#include "talk/base/bytebuffer.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/asyncsocket.h"
++
++extern cricket::AsyncSocket* cricket_socket_;
++
++class XmppSocket : public buzz::AsyncSocket, public sigslot::has_slots<> {
++public:
++  XmppSocket(bool tls);
++  ~XmppSocket();
++
++  virtual buzz::AsyncSocket::State state();
++  virtual buzz::AsyncSocket::Error error();
++
++  virtual bool Connect(const cricket::SocketAddress& addr);
++  virtual bool Read(char * data, size_t len, size_t* len_read);
++  virtual bool Write(const char * data, size_t len);
++  virtual bool Close();
++  virtual bool StartTls(const std::string & domainname);
++
++private:
++  void OnReadEvent(cricket::AsyncSocket * socket);
++  void OnWriteEvent(cricket::AsyncSocket * socket);
++  void OnConnectEvent(cricket::AsyncSocket * socket);
++
++  cricket::AsyncSocket * cricket_socket_;
++  buzz::AsyncSocket::State state_;
++  cricket::ByteBuffer buffer_;
++  bool tls_;
++};
++
++#endif // _XMPPSOCKET_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am	(revision 586398)
+@@ -0,0 +1,15 @@
++noinst_LTLIBRARIES= libcricketexampleslogin.la
++libcricketexampleslogin_la_SOURCES = xmppsocket.cc \
++				     xmppauth.cc \
++				     xmppthread.cc \
++				     xmpppump.cc 
++noinst_HEADERS = xmppauth.h  xmpppump.h  xmppsocket.h  xmppthread.h
++bin_PROGRAMS = login
++login_CXXFLAGS = $(AM_CXXFLAGS)
++login_SOURCES = login_main.cc xmppsocket.cc xmppthread.cc xmpppump.cc xmppauth.cc
++login_LDADD =  $(srcdir)/../../../talk/xmpp/libcricketxmpp.la \
++	       $(srcdir)/../../../talk/xmllite/libcricketxmllite.la \
++	       $(srcdir)/../../../talk/base/libcricketbase.la \
++	       $(EXPAT_LIBS) -lpthread 
++AM_CPPFLAGS  = -DPOSIX
++DEFAULT_INCLUDES = -I$(srcdir)/../../..
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc	(revision 586398)
+@@ -0,0 +1,93 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <algorithm>
++#include "talk/examples/login/xmppauth.h"
++#include "talk/xmpp/saslcookiemechanism.h"
++#include "talk/xmpp/saslplainmechanism.h"
++
++XmppAuth::XmppAuth() : done_(false), error_(false) {
++}
++
++XmppAuth::~XmppAuth() {
++}
++  
++void XmppAuth::StartPreXmppAuth(const buzz::Jid & jid,
++                                const cricket::SocketAddress & server,
++                                const buzz::XmppPassword & pass,
++                                const std::string & auth_cookie) {
++  jid_ = jid;
++  passwd_ = pass;
++  auth_cookie_ = auth_cookie;
++  error_ = auth_cookie.empty();
++  done_ = true;
++
++  SignalAuthDone();
++}
++  
++std::string XmppAuth::ChooseBestSaslMechanism(
++    const std::vector<std::string> & mechanisms,
++    bool encrypted) {
++  std::vector<std::string>::const_iterator it;
++
++  // a token is the weakest auth - 15s, service-limited, so prefer it.
++  it = std::find(mechanisms.begin(), mechanisms.end(), "X-GOOGLE-TOKEN");
++  if (it != mechanisms.end())
++    return "X-GOOGLE-TOKEN";
++
++  // a cookie is the next weakest - 14 days
++  it = std::find(mechanisms.begin(), mechanisms.end(), "X-GOOGLE-COOKIE");
++  if (it != mechanisms.end())
++    return "X-GOOGLE-COOKIE";
++
++  // never pass @google.com passwords without encryption!!
++  if (!encrypted && (jid_.domain() == "google.com"))
++    return "";
++
++  // as a last resort, use plain authentication
++  if (jid_.domain() != "google.com") {
++    it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
++    if (it != mechanisms.end())
++      return "PLAIN";
++  }
++
++  // No good mechanism found
++ return "";
++}
++
++buzz::SaslMechanism* XmppAuth::CreateSaslMechanism(
++    const std::string & mechanism) {
++  if (mechanism == "X-GOOGLE-TOKEN") {
++    return new buzz::SaslCookieMechanism(mechanism, jid_.Str(), auth_cookie_);
++  //} else if (mechanism == "X-GOOGLE-COOKIE") {
++  //  return new buzz::SaslCookieMechanism(mechanism, jid.Str(), sid_);
++  } else if (mechanism == "PLAIN") {
++    return new buzz::SaslPlainMechanism(jid_, passwd_);
++  } else {
++    return NULL;
++  }
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/examples/login/xmpppump.h"
++#include "talk/examples/login/xmppauth.h"
++
++XmppPump::XmppPump(XmppPumpNotify * notify) {
++  state_ = buzz::XmppEngine::STATE_NONE;
++  notify_ = notify;
++  client_ = new buzz::XmppClient(this);  // NOTE: deleted by TaskRunner
++}
++
++void XmppPump::DoLogin(const buzz::XmppClientSettings & xcs,
++                       buzz::AsyncSocket* socket,
++                       buzz::PreXmppAuth* auth) {
++  OnStateChange(buzz::XmppEngine::STATE_START);
++  client_->SignalStateChange.connect(this, &XmppPump::OnStateChange);
++  client_->Connect(xcs, socket, auth);
++  client_->Start();
++}
++
++void XmppPump::DoDisconnect() {
++  client_->Disconnect();
++  OnStateChange(buzz::XmppEngine::STATE_CLOSED);
++}
++
++void XmppPump::OnStateChange(buzz::XmppEngine::State state) {
++  if (state_ == state)
++    return;
++  state_ = state;
++  if (notify_ != NULL)
++    notify_->OnStateChange(state);
++}
++
++void XmppPump::WakeTasks() {
++  cricket::Thread::Current()->Post(this);
++}
++
++unsigned long long XmppPump::CurrentTime() {
++  return cricket::Time();
++}
++
++void XmppPump::OnMessage(cricket::Message *pmsg) {
++  RunTasks();
++}
++
++buzz::XmppReturnStatus XmppPump::SendStanza(const buzz::XmlElement *stanza) {
++  return client_->SendStanza(stanza);
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h	(revision 586398)
+@@ -0,0 +1,71 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPAUTH_H_
++#define _XMPPAUTH_H_
++
++#include <vector>
++
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/jid.h"
++#include "talk/xmpp/saslhandler.h"
++#include "talk/xmpp/prexmppauth.h"
++#include "talk/xmpp/xmpppassword.h"
++
++class XmppAuth: public buzz::PreXmppAuth {
++public:
++  XmppAuth();
++  virtual ~XmppAuth();
++  
++  virtual void StartPreXmppAuth(const buzz::Jid & jid,
++                                const cricket::SocketAddress & server,
++                                const buzz::XmppPassword & pass,
++                                const std::string & auth_cookie);
++ 
++  virtual bool IsAuthDone() { return done_; }
++  virtual bool IsAuthorized() { return !error_; }
++  virtual bool HadError() { return error_; }
++  virtual buzz::CaptchaChallenge GetCaptchaChallenge() {
++      return buzz::CaptchaChallenge();
++  }
++  virtual std::string GetAuthCookie() { return auth_cookie_; }
++
++  virtual std::string ChooseBestSaslMechanism(
++      const std::vector<std::string> & mechanisms,
++      bool encrypted);
++
++  virtual buzz::SaslMechanism * CreateSaslMechanism(
++      const std::string & mechanism);
++
++private:
++  buzz::Jid jid_;
++  buzz::XmppPassword passwd_;
++  std::string auth_cookie_;
++  bool done_, error_;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h	(revision 586398)
+@@ -0,0 +1,73 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _XMPPPUMP_H_
++#define _XMPPPUMP_H_
++
++#include "talk/base/messagequeue.h"
++#include "talk/base/taskrunner.h"
++#include "talk/base/thread.h"
++#include "talk/base/jtime.h"
++#include "talk/xmpp/xmppclient.h"
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmpptask.h"
++
++// Simple xmpp pump
++
++class XmppPumpNotify {
++public:
++  virtual void OnStateChange(buzz::XmppEngine::State state) = 0;
++};
++
++class XmppPump : public cricket::MessageHandler, public buzz::TaskRunner {
++public:
++  XmppPump(XmppPumpNotify * notify = NULL);
++
++  buzz::XmppClient *client() { return client_; }
++
++  void DoLogin(const buzz::XmppClientSettings & xcs,
++               buzz::AsyncSocket* socket,
++               buzz::PreXmppAuth* auth);
++  void DoDisconnect();
++
++  void OnStateChange(buzz::XmppEngine::State state);
++
++  void WakeTasks();
++
++  unsigned long long CurrentTime();
++
++  void OnMessage(cricket::Message *pmsg);
++
++  buzz::XmppReturnStatus SendStanza(const buzz::XmlElement *stanza);
++
++private:
++  buzz::XmppClient *client_;
++  buzz::XmppEngine::State state_;
++  XmppPumpNotify *notify_;
++};
++
++#endif // _XMPPPUMP_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am	(revision 586398)
+@@ -0,0 +1 @@
++SUBDIRS=login call
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h	(revision 586398)
+@@ -0,0 +1,88 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
++#define CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
++
++#include <map>
++#include <string>
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/xmpp/xmppclient.h"
++#include "talk/examples/call/status.h"
++
++namespace buzz {
++class PresencePushTask;
++class Status;
++}
++
++namespace cricket {
++class Thread;
++class NetworkManager;
++class PortAllocator;
++class PhoneSessionClient;
++class Receiver;
++class Call;
++}
++
++struct RosterItem {
++  buzz::Jid jid;
++  buzz::Status::Show show;
++  std::string status;
++};
++
++class CallClient: public sigslot::has_slots<> {
++public:
++  CallClient(buzz::XmppClient* xmpp_client);
++  ~CallClient();
++
++  cricket::PhoneSessionClient* phone_client() const { return phone_client_; }
++
++  void PrintRoster();
++  void MakeCallTo(const std::string& name);
++
++private:
++  typedef std::map<std::string,RosterItem> RosterMap;
++
++  buzz::XmppClient* xmpp_client_;
++  cricket::Thread* worker_thread_;
++  cricket::NetworkManager* network_manager_;
++  cricket::PortAllocator* port_allocator_;
++  cricket::SessionManager* session_manager_;
++  cricket::PhoneSessionClient* phone_client_;
++  cricket::Receiver* receiver_;
++  buzz::PresencePushTask* presence_push_;
++  RosterMap* roster_;
++
++  void OnStateChange(buzz::XmppEngine::State state);
++
++  void InitPhone();
++  void OnRequestSignaling();
++  void OnCallCreate(cricket::Call* call);
++  const std::string strerror(buzz::XmppEngine::Error err);
++  void OnSessionState(cricket::Call* call,
++                      cricket::Session* session,
++                      cricket::Session::State state);
++  void OnSendStanza(cricket::SessionClient *client, const buzz::XmlElement* stanza);
++
++  void InitPresence();
++  void OnStatusUpdate(const buzz::Status& status);
++};
++
++#endif // CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc	(revision 586398)
+@@ -0,0 +1,62 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include "talk/xmpp/xmppclientsettings.h"
++#include "talk/examples/login/xmppthread.h"
++#include "talk/examples/login/xmppauth.h"
++#include "talk/examples/call/callclient.h"
++#include "talk/examples/call/console.h"
++
++void GetString(const char* desc, char* out) {
++  printf("%s: ", desc);
++  fflush(stdout);
++  scanf("%s", out);
++}
++
++int main(int argc, char **argv) {
++  // TODO: Make this into a console task
++  char username[256], auth_cookie[256];
++  GetString("Username", username);
++  GetString("Auth Cookie", auth_cookie);
++
++  printf("Logging in as %s at gmail.com\n", username);
++
++  // We will run the console and the XMPP client on the main thread.  The
++  // CallClient maintains a separate worker thread for voice.
++
++  cricket::PhysicalSocketServer ss;
++  cricket::Thread main_thread(&ss);
++  cricket::ThreadManager::SetCurrent(&main_thread);
++
++  InitConsole(&ss);
++  XmppPump pump;
++  CallClient client(pump.client());
++
++  buzz::XmppClientSettings xcs;
++  xcs.set_user(username);
++  xcs.set_host("gmail.com");
++  xcs.set_use_tls(false);
++  xcs.set_auth_cookie(auth_cookie);
++  xcs.set_server(cricket::SocketAddress("talk.google.com", 5222));
++  pump.DoLogin(xcs, new XmppSocket(false), new XmppAuth());
++
++  main_thread.Loop();
++
++  return 0;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc	(revision 586398)
+@@ -0,0 +1,148 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <sstream>
++#include <time.h>
++#include "talk/xmpp/constants.h"
++#include "talk/xmpp/xmppclient.h"
++#include "talk/examples/call/presenceouttask.h"
++
++namespace buzz {
++
++// string helper functions -----------------------------------------------------
++template <class T> static
++bool FromString(const std::string& s,
++                 T * t) {
++  std::istringstream iss(s);
++  return !(iss>>*t).fail();
++}
++
++template <class T> static
++bool ToString(const T &t,
++               std::string* s) {
++  std::ostringstream oss;
++  oss << t;
++  *s = oss.str();
++  return !oss.fail();
++}
++
++XmppReturnStatus
++PresenceOutTask::Send(const Status & s) {
++  if (GetState() != STATE_INIT)
++    return XMPP_RETURN_BADSTATE;
++
++  stanza_.reset(TranslateStatus(s));
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus
++PresenceOutTask::SendDirected(const Jid & j, const Status & s) {
++  if (GetState() != STATE_INIT)
++    return XMPP_RETURN_BADSTATE;
++
++  XmlElement * presence = TranslateStatus(s);
++  presence->AddAttr(QN_TO, j.Str());
++  stanza_.reset(presence);
++  return XMPP_RETURN_OK;
++}
++
++XmppReturnStatus PresenceOutTask::SendProbe(const Jid & jid) {
++  if (GetState() != STATE_INIT)
++    return XMPP_RETURN_BADSTATE;
++
++  XmlElement * presence = new XmlElement(QN_PRESENCE);
++  presence->AddAttr(QN_TO, jid.Str());
++  presence->AddAttr(QN_TYPE, "probe");
++
++  stanza_.reset(presence);
++  return XMPP_RETURN_OK;
++}
++
++int
++PresenceOutTask::ProcessStart() {
++  if (SendStanza(stanza_.get()) != XMPP_RETURN_OK)
++    return STATE_ERROR;
++  return STATE_DONE;
++}
++
++XmlElement *
++PresenceOutTask::TranslateStatus(const Status & s) {
++  XmlElement * result = new XmlElement(QN_PRESENCE);
++  if (!s.available()) {
++    result->AddAttr(QN_TYPE, STR_UNAVAILABLE);
++  }
++  else {
++    if (s.invisible()) {
++      result->AddAttr(QN_TYPE, STR_INVISIBLE);
++    }
++
++    if (s.show() != Status::SHOW_ONLINE && s.show() != Status::SHOW_OFFLINE) {
++      result->AddElement(new XmlElement(QN_SHOW));
++      switch (s.show()) {
++        default:
++          result->AddText(STR_SHOW_AWAY, 1);
++          break;
++        case Status::SHOW_XA:
++          result->AddText(STR_SHOW_XA, 1);
++          break;
++        case Status::SHOW_DND:
++          result->AddText(STR_SHOW_DND, 1);
++          break;
++        case Status::SHOW_CHAT:
++          result->AddText(STR_SHOW_CHAT, 1);
++          break;
++      }
++    }
++
++    result->AddElement(new XmlElement(QN_STATUS));
++    result->AddText(s.status(), 1);
++
++    std::string pri;
++    ToString(s.priority(), &pri);
++
++    result->AddElement(new XmlElement(QN_PRIORITY));
++    result->AddText(pri, 1);
++
++    if (s.know_capabilities() && s.is_google_client()) {
++      result->AddElement(new XmlElement(QN_CAPS_C, true));
++      result->AddAttr(QN_NODE, GOOGLE_CLIENT_NODE, 1);
++      result->AddAttr(QN_VER, s.version(), 1);
++      result->AddAttr(QN_EXT, s.phone_capability() ? "voice-v1" : "", 1);
++    }
++
++    // Put the delay mark on the presence according to JEP-0091
++    {
++      result->AddElement(new XmlElement(kQnDelayX, true));
++
++      // This here is why we *love* the C runtime
++      time_t current_time_seconds;
++      time(&current_time_seconds);
++      struct tm* current_time = gmtime(&current_time_seconds);
++      char output[256];
++      strftime(output, ARRAY_SIZE(output), "%Y%m%dT%H:%M:%S", current_time);
++      result->AddAttr(kQnStamp, output, 1);
++    }
++
++  }
++
++  return result;
++}
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h	(revision 586398)
+@@ -0,0 +1,46 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _PRESENCEOUTTASK_H_
++#define _PRESENCEOUTTASK_H_
++
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmpptask.h"
++#include "talk/examples/call/status.h"
++
++namespace buzz {
++
++class PresenceOutTask : public XmppTask {
++public:
++  PresenceOutTask(Task * parent) : XmppTask(parent) {}
++  virtual ~PresenceOutTask() {}
++
++  XmppReturnStatus Send(const Status & s);
++  XmppReturnStatus SendDirected(const Jid & j, const Status & s);
++  XmppReturnStatus SendProbe(const Jid& jid);
++
++  virtual int ProcessStart();
++private:
++  XmlElement * TranslateStatus(const Status & s);
++  scoped_ptr<XmlElement> stanza_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc	(revision 586398)
+@@ -0,0 +1,196 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++extern "C" {
++#include <sys/types.h>
++#include <sys/time.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <ctype.h>
++}
++#include <cassert>
++#include <cstdio>
++#include <cstdlib>
++#include <cstdarg>
++
++#include "talk/examples/call/console.h"
++
++namespace {
++
++void PError(const char* desc) {
++  perror(desc);
++  exit(1);
++}
++
++CConsole* gConsole = NULL;
++
++const uint32 MSG_UPDATE = 1;
++
++} // namespace
++
++void InitConsole(cricket::PhysicalSocketServer* ss) {
++  assert(gConsole == NULL);
++  assert(ss);
++  gConsole = new CConsole(ss);
++}
++
++CConsole* Console() {
++  assert(gConsole);
++  return gConsole;
++}
++
++CConsole::CConsole(cricket::PhysicalSocketServer* ss)
++    : prompting_(false), prompt_dirty_(false) {
++  stdin_ = ss->CreateFile(0);
++  stdin_->SignalReadEvent.connect(this, &CConsole::OnReadInput);
++
++  tasks_ = new std::vector<ConsoleTask*>;
++}
++
++CConsole::~CConsole() {
++  delete stdin_;
++  delete tasks_;
++}
++
++void CConsole::Push(ConsoleTask* task) {
++  task->set_console(this);
++  task->SignalDone.connect(this, &CConsole::OnTaskDone);
++  tasks_->push_back(task);
++  task->Start();
++  UpdatePrompt();
++}
++
++void CConsole::Remove(ConsoleTask* task) {
++  int index = -1;
++  for (size_t i = 0; i < tasks_->size(); ++i) {
++    if ((*tasks_)[i] == task)
++      index = i;
++  }
++
++  assert(index >= 0);
++  tasks_->erase(tasks_->begin() + index);
++  if (static_cast<int>(tasks_->size()) == index)
++    UpdatePrompt();
++
++  delete task;
++
++  if (tasks_->size() == 0)
++    exit(0);
++}
++
++void CConsole::Print(const char* str) {
++  if (prompting_)
++    printf("\r");
++  printf("%s\n", str);
++  prompting_ = false;
++  UpdatePrompt();
++}
++
++void CConsole::Print(const std::string& str) {
++  Print(str.c_str());
++}
++
++void CConsole::Printf(const char* format, ...) {
++  va_list ap;
++  va_start(ap, format);
++
++  char buf[4096];
++  int size = vsnprintf(buf, sizeof(buf), format, ap);
++  assert(size >= 0);
++  assert(size < static_cast<int>(sizeof(buf)));
++  buf[size] = '\0';
++  Print(buf);
++
++  va_end(ap);
++}
++
++void CConsole::OnTaskDone(ConsoleTask* task) {
++  Remove(task);
++}
++
++void CConsole::OnReadInput(cricket::AsyncFile* file) {
++  assert(file == stdin_);
++
++  char buf[4096];
++  int size = read(0, buf, sizeof(buf));
++  if (size < 0)
++    PError("read");
++
++  prompting_ = (buf[size-1] != '\n');
++
++  int start = 0;
++  for (int i = 0; i < size; ++i) {
++    if (buf[i] == '\n') {
++      std::string line = input_;
++      line.append(buf + start, i + 1 - start);
++      input_.clear();
++
++      assert(tasks_->size() > 0);
++      tasks_->back()->ProcessLine(line);
++
++      start = i + 1;
++    }
++  }
++
++  input_.append(buf + start, size - start);
++}
++
++void CConsole::OnMessage(cricket::Message* pmsg) {
++  assert(pmsg->message_id == MSG_UPDATE);
++  assert(tasks_->size() > 0);
++  if (prompting_)
++    printf("\n");
++  printf("%s: %s", tasks_->back()->GetPrompt().c_str(), input_.c_str());
++  fflush(stdout);
++  prompting_ = true;
++  prompt_dirty_ = false;
++}
++
++void CConsole::UpdatePrompt() {
++  if (!prompt_dirty_) {
++    prompt_dirty_ = true;
++    cricket::Thread::Current()->Post(this, MSG_UPDATE);
++  }
++}
++
++void ConsoleTask::ParseLine(const std::string& line,
++                            std::vector<std::string>* words) {
++  assert(line.size() > 0);
++  assert(line[line.size() - 1] == '\n');
++
++  int start = -1;
++  int state = 0;
++  for (int index = 0; index <= static_cast<int>(line.size()); ++index) {
++    if (state == 0) {
++      if (!isspace(line[index])) {
++        start = index;
++        state = 1;
++      }
++    } else {
++      assert(state == 1);
++      assert(start >= 0);
++      if (isspace(line[index])) {
++        std::string word(line, start, index - start);
++        words->push_back(word);
++        start = -1;
++        state = 0;
++      }
++    }
++  }
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h	(revision 586398)
+@@ -0,0 +1,82 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef CRICKET_EXAMPLES_CALL_CONSOLE_H__
++#define CRICKET_EXAMPLES_CALL_CONSOLE_H__
++
++#include <string>
++#include <vector>
++
++#include "talk/base/sigslot.h"
++#include "talk/base/thread.h"
++#include "talk/base/physicalsocketserver.h"
++
++class CConsole;
++
++class ConsoleTask {
++public:
++  ConsoleTask() : console_(NULL) {}
++  virtual ~ConsoleTask() {}
++
++  CConsole* console() const { return console_; } 
++  void set_console(CConsole* console) { console_ = console; }
++
++  virtual void Start() {}
++  virtual std::string GetPrompt() = 0;
++  virtual void ProcessLine(const std::string& line) = 0; // includes newline
++
++  sigslot::signal1<ConsoleTask*> SignalDone;
++
++protected:
++  void ParseLine(const std::string& line, std::vector<std::string>* words);
++
++private:
++  CConsole* console_;
++};
++
++class CConsole: public cricket::MessageHandler, public sigslot::has_slots<> {
++public:
++  CConsole(cricket::PhysicalSocketServer* ss);
++  ~CConsole();
++
++  void Push(ConsoleTask* task);
++  void Remove(ConsoleTask* task);
++
++  // final newline should not be included
++  void Print(const char* str);
++  void Print(const std::string& str);
++  void Printf(const char* format, ...);
++
++private:
++  cricket::AsyncFile* stdin_;
++  std::vector<ConsoleTask*>* tasks_;
++  std::string input_;
++  bool prompting_;
++  bool prompt_dirty_;
++
++  void OnTaskDone(ConsoleTask* task);
++  void OnReadInput(cricket::AsyncFile* file);
++  void OnMessage(cricket::Message* pmsg);
++  void UpdatePrompt();
++};
++
++void InitConsole(cricket::PhysicalSocketServer* ss);
++CConsole* Console();
++
++#endif // CRICKET_EXAMPLES_CALL_CONSOLE_H__
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am	(revision 586398)
+@@ -0,0 +1,16 @@
++bin_PROGRAMS = call 
++call_CXXFLAGS = $(AM_CXXFLAGS)
++call_SOURCES = call_main.cc callclient.cc console.cc presencepushtask.cc presenceouttask.cc
++noinst_HEADERS = callclient.h  console.h  presenceouttask.h  presencepushtask.h  status.h
++call_LDADD =  \
++	       $(srcdir)/../../../talk/examples/login/libcricketexampleslogin.la \
++	       $(srcdir)/../../../talk/session/phone/libcricketsessionphone.la \
++	       $(srcdir)/../../../talk/p2p/client/libcricketp2pclient.la \
++	       $(srcdir)/../../../talk/p2p/base/libcricketp2pbase.la \
++	       $(srcdir)/../../../talk/xmpp/libcricketxmpp.la \
++	       $(srcdir)/../../../talk/xmllite/libcricketxmllite.la \
++	       $(srcdir)/../../../talk/base/libcricketbase.la \
++	       $(srcdir)/../../../talk/third_party/mediastreamer/libmediastreamer.la \
++	       $(EXPAT_LIBS) $(ORTP_LIBS) -lpthread $(ILBC_LIBS) $(SPEEX_LIBS) $(GLIB_LIBS) -lasound 
++AM_CPPFLAGS  = -DPOSIX
++DEFAULT_INCLUDES = -I$(srcdir)/../../..
+\ No newline at end of file
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h	(revision 586398)
+@@ -0,0 +1,213 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef _STATUS_H_
++#define _STATUS_H_
++
++#include "talk/xmpp/jid.h"
++#include "talk/xmpp/constants.h"
++
++#define GOOGLE_CLIENT_NODE "http://www.google.com/xmpp/client/caps"
++
++namespace buzz {
++
++class Status {
++public:
++  Status() :
++    pri_(0),
++    show_(SHOW_NONE),
++    available_(false),
++    invisible_(false),
++    e_code_(0),
++    phone_capability_(false),
++    know_capabilities_(false),
++    is_google_client_(false),
++    feedback_probation_(false) {};
++
++  ~Status() {}
++
++  // These are arranged in "priority order", i.e., if we see
++  // two statuses at the same priority but with different Shows,
++  // we will show the one with the highest show in the following
++  // order.
++  enum Show {
++    SHOW_NONE     = 0,
++    SHOW_INVISIBLE = 1,
++    SHOW_OFFLINE  = 2,
++    SHOW_XA       = 3,
++    SHOW_AWAY     = 4,
++    SHOW_DND      = 5,
++    SHOW_ONLINE   = 6,
++    SHOW_CHAT     = 7,
++  };
++
++  const Jid & jid() const { return jid_; }
++  int priority() const { return pri_; }
++  Show show() const { return show_; }
++  const std::string & status() const { return status_; }
++  bool available() const { return available_ ; }
++  bool invisible() const { return invisible_; }
++  int error_code() const { return e_code_; }
++  const std::string & error_string() const { return e_str_; }
++  bool know_capabilities() const { return know_capabilities_; }
++  bool phone_capability() const { return phone_capability_; }
++  bool is_google_client() const { return is_google_client_; }
++  const std::string & version() const { return version_; }
++  bool feedback_probation() const { return feedback_probation_; }
++  const std::string& sent_time() const { return sent_time_; }
++
++  void set_jid(const Jid & jid) { jid_ = jid; }
++  void set_priority(int pri) { pri_ = pri; }
++  void set_show(Show show) { show_ = show; }
++  void set_status(const std::string & status) { status_ = status; }
++  void set_available(bool a) { available_ = a; }
++  void set_invisible(bool i) { invisible_ = i; }
++  void set_error(int e_code, const std::string e_str)
++      { e_code_ = e_code; e_str_ = e_str; }
++  void set_know_capabilities(bool f) { know_capabilities_ = f; }
++  void set_phone_capability(bool f) { phone_capability_ = f; }
++  void set_is_google_client(bool f) { is_google_client_ = f; }
++  void set_version(const std::string & v) { version_ = v; }
++  void set_feedback_probation(bool f) { feedback_probation_ = f; }
++  void set_sent_time(const std::string& time) { sent_time_ = time; }
++
++  void UpdateWith(const Status & new_value) {
++    if (!new_value.know_capabilities()) {
++       bool k = know_capabilities();
++       bool i = is_google_client();
++       bool p = phone_capability();
++       std::string v = version();
++
++       *this = new_value;
++
++       set_know_capabilities(k);
++       set_is_google_client(i);
++       set_phone_capability(p);
++       set_version(v);
++    }
++    else {
++      *this = new_value;
++    }
++  }
++
++  bool HasQuietStatus() const {
++    if (status_.empty())
++      return false;
++    return !(QuietStatus().empty());
++  }
++
++  // Knowledge of other clients' silly automatic status strings -
++  // Don't show these.
++  std::string QuietStatus() const {
++    if (jid_.resource().find("Psi") != std::string::npos) {
++      if (status_ == "Online" ||
++          status_.find("Auto Status") != std::string::npos)
++        return STR_EMPTY;
++    }
++    if (jid_.resource().find("Gaim") != std::string::npos) {
++      if (status_ == "Sorry, I ran out for a bit!")
++        return STR_EMPTY;
++    }
++    return TrimStatus(status_);
++  }
++
++  std::string ExplicitStatus() const {
++    std::string result = QuietStatus();
++    if (result.empty()) {
++      result = ShowStatus();
++    }
++    return result;
++  }
++
++  std::string ShowStatus() const {
++    std::string result;
++    if (!available()) {
++      result = "Offline";
++    }
++    else {
++      switch (show()) {
++        case SHOW_AWAY:
++        case SHOW_XA:
++          result = "Idle";
++          break;
++        case SHOW_DND:
++          result = "Busy";
++          break;
++        case SHOW_CHAT:
++          result = "Chatty";
++          break;
++        default:
++          result = "Available";
++          break;
++      }
++    }
++    return result;
++  }
++
++  static std::string TrimStatus(const std::string & st) {
++    std::string s(st);
++    int j = 0;
++    bool collapsing = true;
++    for (unsigned int i = 0; i < s.length(); i+= 1) {
++      if (s[i] <= ' ' && s[i] >= 0) {
++        if (collapsing) {
++          continue;
++        }
++        else {
++          s[j] = ' ';
++          j += 1;
++          collapsing = true;
++        }
++      }
++      else {
++        s[j] = s[i];
++        j += 1;
++        collapsing = false;
++      }
++    }
++    if (collapsing && j > 0) {
++      j -= 1;
++    }
++    s.erase(j, s.length());
++    return s;
++  }
++
++private:
++  Jid jid_;
++  int pri_;
++  Show show_;
++  std::string status_;
++  bool available_;
++  bool invisible_;
++  int e_code_;
++  std::string e_str_;
++  bool feedback_probation_;
++
++  // capabilities (valid only if know_capabilities_
++  bool know_capabilities_;
++  bool phone_capability_;
++  bool is_google_client_;
++  std::string version_;
++
++  std::string sent_time_; // from the jabber:x:delay element
++};
++
++}
++
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro	(revision 586398)
+@@ -0,0 +1,19 @@
++TEMPLATE = app
++INCLUDEPATH = ../../..
++DEFINES += POSIX
++
++include(../../../../../conf.pri)
++
++# Input
++SOURCES += \
++	call_main.cc \
++	callclient.cc \
++	console.cc \
++	presenceouttask.cc \
++	presencepushtask.cc \
++	../login/xmppauth.cc \
++	../login/xmpppump.cc \
++	../login/xmppsocket.cc \
++	../login/xmppthread.cc
++
++LIBS += ../../../liblibjingle.a
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc	(revision 586398)
+@@ -0,0 +1,172 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include "talk/examples/call/presencepushtask.h"
++#include "talk/xmpp/constants.h"
++#include <sstream>
++
++
++namespace buzz {
++
++// string helper functions -----------------------------------------------------
++template <class T> static
++bool FromString(const std::string& s,
++                 T * t) {
++  std::istringstream iss(s);
++  return !(iss>>*t).fail();
++}
++
++template <class T> static
++bool ToString(const T &t,
++               std::string* s) {
++  std::ostringstream oss;
++  oss << t;
++  *s = oss.str();
++  return !oss.fail();
++}
++
++static bool
++IsXmlSpace(int ch) {
++  return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
++}
++
++static bool
++ListContainsToken(const std::string & list, const std::string & token) {
++  size_t i = list.find(token);
++  if (i == std::string::npos || token.empty())
++    return false;
++  bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
++  bool boundary_after = (i == list.length() - token.length() || IsXmlSpace(list[i + token.length()]));
++  return boundary_before && boundary_after;
++}
++
++
++bool
++PresencePushTask::HandleStanza(const XmlElement * stanza) {
++  if (stanza->Name() != QN_PRESENCE)
++    return false;
++  if (stanza->HasAttr(QN_TYPE) && stanza->Attr(QN_TYPE) != STR_UNAVAILABLE)
++    return false;
++  QueueStanza(stanza);
++  return true;
++}
++
++static bool IsUtf8FirstByte(int c) {
++  return (((c)&0x80)==0) || // is single byte
++    ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
++}
++
++int
++PresencePushTask::ProcessStart() {
++  const XmlElement * stanza = NextStanza();
++  if (stanza == NULL)
++    return STATE_BLOCKED;
++  Status s;
++
++  s.set_jid(Jid(stanza->Attr(QN_FROM)));
++
++  if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
++    s.set_available(false);
++    SignalStatusUpdate(s);
++  }
++  else {
++    s.set_available(true);
++    const XmlElement * status = stanza->FirstNamed(QN_STATUS);
++    if (status != NULL) {
++      s.set_status(status->BodyText());
++
++      // Truncate status messages longer than 300 bytes
++      if (s.status().length() > 300) {
++        size_t len = 300;
++
++        // Be careful not to split legal utf-8 chars in half
++        while (!IsUtf8FirstByte(s.status()[len]) && len > 0) {
++          len -= 1;
++        }
++        std::string truncated(s.status(), 0, len);
++        s.set_status(truncated);
++      }
++    }
++
++    const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
++    if (priority != NULL) {
++      int pri;
++      if (FromString(priority->BodyText(), &pri)) {
++        s.set_priority(pri);
++      }
++    }
++
++    const XmlElement * show = stanza->FirstNamed(QN_SHOW);
++    if (show == NULL || show->FirstChild() == NULL) {
++      s.set_show(Status::SHOW_ONLINE);
++    }
++    else {
++      if (show->BodyText() == "away") {
++        s.set_show(Status::SHOW_AWAY);
++      }
++      else if (show->BodyText() == "xa") {
++        s.set_show(Status::SHOW_XA);
++      }
++      else if (show->BodyText() == "dnd") {
++        s.set_show(Status::SHOW_DND);
++      }
++      else if (show->BodyText() == "chat") {
++        s.set_show(Status::SHOW_CHAT);
++      }
++      else {
++        s.set_show(Status::SHOW_ONLINE);
++      }
++    }
++
++    const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
++    if (caps != NULL) {
++      std::string node = caps->Attr(QN_NODE);
++      std::string ver = caps->Attr(QN_VER);
++      std::string exts = caps->Attr(QN_EXT);
++
++      s.set_know_capabilities(true);
++
++      if (node == GOOGLE_CLIENT_NODE) {
++        s.set_is_google_client(true);
++        s.set_version(ver);
++        if (ListContainsToken(exts, "voice-v1")) {
++          s.set_phone_capability(true);
++        }
++      }
++    }
++
++    const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
++    if (delay != NULL) {
++      // Ideally we would parse this according to the Psuedo ISO-8601 rules
++      // that are laid out in JEP-0082:
++      // http://www.jabber.org/jeps/jep-0082.html
++      std::string stamp = delay->Attr(kQnStamp);
++      s.set_sent_time(stamp);
++    }
++
++    SignalStatusUpdate(s);
++  }
++
++  return STATE_START;
++}
++
++
++}
++
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h	(revision 586398)
+@@ -0,0 +1,44 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _PRESENCEPUSHTASK_H_
++#define _PRESENCEPUSHTASK_H_
++
++#include "talk/xmpp/xmppengine.h"
++#include "talk/xmpp/xmpptask.h"
++#include "talk/base/sigslot.h"
++#include "talk/examples/call/status.h"
++
++namespace buzz {
++
++class PresencePushTask : public XmppTask {
++
++public:
++  PresencePushTask(Task * parent) : XmppTask(parent, XmppEngine::HL_TYPE) {}
++  virtual int ProcessStart();
++  sigslot::signal1<const Status &>SignalStatusUpdate;
++
++protected:
++  virtual bool HandleStanza(const XmlElement * stanza);
++};
++
++  
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc	(revision 586398)
+@@ -0,0 +1,390 @@
++/*
++ * Jingle call example
++ * Copyright 2004--2005, Google Inc.
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <string>
++#include <vector>
++
++#include "talk/xmpp/constants.h"
++#include "talk/base/thread.h"
++#include "talk/base/network.h"
++#include "talk/base/socketaddress.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/session/receiver.h"
++#include "talk/session/sessionsendtask.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/examples/call/callclient.h"
++#include "talk/examples/call/console.h"
++#include "talk/examples/call/presencepushtask.h"
++#include "talk/examples/call/presenceouttask.h"
++
++namespace {
++
++const char* CALL_COMMANDS =
++"Available commands:\n"
++"\n"
++"  hangup  Ends the call.\n"
++"  mute    Stops sending voice.\n"
++"  unmute  Re-starts sending voice.\n"
++"";
++
++class CallTask: public ConsoleTask, public sigslot::has_slots<> {
++public:
++  CallTask(CallClient* call_client, const buzz::Jid& jid, cricket::Call* call)
++      : call_client_(call_client), jid_(jid), call_(call) {
++  }
++
++  virtual ~CallTask() {}
++
++  virtual void Start() {
++    call_client_->phone_client()->SignalCallDestroy.connect(
++        this, &CallTask::OnCallDestroy);
++    if (!call_) {
++      call_ = call_client_->phone_client()->CreateCall();
++      call_->SignalSessionState.connect(this, &CallTask::OnSessionState);
++      session_ = call_->InitiateSession(jid_);
++    }
++    call_client_->phone_client()->SetFocus(call_);
++  }
++
++  virtual std::string GetPrompt() { return jid_.node(); }
++
++  virtual void ProcessLine(const std::string& line) {
++    std::vector<std::string> words;
++    ParseLine(line, &words);
++
++    if ((words.size() == 1) && (words[0] == "hangup")) {
++      call_->Terminate();
++      SignalDone(this);
++    } else if ((words.size() == 1) && (words[0] == "mute")) {
++      call_->Mute(true);
++    } else if ((words.size() == 1) && (words[0] == "unmute")) {
++      call_->Mute(false);
++    } else {
++      console()->Print(CALL_COMMANDS);
++    }
++  }
++
++private:
++  CallClient* call_client_;
++  buzz::Jid jid_;
++  cricket::Call* call_;
++  cricket::Session* session_;
++
++  void OnCallDestroy(cricket::Call* call) {
++    if (call == call_) {
++      console()->Print("call destroyed");
++      SignalDone(this);
++    }
++  }
++
++  void OnSessionState(cricket::Call* call,
++                      cricket::Session* session,
++                      cricket::Session::State state) {
++    if (state == cricket::Session::STATE_SENTINITIATE) {
++      console()->Print("calling...");
++    } else if (state == cricket::Session::STATE_RECEIVEDACCEPT) {
++      console()->Print("call answered");
++    } else if (state == cricket::Session::STATE_RECEIVEDREJECT) {
++      console()->Print("call not answered");
++      SignalDone(this);
++    } else if (state == cricket::Session::STATE_INPROGRESS) {
++      console()->Print("call in progress");
++    } else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) {
++      console()->Print("other side hung up");
++      SignalDone(this);
++    }
++  }
++};
++
++const char* RECEIVE_COMMANDS =
++"Available commands:\n"
++"\n"
++"  accept  Accepts the incoming call and switches to it.\n"
++"  reject  Rejects the incoming call and stays with the current call.\n"
++"";
++
++class ReceiveTask: public ConsoleTask {
++public:
++  ReceiveTask(CallClient* call_client,
++              const buzz::Jid& jid,
++              cricket::Call* call)
++      : call_client_(call_client), jid_(jid), call_(call) {
++  }
++
++  virtual std::string GetPrompt() { return jid_.node(); }
++
++  virtual void ProcessLine(const std::string& line) {
++    std::vector<std::string> words;
++    ParseLine(line, &words);
++
++    if ((words.size() == 1) && (words[0] == "accept")) {
++      assert(call_->sessions().size() == 1);
++      call_->AcceptSession(call_->sessions()[0]);
++      Console()->Push(new CallTask(call_client_, jid_, call_));
++      SignalDone(this);
++    } else if ((words.size() == 1) && (words[0] == "reject")) {
++      call_->RejectSession(call_->sessions()[0]);
++      SignalDone(this);
++    } else {
++      console()->Print(RECEIVE_COMMANDS);
++    }
++  }
++
++private:
++  CallClient* call_client_;
++  buzz::Jid jid_;
++  cricket::Call* call_;
++};
++
++const char* CONSOLE_COMMANDS =
++"Available commands:\n"
++"\n"
++"  roster       Prints the online friends from your roster.\n"
++"  call <name>  Initiates a call to the friend with the given name.\n"
++"  quit         Quits the application.\n"
++"";
++
++class CallConsoleTask: public ConsoleTask {
++public:
++  CallConsoleTask(CallClient* call_client) : call_client_(call_client) {}
++  virtual ~CallConsoleTask() {}
++
++  virtual std::string GetPrompt() { return "console"; }
++
++  virtual void ProcessLine(const std::string& line) {
++    std::vector<std::string> words;
++    ParseLine(line, &words);
++
++    if ((words.size() == 1) && (words[0] == "quit")) {
++      SignalDone(this);
++    } else if ((words.size() == 1) && (words[0] == "roster")) {
++      call_client_->PrintRoster();
++    } else if ((words.size() == 2) && (words[0] == "call")) {
++      call_client_->MakeCallTo(words[1]);
++    } else {
++      console()->Print(CONSOLE_COMMANDS);
++    }
++  }
++
++private:
++  CallClient* call_client_;
++};
++
++const char* DescribeStatus(buzz::Status::Show show, const std::string& desc) {
++  switch (show) {
++  case buzz::Status::SHOW_XA:      return desc.c_str();
++  case buzz::Status::SHOW_ONLINE:  return "online";
++  case buzz::Status::SHOW_AWAY:    return "away";
++  case buzz::Status::SHOW_DND:     return "do not disturb";
++  case buzz::Status::SHOW_CHAT:    return "ready to chat";
++  delault:                         return "offline";
++  }
++}
++
++} // namespace
++
++CallClient::CallClient(buzz::XmppClient* xmpp_client)
++    : xmpp_client_(xmpp_client), roster_(new RosterMap) {
++  xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
++  Console()->Push(new CallConsoleTask(this));
++}
++
++CallClient::~CallClient() {
++  delete roster_;
++}
++
++const std::string CallClient::strerror(buzz::XmppEngine::Error err) {
++  switch (err) {
++   case  buzz::XmppEngine::ERROR_NONE: 
++     return "";
++   case  buzz::XmppEngine::ERROR_XML:  
++     return "Malformed XML or encoding error";
++   case  buzz::XmppEngine::ERROR_STREAM: 
++     return "XMPP stream error";
++   case  buzz::XmppEngine::ERROR_VERSION:
++     return "XMPP version error";
++   case  buzz::XmppEngine::ERROR_UNAUTHORIZED:
++     return "User is not authorized (Confirm your GX cookie at mail.google.com)";
++   case  buzz::XmppEngine::ERROR_TLS:
++     return "TLS could not be negotiated";
++   case	 buzz::XmppEngine::ERROR_AUTH:
++     return "Authentication could not be negotiated";
++   case  buzz::XmppEngine::ERROR_BIND:
++     return "Resource or session binding could not be negotiated";
++   case  buzz::XmppEngine::ERROR_CONNECTION_CLOSED:
++     return "Connection closed by output handler.";
++   case  buzz::XmppEngine::ERROR_DOCUMENT_CLOSED:
++     return "Closed by </stream:stream>";
++   case  buzz::XmppEngine::ERROR_SOCKET:
++     return "Socket error";
++  }
++}
++
++void CallClient::OnStateChange(buzz::XmppEngine::State state) {
++  switch (state) {
++  case buzz::XmppEngine::STATE_START:
++    Console()->Print("connecting...");
++    break;
++
++  case buzz::XmppEngine::STATE_OPENING:
++    Console()->Print("logging in...");
++    break;
++
++  case buzz::XmppEngine::STATE_OPEN:
++    Console()->Print("logged in...");
++    InitPhone();
++    InitPresence();
++    break;
++
++  case buzz::XmppEngine::STATE_CLOSED:
++    buzz::XmppEngine::Error error = xmpp_client_->GetError();
++    Console()->Print("logged out..." + strerror(error));
++    exit(0);
++  }
++}
++
++void CallClient::InitPhone() {
++  std::string client_unique = xmpp_client_->jid().Str();
++  cricket::InitRandom(client_unique.c_str(), client_unique.size());
++
++  worker_thread_ = new cricket::Thread();
++
++  network_manager_ = new cricket::NetworkManager();
++  
++  cricket::SocketAddress *stun_addr = new cricket::SocketAddress("64.233.167.126", 19302);
++  port_allocator_ = new cricket::BasicPortAllocator(network_manager_, stun_addr, NULL);
++
++  session_manager_ = new cricket::SessionManager(
++      port_allocator_, worker_thread_);
++  session_manager_->SignalRequestSignaling.connect(
++      this, &CallClient::OnRequestSignaling);
++  session_manager_->OnSignalingReady();
++
++  phone_client_ = new cricket::PhoneSessionClient(
++      xmpp_client_->jid(),session_manager_);
++  phone_client_->SignalCallCreate.connect(this, &CallClient::OnCallCreate);
++  phone_client_->SignalSendStanza.connect(this, &CallClient::OnSendStanza);
++
++  receiver_ = new cricket::Receiver(xmpp_client_, phone_client_);
++  receiver_->Start();
++
++  worker_thread_->Start();
++}
++
++void CallClient::OnRequestSignaling() {
++  session_manager_->OnSignalingReady();
++}
++
++void CallClient::OnCallCreate(cricket::Call* call) {
++  call->SignalSessionState.connect(this, &CallClient::OnSessionState);
++}
++
++void CallClient::OnSessionState(cricket::Call* call,
++                                cricket::Session* session,
++                                cricket::Session::State state) {
++  if (state == cricket::Session::STATE_RECEIVEDINITIATE) {
++    buzz::Jid jid(session->remote_address());
++    Console()->Printf("Incoming call from '%s'", jid.Str().c_str());
++    Console()->Push(new ReceiveTask(this, jid, call));
++  }
++}
++
++void CallClient::OnSendStanza(cricket::SessionClient *client, const buzz::XmlElement* stanza) {
++  cricket::SessionSendTask* sender =
++      new cricket::SessionSendTask(xmpp_client_, phone_client_);
++  sender->Send(stanza);
++  sender->Start();
++}
++
++void CallClient::InitPresence() {
++  presence_push_ = new buzz::PresencePushTask(xmpp_client_);
++  presence_push_->SignalStatusUpdate.connect(
++    this, &CallClient::OnStatusUpdate);
++  presence_push_->Start();
++
++  buzz::Status my_status;
++  my_status.set_jid(xmpp_client_->jid());
++  my_status.set_available(true);
++  my_status.set_invisible(false);
++  my_status.set_show(buzz::Status::SHOW_ONLINE);
++  my_status.set_priority(0);
++  my_status.set_know_capabilities(true);
++  my_status.set_phone_capability(true);
++  my_status.set_is_google_client(true);
++  my_status.set_version("1.0.0.66");
++
++  buzz::PresenceOutTask* presence_out_ =
++      new buzz::PresenceOutTask(xmpp_client_);
++  presence_out_->Send(my_status);
++  presence_out_->Start();
++}
++
++void CallClient::OnStatusUpdate(const buzz::Status& status) {
++  RosterItem item;
++  item.jid = status.jid();
++  item.show = status.show();
++  item.status = status.status();
++
++  std::string key = item.jid.Str();
++
++  if (status.available() && status.phone_capability()) {
++    Console()->Printf("Adding to roster: %s", key.c_str());
++    (*roster_)[key] = item;
++  } else {
++    Console()->Printf("Removing from roster: %s", key.c_str());
++    RosterMap::iterator iter = roster_->find(key);
++    if (iter != roster_->end())
++      roster_->erase(iter);
++  }
++}
++
++void CallClient::PrintRoster() {
++  Console()->Printf("Roster contains %d callable", roster_->size());
++  RosterMap::iterator iter = roster_->begin();
++  while (iter != roster_->end()) {
++    Console()->Printf("%s - %s",
++                      iter->second.jid.BareJid().Str().c_str(),
++                      DescribeStatus(iter->second.show, iter->second.status));
++    iter++;
++  }
++}
++
++void CallClient::MakeCallTo(const std::string& name) {
++  bool found = false;
++  buzz::Jid found_jid;
++
++  RosterMap::iterator iter = roster_->begin();
++  while (iter != roster_->end()) {
++    if (iter->second.jid.node() == name) {
++      found = true;
++      found_jid = iter->second.jid;
++      break;
++    }
++    ++iter;
++  }
++
++  if (found) {
++    Console()->Printf("Found online friend '%s'", found_jid.Str().c_str());
++    Console()->Push(new CallTask(this, found_jid, NULL));
++  } else {
++    Console()->Printf("Could not find online friend '%s'", name.c_str());
++  } 
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h	(revision 586398)
+@@ -0,0 +1,231 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmlelement_h_
++#define _xmlelement_h_
++
++#include <iosfwd>
++#include <string>
++#include "talk/base/scoped_ptr.h"
++#include "talk/xmllite/qname.h"
++
++namespace buzz {
++
++extern const QName QN_EMPTY;
++extern const QName QN_XMLNS;
++
++
++class XmlChild;
++class XmlText;
++class XmlElement;
++class XmlAttr;
++
++class XmlChild {
++friend class XmlElement;
++
++public:
++
++  XmlChild * NextChild() { return pNextChild_; }
++  const XmlChild * NextChild() const { return pNextChild_; }
++
++  bool IsText() const { return IsTextImpl(); }
++
++  XmlElement * AsElement() { return AsElementImpl(); }
++  const XmlElement * AsElement() const { return AsElementImpl(); }
++
++  XmlText * AsText() { return AsTextImpl(); }
++  const XmlText * AsText() const { return AsTextImpl(); }
++
++
++protected:
++
++  XmlChild() :
++    pNextChild_(NULL) {
++  }
++
++  virtual bool IsTextImpl() const = 0;
++  virtual XmlElement * AsElementImpl() const = 0;
++  virtual XmlText * AsTextImpl() const = 0;
++
++
++  virtual ~XmlChild();
++
++private:
++  XmlChild(const XmlChild & noimpl);
++
++  XmlChild * pNextChild_;
++
++};
++
++class XmlText : public XmlChild {
++public:
++  explicit XmlText(const std::string & text) :
++    XmlChild(),
++    text_(text) {
++  }
++  explicit XmlText(const XmlText & t) :
++    XmlChild(),
++    text_(t.text_) {
++  }
++  explicit XmlText(const char * cstr, size_t len) :
++    XmlChild(),
++    text_(cstr, len) {
++  }
++  virtual ~XmlText();
++
++  const std::string & Text() const { return text_; }
++  void SetText(const std::string & text);
++  void AddParsedText(const char * buf, int len);
++  void AddText(const std::string & text);
++
++protected:
++  virtual bool IsTextImpl() const;
++  virtual XmlElement * AsElementImpl() const;
++  virtual XmlText * AsTextImpl() const;
++
++private:
++  std::string text_;
++};
++
++class XmlAttr {
++friend class XmlElement;
++
++public:
++  XmlAttr * NextAttr() const { return pNextAttr_; }
++  const QName & Name() const { return name_; }
++  const std::string & Value() const { return value_; }
++
++private:
++  explicit XmlAttr(const QName & name, const std::string & value) :
++    pNextAttr_(NULL),
++    name_(name),
++    value_(value) {
++  }
++  explicit XmlAttr(const XmlAttr & att) :
++    pNextAttr_(NULL),
++    name_(att.name_),
++    value_(att.value_) {
++  }
++
++  XmlAttr * pNextAttr_;
++  QName name_;
++  std::string value_;
++};
++
++class XmlElement : public XmlChild {
++public:
++  explicit XmlElement(const QName & name);
++  explicit XmlElement(const QName & name, bool useDefaultNs);
++  explicit XmlElement(const XmlElement & elt);
++
++  virtual ~XmlElement();
++
++  const QName & Name() const { return name_; }
++
++  const std::string & BodyText() const;
++  void SetBodyText(const std::string & text);
++
++  const QName & FirstElementName() const;
++
++  XmlAttr * FirstAttr();
++  const XmlAttr * FirstAttr() const
++    { return const_cast<XmlElement *>(this)->FirstAttr(); }
++
++  //! Attr will return STR_EMPTY if the attribute isn't there:
++  //! use HasAttr to test presence of an attribute. 
++  const std::string & Attr(const QName & name) const;
++  bool HasAttr(const QName & name) const;
++  void SetAttr(const QName & name, const std::string & value);
++  void ClearAttr(const QName & name);
++
++  XmlChild * FirstChild();
++  const XmlChild * FirstChild() const
++    { return const_cast<XmlElement *>(this)->FirstChild(); }
++
++  XmlElement * FirstElement();
++  const XmlElement * FirstElement() const
++    { return const_cast<XmlElement *>(this)->FirstElement(); }
++
++  XmlElement * NextElement();
++  const XmlElement * NextElement() const
++    { return const_cast<XmlElement *>(this)->NextElement(); }
++
++  XmlElement * FirstWithNamespace(const std::string & ns);
++  const XmlElement * FirstWithNamespace(const std::string & ns) const
++    { return const_cast<XmlElement *>(this)->FirstWithNamespace(ns); }
++    
++  XmlElement * NextWithNamespace(const std::string & ns);
++  const XmlElement * NextWithNamespace(const std::string & ns) const
++    { return const_cast<XmlElement *>(this)->NextWithNamespace(ns); }
++
++  XmlElement * FirstNamed(const QName & name);
++  const XmlElement * FirstNamed(const QName & name) const
++    { return const_cast<XmlElement *>(this)->FirstNamed(name); }
++
++  XmlElement * NextNamed(const QName & name);
++  const XmlElement * NextNamed(const QName & name) const
++    { return const_cast<XmlElement *>(this)->NextNamed(name); }
++
++  const std::string & TextNamed(const QName & name) const;
++
++  void InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNewChild);
++  void RemoveChildAfter(XmlChild * pPredecessor);
++
++  void AddParsedText(const char * buf, int len);
++  void AddText(const std::string & text);
++  void AddText(const std::string & text, int depth);
++  void AddElement(XmlElement * pelChild);
++  void AddElement(XmlElement * pelChild, int depth);
++  void AddAttr(const QName & name, const std::string & value);
++  void AddAttr(const QName & name, const std::string & value, int depth);
++  void ClearNamedChildren(const QName & name);
++  void ClearChildren();
++
++  static XmlElement * ForStr(const std::string & str);
++  std::string Str() const;
++
++  void Print(std::ostream * pout, std::string xmlns[], int xmlnsCount) const;
++
++protected:
++  virtual bool IsTextImpl() const;
++  virtual XmlElement * AsElementImpl() const;
++  virtual XmlText * AsTextImpl() const;
++
++private:
++  QName name_;
++  XmlAttr * pFirstAttr_;
++  XmlAttr * pLastAttr_;
++  XmlChild * pFirstChild_;
++  XmlChild * pLastChild_;
++
++};
++
++
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc	(revision 586398)
+@@ -0,0 +1,65 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "xmlconstants.h"
++
++using namespace buzz;
++
++const std::string & XmlConstants::str_empty() {
++  static const std::string str_empty_;
++  return str_empty_;
++}
++
++const std::string & XmlConstants::ns_xml() {
++  static const std::string ns_xml_("http://www.w3.org/XML/1998/namespace");
++  return ns_xml_;
++}
++
++const std::string & XmlConstants::ns_xmlns() {
++  static const std::string ns_xmlns_("http://www.w3.org/2000/xmlns/");
++  return ns_xmlns_;
++}
++
++const std::string & XmlConstants::str_xmlns() {
++  static const std::string str_xmlns_("xmlns");
++  return str_xmlns_;
++}
++
++const std::string & XmlConstants::str_xml() {
++  static const std::string str_xml_("xml");
++  return str_xml_;
++}
++
++const std::string & XmlConstants::str_version() {
++  static const std::string str_version_("version");
++  return str_version_;
++}
++
++const std::string & XmlConstants::str_encoding() {
++  static const std::string str_encoding_("encoding");
++  return str_encoding_;
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc	(revision 586398)
+@@ -0,0 +1,250 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/stl_decl.h"
++#include <string>
++#include <vector>
++#include <iostream>
++#include <expat.h>
++#include "talk/xmllite/xmlelement.h"
++#include "talk/base/common.h"
++#include "talk/xmllite/xmlparser.h"
++#include "talk/xmllite/xmlnsstack.h"
++#include "talk/xmllite/xmlconstants.h"
++
++#include <expat.h>
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++
++static void
++StartElementCallback(void * userData, const char *name, const char **atts) {
++  (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
++}
++
++static void
++EndElementCallback(void * userData, const char *name) {
++  (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
++}
++
++static void
++CharacterDataCallback(void * userData, const char *text, int len) {
++  (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
++}
++
++static void
++XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
++  (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
++}
++
++XmlParser::XmlParser(XmlParseHandler *pxph) :
++    context_(this), pxph_(pxph), sentError_(false) {
++  expat_ = XML_ParserCreate(NULL);
++  XML_SetUserData(expat_, this);
++  XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
++  XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
++  XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
++}
++
++void
++XmlParser::Reset() {
++  if (!XML_ParserReset(expat_, NULL)) {
++    XML_ParserFree(expat_);
++    expat_ = XML_ParserCreate(NULL);
++  }
++  XML_SetUserData(expat_, this);
++  XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
++  XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
++  XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
++  context_.Reset();
++  sentError_ = false;
++}
++
++static bool
++XmlParser_StartsWithXmlns(const char *name) {
++  return name[0] == 'x' &&
++         name[1] == 'm' &&
++         name[2] == 'l' &&
++         name[3] == 'n' &&
++         name[4] == 's';
++}
++
++void
++XmlParser::ExpatStartElement(const char *name, const char **atts) {
++  if (context_.RaisedError() != XML_ERROR_NONE)
++    return;
++  const char **att;
++  context_.StartElement();
++  for (att = atts; *att; att += 2) {
++    if (XmlParser_StartsWithXmlns(*att)) {
++      if ((*att)[5] == '\0') {
++        context_.StartNamespace("", *(att + 1));
++      }
++      else if ((*att)[5] == ':') {
++        if (**(att + 1) == '\0') {
++          // In XML 1.0 empty namespace illegal with prefix (not in 1.1)
++          context_.RaiseError(XML_ERROR_SYNTAX);
++          return;
++        }
++        context_.StartNamespace((*att) + 6, *(att + 1));
++      }
++    }
++  }
++  pxph_->StartElement(&context_, name, atts);
++}
++
++void
++XmlParser::ExpatEndElement(const char *name) {
++  if (context_.RaisedError() != XML_ERROR_NONE)
++    return;
++  context_.EndElement();
++  pxph_->EndElement(&context_, name);
++}
++
++void
++XmlParser::ExpatCharacterData(const char *text, int len) {
++  if (context_.RaisedError() != XML_ERROR_NONE)
++    return;
++  pxph_->CharacterData(&context_, text, len);
++}
++
++void
++XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
++  if (context_.RaisedError() != XML_ERROR_NONE)
++    return;
++
++  if (ver && std::string("1.0") != ver) {
++    context_.RaiseError(XML_ERROR_SYNTAX);
++    return;
++  }
++
++  if (standalone == 0) {
++    context_.RaiseError(XML_ERROR_SYNTAX);
++    return;
++  }
++
++  if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
++               (enc[1] == 'T' || enc[1] == 't') &&
++               (enc[2] == 'F' || enc[2] == 'f') &&
++                enc[3] == '-' && enc[4] =='8')) {
++    context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
++    return;
++  }
++
++}
++
++bool
++XmlParser::Parse(const char *data, size_t len, bool isFinal) {
++  if (sentError_)
++    return false;
++
++  if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) != XML_STATUS_OK)
++    context_.RaiseError(XML_GetErrorCode(expat_));
++
++  if (context_.RaisedError() != XML_ERROR_NONE) {
++    sentError_ = true;
++    pxph_->Error(&context_, context_.RaisedError());
++    return false;
++  }
++
++  return true;
++}
++
++XmlParser::~XmlParser() {
++  XML_ParserFree(expat_);
++}
++
++void
++XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
++  XmlParser parser(pxph);
++  parser.Parse(text.c_str(), text.length(), true);
++}
++
++XmlParser::ParseContext::ParseContext(XmlParser *parser) :
++    parser_(parser),
++    xmlnsstack_(),
++    raised_(XML_ERROR_NONE) {
++}
++
++void
++XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
++  xmlnsstack_.AddXmlns(
++    *prefix ? std::string(prefix) : STR_EMPTY,
++//    ns == NS_CLIENT ? NS_CLIENT :
++//    ns == NS_ROSTER ? NS_ROSTER :
++//    ns == NS_GR ? NS_GR :
++    std::string(ns));
++}
++
++void
++XmlParser::ParseContext::StartElement() {
++  xmlnsstack_.PushFrame();
++}
++
++void
++XmlParser::ParseContext::EndElement() {
++  xmlnsstack_.PopFrame();
++}
++
++QName
++XmlParser::ParseContext::ResolveQName(const char *qname, bool isAttr) {
++  const char *c;
++  for (c = qname; *c; ++c) {
++    if (*c == ':') {
++      const std::string * result;
++      result = xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
++      if (result == NULL)
++        return QN_EMPTY;
++      const char * localname = c + 1;
++      return QName(*result, localname); 
++    }
++  }
++  if (isAttr) {
++    return QName(STR_EMPTY, qname);
++  }
++  
++  const std::string * result;
++  result = xmlnsstack_.NsForPrefix(STR_EMPTY);
++  if (result == NULL)
++    return QN_EMPTY;
++
++  return QName(*result, qname);
++}
++
++void
++XmlParser::ParseContext::Reset() {
++  xmlnsstack_.Reset();
++  raised_ = XML_ERROR_NONE;
++}
++
++XmlParser::ParseContext::~ParseContext() {
++}
++
++}
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h	(revision 586398)
+@@ -0,0 +1,61 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++// Because global constant initialization order is undefined
++// globals cannot depend on other objects to be instantiated.
++// This class creates string objects within static methods 
++// such that globals may refer to these constants by the
++// accessor function and they are guaranteed to be initialized.
++
++#ifndef TALK_XMLLITE_CONSTANTS_H_
++#define TALK_XMLLITE_CONSTANTS_H_
++
++#include <string>
++
++#define STR_EMPTY    XmlConstants::str_empty()
++#define NS_XML       XmlConstants::ns_xml()
++#define NS_XMLNS     XmlConstants::ns_xmlns()
++#define STR_XMLNS    XmlConstants::str_xmlns()
++#define STR_XML      XmlConstants::str_xml()
++#define STR_VERSION  XmlConstants::str_version()
++#define STR_ENCODING XmlConstants::str_encoding()
++namespace buzz {
++	
++class XmlConstants {
++ public:
++  static const std::string & str_empty();
++  static const std::string & ns_xml();
++  static const std::string & ns_xmlns();
++  static const std::string & str_xmlns();
++  static const std::string & str_xml();
++  static const std::string & str_version();
++  static const std::string & str_encoding();
++};
++
++}
++
++#endif  // TALK_XMLLITE_CONSTANTS_H_
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h	(revision 586398)
+@@ -0,0 +1,108 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmlparser_h_
++#define _xmlparser_h_
++
++#include <string>
++#include "talk/xmllite/xmlnsstack.h"
++#include <expat.h>
++
++struct XML_ParserStruct;
++typedef struct XML_ParserStruct * XML_Parser;
++
++namespace buzz {
++
++class XmlParseHandler;
++class XmlParseContext;
++class XmlParser;
++
++class XmlParseContext {
++public:
++  virtual QName ResolveQName(const char * qname, bool isAttr) = 0;
++  virtual void RaiseError(XML_Error err) = 0;
++};
++
++class XmlParseHandler {
++public:
++  virtual void StartElement(XmlParseContext * pctx,
++               const char * name, const char ** atts) = 0;
++  virtual void EndElement(XmlParseContext * pctx,
++               const char * name) = 0;
++  virtual void CharacterData(XmlParseContext * pctx,
++               const char * text, int len) = 0;
++  virtual void Error(XmlParseContext * pctx,
++               XML_Error errorCode) = 0;
++};
++
++class XmlParser {
++public:
++  static void ParseXml(XmlParseHandler * pxph, std::string text);
++
++  explicit XmlParser(XmlParseHandler * pxph);
++  bool Parse(const char * data, size_t len, bool isFinal);
++  void Reset();
++  virtual ~XmlParser();
++
++  // expat callbacks
++  void ExpatStartElement(const char * name, const char ** atts);
++  void ExpatEndElement(const char * name);
++  void ExpatCharacterData(const char * text, int len);
++  void ExpatXmlDecl(const char * ver, const char * enc, int standalone);
++
++private:
++
++  class ParseContext : public XmlParseContext {
++  public:
++    ParseContext(XmlParser * parser);
++    virtual ~ParseContext();
++    virtual QName ResolveQName(const char * qname, bool isAttr);
++    virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
++    XML_Error RaisedError() { return raised_; }
++    void Reset();
++
++    void StartElement();
++    void EndElement();
++    void StartNamespace(const char * prefix, const char * ns);
++
++  private:
++    const XmlParser * parser_;
++    XmlnsStack xmlnsstack_;
++    XML_Error raised_;
++  };
++
++  ParseContext context_;
++  XML_Parser expat_;
++  XmlParseHandler * pxph_;
++  bool sentError_;
++
++
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc	(revision 586398)
+@@ -0,0 +1,167 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <string>
++#include "talk/base/common.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/qname.h"
++#include "talk/xmllite/xmlconstants.h"
++
++//#define new TRACK_NEW
++
++namespace buzz {
++
++static int QName_Hash(const std::string & ns, const char * local) {
++  int result = ns.size() * 101;
++  while (*local) {
++    result *= 19;
++    result += *local;
++    local += 1;
++  }
++  return result;
++}
++
++static const int bits = 9;
++static QName::Data * get_qname_table() {
++  static QName::Data qname_table[1 << bits];
++  return qname_table;
++}
++
++static QName::Data *
++AllocateOrFind(const std::string & ns, const char * local) {
++  int index = QName_Hash(ns, local);
++  int increment = index >> (bits - 1) | 1;
++  QName::Data * qname_table = get_qname_table();
++  for (;;) {
++    index &= ((1 << bits) - 1);
++    if (!qname_table[index].Occupied()) {
++      return new QName::Data(ns, local);
++    }
++    if (qname_table[index].localPart_ == local &&
++        qname_table[index].namespace_ == ns) {
++      qname_table[index].AddRef();
++      return qname_table + index;
++    }
++    index += increment;
++  }
++}
++
++static QName::Data *
++Add(const std::string & ns, const char * local) {
++  int index = QName_Hash(ns, local);
++  int increment = index >> (bits - 1) | 1;
++  QName::Data * qname_table = get_qname_table();
++  for (;;) {
++    index &= ((1 << bits) - 1);
++    if (!qname_table[index].Occupied()) {
++      qname_table[index].namespace_ = ns;
++      qname_table[index].localPart_ = local;
++      qname_table[index].AddRef(); // AddRef twice so it's never deleted
++      qname_table[index].AddRef();
++      return qname_table + index;
++    }
++    if (qname_table[index].localPart_ == local &&
++        qname_table[index].namespace_ == ns) {
++      qname_table[index].AddRef();
++      return qname_table + index;
++    }
++    index += increment;
++  }
++}
++
++QName::~QName() {
++  data_->Release();
++}
++
++QName::QName() : data_(QN_EMPTY.data_) {
++  data_->AddRef();
++}
++
++QName::QName(bool add, const std::string & ns, const char * local) :
++  data_(add ? Add(ns, local) : AllocateOrFind(ns, local)) {}
++  
++QName::QName(bool add, const std::string & ns, const std::string & local) :
++  data_(add ? Add(ns, local.c_str()) : AllocateOrFind(ns, local.c_str())) {}
++  
++QName::QName(const std::string & ns, const char * local) :
++  data_(AllocateOrFind(ns, local)) {}
++
++static std::string
++QName_LocalPart(const std::string & name) {
++  size_t i = name.rfind(':');
++  if (i == std::string::npos)
++    return name;
++  return name.substr(i + 1);
++}
++
++static std::string
++QName_Namespace(const std::string & name) {
++  size_t i = name.rfind(':');
++  if (i == std::string::npos)
++    return STR_EMPTY;
++  return name.substr(0, i);
++}
++
++QName::QName(const std::string & mergedOrLocal) :
++  data_(AllocateOrFind(QName_Namespace(mergedOrLocal),
++                 QName_LocalPart(mergedOrLocal).c_str())) {}
++
++std::string
++QName::Merged() const {
++  if (data_->namespace_ == STR_EMPTY)
++    return data_->localPart_;
++
++  std::string result(data_->namespace_);
++  result.reserve(result.length() + 1 + data_->localPart_.length());
++  result += ':';
++  result += data_->localPart_;
++  return result;
++}
++
++bool
++QName::operator==(const QName & other) const {
++  return other.data_ == data_ ||
++    data_->localPart_ == other.data_->localPart_ &&
++    data_->namespace_ == other.data_->namespace_;
++}
++
++int
++QName::Compare(const QName & other) const {
++  if (data_ == other.data_)
++    return 0;
++  
++  int result = data_->localPart_.compare(other.data_->localPart_);
++  if (result)
++    return result;
++
++  return data_->namespace_.compare(other.data_->namespace_);
++}
++
++}
++
++
++
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h	(revision 586398)
+@@ -0,0 +1,87 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _qname_h_
++#define _qname_h_
++
++#include <string>
++
++namespace buzz {
++
++
++class QName
++{
++public:
++  explicit QName();
++  QName(const QName & qname) : data_(qname.data_) { data_->AddRef(); }
++  explicit QName(bool add, const std::string & ns, const char * local);
++  explicit QName(bool add, const std::string & ns, const std::string & local);
++  explicit QName(const std::string & ns, const char * local);
++  explicit QName(const std::string & mergedOrLocal);
++  QName & operator=(const QName & qn) {
++    qn.data_->AddRef();
++    data_->Release();
++    data_ = qn.data_;
++    return *this;
++  }
++  ~QName();
++  
++  const std::string & Namespace() const { return data_->namespace_; }
++  const std::string & LocalPart() const { return data_->localPart_; }
++  std::string Merged() const;
++  int Compare(const QName & other) const;
++  bool operator==(const QName & other) const;
++  bool operator!=(const QName & other) const { return !operator==(other); }
++  bool operator<(const QName & other) const { return Compare(other) < 0; }
++  
++  class Data {
++  public:
++    Data(const std::string & ns, const std::string & local) :
++      refcount_(1),
++      namespace_(ns),
++      localPart_(local) {}
++
++    Data() : refcount_(0) {}
++      
++    std::string namespace_;
++    std::string localPart_;
++    void AddRef() { refcount_++; }
++    void Release() { if (!--refcount_) { delete this; } }
++    bool Occupied() { return !!refcount_; }
++
++  private:
++    int refcount_;
++  };
++
++private:
++  Data * data_;
++};
++
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc	(revision 586398)
+@@ -0,0 +1,190 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/stl_decl.h"
++#include <string>
++#include <iostream>
++#include <vector>
++#include <sstream>
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/xmllite/xmlnsstack.h"
++#include "talk/xmllite/xmlconstants.h"
++
++namespace buzz {
++
++class XmlPrinterImpl {
++public:
++  XmlPrinterImpl(std::ostream * pout,
++    const std::string * const xmlns, int xmlnsCount);
++  void PrintElement(const XmlElement * element);
++  void PrintQuotedValue(const std::string & text);
++  void PrintBodyText(const std::string & text);
++
++private:
++  std::ostream *pout_;
++  XmlnsStack xmlnsStack_;
++};
++
++void
++XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element) {
++  PrintXml(pout, element, NULL, 0);
++}
++
++void
++XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element,
++    const std::string * const xmlns, int xmlnsCount) {
++  XmlPrinterImpl printer(pout, xmlns, xmlnsCount);
++  printer.PrintElement(element);
++}
++
++XmlPrinterImpl::XmlPrinterImpl(std::ostream * pout,
++    const std::string * const xmlns, int xmlnsCount) :
++  pout_(pout),
++  xmlnsStack_() {
++  int i;
++  for (i = 0; i < xmlnsCount; i += 2) {
++    xmlnsStack_.AddXmlns(xmlns[i], xmlns[i + 1]);
++  }
++}
++
++void
++XmlPrinterImpl::PrintElement(const XmlElement * element) {
++  xmlnsStack_.PushFrame();
++
++  // first go through attrs of pel to add xmlns definitions
++  const XmlAttr * pattr;
++  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
++    if (pattr->Name() == QN_XMLNS)
++      xmlnsStack_.AddXmlns(STR_EMPTY, pattr->Value());
++    else if (pattr->Name().Namespace() == NS_XMLNS)
++      xmlnsStack_.AddXmlns(pattr->Name().LocalPart(),
++        pattr->Value());
++  }
++
++  // then go through qnames to make sure needed xmlns definitons are added
++  std::vector<std::string> newXmlns;
++  std::pair<std::string, bool> prefix;
++  prefix = xmlnsStack_.AddNewPrefix(element->Name().Namespace(), false);
++  if (prefix.second) {
++    newXmlns.push_back(prefix.first);
++    newXmlns.push_back(element->Name().Namespace());
++  }
++
++  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
++    prefix = xmlnsStack_.AddNewPrefix(pattr->Name().Namespace(), true);
++    if (prefix.second) {
++      newXmlns.push_back(prefix.first);
++      newXmlns.push_back(element->Name().Namespace());
++    }
++  }
++
++  // print the element name
++  *pout_ << '<' << xmlnsStack_.FormatQName(element->Name(), false);
++
++  // and the attributes
++  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
++    *pout_ << ' ' << xmlnsStack_.FormatQName(pattr->Name(), true) << "=\"";
++    PrintQuotedValue(pattr->Value());
++    *pout_ << '"';
++  }
++
++  // and the extra xmlns declarations
++  std::vector<std::string>::iterator i(newXmlns.begin());
++  while (i < newXmlns.end()) {
++    if (*i == STR_EMPTY)
++      *pout_ << " xmlns=\"" << *(i + 1) << '"';
++    else
++      *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
++    i += 2;
++  }
++
++  // now the children
++  const XmlChild * pchild = element->FirstChild();
++
++  if (pchild == NULL)
++    *pout_ << "/>";
++  else {
++    *pout_ << '>';
++    while (pchild) {
++      if (pchild->IsText())
++        PrintBodyText(pchild->AsText()->Text());
++      else
++        PrintElement(pchild->AsElement());
++      pchild = pchild->NextChild();
++    }
++    *pout_ << "</" << xmlnsStack_.FormatQName(element->Name(), false) << '>';
++  }
++
++  xmlnsStack_.PopFrame();
++}
++
++void
++XmlPrinterImpl::PrintQuotedValue(const std::string & text) {
++  size_t safe = 0;
++  for (;;) {
++    size_t unsafe = text.find_first_of("<>&\"", safe);
++    if (unsafe == std::string::npos)
++      unsafe = text.length();
++    *pout_ << text.substr(safe, unsafe - safe);
++    if (unsafe == text.length())
++      return;
++    switch (text[unsafe]) {
++      case '<': *pout_ << "&lt;"; break;
++      case '>': *pout_ << "&gt;"; break;
++      case '&': *pout_ << "&amp;"; break;
++      case '"': *pout_ << "&quot;"; break;
++    }
++    safe = unsafe + 1;
++    if (safe == text.length())
++      return;
++  }
++}
++
++void
++XmlPrinterImpl::PrintBodyText(const std::string & text) {
++  size_t safe = 0;
++  for (;;) {
++    size_t unsafe = text.find_first_of("<>&", safe);
++    if (unsafe == std::string::npos)
++      unsafe = text.length();
++    *pout_ << text.substr(safe, unsafe - safe);
++    if (unsafe == text.length())
++      return;
++    switch (text[unsafe]) {
++      case '<': *pout_ << "&lt;"; break;
++      case '>': *pout_ << "&gt;"; break;
++      case '&': *pout_ << "&amp;"; break;
++    }
++    safe = unsafe + 1;
++    if (safe == text.length())
++      return;
++  }
++}
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am	(revision 586398)
+@@ -0,0 +1,18 @@
++libcricketxmllite_la_SOURCES = qname.cc \
++			       xmlbuilder.cc \
++			       xmlconstants.cc \
++ 			       xmlelement.cc \
++			       xmlnsstack.cc \
++			       xmlparser.cc \
++			       xmlprinter.cc
++
++noinst_HEADERS =               qname.h \
++			       xmlbuilder.h \
++			       xmlconstants.h \
++			       xmlelement.h \
++			       xmlnsstack.h \
++			       xmlparser.h \
++			       xmlprinter.h
++AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../..
++
++noinst_LTLIBRARIES = libcricketxmllite.la
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h	(revision 586398)
+@@ -0,0 +1,49 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmlprinter_h_
++#define _xmlprinter_h_
++
++#include <iosfwd>
++#include <string>
++#include "talk/base/scoped_ptr.h"
++
++namespace buzz {
++
++class XmlElement;
++
++class XmlPrinter {
++public:
++  static void PrintXml(std::ostream * pout, const XmlElement * pelt);
++
++  static void PrintXml(std::ostream * pout, const XmlElement * pelt,
++    const std::string * const xmlns, int xmlnsCount);
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc	(revision 586398)
+@@ -0,0 +1,151 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/stl_decl.h"
++#include <vector>
++#include <set>
++#include <expat.h>
++#include "talk/base/common.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlbuilder.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++XmlBuilder::XmlBuilder() :
++  pelCurrent_(NULL),
++  pelRoot_(NULL),
++  pvParents_(new std::vector<XmlElement *>()) {
++}
++
++void
++XmlBuilder::Reset() {
++  pelRoot_.reset();
++  pelCurrent_ = NULL;
++  pvParents_->clear();
++}
++
++XmlElement *
++XmlBuilder::BuildElement(XmlParseContext * pctx,
++                              const char * name, const char ** atts) {
++  QName tagName(pctx->ResolveQName(name, false));
++  if (tagName == QN_EMPTY)
++    return NULL;
++
++  XmlElement * pelNew = new XmlElement(tagName);
++
++  if (!*atts)
++    return pelNew;
++
++  std::set<QName> seenNonlocalAtts;
++
++  while (*atts) {
++    QName attName(pctx->ResolveQName(*atts, true));
++    if (attName == QN_EMPTY) {
++      delete pelNew;
++      return NULL;
++    }
++
++    // verify that namespaced names are unique
++    if (!attName.Namespace().empty()) {
++      if (seenNonlocalAtts.count(attName)) {
++        delete pelNew;
++        return NULL;
++      }
++      seenNonlocalAtts.insert(attName);
++    }
++
++    pelNew->AddAttr(attName, std::string(*(atts + 1)));
++    atts += 2;
++  }
++
++  return pelNew;
++}
++
++void
++XmlBuilder::StartElement(XmlParseContext * pctx,
++                              const char * name, const char ** atts) {
++  XmlElement * pelNew = BuildElement(pctx, name, atts);
++  if (pelNew == NULL) {
++    pctx->RaiseError(XML_ERROR_SYNTAX);
++    return;
++  }
++
++  if (!pelCurrent_) {
++    pelCurrent_ = pelNew;
++    pelRoot_.reset(pelNew);
++    pvParents_->push_back(NULL);
++  } else {
++    pelCurrent_->AddElement(pelNew);
++    pvParents_->push_back(pelCurrent_);
++    pelCurrent_ = pelNew;
++  }
++}
++
++void
++XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
++  UNUSED(pctx);
++  UNUSED(name);
++  pelCurrent_ = pvParents_->back();
++  pvParents_->pop_back();
++}
++
++void
++XmlBuilder::CharacterData(XmlParseContext * pctx,
++                               const char * text, int len) {
++  UNUSED(pctx);
++  if (pelCurrent_) {
++    pelCurrent_->AddParsedText(text, len);
++  }
++}
++
++void
++XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
++  UNUSED(pctx);
++  UNUSED(err);
++  pelRoot_.reset(NULL);
++  pelCurrent_ = NULL;
++  pvParents_->clear();
++}
++
++XmlElement *
++XmlBuilder::CreateElement() {
++  return pelRoot_.release();
++}
++
++XmlElement *
++XmlBuilder::BuiltElement() {
++  return pelRoot_.get();
++}
++
++XmlBuilder::~XmlBuilder() {
++}
++
++
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc	(revision 586398)
+@@ -0,0 +1,205 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/stl_decl.h"
++#include <string>
++#include <iostream>
++#include <vector>
++#include <sstream>
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlnsstack.h"
++#include "talk/xmllite/xmlconstants.h"
++
++namespace buzz {
++
++XmlnsStack::XmlnsStack() :
++  pxmlnsStack_(new std::vector<std::string>),
++  pxmlnsDepthStack_(new std::vector<size_t>) {
++}
++
++XmlnsStack::~XmlnsStack() {}
++
++void
++XmlnsStack::PushFrame() {
++  pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
++}
++
++void
++XmlnsStack::PopFrame() {
++  size_t prev_size = pxmlnsDepthStack_->back();
++  pxmlnsDepthStack_->pop_back();
++  if (prev_size < pxmlnsStack_->size()) {
++    pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
++                        pxmlnsStack_->end());
++  }
++}
++const std::pair<std::string, bool> NS_NOT_FOUND(STR_EMPTY, false);
++const std::pair<std::string, bool> EMPTY_NS_FOUND(STR_EMPTY, true);
++const std::pair<std::string, bool> XMLNS_DEFINITION_FOUND(NS_XMLNS, true);
++
++const std::string *
++XmlnsStack::NsForPrefix(const std::string & prefix) {
++  if (prefix.length() >= 3 &&
++      (prefix[0] == 'x' || prefix[0] == 'X') &&
++      (prefix[1] == 'm' || prefix[1] == 'M') &&
++      (prefix[2] == 'l' || prefix[2] == 'L')) {
++    if (prefix == "xml")
++      return &(NS_XML);
++    if (prefix == "xmlns")
++      return &(NS_XMLNS);
++    return NULL;
++  }
++
++  std::vector<std::string>::iterator pos;
++  for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
++    pos -= 2;
++    if (*pos == prefix)
++      return &(*(pos + 1));
++  }
++
++  if (prefix == STR_EMPTY)
++    return &(STR_EMPTY); // default namespace
++
++  return NULL; // none found
++}
++
++bool
++XmlnsStack::PrefixMatchesNs(const std::string & prefix, const std::string & ns) {
++  const std::string * match = NsForPrefix(prefix);
++  if (match == NULL)
++    return false;
++  return (*match == ns);
++}
++
++std::pair<std::string, bool>
++XmlnsStack::PrefixForNs(const std::string & ns, bool isattr) {
++  if (ns == NS_XML)
++    return std::make_pair(std::string("xml"), true);
++  if (ns == NS_XMLNS)
++    return std::make_pair(std::string("xmlns"), true);
++  if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
++    return std::make_pair(STR_EMPTY, true);
++
++  std::vector<std::string>::iterator pos;
++  for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
++    pos -= 2;
++    if (*(pos + 1) == ns &&
++        (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
++      return std::make_pair(*pos, true);
++  }
++
++  return std::make_pair(STR_EMPTY, false); // none found
++}
++
++std::string
++XmlnsStack::FormatQName(const QName & name, bool isAttr) {
++  std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
++  if (prefix == STR_EMPTY)
++    return name.LocalPart();
++  else
++    return prefix + ':' + name.LocalPart();
++}
++
++void
++XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
++  pxmlnsStack_->push_back(prefix);
++  pxmlnsStack_->push_back(ns);
++}
++
++void
++XmlnsStack::RemoveXmlns() {
++  pxmlnsStack_->pop_back();
++  pxmlnsStack_->pop_back();
++}
++
++static bool IsAsciiLetter(char ch) {
++  return ((ch >= 'a' && ch <= 'z') ||
++          (ch >= 'A' && ch <= 'Z'));
++}
++
++static std::string AsciiLower(const std::string & s) {
++  std::string result(s);
++  size_t i;
++  for (i = 0; i < result.length(); i++) {
++    if (result[i] >= 'A' && result[i] <= 'Z')
++      result[i] += 'a' - 'A';
++  }
++  return result;
++}
++
++static std::string SuggestPrefix(const std::string & ns) {
++  size_t len = ns.length();
++  size_t i = ns.find_last_of('.');
++  if (i != std::string::npos && len - i <= 4 + 1)
++    len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
++  size_t last = len;
++  while (last > 0) {
++    last -= 1;
++    if (IsAsciiLetter(ns[last])) {
++      size_t first = last;
++      last += 1;
++      while (first > 0) {
++        if (!IsAsciiLetter(ns[first - 1]))
++          break;
++        first -= 1;
++      }
++      if (last - first > 4)
++        last = first + 3;
++      std::string candidate(AsciiLower(ns.substr(first, last - first)));
++      if (candidate.find("xml") != 0)
++        return candidate;
++      break;
++    }
++  }
++  return "ns";
++}
++
++
++std::pair<std::string, bool>
++XmlnsStack::AddNewPrefix(const std::string & ns, bool isAttr) {
++  if (PrefixForNs(ns, isAttr).second)
++    return std::make_pair(STR_EMPTY, false);
++
++  std::string base(SuggestPrefix(ns));
++  std::string result(base);
++  int i = 2;
++  while (NsForPrefix(result) != NULL) {
++    std::stringstream ss;
++    ss << base;
++    ss << (i++);
++    ss >> result;
++  }
++  AddXmlns(result, ns);
++  return std::make_pair(result, true);
++}
++
++void XmlnsStack::Reset() {
++  pxmlnsStack_->clear();
++  pxmlnsDepthStack_->clear();
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h	(revision 586398)
+@@ -0,0 +1,79 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmlbuilder_h_
++#define _xmlbuilder_h_
++
++#include <string>
++#include "talk/base/scoped_ptr.h"
++#include "talk/base/stl_decl.h"
++#include "talk/xmllite/xmlparser.h"
++
++#ifdef OSX
++#include "talk/third_party/expat/expat.h"
++#else
++#include <expat.h>
++#endif
++
++namespace buzz {
++
++class XmlElement;
++class XmlParseContext;
++
++
++class XmlBuilder : public XmlParseHandler {
++public:
++  XmlBuilder();
++
++  static XmlElement * BuildElement(XmlParseContext * pctx,
++                                  const char * name, const char ** atts);
++  virtual void StartElement(XmlParseContext * pctx,
++                            const char * name, const char ** atts);
++  virtual void EndElement(XmlParseContext * pctx, const char * name);
++  virtual void CharacterData(XmlParseContext * pctx,
++                             const char * text, int len);
++  virtual void Error(XmlParseContext * pctx, XML_Error);
++  virtual ~XmlBuilder();
++
++  void Reset();
++
++  // Take ownership of the built element; second call returns NULL
++  XmlElement * CreateElement();
++
++  // Peek at the built element without taking ownership
++  XmlElement * BuiltElement();
++
++private:
++  XmlElement * pelCurrent_;
++  scoped_ptr<XmlElement> pelRoot_;
++  scoped_ptr<std::vector<XmlElement *, std::allocator<XmlElement *> > >
++    pvParents_;
++};
++
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h	(revision 586398)
+@@ -0,0 +1,62 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _xmlnsstack_h_
++#define _xmlnsstack_h_
++
++#include <string>
++#include "talk/base/scoped_ptr.h"
++#include "talk/base/stl_decl.h"
++#include "talk/xmllite/qname.h"
++
++namespace buzz {
++
++class XmlnsStack {
++public:
++  XmlnsStack();
++  ~XmlnsStack();
++
++  void AddXmlns(const std::string & prefix, const std::string & ns);
++  void RemoveXmlns();
++  void PushFrame();
++  void PopFrame();
++  void Reset();
++
++  const std::string * NsForPrefix(const std::string & prefix);
++  bool PrefixMatchesNs(const std::string & prefix, const std::string & ns);
++  std::pair<std::string, bool> PrefixForNs(const std::string & ns, bool isAttr);
++  std::pair<std::string, bool> AddNewPrefix(const std::string & ns, bool isAttr);
++  std::string FormatQName(const QName & name, bool isAttr);
++
++private:
++
++  scoped_ptr<std::vector<std::string, std::allocator<std::string> > > pxmlnsStack_;
++  scoped_ptr<std::vector<size_t, std::allocator<size_t> > > pxmlnsDepthStack_;
++};
++}
++
++#endif
+--- kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc	(revision 586398)
+@@ -0,0 +1,491 @@
++/*
++ * libjingle
++ * Copyright 2004--2005, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without 
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice, 
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products 
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <string>
++#include <iostream>
++#include <vector>
++#include <sstream>
++
++#include "talk/base/common.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/qname.h"
++#include "talk/xmllite/xmlparser.h"
++#include "talk/xmllite/xmlbuilder.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/xmllite/xmlconstants.h"
++
++#define new TRACK_NEW
++
++namespace buzz {
++
++const QName QN_EMPTY(true, STR_EMPTY, STR_EMPTY);
++const QName QN_XMLNS(true, STR_EMPTY, STR_XMLNS);
++
++
++XmlChild::~XmlChild() {
++}
++
++bool
++XmlText::IsTextImpl() const {
++  return true;
++}
++
++XmlElement *
++XmlText::AsElementImpl() const {
++  return NULL;
++}
++
++XmlText *
++XmlText::AsTextImpl() const {
++  return const_cast<XmlText *>(this);
++}
++
++void
++XmlText::SetText(const std::string & text) {
++  text_ = text;
++}
++
++void
++XmlText::AddParsedText(const char * buf, int len) {
++  text_.append(buf, len);
++}
++
++void
++XmlText::AddText(const std::string & text) {
++  text_ += text;
++}
++
++XmlText::~XmlText() {
++}
++
++XmlElement::XmlElement(const QName & name) :
++    name_(name),
++    pFirstAttr_(NULL),
++    pLastAttr_(NULL),
++    pFirstChild_(NULL),
++    pLastChild_(NULL) {
++}
++
++XmlElement::XmlElement(const XmlElement & elt) :
++    XmlChild(),
++    name_(elt.name_),
++    pFirstAttr_(NULL),
++    pLastAttr_(NULL),
++    pFirstChild_(NULL),
++    pLastChild_(NULL) {
++
++  // copy attributes
++  XmlAttr * pAttr;
++  XmlAttr ** ppLastAttr = &pFirstAttr_;
++  XmlAttr * newAttr = NULL;
++  for (pAttr = elt.pFirstAttr_; pAttr; pAttr = pAttr->NextAttr()) {
++    newAttr = new XmlAttr(*pAttr);
++    *ppLastAttr = newAttr;
++    ppLastAttr = &(newAttr->pNextAttr_);
++  }
++  pLastAttr_ = newAttr;
++
++  // copy children
++  XmlChild * pChild;
++  XmlChild ** ppLast = &pFirstChild_;
++  XmlChild * newChild = NULL;
++
++  for (pChild = elt.pFirstChild_; pChild; pChild = pChild->NextChild()) {
++    if (pChild->IsText()) {
++      newChild = new XmlText(*(pChild->AsText()));
++    } else {
++      newChild = new XmlElement(*(pChild->AsElement()));
++    }
++    *ppLast = newChild;
++    ppLast = &(newChild->pNextChild_);
++  }
++  pLastChild_ = newChild;
++
++}
++
++XmlElement::XmlElement(const QName & name, bool useDefaultNs) :
++  name_(name),
++  pFirstAttr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
++  pLastAttr_(pFirstAttr_),
++  pFirstChild_(NULL),
++  pLastChild_(NULL) {
++}
++
++bool
++XmlElement::IsTextImpl() const {
++  return false;
++}
++
++XmlElement *
++XmlElement::AsElementImpl() const {
++  return const_cast<XmlElement *>(this);
++}
++
++XmlText *
++XmlElement::AsTextImpl() const {
++  return NULL;
++}
++
++const std::string &
++XmlElement::BodyText() const {
++  if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
++    return pFirstChild_->AsText()->Text();
++  }
++
++  return STR_EMPTY;
++}
++
++void
++XmlElement::SetBodyText(const std::string & text) {
++  if (text == STR_EMPTY) {
++    ClearChildren();
++  } else if (pFirstChild_ == NULL) {
++    AddText(text);
++  } else if (pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
++    pFirstChild_->AsText()->SetText(text);
++  } else {
++    ClearChildren();
++    AddText(text);
++  }
++}
++
++const QName &
++XmlElement::FirstElementName() const {
++  const XmlElement * element = FirstElement();
++  if (element == NULL)
++    return QN_EMPTY;
++  return element->Name();
++}
++
++XmlAttr *
++XmlElement::FirstAttr() {
++  return pFirstAttr_;
++}
++
++const std::string &
++XmlElement::Attr(const QName & name) const {
++  XmlAttr * pattr;
++  for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
++    if (pattr->name_ == name)
++      return pattr->value_;
++  }
++  return STR_EMPTY;
++}
++
++bool
++XmlElement::HasAttr(const QName & name) const {
++  XmlAttr * pattr;
++  for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
++    if (pattr->name_ == name)
++      return true;
++  }
++  return false;
++}
++
++void
++XmlElement::SetAttr(const QName & name, const std::string & value) {
++  XmlAttr * pattr;
++  for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
++    if (pattr->name_ == name)
++      break;
++  }
++  if (!pattr) {
++    pattr = new XmlAttr(name, value);
++    if (pLastAttr_)
++      pLastAttr_->pNextAttr_ = pattr;
++    else
++      pFirstAttr_ = pattr;
++    pLastAttr_ = pattr;
++    return;
++  }
++  pattr->value_ = value;
++}
++
++void
++XmlElement::ClearAttr(const QName & name) {
++  XmlAttr * pattr;
++  XmlAttr *pLastAttr = NULL;
++  for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
++    if (pattr->name_ == name)
++      break;
++    pLastAttr = pattr;
++  }
++  if (!pattr)
++    return;
++  if (!pLastAttr)
++    pFirstAttr_ = pattr->pNextAttr_;
++  else
++    pLastAttr->pNextAttr_ = pattr->pNextAttr_;
++  if (pLastAttr_ == pattr)
++    pLastAttr_ = pLastAttr;
++  delete pattr;
++}
++
++XmlChild *
++XmlElement::FirstChild() {
++  return pFirstChild_;
++}
++
++XmlElement *
++XmlElement::FirstElement() {
++  XmlChild * pChild;
++  for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText())
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++XmlElement *
++XmlElement::NextElement() {
++  XmlChild * pChild;
++  for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText())
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++XmlElement *
++XmlElement::FirstWithNamespace(const std::string & ns) {
++  XmlChild * pChild;
++  for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++XmlElement *
++XmlElement::NextWithNamespace(const std::string & ns) {
++  XmlChild * pChild;
++  for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++XmlElement *
++XmlElement::FirstNamed(const QName & name) {
++  XmlChild * pChild;
++  for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++XmlElement *
++XmlElement::NextNamed(const QName & name) {
++  XmlChild * pChild;
++  for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
++      return pChild->AsElement();
++  }
++  return NULL;
++}
++
++const std::string &
++XmlElement::TextNamed(const QName & name) const {
++  XmlChild * pChild;
++  for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
++    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
++      return pChild->AsElement()->BodyText();
++  }
++  return STR_EMPTY;
++}
++
++void
++XmlElement::InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNext) {
++  if (pPredecessor == NULL) {
++    pNext->pNextChild_ = pFirstChild_;
++    pFirstChild_ = pNext;
++  }
++  else {
++    pNext->pNextChild_ = pPredecessor->pNextChild_;
++    pPredecessor->pNextChild_ = pNext;
++  }
++}
++
++void
++XmlElement::RemoveChildAfter(XmlChild * pPredecessor) {
++  XmlChild * pNext;
++
++  if (pPredecessor == NULL) {
++    pNext = pFirstChild_;
++    pFirstChild_ = pNext->pNextChild_;
++  }
++  else {
++    pNext = pPredecessor->pNextChild_;
++    pPredecessor->pNextChild_ = pNext->pNextChild_;
++  }
++
++  if (pLastChild_ == pNext)
++    pLastChild_ = pPredecessor;
++
++  delete pNext;
++}
++
++void
++XmlElement::AddAttr(const QName & name, const std::string & value) {
++  ASSERT(!HasAttr(name));
++
++  XmlAttr ** pprev = pLastAttr_ ? &(pLastAttr_->pNextAttr_) : &pFirstAttr_;
++  pLastAttr_ = (*pprev = new XmlAttr(name, value));
++}
++
++void
++XmlElement::AddAttr(const QName & name, const std::string & value,
++                         int depth) {
++  XmlElement * element = this;
++  while (depth--) {
++    element = element->pLastChild_->AsElement();
++  }
++  element->AddAttr(name, value);
++}
++
++void
++XmlElement::AddParsedText(const char * cstr, int len) {
++  if (len == 0)
++    return;
++
++  if (pLastChild_ && pLastChild_->IsText()) {
++    pLastChild_->AsText()->AddParsedText(cstr, len);
++    return;
++  }
++  XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
++  pLastChild_ = *pprev = new XmlText(cstr, len);
++}
++
++void
++XmlElement::AddText(const std::string & text) {
++  if (text == STR_EMPTY)
++    return;
++
++  if (pLastChild_ && pLastChild_->IsText()) {
++    pLastChild_->AsText()->AddText(text);
++    return;
++  }
++  XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
++  pLastChild_ = *pprev = new XmlText(text);
++}
++
++void
++XmlElement::AddText(const std::string & text, int depth) {
++  // note: the first syntax is ambigious for msvc 6
++  // XmlElement * pel(this);
++  XmlElement * element = this;
++  while (depth--) {
++    element = element->pLastChild_->AsElement();
++  }
++  element->AddText(text);
++}
++
++void
++XmlElement::AddElement(XmlElement *pelChild) {
++  if (pelChild == NULL)
++    return;
++
++  XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
++  pLastChild_ = *pprev = pelChild;
++  pelChild->pNextChild_ = NULL;
++}
++
++void
++XmlElement::AddElement(XmlElement *pelChild, int depth) {
++  XmlElement * element = this;
++  while (depth--) {
++    element = element->pLastChild_->AsElement();
++  }
++  element->AddElement(pelChild);
++}
++
++void
++XmlElement::ClearNamedChildren(const QName & name) {
++  XmlChild * prev_child = NULL;
++  XmlChild * next_child;
++  XmlChild * child;
++  for (child = FirstChild(); child; child = next_child) {
++    next_child = child->NextChild();
++    if (!child->IsText() && child->AsElement()->Name() == name)
++    {
++      RemoveChildAfter(prev_child);
++      continue;
++    }
++    prev_child = child;
++  }
++}
++
++void
++XmlElement::ClearChildren() {
++  XmlChild * pchild;
++  for (pchild = pFirstChild_; pchild; ) {
++    XmlChild * pToDelete = pchild;
++    pchild = pchild->pNextChild_;
++    delete pToDelete;
++  }
++  pFirstChild_ = pLastChild_ = NULL;
++}
++
++std::string
++XmlElement::Str() const {
++  std::stringstream ss;
++  Print(&ss, NULL, 0);
++  return ss.str();
++}
++
++XmlElement *
++XmlElement::ForStr(const std::string & str) {
++  XmlBuilder builder;
++  XmlParser::ParseXml(&builder, str);
++  return builder.CreateElement();
++}
++
++void
++XmlElement::Print(
++    std::ostream * pout, std::string xmlns[], int xmlnsCount) const {
++  XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount);
++}
++
++XmlElement::~XmlElement() {
++  XmlAttr * pattr;
++  for (pattr = pFirstAttr_; pattr; ) {
++    XmlAttr * pToDelete = pattr;
++    pattr = pattr->pNextAttr_;
++    delete pToDelete;
++  }
++
++  XmlChild * pchild;
++  for (pchild = pFirstChild_; pchild; ) {
++    XmlChild * pToDelete = pchild;
++    pchild = pchild->pNextChild_;
++    delete pToDelete;
++  }
++}
++
++}
+--- kopete/protocols/jabber/jingle/libjingle/NEWS	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/NEWS	(revision 586398)
+@@ -0,0 +1 @@
++* Initial source release
+--- kopete/protocols/jabber/jingle/libjingle/README	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/README	(revision 586398)
+@@ -0,0 +1,59 @@
++Libjingle
++
++Libjingle is a set of components provided by Google to interoperate with Google
++Talk's peer-to-peer and voice capabilities. This package will create several
++static libraries you may link to your project as needed.
++
++-talk               - No source files in talk/, just these subdirectories
++|-base              - Contains basic low-level portable utility functions for 
++|                     things like threads and sockets
++|-p2p               - The P2P stack
++  |-base            - Base p2p functionality
++  |-client          - Hooks to tie it into XMPP
++|-session           - Signaling
++  |-phone           - Signaling code specific to making phone calls
++|-third_party       - Components that aren't ours
++  |-mediastreamer   - Media components for dealing with sound hardware and 
++  |                   voice codecs
++|-xmllite           - XML parser
++|-xmpp              - XMPP engine
++
++In addition, this package contains two examples in talk/examples which 
++illustrate the basic concepts of how the provided classes work.
++
++The xmllite component of libjingle depends on expat. You can download expat 
++from http://expat.sourceforge.net/.
++
++mediastreamer, the media components used by the example applications depend on
++the oRTP and iLBC components from linphone, which can be found at 
++http://www.linphone.org. Linphone, in turn depends on GLib, which can be found
++at http://www.gtk.org. This GLib dependency should be removed in future 
++releases.
++
++Building Libjingle
++
++Once the dependencies are installed, run ./configure. ./configure will return
++an error if it failed to locate the proper dependencies. If ./configure
++succeeds, run 'make' to build the components and examples.
++
++When the build is complete, you can run the call example from 
++talk/examples/call. This will ask you for your GMail username and your GMail
++auth cookie. Your GMail auth cookie is the GX cookie from mail.google.com 
++found in your web browser.
++
++Relay Server
++
++Libjingle will also build a relay server that may be used to relay traffic
++when a direct peer-to-peer connection could not be established. The relay
++server will build in talk/p2p/base/relayserver and will listen on UDP
++ports 5000 and 5001. See the Libjingle Developer Guide at 
++http://code.google.com/apis/talk/index.html for information about configuring
++a client to use this relay server.
++
++STUN Server
++
++Lastly, Libjingle builds a STUN server which implements the STUN protocol for
++Simple Traversal of UDP over NAT. The STUN server is built as
++talk/p2p/base/stunserver and listens on UDP port 7000. See the Libjingle
++Developer Guide at http://code.google.com/apis/talk/index.html for information
++about configuring a client to use this STUN server.
+--- kopete/protocols/jabber/jingle/libjingle/libjingle.pro	(revision 0)
++++ kopete/protocols/jabber/jingle/libjingle/libjingle.pro	(revision 586398)
+@@ -0,0 +1,142 @@
++TEMPLATE = lib
++CONFIG += staticlib
++CONFIG += debug
++
++target.extra = true
++
++exists(../../conf.pri) {
++	include(../../conf.pri)
++}
++
++JINGLE_CPP = .
++INCLUDEPATH += $$JINGLE_CPP $$JINGLE_CPP/talk/third_party/mediastreamer
++DEFINES += POSIX
++OBJECTS_DIR = $$JINGLE_CPP/.obj
++
++# Base
++SOURCES += \
++	$$JINGLE_CPP/talk/base/asyncpacketsocket.cc \
++	$$JINGLE_CPP/talk/base/asynctcpsocket.cc \
++	$$JINGLE_CPP/talk/base/asyncudpsocket.cc \
++	$$JINGLE_CPP/talk/base/base64.cc \
++	$$JINGLE_CPP/talk/base/bytebuffer.cc \
++	$$JINGLE_CPP/talk/base/md5c.c \
++	$$JINGLE_CPP/talk/base/messagequeue.cc \
++	$$JINGLE_CPP/talk/base/network.cc \
++	$$JINGLE_CPP/talk/base/physicalsocketserver.cc \
++	$$JINGLE_CPP/talk/base/socketadapters.cc \
++	$$JINGLE_CPP/talk/base/socketaddress.cc \
++	$$JINGLE_CPP/talk/base/task.cc \
++	$$JINGLE_CPP/talk/base/taskrunner.cc \
++	$$JINGLE_CPP/talk/base/thread.cc \
++	$$JINGLE_CPP/talk/base/time.cc
++
++# Not needed ?
++#$$JINGLE_CPP/talk/base/socketaddresspair.cc \
++#$$JINGLE_CPP/talk/base/host.cc \
++
++# P2P Base
++SOURCES += \
++	$$JINGLE_CPP/talk/p2p/base/helpers.cc \
++	$$JINGLE_CPP/talk/p2p/base/p2psocket.cc \
++	$$JINGLE_CPP/talk/p2p/base/port.cc \
++	$$JINGLE_CPP/talk/p2p/base/relayport.cc \
++	$$JINGLE_CPP/talk/p2p/base/session.cc \
++	$$JINGLE_CPP/talk/p2p/base/sessionmanager.cc \
++	$$JINGLE_CPP/talk/p2p/base/socketmanager.cc \
++	$$JINGLE_CPP/talk/p2p/base/stun.cc \
++	$$JINGLE_CPP/talk/p2p/base/stunport.cc \
++	$$JINGLE_CPP/talk/p2p/base/stunrequest.cc \
++	$$JINGLE_CPP/talk/p2p/base/tcpport.cc \
++	$$JINGLE_CPP/talk/p2p/base/udpport.cc
++	
++# P2P Client
++SOURCES += \
++	$$JINGLE_CPP/talk/p2p/client/basicportallocator.cc \
++	$$JINGLE_CPP/talk/p2p/client/sessionclient.cc \
++	$$JINGLE_CPP/talk/p2p/client/socketmonitor.cc
++
++
++# XMLLite
++SOURCES += \
++	$$JINGLE_CPP/talk/xmllite/qname.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlbuilder.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlconstants.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlelement.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlnsstack.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlparser.cc \
++	$$JINGLE_CPP/talk/xmllite/xmlprinter.cc
++
++# XMPP
++SOURCES += \
++	$$JINGLE_CPP/talk/xmpp/constants.cc \
++	$$JINGLE_CPP/talk/xmpp/jid.cc \
++	$$JINGLE_CPP/talk/xmpp/saslmechanism.cc \
++	$$JINGLE_CPP/talk/xmpp/xmppclient.cc \
++	$$JINGLE_CPP/talk/xmpp/xmppengineimpl.cc \
++	$$JINGLE_CPP/talk/xmpp/xmppengineimpl_iq.cc \
++	$$JINGLE_CPP/talk/xmpp/xmpplogintask.cc \
++	$$JINGLE_CPP/talk/xmpp/xmppstanzaparser.cc \
++	$$JINGLE_CPP/talk/xmpp/xmpptask.cc
++
++# Session
++SOURCES += \
++		$$JINGLE_CPP/talk/session/phone/call.cc \
++		$$JINGLE_CPP/talk/session/phone/audiomonitor.cc \
++		$$JINGLE_CPP/talk/session/phone/phonesessionclient.cc \
++		$$JINGLE_CPP/talk/session/phone/channelmanager.cc \
++		$$JINGLE_CPP/talk/session/phone/linphonemediaengine.cc \
++		$$JINGLE_CPP/talk/session/phone/voicechannel.cc
++	
++#contains(DEFINES, HAVE_PORTAUDIO) {
++#	SOURCES += \
++#		$$JINGLE_CPP/talk/session/phone/portaudiomediaengine.cc
++#}
++
++
++# Mediastreamer
++SOURCES += \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/audiostream.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/ms.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msAlawdec.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msAlawenc.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msbuffer.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mscodec.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mscopy.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msfdispatcher.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msfifo.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msfilter.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msilbcdec.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msilbcenc.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msMUlawdec.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msMUlawenc.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msnosync.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msossread.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msosswrite.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msqdispatcher.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msqueue.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msread.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msringplayer.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msrtprecv.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msrtpsend.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mssoundread.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mssoundwrite.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msspeexdec.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/msspeexenc.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mssync.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mstimer.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/mswrite.c \
++	$$JINGLE_CPP/talk/third_party/mediastreamer/sndcard.c
++
++contains(DEFINES, HAVE_ALSA_ASOUNDLIB_H) {
++	SOURCES += $$JINGLE_CPP/talk/third_party/mediastreamer/alsacard.c
++}
++
++contains(DEFINES, HAVE_PORTAUDIO) {
++	SOURCES += $$JINGLE_CPP/talk/third_party/mediastreamer/portaudiocard.c
++}
++
++#$$JINGLE_CPP/talk/third_party/mediastreamer/osscard.c \
++#$$JINGLE_CPP/talk/third_party/mediastreamer/jackcard.c \
++#$$JINGLE_CPP/talk/third_party/mediastreamer/hpuxsndcard.c \
++	
+--- kopete/protocols/jabber/jingle/jinglevoicecaller.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicecaller.cpp	(revision 586398)
+@@ -0,0 +1,376 @@
++
++#define POSIX //FIXME
++#include "talk/xmpp/constants.h"
++#include "talk/base/sigslot.h"
++#include "talk/xmpp/jid.h"
++#include "talk/xmllite/xmlelement.h"
++#include "talk/xmllite/xmlprinter.h"
++#include "talk/base/network.h"
++#include "talk/p2p/base/session.h"
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/base/helpers.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/client/sessionclient.h"
++#include "talk/base/physicalsocketserver.h"
++#include "talk/base/thread.h"
++#include "talk/base/socketaddress.h"
++#include "talk/session/phone/call.h"
++#include "talk/session/phone/phonesessionclient.h"
++#include "talk/session/sessionsendtask.h"
++
++
++
++#include <qstring.h>
++#include <qdom.h>
++
++
++
++#include "im.h"
++#include "xmpp.h"
++#include "xmpp_xmlcommon.h"
++#include "jinglevoicecaller.h"
++#include "jabberprotocol.h"
++
++// Should change in the future
++#define JINGLE_NS "http://www.google.com/session"
++
++#include "jabberaccount.h"
++#include <kdebug.h>
++#define qDebug( X )  kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << X << endl
++#define qWarning( X )  kdWarning() <<k_funcinfo<< X << endl
++
++// ----------------------------------------------------------------------------
++
++class JingleIQResponder : public XMPP::Task
++{
++public:
++	JingleIQResponder(XMPP::Task *);
++	~JingleIQResponder();
++
++	bool take(const QDomElement &);
++};
++
++/**
++ * \class JingleIQResponder
++ * \brief A task that responds to jingle candidate queries with an empty reply.
++ */
++ 
++JingleIQResponder::JingleIQResponder(Task *parent) :Task(parent)
++{
++}
++
++JingleIQResponder::~JingleIQResponder()
++{
++}
++
++bool JingleIQResponder::take(const QDomElement &e)
++{
++	if(e.tagName() != "iq")
++		return false;
++	
++	QDomElement first = e.firstChild().toElement();
++	if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) {
++		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
++		send(iq);
++		return true;
++	}
++	
++	return false;
++}
++
++// ----------------------------------------------------------------------------
++
++/**
++ * \brief A class for handling signals from libjingle.
++ */
++class JingleClientSlots : public sigslot::has_slots<> 
++{
++public:
++	JingleClientSlots(JingleVoiceCaller *voiceCaller);
++
++	void callCreated(cricket::Call *call);
++	void callDestroyed(cricket::Call *call);
++	void sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza);
++	void requestSignaling();
++	void stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state);
++
++private:
++	JingleVoiceCaller* voiceCaller_;
++};
++
++
++JingleClientSlots::JingleClientSlots(JingleVoiceCaller *voiceCaller) : voiceCaller_(voiceCaller)
++{
++}
++
++void JingleClientSlots::callCreated(cricket::Call *call) 
++{
++	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
++	call->SignalSessionState.connect(this, &JingleClientSlots::stateChanged);
++}
++
++void JingleClientSlots::callDestroyed(cricket::Call *call)
++{
++	qDebug("JingleClientSlots: Call destroyed");
++	Jid jid(call->sessions()[0]->remote_address().c_str());
++	if (voiceCaller_->calling(jid)) {
++		qDebug(QString("Removing unterminated call to %1").arg(jid.full()));
++		voiceCaller_->removeCall(jid);
++		emit voiceCaller_->terminated(jid);
++	}
++}
++
++void JingleClientSlots::sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza) 
++{
++	QString st(stanza->Str().c_str());
++	st.replace("cli:iq","iq");
++	st.replace(":cli=","=");
++	fprintf(stderr,"bling\n");
++	voiceCaller_->sendStanza(st.latin1());
++	fprintf(stderr,"blong\n");
++	fprintf(stderr,"Sending stanza \n%s\n\n",st.latin1());
++}
++
++void JingleClientSlots::requestSignaling() 
++{
++	voiceCaller_->session_manager_->OnSignalingReady();
++}
++
++void JingleClientSlots::stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state) 
++{
++	qDebug(QString("jinglevoicecaller.cpp: State changed (%1)").arg(state));
++	// Why is c_str() stuff needed to make it compile on OS X ?
++	Jid jid(session->remote_address().c_str());
++
++	if (state == cricket::Session::STATE_INIT) { }
++	else if (state == cricket::Session::STATE_SENTINITIATE) { 
++		voiceCaller_->registerCall(jid,call);
++	}
++	else if (state == cricket::Session::STATE_RECEIVEDINITIATE) {
++		voiceCaller_->registerCall(jid,call);
++		emit voiceCaller_->incoming(jid);
++	}
++	else if (state == cricket::Session::STATE_SENTACCEPT) { }
++	else if (state == cricket::Session::STATE_RECEIVEDACCEPT) {
++		emit voiceCaller_->accepted(jid);
++	}
++	else if (state == cricket::Session::STATE_SENTMODIFY) { }
++	else if (state == cricket::Session::STATE_RECEIVEDMODIFY) {
++		qWarning(QString("jinglevoicecaller.cpp: RECEIVEDMODIFY not implemented yet (was from %1)").arg(jid.full()));
++	}
++	else if (state == cricket::Session::STATE_SENTREJECT) { }
++	else if (state == cricket::Session::STATE_RECEIVEDREJECT) {
++		voiceCaller_->removeCall(jid);
++		emit voiceCaller_->rejected(jid);
++	}
++	else if (state == cricket::Session::STATE_SENTREDIRECT) { }
++	else if (state == cricket::Session::STATE_SENTTERMINATE) {
++		voiceCaller_->removeCall(jid);
++		emit voiceCaller_->terminated(jid);
++	}
++	else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) {
++		voiceCaller_->removeCall(jid);
++		emit voiceCaller_->terminated(jid);
++	}
++	else if (state == cricket::Session::STATE_INPROGRESS) {
++		emit voiceCaller_->in_progress(jid);
++	}
++}
++
++// ----------------------------------------------------------------------------
++
++/**
++ * \class JingleVoiceCaller
++ * \brief A Voice Calling implementation using libjingle.
++ */
++
++JingleVoiceCaller::JingleVoiceCaller(PsiAccount* acc) : VoiceCaller(acc)
++{
++	initialized_ = false;
++}
++
++void JingleVoiceCaller::initialize()
++{
++	if (initialized_)
++		return;
++
++	QString jid = ((ClientStream&) account()->client()->client()->stream()).jid().full();
++	qDebug(QString("jinglevoicecaller.cpp: Creating new caller for %1").arg(jid));
++	if (jid.isEmpty()) {
++		qWarning("jinglevoicecaller.cpp: Empty JID");
++		return;
++	}
++
++	buzz::Jid j(jid.ascii());
++	cricket::InitRandom(j.Str().c_str(),j.Str().size());
++
++	// Global variables
++	if (!socket_server_) {
++		socket_server_ = new cricket::PhysicalSocketServer();
++		cricket::Thread *t = new cricket::Thread((cricket::PhysicalSocketServer*)(socket_server_));
++		cricket::ThreadManager::SetCurrent(t);
++		t->Start();
++		thread_ = t;
++
++		stun_addr_ = new cricket::SocketAddress("64.233.167.126",19302);
++		network_manager_ = new cricket::NetworkManager();
++		port_allocator_ = new cricket::BasicPortAllocator((cricket::NetworkManager*)(network_manager_), (cricket::SocketAddress*)(stun_addr_), /* relay server */ NULL);
++	}
++
++	// Session manager
++	session_manager_ = new cricket::SessionManager((cricket::PortAllocator*)(port_allocator_), thread_);
++	slots_ = new JingleClientSlots(this); 
++	session_manager_->SignalRequestSignaling.connect(slots_, &JingleClientSlots::requestSignaling);
++	session_manager_->OnSignalingReady();
++
++	// Phone Client
++	phone_client_ = new cricket::PhoneSessionClient(j, (cricket::SessionManager*)(session_manager_));
++	phone_client_->SignalCallCreate.connect(slots_, &JingleClientSlots::callCreated);
++	phone_client_->SignalCallDestroy.connect(slots_, &JingleClientSlots::callDestroyed);
++	phone_client_->SignalSendStanza.connect(slots_, &JingleClientSlots::sendStanza);
++
++	// IQ Responder
++	new JingleIQResponder(account()->client()->rootTask());
++
++	// Listen to incoming packets
++	connect(account()->client()->client(),SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&)));
++
++	initialized_ = true;
++}
++
++
++void JingleVoiceCaller::deinitialize()
++{
++	if (!initialized_)
++		return;
++
++	// Stop listening to incoming packets
++	disconnect(account()->client(),SIGNAL(xmlIncoming(const QString&)),this,SLOT(receiveStanza(const QString&)));
++
++	// Disconnect signals (is this needed)
++	//phone_client_->SignalCallCreate.disconnect(slots_);
++	//phone_client_->SignalSendStanza.disconnect(slots_);
++	
++	// Delete objects
++	delete phone_client_;
++	delete session_manager_;
++	delete slots_;
++
++	initialized_ = false;
++}
++
++
++JingleVoiceCaller::~JingleVoiceCaller()
++{
++}
++
++bool JingleVoiceCaller::calling(const Jid& jid)
++{
++	return calls_.contains(jid.full());
++}
++
++void JingleVoiceCaller::call(const Jid& jid)
++{
++	qDebug(QString("jinglevoicecaller.cpp: Calling %1").arg(jid.full()));
++	cricket::Call *c = ((cricket::PhoneSessionClient*)(phone_client_))->CreateCall();
++	c->InitiateSession(buzz::Jid(jid.full().ascii()));
++	phone_client_->SetFocus(c);
++}
++
++void JingleVoiceCaller::accept(const Jid& j)
++{
++	qDebug("jinglevoicecaller.cpp: Accepting call");
++	cricket::Call* call = calls_[j.full()];
++	if (call != NULL) {
++		call->AcceptSession(call->sessions()[0]);
++		phone_client_->SetFocus(call);
++	}
++}
++
++void JingleVoiceCaller::reject(const Jid& j)
++{
++	qDebug("jinglevoicecaller.cpp: Rejecting call");
++	cricket::Call* call = calls_[j.full()];
++	if (call != NULL) {
++		call->RejectSession(call->sessions()[0]);
++		calls_.remove(j.full());
++	}
++}
++
++void JingleVoiceCaller::terminate(const Jid& j)
++{
++	qDebug(QString("jinglevoicecaller.cpp: Terminating call to %1").arg(j.full()));
++	cricket::Call* call = calls_[j.full()];
++	if (call != NULL) {
++		call->Terminate();
++		calls_.remove(j.full());
++	}
++}
++
++void JingleVoiceCaller::sendStanza(const char* stanza)
++{
++	account()->client()->send(QString(stanza));
++}
++
++void JingleVoiceCaller::registerCall(const Jid& jid, cricket::Call* call)
++{
++	qDebug("jinglevoicecaller.cpp: Registering call\n");
++	kdDebug(14000) << k_funcinfo << jid.full() << endl;
++	if (!calls_.contains(jid.full())) {
++		calls_[jid.full()] = call;
++	}
++// 	else {
++// 		qWarning("jinglevoicecaller.cpp: Auto-rejecting call because another call is currently open");
++// 		call->RejectSession(call->sessions()[0]);
++// 	}
++}
++
++void JingleVoiceCaller::removeCall(const Jid& j)
++{
++	qDebug(QString("JingleVoiceCaller: Removing call to %1").arg(j.full()));
++	calls_.remove(j.full());
++}
++
++void JingleVoiceCaller::receiveStanza(const QString& stanza)
++{
++	QDomDocument doc;
++	doc.setContent(stanza);
++
++	// Check if it is offline presence from an open chat
++	if (doc.documentElement().tagName() == "presence") {
++		Jid from = Jid(doc.documentElement().attribute("from"));
++		QString type = doc.documentElement().attribute("type");
++		if (type == "unavailable" && calls_.contains(from.full())) {
++			qDebug("JingleVoiceCaller: User went offline without closing a call.");
++			removeCall(from);
++			emit terminated(from);
++		}
++		return;
++	}
++	
++	// Check if the packet is destined for libjingle.
++	// We could use Session::IsClientStanza to check this, but this one crashes
++	// for some reason.
++	QDomNode n = doc.documentElement().firstChild();
++	bool ok = false;
++	while (!n.isNull() && !ok) {
++		QDomElement e = n.toElement();
++		if (!e.isNull() && e.attribute("xmlns") == JINGLE_NS) {
++			ok = true;
++		}
++		n = n.nextSibling();
++	}
++	
++	// Spread the word
++	if (ok) {
++		qDebug(QString("jinglevoicecaller.cpp: Handing down %1").arg(stanza));
++		buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii());
++		phone_client_->OnIncomingStanza(e);
++	}
++}
++
++cricket::SocketServer* JingleVoiceCaller::socket_server_ = NULL;
++cricket::Thread* JingleVoiceCaller::thread_ = NULL;
++cricket::NetworkManager* JingleVoiceCaller::network_manager_ = NULL;
++cricket::BasicPortAllocator* JingleVoiceCaller::port_allocator_ = NULL;
++cricket::SocketAddress* JingleVoiceCaller::stun_addr_ = NULL;
+--- kopete/protocols/jabber/jingle/jinglesession.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglesession.h	(revision 586398)
+@@ -0,0 +1,94 @@
++/*
++    jinglesession.h - Define a Jingle session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 JINGLESESSION_H
++#define JINGLESESSION_H
++
++#include <qobject.h>
++#include <qstring.h>
++
++#include <xmpp.h> // XMPP::Jid
++#include <qvaluelist.h>
++
++class JabberAccount;
++/**
++ * @brief Base class for peer-to-peer session that use Jingle signaling
++ *
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
++class JingleSession : public QObject
++{
++	Q_OBJECT
++public:
++	typedef QValueList<XMPP::Jid> JidList;
++
++	JingleSession(JabberAccount *account, const JidList &peers);
++	virtual ~JingleSession();
++
++	/**
++	 * Return the JabberAccount associated with this session.
++	 */
++	JabberAccount *account();
++
++	const XMPP::Jid &myself() const;
++	const JidList &peers() const;
++	JidList &peers();
++	
++	/**
++	 * Return the type of session(ex: voice, video, games)
++	 * Note that you must return the XML namespace that define 
++	 * the session: ex:(http://jabber.org/protocol/jingle/sessions/audio)
++	 */
++	virtual QString sessionType() = 0;
++
++public slots:
++	/**
++	 * @brief Start a session with the give JID.
++	 * You should begin the negociation here.
++	 */
++	virtual void start() = 0;
++	/**
++	 * @brief Acept a session request.
++	 */
++	virtual void accept() = 0;
++	/**
++	 * @brief Decline a session request.
++	 */
++	virtual void decline() = 0;
++	/**
++	 * @brief Terminate a Jingle session.
++	 */
++	virtual void terminate() = 0;
++
++protected slots:
++	void sendStanza(const QString &stanza);
++	
++signals:
++	/**
++	 * Session is started(negocation and connection test are done).
++	 */
++	void sessionStarted();
++
++	void accepted();
++	void declined();
++	void terminated();
++
++private:
++	class Private;
++	Private *d;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp	(revision 586398)
+@@ -0,0 +1,208 @@
++/*
++    jinglevoicesessiondialog.cpp - GUI for a voice session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 "jinglevoicesessiondialog.h"
++
++// Qt includes
++#include <qlabel.h>
++#include <qpixmap.h>
++#include <qimage.h>
++
++// Jingle includes
++// #include "jinglevoicesession.h"
++// #include "jinglesessionmanager.h"
++#include "voicecaller.h"
++
++// KDE includes
++#include <klocale.h>
++#include <kpushbutton.h>
++
++// Kopete includes
++#include "jabberaccount.h"
++#include "jabbercontact.h"
++#include "jabbercontactpool.h"
++
++#include "kopeteglobal.h"
++#include "kopetemetacontact.h"
++
++using namespace XMPP;
++
++JingleVoiceSessionDialog::JingleVoiceSessionDialog(const Jid &peerJid, VoiceCaller *caller, QWidget *parent, const char *name)
++ : JingleVoiceSessionDialogBase(parent, name), m_session(caller), m_peerJid(peerJid), m_sessionState(Incoming)
++{
++	QString contactJid = m_peerJid.full();
++	setCaption( i18n("Voice session with %1").arg(contactJid) );
++
++	connect(buttonAccept, SIGNAL(clicked()), this, SLOT(slotAcceptClicked()));
++	connect(buttonDecline, SIGNAL(clicked()), this, SLOT(slotDeclineClicked()));
++	connect(buttonTerminate, SIGNAL(clicked()), this, SLOT(slotTerminateClicked()));
++
++// NOTE: Disabled for 0.12
++#if 0
++	connect(m_session, SIGNAL(sessionStarted()), this, SLOT(sessionStarted()));
++	connect(m_session, SIGNAL(accepted()), this, SLOT(sessionAccepted()));
++	connect(m_session, SIGNAL(declined()), this, SLOT(sessionDeclined()));
++	connect(m_session, SIGNAL(terminated()), this, SLOT(sessionTerminated()));
++#endif
++	connect(m_session, SIGNAL(accepted( const Jid & )), this, SLOT( sessionAccepted(const Jid &) ));
++	connect(m_session, SIGNAL(in_progress( const Jid & )), this, SLOT( sessionStarted(const Jid &) ));
++	connect(m_session, SIGNAL(rejected( const Jid& )), this, SLOT( sessionDeclined(const Jid &) ));
++	connect(m_session, SIGNAL(terminated( const Jid& )), this, SLOT( sessionTerminated(const Jid &) ));
++
++	// Find JabberContact for the peer and fill this dialog with contact information.
++	JabberContact *peerContact = static_cast<JabberContact*>( m_session->account()->contactPool()->findRelevantRecipient( m_peerJid ) );
++	if( peerContact )
++	{
++		setContactInformation( peerContact );
++	}
++	
++	labelSessionStatus->setText( i18n("Incoming Session...") );
++	buttonAccept->setEnabled(true);
++	buttonDecline->setEnabled(true);
++}
++
++JingleVoiceSessionDialog::~JingleVoiceSessionDialog()
++{
++	//m_session->account()->sessionManager()->removeSession(m_session);
++}
++
++void JingleVoiceSessionDialog::setContactInformation(JabberContact *contact)
++{
++	if( contact->metaContact() )
++	{
++		labelDisplayName->setText( contact->metaContact()->displayName() );
++		labelContactPhoto->setPixmap( QPixmap(contact->metaContact()->photo()) );
++	}
++	else
++	{
++		labelDisplayName->setText( contact->nickName() );
++		labelDisplayName->setPixmap( QPixmap(contact->property(Kopete::Global::Properties::self()->photo()).value().toString()) );
++	}
++}
++
++void JingleVoiceSessionDialog::start()
++{
++	labelSessionStatus->setText( i18n("Waiting for other peer...") );
++	buttonAccept->setEnabled(false);
++	buttonDecline->setEnabled(false);
++	buttonTerminate->setEnabled(true);
++	//m_session->start();
++	m_session->call( m_peerJid );
++	m_sessionState = Waiting;
++}
++
++void JingleVoiceSessionDialog::slotAcceptClicked()
++{
++	labelSessionStatus->setText( i18n("Session accepted.") );
++	buttonAccept->setEnabled(false);
++	buttonDecline->setEnabled(false);
++	buttonTerminate->setEnabled(true);
++	
++	//m_session->accept();
++	m_session->accept( m_peerJid );
++	m_sessionState = Accepted;
++}
++
++void JingleVoiceSessionDialog::slotDeclineClicked()
++{
++	labelSessionStatus->setText( i18n("Session declined.") );
++	buttonAccept->setEnabled(false);
++	buttonDecline->setEnabled(false);
++	buttonTerminate->setEnabled(false);
++
++	//m_session->decline();
++	m_session->reject( m_peerJid );
++	m_sessionState = Declined;
++	finalize();
++}
++
++void JingleVoiceSessionDialog::slotTerminateClicked()
++{
++	labelSessionStatus->setText( i18n("Session terminated.") );
++	buttonAccept->setEnabled(false);
++	buttonDecline->setEnabled(false);
++	buttonTerminate->setEnabled(false);
++
++	//m_session->terminate();
++	m_session->terminate( m_peerJid );
++	m_sessionState = Terminated;
++	finalize();
++	close();
++}
++
++void JingleVoiceSessionDialog::sessionStarted(const Jid &jid)
++{
++	if( m_peerJid.compare(jid) )
++	{
++		labelSessionStatus->setText( i18n("Session in progress.") );
++		buttonAccept->setEnabled(false);
++		buttonDecline->setEnabled(false);
++		buttonTerminate->setEnabled(true);
++		m_sessionState = Started;
++	}
++}
++
++void JingleVoiceSessionDialog::sessionAccepted(const Jid &jid)
++{
++	if( m_peerJid.compare(jid) )
++	{
++		labelSessionStatus->setText( i18n("Session accepted.") );
++		buttonAccept->setEnabled(false);
++		buttonDecline->setEnabled(false);
++		buttonTerminate->setEnabled(true);
++		m_sessionState = Accepted;
++	}
++}
++
++void JingleVoiceSessionDialog::sessionDeclined(const Jid &jid)
++{
++	if( m_peerJid.compare(jid) )
++	{
++		labelSessionStatus->setText( i18n("Session declined.") );
++		buttonAccept->setEnabled(false);
++		buttonDecline->setEnabled(false);
++		buttonTerminate->setEnabled(false);
++		m_sessionState = Declined;
++	}
++}
++
++void JingleVoiceSessionDialog::sessionTerminated(const Jid &jid)
++{
++	if( m_peerJid.compare(jid) )
++	{
++		labelSessionStatus->setText( i18n("Session terminated.") );
++		buttonAccept->setEnabled(false);
++		buttonDecline->setEnabled(false);
++		buttonTerminate->setEnabled(false);
++		m_sessionState = Terminated;
++	}
++}
++
++void JingleVoiceSessionDialog::reject()
++{
++	finalize();
++	QDialog::reject();
++}
++
++void JingleVoiceSessionDialog::finalize()
++{
++	disconnect(m_session, SIGNAL(accepted( const Jid & )), this, SLOT( sessionAccepted(const Jid &) ));
++	disconnect(m_session, SIGNAL(in_progress( const Jid & )), this, SLOT( sessionStarted(const Jid &) ));
++	disconnect(m_session, SIGNAL(rejected( const Jid& )), this, SLOT( sessionDeclined(const Jid &) ));
++	disconnect(m_session, SIGNAL(terminated( const Jid& )), this, SLOT( sessionTerminated(const Jid &) ));
++}
++
++#include "jinglevoicesessiondialog.moc"
+--- kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp	(revision 586398)
+@@ -0,0 +1,75 @@
++/*
++    jingleswatchsessiontask.cpp - Watch for incoming Jingle sessions.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 "jinglewatchsessiontask.h"
++
++#include <kdebug.h>
++
++#include "jabberprotocol.h"
++
++#define JINGLE_NS "http://www.google.com/session"
++
++JingleWatchSessionTask::JingleWatchSessionTask(XMPP::Task *parent)
++ : Task(parent)
++{}
++
++JingleWatchSessionTask::~JingleWatchSessionTask()
++{}
++
++//NOTE: This task watch for pre-JEP session.
++bool JingleWatchSessionTask::take(const QDomElement &element)
++{
++	if(element.tagName() != "iq")
++		return false;
++	
++	QString sessionType, initiator;
++	
++	QDomElement first = element.firstChild().toElement();
++	if( !first.isNull() && first.attribute("xmlns") == JINGLE_NS && first.tagName() == "session" ) 
++	{
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Checking for incoming sesssion." << endl;
++		initiator = first.attribute("initiator");
++	
++		// Only proceed initiate type Jingle XMPP call.
++		if( first.attribute("type") != QString::fromUtf8("initiate") )
++			return false;
++		
++		int nodeIndex;
++
++		QDomNodeList nodeList = first.childNodes();
++		// Do not check first child
++		for(nodeIndex = 0; nodeIndex < nodeList.length(); nodeIndex++)
++		{
++			QDomElement nodeElement = nodeList.item(nodeIndex).toElement();
++			if(nodeElement.tagName() == "description")
++			{
++				sessionType = nodeElement.attribute("xmlns");
++			}
++		}
++
++		if( !initiator.isEmpty() && !sessionType.isEmpty() )
++		{
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Emmiting incoming sesssion." << endl;
++			emit watchSession(sessionType, initiator);
++			return true;
++		}
++	}
++	
++	return false;
++}
++
++#include "jinglewatchsessiontask.moc"
+\ No newline at end of file
+--- kopete/protocols/jabber/jingle/jinglevoicecaller.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicecaller.h	(revision 586398)
+@@ -0,0 +1,72 @@
++#define PsiAccount JabberAccount
++
++#ifndef JINGLEVOICECALLER_H
++#define JINGLEVOICECALLER_H
++
++#include <qmap.h>
++
++#include "im.h"
++#include "voicecaller.h"
++
++using namespace XMPP;
++
++
++class PsiAccount;
++
++namespace cricket {
++	class SocketServer;
++	class Thread;
++	class NetworkManager;
++	class BasicPortAllocator;
++	class SessionManager;
++	class PhoneSessionClient;
++	class Call;
++	class SocketAddress;
++}
++
++class JingleClientSlots;
++class JingleCallSlots;
++
++
++class JingleVoiceCaller : public VoiceCaller
++{
++	Q_OBJECT
++
++	friend class JingleClientSlots;
++
++public:
++	JingleVoiceCaller(PsiAccount* account);
++	~JingleVoiceCaller();
++	
++	virtual bool calling(const Jid&);
++	
++	virtual void initialize();
++	virtual void deinitialize();
++
++	virtual void call(const Jid&);
++	virtual void accept(const Jid&);
++	virtual void reject(const Jid&);
++	virtual void terminate(const Jid&);
++
++protected:
++	void sendStanza(const char*);
++	void registerCall(const Jid&, cricket::Call*);
++	void removeCall(const Jid&);
++
++protected slots:
++	void receiveStanza(const QString&);
++
++private:
++	bool initialized_;
++	static cricket::SocketServer *socket_server_;
++	static cricket::Thread *thread_;
++	static cricket::NetworkManager *network_manager_;
++	static cricket::BasicPortAllocator *port_allocator_;
++	static cricket::SocketAddress *stun_addr_;
++	cricket::SessionManager *session_manager_;
++	cricket::PhoneSessionClient *phone_client_;
++	JingleClientSlots *slots_;
++	QMap<QString,cricket::Call*> calls_;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++    jinglevoicesessiondialog.h - GUI for a voice session.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 JINGLEVOICESESSIONDIALOG_H
++#define JINGLEVOICESESSIONDIALOG_H
++
++#include "jinglevoicesessiondialogbase.h"
++
++#include <im.h>
++#include <xmpp.h>
++
++using namespace XMPP;
++
++class JabberContact;
++class VoiceCaller;
++
++class JingleVoiceSessionDialog : public JingleVoiceSessionDialogBase
++{
++	Q_OBJECT
++public:
++	enum SessionState { Incoming, Waiting, Accepted, Declined, Started, Terminated };
++
++	JingleVoiceSessionDialog(const Jid &peerJid, VoiceCaller *caller, QWidget *parent = 0, const char *name = 0);
++	~JingleVoiceSessionDialog();
++
++public slots:
++	void start();
++
++protected slots:
++	void reject();
++
++protected:
++	void finalize();
++
++private slots:
++	void slotAcceptClicked();
++	void slotDeclineClicked();
++	void slotTerminateClicked();
++
++	void sessionStarted(const Jid &jid);
++	void sessionAccepted(const Jid &jid);
++	void sessionDeclined(const Jid &jid);
++	void sessionTerminated(const Jid &jid);
++
++private:
++	void setContactInformation(JabberContact *contact);
++
++	VoiceCaller *m_session;
++	Jid m_peerJid;
++	SessionState m_sessionState;
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/configure.in.bot	(revision 0)
++++ kopete/protocols/jabber/jingle/configure.in.bot	(revision 586398)
+@@ -0,0 +1,16 @@
++if test "$with_jingle" = yes; then
++	echo ""
++	echo Supported Jabber Jingle voice Codecs for Kopete:
++	echo Speex: $speex_found
++	echo iLBC:  $ilbc_found
++	echo MULAW: yes
++else
++	echo ""
++	echo "You have disabled Jabber Jingle voice support or you are missing required libraries required to compile it."
++	echo "Jingle is a new Jabber standard that define a signaling protocol via XMPP for peer-to-peer applications."
++	echo "Jingle audio is compatible with the Google Talk voice service."
++	echo ""
++	echo "Required Jingle dependencies are listed on this page:"
++	echo "http://wiki.kde.org/tiki-index.php?page=Kopete+Jabber+Jingle"
++	all_tests=bad
++fi
+--- kopete/protocols/jabber/jingle/Makefile.am	(revision 0)
++++ kopete/protocols/jabber/jingle/Makefile.am	(revision 586398)
+@@ -0,0 +1,28 @@
++SUBDIRS = libjingle
++METASOURCES = AUTO
++AM_CPPFLAGS = $(KOPETE_INCLUDES) \
++	-I$(srcdir)/../libiris/iris/include \
++	-I$(srcdir)/../libiris/iris/xmpp-im \
++	-I$(srcdir)/../libiris/iris/jabber \
++	-I$(srcdir)/../libiris/qca/src \
++	-I$(srcdir)/../libiris/cutestuff/util \
++	-I$(srcdir)/libjingle \
++	-I$(srcdir)/.. \
++	$(all_includes)
++
++noinst_LTLIBRARIES = libkopetejabberjingle.la 
++
++# libkopetejabberjingle_la_SOURCES = jinglevoicecaller.cpp  \
++# 	jinglewatchsessiontask.cpp jinglesession.cpp jinglevoicesession.cpp jinglesessionmanager.cpp \
++# 	jinglevoicesessiondialogbase.ui jinglevoicesessiondialog.cpp
++
++libkopetejabberjingle_la_SOURCES = jinglevoicecaller.cpp jinglevoicesessiondialogbase.ui jinglevoicesessiondialog.cpp
++
++libkopetejabberjingle_la_LIBADD = libjingle/talk/session/phone/libcricketsessionphone.la \
++	libjingle/talk/p2p/client/libcricketp2pclient.la \
++	libjingle/talk/p2p/base/libcricketp2pbase.la \
++	libjingle/talk/xmpp/libcricketxmpp.la \
++	libjingle/talk/xmllite/libcricketxmllite.la \
++	libjingle/talk/base/libcricketbase.la \
++	libjingle/talk/third_party/mediastreamer/libmediastreamer.la  \
++	$(EXPAT_LIBS) $(ORTP_LIBS) -lpthread $(ILBC_LIBS) $(SPEEX_LIBS) $(GLIB_LIBS) $(ALSA_LIBS)
+--- kopete/protocols/jabber/jingle/DESIGN	(revision 0)
++++ kopete/protocols/jabber/jingle/DESIGN	(revision 586398)
+@@ -0,0 +1,121 @@
++Voice Use cases:
++----------------
++
++In JabberAccount:
++-Account is connected:
++* Init the JingleSessionManager (accessible via account()->jingleSessionManager())
++* Add voice extension to client features.
++* Connect to incomingSession(const QString &sessionType, JingleSession *session) signal in JabberAccount.
++
++-On incoming session
++* Create and show VoiceConversationDialog.
++* VoiceConversationDialog will handle the communcation between the user and the session.
++
++In JabberContact:
++-User select "Start voice conversation..."
++* Get the best resource that support voice. If no compatible resource is found, show a message box.
++* Create a JingleVoiceSession using JingleVoiceSessionManager.
++* Create VoiceConversationDialog
++* and VoiceConversationDialog will handle the communication between the user and the session.
++
++In VoiceConversationDialog:
++-Incoming voice session
++* Accept the session call JingleVoiceSession::accept();
++* Decline the session call JingleVoiceSession::decline();
++
++-Accepted voice session
++* Change GUI to "Voice session in progress."
++
++-On declining voice session or terminating a session.
++* Remove JingleVoiceSession from JingleVoiceSessionManager.
++* Close the dialog.
++
++===================================================================================================
++Design with future in mind. Only voice session type is available today, but others will come.
++
++A session is a connection between two or multiple peers.
++A session do not handle multiple "calls"(or whatever it called depending of the context). That's will be job of SessionManager
++A sesson has a myself user and others users, all identified by their full JID. (maybe their JabberBaseContact or JabberResource object ?)
++
++-Maybe use the Channel pattern, where Session will hold one or multiple Channels. Think for voice+video for example. ?
++
++All manager classes must be unique for each account.
++
++JidList = QValueList<XMPP::Jid> or QStringList if QValueList<XMPP::Jid> doesn't work.
++
++JingleSession and derivated are created by the Manager class.
++
++SessionType is the XML Namespace of the session type (ex: http://jabber.org/protocol/sessions/audio)
++
++JingleSessionManager
++--------------------
++Manage Jingle sessions. 
++-Manage global (maybe static ?)objects shared by all sessions (cricket::BasicPortAllocator, cricket::SessionManager).
++
++Has a JingleWatchSessionTask(derived from XMPP::Task) that check for incoming session in JingleSessionManager, that check the session type,
++create the right JingleSession subclass, then emit the required signal. This bypass libjingle to have a better
++control on incoming session request and avoid using multiple Manager for each session type.
++
++JingleSessionManager manage the JingleSession pointers. Do not delete it in user classes.
++
++* JingleSessionManager(JabberAccount *)
++
++* public slots:
++* JingleSession *createSession(const QString &sessionType, const JidList &peers);
++* void removeSession(JingleSession *);
++
++signals:
++* void incomingSession(const QString &sessionType, JingleSession *session);
++
++JingleSession
++-------------
++Base class for Jingle session. A session is a 
++
++* JingleSession(JingleSessionManager *manager, const JidList &peers);
++
++* XMPP::Jid &myself(); // account()->client()->jid();
++* JidList &peers();
++* JabberAccount *account();
++* JingleSessionManager *manager();
++
++// Start the negociation phase.
++* virtual void start() = 0;
++// Send the IQ stanza with action "accept"
++* virtual void accept() = 0;
++// Send the IQ stanza with action "
++* virtual void decline() = 0;
++* virtual void terminate() = 0;
++
++// Return Session XML namespace
++* virtual QString sessionType() = 0;
++
++protected slots:
++	void sendStanza(const QString &stanza) { account()->client->send(stanza);
++
++signals:
++	void accepted();
++	void declined();
++	void terminated();
++
++JingleVoiceSession : public JingleSession
++------------------
++Define a VoIP voice session between two peers(for the moment).
++Hold the PhoneSessionClient object.
++
++connect(account()->client(),SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&)));
++
++
++private slots:
++	void receiveStanza(const QString &stanza);
++	
++VoiceConversationDialog
++-----------------------
++* VoiceConversationDialog(JingleVoiceSession *)
++VoiceConversationDialog will handle the communcation between the user and a session.
++Should auto-delete when closed.
++It can:
++-Accept a voice session.
++-Decline a voice session.
++-Terminate a voice session(or hang-up).
++
++It is the Action menu that can start a session.
+--- kopete/protocols/jabber/jingle/jinglewatchsessiontask.h	(revision 0)
++++ kopete/protocols/jabber/jingle/jinglewatchsessiontask.h	(revision 586398)
+@@ -0,0 +1,39 @@
++/*
++    jingleswatchsessiontask.h - Watch for incoming Jingle sessions.
++
++    Copyright (c) 2006      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel at 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 JINGLEWATCHSESSIONTASK_H
++#define JINGLEWATCHSESSIONTASK_H
++
++#include <xmpp_tasks.h>
++
++/**
++ * This task watch for incoming Jingle session and notify manager.
++ * It is declared in the header to be "moc"-able.
++ */
++class JingleWatchSessionTask : public XMPP::Task
++{
++	Q_OBJECT
++public:
++	JingleWatchSessionTask(XMPP::Task *parent);
++	~JingleWatchSessionTask();
++
++	bool take(const QDomElement &element);
++
++signals:
++	void watchSession(const QString &sessionType, const QString &initiator);
++};
++
++#endif
+--- kopete/protocols/jabber/jingle/voicecaller.h	(revision 0)
++++ kopete/protocols/jabber/jingle/voicecaller.h	(revision 586398)
+@@ -0,0 +1,96 @@
++#define PsiAccount JabberAccount
++class PsiAccount;
++
++#ifndef VOICECALLER_H
++#define VOICECALLER_H
++
++#include "im.h"
++
++
++
++
++using namespace XMPP;
++
++/**
++ * \brief An abstract class for a voice call implementation.
++ */
++class VoiceCaller : public QObject
++{
++	Q_OBJECT
++
++public:
++	/**
++	 * \brief Base constructor.
++	 * 
++	 * \param account the account to which this voice caller belongs
++	 */
++	VoiceCaller(PsiAccount* account) : account_(account) { };
++	
++	/**
++	 * \brief Retrieves the account to which this voice caller belongs.
++	 */
++	PsiAccount* account() { return account_; }
++
++	/**
++	 * \brief Initializes the voice caller. 
++	 * This should be called when the connection is open.
++	 */
++	virtual void initialize() = 0;
++
++	/**
++	 * \brief De-initializes the voice caller. 
++	 * This should be called when the connection is about to be closed.
++	 */
++	virtual void deinitialize() = 0;
++
++	/**
++	 * \brief Call the given JID.
++	 */
++	virtual void call(const Jid&) = 0;
++
++	/**
++	 * \brief Accept a call from the given JID.
++	 */
++	virtual void accept(const Jid&) = 0;
++
++	/**
++	 * \brief Reject the call from the given JID.
++	 */
++	virtual void reject(const Jid&) = 0;
++	
++	/**
++	 * \brief Terminate the call from the given JID.
++	 */
++	virtual void terminate(const Jid&) = 0;
++
++signals:
++	/**
++	 * \brief Incoming call from the given JID.
++	 */
++	void incoming(const Jid&);
++	
++	/**
++	 * \brief Contact accepted an incoming call.
++	 */
++	void accepted(const Jid&);
++
++	/**
++	 * \brief Contact rejected an incoming call.
++	 */
++	void rejected(const Jid&);
++
++	/**
++	 * \brief Call with given JID is in progress.
++	 */
++	void in_progress(const Jid&);
++
++	/**
++	 * \brief Call with given JID is terminated.
++	 */
++	void terminated(const Jid&);
++
++private:
++	PsiAccount* account_;
++};
++
++#endif
+--- kopete/protocols/jabber/Makefile.am	(revision 568672)
++++ kopete/protocols/jabber/Makefile.am	(revision 586398)
+@@ -1,5 +1,11 @@
++if include_jingle
++JINGLE=jingle
++JINGLE_LIBS=jingle/libkopetejabberjingle.la
++JINGLE_INCLUDES=-I$(srcdir)/jingle -I$(top_builddir)/kopete/protocols/jabber/jingle
++endif
++
+ METASOURCES = AUTO
+-SUBDIRS = ui icons libiris . kioslave
++SUBDIRS = ui icons libiris $(JINGLE) . kioslave
+ AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+ 	-I$(srcdir)/libiris/iris/include \
+ 	-I$(srcdir)/libiris/iris/xmpp-im \
+@@ -9,7 +15,7 @@
+ 	-I$(srcdir)/libiris/cutestuff/network \
+ 	-I$(srcdir)/ui \
+ 	-I./ui \
+-	$(all_includes)
++	$(all_includes) $(JINGLE_INCLUDES)
+ 
+ noinst_LTLIBRARIES = libjabberclient.la
+ libjabberclient_la_SOURCES = \
+@@ -33,7 +39,10 @@
+ 	jabberformlineedit.cpp \
+ 	jabberchatsession.cpp \
+ 	jabbergroupchatmanager.cpp \
+-	jabberfiletransfer.cpp
++	jabberfiletransfer.cpp \
++	jabbercapabilitiesmanager.cpp\
++	jabbertransport.cpp\
++	jabberbookmarks.cpp
+ 
+ kopete_jabber_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries)
+ kopete_jabber_la_LIBADD  = $(top_builddir)/kopete/libkopete/libkopete.la \
+@@ -45,10 +54,14 @@
+ 	libiris/qca/src/libqca.la \
+ 	libiris/cutestuff/network/libcutestuff_network.la \
+ 	libiris/cutestuff/util/libcutestuff_util.la \
+-	libjabberclient.la
++	libjabberclient.la \
++	$(JINGLE_LIBS)
+ 
+ service_DATA = kopete_jabber.desktop
+ servicedir = $(kde_servicesdir)
+ 
++mydatadir = $(kde_datadir)/kopete_jabber
++mydata_DATA = jabberchatui.rc
++
+ noinst_HEADERS = jabberresourcepool.h jabbercontact.h jabbergroupcontact.h \
+ 	jabberclient.h
+--- kopete/protocols/jabber/jabberchatsession.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberchatsession.cpp	(revision 586398)
+@@ -18,17 +18,28 @@
+ #include "jabberchatsession.h"
+ 
+ #include <qptrlist.h>
++#include <qlabel.h>
++#include <qimage.h>
++#include <qtooltip.h>
++#include <qfile.h>
++#include <qiconset.h>
++
+ #include <kconfig.h>
+ #include <kdebug.h>
+ #include <klocale.h>
+ #include "kopetechatsessionmanager.h"
++#include "kopetemessage.h"
+ #include "kopeteviewplugin.h"
+ #include "kopeteview.h"
+ #include "jabberprotocol.h"
+ #include "jabberaccount.h"
+ #include "jabberclient.h"
+ #include "jabbercontact.h"
++#include "jabberresource.h"
++#include "jabberresourcepool.h"
++#include "kioslave/jabberdisco.h"
+ 
++
+ JabberChatSession::JabberChatSession ( JabberProtocol *protocol, const JabberBaseContact *user,
+ 											 Kopete::ContactPtrList others, const QString &resource, const char *name )
+ 											 : Kopete::ChatSession ( user, others, protocol,  name )
+@@ -47,14 +58,49 @@
+ 
+ 	// check if the user ID contains a hardwired resource,
+ 	// we'll have to use that one in that case
+-	XMPP::Jid jid ( user->contactId () );
++	XMPP::Jid jid = user->rosterItem().jid() ;
+ 
+ 	mResource = jid.resource().isEmpty () ? resource : jid.resource ();
+-
+ 	slotUpdateDisplayName ();
+ 
++#ifdef SUPPORT_JINGLE
++	KAction *jabber_voicecall = new KAction( i18n("Voice call" ), "voicecall", 0, members().getFirst(), SLOT(voiceCall ()), actionCollection(), "jabber_voicecall" );
++
++	setInstance(protocol->instance());
++	jabber_voicecall->setEnabled( false );
++
++	
++	Kopete::ContactPtrList chatMembers = members ();
++	if ( chatMembers.first () )
++	{
++		// Check if the current contact support Voice calls, also honour lock by default.
++		// FIXME: we should use the active ressource
++		JabberResource *bestResource = account()->resourcePool()->  bestJabberResource( static_cast<JabberBaseContact*>(chatMembers.first())->rosterItem().jid() );
++		if( bestResource && bestResource->features().canVoice() )
++		{
++			jabber_voicecall->setEnabled( true );
++		}
++	}
++
++#endif
++
++ new KAction( i18n( "Send File" ), "attach", 0, this, SLOT( slotSendFile() ), actionCollection(), "jabberSendFile" );
++
++	setXMLFile("jabberchatui.rc");
++
+ }
+ 
++JabberChatSession::~JabberChatSession( )
++{
++	JabberAccount * a = dynamic_cast<JabberAccount *>(Kopete::ChatSession::account ());
++	if( !a ) //When closing kopete, the account is partially destroyed already,  dynamic_cast return 0
++		return;
++	if ( a->configGroup()->readBoolEntry ("SendEvents", true) &&
++			 a->configGroup()->readBoolEntry ("SendGoneEvent", true) )
++		sendNotification( XMPP::GoneEvent );
++}
++
++
+ void JabberChatSession::slotUpdateDisplayName ()
+ {
+ 	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << endl;
+@@ -65,7 +111,7 @@
+ 	if ( !chatMembers.first () )
+ 		return;
+ 
+-	XMPP::Jid jid ( chatMembers.first()->contactId () );
++	XMPP::Jid jid = static_cast<JabberBaseContact*>(chatMembers.first())->rosterItem().jid();
+ 
+ 	if ( !mResource.isEmpty () )
+ 		jid.setResource ( mResource );
+@@ -106,7 +152,6 @@
+ 	mResource = fromResource;
+ 
+ 	slotUpdateDisplayName ();
+-
+ 	Kopete::ChatSession::appendMessage ( msg );
+ 
+ 	// We send the notifications for Delivered and Displayed events. More granular management
+@@ -140,12 +185,8 @@
+ 		++listIterator;
+ 		if ( contact->isContactRequestingEvent( event ) )
+ 		{
+-			// create JID for us as sender
+-			XMPP::Jid fromJid ( myself()->contactId () );
+-			fromJid.setResource ( account()->resource () );
+-	
+ 			// create JID for the recipient
+-			XMPP::Jid toJid ( contact->contactId () );
++			XMPP::Jid toJid = contact->rosterItem().jid();
+ 	
+ 			// set resource properly if it has been selected already
+ 			if ( !resource().isEmpty () )
+@@ -153,11 +194,21 @@
+ 	
+ 			XMPP::Message message;
+ 	
+-			message.setFrom ( fromJid );
++			message.setFrom ( account()->client()->jid() );
+ 			message.setTo ( toJid );
+ 			message.setEventId ( contact->lastReceivedMessageId () );
+ 			// store composing event depending on state
+ 			message.addEvent ( event );
++			
++			if (view() && view()->plugin()->pluginId() == "kopete_emailwindow" )
++			{	
++				message.setType ( "normal" );
++			}
++			else
++			{	
++				message.setType ( "chat" );
++			}
++
+ 	
+ 			// send message
+ 			account()->client()->sendMessage ( message );
+@@ -172,7 +223,7 @@
+ 		return;
+ 
+ 	// create JID for us as sender
+-	XMPP::Jid fromJid ( myself()->contactId () );
++	XMPP::Jid fromJid = static_cast<const JabberBaseContact*>(myself())->rosterItem().jid();
+ 	fromJid.setResource ( account()->configGroup()->readEntry( "Resource", QString::null ) );
+ 
+ 	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Sending out typing notification (" << typing << ") to all chat members." << endl;
+@@ -186,14 +237,13 @@
+ 	if( account()->isConnected () )
+ 	{
+ 		XMPP::Message jabberMessage;
+-		Kopete::Contact *recipient = message.to().first ();
++		JabberBaseContact *recipient = static_cast<JabberBaseContact*>(message.to().first());
+ 
+-		XMPP::Jid jid ( message.from()->contactId () );
+-		jid.setResource ( account()->configGroup()->readEntry( "Resource", QString::null ) );
+-		jabberMessage.setFrom ( jid );
++		jabberMessage.setFrom ( account()->client()->jid() );
+ 
+-		XMPP::Jid toJid ( recipient->contactId () );
+ 
++		XMPP::Jid toJid = recipient->rosterItem().jid();
++
+ 		if( !resource().isEmpty () )
+ 			toJid.setResource ( resource() );
+ 
+@@ -227,8 +277,30 @@
+         else
+         {
+ 			// this message is not encrypted
+-			jabberMessage.setBody ( message.plainBody () );
+-        }
++			jabberMessage.setBody ( message.plainBody ());
++			if (message.format() ==  Kopete::Message::RichText) 
++			{
++				JabberResource *bestResource = account()->resourcePool()->bestJabberResource(toJid);
++				if( bestResource && bestResource->features().canXHTML() )
++				{
++					QString xhtmlBody = message.escapedBody();
++					
++					// According to JEP-0071 8.9  it is only RECOMMANDED to replace \n with <br/>
++					//  which mean that some implementation (gaim 2 beta) may still think that \n are linebreak.  
++					// and considered the fact that KTextEditor generate a well indented XHTML, we need to remove all \n from it
++					//  see Bug 121627
++					// Anyway, theses client that do like that are *WRONG*  considreded the example of jep-71 where there are lot of
++					// linebreak that are not interpreted.  - Olivier 2006-31-03
++					xhtmlBody.replace("\n","");
++					
++					//&nbsp; is not a valid XML entity
++					xhtmlBody.replace("&nbsp;" , "&#160;");
++							
++					xhtmlBody="<p "+ message.getHtmlStyleAttribute() +">"+ xhtmlBody +"</p>";
++					jabberMessage.setXHTMLBody ( xhtmlBody );
++				}
++        	}
++		}
+ 
+ 		// determine type of the widget and set message type accordingly
+ 		// "kopete_emailwindow" is the default email Kopete::ViewPlugin.  If other email plugins
+@@ -273,6 +345,12 @@
+ 
+ }
+ 
++ void JabberChatSession::slotSendFile()
++      {
++              QPtrList<Kopete::Contact>contacts = members();
++              static_cast<JabberContact *>(contacts.first())->sendFile();
++      }
++
+ #include "jabberchatsession.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/jabber/icons/Makefile.am	(revision 568672)
++++ kopete/protocols/jabber/icons/Makefile.am	(revision 586398)
+@@ -1,2 +1 @@
+-kopeteicondir = $(kde_datadir)/kopete/icons
+-kopeteicon_ICON = AUTO
++KDE_ICON=AUTO
+\ No newline at end of file
+--- kopete/protocols/jabber/jabbercontactpool.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabbercontactpool.cpp	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabbercontactpool.cpp
+   *
+   * Copyright (c) 2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -20,6 +21,8 @@
+ #include <qptrlist.h>
+ #include <kdebug.h>
+ #include <kmessagebox.h>
++#include <kopeteaccountmanager.h>
++#include <kopetecontactlist.h>
+ #include "kopeteuiglobal.h"
+ #include "jabberprotocol.h"
+ #include "jabberbasecontact.h"
+@@ -28,6 +31,7 @@
+ #include "jabbergroupmembercontact.h"
+ #include "jabberresourcepool.h"
+ #include "jabberaccount.h"
++#include "jabbertransport.h"
+ 
+ JabberContactPool::JabberContactPool ( JabberAccount *account )
+ {
+@@ -49,7 +53,7 @@
+ 	// see if the contact already exists
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( mContactItem->contact()->contactId().lower() == contact.jid().full().lower() )
++		if ( mContactItem->contact()->rosterItem().jid().full().lower() == contact.jid().full().lower() )
+ 		{
+ 			return mContactItem;
+ 		}
+@@ -61,12 +65,11 @@
+ 
+ JabberContact *JabberContactPool::addContact ( const XMPP::RosterItem &contact, Kopete::MetaContact *metaContact, bool dirty )
+ {
+-
+ 	// see if the contact already exists
+ 	JabberContactPoolItem *mContactItem = findPoolItem ( contact );
+ 	if ( mContactItem)
+ 	{
+-		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << contact.jid().full() << endl;
++		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << contact.jid().full() << "   -  " <<   mContactItem->contact() << endl;
+ 
+ 		// It exists, update it.
+ 		mContactItem->contact()->updateContact ( contact );
+@@ -86,9 +89,18 @@
+ 	}
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Adding new contact " << contact.jid().full() << endl;
+-
++	
++	JabberTransport *transport=0l;
++	QString legacyId;
++	//find if the contact should be added to a transport.
++	if(mAccount->transports().contains(contact.jid().domain()))
++	{
++		transport=mAccount->transports()[contact.jid().domain()];
++		legacyId=transport->legacyId( contact.jid() );
++	}
++		
+ 	// create new contact instance and add it to the dictionary
+-	JabberContact *newContact = new JabberContact ( contact, mAccount, metaContact );
++	JabberContact *newContact = new JabberContact ( contact, transport ? (Kopete::Account*)transport : (Kopete::Account*)mAccount, metaContact , legacyId );
+ 	JabberContactPoolItem *newContactItem = new JabberContactPoolItem ( newContact );
+ 	connect ( newContact, SIGNAL ( contactDestroyed ( Kopete::Contact * ) ), this, SLOT ( slotContactDestroyed ( Kopete::Contact * ) ) );
+ 	newContactItem->setDirty ( dirty );
+@@ -107,13 +119,34 @@
+ 	JabberContactPoolItem *mContactItem = findPoolItem ( mContact );
+ 	if ( mContactItem)
+ 	{
+-		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << mContact.jid().full() << endl;
++		if(mContactItem->contact()->inherits(roomContact ?
++				 (const char*)("JabberGroupContact") : (const char*)("JabberGroupMemberContact") ) )
++		{
++			
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << mContact.jid().full() << endl;
++			
++			// It exists, update it.
++			mContactItem->contact()->updateContact ( mContact );
++			mContactItem->setDirty ( dirty );
++	
++			//we must tell to the originating function that no new contact has been added
++			return 0L;//mContactItem->contact ();
++		}
++		else
++		{
++			//this happen if we receive a MUC invitaiton:  when the invitaiton is received, it's from the muc itself
++			//and then kopete will create a temporary contact for it. but it will not be a good contact.
++			kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Bad contact will be removed and re-added " << mContact.jid().full() << endl;
++			Kopete::MetaContact *old_mc=mContactItem->contact()->metaContact();
++			delete mContactItem->contact();
++			mContactItem = 0L;
++			if(old_mc->contacts().isEmpty() && old_mc!=metaContact)
++			{
++				Kopete::ContactList::self()->removeMetaContact( old_mc );
++			}
++			
++		}
+ 
+-		// It exists, update it.
+-		mContactItem->contact()->updateContact ( mContact );
+-		mContactItem->setDirty ( dirty );
+-
+-		return mContactItem->contact ();
+ 	}
+ 
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Adding new contact " << mContact.jid().full() << endl;
+@@ -143,13 +176,21 @@
+ 
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( mContactItem->contact()->contactId().lower() == jid.full().lower() )
++		if ( mContactItem->contact()->rosterItem().jid().full().lower() == jid.full().lower() )
+ 		{
+ 			/*
+ 			 * The following deletion will cause slotContactDestroyed()
+ 			 * to be called, which will clean the up the list.
+ 			 */
+-			delete mContactItem->contact ();
++			if(mContactItem->contact())
++			{
++				Kopete::MetaContact *mc=mContactItem->contact()->metaContact();
++				delete mContactItem->contact ();
++				if(mc && mc->contacts().isEmpty())
++				{
++					Kopete::ContactList::self()->removeMetaContact(mc) ;
++				}
++			}
+ 			return;
+ 		}
+ 	}
+@@ -162,7 +203,8 @@
+ {
+ 	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Contact deleted, collecting the pieces..." << endl;
+ 
+-	JabberBaseContact *jabberContact = static_cast<JabberBaseContact *>( contact );
++	JabberBaseContact *jabberContact = static_cast<JabberBaseContact *>( contact ); 
++	//WARNING  this ptr is not usable, we are in the Kopete::Contact destructor
+ 
+ 	// remove contact from the pool
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+@@ -175,7 +217,14 @@
+ 	}
+ 
+ 	// delete all resources for it
+-	mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contact->contactId() ) );
++	if(contact->account()==(Kopete::Account*)(mAccount))
++		mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contact->contactId() ) );
++	else
++	{
++		//this is a legacy contact. we have no way to get the real Jid at this point, we can only guess it.
++		QString contactId= contact->contactId().replace('@','%') + "@" + contact->account()->myself()->contactId();
++		mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contactId ) ) ;
++	}
+ 
+ }
+ 
+@@ -201,7 +250,7 @@
+ 
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( mContactItem->contact()->contactId().lower() == jid.full().lower() )
++		if ( mContactItem->contact()->rosterItem().jid().full().lower() == jid.full().lower() )
+ 		{
+ 			mContactItem->setDirty ( dirty );
+ 			return;
+@@ -237,7 +286,7 @@
+ 
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( mContactItem->contact()->contactId().lower () == jid.full().lower () )
++		if ( mContactItem->contact()->rosterItem().jid().full().lower () == jid.full().lower () )
+ 		{
+ 			return mContactItem->contact ();
+ 		}
+@@ -252,7 +301,7 @@
+ 
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( mContactItem->contact()->contactId().lower () == jid.userHost().lower () )
++		if ( mContactItem->contact()->rosterItem().jid().full().lower () == jid.userHost().lower () )
+ 		{
+ 			return mContactItem->contact ();
+ 		}
+@@ -268,7 +317,7 @@
+ 
+ 	for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
+ 	{
+-		if ( XMPP::Jid ( mContactItem->contact()->contactId() ).userHost().lower () == jid.userHost().lower () )
++		if ( mContactItem->contact()->rosterItem().jid().userHost().lower () == jid.userHost().lower () )
+ 		{
+ 			list.append ( mContactItem->contact () );
+ 		}
+--- kopete/protocols/jabber/jabberbasecontact.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberbasecontact.cpp	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabbercontact.cpp  -  Base class for the Kopete Jabber protocol contact
+   *
+   * Copyright (c) 2002-2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c)      2006 by Olivier Goffart <ogoffart at kde.org>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -18,7 +19,14 @@
+ #include <kdebug.h>
+ #include <klocale.h>
+ #include <kiconloader.h>
++#include <kstandarddirs.h>
++#include <qtimer.h>
++#include <qimage.h>
++#include <qregexp.h>
++#include <kmessagebox.h>
++#include <kio/netaccess.h>
+ 
++
+ #include <kopetegroup.h>
+ #include <kopetecontactlist.h>
+ 
+@@ -32,44 +40,42 @@
+ #include "jabberresourcepool.h"
+ #include "kopetemetacontact.h"
+ #include "kopetemessage.h"
++#include "kopeteuiglobal.h"
++#include "jabbertransport.h"
++#include "dlgjabbervcard.h"
+ 
++
+ /**
+  * JabberBaseContact constructor
+  */
+-JabberBaseContact::JabberBaseContact (const XMPP::RosterItem &rosterItem, JabberAccount *account, Kopete::MetaContact * mc)
+-				: Kopete::Contact (account, rosterItem.jid().full(), mc)
++JabberBaseContact::JabberBaseContact (const XMPP::RosterItem &rosterItem, Kopete::Account *account, Kopete::MetaContact * mc, const QString &legacyId)
++	: Kopete::Contact (account, legacyId.isEmpty() ? rosterItem.jid().full() : legacyId , mc )
+ {
+-
+ 	setDontSync ( false );
++	
++	JabberTransport *t=transport();
++	m_account= t ? t->account() : static_cast<JabberAccount *>(Kopete::Contact::account());
+ 
++
+ 	// take roster item and update display name
+ 	updateContact ( rosterItem );
+ 
+-	// since we're not in the account's contact pool yet
+-	// (we'll only be once we returned from this constructor),
+-	// we need to force an update to our status here
+-	// FIXME: libkopete doesn't allow us to use this call
+-	// here anymore as it causes an invocation of manager()
+-	// which is still a pure virtual in this constructor.
+-	// (needs to be done in subclasses instead)
+-	//reevaluateStatus ();
+-
+ }
+ 
++
+ JabberProtocol *JabberBaseContact::protocol ()
+ {
+ 
+ 	return static_cast<JabberProtocol *>(Kopete::Contact::protocol ());
+-
+ }
+ 
+-JabberAccount *JabberBaseContact::account ()
++
++JabberTransport * JabberBaseContact::transport( )
+ {
++	return dynamic_cast<JabberTransport*>(Kopete::Contact::account());
++}
+ 
+-	return static_cast<JabberAccount *>(Kopete::Contact::account ());
+ 
+-}
+-
+ /* Return if we are reachable (defaults to true because
+    we can send on- and offline, only return false if the
+    account itself is offline, too) */
+@@ -106,8 +112,14 @@
+ 		// only update the alias if its not empty
+ 		if ( !item.name().isEmpty () && item.name() != item.jid().bare() )
+ 		{
+-			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "setting display name of " << contactId () << " to " << item.name() << endl;
+-			metaContact()->setDisplayName ( item.name () );
++			QString newName = item.name ();
++			QString oldName = metaContact()->displayName();
++			Kopete::Contact *source=metaContact()->displayNameSourceContact();
++//			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "setting display name of " << contactId () << " to " << newName << endl;
++			metaContact()->setDisplayName ( newName );
++			//automatically set  to custom source if the source is to this contact.
++			if( metaContact()->displayNameSource()==Kopete::MetaContact::SourceContact && newName != oldName && ( source == this || source == 0L  ) )
++				metaContact()->setDisplayNameSource( Kopete::MetaContact::SourceCustom );
+ 		}
+ 	}
+ 
+@@ -134,78 +146,83 @@
+ 			break;
+ 	}
+ 
+-	/*
+-	 * In this method, as opposed to KC::syncGroups(),
+-	 * the group list from the server is authoritative.
+-	 * As such, we need to find a list of all groups
+-	 * that the meta contact resides in but does not
+-	 * reside in on the server anymore, as well as all
+-	 * groups that the meta contact does not reside in,
+-	 * but resides in on the server.
+-	 * Then, we'll have to synchronize the KMC using
+-	 * that information.
+-	 */
+-	Kopete::GroupList groupsToRemoveFrom, groupsToAddTo;
+-
+-	// find all groups our contact is in but that are not in the server side roster
+-	for ( unsigned i = 0; i < metaContact()->groups().count (); i++ )
++	if( !metaContact()->isTemporary() )
+ 	{
+-		if ( item.groups().find ( metaContact()->groups().at(i)->displayName () ) == item.groups().end () )
+-			groupsToRemoveFrom.append ( metaContact()->groups().at ( i ) );
+-	}
+-
+-	// now find all groups that are in the server side roster but not in the local group
+-	for ( unsigned i = 0; i < item.groups().count (); i++ )
+-	{
+-		bool found = false;
+-		for ( unsigned j = 0; j < metaContact()->groups().count (); j++)
++		/*
++		* In this method, as opposed to KC::syncGroups(),
++		* the group list from the server is authoritative.
++		* As such, we need to find a list of all groups
++		* that the meta contact resides in but does not
++		* reside in on the server anymore, as well as all
++		* groups that the meta contact does not reside in,
++		* but resides in on the server.
++		* Then, we'll have to synchronize the KMC using
++		* that information.
++		*/
++		Kopete::GroupList groupsToRemoveFrom, groupsToAddTo;
++	
++		// find all groups our contact is in but that are not in the server side roster
++		for ( unsigned i = 0; i < metaContact()->groups().count (); i++ )
+ 		{
+-			if ( metaContact()->groups().at(j)->displayName () == *item.groups().at(i) )
++			if ( item.groups().find ( metaContact()->groups().at(i)->displayName () ) == item.groups().end () )
++				groupsToRemoveFrom.append ( metaContact()->groups().at ( i ) );
++		}
++	
++		// now find all groups that are in the server side roster but not in the local group
++		for ( unsigned i = 0; i < item.groups().count (); i++ )
++		{
++			bool found = false;
++			for ( unsigned j = 0; j < metaContact()->groups().count (); j++)
+ 			{
+-				found = true;
+-				break;
++				if ( metaContact()->groups().at(j)->displayName () == *item.groups().at(i) )
++				{
++					found = true;
++					break;
++				}
+ 			}
++			
++			if ( !found )
++			{
++				groupsToAddTo.append ( Kopete::ContactList::self()->findGroup ( *item.groups().at(i) ) );
++			}
+ 		}
+-		
+-		if ( !found )
++	
++		/*
++		* Special case: if we don't add the contact to any group and the
++		* list of groups to remove from contains the top level group, we
++		* risk removing the contact from the visible contact list. In this
++		* case, we need to make sure at least the top level group stays.
++		*/
++		if ( ( groupsToAddTo.count () == 0 ) && ( groupsToRemoveFrom.contains ( Kopete::Group::topLevel () ) ) )
+ 		{
+-			groupsToAddTo.append ( Kopete::ContactList::self()->findGroup ( *item.groups().at(i) ) );
++			groupsToRemoveFrom.remove ( Kopete::Group::topLevel () );
+ 		}
++	
++		for ( Kopete::Group *group = groupsToRemoveFrom.first (); group; group = groupsToRemoveFrom.next () )
++		{
++			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Removing " << contactId() << " from group " << group->displayName () << endl;
++			metaContact()->removeFromGroup ( group );
++		}
++	
++		for ( Kopete::Group *group = groupsToAddTo.first (); group; group = groupsToAddTo.next () )
++		{
++			kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Adding " << contactId() << " to group " << group->displayName () << endl;
++			metaContact()->addToGroup ( group );
++		}
+ 	}
+ 
+ 	/*
+-	 * Special case: if we don't add the contact to any group and the
+-	 * list of groups to remove from contains the top level group, we
+-	 * risk removing the contact from the visible contact list. In this
+-	 * case, we need to make sure at least the top level group stays.
+-	 */
+-	if ( ( groupsToAddTo.count () == 0 ) && ( groupsToRemoveFrom.contains ( Kopete::Group::topLevel () ) ) )
+-	{
+-		groupsToRemoveFrom.remove ( Kopete::Group::topLevel () );
+-	}
+-
+-	for ( Kopete::Group *group = groupsToRemoveFrom.first (); group; group = groupsToRemoveFrom.next () )
+-	{
+-		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Removing " << contactId() << " from group " << group->displayName () << endl;
+-		metaContact()->removeFromGroup ( group );
+-	}
+-
+-	for ( Kopete::Group *group = groupsToAddTo.first (); group; group = groupsToAddTo.next () )
+-	{
+-		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Adding " << contactId() << " to group " << group->displayName () << endl;
+-		metaContact()->addToGroup ( group );
+-	}
+-
+-	/*
+ 	 * Enable updates for the server again.
+ 	 */
+ 	setDontSync ( false );
++	
++	//can't do it now because it's called from contructor at a point some virtual function are not available
++	QTimer::singleShot(0, this, SLOT(reevaluateStatus()));
+ 
+ }
+ 
+ void JabberBaseContact::updateResourceList ()
+ {
+-
+ 	/*
+ 	 * Set available resources.
+ 	 * This is a bit more complicated: We need to generate
+@@ -214,7 +231,7 @@
+ 	 * the richtext.
+ 	 */
+ 	JabberResourcePool::ResourceList resourceList;
+-	account()->resourcePool()->findResources ( XMPP::Jid ( contactId () ), resourceList );
++	account()->resourcePool()->findResources ( rosterItem().jid() , resourceList );
+ 
+ 	if ( resourceList.isEmpty () )
+ 	{
+@@ -237,7 +254,27 @@
+ 			resourceListStr += QString ( "<tr><td>%1: %2 (%3)</td></tr>" ).
+ 							   arg ( i18n ( "Client" ), (*it)->clientName (), (*it)->clientSystem () );
+ 		}
+-
++		
++		// Supported features
++#if 0  //disabled because it's just an ugly and long list of incomprehensible namespaces to the user
++		QStringList supportedFeatures = (*it)->features().list();
++		QStringList::ConstIterator featuresIt, featuresItEnd = supportedFeatures.constEnd();
++		if( !supportedFeatures.empty() )
++			resourceListStr += QString( "<tr><td>Supported Features:" );
++		for( featuresIt = supportedFeatures.constBegin(); featuresIt != featuresItEnd; ++featuresIt )
++		{
++			XMPP::Features tempFeature(*featuresIt);
++			resourceListStr += QString("\n<br>");
++			if ( tempFeature.id() > XMPP::Features::FID_None )
++				resourceListStr += tempFeature.name() + QString(" (");
++			resourceListStr += *featuresIt;
++			if ( tempFeature.id() > Features::FID_None )
++				resourceListStr += QString(")");	
++		}
++		if( !supportedFeatures.empty() )
++			resourceListStr += QString( "</td></tr>" );
++#endif
++		
+ 		// resource timestamp
+ 		resourceListStr += QString ( "<tr><td>%1: %2</td></tr>" ).
+ 						   arg ( i18n ( "Timestamp" ), KGlobal::locale()->formatDateTime ( (*it)->resource().status().timeStamp(), true, true ) );
+@@ -266,6 +303,20 @@
+ 	XMPP::Resource resource = account()->resourcePool()->bestResource ( mRosterItem.jid () );
+ 
+ 	status = protocol()->resourceToKOS ( resource );
++	
++	
++	/* Add some icon to show the subscription */ 
++	if( ( mRosterItem.subscription().type() == XMPP::Subscription::None || mRosterItem.subscription().type() == XMPP::Subscription::From)
++			 && inherits ( "JabberContact" ) && metaContact() != Kopete::ContactList::self()->myself() && account()->isConnected() )
++	{
++		status = Kopete::OnlineStatus(status.status() ,
++									  status.weight() ,
++									  protocol() ,
++									  status.internalStatus() | 0x0100,
++									  status.overlayIcons() + QStringList("status_unknown_overlay") , //FIXME: find better icon
++									  status.description() );
++	}
++	
+ 
+ 	updateResourceList ();
+ 
+@@ -290,7 +341,7 @@
+ QString JabberBaseContact::fullAddress ()
+ {
+ 
+-	XMPP::Jid jid ( contactId () );
++	XMPP::Jid jid = rosterItem().jid();
+ 
+ 	if ( jid.resource().isEmpty () )
+ 	{
+@@ -337,11 +388,289 @@
+ {
+ 
+ 	// Contact id and display name are already set for us, only add the rest
+-	serializedData["identityId"] = account()->accountId();
++	serializedData["JID"] = mRosterItem.jid().full();
+ 
+ 	serializedData["groups"] = mRosterItem.groups ().join (QString::fromLatin1 (","));
+ }
+ 
++void JabberBaseContact::slotUserInfo( )
++{
++	if ( !account()->isConnected () )
++	{
++		account()->errorConnectFirst ();
++		return;
++	}
++	
++	// Update the vCard
++	//slotGetTimedVCard();
++
++	new dlgJabberVCard ( account(), this, Kopete::UI::Global::mainWidget () );
++}
++
++void JabberBaseContact::setPropertiesFromVCard ( const XMPP::VCard &vCard )
++{
++	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Updating vCard for " << contactId () << endl;
++
++	// update vCard cache timestamp if this is not a temporary contact
++	if ( metaContact() && !metaContact()->isTemporary () )
++	{
++		setProperty ( protocol()->propVCardCacheTimeStamp, QDateTime::currentDateTime().toString ( Qt::ISODate ) );
++	}
++
++	
++	/*
++	* Set the nickname property.
++	*  but ignore it if we are in a groupchat, or it will clash with the normal nickname
++	*/
++	if(inherits ( "JabberContact" ))
++	{
++		if ( !vCard.nickName().isEmpty () )
++		{
++			setProperty ( protocol()->propNickName, vCard.nickName () );
++		}
++		else
++		{
++			removeProperty ( protocol()->propNickName );
++		}
++	}
++
++	/**
++	 * Kopete does not allow a modification of the "full name"
++	 * property. However, some vCards specify only the full name,
++	 * some specify only first and last name.
++	 * Due to these inconsistencies, if first and last name don't
++	 * exist, it is attempted to parse the full name.
++	 */
++
++	// remove all properties first
++	removeProperty ( protocol()->propFirstName );
++	removeProperty ( protocol()->propLastName );
++	removeProperty ( protocol()->propFullName );
++
++	if ( !vCard.fullName().isEmpty () && vCard.givenName().isEmpty () && vCard.familyName().isEmpty () )
++	{
++		QString lastName = vCard.fullName().section ( ' ', 0, -1 );
++		QString firstName = vCard.fullName().left(vCard.fullName().length () - lastName.length ()).stripWhiteSpace ();
++
++		setProperty ( protocol()->propFirstName, firstName );
++		setProperty ( protocol()->propLastName, lastName );
++	}
++	else
++	{
++		if ( !vCard.givenName().isEmpty () )
++			setProperty ( protocol()->propFirstName, vCard.givenName () );
++
++		if ( !vCard.familyName().isEmpty () )
++			setProperty ( protocol()->propLastName, vCard.familyName () );
++	}
++	if( !vCard.fullName().isEmpty() )
++		setProperty ( protocol()->propFullName, vCard.fullName() );
++
++	/* 
++	* Set the general information 
++	*/
++	removeProperty( protocol()->propJid );
++	removeProperty( protocol()->propBirthday );
++	removeProperty( protocol()->propTimezone );
++	removeProperty( protocol()->propHomepage );
++
++	setProperty( protocol()->propJid, vCard.jid() );
++	
++	if( !vCard.bdayStr().isEmpty () )
++		setProperty( protocol()->propBirthday, vCard.bdayStr() );
++	if( !vCard.timezone().isEmpty () )
++		setProperty( protocol()->propTimezone, vCard.timezone() );
++	if( !vCard.url().isEmpty () )
++		setProperty( protocol()->propHomepage, vCard.url() );
++
++	/*
++	* Set the work information.
++	*/
++	removeProperty( protocol()->propCompanyName );
++	removeProperty( protocol()->propCompanyDepartement );
++	removeProperty( protocol()->propCompanyPosition );
++	removeProperty( protocol()->propCompanyRole );
++	
++	if( !vCard.org().name.isEmpty() )
++		setProperty( protocol()->propCompanyName, vCard.org().name );
++	if( !vCard.org().unit.join(",").isEmpty() )
++		setProperty( protocol()->propCompanyDepartement, vCard.org().unit.join(",")) ;
++	if( !vCard.title().isEmpty() )
++		setProperty( protocol()->propCompanyPosition, vCard.title() );
++	if( !vCard.role().isEmpty() )
++		setProperty( protocol()->propCompanyRole, vCard.role() );
++
++	/*
++	* Set the about information
++	*/
++	removeProperty( protocol()->propAbout );
++
++	if( !vCard.desc().isEmpty() )
++		setProperty( protocol()->propAbout, vCard.desc() );
++
++	
++	/*
++	* Set the work and home addresses information
++	*/
++	removeProperty( protocol()->propWorkStreet );
++	removeProperty( protocol()->propWorkExtAddr );
++	removeProperty( protocol()->propWorkPOBox );
++	removeProperty( protocol()->propWorkCity );
++	removeProperty( protocol()->propWorkPostalCode );
++	removeProperty( protocol()->propWorkCountry );
++
++	removeProperty( protocol()->propHomeStreet );
++	removeProperty( protocol()->propHomeExtAddr );
++	removeProperty( protocol()->propHomePOBox );
++	removeProperty( protocol()->propHomeCity );
++	removeProperty( protocol()->propHomePostalCode );
++	removeProperty( protocol()->propHomeCountry );
++
++	for(XMPP::VCard::AddressList::const_iterator it = vCard.addressList().begin(); it != vCard.addressList().end(); it++)
++	{
++		XMPP::VCard::Address address = (*it);
++
++		if(address.work)
++		{
++			setProperty( protocol()->propWorkStreet, address.street );
++			setProperty( protocol()->propWorkExtAddr, address.extaddr );
++			setProperty( protocol()->propWorkPOBox, address.pobox );
++			setProperty( protocol()->propWorkCity, address.locality );
++			setProperty( protocol()->propWorkPostalCode, address.pcode );
++			setProperty( protocol()->propWorkCountry, address.country );
++		}
++		else
++			if(address.home)
++		{
++			setProperty( protocol()->propHomeStreet, address.street );
++			setProperty( protocol()->propHomeExtAddr, address.extaddr );
++			setProperty( protocol()->propHomePOBox, address.pobox );
++			setProperty( protocol()->propHomeCity, address.locality );
++			setProperty( protocol()->propHomePostalCode, address.pcode );
++			setProperty( protocol()->propHomeCountry, address.country );
++		}
++	}
++
++
++	/*
++	* Delete emails first, they might not be present
++	* in the vCard at all anymore.
++	*/
++	removeProperty ( protocol()->propEmailAddress );
++	removeProperty ( protocol()->propWorkEmailAddress );
++
++	/*
++	* Set the home and work email information.
++	*/
++	XMPP::VCard::EmailList::const_iterator emailEnd = vCard.emailList().end ();
++	for(XMPP::VCard::EmailList::const_iterator it = vCard.emailList().begin(); it != emailEnd; ++it)
++	{
++		XMPP::VCard::Email email = (*it);
++		
++		if(email.work)
++		{
++			if( !email.userid.isEmpty() )
++				setProperty ( protocol()->propWorkEmailAddress, email.userid );
++		}
++		else
++			if(email.home)
++		{	
++			if( !email.userid.isEmpty() )
++				setProperty ( protocol()->propEmailAddress, email.userid );
++		}
++	}
++
++	/*
++	* Delete phone number properties first as they might have
++	* been unset during an update and are not present in
++	* the vCard at all anymore.
++	*/
++	removeProperty ( protocol()->propPrivatePhone );
++	removeProperty ( protocol()->propPrivateMobilePhone );
++	removeProperty ( protocol()->propWorkPhone );
++	removeProperty ( protocol()->propWorkMobilePhone );
++
++	/*
++	* Set phone numbers. Note that if a mobile phone number
++	* is specified, it's assigned to the private mobile
++	* phone number property. This might not be the desired
++	* behavior for all users.
++	*/
++	XMPP::VCard::PhoneList::const_iterator phoneEnd = vCard.phoneList().end ();
++	for(XMPP::VCard::PhoneList::const_iterator it = vCard.phoneList().begin(); it != phoneEnd; ++it)
++	{
++		XMPP::VCard::Phone phone = (*it);
++
++		if(phone.work)
++		{
++			setProperty ( protocol()->propWorkPhone, phone.number );
++		}
++		else
++			if(phone.fax)
++		{
++			setProperty ( protocol()->propPhoneFax, phone.number);
++		}
++		else
++			if(phone.cell)
++		{
++			setProperty ( protocol()->propPrivateMobilePhone, phone.number );
++		}
++		else
++			if(phone.home)
++		{
++			setProperty ( protocol()->propPrivatePhone, phone.number );
++		}
++
++	}
++
++	/*
++	* Set photo/avatar property.
++	*/
++	removeProperty( protocol()->propPhoto );
++
++	QImage contactPhoto;
++	QString fullJid =  mRosterItem.jid().full();
++	QString finalPhotoPath = locateLocal("appdata", "jabberphotos/" + fullJid.replace(QRegExp("[./~]"),"-")  +".png");
++	
++	// photo() is a QByteArray
++	if ( !vCard.photo().isEmpty() )
++	{
++		kdDebug( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Contact has a photo embedded into his vCard." << endl;
++
++		// QImage is used to save to disk in PNG later.
++		contactPhoto = QImage( vCard.photo() );
++	}
++	// Contact photo is a URI.
++	else if( !vCard.photoURI().isEmpty() )
++	{
++		QString tempPhotoPath = 0;
++		
++		// Downalod photo from URI.
++		if( !KIO::NetAccess::download( vCard.photoURI(), tempPhotoPath, 0) ) 
++		{
++			KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget (), KMessageBox::Sorry, i18n( "Downloading of Jabber contact photo failed!" ) );
++			return;
++		}
++
++		kdDebug( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Contact photo is a URI." << endl;
++
++		contactPhoto = QImage( tempPhotoPath );
++		
++		KIO::NetAccess::removeTempFile(  tempPhotoPath );
++	}
++
++	// Save the image to the disk, then set the property.
++	if( !contactPhoto.isNull() && contactPhoto.save(finalPhotoPath, "PNG") )
++	{
++		kdDebug( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Setting photo for contact: " << fullJid << endl;
++		setProperty( protocol()->propPhoto, finalPhotoPath );
++	}
++
++}
++
++
++
++
+ #include "jabberbasecontact.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/jabber/jabberresourcepool.h	(revision 568672)
++++ kopete/protocols/jabber/jabberresourcepool.h	(revision 586398)
+@@ -2,6 +2,7 @@
+   * jabberresourcepool.h
+   *
+   * Copyright (c) 2004 by Till Gerken <till at tantalo.net>
++  * Copyright (c) 2006 by Michaël Larouche <michael.larouche at kdemail.net>
+   *
+   * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
+   *
+@@ -26,12 +27,11 @@
+ 
+ /**
+  * @author Till Gerken <till at tantalo.net>
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
+  */
+ class JabberResourcePool : public QObject
+ {
+-
+-Q_OBJECT
+-
++	Q_OBJECT
+ public:
+ 	static XMPP::Resource EmptyResource;
+ 
+@@ -86,11 +86,26 @@
+ 	void removeLock ( const XMPP::Jid &jid );
+ 
+ 	/**
++	 * Return the JabberResource instance for the locked resource, if any.
++	 */
++	 JabberResource *lockedJabberResource( const XMPP::Jid &jid );
++
++	/**
+ 	 * Return currently locked resource, if any
+ 	 */
+ 	const XMPP::Resource &lockedResource ( const XMPP::Jid &jid );
+ 
+ 	/**
++	 * Return a usable JabberResource for a given JID.
++	 *
++	 * @param jid Jid to look for the best resource.
++	 * @param honourLock Honour the resource locked by the user.
++	 * 
++	 * @return a JabberResource instance.
++	 */
++	JabberResource *bestJabberResource( const XMPP::Jid &jid, bool honourLock = true );
++
++	/**
+ 	 * Return usable resource for a given JID
+ 	 * Matches by userHost(), honours locks for a JID by default
+ 	 */
+@@ -101,17 +116,14 @@
+ 	 */
+ 	void findResources ( const XMPP::Jid &jid, JabberResourcePool::ResourceList &resourceList );
+ 	void findResources ( const XMPP::Jid &jid, XMPP::ResourceList &resourceList );
+-
++	
+ private slots:
+ 	void slotResourceDestroyed ( QObject *sender );
+ 	void slotResourceUpdated ( JabberResource *resource );
+-
++	
+ private:
+-	QPtrList<JabberResource> mPool;
+-	QPtrList<JabberResource> mLockList;
+-
+-	JabberAccount *mAccount;
+-
++	class Private;
++	Private *d;
+ };
+ 
+ #endif
+--- kopete/protocols/jabber/ui/dlgjabberbrowse.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberbrowse.cpp	(revision 586398)
+@@ -60,7 +60,7 @@
+ 
+ 	if (!task->success ())
+ 	{
+-		KMessageBox::information (this, i18n ("Unable to retrieve search form."), i18n ("Jabber Error"));
++		KMessageBox::queuedMessageBox(this, KMessageBox::Information, i18n ("Unable to retrieve search form."), i18n ("Jabber Error"));
+ 
+ 		return;
+ 	}
+@@ -111,7 +111,7 @@
+ 
+ 	if (!task->success ())
+ 	{
+-		KMessageBox::error (this, i18n ("The Jabber server declined the search."), i18n ("Jabber Search"));
++		KMessageBox::queuedMessageBox (this, KMessageBox::Error, i18n ("The Jabber server declined the search."), i18n ("Jabber Search"));
+ 
+ 		return;
+ 	}
+--- kopete/protocols/jabber/ui/dlgjabberchatjoin.h	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberchatjoin.h	(revision 586398)
+@@ -19,28 +19,47 @@
+ #ifndef DLGJABBERCHATJOIN_H
+ #define DLGJABBERCHATJOIN_H
+ 
+-#include <kdialogbase.h>
++#include "dlgchatjoin.h"
+ #include "jabberaccount.h"
+ 
+-/**
+-  *@author Till Gerken <till at tantalo.net>
+-  */
+-
+-class dlgJabberChatJoin : public KDialogBase
++class dlgJabberChatJoin : public dlgChatJoin
+ {
++  Q_OBJECT
+ 
+-	Q_OBJECT
+-
+ public:
+-	  dlgJabberChatJoin (JabberAccount *account, QWidget * parent = 0, const char *name = 0);
++  dlgJabberChatJoin(JabberAccount *account, QWidget* parent = 0, const char* name = 0);
++  ~dlgJabberChatJoin();
++  /*$PUBLIC_FUNCTIONS$*/
+ 
+-private slots:
+-	void slotOk ();
+-	void slotCancel ();
++public slots:
++  /*$PUBLIC_SLOTS$*/
++  virtual void          slotJoin();
++  virtual void          slotBowse();
+ 
++protected:
++  /*$PROTECTED_FUNCTIONS$*/
++
++protected slots:
++  /*$PROTECTED_SLOTS$*/
++
+ private:
++	
++
+ 	JabberAccount *m_account;
+ 
++	/*
++		TODO : Used to look for the default chat server,
++		this is duplicate with dlgjabberservices.h
++		should be merged elsewhere !
++	*/
++	void checkDefaultChatroomServer();
++private slots:
++	void slotQueryFinished();
++	void slotDiscoFinished();
++
++	// end todo.
++
+ };
+ 
+ #endif
++
+--- kopete/protocols/jabber/ui/dlgservices.ui	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgservices.ui	(revision 586398)
+@@ -1,4 +1,4 @@
+-<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+ <class>dlgServices</class>
+ <widget class="QDialog">
+     <property name="name">
+@@ -83,40 +83,32 @@
+                 </widget>
+             </hbox>
+         </widget>
+-        <widget class="QTable">
++        <widget class="QListView">
++            <column>
++                <property name="text">
++                    <string>Jid</string>
++                </property>
++                <property name="clickable">
++                    <bool>true</bool>
++                </property>
++                <property name="resizable">
++                    <bool>true</bool>
++                </property>
++            </column>
++            <column>
++                <property name="text">
++                    <string>Name</string>
++                </property>
++                <property name="clickable">
++                    <bool>true</bool>
++                </property>
++                <property name="resizable">
++                    <bool>true</bool>
++                </property>
++            </column>
+             <property name="name">
+-                <cstring>tblServices</cstring>
++                <cstring>lvServices</cstring>
+             </property>
+-            <property name="enabled">
+-                <bool>true</bool>
+-            </property>
+-            <property name="focusPolicy">
+-                <enum>NoFocus</enum>
+-            </property>
+-            <property name="frameShape">
+-                <enum>StyledPanel</enum>
+-            </property>
+-            <property name="resizePolicy">
+-                <enum>Default</enum>
+-            </property>
+-            <property name="numRows">
+-                <number>0</number>
+-            </property>
+-            <property name="numCols">
+-                <number>2</number>
+-            </property>
+-            <property name="columnMovingEnabled">
+-                <bool>true</bool>
+-            </property>
+-            <property name="readOnly">
+-                <bool>true</bool>
+-            </property>
+-            <property name="selectionMode">
+-                <enum>NoSelection</enum>
+-            </property>
+-            <property name="focusStyle">
+-                <enum>FollowStyle</enum>
+-            </property>
+         </widget>
+         <widget class="QLayoutWidget">
+             <property name="name">
+--- kopete/protocols/jabber/ui/jabberregisteraccount.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/jabberregisteraccount.cpp	(revision 586398)
+@@ -374,7 +374,7 @@
+ 	else
+ 	{
+ 		mMainWidget->lblStatusMessage->setText ( i18n ( "Registration failed." ) );
+-		KMessageBox::information (Kopete::UI::Global::mainWidget (),
++		KMessageBox::queuedMessageBox (Kopete::UI::Global::mainWidget (), KMessageBox::Information,
+ 								  i18n ("Unable to create account on the server. The Jabber ID is probably already in use."),
+ 								  i18n ("Jabber Account Registration"));
+ 
+--- kopete/protocols/jabber/ui/jabberaddcontactpage.h	(revision 568672)
++++ kopete/protocols/jabber/ui/jabberaddcontactpage.h	(revision 586398)
+@@ -42,9 +42,27 @@
+ 	QLabel *noaddMsg1;
+ 	QLabel *noaddMsg2;
+ 	bool canadd;
++public slots:
++	void slotPromtReceived();
+ };
+ 
++class JabberTransport;
+ 
++/**
++ * @author Olivier Goffart
++ * this class is just there to workaround the fact that it's not possible to add contact assync with Kopete::AddContactPage::apply
++ */
++class  JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND : public QObject
++{ Q_OBJECT
++	public:
++		JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND( JabberTransport * , Kopete::MetaContact *mc, QObject *parent);
++		Kopete::MetaContact *metacontact;
++		JabberTransport *transport;
++	public slots:
++		void slotJidReceived();
++};
++
++
+ #endif
+ 
+ 
+--- kopete/protocols/jabber/ui/jabbereditaccountwidget.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/jabbereditaccountwidget.cpp	(revision 586398)
+@@ -86,6 +86,7 @@
+ 
+ 	mID->setText (account()->accountId ());
+ 	mPass->load (&account()->password ());
++	cbAutoConnect->setChecked (account()->excludeConnect());
+ 	
+ 	mResource->setText (account()->configGroup()->readEntry ("Resource", QString::fromLatin1("Kopete")));
+ 	mPriority->setValue (account()->configGroup()->readNumEntry ("Priority", 5));
+@@ -101,7 +102,9 @@
+ 
+ 	if(cbCustomServer->isChecked ())
+ 	{
++		labelServer->setEnabled(true);
+ 		mServer->setEnabled(true);
++		labelPort->setEnabled(true);
+ 		mPort->setEnabled(true);
+ 	}
+ 	else
+@@ -123,8 +126,12 @@
+ 	cbSendDeliveredEvent->setChecked( account()->configGroup()->readBoolEntry("SendDeliveredEvent", true) );
+ 	cbSendDisplayedEvent->setChecked( account()->configGroup()->readBoolEntry("SendDisplayedEvent", true) );
+ 	cbSendComposingEvent->setChecked( account()->configGroup()->readBoolEntry("SendComposingEvent", true) );
++	cbSendGoneEvent->setChecked( account()->configGroup()->readBoolEntry("SendGoneEvent", true) );
+ 
+ 	cbHideSystemInfo->setChecked( account()->configGroup()->readBoolEntry("HideSystemInfo", false) );
++
++	// Global Identity
++	cbGlobalIdentity->setChecked( account()->configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) );
+ }
+ 
+ Kopete::Account *JabberEditAccountWidget::apply ()
+@@ -138,7 +145,7 @@
+ 
+ 	if(account()->isConnected())
+ 	{
+-		KMessageBox::information(this,
++		KMessageBox::queuedMessageBox(this, KMessageBox::Information,
+ 					i18n("The changes you just made will take effect next time you log in with Jabber."),
+ 					i18n("Jabber Changes During Online Jabber Session"));
+ 	}
+@@ -182,9 +189,12 @@
+ 	account()->configGroup()->writeEntry("SendDeliveredEvent", cbSendDeliveredEvent->isChecked());
+ 	account()->configGroup()->writeEntry("SendDisplayedEvent", cbSendDisplayedEvent->isChecked());
+ 	account()->configGroup()->writeEntry("SendComposingEvent", cbSendComposingEvent->isChecked());
++	account()->configGroup()->writeEntry("SendGoneEvent", cbSendGoneEvent->isChecked());
+ 	
+ 	account()->configGroup()->writeEntry("HideSystemInfo", cbHideSystemInfo->isChecked());
+ 
++	// Global Identity
++	account()->configGroup()->writeEntry("ExcludeGlobalIdentity", cbGlobalIdentity->isChecked());
+ }
+ 
+ bool JabberEditAccountWidget::validateData ()
+@@ -212,12 +222,16 @@
+ 		// check if ssl is enabled and set the port correctly
+ 		sslToggled(cbUseSSL->isChecked());
+ 		mServer->setText(newServer);
++		labelServer->setEnabled(false);
+ 		mServer->setEnabled(false);
++		labelPort->setEnabled(false);
+ 		mPort->setEnabled(false);
+ 	}
+ 	else
+ 	{
++		labelServer->setEnabled(true);
+ 		mServer->setEnabled(true);
++		labelPort->setEnabled(true);
+ 		mPort->setEnabled(true);
+ 	}
+ 
+--- kopete/protocols/jabber/ui/dlgchatroomslist.ui	(revision 0)
++++ kopete/protocols/jabber/ui/dlgchatroomslist.ui	(revision 586398)
+@@ -0,0 +1,185 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>dlgChatRoomsList</class>
++<widget class="KDialog">
++    <property name="name">
++        <cstring>dlgChatRoomsList</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>467</width>
++            <height>298</height>
++        </rect>
++    </property>
++    <property name="caption">
++        <string>List Chatrooms</string>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout4</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel">
++                    <property name="name">
++                        <cstring>lblServer</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Server</string>
++                    </property>
++                </widget>
++                <widget class="QLineEdit">
++                    <property name="name">
++                        <cstring>leServer</cstring>
++                    </property>
++                </widget>
++                <widget class="QPushButton">
++                    <property name="name">
++                        <cstring>pbQuery</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Query</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++        <widget class="QTable">
++            <column>
++                <property name="text">
++                    <string>Chatroom Name</string>
++                </property>
++                <property name="pixmap">
++                    <pixmap></pixmap>
++                </property>
++            </column>
++            <column>
++                <property name="text">
++                    <string>Chatroom Description</string>
++                </property>
++                <property name="pixmap">
++                    <pixmap></pixmap>
++                </property>
++            </column>
++            <property name="name">
++                <cstring>tblChatRoomsList</cstring>
++            </property>
++            <property name="focusPolicy">
++                <enum>ClickFocus</enum>
++            </property>
++            <property name="numRows">
++                <number>0</number>
++            </property>
++            <property name="numCols">
++                <number>2</number>
++            </property>
++            <property name="rowMovingEnabled">
++                <bool>true</bool>
++            </property>
++            <property name="columnMovingEnabled">
++                <bool>true</bool>
++            </property>
++            <property name="readOnly">
++                <bool>true</bool>
++            </property>
++            <property name="selectionMode">
++                <enum>SingleRow</enum>
++            </property>
++            <property name="focusStyle">
++                <enum>FollowStyle</enum>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout5</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <spacer>
++                    <property name="name">
++                        <cstring>spacer2</cstring>
++                    </property>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
++                    </property>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
++                    </property>
++                    <property name="sizeHint">
++                        <size>
++                            <width>121</width>
++                            <height>21</height>
++                        </size>
++                    </property>
++                </spacer>
++                <widget class="QPushButton">
++                    <property name="name">
++                        <cstring>pbJoin</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Join</string>
++                    </property>
++                </widget>
++                <widget class="QPushButton">
++                    <property name="name">
++                        <cstring>pbClose</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Clos&amp;e</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++    </vbox>
++</widget>
++<connections>
++    <connection>
++        <sender>pbClose</sender>
++        <signal>clicked()</signal>
++        <receiver>dlgChatRoomsList</receiver>
++        <slot>close()</slot>
++    </connection>
++    <connection>
++        <sender>pbJoin</sender>
++        <signal>clicked()</signal>
++        <receiver>dlgChatRoomsList</receiver>
++        <slot>slotJoin()</slot>
++    </connection>
++    <connection>
++        <sender>pbQuery</sender>
++        <signal>clicked()</signal>
++        <receiver>dlgChatRoomsList</receiver>
++        <slot>slotQuery()</slot>
++    </connection>
++    <connection>
++        <sender>tblChatRoomsList</sender>
++        <signal>clicked(int,int,int,const QPoint&amp;)</signal>
++        <receiver>dlgChatRoomsList</receiver>
++        <slot>slotClick(int,int,int,const QPoint&amp;)</slot>
++    </connection>
++    <connection>
++        <sender>tblChatRoomsList</sender>
++        <signal>doubleClicked(int,int,int,const QPoint&amp;)</signal>
++        <receiver>dlgChatRoomsList</receiver>
++        <slot>slotDoubleClick(int,int,int,const QPoint&amp;)</slot>
++    </connection>
++</connections>
++<slots>
++    <slot>slotQuery()</slot>
++    <slot>slotJoin()</slot>
++    <slot>slotClick(int row, int col, int button, const QPoint&amp; mousePos)</slot>
++    <slot>slotDoubleClick(int row, int col, int button, const QPoint&amp; mousePos)</slot>
++</slots>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kdialog.h</includehint>
++</includehints>
++</UI>
+--- kopete/protocols/jabber/ui/dlgvcard.ui	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgvcard.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>592</width>
+-            <height>408</height>
++            <width>764</width>
++            <height>487</height>
+         </rect>
+     </property>
+     <grid>
+@@ -31,7 +31,7 @@
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="3">
++                    <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+                             <cstring>layout13</cstring>
+                         </property>
+@@ -62,67 +62,8 @@
+                             </widget>
+                         </hbox>
+                     </widget>
+-                    <widget class="KPushButton" row="7" column="2">
++                    <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+-                            <cstring>btnSaveNick</cstring>
+-                        </property>
+-                        <property name="text">
+-                            <string>&amp;Save Nickname to Contact List</string>
+-                        </property>
+-                    </widget>
+-                    <spacer row="6" column="1">
+-                        <property name="name">
+-                            <cstring>spacer9</cstring>
+-                        </property>
+-                        <property name="orientation">
+-                            <enum>Vertical</enum>
+-                        </property>
+-                        <property name="sizeType">
+-                            <enum>Expanding</enum>
+-                        </property>
+-                        <property name="sizeHint">
+-                            <size>
+-                                <width>20</width>
+-                                <height>85</height>
+-                            </size>
+-                        </property>
+-                    </spacer>
+-                    <spacer row="6" column="0">
+-                        <property name="name">
+-                            <cstring>spacer22</cstring>
+-                        </property>
+-                        <property name="orientation">
+-                            <enum>Vertical</enum>
+-                        </property>
+-                        <property name="sizeType">
+-                            <enum>Expanding</enum>
+-                        </property>
+-                        <property name="sizeHint">
+-                            <size>
+-                                <width>20</width>
+-                                <height>85</height>
+-                            </size>
+-                        </property>
+-                    </spacer>
+-                    <spacer row="7" column="0" rowspan="1" colspan="2">
+-                        <property name="name">
+-                            <cstring>spacer23</cstring>
+-                        </property>
+-                        <property name="orientation">
+-                            <enum>Horizontal</enum>
+-                        </property>
+-                        <property name="sizeType">
+-                            <enum>Expanding</enum>
+-                        </property>
+-                        <property name="sizeHint">
+-                            <size>
+-                                <width>270</width>
+-                                <height>20</height>
+-                            </size>
+-                        </property>
+-                    </spacer>
+-                    <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="3">
+-                        <property name="name">
+                             <cstring>layout12</cstring>
+                         </property>
+                         <hbox>
+@@ -216,7 +157,7 @@
+                             </widget>
+                         </hbox>
+                     </widget>
+-                    <widget class="QLayoutWidget" row="5" column="0" rowspan="1" colspan="3">
++                    <widget class="QLayoutWidget" row="5" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+                             <cstring>layout14</cstring>
+                         </property>
+@@ -247,7 +188,7 @@
+                             </widget>
+                         </hbox>
+                     </widget>
+-                    <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="3">
++                    <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+                             <cstring>layout11</cstring>
+                         </property>
+@@ -278,7 +219,7 @@
+                             </widget>
+                         </hbox>
+                     </widget>
+-                    <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="3">
++                    <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+                             <cstring>layout10</cstring>
+                         </property>
+@@ -312,7 +253,7 @@
+                             </widget>
+                         </hbox>
+                     </widget>
+-                    <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="3">
++                    <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
+                         <property name="name">
+                             <cstring>layout9</cstring>
+                         </property>
+@@ -343,6 +284,134 @@
+                             </widget>
+                         </hbox>
+                     </widget>
++                    <spacer row="7" column="0">
++                        <property name="name">
++                            <cstring>spacer22</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Expanding</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>20</width>
++                                <height>20</height>
++                            </size>
++                        </property>
++                    </spacer>
++                    <spacer row="7" column="1">
++                        <property name="name">
++                            <cstring>spacer9</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Expanding</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>20</width>
++                                <height>20</height>
++                            </size>
++                        </property>
++                    </spacer>
++                    <widget class="QGroupBox" row="6" column="0" rowspan="1" colspan="2">
++                        <property name="name">
++                            <cstring>groupBox1</cstring>
++                        </property>
++                        <property name="title">
++                            <string>Photo</string>
++                        </property>
++                        <grid>
++                            <property name="name">
++                                <cstring>unnamed</cstring>
++                            </property>
++                            <widget class="QPushButton" row="1" column="0" rowspan="1" colspan="2">
++                                <property name="name">
++                                    <cstring>btnSelectPhoto</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>&amp;Select Photo...</string>
++                                </property>
++                            </widget>
++                            <widget class="QPushButton" row="1" column="2" rowspan="1" colspan="2">
++                                <property name="name">
++                                    <cstring>btnClearPhoto</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Clear Pho&amp;to</string>
++                                </property>
++                            </widget>
++                            <widget class="QLabel" row="0" column="1" rowspan="1" colspan="2">
++                                <property name="name">
++                                    <cstring>lblPhoto</cstring>
++                                </property>
++                                <property name="sizePolicy">
++                                    <sizepolicy>
++                                        <hsizetype>0</hsizetype>
++                                        <vsizetype>0</vsizetype>
++                                        <horstretch>0</horstretch>
++                                        <verstretch>0</verstretch>
++                                    </sizepolicy>
++                                </property>
++                                <property name="minimumSize">
++                                    <size>
++                                        <width>96</width>
++                                        <height>96</height>
++                                    </size>
++                                </property>
++                                <property name="maximumSize">
++                                    <size>
++                                        <width>96</width>
++                                        <height>96</height>
++                                    </size>
++                                </property>
++                                <property name="frameShape">
++                                    <enum>GroupBoxPanel</enum>
++                                </property>
++                                <property name="scaledContents">
++                                    <bool>true</bool>
++                                </property>
++                            </widget>
++                            <spacer row="0" column="0">
++                                <property name="name">
++                                    <cstring>spacer10</cstring>
++                                </property>
++                                <property name="orientation">
++                                    <enum>Horizontal</enum>
++                                </property>
++                                <property name="sizeType">
++                                    <enum>Expanding</enum>
++                                </property>
++                                <property name="sizeHint">
++                                    <size>
++                                        <width>40</width>
++                                        <height>20</height>
++                                    </size>
++                                </property>
++                            </spacer>
++                            <spacer row="0" column="3">
++                                <property name="name">
++                                    <cstring>spacer11</cstring>
++                                </property>
++                                <property name="orientation">
++                                    <enum>Horizontal</enum>
++                                </property>
++                                <property name="sizeType">
++                                    <enum>Expanding</enum>
++                                </property>
++                                <property name="sizeHint">
++                                    <size>
++                                        <width>40</width>
++                                        <height>20</height>
++                                    </size>
++                                </property>
++                            </spacer>
++                        </grid>
++                    </widget>
+                 </grid>
+             </widget>
+             <widget class="QWidget">
+@@ -944,6 +1013,14 @@
+                 </grid>
+             </widget>
+         </widget>
++        <widget class="QLabel" row="1" column="0">
++            <property name="name">
++                <cstring>lblStatus</cstring>
++            </property>
++            <property name="text">
++                <string></string>
++            </property>
++        </widget>
+     </grid>
+ </widget>
+ <tabstops>
+@@ -954,7 +1031,6 @@
+     <tabstop>leBirthday</tabstop>
+     <tabstop>leTimezone</tabstop>
+     <tabstop>leHomepage</tabstop>
+-    <tabstop>btnSaveNick</tabstop>
+     <tabstop>leHomeStreet</tabstop>
+     <tabstop>leHomeExtAddr</tabstop>
+     <tabstop>leHomePOBox</tabstop>
+@@ -981,7 +1057,6 @@
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
+-    <includehint>kpushbutton.h</includehint>
+     <includehint>kurllabel.h</includehint>
+     <includehint>kurllabel.h</includehint>
+     <includehint>kurllabel.h</includehint>
+--- kopete/protocols/jabber/ui/dlgjabberservices.h	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberservices.h	(revision 586398)
+@@ -25,6 +25,7 @@
+ #include "xmpp_tasks.h"
+ 
+ #include "dlgservices.h"
++#include <qlistview.h>
+ 
+ /**
+   *@author Till Gerken <till at tantalo.net>
+@@ -39,17 +40,34 @@
+ 	 ~dlgJabberServices ();
+ 
+ private slots:
+-	void slotSetSelection (int row, int, int, const QPoint &);
+-	void slotQuery ();
+-	void slotQueryFinished ();
++	void slotSetSelection (QListViewItem *);
++	void slotService ();
++	void slotServiceFinished ();
+ 	void slotRegister ();
+ 	void slotBrowse ();
++	
++	void slotDisco();
++	void slotDiscoFinished();
+ 
+ private:
+ 	JabberAccount *m_account;
+-	XMPP::JT_GetServices * serviceTask;
+-	int selectedRow;
++	XMPP::Jid current_jid;
+ 
+ };
+ 
++
++class dlgJabberServies_item : protected QObject, public QListViewItem  
++{
++	Q_OBJECT
++	public:
++		dlgJabberServies_item( QListView *parent , const QString &s1 , const QString &s2 ) 
++			: QListViewItem(parent,s1,s2), can_browse(false) , can_register(false) {}
++		bool can_browse, can_register;
++		XMPP::Jid jid;
++		
++		void updateInfo(const XMPP::Jid& jid, const QString &node , JabberAccount *account);
++	private slots:
++		void slotDiscoFinished();
++};
++
+ #endif
+--- kopete/protocols/jabber/ui/dlgaddcontact.ui	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgaddcontact.ui	(revision 586398)
+@@ -1,4 +1,4 @@
+-<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+ <class>dlgAddContact</class>
+ <widget class="QWidget">
+     <property name="name">
+@@ -74,7 +74,7 @@
+                 <string>&lt;i&gt;(for example: joe at jabber.org)&lt;/i&gt;</string>
+             </property>
+             <property name="alignment">
+-                <set>AlignVCenter|AlignRight</set>
++                <set>WordBreak|AlignVCenter|AlignRight</set>
+             </property>
+         </widget>
+         <spacer>
+@@ -96,6 +96,8 @@
+         </spacer>
+     </vbox>
+ </widget>
++<customwidgets>
++</customwidgets>
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
+     <includehint>klineedit.h</includehint>
+--- kopete/protocols/jabber/ui/dlgjabberchatjoin.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberchatjoin.cpp	(revision 586398)
+@@ -16,53 +16,114 @@
+  *                                                                         *
+  ***************************************************************************/
+ 
+-#include "dlgjabberchatjoin.h"
+-
+ #include <kdebug.h>
+ #include <klocale.h>
+-#include <kdialogbase.h>
+ #include <qlineedit.h>
++#include <qpushbutton.h>
+ 
+ #include "jabberaccount.h"
+ #include "jabberclient.h"
++#include "dlgjabberchatroomslist.h"
+ 
+-#include "dlgchatjoin.h"
++#include "dlgjabberchatjoin.h"
+ 
+-dlgJabberChatJoin::dlgJabberChatJoin (JabberAccount *account, QWidget * parent, const char *name)
+-									: KDialogBase (parent, name, false,
+-												   i18n("Join Jabber Groupchat"),
+-												   KDialogBase::Ok | KDialogBase::Cancel)
++dlgJabberChatJoin::dlgJabberChatJoin(JabberAccount *account, QWidget* parent, const char* name) :
++dlgChatJoin(parent, name),
++m_account(account)
+ {
++	setCaption(i18n("Join Jabber Groupchat"));
++	leNick->setText(m_account->client()->client()->user());
++	checkDefaultChatroomServer();
++}
+ 
+-	m_account = account;
++dlgJabberChatJoin::~dlgJabberChatJoin()
++{
++}
+ 
+-	setMainWidget ( new dlgChatJoin ( this ) );
++/*$SPECIALIZATION$*/
++void dlgJabberChatJoin::slotJoin()
++{
++	if(!m_account->isConnected())
++	{
++		m_account->errorConnectFirst();
++		return;
++	}
+ 
++	m_account->client()->joinGroupChat(leServer->text(), leRoom->text(), leNick->text());
++	accept();
+ }
+ 
+-void dlgJabberChatJoin::slotOk ()
++void dlgJabberChatJoin::slotBowse()
+ {
+-
+ 	if(!m_account->isConnected())
+ 	{
+ 		m_account->errorConnectFirst();
+ 		return;
+ 	}
+ 
+-	dlgChatJoin *widget = dynamic_cast<dlgChatJoin *>(mainWidget ());
++	dlgJabberChatRoomsList *crl = new dlgJabberChatRoomsList(m_account, leServer->text() , leNick->text());
++	crl->show();
++	accept();
++}
+ 
+-	// send the join request
+-	m_account->client()->joinGroupChat ( widget->leServer->text (), widget->leRoom->text (), widget->leNick->text () );
++/*
++	TODO : Used to look for the default chat server,
++	this is duplicate with dlgjabberservices.cpp
++	should be merged elsewhere !
++*/
++//	JabberAccount *m_account;
++//	XMPP::JT_GetServices * serviceTask;
+ 
+-	delete this;
++void dlgJabberChatJoin::checkDefaultChatroomServer()
++{
++	XMPP::JT_GetServices *serviceTask = new XMPP::JT_GetServices(m_account->client()->rootTask());
++	connect(serviceTask, SIGNAL (finished()), this, SLOT (slotQueryFinished()));
+ 
++	serviceTask->get(m_account->server());
++	serviceTask->go(true);
+ }
+ 
+-void dlgJabberChatJoin::slotCancel ()
++void dlgJabberChatJoin::slotQueryFinished()
+ {
++	XMPP::JT_GetServices *task = (XMPP::JT_GetServices*)sender();
++	if (!task->success ())
++		return;
++	
++	if(!leServer->text().isEmpty())
++	{  //the user already started to type the server manyally. abort auto-detect
++		return;
++	}
+ 
+-	delete this;
++	for (XMPP::AgentList::const_iterator it = task->agents().begin(); it != task->agents().end(); ++it)
++	{
++		XMPP::JT_DiscoInfo *discoTask = new XMPP::JT_DiscoInfo(m_account->client()->rootTask());
++		connect(discoTask, SIGNAL (finished()), this, SLOT (slotDiscoFinished()));
+ 
++		discoTask->get((*it).jid().full());
++		discoTask->go(true);
++	}
+ }
+ 
++void dlgJabberChatJoin::slotDiscoFinished()
++{
++	XMPP::JT_DiscoInfo *task = (XMPP::JT_DiscoInfo*)sender();
++
++	if (!task->success())
++		return;
++	
++	if(!leServer->text().isEmpty())
++	{  //the user already started to type the server manyally. abort auto-detect
++		return;
++	}
++
++
++	if (task->item().features().canGroupchat() && !task->item().features().isGateway())
++	{
++		leServer->setText(task->item().jid().full());
++	}
++}
++
++// end todo
++
+ #include "dlgjabberchatjoin.moc"
++
+--- kopete/protocols/jabber/ui/dlgjabberchatroomslist.h	(revision 0)
++++ kopete/protocols/jabber/ui/dlgjabberchatroomslist.h	(revision 586398)
+@@ -0,0 +1,54 @@
++//
++// C++ Interface: 
++//
++// Description: 
++//
++//
++// Author: Kopete Developers <kopete-devel at kde.org>, (C) 2005
++//
++// Copyright: See COPYING file that comes with this distribution
++//
++//
++
++#ifndef DLGJABBERCHATROOMSLIST_H
++#define DLGJABBERCHATROOMSLIST_H
++
++#include "jabberaccount.h"
++#include "xmpp_tasks.h"
++
++#include "dlgchatroomslist.h"
++
++class dlgJabberChatRoomsList : public dlgChatRoomsList
++{
++  Q_OBJECT
++
++public:
++	dlgJabberChatRoomsList(JabberAccount* account, const QString& server = QString::null, const QString& nick = QString::null, QWidget* parent = 0, const char* name = 0);
++  ~dlgJabberChatRoomsList();
++  /*$PUBLIC_FUNCTIONS$*/
++
++public slots:
++  /*$PUBLIC_SLOTS$*/
++  virtual void slotJoin();
++  virtual void slotQuery();
++  virtual void slotDoubleClick(int row, int col, int button, const QPoint& mousePos);
++  virtual void slotClick(int row, int col, int button, const QPoint& mousePos);
++
++protected:
++  /*$PROTECTED_FUNCTIONS$*/
++
++protected slots:
++  /*$PROTECTED_SLOTS$*/
++
++	void slotQueryFinished();
++
++private:
++
++	JabberAccount *m_account;
++	int m_selectedRow;
++	QString m_chatServer;
++	QString m_nick;
++};
++
++#endif
++
+--- kopete/protocols/jabber/ui/dlgjabbereditaccountwidget.ui	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabbereditaccountwidget.ui	(revision 586398)
+@@ -9,8 +9,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>637</width>
+-            <height>456</height>
++            <width>706</width>
++            <height>455</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -38,7 +38,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>B&amp;asic Setup</string>
++                    <string>&amp;Basic Setup</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -112,6 +112,14 @@
+                                     <string>Check to disable automatic connection.  If checked, you may connect to this account manually using the icon in the bottom of the main Kopete window</string>
+                                 </property>
+                             </widget>
++                            <widget class="QCheckBox">
++                                <property name="name">
++                                    <cstring>cbGlobalIdentity</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Exclu&amp;de from Global Identity</string>
++                                </property>
++                            </widget>
+                         </vbox>
+                     </widget>
+                     <widget class="QGroupBox">
+@@ -713,34 +721,109 @@
+                     <cstring>TabPage</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>&amp;Privacy</string>
++                    <string>Pri&amp;vacy</string>
+                 </attribute>
+-                <grid>
++                <vbox>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2">
++                    <widget class="QGroupBox">
+                         <property name="name">
++                            <cstring>groupBox7</cstring>
++                        </property>
++                        <property name="title">
++                            <string>General Privacy</string>
++                        </property>
++                        <grid>
++                            <property name="name">
++                                <cstring>unnamed</cstring>
++                            </property>
++                            <spacer row="0" column="1">
++                                <property name="name">
++                                    <cstring>spacer9</cstring>
++                                </property>
++                                <property name="orientation">
++                                    <enum>Horizontal</enum>
++                                </property>
++                                <property name="sizeType">
++                                    <enum>Expanding</enum>
++                                </property>
++                                <property name="sizeHint">
++                                    <size>
++                                        <width>40</width>
++                                        <height>20</height>
++                                    </size>
++                                </property>
++                            </spacer>
++                            <widget class="QCheckBox" row="0" column="0">
++                                <property name="name">
++                                    <cstring>cbHideSystemInfo</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>&amp;Hide system and client info</string>
++                                </property>
++                                <property name="whatsThis" stdset="0">
++                                    <string>By default, Kopete gives the other users some info about your system and the client. You can check this box in order to  hide those infos.</string>
++                                </property>
++                            </widget>
++                        </grid>
++                    </widget>
++                    <widget class="QGroupBox">
++                        <property name="name">
+                             <cstring>groupBox6</cstring>
+                         </property>
+                         <property name="title">
+                             <string>Notifications</string>
+                         </property>
+-                        <grid>
++                        <vbox>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLayoutWidget" row="0" column="0">
++                            <widget class="QCheckBox">
+                                 <property name="name">
+-                                    <cstring>layout17</cstring>
++                                    <cstring>cbSendEvents</cstring>
+                                 </property>
++                                <property name="enabled">
++                                    <bool>true</bool>
++                                </property>
++                                <property name="text">
++                                    <string>Always send not&amp;ifications</string>
++                                </property>
++                                <property name="checked">
++                                    <bool>true</bool>
++                                </property>
++                                <property name="whatsThis" stdset="0">
++                                    <string>Check this box if you want to always send notifications to your contacts.</string>
++                                </property>
++                            </widget>
++                            <widget class="QLayoutWidget">
++                                <property name="name">
++                                    <cstring>layout10</cstring>
++                                </property>
+                                 <hbox>
+                                     <property name="name">
+                                         <cstring>unnamed</cstring>
+                                     </property>
++                                    <spacer>
++                                        <property name="name">
++                                            <cstring>spacer6</cstring>
++                                        </property>
++                                        <property name="orientation">
++                                            <enum>Horizontal</enum>
++                                        </property>
++                                        <property name="sizeType">
++                                            <enum>Fixed</enum>
++                                        </property>
++                                        <property name="sizeHint">
++                                            <size>
++                                                <width>30</width>
++                                                <height>20</height>
++                                            </size>
++                                        </property>
++                                    </spacer>
+                                     <widget class="QLayoutWidget">
+                                         <property name="name">
+-                                            <cstring>layout16</cstring>
++                                            <cstring>layout9</cstring>
+                                         </property>
+                                         <vbox>
+                                             <property name="name">
+@@ -748,133 +831,73 @@
+                                             </property>
+                                             <widget class="QCheckBox">
+                                                 <property name="name">
+-                                                    <cstring>cbSendEvents</cstring>
++                                                    <cstring>cbSendDeliveredEvent</cstring>
+                                                 </property>
+                                                 <property name="enabled">
+                                                     <bool>true</bool>
+                                                 </property>
+                                                 <property name="text">
+-                                                    <string>Always send not&amp;ifications</string>
++                                                    <string>Alwa&amp;ys send delivered notifications</string>
+                                                 </property>
+                                                 <property name="checked">
+                                                     <bool>true</bool>
+                                                 </property>
+                                                 <property name="whatsThis" stdset="0">
+-                                                    <string>Check this box if you want to always send notifications to your contacts.</string>
++                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Delivered notification&lt;/b&gt; to your contacts : when a message is delivered to Kopete, Kopete can notify your contact that it has received the message.&lt;/qt&gt;</string>
+                                                 </property>
+                                             </widget>
+-                                            <widget class="QLayoutWidget">
++                                            <widget class="QCheckBox">
+                                                 <property name="name">
+-                                                    <cstring>layout14</cstring>
++                                                    <cstring>cbSendDisplayedEvent</cstring>
+                                                 </property>
+-                                                <hbox>
+-                                                    <property name="name">
+-                                                        <cstring>unnamed</cstring>
+-                                                    </property>
+-                                                    <spacer>
+-                                                        <property name="name">
+-                                                            <cstring>spacer6</cstring>
+-                                                        </property>
+-                                                        <property name="orientation">
+-                                                            <enum>Horizontal</enum>
+-                                                        </property>
+-                                                        <property name="sizeType">
+-                                                            <enum>Fixed</enum>
+-                                                        </property>
+-                                                        <property name="sizeHint">
+-                                                            <size>
+-                                                                <width>30</width>
+-                                                                <height>20</height>
+-                                                            </size>
+-                                                        </property>
+-                                                    </spacer>
+-                                                    <widget class="QLayoutWidget">
+-                                                        <property name="name">
+-                                                            <cstring>layout6</cstring>
+-                                                        </property>
+-                                                        <vbox>
+-                                                            <property name="name">
+-                                                                <cstring>unnamed</cstring>
+-                                                            </property>
+-                                                            <widget class="QCheckBox">
+-                                                                <property name="name">
+-                                                                    <cstring>cbSendDeliveredEvent</cstring>
+-                                                                </property>
+-                                                                <property name="enabled">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="text">
+-                                                                    <string>Alwa&amp;ys send delivered notifications</string>
+-                                                                </property>
+-                                                                <property name="checked">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="whatsThis" stdset="0">
+-                                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Delivered notification&lt;/b&gt; to your contacts : when a message is delivered to Kopete, Kopete can notify your contact that it has received the message.&lt;/qt&gt;</string>
+-                                                                </property>
+-                                                            </widget>
+-                                                            <widget class="QCheckBox">
+-                                                                <property name="name">
+-                                                                    <cstring>cbSendDisplayedEvent</cstring>
+-                                                                </property>
+-                                                                <property name="enabled">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="text">
+-                                                                    <string>Al&amp;ways send displayed notifications</string>
+-                                                                </property>
+-                                                                <property name="checked">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="whatsThis" stdset="0">
+-                                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Displayed notification&lt;/b&gt; to your contacts : when a message is displayed in Kopete, Kopete can notify your contact that it has displayed the message.&lt;/qt&gt;</string>
+-                                                                </property>
+-                                                            </widget>
+-                                                            <widget class="QCheckBox">
+-                                                                <property name="name">
+-                                                                    <cstring>cbSendComposingEvent</cstring>
+-                                                                </property>
+-                                                                <property name="enabled">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="text">
+-                                                                    <string>Always send &amp;typing notifications</string>
+-                                                                </property>
+-                                                                <property name="checked">
+-                                                                    <bool>true</bool>
+-                                                                </property>
+-                                                                <property name="whatsThis" stdset="0">
+-                                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Typing notification&lt;/b&gt; to your contacts : when you are composing a message, you might want your contact to know that you are typing so that he knows you are answering.&lt;/qt&gt;</string>
+-                                                                </property>
+-                                                            </widget>
+-                                                        </vbox>
+-                                                    </widget>
+-                                                </hbox>
++                                                <property name="enabled">
++                                                    <bool>true</bool>
++                                                </property>
++                                                <property name="text">
++                                                    <string>Al&amp;ways send displayed notifications</string>
++                                                </property>
++                                                <property name="checked">
++                                                    <bool>true</bool>
++                                                </property>
++                                                <property name="whatsThis" stdset="0">
++                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Displayed notification&lt;/b&gt; to your contacts : when a message is displayed in Kopete, Kopete can notify your contact that it has displayed the message.&lt;/qt&gt;</string>
++                                                </property>
+                                             </widget>
++                                            <widget class="QCheckBox">
++                                                <property name="name">
++                                                    <cstring>cbSendComposingEvent</cstring>
++                                                </property>
++                                                <property name="enabled">
++                                                    <bool>true</bool>
++                                                </property>
++                                                <property name="text">
++                                                    <string>Always send &amp;typing notifications</string>
++                                                </property>
++                                                <property name="checked">
++                                                    <bool>true</bool>
++                                                </property>
++                                                <property name="whatsThis" stdset="0">
++                                                    <string>&lt;qt&gt;Check this box to send the &lt;b&gt;Typing notification&lt;/b&gt; to your contacts : when you are composing a message, you might want your contact to know that you are typing so that he knows you are answering.&lt;/qt&gt;</string>
++                                                </property>
++                                            </widget>
++                                            <widget class="QCheckBox">
++                                                <property name="name">
++                                                    <cstring>cbSendGoneEvent</cstring>
++                                                </property>
++                                                <property name="text">
++                                                    <string>Always send &amp;gone notifications (closing the window)</string>
++                                                </property>
++                                                <property name="checked">
++                                                    <bool>true</bool>
++                                                </property>
++                                            </widget>
+                                         </vbox>
+                                     </widget>
+-                                    <spacer>
+-                                        <property name="name">
+-                                            <cstring>spacer10</cstring>
+-                                        </property>
+-                                        <property name="orientation">
+-                                            <enum>Horizontal</enum>
+-                                        </property>
+-                                        <property name="sizeType">
+-                                            <enum>Expanding</enum>
+-                                        </property>
+-                                        <property name="sizeHint">
+-                                            <size>
+-                                                <width>250</width>
+-                                                <height>20</height>
+-                                            </size>
+-                                        </property>
+-                                    </spacer>
+                                 </hbox>
+                             </widget>
+-                        </grid>
++                        </vbox>
+                     </widget>
+-                    <spacer row="2" column="1">
++                    <spacer>
+                         <property name="name">
+                             <cstring>spacer5</cstring>
+                         </property>
+@@ -887,52 +910,11 @@
+                         <property name="sizeHint">
+                             <size>
+                                 <width>21</width>
+-                                <height>190</height>
++                                <height>110</height>
+                             </size>
+                         </property>
+                     </spacer>
+-                    <widget class="QGroupBox" row="0" column="0">
+-                        <property name="name">
+-                            <cstring>groupBox7</cstring>
+-                        </property>
+-                        <property name="title">
+-                            <string>General Privacy</string>
+-                        </property>
+-                        <grid>
+-                            <property name="name">
+-                                <cstring>unnamed</cstring>
+-                            </property>
+-                            <spacer row="0" column="1">
+-                                <property name="name">
+-                                    <cstring>spacer9</cstring>
+-                                </property>
+-                                <property name="orientation">
+-                                    <enum>Horizontal</enum>
+-                                </property>
+-                                <property name="sizeType">
+-                                    <enum>Expanding</enum>
+-                                </property>
+-                                <property name="sizeHint">
+-                                    <size>
+-                                        <width>40</width>
+-                                        <height>20</height>
+-                                    </size>
+-                                </property>
+-                            </spacer>
+-                            <widget class="QCheckBox" row="0" column="0">
+-                                <property name="name">
+-                                    <cstring>cbHideSystemInfo</cstring>
+-                                </property>
+-                                <property name="text">
+-                                    <string>&amp;Hide system and client info</string>
+-                                </property>
+-                                <property name="whatsThis" stdset="0">
+-                                    <string>By default, Kopete gives the other users some info about your system and the client. You can check this box in order to  hide those infos.</string>
+-                                </property>
+-                            </widget>
+-                        </grid>
+-                    </widget>
+-                </grid>
++                </vbox>
+             </widget>
+         </widget>
+     </grid>
+@@ -958,7 +940,7 @@
+ </customwidgets>
+ <images>
+     <image name="image0">
+-        <data format="PNG" length="866">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032949444154388db59531681b6714c77f32373c8186ef0305eea005093258900eca26d30e3174a8a807d1c9ee940e5d4a276f09a414e22974ee609a4c75a0857a70a20c199ce93424e43414aee0c26910dc8105f7410df706413a7c915551db049a3e38b87bf7bedffddfc7ff7d578be398456c6c6cbce13d441cc7b5da02fcf4e8e99bde7a8f899b501515d959f64e10e71cd949c6e8d508e6cb7cb050fae49727444d87ed08a566dc0cea545a621b96725e62c522f312c4929ff9e7725e6203439282ec0bc72f74150c30c927d89690163f539619a044564973a1980ae54c01c136a1db518a0024808942780dead16a27e7e0ca55949a81668023b242fcd2901c394663072cd408ad75e18b6d43a7076143710aa1b9049ccd326e064a5979e8f0191cfc5878544368af1b24807caa4cfe507ef8aea0bf6dd8b92de7f00bc1562c95e64416e297f216aadcfa3ca43f10da1f8243112286871507fb05c3c7059d568bde96c5885b01af2d6e4a2db10dc8ff128e0fdd39f4cbaf8576dbe170702afcf6b86467bbce57df8680f0d3230767e0e62bdc55c5e53c476742fabbc318437f209886c3cd41d4b0f74049c78ef21476ef5846cf7ded2831848d55f0aa62816caade11adb7ed2fa0f71ce9d8619ac2e627824a45a72b00e413c5a95c0cf63e052bbe2014bfa738c3de3d251dfb0f8a80fda04e6480600113cc558a11a0e10b93a9225886cff04a8d10868662eab87f37271e59f2136f85a855bfda15f9594eb7a3b4ae0b933f95e161c5ceed88f254e97f2ad49b75eedf8562e2d8fb264355314da1dbada866abe47fedb106d01f78b71fec170c8f7276ef58da3de8f64a76bf6f634283730e9d2b9b8390ce0dae565c6a8e04b0710b746678f8a8e0e18382d173a1d7151c909fe4e84ccf57be3e76245b115143584ee73f27afc8e80b4c667e4c37b7054c8be1afde0de978a9c63485fea0457cec70aa089015ab9297e0938c240573cdb7651a4a7f20f43feb304a72aac2e73bd723da1fe5746ec0682bc26070f38c345905d7e238f6077c00dd8f85280211fcd91af84b02ef94a50c004502c1394813252f14575ca09839242f9484cb42df31e763edd237ff31d6c0ffa3fe17f0fb86c7715cfb1ba8bd86cc8d2decd30000000049454e44ae426082</data>
++        <data format="PNG" length="868">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032b49444154388db59531681b6714c77f32373c8186ef0305eea0050932f8201d944d493bc4d0a1a21e4427bb533a74299dbc25905288a7d0b9836932d58116eac1411932388ba421a5a7a17005174e83e00e2cb80f6ab83708d2e18bec8ada26d0f4c1c1ddbbf7fdeeff3efeefbbda70346419b76fdd7ecd3b88e16858ab2dc183c3c1ebee7a97a99b521515d969f65610e71cd971c6f8d7312ccef3c152e9b39f9e11351d36164acdb819d4a9b4c4362ce5a2c48a45162588253ff5cfe5a2c406862405d9138e5eea2a18609a4fb12d212d7ea42c334089ac92e6423113cab902826d4227568a002480a942780dead16a2767e0ca55949a81668023b2c2e8952139748c270e58aa115aebc2675b86b80b6143710aa1b9049ccd336e064a5979e8e039ec7f5f78544368af1b24807ca64cff50befba6a0b765d8be2b67f00bc1562c95e6441646afe40d54b9f36948af2fb4df078722440c0e2af6f70a064f0be2568beea6c5885b01af2d6f4a2db10dc8ff128e0edc19f4f32f8576dbe1707022fcf2b4647babce175f8780f0c31307a7e0162bdc55c5e52247e742fabbc31843af2f9886c32d40d4b0fb4849278ef20476ee59c62f7ced3831848d55f0aa62816ca6de11ad37ed2fa10f1ce9c4619ac2c647824a45dc1100f2a9e2542e067b9f82155f108adf539c61f781924efc0745c0be57273240b08409e62ac508d0f085c94c112c83e778a54608434331733cbc9f331a5bf2636f85a855bfda15f9694e27565ad785e99fcae0a062fb6e4479a2f43e16eacd3a0fef433175ec7e95a1aa98a6d0e95454f355f2bff65803e8f5bddbf7f70a0687393bf72ced2e74ba253bdfb631a1c139872e948d7e487c83ab15979a2301dcba033a373c7e52f0f851c1f885d0ed080ec88f7374ae672b7f3b72249b115143389fce7f4e5e91d11398cefd986e6c099816839fbd1bd2c9b91ad3147afd16a32387534580ac58957c0e3ece485230d77c5ba6a1f4fa42ef9398719253153e1f5f8f687f9013df80f16684c1e0161969b20aae0d47437fc007d0f950882210c19fad81bf24f04e399701a04820380769a2e485e28a0b14b380e4a5927059e85be67cac5dfae63fc61af87fd4ff027ed7f0e16858fb1ba5cd86c64770b2e90000000049454e44ae426082</data>
+     </image>
+ </images>
+ <connections>
+@@ -1005,4 +987,7 @@
+     <tabstop>cbSendComposingEvent</tabstop>
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kopetepasswordwidget.h</includehint>
++</includehints>
+ </UI>
+--- kopete/protocols/jabber/ui/dlgjabbervcard.h	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabbervcard.h	(revision 586398)
+@@ -4,6 +4,7 @@
+                              -------------------
+     begin                : Thu Aug 08 2002
+     copyright            : (C) 2002-2003 by Till Gerken <till at tantalo.net>
++                           (C) 2005      by Michaël Larouche <michael.larouche at kdemail.net>
+     email                : kopete-devel at kde.org
+  ***************************************************************************/
+ 
+@@ -24,34 +25,86 @@
+ 
+ class JabberAccount;
+ class JabberContact;
++class JabberBaseContact;
+ class QString;
+ class dlgVCard;
+ 
++/**
++ * @brief Show the information of a Jabber contact.
++ *
++ * This dialog shows the information of a Jabber contact from
++ * the contact properties(from Kopete). 
++ * Also it is used to edit the information of the Account myself contact.
++ *
++ * First it fetch a new version of the vcard then it display the
++ * information. User can force the update using the "Update vCard" button.
++ * 
++ * @author Till Gerken <till at tantolo.net>
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
+ class dlgJabberVCard : public KDialogBase
+ {
+ 	Q_OBJECT
+ 
+ public:
+-	dlgJabberVCard (JabberAccount *account, JabberContact *contact, QWidget * parent = 0, const char *name = 0);
++	/**
++	 * Create the information(vcard) dialog.
++	 *
++	 * @param account the current Jabber account 
++	 * @param contact the contact to display or edit information.
++	 * @param widget Parent widget.
++	 * @param name widget name.
++	 */
++	dlgJabberVCard (JabberAccount *account, JabberBaseContact *contact, QWidget * parent = 0, const char *name = 0);
+ 	~dlgJabberVCard ();
+ 
+-signals:
+-	void informationChanged();
+-
+ private slots:
+-	void slotSaveNickname();
++	/**
++	 * Show the KFileDialog for image to select a photo for the contact.
++	 */
++	void slotSelectPhoto();
++	/**
++	 * Remove(clear) the photo. 
++	 * Maybe the user doesn't want to export a photo anymore.
++	 */
++	void slotClearPhoto();
++	/**
++	 * Send vCard to the server.
++	 */
+ 	void slotSaveVCard();
++	/**
++	 * Put back the information from the dialog into the contact properties
++	 */
++	void slotVCardSaved();
++	/**
++	 * Close the dialog.
++	 */
+ 	void slotClose();
++	/**
++	 * Open a link. (ex: the homepage link or the email address)
++	 */
+ 	void slotOpenURL(const QString &url);
+ 
++	/**
++	 * Retrieve vCard information for the current contact.
++	 */
++	void slotGetVCard();
++	/**
++	 * vCard was succesfully fetched, update contact properties
++	 * and enable display.
++	 */
++	void slotGotVCard();
++
+ private:
+ 	JabberAccount *m_account;
+-	JabberContact *m_contact;
++	JabberBaseContact *m_contact;
+ 	dlgVCard *m_mainWidget;
++	QString m_photoPath;
+ 
+ 	void assignContactProperties();
+ 	void setReadOnly(bool state);
+-
++	void setEnabled(bool state);
++	
+ };
+ 
+ #endif // DLGJABBERVCARD_H
+--- kopete/protocols/jabber/ui/dlgjabberchangepassword.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberchangepassword.cpp	(revision 586398)
+@@ -52,7 +52,7 @@
+ 	if ( !strlen ( m_mainWidget->peCurrentPassword->password () )
+ 		|| ( m_account->password().cachedValue () != m_mainWidget->peCurrentPassword->password () ) )
+ 	{
+-		KMessageBox::sorry ( this,
++		KMessageBox::queuedMessageBox ( this, KMessageBox::Sorry,
+ 							 i18n ( "You entered your current password incorrectly." ),
+ 							 i18n ( "Password Incorrect" ) );
+ 		return;
+@@ -60,7 +60,7 @@
+ 
+ 	if ( strcmp ( m_mainWidget->peNewPassword1->password (), m_mainWidget->peNewPassword2->password () ) != 0 )
+ 	{
+-		KMessageBox::sorry ( this,
++		KMessageBox::queuedMessageBox ( this, KMessageBox::Sorry,
+ 							 i18n ( "Your new passwords do not match. Please enter them again." ),
+ 							 i18n ( "Password Incorrect" ) );
+ 		return;
+@@ -68,7 +68,7 @@
+ 
+ 	if ( !strlen ( m_mainWidget->peNewPassword1->password () ) )
+ 	{
+-		KMessageBox::sorry ( this,
++		KMessageBox::queuedMessageBox ( this, KMessageBox::Sorry,
+ 							 i18n ( "For security reasons, you are not allowed to set an empty password." ),
+ 							 i18n ( "Password Incorrect" ) );
+ 		return;
+@@ -116,7 +116,7 @@
+ 
+ 	if ( task->success () )
+ 	{
+-		KMessageBox::information ( this,
++		KMessageBox::queuedMessageBox ( dynamic_cast<QWidget*>(parent()), KMessageBox::Information,
+ 								   i18n ( "Your password has been changed successfully. Please note that the change may not be instantaneous. If you have problems logging in with your new password, please contact the administrator." ),
+ 								   i18n ( "Jabber Password Change" ) );
+ 
+@@ -124,11 +124,11 @@
+ 	}
+ 	else
+ 	{
+-		KMessageBox::sorry ( this,
++		KMessageBox::queuedMessageBox ( dynamic_cast<QWidget*>(parent()), KMessageBox::Sorry, 
+ 							 i18n ( "Your password could not be changed. Either your server does not support this feature or the administrator does not allow you to change your password." ) );
+ 	}
+ 
+-	deleteLater ();
++	deleteLater();
+ 
+ }
+ 
+--- kopete/protocols/jabber/ui/jabberaddcontactpage.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/jabberaddcontactpage.cpp	(revision 586398)
+@@ -5,6 +5,7 @@
+     begin                : Thu Aug 08 2002
+     copyright            : (C) 2003 by Till Gerken <till at tantalo.net>
+                            (C) 2003 by Daniel Stone <dstone at kde.org>
++                           (C) 2006 by Olivier Goffart <ogoffart at kde.org>
+     email                : kopete-devel at kde.org
+  ***************************************************************************/
+ 
+@@ -29,19 +30,32 @@
+ 
+ #include "dlgaddcontact.h"
+ #include "jabberaccount.h"
++#include "jabbertransport.h"
++#include "kopetecontact.h"
+ #include "jabberclient.h"
+ #include "xmpp_tasks.h"
+ 
+ JabberAddContactPage::JabberAddContactPage (Kopete::Account * owner, QWidget * parent, const char *name):AddContactPage (parent, name)
+ {
+ 	(new QVBoxLayout (this))->setAutoAdd (true);
+-	if (owner->isConnected ())
++	
++	JabberTransport *transport=dynamic_cast<JabberTransport*>(owner);
++	JabberAccount *jaccount= transport ? transport->account() : dynamic_cast<JabberAccount*>(owner);
++	
++	if (jaccount->isConnected ())
+ 	{
+ 		jabData = new dlgAddContact (this);
+ 		jabData->show ();
+-
++		
++		if(transport)
++		{
++			jabData->textLabel1->setText( i18n("Loading instruction from gateway...") );
++			XMPP::JT_Gateway * gatewayTask = new XMPP::JT_Gateway ( jaccount->client()->rootTask () );
++			QObject::connect (gatewayTask, SIGNAL (finished ()), this, SLOT (slotPromtReceived()));
++			gatewayTask->get ( transport->myself()->contactId() );
++			gatewayTask->go ( true );
++		}
+ 		canadd = true;
+-
+ 	}
+ 	else
+ 	{
+@@ -67,19 +81,34 @@
+ 
+ 	if( canadd && validateData () )
+ 	{
++		JabberTransport *transport=dynamic_cast<JabberTransport*>(account);
++		JabberAccount *jaccount=transport?transport->account():dynamic_cast<JabberAccount*>(account);
++				
+ 		QString contactId = jabData->addID->text ();
++		
++		if(transport)
++		{
++			XMPP::JT_Gateway * gatewayTask = new XMPP::JT_Gateway ( jaccount->client()->rootTask () );
++			JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND *workaround = 
++					new JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND( transport , parentContact , gatewayTask );
++			QObject::connect (gatewayTask, SIGNAL (finished ()), workaround, SLOT (slotJidReceived()));
++			gatewayTask->set ( transport->myself()->contactId() , contactId );
++			gatewayTask->go ( true );
++			return true;
++		}
++		
+ 		QString displayName = parentContact->displayName ();
+-		
++		/*		
+ 		if ( displayName.isEmpty () )
+ 			displayName = contactId;
+-
++		*/
+ 		// collect all group names
+ 		QStringList groupNames;
+ 		Kopete::GroupList groupList = parentContact->groups();
+ 		for(Kopete::Group *group = groupList.first(); group; group = groupList.next())
+ 			groupNames += group->displayName();
+ 
+-		if ( account->addContact ( contactId, parentContact, Kopete::Account::ChangeKABC ) )
++		if ( jaccount->addContact ( contactId, parentContact, Kopete::Account::ChangeKABC ) )
+ 		{
+ 			XMPP::RosterItem item;
+ 			XMPP::Jid jid ( contactId );
+@@ -89,13 +118,13 @@
+ 			item.setGroups ( groupNames );
+ 
+ 			// add the new contact to our roster.
+-			XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( static_cast<JabberAccount *>(account)->client()->rootTask () );
++			XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( jaccount->client()->rootTask () );
+ 
+ 			rosterTask->set ( item.jid(), item.name(), item.groups() );
+ 			rosterTask->go ( true );
+ 
+ 			// send a subscription request.
+-			XMPP::JT_Presence *presenceTask = new XMPP::JT_Presence ( static_cast<JabberAccount *>(account)->client()->rootTask () );
++			XMPP::JT_Presence *presenceTask = new XMPP::JT_Presence ( jaccount->client()->rootTask () );
+ 
+ 			presenceTask->sub ( jid, "subscribe" );
+ 			presenceTask->go ( true );
+@@ -107,6 +136,82 @@
+ 	return false;
+ }
+ 
++void JabberAddContactPage::slotPromtReceived( )
++{
++	XMPP::JT_Gateway * task = (XMPP::JT_Gateway *) sender ();
++
++	if (task->success ())
++	{
++		jabData->lblID->setText( task->prompt() );
++		jabData->textLabel1->setText( task->desc() );
++	}
++	else
++	{
++		jabData->textLabel1->setText( i18n("An error occured while loading instructions from gateway.") );
++	}
++}
++
++JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND::JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND( JabberTransport *t, Kopete::MetaContact * mc, QObject* task )
++	: QObject(task) , metacontact(mc) ,  transport(t)
++{}
++
++void JabberAddContactPage_there_is_no_possibility_to_add_assync_WORKAROUND::slotJidReceived( )
++{
++	XMPP::JT_Gateway * task = (XMPP::JT_Gateway *) sender ();
++	
++	if (!task->success ())
++	{
++		return;
++		// maybe we should show an error message, but i don't like showing error message  - Olivier
++	}
++
++	QString contactId=task->prompt();
++	
++	Kopete::MetaContact* parentContact=metacontact;
++	JabberAccount *jaccount=transport->account();;
++	
++	/*\
++	 *   this is a copy of the end of JabberAddContactPage::apply
++	\*/
++	
++	QString displayName = parentContact->displayName ();
++		/*		
++	if ( displayName.isEmpty () )
++	displayName = contactId;
++		*/
++		// collect all group names
++	QStringList groupNames;
++	Kopete::GroupList groupList = parentContact->groups();
++	for(Kopete::Group *group = groupList.first(); group; group = groupList.next())
++		groupNames += group->displayName();
++
++	if ( jaccount->addContact ( contactId, parentContact, Kopete::Account::ChangeKABC ) )
++	{
++		XMPP::RosterItem item;
++		XMPP::Jid jid ( contactId );
++
++		item.setJid ( jid );
++		item.setName ( displayName );
++		item.setGroups ( groupNames );
++
++			// add the new contact to our roster.
++		XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( jaccount->client()->rootTask () );
++
++		rosterTask->set ( item.jid(), item.name(), item.groups() );
++		rosterTask->go ( true );
++
++			// send a subscription request.
++		XMPP::JT_Presence *presenceTask = new XMPP::JT_Presence ( jaccount->client()->rootTask () );
++
++		presenceTask->sub ( jid, "subscribe" );
++		presenceTask->go ( true );
++
++		return;
++	}
++}
++
++
++
+ #include "jabberaddcontactpage.moc"
+ 
+ /*
+--- kopete/protocols/jabber/ui/dlgjabberservices.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberservices.cpp	(revision 586398)
+@@ -43,56 +43,53 @@
+ 	}
+ 
+ 	// disable the left margin
+-	tblServices->setLeftMargin (0);
++	//tblServices->setLeftMargin (0);
+ 
+ 	// no content for now
+-	tblServices->setNumRows (0);
++	//tblServices->setNumRows (0);
+ 
+ 	// disable the buttons as long as nothing has been selected
+ 	btnRegister->setDisabled (true);
+ 	btnBrowse->setDisabled (true);
+ 
+ 	// allow autostretching
+-	tblServices->setColumnStretchable (0, true);
+-	tblServices->setColumnStretchable (1, true);
++	//tblServices->setColumnStretchable (0, true);
++	//tblServices->setColumnStretchable (1, true);
+ 
+ 	// disable user selections
+-	tblServices->setSelectionMode (QTable::NoSelection);
++	//tblServices->setSelectionMode (QTable::NoSelection);
+ 
+ 	// name table headers
+-	tblServices->horizontalHeader ()->setLabel (0, i18n ("Name"));
+-	tblServices->horizontalHeader ()->setLabel (1, i18n ("Address"));
++	//tblServices->horizontalHeader ()->setLabel (0, i18n ("Name"));
++	//tblServices->horizontalHeader ()->setLabel (1, i18n ("Address"));
+ 
+-	connect (btnQuery, SIGNAL (clicked ()), this, SLOT (slotQuery ()));
+-	connect (tblServices, SIGNAL (clicked (int, int, int, const QPoint &)), this, SLOT (slotSetSelection (int, int, int, const QPoint &)));
++	connect (btnQuery, SIGNAL (clicked ()), this, SLOT (slotDisco ()));
++	//connect (tblServices, SIGNAL (clicked (int, int, int, const QPoint &)), this, SLOT (slotSetSelection (int, int, int, const QPoint &)));
++	connect (lvServices, SIGNAL (selectionChanged (QListViewItem *)), this, SLOT (slotSetSelection (QListViewItem *)));
+ 
+ 	connect (btnRegister, SIGNAL (clicked ()), this, SLOT (slotRegister ()));
+ 	connect (btnBrowse, SIGNAL (clicked ()), this, SLOT (slotBrowse ()));
+ 
+-	serviceTask = 0L;
+-
+-	selectedRow = 0;
+-
+ }
+ 
+-void dlgJabberServices::slotSetSelection (int row, int, int, const QPoint &)
++void dlgJabberServices::slotSetSelection (QListViewItem *it)
+ {
+-
+-	if(serviceTask && (uint(row) <= serviceTask->agents().count()))
++	dlgJabberServies_item *item=dynamic_cast<dlgJabberServies_item*>(it);
++	if(!item)
+ 	{
+-		tblServices->clearSelection (true);
+-		tblServices->addSelection (QTableSelection (row, 0, row, 1));
+-
+-		// query the agent list about the selected item
+-		btnRegister->setDisabled (!serviceTask->agents()[row].features().canRegister ());
+-		btnBrowse->setDisabled (!serviceTask->agents()[row].features().canSearch ());
+-
+-		selectedRow = row;
++		btnRegister->setDisabled (true);
++		btnBrowse->setDisabled (true);
+ 	}
++	else
++	{
++		btnRegister->setDisabled (! item->can_register);
++		btnBrowse->setDisabled (! item->can_browse);
++		current_jid=item->jid;
++	}
+ 
+ }
+ 
+-void dlgJabberServices::slotQuery ()
++void dlgJabberServices::slotService ()
+ {
+ 
+ 	if(!m_account->isConnected())
+@@ -100,13 +97,10 @@
+ 		m_account->errorConnectFirst();
+ 		return;
+ 	}
++	
++	XMPP::JT_GetServices *serviceTask = new XMPP::JT_GetServices (m_account->client()->rootTask ());
++	connect (serviceTask, SIGNAL (finished ()), this, SLOT (slotServiceFinished ()));
+ 
+-	// create the jabber task
+-	delete serviceTask;
+-
+-	serviceTask = new XMPP::JT_GetServices (m_account->client()->rootTask ());
+-	connect (serviceTask, SIGNAL (finished ()), this, SLOT (slotQueryFinished ()));
+-
+ 	/* populate server field if it is empty */
+ 	if(leServer->text().isEmpty())
+ 		leServer->setText(m_account->server());
+@@ -114,11 +108,12 @@
+ 	kdDebug (14130) << "[dlgJabberServices] Trying to fetch a list of services at " << leServer->text () << endl;
+ 
+ 	serviceTask->get (leServer->text ());
+-	serviceTask->go (false);
+-
++	serviceTask->go (true);
+ }
+ 
+-void dlgJabberServices::slotQueryFinished ()
++
++
++void dlgJabberServices::slotServiceFinished ()
+ {
+ 	kdDebug (14130) << "[dlgJabberServices] Query task finished" << endl;
+ 
+@@ -126,27 +121,76 @@
+ 
+ 	if (!task->success ())
+ 	{
+-		KMessageBox::error (this, i18n ("Unable to retrieve the list of services."), i18n ("Jabber Error"));
++		QString error = task->statusString();
++		KMessageBox::queuedMessageBox (this, KMessageBox::Error, i18n ("Unable to retrieve the list of services.\nReason: %1").arg(error), i18n ("Jabber Error"));
+ 		return;
+ 	}
+ 
+-	tblServices->setNumRows (task->agents ().count ());
++	lvServices->clear();
+ 
+-	int row = 0;
+-
+ 	for (XMPP::AgentList::const_iterator it = task->agents ().begin (); it != task->agents ().end (); ++it)
+ 	{
+-		tblServices->setText (row, 0, (*it).name ());
+-		tblServices->setText (row, 1, (*it).jid ().userHost ());
+-		row++;
++		dlgJabberServies_item *item=new dlgJabberServies_item( lvServices , (*it).jid ().userHost () , (*it).name ());
++		item->jid=(*it).jid();
++		item->can_browse=(*it).features().canSearch();
++		item->can_register=(*it).features().canRegister();
+ 	}
++}
+ 
++void dlgJabberServices::slotDisco()
++{
++	lvServices->clear();
++
++	if(!m_account->isConnected())
++	{
++		m_account->errorConnectFirst();
++		return;
++	}
++	
++	JT_DiscoItems *jt = new JT_DiscoItems(m_account->client()->rootTask());
++	connect(jt, SIGNAL(finished()), this, SLOT(slotDiscoFinished()));
++	
++	/* populate server field if it is empty */
++	if(leServer->text().isEmpty())
++		leServer->setText(m_account->server());
++	
++	jt->get(leServer->text() , QString());
++	jt->go(true);
+ }
+ 
++
++
++
++
++void dlgJabberServices::slotDiscoFinished( )
++{
++	XMPP::JT_DiscoItems *jt = (JT_DiscoItems *)sender();
++
++	if ( jt->success() ) 
++	{
++		QValueList<XMPP::DiscoItem> list = jt->items();
++		
++		lvServices->clear();
++
++		for(QValueList<XMPP::DiscoItem>::ConstIterator it = list.begin(); it != list.end(); ++it) 
++		{
++			const XMPP::DiscoItem a = *it;
++			dlgJabberServies_item *item=new dlgJabberServies_item( lvServices , (*it).jid ().userHost () , (*it).name ());
++			item->jid=a.jid();
++			item->updateInfo(a.jid() , a.node(), m_account);
++		}
++	}
++	else
++	{
++		slotService();
++	}
++}
++
++
+ void dlgJabberServices::slotRegister ()
+ {
+ 
+-	dlgJabberRegister *registerDialog = new dlgJabberRegister (m_account, serviceTask->agents ()[selectedRow].jid ());
++	dlgJabberRegister *registerDialog = new dlgJabberRegister (m_account, current_jid);
+ 
+ 	registerDialog->show ();
+ 	registerDialog->raise ();
+@@ -156,7 +200,7 @@
+ void dlgJabberServices::slotBrowse ()
+ {
+ 
+-	dlgJabberBrowse *browseDialog = new dlgJabberBrowse (m_account, serviceTask->agents ()[selectedRow].jid ());
++	dlgJabberBrowse *browseDialog = new dlgJabberBrowse (m_account, current_jid);
+ 
+ 	browseDialog->show ();
+ 	browseDialog->raise ();
+@@ -165,7 +209,29 @@
+ 
+ dlgJabberServices::~dlgJabberServices ()
+ {
++}
+ 
+-	delete serviceTask;
++void dlgJabberServies_item::updateInfo( const XMPP::Jid & jid , const QString & node , JabberAccount *account )
++{
++	XMPP::JT_DiscoInfo *jt = new XMPP::JT_DiscoInfo(account->client()->rootTask());
++	connect(jt, SIGNAL(finished()),this, SLOT(slotDiscoFinished()));
++	jt->get(jid, node);
++	jt->go(true);
+ 
+ }
++
++void dlgJabberServies_item::slotDiscoFinished( )
++{
++	JT_DiscoInfo *jt = (JT_DiscoInfo *)sender();
++
++	if ( jt->success() ) 
++	{
++		can_browse = jt->item().features().canSearch();
++		can_register = jt->item().features().canRegister();
++	}
++	else
++	{
++		//TODO: error message  (it's a simple message box to show)
++	}
++}
++
+--- kopete/protocols/jabber/ui/dlgjabberregister.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabberregister.cpp	(revision 586398)
+@@ -72,7 +72,8 @@
+ 
+ void dlgJabberRegister::slotSendForm ()
+ {
+-
++	if(!translator)
++		return;
+ 	XMPP::JT_Register * task = new XMPP::JT_Register (m_account->client()->rootTask ());
+ 
+ 	connect (task, SIGNAL (finished ()), this, SLOT (slotSentForm ()));
+--- kopete/protocols/jabber/ui/dlgchatjoin.ui	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgchatjoin.ui	(revision 586398)
+@@ -1,6 +1,6 @@
+-<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+ <class>dlgChatJoin</class>
+-<widget class="QWidget">
++<widget class="KDialog">
+     <property name="name">
+         <cstring>dlgChatJoin</cstring>
+     </property>
+@@ -8,69 +8,123 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>290</width>
+-            <height>122</height>
++            <width>291</width>
++            <height>160</height>
+         </rect>
+     </property>
+     <grid>
+         <property name="name">
+             <cstring>unnamed</cstring>
+         </property>
+-        <widget class="QLayoutWidget" row="0" column="0">
++        <widget class="QLabel" row="2" column="0">
+             <property name="name">
++                <cstring>lblNick</cstring>
++            </property>
++            <property name="text">
++                <string>Nick:</string>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="1" column="1">
++            <property name="name">
++                <cstring>leServer</cstring>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="2" column="1">
++            <property name="name">
++                <cstring>leNick</cstring>
++            </property>
++        </widget>
++        <widget class="QLineEdit" row="0" column="1">
++            <property name="name">
++                <cstring>leRoom</cstring>
++            </property>
++        </widget>
++        <widget class="QLabel" row="0" column="0">
++            <property name="name">
++                <cstring>lblRoom</cstring>
++            </property>
++            <property name="text">
++                <string>Room:</string>
++            </property>
++        </widget>
++        <widget class="QLabel" row="1" column="0">
++            <property name="name">
++                <cstring>lblServer</cstring>
++            </property>
++            <property name="text">
++                <string>Server:</string>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget" row="3" column="1">
++            <property name="name">
+                 <cstring>layout3</cstring>
+             </property>
+-            <grid>
++            <hbox>
+                 <property name="name">
+                     <cstring>unnamed</cstring>
+                 </property>
+-                <widget class="QLabel" row="2" column="0">
++                <spacer>
+                     <property name="name">
+-                        <cstring>lblNick</cstring>
++                        <cstring>spacer2</cstring>
+                     </property>
+-                    <property name="text">
+-                        <string>Nick:</string>
++                    <property name="orientation">
++                        <enum>Horizontal</enum>
+                     </property>
+-                </widget>
+-                <widget class="QLineEdit" row="1" column="1">
+-                    <property name="name">
+-                        <cstring>leServer</cstring>
++                    <property name="sizeType">
++                        <enum>Expanding</enum>
+                     </property>
+-                </widget>
+-                <widget class="QLineEdit" row="2" column="1">
+-                    <property name="name">
+-                        <cstring>leNick</cstring>
++                    <property name="sizeHint">
++                        <size>
++                            <width>41</width>
++                            <height>20</height>
++                        </size>
+                     </property>
+-                </widget>
+-                <widget class="QLineEdit" row="0" column="1">
++                </spacer>
++                <widget class="QPushButton">
+                     <property name="name">
+-                        <cstring>leRoom</cstring>
++                        <cstring>pbJoin</cstring>
+                     </property>
+-                </widget>
+-                <widget class="QLabel" row="0" column="0">
+-                    <property name="name">
+-                        <cstring>lblRoom</cstring>
+-                    </property>
+                     <property name="text">
+-                        <string>Room:</string>
++                        <string>&amp;Join</string>
+                     </property>
++                    <property name="default">
++                        <bool>true</bool>
++                    </property>
+                 </widget>
+-                <widget class="QLabel" row="1" column="0">
++                <widget class="QPushButton">
+                     <property name="name">
+-                        <cstring>lblServer</cstring>
++                        <cstring>pbBrowse</cstring>
+                     </property>
+                     <property name="text">
+-                        <string>Server:</string>
++                        <string>Bro&amp;wse</string>
+                     </property>
+                 </widget>
+-            </grid>
++            </hbox>
+         </widget>
+     </grid>
+ </widget>
++<connections>
++    <connection>
++        <sender>pbJoin</sender>
++        <signal>clicked()</signal>
++        <receiver>dlgChatJoin</receiver>
++        <slot>slotJoin()</slot>
++    </connection>
++    <connection>
++        <sender>pbBrowse</sender>
++        <signal>clicked()</signal>
++        <receiver>dlgChatJoin</receiver>
++        <slot>slotBowse()</slot>
++    </connection>
++</connections>
+ <tabstops>
+     <tabstop>leRoom</tabstop>
+     <tabstop>leServer</tabstop>
+     <tabstop>leNick</tabstop>
+ </tabstops>
++<slots>
++    <slot>slotBowse()</slot>
++    <slot>slotJoin()</slot>
++</slots>
+ <layoutdefaults spacing="6" margin="11"/>
+ </UI>
+--- kopete/protocols/jabber/ui/Makefile.am	(revision 568672)
++++ kopete/protocols/jabber/ui/Makefile.am	(revision 586398)
+@@ -10,19 +10,13 @@
+ 
+ noinst_LTLIBRARIES = libkopetejabberui.la
+ 
+-libkopetejabberui_la_SOURCES = \
+-	dlgsendraw.ui dlgjabbersendraw.cpp \
+-	dlgaddcontact.ui jabberaddcontactpage.cpp \
+-	dlgvcard.ui dlgjabbervcard.cpp \
+-	dlgservices.ui dlgjabberservices.cpp \
+-	dlgregister.ui dlgjabberregister.cpp \
+-	dlgbrowse.ui dlgjabberbrowse.cpp \
+-	dlgchatjoin.ui dlgjabberchatjoin.cpp \
+-	dlgjabbereditaccountwidget.ui jabbereditaccountwidget.cpp \
+-	dlgjabberregisteraccount.ui jabberregisteraccount.cpp \
+-	dlgjabberchooseserver.ui jabberchooseserver.cpp \
+-	dlgchangepassword.ui dlgjabberchangepassword.cpp \
+-	empty.cpp
++libkopetejabberui_la_SOURCES = dlgsendraw.ui dlgjabbersendraw.cpp \
++	dlgaddcontact.ui jabberaddcontactpage.cpp dlgvcard.ui dlgjabbervcard.cpp \
++	dlgjabberservices.cpp dlgregister.ui dlgjabberregister.cpp dlgbrowse.ui dlgjabberbrowse.cpp \
++	dlgjabbereditaccountwidget.ui jabbereditaccountwidget.cpp dlgjabberregisteraccount.ui \
++	jabberregisteraccount.cpp dlgjabberchooseserver.ui jabberchooseserver.cpp dlgchangepassword.ui \
++	dlgjabberchangepassword.cpp empty.cpp dlgchatroomslist.ui dlgjabberchatroomslist.cpp dlgchatjoin.ui \
++	dlgjabberchatjoin.cpp dlgservices.ui
+ 
+ EXTRA_DIST = dlgjabbereditaccountwidget.ui \
+ 	dlgsendraw.ui \
+@@ -32,3 +26,6 @@
+ 	dlgservices.ui \
+ 	dlgregister.ui \
+ 	dlgbrowse.ui
++
++
++noinst_HEADERS = dlgjabberchatroomslist.h dlgjabberchatjoin.h
+--- kopete/protocols/jabber/ui/dlgjabberchatroomslist.cpp	(revision 0)
++++ kopete/protocols/jabber/ui/dlgjabberchatroomslist.cpp	(revision 586398)
+@@ -0,0 +1,117 @@
++//
++// C++ Implementation: 
++//
++// Description: 
++//
++//
++// Author: Kopete Developers <kopete-devel at kde.org>, (C) 2005
++//
++// Copyright: See COPYING file that comes with this distribution
++//
++//
++#include <kmessagebox.h>
++#include <klocale.h>
++#include <kdebug.h>
++
++#include <qtable.h>
++#include <qlineedit.h>
++#include <qpushbutton.h>
++#include <qlabel.h>
++
++#include "dlgjabberchatroomslist.h"
++#include "jabberprotocol.h"
++
++dlgJabberChatRoomsList::dlgJabberChatRoomsList(JabberAccount* account, const QString& server, const QString &nick,  QWidget *parent, const char *name) :
++dlgChatRoomsList(parent, name),
++	m_account(account) , m_selectedRow(-1) ,  m_nick(nick)
++{
++	if (!server.isNull())
++		leServer->setText(server);
++	else if(m_account->isConnected())
++		leServer->setText(m_account->server());
++
++	m_chatServer = leServer->text();
++
++	// locales
++	setCaption(i18n("List Chatrooms"));
++
++	tblChatRoomsList->setLeftMargin (0);
++	tblChatRoomsList->setColumnStretchable(0, true);
++	tblChatRoomsList->setColumnStretchable(1, true);
++
++	if (!server.isNull())
++		slotQuery();
++}
++
++dlgJabberChatRoomsList::~dlgJabberChatRoomsList()
++{
++}
++
++/*$SPECIALIZATION$*/
++void dlgJabberChatRoomsList::slotJoin()
++{
++	if(!m_account->isConnected())
++	{
++		m_account->errorConnectFirst();
++		return;
++	}
++
++	if (m_selectedRow >= 0)
++	{
++		kdDebug (JABBER_DEBUG_GLOBAL) << "join chat room : " <<  m_account->client()->client()->user() << " @ " << tblChatRoomsList->text(m_selectedRow, 0) << " on " << m_chatServer << endl;
++		m_account->client()->joinGroupChat(m_chatServer, tblChatRoomsList->text(m_selectedRow, 0), m_nick);
++	}
++}
++
++void dlgJabberChatRoomsList::slotQuery()
++{
++	if(!m_account->isConnected())
++	{
++		m_account->errorConnectFirst();
++		return;
++	}
++
++	tblChatRoomsList->setNumRows(0);
++
++	XMPP::JT_DiscoItems *discoTask = new XMPP::JT_DiscoItems(m_account->client()->rootTask());
++	connect (discoTask, SIGNAL(finished()), this, SLOT(slotQueryFinished()));
++
++	m_chatServer = leServer->text();
++	discoTask->get(leServer->text());
++	discoTask->go(true);
++}
++
++void dlgJabberChatRoomsList::slotQueryFinished()
++{
++	XMPP::JT_DiscoItems *task = (XMPP::JT_DiscoItems*)sender();
++	if (!task->success())
++	{
++		KMessageBox::queuedMessageBox(this, KMessageBox::Error, i18n("Unable to retrieve the list of chat rooms."),  i18n("Jabber Error"));
++		return;
++	}
++
++	const XMPP::DiscoList& items = task->items();
++	tblChatRoomsList->setNumRows(items.count());
++
++	int row = 0;
++	for (XMPP::DiscoList::const_iterator it = items.begin(); it != items.end(); ++it)
++	{
++		tblChatRoomsList->setText(row, 0, (*it).jid().user());
++		tblChatRoomsList->setText(row, 1, (*it).name());
++		++row;
++	}
++}
++
++void dlgJabberChatRoomsList::slotDoubleClick(int row, int /*col*/, int /*button*/, const QPoint& /*mousePos*/)
++{
++	m_selectedRow = row;
++	slotJoin();
++}
++
++void dlgJabberChatRoomsList::slotClick(int row, int /*col*/, int /*button*/, const QPoint& /*mousePos*/)
++{
++	m_selectedRow = row;
++}
++
++#include "dlgjabberchatroomslist.moc"
++
+--- kopete/protocols/jabber/ui/dlgjabbervcard.cpp	(revision 568672)
++++ kopete/protocols/jabber/ui/dlgjabbervcard.cpp	(revision 586398)
+@@ -4,7 +4,7 @@
+                              -------------------
+     begin                : Thu Aug 08 2002
+     copyright            : (C) 2002-2003 by Till Gerken <till at tantalo.net>
+-    copyright            : (C) 2005      by Michaël Larouche <michael.larouche at kdemail.net>
++                           (C) 2005      by Michaël Larouche <michael.larouche at kdemail.net>
+     email                : kopete-devel at kde.org
+ 
+     Rewritten version of the original dialog
+@@ -22,23 +22,31 @@
+ 
+ #include "dlgjabbervcard.h"
+ 
++// Qt includes
+ #include <qtextedit.h>
++#include <qwidgetstack.h>
++#include <qregexp.h>
++#include <qbuffer.h>
+ 
+-#include <qapplication.h>
+-#include <qwidgetstack.h>
++// KDE includes
+ #include <kdebug.h>
+ #include <kpushbutton.h>
+ #include <klineedit.h>
+ #include <klocale.h>
+ #include <kurllabel.h>
+-#include <kdialogbase.h>
+ #include <kmessagebox.h>
+ #include <krun.h>
++#include <kio/netaccess.h>
++#include <kfiledialog.h>
++#include <kpixmapregionselectordialog.h>
++#include <kstandarddirs.h>
+ 
++// libiris(XMPP backend) includes
+ #include "im.h"
+ #include "xmpp.h"
+ #include "xmpp_tasks.h"
+ 
++// Kopete includes
+ #include "jabberprotocol.h"
+ #include "jabbercontact.h"
+ #include "jabberaccount.h"
+@@ -52,8 +60,8 @@
+  *  name 'name'
+  *
+  */
+-dlgJabberVCard::dlgJabberVCard (JabberAccount *account, JabberContact *contact, QWidget * parent, const char *name)
+-	: KDialogBase (parent, name, false, i18n("Jabber vCard"), Close | User1, Close, false, i18n("&Save User Info"))
++dlgJabberVCard::dlgJabberVCard (JabberAccount *account, JabberBaseContact *contact, QWidget * parent, const char *name)
++	: KDialogBase (parent, name, false, i18n("Jabber vCard"), Close | User1 | User2, Close, false, i18n("&Save User Info"), i18n("&Fetch vCard") )
+ {
+ 
+ 	m_account = account;
+@@ -63,17 +71,20 @@
+ 	setMainWidget(m_mainWidget);
+ 
+ 	connect (this, SIGNAL (user1Clicked()), this, SLOT (slotSaveVCard ()));
+-	connect (m_mainWidget->btnSaveNick, SIGNAL (clicked ()), this, SLOT (slotSaveNickname ()));
++	connect (this, SIGNAL( user2Clicked()), this, SLOT (slotGetVCard ()));
++
++	connect (m_mainWidget->btnSelectPhoto, SIGNAL (clicked()), this, SLOT (slotSelectPhoto()));
++	connect (m_mainWidget->btnClearPhoto, SIGNAL (clicked()), this, SLOT (slotClearPhoto()));
+ 	connect (m_mainWidget->urlHomeEmail, SIGNAL (leftClickedURL(const QString &)), this, SLOT (slotOpenURL (const QString &)));
+ 	connect (m_mainWidget->urlWorkEmail, SIGNAL (leftClickedURL(const QString &)), this, SLOT (slotOpenURL (const QString &)));
+ 	connect (m_mainWidget->urlHomepage, SIGNAL (leftClickedURL(const QString &)), this, SLOT (slotOpenURL (const QString &)));
+ 
+-	if(m_account->myself() == m_contact)
+-		setReadOnly (false);
+-	else
+-		setReadOnly (true);
++	assignContactProperties();
+ 
+-	assignContactProperties();
++	show ();
++	raise ();
++
++	slotGetVCard();
+ }
+ 
+ /*
+@@ -98,13 +109,12 @@
+  */
+ void dlgJabberVCard::assignContactProperties ()
+ {
+-
+ 	// general tab
+ 	m_mainWidget->leNick->setText (m_contact->property(m_account->protocol()->propNickName).value().toString());
+ 	m_mainWidget->leName->setText (m_contact->property(m_account->protocol()->propFullName).value().toString());
+ 	// Guess the JID from the Kopete::Contact if the propJid is empty.
+ 	if( m_contact->property( m_account->protocol()->propJid ).value().toString().isEmpty() )
+-		m_mainWidget->leJID->setText (m_contact->contactId());
++		m_mainWidget->leJID->setText (m_contact->rosterItem().jid().full());
+ 	else
+ 		m_mainWidget->leJID->setText (m_contact->property(m_account->protocol()->propJid).value().toString());
+ 	m_mainWidget->leBirthday->setText (m_contact->property(m_account->protocol()->propBirthday).value().toString());
+@@ -116,6 +126,13 @@
+ 	m_mainWidget->urlHomepage->setURL (homepage);
+ 	m_mainWidget->urlHomepage->setUseCursor ( !homepage.isEmpty () );
+ 
++	// Set photo
++	m_photoPath = m_contact->property(m_account->protocol()->propPhoto).value().toString();
++	if( !m_photoPath.isEmpty() )
++	{
++		m_mainWidget->lblPhoto->setPixmap( QPixmap(m_photoPath) );
++	}
++
+ 	// addresses
+ 	m_mainWidget->leWorkStreet->setText (m_contact->property(m_account->protocol()->propWorkStreet).value().toString());
+ 	m_mainWidget->leWorkExtAddr->setText (m_contact->property(m_account->protocol()->propWorkExtAddr).value().toString());
+@@ -140,12 +157,16 @@
+ 	m_mainWidget->leWorkEmail->setText (workEmail);
+ 	m_mainWidget->urlWorkEmail->setText (workEmail);
+ 	m_mainWidget->urlWorkEmail->setURL ("mailto:" + workEmail);
+-	m_mainWidget->urlWorkEmail->setUseCursor ( !workEmail.stripWhiteSpace().isEmpty () );
++	bool enableMail=!workEmail.stripWhiteSpace().isEmpty ();
++	m_mainWidget->urlWorkEmail->setUseCursor ( enableMail );
++	m_mainWidget->urlWorkEmail->setEnabled ( enableMail ); 
+ 		
+ 	m_mainWidget->leHomeEmail->setText (homeEmail);
+ 	m_mainWidget->urlHomeEmail->setText (homeEmail);
++	enableMail=!homeEmail.stripWhiteSpace().isEmpty ();
+ 	m_mainWidget->urlHomeEmail->setURL ("mailto:" + homeEmail);
+-	m_mainWidget->urlHomeEmail->setUseCursor ( !homeEmail.stripWhiteSpace().isEmpty () );
++	m_mainWidget->urlHomeEmail->setUseCursor ( enableMail );
++	m_mainWidget->urlHomeEmail->setEnabled ( enableMail );
+ 
+ 	// work information tab
+ 	m_mainWidget->leCompany->setText (m_contact->property(m_account->protocol()->propCompanyName).value().toString());
+@@ -161,40 +182,25 @@
+ 
+ 	// about tab
+ 	m_mainWidget->teAbout->setText (m_contact->property(m_account->protocol()->propAbout).value().toString());
+-	
+-	show ();
+-	raise ();
+-}
+ 
+-/*
+- * Save the nickname
+- */
+-void dlgJabberVCard::slotSaveNickname ()
+-{
+-
+-	JabberBaseContact *jc = m_account->contactPool()->findExactMatch ( XMPP::Jid ( m_contact->contactId() ) );
+-
+-	if(!jc)
+-	{
+-		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: Trying to save new nickname for non-existant contact " << m_contact->contactId() << endl;
+-	}
++	if(m_account->myself() == m_contact)
++		setReadOnly (false);
+ 	else
+-	{
+-		jc->metaContact()->setDisplayNameSourceContact( jc );
+-	}
+-
++		setReadOnly (true);
+ }
+ 
+ void dlgJabberVCard::setReadOnly (bool state)
+ {
+-
+ 	// general tab
+-	m_mainWidget->leNick->setReadOnly (false);
++	m_mainWidget->leNick->setReadOnly (state);
+ 	m_mainWidget->leName->setReadOnly (state);
+ 	m_mainWidget->leJID->setReadOnly (state);
+ 	m_mainWidget->leBirthday->setReadOnly (state);
+ 	m_mainWidget->leTimezone->setReadOnly (state);
+ 	m_mainWidget->wsHomepage->raiseWidget(state ? 0 : 1);
++	// Disable photo buttons when read only
++	m_mainWidget->btnSelectPhoto->setEnabled(!state);
++	m_mainWidget->btnClearPhoto->setEnabled(!state);
+ 
+ 	// home address tab
+ 	m_mainWidget->leHomeStreet->setReadOnly (state);
+@@ -231,7 +237,57 @@
+ 
+ 	// save button
+ 	enableButton(User1, !state);
++}
+ 
++void dlgJabberVCard::setEnabled(bool state)
++{
++	// general tab
++	m_mainWidget->leNick->setEnabled (state);
++	m_mainWidget->leName->setEnabled (state);
++	m_mainWidget->leJID->setEnabled (state);
++	m_mainWidget->leBirthday->setEnabled (state);
++	m_mainWidget->leTimezone->setEnabled (state);
++	m_mainWidget->wsHomepage->raiseWidget(state ? 1 : 0);
++	// Disable photo buttons when read only
++	m_mainWidget->btnSelectPhoto->setEnabled(state);
++	m_mainWidget->btnClearPhoto->setEnabled(state);
++
++	// home address tab
++	m_mainWidget->leHomeStreet->setEnabled (state);
++	m_mainWidget->leHomeExtAddr->setEnabled (state);
++	m_mainWidget->leHomePOBox->setEnabled (state);
++	m_mainWidget->leHomeCity->setEnabled (state);
++	m_mainWidget->leHomePostalCode->setEnabled (state);
++	m_mainWidget->leHomeCountry->setEnabled (state);
++	m_mainWidget->wsHomeEmail->raiseWidget(state ? 0 : 1);
++
++	// work address tab
++	m_mainWidget->leWorkStreet->setEnabled (state);
++	m_mainWidget->leWorkExtAddr->setEnabled (state);
++	m_mainWidget->leWorkPOBox->setEnabled (state);
++	m_mainWidget->leWorkCity->setEnabled (state);
++	m_mainWidget->leWorkPostalCode->setEnabled (state);
++	m_mainWidget->leWorkCountry->setEnabled (state);
++	m_mainWidget->wsWorkEmail->raiseWidget(state ? 0 : 1);
++
++	// work information tab
++	m_mainWidget->leCompany->setEnabled (state);
++	m_mainWidget->leDepartment->setEnabled (state);
++	m_mainWidget->lePosition->setEnabled (state);
++	m_mainWidget->leRole->setEnabled (state);
++
++	// phone numbers tab
++	m_mainWidget->lePhoneHome->setEnabled (state);
++	m_mainWidget->lePhoneWork->setEnabled (state);
++	m_mainWidget->lePhoneFax->setEnabled (state);
++	m_mainWidget->lePhoneCell->setEnabled (state);
++
++	// about tab
++	m_mainWidget->teAbout->setEnabled (state);
++
++	// save button
++	enableButton(User1, state);
++	enableButton(User2, state);
+ }
+ 
+ /*
+@@ -239,59 +295,260 @@
+  */
+ void dlgJabberVCard::slotSaveVCard()
+ {
+-	// general tab
+-	m_contact->setProperty(m_account->protocol()->propNickName, m_mainWidget->leNick->text());
+-	m_contact->setProperty(m_account->protocol()->propFullName, m_mainWidget->leName->text());
+-	m_contact->setProperty(m_account->protocol()->propJid, m_mainWidget->leJID->text());
+-	m_contact->setProperty(m_account->protocol()->propBirthday, m_mainWidget->leBirthday->text());
+-	m_contact->setProperty(m_account->protocol()->propTimezone, m_mainWidget->leTimezone->text());
+-	m_contact->setProperty(m_account->protocol()->propHomepage, m_mainWidget->leHomepage->text());
++	setEnabled(false);
++	m_mainWidget->lblStatus->setText( i18n("Saving vCard to server...") );
+ 
++	XMPP::VCard vCard;
++	XMPP::VCard::AddressList addressList;
++	XMPP::VCard::EmailList emailList;
++	XMPP::VCard::PhoneList phoneList;
++
++	// General information
++	vCard.setNickName( m_mainWidget->leNick->text() );
++	vCard.setFullName( m_mainWidget->leName->text() );
++	vCard.setJid( m_mainWidget->leJID->text() );
++	vCard.setBdayStr( m_mainWidget->leBirthday->text() );
++	vCard.setTimezone( m_mainWidget->leTimezone->text() );
++	vCard.setUrl( m_mainWidget->leHomepage->text() );
++
+ 	// home address tab
+-	m_contact->setProperty(m_account->protocol()->propHomeStreet, m_mainWidget->leHomeStreet->text());
+-	m_contact->setProperty(m_account->protocol()->propHomeExtAddr, m_mainWidget->leHomeExtAddr->text());
+-	m_contact->setProperty(m_account->protocol()->propHomePOBox, m_mainWidget->leHomePOBox->text());
+-	m_contact->setProperty(m_account->protocol()->propHomeCity, m_mainWidget->leHomeCity->text());
+-	m_contact->setProperty(m_account->protocol()->propHomePostalCode, m_mainWidget->leHomePostalCode->text());
+-	m_contact->setProperty(m_account->protocol()->propHomeCountry, m_mainWidget->leHomeCountry->text());
++	XMPP::VCard::Address homeAddress;
+ 
++	homeAddress.home = true;
++	homeAddress.street = m_mainWidget->leHomeStreet->text();
++	homeAddress.extaddr = m_mainWidget->leHomeExtAddr->text();
++	homeAddress.pobox = m_mainWidget->leHomePOBox->text();
++	homeAddress.locality = m_mainWidget->leHomeCity->text();
++	homeAddress.pcode = m_mainWidget->leHomePostalCode->text();
++	homeAddress.country = m_mainWidget->leHomeCountry->text();
++
+ 	// work address tab
+-	m_contact->setProperty(m_account->protocol()->propWorkStreet, m_mainWidget->leWorkStreet->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkExtAddr, m_mainWidget->leWorkExtAddr->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkPOBox, m_mainWidget->leWorkPOBox->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkCity, m_mainWidget->leWorkCity->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkPostalCode, m_mainWidget->leWorkPostalCode->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkCountry, m_mainWidget->leWorkCountry->text());
++	XMPP::VCard::Address workAddress;
+ 
+-	// email addresses
+-	m_contact->setProperty(m_account->protocol()->propEmailAddress, m_mainWidget->leHomeEmail->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkEmailAddress, m_mainWidget->leWorkEmail->text());
++	workAddress.work = true;
++	workAddress.street = m_mainWidget->leWorkStreet->text();
++	workAddress.extaddr = m_mainWidget->leWorkExtAddr->text();
++	workAddress.pobox = m_mainWidget->leWorkPOBox->text();
++	workAddress.locality = m_mainWidget->leWorkCity->text();
++	workAddress.pcode = m_mainWidget->leWorkPostalCode->text();
++	workAddress.country = m_mainWidget->leWorkCountry->text();
+ 
++	addressList.append(homeAddress);
++	addressList.append(workAddress);
++
++	vCard.setAddressList(addressList);
++
++	// home email
++	XMPP::VCard::Email homeEmail;
++
++	homeEmail.home = true;
++	homeEmail.userid = m_mainWidget->leHomeEmail->text();
++
++	// work email
++	XMPP::VCard::Email workEmail;
++
++	workEmail.work = true;
++	workEmail.userid = m_mainWidget->leWorkEmail->text();
++
++	emailList.append(homeEmail);
++	emailList.append(workEmail);
++
++	vCard.setEmailList(emailList);
++
+ 	// work information tab
+-	m_contact->setProperty(m_account->protocol()->propCompanyName, m_mainWidget->leCompany->text());
+-	m_contact->setProperty(m_account->protocol()->propCompanyDepartement, m_mainWidget->leDepartment->text());
+-	m_contact->setProperty(m_account->protocol()->propCompanyPosition, m_mainWidget->lePosition->text());
+-	m_contact->setProperty(m_account->protocol()->propCompanyRole, m_mainWidget->leRole->text());
++	XMPP::VCard::Org org;
++	org.name = m_mainWidget->leCompany->text();
++	org.unit = QStringList::split(",", m_mainWidget->leDepartment->text());
++	vCard.setOrg(org);
++	vCard.setTitle( m_mainWidget->lePosition->text() );
++	vCard.setRole( m_mainWidget->leRole->text() );
+ 
+ 	// phone numbers tab
+-	m_contact->setProperty(m_account->protocol()->propPrivatePhone, m_mainWidget->lePhoneHome->text());
+-	m_contact->setProperty(m_account->protocol()->propWorkPhone, m_mainWidget->lePhoneWork->text());
+-	m_contact->setProperty(m_account->protocol()->propPhoneFax, m_mainWidget->lePhoneFax->text());
+-	m_contact->setProperty(m_account->protocol()->propPrivateMobilePhone, m_mainWidget->lePhoneCell->text());
++	XMPP::VCard::Phone phoneHome;
++	phoneHome.home = true;
++	phoneHome.number = m_mainWidget->lePhoneHome->text();
+ 
++	XMPP::VCard::Phone phoneWork;
++	phoneWork.work = true;
++	phoneWork.number = m_mainWidget->lePhoneWork->text();
++
++	XMPP::VCard::Phone phoneFax;
++	phoneFax.fax = true;
++	phoneFax.number = m_mainWidget->lePhoneFax->text();
++
++	XMPP::VCard::Phone phoneCell;
++	phoneCell.cell = true;
++	phoneCell.number = m_mainWidget->lePhoneCell->text();
++
++	phoneList.append(phoneHome);
++	phoneList.append(phoneWork);
++	phoneList.append(phoneFax);
++	phoneList.append(phoneCell);
++
++	vCard.setPhoneList(phoneList);
++
+ 	// about tab
+-	m_contact->setProperty(m_account->protocol()->propAbout, m_mainWidget->teAbout->text());
++	vCard.setDesc( m_mainWidget->teAbout->text() );
+ 
+-	emit informationChanged();
++	// Set contact photo as a binary value (if he has set a photo)
++	if( !m_photoPath.isEmpty() )
++	{
++		QString photoPath = m_photoPath;
++		QImage image( photoPath );
++		QByteArray ba;
++		QBuffer buffer( ba );
++		buffer.open( IO_WriteOnly );
++		image.save( &buffer, "PNG" );
++		vCard.setPhoto( ba );
++	}
+ 
++	vCard.setVersion("3.0");
++	vCard.setProdId("Kopete");
++
++	XMPP::JT_VCard *task = new XMPP::JT_VCard( m_account->client()->rootTask() );
++	// signal to ourselves when the vCard data arrived
++	QObject::connect(task, SIGNAL(finished()), this, SLOT(slotVCardSaved()));
++	task->set(vCard);
++	task->go(true);
+ }
+ 
++void dlgJabberVCard::slotVCardSaved()
++{
++	XMPP::JT_VCard *vCard = (XMPP::JT_VCard*)sender();
++	
++	if( vCard->success() )
++	{
++		m_mainWidget->lblStatus->setText( i18n("vCard save sucessful.") );
++		m_contact->setPropertiesFromVCard( vCard->vcard() );
++	}
++	else
++	{
++		m_mainWidget->lblStatus->setText( i18n("Error: Unable to save vCard.") );
++	}
++
++	setEnabled(true);
++}
++
++void dlgJabberVCard::slotGetVCard()
++{
++	m_mainWidget->lblStatus->setText( i18n("Fetching contact vCard...") );
++
++	setReadOnly(true);
++	setEnabled(false);
++
++	XMPP::JT_VCard *task = new XMPP::JT_VCard ( m_account->client()->rootTask() );
++	// signal to ourselves when the vCard data arrived
++	QObject::connect( task, SIGNAL ( finished () ), this, SLOT ( slotGotVCard () ) );
++	task->get ( m_contact->rosterItem().jid().full() );
++	task->go ( true );	
++}
++
++void dlgJabberVCard::slotGotVCard()
++{
++	XMPP::JT_VCard * vCard = (XMPP::JT_VCard *) sender ();
++	
++	if( vCard->success() )
++	{
++		m_contact->setPropertiesFromVCard( vCard->vcard() );
++		setEnabled( true );
++
++		assignContactProperties();		
++
++		m_mainWidget->lblStatus->setText( i18n("vCard fetching Done.") );
++	}
++	else
++	{
++		m_mainWidget->lblStatus->setText( i18n("Error: vCard could not be fetched correctly. Check connectivity with the Jabber server.") );
++		//it is maybe possible to anyway edit our own vCard (if it is new
++		if(m_account->myself() == m_contact)
++			setEnabled( true );
++	}
++}
++
++void dlgJabberVCard::slotSelectPhoto()
++{
++	QString path;
++	bool remoteFile = false;
++	KURL filePath = KFileDialog::getImageOpenURL( QString::null, this, i18n( "Jabber Photo" ) );
++	if( filePath.isEmpty() )
++		return;
++
++	if( !filePath.isLocalFile() ) 
++	{
++		if( !KIO::NetAccess::download( filePath, path, this ) ) 
++		{
++			KMessageBox::queuedMessageBox( this, KMessageBox::Sorry, i18n( "Downloading of Jabber contact photo failed!" ) );
++			return;
++		}
++		remoteFile = true;
++	}
++	else 
++		path = filePath.path();
++
++	QImage img( path );
++	img = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap(img), 96, 96, this );
++
++	if( !img.isNull() ) 
++	{
++		if(img.width() > 96 || img.height() > 96)
++		{
++			// Scale and crop the picture.
++			img = img.smoothScale( 96, 96, QImage::ScaleMin );
++			// crop image if not square
++			if(img.width() < img.height()) 
++				img = img.copy((img.width()-img.height())/2, 0, 96, 96);
++			else if (img.width() > img.height())
++				img = img.copy(0, (img.height()-img.width())/2, 96, 96);
++
++		}
++		else if (img.width() < 32 || img.height() < 32)
++		{
++			// Scale and crop the picture.
++			img = img.smoothScale( 32, 32, QImage::ScaleMin );
++			// crop image if not square
++			if(img.width() < img.height())
++				img = img.copy((img.width()-img.height())/2, 0, 32, 32);
++			else if (img.width() > img.height())
++				img = img.copy(0, (img.height()-img.width())/2, 32, 32);
++	
++		}
++		else if (img.width() != img.height())
++		{
++			if(img.width() < img.height())
++				img = img.copy((img.width()-img.height())/2, 0, img.height(), img.height());
++			else if (img.width() > img.height())
++				img = img.copy(0, (img.height()-img.width())/2, img.height(), img.height());
++		}
++
++		m_photoPath = locateLocal("appdata", "jabberphotos/" + m_contact->rosterItem().jid().full().lower().replace(QRegExp("[./~]"),"-")  +".png");
++		if( img.save(m_photoPath, "PNG") )
++		{
++			m_mainWidget->lblPhoto->setPixmap( QPixmap(img) );
++		}
++		else
++		{
++			m_photoPath = QString::null;
++		}
++	}
++	else
++	{
++		KMessageBox::queuedMessageBox( this, KMessageBox::Sorry, i18n( "<qt>An error occurred when trying to change the photo.<br>"
++			"Make sure that you have selected a correct image file</qt>" ) );
++	}
++	if( remoteFile )
++		KIO::NetAccess::removeTempFile( path );
++}
++
++void dlgJabberVCard::slotClearPhoto()
++{
++	m_mainWidget->lblPhoto->setPixmap( QPixmap() );
++	m_photoPath = QString::null;
++}
++
+ void dlgJabberVCard::slotOpenURL(const QString &url)
+ {
+-
+ 	if ( !url.isEmpty () || (url == QString::fromLatin1("mailto:") ) )
+ 		new KRun(KURL( url ) );
+-
+ }
+ 
+ #include "dlgjabbervcard.moc"
+--- kopete/protocols/jabber/jabbergroupchatmanager.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabbergroupchatmanager.cpp	(revision 586398)
+@@ -34,6 +34,8 @@
+ 	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "New message manager for " << user->contactId () << endl;
+ 
+ 	mRoomJid = roomJid;
++	
++	setMayInvite( true );
+ 
+ 	// make sure Kopete knows about this instance
+ 	Kopete::ChatSessionManager::self()->registerChatSession ( this );
+@@ -42,7 +44,10 @@
+ 			  this, SLOT ( slotMessageSent ( Kopete::Message &, Kopete::ChatSession * ) ) );
+ 
+ 	updateDisplayName ();
++}
+ 
++JabberGroupChatManager::~JabberGroupChatManager()
++{
+ }
+ 
+ void JabberGroupChatManager::updateDisplayName ()
+@@ -63,7 +68,7 @@
+ JabberAccount *JabberGroupChatManager::account () const
+ {
+ 
+-	return static_cast<JabberAccount *>(Kopete::ChatSession::account ());
++	return user()->account();
+ 
+ }
+ 
+@@ -74,8 +79,8 @@
+ 	{
+ 		XMPP::Message jabberMessage;
+ 
+-		XMPP::Jid jid ( message.from()->contactId () );
+-		jabberMessage.setFrom ( jid );
++		jabberMessage.setFrom ( account()->client()->jid() );
++		
+ 
+ 		XMPP::Jid toJid ( mRoomJid );
+ 
+@@ -128,9 +133,30 @@
+ 		// but we need to stop the animation etc.
+ 		messageSucceeded ();
+ 	}
++}
+ 
++void JabberGroupChatManager::inviteContact( const QString & contactId )
++{
++	if( account()->isConnected () )
++	{
++		//NOTE: this is the obsolete, NOT RECOMMANDED protocol.
++		//      iris doesn't implement groupchat yet
++		XMPP::Message jabberMessage;
++		jabberMessage.setFrom ( account()->client()->jid() );
++		jabberMessage.setTo ( contactId );
++		jabberMessage.setInvite( mRoomJid.userHost() );
++		jabberMessage.setBody( i18n("You have been invited to %1").arg( mRoomJid.userHost() ) );
++
++		// send the message
++		account()->client()->sendMessage ( jabberMessage );
++	}
++	else
++	{
++		account()->errorConnectFirst ();
++	}
+ }
+ 
++
+ #include "jabbergroupchatmanager.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/jabber/jabberresource.cpp	(revision 568672)
++++ kopete/protocols/jabber/jabberresource.cpp	(revision 586398)
+@@ -1,9 +1,10 @@
+  /*
+   * jabberresource.cpp
+   *
++  * Copyright (c) 2005-2006 by Michaël Larouche <michael.larouche at kdemail.net>
+   * Copyright (c) 2004 by Till Gerken <till at tantalo.net>
+   *
+-  * Kopete    (c) by the Kopete developers  <kopete-devel at kde.org>
++  * Kopete    (c) 2001-2006 by the Kopete developers  <kopete-devel at kde.org>
+   *
+   * *************************************************************************
+   * *                                                                       *
+@@ -17,81 +18,115 @@
+ 
+ #include "jabberresource.h"
+ 
++// Qt includes
++#include <qtimer.h>
++
++// KDE includes
+ #include <kdebug.h>
+-#include <qtimer.h>
+-#include "xmpp_tasks.h"
++
++// libiris includes
++#include <im.h>
++#include <xmpp_tasks.h>
++
++// Kopete includes
++#include "jabberprotocol.h"
+ #include "jabberaccount.h"
++#include "jabbercapabilitiesmanager.h"
+ 
++class JabberResource::Private
++{
++public:
++	Private( JabberAccount *t_account, const XMPP::Jid &t_jid, const XMPP::Resource &t_resource )
++	 : account(t_account), jid(t_jid), resource(t_resource), capsEnabled(false)
++	{
++		// Make sure the resource is always set.
++		jid.setResource(resource.name());
++	}
++
++	JabberAccount *account;
++	XMPP::Jid jid;
++	XMPP::Resource resource;
++	
++	QString clientName, clientSystem;
++	XMPP::Features supportedFeatures;
++	bool capsEnabled;
++};
++
+ JabberResource::JabberResource ( JabberAccount *account, const XMPP::Jid &jid, const XMPP::Resource &resource )
++	: d( new Private(account, jid, resource) )
+ {
++	d->capsEnabled = account->protocol()->capabilitiesManager()->capabilitiesEnabled(jid);
+ 
+-	mJid = jid;
+-	mResource = resource;
+-	mAccount = account;
+-
+ 	if ( account->isConnected () )
+ 	{
+-		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Scheduling request for client version for " << jid.full () << endl;
+-
+ 		QTimer::singleShot ( account->client()->getPenaltyTime () * 1000, this, SLOT ( slotGetTimedClientVersion () ) );
++		if(!d->capsEnabled)
++		{
++			QTimer::singleShot ( account->client()->getPenaltyTime () * 1000, this, SLOT ( slotGetDiscoCapabilties () ) );
++		}
+ 	}
+-
+ }
+ 
+ JabberResource::~JabberResource ()
+ {
++	delete d;
+ }
+ 
+ const XMPP::Jid &JabberResource::jid () const
+ {
+-
+-	return mJid;
+-
++	return d->jid;
+ }
+ 
+ const XMPP::Resource &JabberResource::resource () const
+ {
+-
+-	return mResource;
+-
++	return d->resource;
+ }
+ 
+ void JabberResource::setResource ( const XMPP::Resource &resource )
+ {
++	d->resource = resource;
+ 
+-	mResource = resource;
++	// Check if the caps are now available.
++	d->capsEnabled = d->account->protocol()->capabilitiesManager()->capabilitiesEnabled(d->jid);
+ 
++	emit updated( this );
+ }
+ 
+ const QString &JabberResource::clientName () const
+ {
+-
+-	return mClientName;
+-
++	return d->clientName;
+ }
+ 
+ const QString &JabberResource::clientSystem () const
+ {
++	return d->clientSystem;
++}
+ 
+-	return mClientSystem;
+-
++XMPP::Features JabberResource::features() const
++{
++	if(d->capsEnabled)
++	{
++		return d->account->protocol()->capabilitiesManager()->features(d->jid);
++	}
++	else
++	{
++		return d->supportedFeatures;
++	}
+ }
+ 
+ void JabberResource::slotGetTimedClientVersion ()
+ {
+-
+-	if ( mAccount->isConnected () )
++	if ( d->account->isConnected () )
+ 	{
+-		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Requesting client version for " << mJid.full () << endl;
++		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Requesting client version for " << d->jid.full () << endl;
+ 
+ 		// request client version
+-		XMPP::JT_ClientVersion *task = new XMPP::JT_ClientVersion ( mAccount->client()->rootTask () );
++		XMPP::JT_ClientVersion *task = new XMPP::JT_ClientVersion ( d->account->client()->rootTask () );
+ 		// signal to ourselves when the vCard data arrived
+ 		QObject::connect ( task, SIGNAL ( finished () ), this, SLOT ( slotGotClientVersion () ) );
+-		task->get ( mJid );
++		task->get ( d->jid );
+ 		task->go ( true );
+ 	}
+-
+ }
+ 
+ void JabberResource::slotGotClientVersion ()
+@@ -100,12 +135,37 @@
+ 
+ 	if ( clientVersion->success () )
+ 	{
+-		mClientName = clientVersion->name () + " " + clientVersion->version ();
+-		mClientSystem = clientVersion->os ();
++		d->clientName = clientVersion->name () + " " + clientVersion->version ();
++		d->clientSystem = clientVersion->os ();
++
++		emit updated ( this );
+ 	}
++}
+ 
+-	emit updated ( this );
++void JabberResource:: slotGetDiscoCapabilties ()
++{
++	if ( d->account->isConnected () )
++	{
++		kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Requesting Client Features for " << d->jid.full () << endl;
+ 
++		XMPP:: JT_DiscoInfo *task = new XMPP::JT_DiscoInfo ( d->account->client()->rootTask () );
++		// Retrive features when service discovery is done.
++		QObject::connect ( task, SIGNAL ( finished () ), this, SLOT (slotGotDiscoCapabilities () ) );
++		task->get ( d->jid);
++		task->go ( true );
++	}
+ }
+ 
++void JabberResource::slotGotDiscoCapabilities ()
++{
++	XMPP::JT_DiscoInfo *discoInfo = (XMPP::JT_DiscoInfo *) sender ();
++
++	if ( discoInfo->success () )
++	{
++		d->supportedFeatures = discoInfo->item().features();
++		
++		emit updated ( this );
++	}
++}
++
+ #include "jabberresource.moc"
+--- kopete/protocols/oscar/oscarvisibilitydialog.cpp	(revision 0)
++++ kopete/protocols/oscar/oscarvisibilitydialog.cpp	(revision 586398)
+@@ -0,0 +1,135 @@
++/*
++    oscarvisibilitydialog.cpp  -  Visibility Dialog
++
++    Copyright (c) 2005 by Roman Jarosz <kedgedev at centrum.cz>
++    Kopete    (c) 2005 by the Kopete developers  <kopete-devel at 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 "oscarvisibilitydialog.h"
++
++#include <qstringlist.h>
++#include <qpushbutton.h>
++
++#include <klocale.h>
++
++#include "oscarvisibilitybase.h"
++#include "client.h"
++
++
++OscarVisibilityDialog::OscarVisibilityDialog( Client* client, QWidget* parent )
++ : KDialogBase( parent,  0, false, i18n( "Add Contacts to Visible or Invisible List" ),
++                Ok | Cancel ), m_client( client )
++{
++	m_visibilityUI = new OscarVisibilityBase( this );
++	setMainWidget( m_visibilityUI );
++	
++	QObject::connect(m_visibilityUI->visibleAdd, SIGNAL(clicked()),
++	                 this, SLOT(slotAddToVisible()));
++	QObject::connect(m_visibilityUI->visibleRemove, SIGNAL(clicked()),
++	                 this, SLOT(slotRemoveFromVisible()));
++	QObject::connect(m_visibilityUI->invisibleAdd, SIGNAL(clicked()),
++	                 this, SLOT(slotAddToInvisible()));
++	QObject::connect(m_visibilityUI->invisibleRemove, SIGNAL(clicked()),
++	                 this, SLOT(slotRemoveFromInvisible()));
++}
++
++void OscarVisibilityDialog::addContacts( const ContactMap& contacts )
++{
++	m_contactMap = contacts;
++	
++	ContactMap::Iterator it, cEnd = m_contactMap.end();
++	for ( it = m_contactMap.begin(); it != cEnd; ++it )
++		m_visibilityUI->contacts->insertItem( it.key() );
++	
++}
++
++void OscarVisibilityDialog::addVisibleContacts( const QStringList& contactList )
++{
++	m_visibilityUI->visibleContacts->insertStringList( contactList );
++}
++
++void OscarVisibilityDialog::addInvisibleContacts( const QStringList& contactList )
++{
++	m_visibilityUI->invisibleContacts->insertStringList( contactList );
++}
++
++void OscarVisibilityDialog::slotAddToVisible()
++{
++	QListBoxItem *itm = m_visibilityUI->contacts->selectedItem();
++	if ( !itm ) return;
++	
++	QString contactId = m_contactMap[itm->text()];
++	m_visibleListChangesMap[contactId] = Add;
++	
++	if ( !m_visibilityUI->visibleContacts->findItem( itm->text(), Qt::CaseSensitive | Qt::ExactMatch ) )
++		m_visibilityUI->visibleContacts->insertItem( itm->text() );
++}
++
++void OscarVisibilityDialog::slotRemoveFromVisible()
++{
++	QListBoxItem *itm = m_visibilityUI->visibleContacts->selectedItem();
++	if ( !itm ) return;
++	
++	QString contactId = m_contactMap[itm->text()];
++	m_visibleListChangesMap[contactId] = Remove;
++	
++	int visIdx = m_visibilityUI->visibleContacts->index( itm );
++	m_visibilityUI->visibleContacts->removeItem( visIdx );
++}
++
++void OscarVisibilityDialog::slotAddToInvisible()
++{
++	QListBoxItem *itm = m_visibilityUI->contacts->selectedItem();
++	if ( !itm ) return;
++	
++	QString contactId = m_contactMap[itm->text()];
++	m_invisibleListChangesMap[contactId] = Add;
++	
++	if ( !m_visibilityUI->invisibleContacts->findItem( itm->text(), Qt::CaseSensitive | Qt::ExactMatch ) )
++		m_visibilityUI->invisibleContacts->insertItem( itm->text() );
++}
++
++void OscarVisibilityDialog::slotRemoveFromInvisible()
++{
++	QListBoxItem *itm = m_visibilityUI->invisibleContacts->selectedItem();
++	if ( !itm ) return;
++	
++	QString contactId = m_contactMap[itm->text()];
++	m_invisibleListChangesMap[contactId] = Remove;
++	
++	int visIdx = m_visibilityUI->invisibleContacts->index( itm );
++	m_visibilityUI->invisibleContacts->removeItem( visIdx );
++}
++
++void OscarVisibilityDialog::slotOk()
++{
++	ChangeMap::Iterator it, cEnd = m_visibleListChangesMap.end();
++	for ( it = m_visibleListChangesMap.begin(); it != cEnd; ++it ) {
++		m_client->setVisibleTo( it.key(), it.data() );
++	}
++	
++	cEnd = m_invisibleListChangesMap.end();
++	for ( it = m_invisibleListChangesMap.begin(); it != cEnd; ++it ) {
++		m_client->setInvisibleTo( it.key(), it.data() );
++	}
++	
++	KDialogBase::slotOk();
++	emit closing();
++}
++
++void OscarVisibilityDialog::slotCancel()
++{
++	KDialogBase::slotCancel();
++	emit closing();
++}
++
++#include "oscarvisibilitydialog.moc"
+--- kopete/protocols/oscar/oscarversionupdater.cpp	(revision 0)
++++ kopete/protocols/oscar/oscarversionupdater.cpp	(revision 586398)
+@@ -0,0 +1,295 @@
++/*
++    oscarversionupdater.cpp  -  Version Updater
++
++    Copyright (c) 2006 by Roman Jarosz <kedgedev at centrum.cz>
++    Kopete    (c) 2006 by the Kopete developers  <kopete-devel at 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 "oscarversionupdater.h"
++
++#include <qdom.h>
++#include <qmutex.h>
++
++#include <kdebug.h>
++#include <kio/job.h>
++#include <kconfig.h>
++#include <kglobal.h>
++
++
++QMutex updateMutex;
++OscarVersionUpdater *OscarVersionUpdater::versionUpdaterStatic = 0L;
++
++OscarVersionUpdater::OscarVersionUpdater()
++: mStamp( 1 ), mUpdating( false )
++{
++	initICQVersionInfo();
++	initAIMVersionInfo();
++}
++
++OscarVersionUpdater::~OscarVersionUpdater()
++{
++}
++
++OscarVersionUpdater *OscarVersionUpdater::self()
++{
++	if ( !versionUpdaterStatic )
++		versionUpdaterStatic = new OscarVersionUpdater();
++	
++	return versionUpdaterStatic;
++}
++
++bool OscarVersionUpdater::update( unsigned int stamp )
++{
++	kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << endl;
++	bool doUpdate = false;
++	bool isUpdating = false;
++	
++	updateMutex.lock();
++	if ( !mUpdating && stamp == mStamp )
++	{
++		doUpdate = true;
++		mUpdating = true;
++	}
++	isUpdating = mUpdating;
++	updateMutex.unlock();
++	
++	if ( doUpdate )
++	{
++		mVersionData.resize( 0 );
++		
++		KConfigGroup config( KGlobal::config(), "Oscar" );
++		QString url = config.readEntry( "NewVersionURL", "http://kopete.kde.org/oscarversions.xml" );
++		mTransferJob = KIO::get ( url );
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Download version info from server."<< endl;
++		
++		connect ( mTransferJob, SIGNAL ( result ( KIO::Job* ) ),
++		          this, SLOT ( slotTransferResult ( KIO::Job* ) ) );
++		connect ( mTransferJob, SIGNAL ( data ( KIO::Job*, const QByteArray& ) ),
++		          this, SLOT ( slotTransferData ( KIO::Job*, const QByteArray& ) ) );
++	}
++	return isUpdating;
++}
++
++unsigned int OscarVersionUpdater::stamp() const
++{
++	return mStamp;
++}
++
++void OscarVersionUpdater::initICQVersionInfo()
++{
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl;
++	KConfigGroup config( KGlobal::config(), "ICQVersion" );
++	
++	mICQVersion.clientString = config.readEntry( "ClientString", "ICQBasic" );
++	mICQVersion.clientId = config.readEntry( "ClientId", "0x010A" ).toUShort( 0, 0 );
++	mICQVersion.major = config.readEntry( "Major", "0x0014" ).toUShort( 0, 0 );
++	mICQVersion.minor = config.readEntry( "Minor", "0x0034" ).toUShort( 0, 0 );
++	mICQVersion.point = config.readEntry( "Point", "0x0000" ).toUShort( 0, 0 );
++	mICQVersion.build = config.readEntry( "Build", "0x0BB8" ).toUShort( 0, 0 );
++	mICQVersion.other = config.readEntry( "Other", "0x0000043D" ).toUInt( 0, 0 );
++	mICQVersion.country = config.readEntry( "Country", "us" );
++	mICQVersion.lang = config.readEntry( "Lang", "en" );
++}
++
++void OscarVersionUpdater::initAIMVersionInfo()
++{
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl;
++	
++	KConfigGroup config( KGlobal::config(), "AIMVersion" );
++	
++	mAIMVersion.clientString = config.readEntry( "ClientString", "AOL Instant Messenger (SM), version 5.1.3036/WIN32" );
++	mAIMVersion.clientId = config.readEntry( "ClientId", "0x0109" ).toUShort( 0, 0 );
++	mAIMVersion.major = config.readEntry( "Major", "0x0005" ).toUShort( 0, 0 );
++	mAIMVersion.minor = config.readEntry( "Minor", "0x0001" ).toUShort( 0, 0 );
++	mAIMVersion.point = config.readEntry( "Point", "0x0000" ).toUShort( 0, 0 );
++	mAIMVersion.build = config.readEntry( "Build", "0x0bdc" ).toUShort( 0, 0 );
++	mAIMVersion.other = config.readEntry( "Other", "0x000000d2" ).toUInt( 0, 0 );
++	mAIMVersion.country = config.readEntry( "Country", "us" );
++	mAIMVersion.lang = config.readEntry( "Lang", "en" );
++}
++
++void OscarVersionUpdater::printDebug()
++{
++	kdDebug(OSCAR_RAW_DEBUG) << "*************** AIM VERSION INFO ***************" << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "client string: " << mAIMVersion.clientString << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "client id: "  << QString::number( mAIMVersion.clientId, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "major: "  << QString::number( mAIMVersion.major, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "minor: "  << QString::number( mAIMVersion.minor, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "point: "  << QString::number( mAIMVersion.point, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "build: "  << QString::number( mAIMVersion.build, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "other: "  << QString::number( mAIMVersion.other, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "country: "  << mAIMVersion.country << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "lang: "  << mAIMVersion.lang << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "************************************************" << endl;
++	
++	kdDebug(OSCAR_RAW_DEBUG) << "*************** ICQ VERSION INFO ***************" << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "client string: " << mICQVersion.clientString << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "client id: "  << QString::number( mICQVersion.clientId, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "major: "  << QString::number( mICQVersion.major, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "minor: "  << QString::number( mICQVersion.minor, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "point: "  << QString::number( mICQVersion.point, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "build: "  << QString::number( mICQVersion.build, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "other: "  << QString::number( mICQVersion.other, 16 ) << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "country: "  << mICQVersion.country << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "lang: "  << mICQVersion.lang << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "************************************************" << endl;
++}
++
++void OscarVersionUpdater::slotTransferData ( KIO::Job */*job*/, const QByteArray &data )
++{
++	unsigned oldSize = mVersionData.size();
++	mVersionData.resize ( oldSize + data.size() );
++	memcpy ( &mVersionData.data()[oldSize], data.data(), data.size() );
++	
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Data size " << mVersionData.size() << endl;
++}
++
++void OscarVersionUpdater::slotTransferResult ( KIO::Job *job )
++{
++	bool bUpdate = false;
++	if ( job->error() || mTransferJob->isErrorPage() )
++	{
++		//TODO show error
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Download of version info has faild!" << endl;
++	}
++	else
++	{
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Updating version info" << endl;
++		
++		QDomDocument doc;
++		if ( doc.setContent ( mVersionData ) )
++		{
++			Oscar::ClientVersion tmpICQ = mICQVersion;
++			Oscar::ClientVersion tmpAIM = mAIMVersion;
++			
++			parseDocument( doc );
++			
++			if ( !equal( tmpICQ, mICQVersion ) )
++			{
++				storeVersionInfo( "ICQVersion", mICQVersion );
++				bUpdate = true;
++			}
++			
++			if ( !equal( tmpAIM, mAIMVersion ) )
++			{
++				storeVersionInfo( "AIMVersion", mAIMVersion );
++				bUpdate = true;
++			}
++		}
++	}
++	
++	// clear
++	mVersionData.resize( 0 );
++	mTransferJob = 0;
++	
++	updateMutex.lock();
++	if ( bUpdate )
++		mStamp++;
++	mUpdating = false;
++	updateMutex.unlock();
++}
++
++void OscarVersionUpdater::parseDocument( QDomDocument& doc )
++{
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl;
++	
++	QDomElement root = doc.documentElement();
++	if ( root.tagName() != "oscar" )
++		return;
++	
++	QDomElement versionElement = root.firstChild().toElement();
++	while( !versionElement.isNull() )
++	{
++		if ( versionElement.tagName() == "icq" )
++			parseVersion( mICQVersion, versionElement );
++		else if ( versionElement.tagName() == "aim" )
++			parseVersion( mAIMVersion, versionElement );
++		
++		versionElement = versionElement.nextSibling().toElement();
++	}
++}
++
++bool OscarVersionUpdater::parseVersion( Oscar::ClientVersion& version, QDomElement& element )
++{
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl;
++	
++	// clear structure
++	version.clientString = QString::null;
++	version.clientId = 0x0000;
++	version.major = 0x0000;
++	version.minor = 0x0000;
++	version.point = 0x0000;
++	version.build = 0x0000;
++	version.other = 0x00000000;
++	version.country = QString::null;
++	version.lang = QString::null;
++	
++	QDomElement versionChild = element.firstChild().toElement();
++	while ( !versionChild.isNull() )
++	{
++		if ( versionChild.tagName() == "client" )
++			version.clientString = versionChild.text();
++		else if ( versionChild.tagName() == "clientId" )
++			version.clientId = versionChild.text().toUShort( 0, 0);
++		else if ( versionChild.tagName() == "major" )
++			version.major = versionChild.text().toUShort( 0, 0 );
++		else if ( versionChild.tagName() == "minor" )
++			version.minor = versionChild.text().toUShort( 0, 0 );
++		else if ( versionChild.tagName() == "point" )
++			version.point = versionChild.text().toUShort( 0, 0 );
++		else if ( versionChild.tagName() == "build" )
++			version.build = versionChild.text().toUShort( 0, 0 );
++		else if ( versionChild.tagName() == "other" )
++			version.other = versionChild.text().toUInt( 0, 0 );
++		else if ( versionChild.tagName() == "country" )
++			version.country = versionChild.text();
++		else if ( versionChild.tagName() == "lang" )
++			version.lang = versionChild.text();
++		
++		versionChild = versionChild.nextSibling().toElement();
++	}
++	
++	return true;
++}
++
++void OscarVersionUpdater::storeVersionInfo( const QString& group, const Oscar::ClientVersion& version ) const
++{
++	kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Storing version info to group: " << group << endl;
++	KConfigGroup config( KGlobal::config(), group );
++	
++	config.writeEntry( "ClientString", version.clientString );
++	config.writeEntry( "ClientId", version.clientId );
++	config.writeEntry( "Major", version.major );
++	config.writeEntry( "Minor", version.minor );
++	config.writeEntry( "Point", version.point );
++	config.writeEntry( "Build", version.build );
++	config.writeEntry( "Other", version.other );
++	config.writeEntry( "Country", version.country );
++	config.writeEntry( "Lang", version.lang );
++	config.sync();
++}
++
++bool OscarVersionUpdater::equal( const Oscar::ClientVersion& a, const Oscar::ClientVersion& b ) const
++{
++	if ( a.clientString != b.clientString || a.clientId != b.clientId ||
++	     a.major != b.major|| a.minor != b.minor ||
++	     a.point != b.point || a.build != b.build ||
++	     a.other != b.other || a.country != b.country ||
++	     a.lang != b.lang )
++	{
++		return false;
++	}
++	
++	return true;
++}
++
++#include "oscarversionupdater.moc"
+--- kopete/protocols/oscar/oscarencodingselectiondialog.cpp	(revision 568672)
++++ kopete/protocols/oscar/oscarencodingselectiondialog.cpp	(revision 586398)
+@@ -32,6 +32,7 @@
+     clearWFlags( QWidget::WDestructiveClose );
+     m_encodingUI = new OscarEncodingBaseUI( this );
+     //fill the encoding combo boxes
++  	m_encodings.insert(0, i18n("Default"));
+   	m_encodings.insert(2026, i18n("Big5"));
+ 	m_encodings.insert(2101, i18n("Big5-HKSCS"));
+ 	m_encodings.insert(18, i18n("euc-JP Japanese"));
+@@ -76,6 +77,9 @@
+ 
+ 	m_encodings.insert(2259, i18n("TIS-620 Thai"));
+ 
++	m_encodings.insert(106, i18n("UTF-8 Unicode"));
++	m_encodings.insert(1015, i18n("UTF-16 Unicode"));
++
+     m_encodingUI->encodingCombo->insertStringList( m_encodings.values() );
+     if( (initialEncodingIndex = m_encodings.keys().findIndex(initialEncoding)) == -1 )
+     {
+--- kopete/protocols/oscar/oscarvisibilitydialog.h	(revision 0)
++++ kopete/protocols/oscar/oscarvisibilitydialog.h	(revision 586398)
+@@ -0,0 +1,70 @@
++/*
++    oscarvisibilitydialog.h  -  Visibility Dialog
++
++    Copyright (c) 2005 by Roman Jarosz <kedgedev at centrum.cz>
++    Kopete    (c) 2005 by the Kopete developers  <kopete-devel at 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 OSCARVISIBILITYDIALOG_H
++#define OSCARVISIBILITYDIALOG_H
++
++#include <kdialogbase.h>
++#include "kopete_export.h"
++
++/**
++	@author Roman Jarosz <kedgedev at centrum.cz>
++*/
++class OscarVisibilityBase;
++class QStringList;
++class Client;
++
++class KOPETE_EXPORT OscarVisibilityDialog : public KDialogBase
++{
++	Q_OBJECT
++public:
++	typedef QMap<QString, QString> ContactMap;
++
++	OscarVisibilityDialog( Client* client, QWidget* parent );
++	~OscarVisibilityDialog() {}
++
++	void addContacts( const ContactMap& contacts );
++	void addVisibleContacts( const QStringList& contactList );
++	void addInvisibleContacts( const QStringList& contactList );
++
++signals:
++	void closing();
++
++protected:
++	virtual void slotOk();
++	virtual void slotCancel();
++
++protected slots:
++	void slotAddToVisible();
++	void slotRemoveFromVisible();
++	void slotAddToInvisible();
++	void slotRemoveFromInvisible();
++
++private:
++	enum Action{ Remove = 0, Add };
++	typedef QMap<QString, Action> ChangeMap;
++	
++	//maps with changes that should be send to server
++	ChangeMap m_visibleListChangesMap;
++	ChangeMap m_invisibleListChangesMap;
++	
++	ContactMap m_contactMap;
++	
++	OscarVisibilityBase* m_visibilityUI;
++	Client* m_client;
++};
++
++#endif
+--- kopete/protocols/oscar/oscarvisibilitybase.ui	(revision 0)
++++ kopete/protocols/oscar/oscarvisibilitybase.ui	(revision 586398)
+@@ -0,0 +1,170 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>OscarVisibilityBase</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>OscarVisibilityBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>594</width>
++            <height>409</height>
++        </rect>
++    </property>
++    <grid>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <widget class="QLabel" row="0" column="2">
++            <property name="name">
++                <cstring>textLabel2</cstring>
++            </property>
++            <property name="text">
++                <string>Always visible:</string>
++            </property>
++        </widget>
++        <widget class="QLabel" row="0" column="0">
++            <property name="name">
++                <cstring>textLabel1</cstring>
++            </property>
++            <property name="text">
++                <string>Contacts:</string>
++            </property>
++        </widget>
++        <widget class="QListBox" row="1" column="0" rowspan="9" colspan="1">
++            <property name="name">
++                <cstring>contacts</cstring>
++            </property>
++        </widget>
++        <spacer row="1" column="1">
++            <property name="name">
++                <cstring>spacer4</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>31</width>
++                    <height>40</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QPushButton" row="2" column="1">
++            <property name="name">
++                <cstring>visibleAdd</cstring>
++            </property>
++            <property name="text">
++                <string>Add</string>
++            </property>
++        </widget>
++        <widget class="QPushButton" row="3" column="1">
++            <property name="name">
++                <cstring>visibleRemove</cstring>
++            </property>
++            <property name="text">
++                <string>Remove</string>
++            </property>
++        </widget>
++        <spacer row="4" column="1">
++            <property name="name">
++                <cstring>spacer2</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>21</width>
++                    <height>40</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QListBox" row="1" column="2" rowspan="4" colspan="1">
++            <property name="name">
++                <cstring>visibleContacts</cstring>
++            </property>
++        </widget>
++        <widget class="QPushButton" row="8" column="1">
++            <property name="name">
++                <cstring>invisibleRemove</cstring>
++            </property>
++            <property name="text">
++                <string>Remove</string>
++            </property>
++        </widget>
++        <spacer row="9" column="1">
++            <property name="name">
++                <cstring>spacer5</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>21</width>
++                    <height>40</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QPushButton" row="7" column="1">
++            <property name="name">
++                <cstring>invisibleAdd</cstring>
++            </property>
++            <property name="text">
++                <string>Add</string>
++            </property>
++        </widget>
++        <widget class="QListBox" row="6" column="2" rowspan="4" colspan="1">
++            <property name="name">
++                <cstring>invisibleContacts</cstring>
++            </property>
++        </widget>
++        <spacer row="6" column="1">
++            <property name="name">
++                <cstring>spacer6</cstring>
++            </property>
++            <property name="orientation">
++                <enum>Vertical</enum>
++            </property>
++            <property name="sizeType">
++                <enum>Expanding</enum>
++            </property>
++            <property name="sizeHint">
++                <size>
++                    <width>21</width>
++                    <height>40</height>
++                </size>
++            </property>
++        </spacer>
++        <widget class="QLabel" row="5" column="2">
++            <property name="name">
++                <cstring>textLabel3</cstring>
++            </property>
++            <property name="text">
++                <string>Always invisible:</string>
++            </property>
++        </widget>
++    </grid>
++</widget>
++<tabstops>
++    <tabstop>contacts</tabstop>
++    <tabstop>visibleAdd</tabstop>
++    <tabstop>visibleRemove</tabstop>
++    <tabstop>invisibleAdd</tabstop>
++    <tabstop>invisibleRemove</tabstop>
++    <tabstop>visibleContacts</tabstop>
++    <tabstop>invisibleContacts</tabstop>
++</tabstops>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+--- kopete/protocols/oscar/oscarversionupdater.h	(revision 0)
++++ kopete/protocols/oscar/oscarversionupdater.h	(revision 586398)
+@@ -0,0 +1,120 @@
++/*
++    oscarversionupdater.h  -  Version Updater
++
++    Copyright (c) 2006 by Roman Jarosz <kedgedev at centrum.cz>
++    Kopete    (c) 2006 by the Kopete developers  <kopete-devel at 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 OSCARVERSIONUPDATER_H
++#define OSCARVERSIONUPDATER_H
++
++#include <qobject.h>
++
++#include <oscartypes.h>
++
++namespace KIO
++{
++class Job;
++class TransferJob;
++}
++
++class QDomElement;
++class QDomDocument;
++
++/**
++	@author Roman Jarosz <kedgedev at centrum.cz>
++*/
++
++class OscarVersionUpdater : public QObject
++{
++	Q_OBJECT
++	
++public:
++	OscarVersionUpdater();
++	~OscarVersionUpdater();
++	
++	static OscarVersionUpdater* self();
++	
++	/**
++	 * Update version info from server.
++	 * @param stamp is update number.
++	 */
++	bool update( unsigned int stamp );
++	
++	/**
++	 * Update version info from server.
++	 * @return true if update is in progress or starts.
++	 */
++	unsigned int stamp() const;
++	
++	/**
++	 * Return structure with version info for ICQ.
++	 * @return Oscar::ClientVersion.
++	 */
++	const Oscar::ClientVersion* getICQVersion() const { return &mICQVersion; }
++	
++	/**
++	 * Return structure with version info for AIM.
++	 * @return Oscar::ClientVersion.
++	 */
++	const Oscar::ClientVersion* getAIMVersion() const { return &mAIMVersion; }
++	
++	/**
++	 * Set structure with ICQ version info to default.
++	 */
++	void initICQVersionInfo();
++	
++	/**
++	 * Set structure with AIM version info to default.
++	 */
++	void initAIMVersionInfo();
++	
++	/**
++	 * Print debug info.
++	 */
++	void printDebug();
++
++private slots:
++	void slotTransferData( KIO::Job *job, const QByteArray &data );
++	void slotTransferResult( KIO::Job *job );
++	
++private:
++	void parseDocument( QDomDocument& doc );
++	bool parseVersion( Oscar::ClientVersion& version, QDomElement& element );
++	
++	/**
++	 * Store version info structure to KConfigGroup
++	 * @param group is the group name.
++	 * @param version is version info structure.
++	 */
++	void storeVersionInfo( const QString& group, const Oscar::ClientVersion& version ) const;
++	
++	/**
++	 * Compare two versions.
++	 * @return true if a and b is equal.
++	 */
++	bool equal( const Oscar::ClientVersion& a, const Oscar::ClientVersion& b ) const;
++	
++private:
++	static OscarVersionUpdater *versionUpdaterStatic;
++	
++	Oscar::ClientVersion mICQVersion;
++	Oscar::ClientVersion mAIMVersion;
++	
++	KIO::TransferJob *mTransferJob;
++	QByteArray mVersionData;
++	
++	unsigned int mStamp;
++	bool mUpdating;
++};
++
++#endif
+--- kopete/protocols/oscar/liboscar/connection.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/connection.cpp	(revision 586398)
+@@ -169,6 +169,11 @@
+ 	return d->client->ssiManager();
+ }
+ 
++const Oscar::ClientVersion* Connection::version() const
++{
++	return d->client->version();
++}
++
+ bool Connection::isLoggedIn() const
+ {
+ 	return m_loggedIn;
+--- kopete/protocols/oscar/liboscar/connectionhandler.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/connectionhandler.h	(revision 586398)
+@@ -19,9 +19,15 @@
+ #ifndef CONNECTIONHANDLER_H
+ #define CONNECTIONHANDLER_H
+ 
++#include "oscartypes.h"
++#include <qstring.h>
++#include <qpair.h>
+ 
++
+ class Connection;
+ 
++typedef QPair<Oscar::WORD, QString> ConnectionRoomInfo;
++
+ /**
+ @author Kopete Developers
+ */
+@@ -71,6 +77,39 @@
+ 	 */
+ 	Connection* defaultConnection() const;
+ 
++	/**
++	 * Add chat room information to a connection so that we can track
++	 * connections by chat room
++	 * @param c The connection to add information to
++	 * @param exchange the exchange the chat room is in
++	 * @param room the name of the chat room
++	 */
++	void addChatInfoForConnection( Connection* c, Oscar::WORD exchange, const QString& room );
++
++	/**
++	 * Get the connection for a particular room name and exchange number.
++	 * @param exchange the chat room exchange the room is on
++	 * @param room the name of the chat room to find a connection for
++	 * @return a Connection for the chat room or 0L if no connection for that room
++	 */
++	Connection* connectionForChatRoom( Oscar::WORD exchange, const QString& room );
++
++    /**
++     * Get the room name for the chat room based the connection
++     * @return The name of the chat room that this connection is connected to
++     * If the connection passed in by @p c is not a chat room connection then
++     * QString::null is returned.
++     */
++    QString chatRoomForConnection( Connection* c );
++
++    /**
++     * Get the exchange number for the chat room based on the connection
++     * @return The exchange of the chat room that this connection is connected
++     * to. If the connection passed in by @p c is not a chat room connection
++     * then 0xFFFF is returned
++     */
++    Oscar::WORD exchangeForConnection( Connection* c );
++
+ private:
+ 	class Private;
+ 	Private* d;
+--- kopete/protocols/oscar/liboscar/buffer.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/buffer.cpp	(revision 586398)
+@@ -174,6 +174,13 @@
+ 	return addString(data,len);
+ }
+ 
++int Buffer::addLETLV(WORD type, WORD len, const char *data)
++{
++	addLEWord( type );
++	addLEWord( len );
++	return addString( data, len );
++}
++
+ BYTE Buffer::getByte()
+ {
+ 	BYTE thebyte = 0x00;
+@@ -295,6 +302,13 @@
+ 	return addWord(data);
+ }
+ 
++int Buffer::addLETLV16(const WORD type, const WORD data)
++{
++	addLEWord(type);
++	addLEWord(0x0002); //2 bytes long
++	return addLEWord(data);
++}
++
+ int Buffer::addTLV8(const WORD type, const BYTE data)
+ {
+ 	addWord(type);
+@@ -302,6 +316,13 @@
+ 	return addByte(data);
+ }
+ 
++int Buffer::addLETLV8(const WORD type, const BYTE data)
++{
++	addLEWord(type);
++	addLEWord(0x0001); //1 byte long
++	return addLEByte(data);
++}
++
+ TLV Buffer::getTLV()
+ {
+ 	TLV t;
+--- kopete/protocols/oscar/liboscar/oscarmessage.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscarmessage.cpp	(revision 586398)
+@@ -20,35 +20,54 @@
+ #include "oscarmessage.h"
+ 
+ #include <qdeepcopy.h>
++#include <qtextcodec.h>
+ 
+ 
+ Oscar::Message::Message()
++: m_channel( -1 ),
++  m_properties( -1 ),
++  m_messageType( 0 ),
++  m_protocolVersion( 0 ),
++  m_channel2Counter( 0 ),
++  m_encoding( UserDefined )
+ {
+-	m_channel = -1;
+-	m_properties = -1;
+ }
+ 
+-Oscar::Message::Message( const QString& text, int channel, int properties, QDateTime timestamp )
++Oscar::Message::Message( Encoding messageEncoding, const QByteArray& messageText, int channel, int properties, QDateTime timestamp )
++: m_channel( channel ),
++  m_properties( properties ),
++  m_messageType( 0 ),
++  m_protocolVersion( 0 ),
++  m_channel2Counter( 0 ),
++  m_textArray( messageText ),
++  m_timestamp( timestamp ),
++  m_encoding( messageEncoding )
+ {
+-	m_text = text;
+-	m_channel = channel;
+-	m_properties = properties;
+-	m_timestamp = timestamp;
+ }
+ 
+-Oscar::Message::Message( const Oscar::Message& m )
++Oscar::Message::Message( Encoding messageEncoding, const QCString& messageText, int channel, int properties, QDateTime timestamp )
++: m_channel( channel ),
++  m_properties( properties ),
++  m_messageType( 0 ),
++  m_protocolVersion( 0 ),
++  m_channel2Counter( 0 ),
++  m_timestamp( timestamp ),
++  m_encoding( messageEncoding )
+ {
+-	m_text = m.m_text;
+-	m_channel = m.m_channel;
+-	m_properties = m.m_properties;
+-	m_timestamp = m.m_timestamp;
+-	m_icbmCookie.truncate( 0 );
+-	m_icbmCookie.duplicate( m.m_icbmCookie );
+-	m_protocolVersion = m.m_protocolVersion;
+-	m_channel2Counter = m.m_channel2Counter;
+-	m_messageType = m.m_messageType;
++	setTextArray( messageText );
+ }
+ 
++Oscar::Message::Message( Encoding messageEncoding, const QString& messageText, int channel, int properties, QDateTime timestamp, QTextCodec* codec )
++: m_channel( channel ),
++  m_properties( properties ),
++  m_messageType( 0 ),
++  m_protocolVersion( 0 ),
++  m_channel2Counter( 0 ),
++  m_timestamp( timestamp )
++{
++	setText( messageEncoding, messageText, codec );
++}
++
+ QString Oscar::Message::sender() const
+ {
+ 	return m_sender;
+@@ -69,26 +88,93 @@
+ 	m_receiver = receiver;
+ }
+ 
+-QString Oscar::Message::text() const
++QByteArray Oscar::Message::textArray() const
+ {
+-	return m_text;
++    return m_textArray;
+ }
+ 
+-void Oscar::Message::setText( const QString& newText )
++QString Oscar::Message::text( QTextCodec *codec ) const
+ {
+-	m_text = newText;
++	switch ( m_encoding )
++	{
++	case Oscar::Message::UserDefined:
++		return codec->toUnicode( m_textArray );
++	case Oscar::Message::UTF8:
++		return QString::fromUtf8( m_textArray.data(), m_textArray.size() );
++	case Oscar::Message::UCS2:
++	{
++		uint len = m_textArray.size() / 2;
++		QString result;
++		result.setLength( len );
++		QByteArray::ConstIterator p = m_textArray.begin();
++		for ( uint i = 0; i < len; i++)
++		{
++			char row = *p++;
++			char cell = *p++;
++			result[i] = QChar( cell, row );
++		}
++		return result;
++	}
++	default:
++		break; // Should never happen.
++	}
++	return QString::null;
++	//FIXME: warn at least with kdWarning if an unrecognised encoding style was seen.
+ }
+ 
+-QByteArray Oscar::Message::textArray() const
++void Oscar::Message::setText( Oscar::Message::Encoding newEncoding, const QString& newText, QTextCodec* codec )
+ {
+-    return m_textArray;
++	uint len;
++	switch ( newEncoding )
++	{
++	case Oscar::Message::UserDefined:
++		// Oscar::Message::setTextArray( const QCString& )
++		// strips trailing null byte automatically.
++		setTextArray( codec->fromUnicode( newText ) );
++		break;
++	case Oscar::Message::UTF8:
++		// Oscar::Message::setTextArray( const QCString& )
++		// strips trailing null byte automatically.
++		setTextArray( newText.utf8() );
++		break;
++	case Oscar::Message::UCS2:
++	{
++		len = newText.length();
++		m_textArray.resize( len * 2 );
++		QByteArray::Iterator p = m_textArray.begin();
++		for ( uint i = 0; i < len; i++)
++		{
++			*p++ = newText[i].row();
++			*p++ = newText[i].cell();
++		}
++		break;
++	}
++	default:
++		break; // Should never happen.
++	}
++	m_encoding = newEncoding;
+ }
+ 
+ void Oscar::Message::setTextArray( const QByteArray& newTextArray )
+ {
+-    m_textArray.duplicate( newTextArray );
++	m_textArray.duplicate( newTextArray );
+ }
+ 
++void Oscar::Message::setTextArray( const QCString& newTextArray )
++{
++	m_textArray.duplicate( newTextArray );
++	uint len = m_textArray.size();
++	if ( len > 0 )
++	{
++		--len;
++		if ( m_textArray[len] == '\0' )
++		{
++			// Strip trailing null byte.
++			m_textArray.resize( len );
++		}
++	}
++}
++
+ int Oscar::Message::properties() const
+ {
+ 	return m_properties;
+@@ -172,6 +258,36 @@
+ 	m_messageType = type;
+ }
+ 
++Oscar::WORD Oscar::Message::exchange() const
++{
++    return m_exchange;
++}
++
++void Oscar::Message::setExchange( Oscar::WORD exchange )
++{
++    m_exchange = exchange;
++}
++
++QString Oscar::Message::chatRoom() const
++{
++    return m_chatRoom;
++}
++
++void Oscar::Message::setChatRoom( const QString& room )
++{
++    m_chatRoom = room;
++}
++
++Oscar::Message::Encoding Oscar::Message::encoding() const
++{
++	return m_encoding;
++}
++
++void Oscar::Message::setEncoding( Oscar::Message::Encoding newEncoding )
++{
++	m_encoding = newEncoding;
++}
++
+ Oscar::Message::operator bool() const
+ {
+ 	return m_channel != -1 && m_properties != -1;
+--- kopete/protocols/oscar/liboscar/icquserinfo.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/icquserinfo.cpp	(revision 586398)
+@@ -183,7 +183,7 @@
+ 		for ( int i = 0; i < len; i++ )
+ 		{
+ 			int t=buffer->getLEWord();
+-			QString d = buffer->getLELNTS();
++			QCString d = buffer->getLELNTS();
+ 			if (t>0) { //there is some topic
+ 				if (count<4) { //i think this could not happen, i have never seen more
+ 					topics[count]=t;
+@@ -216,19 +216,19 @@
+ 	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Found UIN " << QString::number( uin ) << endl;
+ 	len = buffer->getLEWord();
+ 	if ( len > 0 )
+-		nickName = QString( buffer->getBlock( len ) );
++		nickName = QCString( buffer->getBlock( len ) );
+ 	
+ 	len = buffer->getLEWord();
+ 	if ( len > 0 )
+-		firstName = QString( buffer->getBlock( len ) );
++		firstName = QCString( buffer->getBlock( len ) );
+ 	
+ 	len = buffer->getLEWord();
+ 	if ( len > 0 )
+-		lastName = QString( buffer->getBlock( len ) );
++		lastName = QCString( buffer->getBlock( len ) );
+ 	
+ 	len = buffer->getLEWord();
+ 	if ( len > 0 )
+-		email = QString( buffer->getBlock( len ) );
++		email = QCString( buffer->getBlock( len ) );
+ 	
+ 	auth = ( buffer->getByte() != 0x01 );
+ 	online = ( buffer->getLEWord() == 0x0001 );
+--- kopete/protocols/oscar/liboscar/usersearchtask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/usersearchtask.cpp	(revision 586398)
+@@ -135,7 +135,7 @@
+ 	SNAC s = { 0x0015, 0x0002, 0x0000, client()->snacSequence() };
+ 	
+ 	setRequestType( 0x07D0 );
+-	setRequestSubType( 0x0533 );
++	setRequestSubType( 0x055F );
+ 	setSequence( f.sequence );
+ 	Buffer* tlvData = new Buffer();
+ 	/*
+@@ -241,67 +241,66 @@
+ 	*/
+ 	if ( !info.firstName.isEmpty() )
+ 	{
+-		tlvData->addLEWord( info.firstName.length() );
+-		tlvData->addLEString( info.firstName.latin1(), info.firstName.length() );
++		Buffer bufFileName;
++		bufFileName.addLEWord( info.firstName.length() );
++		bufFileName.addLEString( info.firstName, info.firstName.length() );
++		tlvData->addLETLV( 0x0140, bufFileName.length(), bufFileName.buffer() );
+ 	}
+-	else
+-		tlvData->addLEWord( 0x0000 );
+-	
++
+ 	if ( !info.lastName.isEmpty() )
+ 	{
+-		tlvData->addLEWord( info.lastName.length() );
+-		tlvData->addLEString( info.lastName.latin1(), info.lastName.length() );
++		Buffer bufLastName;
++		bufLastName.addLEWord( info.lastName.length() );
++		bufLastName.addLEString( info.lastName, info.lastName.length() );
++		tlvData->addLETLV( 0x014A, bufLastName.length(), bufLastName.buffer() );
+ 	}
+-	else
+-		tlvData->addLEWord( 0x0000 );
+-	
++
+ 	if ( !info.nickName.isEmpty() )
+ 	{
+-		tlvData->addLEWord( info.nickName.length() );
+-		tlvData->addLEString( info.nickName.latin1(), info.nickName.length() );
++		Buffer bufNickName;
++		bufNickName.addLEWord( info.nickName.length() );
++		bufNickName.addLEString( info.nickName, info.nickName.length() );
++		tlvData->addLETLV( 0x0154, bufNickName.length(), bufNickName.buffer() );
+ 	}
+-	else
+-		tlvData->addLEWord( 0x0000 );
+-	
++
+ 	if ( !info.email.isEmpty() )
+ 	{
+-		tlvData->addLEWord( info.email.length() );
+-		tlvData->addLEString( info.email.latin1(), info.email.length() );
++		Buffer bufEmail;
++		bufEmail.addLEWord( info.email.length() );
++		bufEmail.addLEString( info.email, info.email.length() );
++		tlvData->addLETLV( 0x015E, bufEmail.length(), bufEmail.buffer() );
+ 	}
+-	else
+-		tlvData->addLEWord( 0x0000 );
+-	
+-	tlvData->addLEWord( info.age );
+-	tlvData->addLEWord( info.age );
+-	tlvData->addByte( info.gender );
+-	tlvData->addByte( info.language );
+-	
++
++	if ( info.age > 0 )
++	{
++		Buffer bufAge;
++		bufAge.addWord( info.age );
++		bufAge.addWord( info.age );
++		tlvData->addLETLV( 0x0168, bufAge.length(), bufAge.buffer() );
++	}
++
++	if ( info.gender > 0 )
++		tlvData->addLETLV8( 0x017C, info.gender );
++
++	if ( info.language > 0 )
++		tlvData->addLETLV16( 0x0186, info.language );
++
++	if ( info.country > 0 )
++		tlvData->addLETLV16( 0x01A4, info.country );
++
+ 	if ( !info.city.isEmpty() )
+ 	{
+-		tlvData->addLEWord( info.city.length() );
+-		tlvData->addLEString( info.city.latin1(), info.city.length() );
++		Buffer bufCity;
++		bufCity.addLEWord( info.city.length() );
++		bufCity.addLEString( info.city, info.city.length() );
++		tlvData->addLETLV( 0x0190, bufCity.length(), bufCity.buffer() );
+ 	}
+-	else
+-		tlvData->addLEWord( 0x0000 );
+ 
+-	tlvData->addLEWord( 0x0000 );
+-	tlvData->addLEWord( info.country );
+-	tlvData->addLEWord( 0x0000 ); //company
+-	tlvData->addLEWord( 0x0000 ); //department
+-	tlvData->addLEWord( 0x0000 ); //position
+-	tlvData->addLEWord( info.occupation );
+-	tlvData->addLEWord( 0x0000 ); //past category
+-	tlvData->addLEWord( 0x0000 ); //past keywords
+-	tlvData->addLEWord( 0x0000 ); //interests category
+-	tlvData->addLEWord( 0x0000 ); //interests keywords
+-	tlvData->addLEWord( 0x0000 ); //affiliations category
+-	tlvData->addLEWord( 0x0000 ); //affiliations keywords
+-	tlvData->addLEWord( 0x0000 ); //homepage category
+-	tlvData->addLEWord( 0x0000 ); //homepage keywords
++	if ( info.occupation > 0 )
++		tlvData->addLETLV16( 0x01CC, info.occupation );
++
+ 	if ( info.onlineOnly )
+-		tlvData->addByte( 0x01 );
+-	else
+-		tlvData->addByte( 0x00 );
++		tlvData->addLETLV8( 0x0230, 0x01 );
+ 	
+ 	Buffer* buf = addInitialData( tlvData );
+ 	delete tlvData; //we're done with it
+--- kopete/protocols/oscar/liboscar/chatnavservicetask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/chatnavservicetask.cpp	(revision 586398)
+@@ -20,11 +20,11 @@
+ 
+ #include "transfer.h"
+ #include "buffer.h"
++#include "task.h"
++#include "client.h"
+ #include "connection.h"
+-#include "oscartypes.h"
+ 
+ 
+-
+ ChatNavServiceTask::ChatNavServiceTask( Task* parent ) : Task( parent )
+ {
+ 	m_type = Limits;
+@@ -45,6 +45,10 @@
+ 	return m_type;
+ }
+ 
++QValueList<int> ChatNavServiceTask::exchangeList() const
++{
++    return m_exchanges;
++}
+ 
+ bool ChatNavServiceTask::forMe( const Transfer* transfer ) const
+ {
+@@ -82,12 +86,17 @@
+         case 0x0003:
+             kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "exchange info TLV found" << endl;
+ 			handleExchangeInfo( t );
++            //set the exchanges for the client
++            emit haveChatExchanges( m_exchanges );
+             break;
+         case 0x0004:
+             kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "room info TLV found" << endl;
++            handleBasicRoomInfo( t );
+             break;
+         };
+     }
++
++
+     setSuccess( 0, QString::null );
+     setTransfer( 0 );
+ 	return true;
+@@ -137,6 +146,7 @@
+ 	b->addWord( lang.length() );
+ 	b->addString( lang.latin1(), lang.length() );
+ 
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending join room packet" << endl;
+ 	Transfer* t = createTransfer( f, s, b );
+ 	send( t );
+ }
+@@ -144,42 +154,47 @@
+ 
+ void ChatNavServiceTask::handleExchangeInfo( const TLV& t )
+ {
+-	kdDebug(OSCAR_RAW_DEBUG) << "Parsing exchange info TLV" << t.length << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "Parsing exchange info TLV" << endl;
+ 	Buffer b(t.data);
+-	WORD id = b.getWord();
+-	int tlvCount = b.getWord();
+-	int realCount = 0;
+-	kdDebug(OSCAR_RAW_DEBUG) << "Expecting " << tlvCount << " TLVs" << endl;
++    ChatExchangeInfo exchangeInfo;
++
++	exchangeInfo.number = b.getWord();
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "exchange id is: " << exchangeInfo.number << endl;
++    b.getWord();
+ 	while ( b.length() > 0 )
+ 	{
+ 		TLV t = b.getTLV();
++        Buffer tmp = t.data;
+ 		switch (t.type)
+ 		{
+ 		case 0x02:
+-			kdDebug(OSCAR_RAW_DEBUG) << "user class is " << t.data << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "user class is " << t.data << endl;
+ 			break;
+ 		case 0x03:
++            exchangeInfo.maxRooms = tmp.getWord();
+ 			kdDebug(OSCAR_RAW_DEBUG) << "max concurrent rooms for the exchange is " << t.data << endl;
+ 			break;
+ 		case 0x04:
+-			kdDebug(OSCAR_RAW_DEBUG) << "max room name length is " << t.data << endl;
++            exchangeInfo.maxRoomNameLength = tmp.getWord();
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "max room name length is " << exchangeInfo.maxRoomNameLength << endl;
+ 			break;
+ 		case 0x05:
+-			kdDebug(OSCAR_RAW_DEBUG) << "received root rooms info" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "received root rooms info" << endl;
+ 			break;
+ 		case 0x06:
+-			kdDebug(OSCAR_RAW_DEBUG) << "received search tags" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "received search tags" << endl;
+ 			break;
+ 		case 0xCA:
+-			kdDebug(OSCAR_RAW_DEBUG) << "have exchange creation time" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "have exchange creation time" << endl;
+ 			break;
+ 		case 0xC9:
+-			kdDebug(OSCAR_RAW_DEBUG) << "got chat flag" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "got chat flag" << endl;
+ 			break;
+ 		case 0xD0:
+-			kdDebug(OSCAR_RAW_DEBUG) << "got mandantory channels" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "got mandantory channels" << endl;
+ 			break;
+ 		case 0xD1:
++            exchangeInfo.maxMsgLength = tmp.getWord();
+ 			kdDebug(OSCAR_RAW_DEBUG) << "max message length" << t.data << endl;
+ 			break;
+ 		case 0xD2:
+@@ -189,34 +204,42 @@
+ 		{
+ 			QString eName( t.data );
+ 			kdDebug(OSCAR_RAW_DEBUG) << "exchange name: " << eName << endl;
++            exchangeInfo.description = eName;
+ 			break;
+ 		}
+ 		case 0xD4:
+-			kdDebug(OSCAR_RAW_DEBUG) << "got optional channels" << endl;
++			//kdDebug(OSCAR_RAW_DEBUG) << "got optional channels" << endl;
+ 			break;
+ 		case 0xD5:
+-			kdDebug(OSCAR_RAW_DEBUG) << "creation permissions " << t.data << endl;
++            exchangeInfo.canCreate = tmp.getByte();
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "creation permissions " << exchangeInfo.canCreate << endl;
+ 			break;
+ 		default:
+ 			kdDebug(OSCAR_RAW_DEBUG) << "unknown TLV type " << t.type << endl;
+ 			break;
+ 		}
+-		realCount++;
+ 	}
+-	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "real tlv count is: " << realCount << endl;
++    m_exchanges.append( exchangeInfo.number );
+ }
+ 
+ void ChatNavServiceTask::handleBasicRoomInfo( const TLV& t )
+ {
+-	kdDebug(OSCAR_RAW_DEBUG) << "Parsing exchange info TLV" << t.length << endl;
++	kdDebug(OSCAR_RAW_DEBUG) << "Parsing room info TLV" << t.length << endl;
+ 	Buffer b(t.data);
+-	WORD id = b.getWord();
+-	int tlvCount = b.getWord();
+-	int realCount = 0;
+-	kdDebug(OSCAR_RAW_DEBUG) << "Expecting " << tlvCount << " TLVs" << endl;
+-	while ( b.length() > 0 )
+-	{
+-		TLV t = b.getTLV();
++    WORD exchange = b.getWord();
++    QByteArray cookie( b.getBlock( b.getByte() ) );
++    WORD instance = b.getWord();
++    b.getByte(); //detail level, which i'm not sure we need
++    WORD tlvCount = b.getWord();
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "e: " << exchange
++                             << " c: " << cookie << " i: " << instance << endl;
++
++    QValueList<Oscar::TLV> tlvList = b.getTLVList();
++    QValueList<Oscar::TLV>::iterator it, itEnd = tlvList.end();
++    QString roomName;
++    for ( it = tlvList.begin(); it != itEnd; ++it )
++    {
++        TLV t = ( *it );
+ 		switch (t.type)
+ 		{
+ 		case 0x66:
+@@ -232,7 +255,8 @@
+ 			kdDebug(OSCAR_RAW_DEBUG) << "evil generated array" << endl;
+ 			break;
+ 		case 0x6A:
+-			kdDebug(OSCAR_RAW_DEBUG) << "fully qualified name" << endl;
++            roomName = QString( t.data );
++			kdDebug(OSCAR_RAW_DEBUG) << "fully qualified name" << roomName << endl;
+ 			break;
+ 		case 0x6B:
+ 			kdDebug(OSCAR_RAW_DEBUG) << "moderator" << endl;
+@@ -271,8 +295,9 @@
+ 			kdDebug(OSCAR_RAW_DEBUG) << "unknown TLV type " << t.type << endl;
+ 			break;
+ 		}
+-		realCount++;
+ 	}
++
++    emit connectChat( exchange, cookie, instance, roomName );
+ }
+ 
+ void ChatNavServiceTask::handleCreateRoomInfo( const TLV& t )
+@@ -326,4 +351,5 @@
+ 	}
+ }
+ 
++#include "chatnavservicetask.moc"
+ //kate: indent-mode csands; tab-width 4;
+--- kopete/protocols/oscar/liboscar/ssimodifytask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/ssimodifytask.cpp	(revision 586398)
+@@ -177,7 +177,7 @@
+ 	m_opType = Remove;
+ 	m_opSubject = NoSubject;
+ 	m_oldItem = item;
+-	return false;
++	return true;
+ }
+ 
+ bool SSIModifyTask::modifyItem( const Oscar::SSI& oldItem, const Oscar::SSI& newItem )
+@@ -418,11 +418,28 @@
+ void SSIModifyTask::updateSSIManager()
+ {
+ 	if ( m_oldItem.isValid() && m_newItem.isValid() )
+-	{ //changing groups on the server, or renaming. the group item will have already been updated
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << m_oldItem.name() << endl;
+-		m_ssiManager->removeContact( m_oldItem.name() );
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "and adding " << m_newItem.name() << " to SSI manager" << endl;
+-		m_ssiManager->newContact( m_newItem );
++	{
++		if ( m_opSubject == Contact )
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << m_oldItem.name() << endl;
++			m_ssiManager->removeContact( m_oldItem.name() );
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "and adding " << m_newItem.name() << " to SSI manager" << endl;
++			m_ssiManager->newContact( m_newItem );
++		}
++		else if ( m_opSubject == Group )
++		{
++			if ( m_opType == Rename )
++				m_ssiManager->updateGroup( m_oldItem, m_newItem );
++			else if ( m_opType == Change )
++				m_ssiManager->updateContact( m_oldItem, m_newItem );
++		}
++		else if ( m_opSubject == NoSubject )
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << m_oldItem.name() << endl;
++			m_ssiManager->removeItem( m_oldItem );
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "and adding " << m_newItem.name() << " to SSI manager" << endl;
++			m_ssiManager->newItem( m_newItem );
++		}
+ 		setSuccess( 0, QString::null );
+ 		return;
+ 	}
+@@ -432,8 +449,10 @@
+ 		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << m_oldItem.name() << " from SSI manager" << endl;
+ 		if ( m_opSubject == Group )
+ 			m_ssiManager->removeGroup( m_oldItem.name() );
+-		if ( m_opSubject == Contact )
++		else if ( m_opSubject == Contact )
+ 			m_ssiManager->removeContact( m_oldItem.name() );
++		else if ( m_opSubject == NoSubject )
++			m_ssiManager->removeItem( m_oldItem );
+ 		setSuccess( 0, QString::null );
+ 		return;
+ 	}
+@@ -443,8 +462,10 @@
+ 		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Adding " << m_newItem.name() << " to SSI manager" << endl;
+ 		if ( m_opSubject == Group )
+ 			m_ssiManager->newGroup( m_newItem );
+-		if ( m_opSubject == Contact )
++		else if ( m_opSubject == Contact )
+ 			m_ssiManager->newContact( m_newItem );
++		else if ( m_opSubject == NoSubject )
++			m_ssiManager->newItem( m_newItem );
+ 		setSuccess( 0, QString::null );
+ 		return;
+ 	}
+--- kopete/protocols/oscar/liboscar/oscarutils.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscarutils.h	(revision 586398)
+@@ -40,6 +40,12 @@
+ KOPETE_EXPORT TLV findTLV( const QValueList<TLV>&, int type );
+ 
+ /**
++ * Update TLVs of SSI item from TLV list if necessary
++ * \return true if something was updated
++ */
++KOPETE_EXPORT bool uptateTLVs( SSI& item, const QValueList<TLV>& list );
++
++/**
+  * Get the value of the capability that corresponds to the value
+  * in the Capabilities enum
+  * \return -1 if the capability isn't found
+--- kopete/protocols/oscar/liboscar/offlinemessagestask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/offlinemessagestask.h	(revision 586398)
+@@ -21,6 +21,7 @@
+ 
+ #include "icqtask.h"
+ #include "oscarmessage.h"
++
+ /**
+ ICQ Offline messages handling
+ 
+@@ -47,7 +48,6 @@
+ 	void deleteOfflineMessages();
+ 	
+ private:
+-	int m_msgCount;
+ 	int m_sequence;
+ };
+ 
+--- kopete/protocols/oscar/liboscar/sendmessagetask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/sendmessagetask.h	(revision 586398)
+@@ -31,22 +31,23 @@
+ 
+ 	//! Set the message to be sent
+ 	void setMessage( const Oscar::Message& msg );
+-	
++
+ 	//! Are we sending an auto response
+ 	void setAutoResponse( bool autoResponse );
+-	
++
+ 	virtual void onGo();
+ 
+ private:
+ 	void addBasicTLVs( Buffer* b );
+-	void addChannel1Data( Buffer* b, const QString& message );
+-	void addChannel2Data( Buffer* b, const QString& message );
+-	void addChannel4Data( Buffer* b, const QString& message );
+-	void addRendezvousMessageData( Buffer* b, const QString& message );
++	void addChannel1Data( Buffer* b );
++	void addChannel2Data( Buffer* b );
++	void addChannel4Data( Buffer* b );
++	void addRendezvousMessageData( Buffer* b );
+ 
+ private:
+ 	Oscar::Message m_message;
+ 	bool m_autoResponse;
++	uint m_cookieCount;
+ };
+ 
+ #endif
+--- kopete/protocols/oscar/liboscar/aimlogintask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/aimlogintask.cpp	(revision 586398)
+@@ -154,6 +154,8 @@
+ 	FLAP f = { 0x02, 0, 0 };
+ 	SNAC s = { 0x0017, 0x0002, 0x0000, client()->snacSequence() };
+ 	Buffer *outbuf = new Buffer;
++	const Oscar::ClientVersion* version = client()->version();
++	
+ 	outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1());
+ 
+ 	QByteArray digest( 17 ); //apparently MD5 digests are 16 bytes long
+@@ -161,16 +163,16 @@
+ 	digest[16] = '\0';  //do this so that addTLV sees a NULL-terminator
+ 
+ 	outbuf->addTLV(0x0025, 16, digest);
+-	outbuf->addTLV(0x0003, 0x32, AIM_CLIENTSTRING);
+-	outbuf->addTLV16(0x0016, AIM_CLIENTID);
+-	outbuf->addTLV16(0x0017, AIM_MAJOR);
+-	outbuf->addTLV16(0x0018, AIM_MINOR);
+-	outbuf->addTLV16(0x0019, AIM_POINT);
+-	outbuf->addTLV16(0x001a, AIM_BUILD);
++	outbuf->addTLV(0x0003, version->clientString.length(), version->clientString.latin1() );
++	outbuf->addTLV16(0x0016, version->clientId );
++	outbuf->addTLV16(0x0017, version->major );
++	outbuf->addTLV16(0x0018, version->minor );
++	outbuf->addTLV16(0x0019, version->point );
++	outbuf->addTLV16(0x001a, version->build );
+ 	outbuf->addDWord(0x00140004); //TLV type 0x0014, length 0x0004
+-	outbuf->addDWord(AIM_OTHER); //TLV data for type 0x0014
+-	outbuf->addTLV(0x000f, 0x0002, AIM_LANG);
+-	outbuf->addTLV(0x000e, 0x0002, AIM_COUNTRY);
++	outbuf->addDWord( version->other ); //TLV data for type 0x0014
++	outbuf->addTLV(0x000f, version->lang.length(), version->lang.latin1() );
++	outbuf->addTLV(0x000e, version->country.length(), version->country.latin1() );
+ 
+ 	//if set, old-style buddy lists will not work... you will need to use SSI
+ 	outbuf->addTLV8(0x004a,0x01);
+--- kopete/protocols/oscar/liboscar/icqlogintask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/icqlogintask.cpp	(revision 586398)
+@@ -55,19 +55,21 @@
+ 	Buffer *outbuf = new Buffer();
+ 
+ 	QString encodedPassword = encodePassword( client()->password() );
++	const Oscar::ClientVersion* version = client()->version();
+ 	
+-	outbuf->addDWord(flapVersion);
+-	outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1() );
+-	outbuf->addTLV(0x0002, encodedPassword.length(), encodedPassword.latin1() );
+-	outbuf->addTLV(0x0003, strlen(ICQ_CLIENTSTRING), ICQ_CLIENTSTRING);
+-	outbuf->addTLV16(0x0016, ICQ_CLIENTID);
+-	outbuf->addTLV16(0x0017, ICQ_MAJOR);
+-	outbuf->addTLV16(0x0018, ICQ_MINOR);
+-	outbuf->addTLV16(0x0019, ICQ_POINT);
+-	outbuf->addTLV16(0x001a, ICQ_BUILD);
+-	outbuf->addTLV(0x0014, 0x0004, ICQ_OTHER); // distribution chan
+-	outbuf->addTLV(0x000f, 0x0002, ICQ_LANG);
+-	outbuf->addTLV(0x000e, 0x0002, ICQ_COUNTRY);
++	outbuf->addDWord( flapVersion );
++	outbuf->addTLV( 0x0001, client()->userId().length(), client()->userId().latin1() );
++	outbuf->addTLV( 0x0002, encodedPassword.length(), encodedPassword.latin1() );
++	outbuf->addTLV( 0x0003, version->clientString.length(), version->clientString.latin1() );
++	outbuf->addTLV16( 0x0016, version->clientId );
++	outbuf->addTLV16( 0x0017, version->major );
++	outbuf->addTLV16( 0x0018, version->minor );
++	outbuf->addTLV16(  0x0019, version->point );
++	outbuf->addTLV16(0x001a, version->build );
++	outbuf->addDWord( 0x00140004 ); //TLV type 0x0014, length 0x0004
++	outbuf->addDWord( version->other ); //TLV data for type 0x0014
++	outbuf->addTLV( 0x000f, version->lang.length(), version->lang.latin1() );
++	outbuf->addTLV( 0x000e, version->country.length(), version->country.latin1() );
+ 
+ 	Transfer* ft = createTransfer( f, outbuf );
+ 	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending ICQ channel 0x01 login packet" << endl;
+--- kopete/protocols/oscar/liboscar/ssimanager.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/ssimanager.h	(revision 586398)
+@@ -87,6 +87,8 @@
+ 	
+ 	Oscar::SSI findItemForIcon( QByteArray iconHash ) const;
+ 	Oscar::SSI findItemForIconByRef( int ) const;
++	
++	Oscar::SSI findItem( const QString &contact, int type ) const;
+ 
+ 	QValueList<Oscar::SSI> groupList() const;
+ 	QValueList<Oscar::SSI> contactList() const;
+@@ -101,10 +103,12 @@
+ 
+ public slots:
+ 	bool newGroup( const Oscar::SSI& group );
++	bool updateGroup( const Oscar::SSI& oldGroup, const Oscar::SSI& newGroup );
+ 	bool removeGroup( const Oscar::SSI& group );
+ 	bool removeGroup( const QString& group );
+ 
+ 	bool newContact( const Oscar::SSI& contact );
++	bool updateContact( const Oscar::SSI& oldContact, const Oscar::SSI& newContact );
+ 	bool removeContact( const Oscar::SSI& contact );
+ 	bool removeContact( const QString& contact );
+ 	
+@@ -119,12 +123,18 @@
+ 	//! Emitted when we've added a new contact to the list
+ 	void contactAdded( const Oscar::SSI& );
+ 	
++	//! Emitted when we've updated a contact in the list
++	void contactUpdated( const Oscar::SSI& );
++	
+ 	//! Emitted when we've removed a contact from the list
+ 	void contactRemoved( const QString& contactName );
+ 	
+ 	//! Emitted when we've added a new group to the list
+ 	void groupAdded( const Oscar::SSI& );
+ 	
++	//! Emitted when we've updated a group in the list
++	void groupUpdated( const Oscar::SSI& );
++	
+ 	//! Emitted when we've removed a group from the ssi list
+ 	void groupRemoved( const QString& groupName );
+ 	
+--- kopete/protocols/oscar/liboscar/oscartypes.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscartypes.h	(revision 586398)
+@@ -132,7 +132,7 @@
+ 	// third number, point version 100+
+ 	// fourth number,  point version 0-99
+ 	{'K', 'o', 'p', 'e', 't', 'e', ' ', 'I',
+-			'C', 'Q', ' ', ' ', 0, 10, 0, 92},
++			'C', 'Q', ' ', ' ', 0, 12, 0, 1},
+ 
+ 	// CAP_MICQ
+ 	// last 4 bytes determine version
+@@ -210,7 +210,9 @@
+ struct ChatExchangeInfo
+ {
+ 	WORD number;
+-	BYTE maxNameLength;
++    WORD maxRooms;
++    WORD maxRoomNameLength;
++	WORD maxMsgLength;
+ 	BYTE flags;
+ 	QString description;
+ 	BYTE canCreate;
+@@ -230,29 +232,24 @@
+ 	QString name;
+ };
+ 
++struct ClientVersion
++{
++	QString clientString;
++	WORD clientId;
++	WORD major;
++	WORD minor;
++	WORD point;
++	WORD build;
++	DWORD other;
++	QString country;
++	QString lang;
++};
++
+ 	/* ICQ Version Characteristics */
+ 	const unsigned char ICQ_TCP_VERSION 	= 0x0008;
+-	const char ICQ_CLIENTSTRING[] 		= "ICQBasic";
+-	const WORD ICQ_CLIENTID 		= 0x010A;
+-	const WORD ICQ_MAJOR 			= 0x0014;
+-	const WORD ICQ_MINOR 			= 0x0034;
+-	const WORD ICQ_POINT 			= 0x0000;
+-	const WORD ICQ_BUILD 			= 0x0BB8;
+-	const char ICQ_OTHER[] 			= { 0x00, 0x00, 0x04, 0x3d };
+-	const char ICQ_COUNTRY[] 		= "us";
+-	const char ICQ_LANG[] 			= "en";
+ 
+ 	/* AIM Version Characteristics */
+ 	const char AIM_MD5_STRING[]     = "AOL Instant Messenger (SM)";
+-	const char AIM_CLIENTSTRING[]   = "AOL Instant Messenger (SM), version 5.1.3036/WIN32";
+-	const WORD AIM_CLIENTID         = 0x0109;
+-	const WORD AIM_MAJOR            = 0x0005;
+-	const WORD AIM_MINOR            = 0x0001;
+-	const WORD AIM_POINT            = 0x0000;
+-	const WORD AIM_BUILD            = 0x0bdc;
+-	const DWORD AIM_OTHER           = 0x000000d2;
+-	const char AIM_COUNTRY[]        = "us";
+-	const char AIM_LANG[]           = "en";
+ 
+ 	/* SSI types */
+ 	const WORD ROSTER_CONTACT       = 0x0000; // a normal contact
+@@ -267,6 +264,27 @@
+ 	const WORD ROSTER_NONICQ        = 0x0010; // a non-icq contact, no UIN, used to send SMS
+ 	const WORD ROSTER_IMPORTTIME    = 0x0013; // roster import time (name: "Import time")
+ 	const WORD ROSTER_BUDDYICONS    = 0x0014; // Buddy icon info. (names: from "0" and incrementing by one)
++
++    /* User classes/statuses */
++    const WORD CLASS_UNCONFIRMED    = 0x0001; // AOL Unconfirmed user
++    const WORD CLASS_ADMINISTRATOR  = 0x0002; // AOL Administrator
++    const WORD CLASS_AOL            = 0x0004; // AOL Staff
++    const WORD CLASS_COMMERCIAL     = 0x0008; // AOL commercial account
++    const WORD CLASS_FREE           = 0x0010; // ICQ non-commerical account
++    const WORD CLASS_AWAY           = 0x0020; // Away status
++    const WORD CLASS_ICQ            = 0x0040; // ICQ user
++    const WORD CLASS_WIRELESS       = 0x0080; // AOL wireless user
++    const WORD CLASS_UNKNOWN100     = 0x0100; // Unknown
++    const WORD CLASS_UNKNOWN400     = 0x0400; // Unknown
++    const WORD CLASS_UNKNOWN800     = 0x0800; // Unknown
++
++    const WORD STATUS_ONLINE        = 0x0000; // Online
++    const WORD STATUS_AWAY          = 0x0001; // Away
++    const WORD STATUS_DND           = 0x0002; // Do not Disturb
++    const WORD STATUS_NA            = 0x0004; // Not Available
++    const WORD STATUS_OCCUPIED      = 0x0010; // Occupied (BUSY/BISY)
++    const WORD STATUS_FREE4CHAT     = 0x0020; // Free for chat
++    const WORD STATUS_INVISIBLE     = 0x0100; // Invisible
+ }
+ 
+ #endif
+--- kopete/protocols/oscar/liboscar/buffer.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/buffer.h	(revision 586398)
+@@ -136,6 +136,11 @@
+ 		int addTLV(WORD, WORD, const char *);
+ 
+ 		/**
++		 * Adds a little-endian TLV with the given type and data
++		 */
++		int addLETLV(WORD, WORD, const char *);
++
++		/**
+ 		 * Returns a QString representation of the buffer
+ 		 */
+ 		QString toString() const;
+@@ -204,11 +209,21 @@
+ 		int addTLV16(const WORD type, const WORD data);
+ 
+ 		/**
++		 * adds a 16-bit long little-endian TLV
++		 */
++		int addLETLV16(const WORD type, const WORD data);
++
++		/**
+ 		 * adds the given byte to a TLV
+ 		 */
+ 		int addTLV8(const WORD type, const BYTE data);
+ 
+ 		/**
++		 * adds the given byte to a little-endian TLV
++		 */
++		int addLETLV8(const WORD type, const BYTE data);
++
++		/**
+ 		 * Gets a TLV, storing it in a struct and returning it
+ 		 */
+ 		TLV getTLV();
+--- kopete/protocols/oscar/liboscar/profiletask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/profiletask.cpp	(revision 586398)
+@@ -98,6 +98,7 @@
+ 		capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile
+ 		//capBuf.addString( oscar_caps[CAP_RTFMSGS], 16 ); // we do incoming RTF messages
+ 		capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us!
++		capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture?
+ 	}
+ 	else
+ 	{
+--- kopete/protocols/oscar/liboscar/oscarutils.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscarutils.cpp	(revision 586398)
+@@ -52,6 +52,32 @@
+ 	return t;
+ }
+ 
++bool Oscar::uptateTLVs( SSI& item, const QValueList<TLV>& list )
++{
++	bool changed = false;
++	QValueList<TLV> tList( item.tlvList() );
++
++	QValueList<TLV>::const_iterator it;
++	for ( it = list.begin(); it != list.end(); ++it )
++	{
++		TLV t = Oscar::findTLV( tList, ( *it ).type );
++		if ( t && t.length == ( *it ).length &&
++		     memcmp( t.data.data(), ( *it ).data.data(), t.length ) == 0 )
++			continue;
++
++		if ( t )
++			tList.remove( t );
++
++		tList.append( *it );
++		changed = true;
++	}
++
++	if ( changed )
++		item.setTLVList( tList );
++
++	return changed;
++}
++
+ int Oscar::parseCap( char* cap )
+ {
+ 	int capflag = -1;
+--- kopete/protocols/oscar/liboscar/ssilisttask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/ssilisttask.cpp	(revision 586398)
+@@ -98,7 +98,7 @@
+ 	{
+ 		tlvList.clear();
+ 		WORD strlength = buffer->getWord();
+-		QString itemName = QString( buffer->getBlock( strlength ) );
++		QString itemName = QString::fromUtf8( buffer->getBlock( strlength ), strlength );
+ 		WORD groupId = buffer->getWord();
+ 		WORD itemId = buffer->getWord();
+ 		WORD itemType = buffer->getWord();
+--- kopete/protocols/oscar/liboscar/connectionhandler.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/connectionhandler.cpp	(revision 586398)
+@@ -26,6 +26,7 @@
+ {
+ public:
+ 	QValueList<Connection*> connections;
++    QMap<Connection*, ConnectionRoomInfo> chatRoomConnections;
+ };
+ 
+ ConnectionHandler::ConnectionHandler()
+@@ -109,3 +110,65 @@
+ 	return d->connections.first();
+ }
+ 
++void ConnectionHandler::addChatInfoForConnection( Connection* c, Oscar::WORD exchange, const QString& room )
++{
++    if ( d->connections.findIndex( c ) == -1 )
++        d->connections.append( c );
++
++    ConnectionRoomInfo info = qMakePair( exchange, room );
++    d->chatRoomConnections[c] = info;
++}
++
++Connection* ConnectionHandler::connectionForChatRoom( Oscar::WORD exchange, const QString& room )
++{
++    ConnectionRoomInfo infoToFind = qMakePair( exchange, room );
++    QMap<Connection*, ConnectionRoomInfo>::iterator it,  itEnd = d->chatRoomConnections.end();
++    for ( it = d->chatRoomConnections.begin(); it != itEnd; ++it )
++    {
++        if ( it.data() == infoToFind )
++        {
++            Connection* c = it.key();
++            return c;
++        }
++    }
++
++    return 0;
++}
++
++QString ConnectionHandler::chatRoomForConnection( Connection* c )
++{
++    if ( d->connections.findIndex( c ) == -1 )
++        return QString::null;
++
++    QMap<Connection*, ConnectionRoomInfo>::iterator it, itEnd = d->chatRoomConnections.end();
++    for ( it = d->chatRoomConnections.begin(); it != itEnd; ++it )
++    {
++        if ( it.key() == c )
++        {
++            QString room = it.data().second;
++            return room;
++        }
++    }
++
++    return QString::null;
++}
++
++Oscar::WORD ConnectionHandler::exchangeForConnection( Connection* c )
++{
++
++    if ( d->connections.findIndex( c ) == -1 )
++        return 0xFFFF;
++
++    QMap<Connection*, ConnectionRoomInfo>::iterator it, itEnd = d->chatRoomConnections.end();
++    for ( it = d->chatRoomConnections.begin(); it != itEnd; ++it )
++    {
++        if ( it.key() == c )
++        {
++            Oscar::WORD exchange = it.data().first;
++            return exchange;
++        }
++    }
++
++    return 0xFFFF;
++}
++
+--- kopete/protocols/oscar/liboscar/messagereceivertask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/messagereceivertask.h	(revision 586398)
+@@ -19,6 +19,7 @@
+ #include "task.h"
+ #include <qstring.h>
+ #include <qcstring.h>
++#include "oscarmessage.h"
+ #include "oscartypeclasses.h"
+ #include "oscarmessage.h"
+ 
+--- kopete/protocols/oscar/liboscar/client.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/client.cpp	(revision 586398)
+@@ -21,6 +21,7 @@
+ #include "client.h"
+ 
+ #include <qtimer.h>
++#include <qtextcodec.h>
+ 
+ #include <kdebug.h> //for kdDebug()
+ #include <klocale.h>
+@@ -40,6 +41,7 @@
+ #include "oscarclientstream.h"
+ #include "oscarconnector.h"
+ #include "oscarsettings.h"
++#include "oscarutils.h"
+ #include "ownuserinfotask.h"
+ #include "profiletask.h"
+ #include "senddcinfotask.h"
+@@ -55,9 +57,28 @@
+ #include "userinfotask.h"
+ #include "usersearchtask.h"
+ #include "warningtask.h"
++#include "chatservicetask.h"
+ #include "rateclassmanager.h"
+ 
+ 
++namespace
++{
++	class DefaultCodecProvider : public Client::CodecProvider
++	{
++	public:
++		virtual QTextCodec* codecForContact( const QString& ) const
++		{
++			return QTextCodec::codecForMib( 4 );
++		}
++		virtual QTextCodec* codecForAccount() const
++		{
++			return QTextCodec::codecForMib( 4 );
++		}
++	};
++
++	DefaultCodecProvider defaultCodecProvider;
++}
++
+ class Client::ClientPrivate
+ {
+ public:
+@@ -97,6 +118,9 @@
+ 	//Our Userinfo
+ 	UserDetails ourDetails;
+ 
++    //Infos
++    QValueList<int> exchanges;
++
+ 	QString statusMessage; // for away-,DND-message etc...
+ 
+ 	//away messages
+@@ -107,6 +131,9 @@
+ 	};
+ 	QValueList<AwayMsgRequest> awayMsgRequestQueue;
+ 	QTimer* awayMsgRequestTimer;
++	CodecProvider* codecProvider;
++	
++	const Oscar::ClientVersion* version;
+ };
+ 
+ Client::Client( QObject* parent )
+@@ -134,6 +161,7 @@
+ 	d->stage = ClientPrivate::StageOne;
+ 	d->typingNotifyTask = 0L;
+ 	d->awayMsgRequestTimer = new QTimer();
++	d->codecProvider = &defaultCodecProvider;
+ 
+ 	connect( this, SIGNAL( redirectionFinished( WORD ) ),
+ 	         this, SLOT( checkRedirectionQueue( WORD ) ) );
+@@ -147,6 +175,7 @@
+ 	//delete the connections differently than in deleteConnections()
+ 	//deleteLater() seems to cause destruction order issues
+ 	deleteStaticTasks();
++    delete d->settings;
+ 	delete d->ssiManager;
+ 	delete d->awayMsgRequestTimer;
+ 	delete d;
+@@ -195,6 +224,10 @@
+ 		d->connectWithMessage = QString::null;
+ 	}
+ 
++    d->exchanges.clear();
++    d->redirectRequested = false;
++    d->currentRedirect = 0;
++    d->redirectionServices.clear();
+     d->ssiManager->clear();
+ }
+ 
+@@ -282,6 +315,11 @@
+ 	return d->ssiManager;
+ }
+ 
++const Oscar::ClientVersion* Client::version() const
++{
++	return d->version;
++}
++
+ // SLOTS //
+ 
+ void Client::streamConnected()
+@@ -407,7 +445,16 @@
+ 	emit haveOwnInfo();
+ }
+ 
++void Client::setCodecProvider( Client::CodecProvider* codecProvider )
++{
++	d->codecProvider = codecProvider;
++}
+ 
++void Client::setVersion( const Oscar::ClientVersion* version )
++{
++	d->version = version;
++}
++
+ // INTERNALS //
+ 
+ QString Client::userId() const
+@@ -448,30 +495,52 @@
+ 
+ void Client::sendMessage( const Oscar::Message& msg, bool isAuto)
+ {
+-	Connection* c = d->connections.connectionForFamily( 0x0004 );
+-	if ( !c )
+-		return;
+-	SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() );
+-	// Set whether or not the message is an automated response
+-	sendMsgTask->setAutoResponse( isAuto );
+-	sendMsgTask->setMessage( msg );
+-	sendMsgTask->go( true );
++    Connection* c = 0L;
++    if ( msg.type() == 0x0003 )
++    {
++        c = d->connections.connectionForChatRoom( msg.exchange(), msg.chatRoom() );
++        if ( !c )
++            return;
++
++        kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending message to chat room" << endl;
++        ChatServiceTask* cst = new ChatServiceTask( c->rootTask(), msg.exchange(), msg.chatRoom() );
++        cst->setMessage( msg );
++        cst->setEncoding( d->codecProvider->codecForAccount()->name() );
++        cst->go( true );
++    }
++    else
++    {
++        c = d->connections.connectionForFamily( 0x0004 );
++        if ( !c )
++            return;
++        SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() );
++        // Set whether or not the message is an automated response
++        sendMsgTask->setAutoResponse( isAuto );
++        sendMsgTask->setMessage( msg );
++        sendMsgTask->go( true );
++    }
+ }
+ 
+ void Client::receivedMessage( const Oscar::Message& msg )
+ {
+-	if ( ( msg.type() == 2 ) && ( ! msg.hasProperty( Oscar::Message::AutoResponse ) ) )
++	if ( msg.type() == 2 && !msg.hasProperty( Oscar::Message::AutoResponse ) )
+ 	{
+ 		// type 2 message needs an autoresponse, regardless of type
+ 		Connection* c = d->connections.connectionForFamily( 0x0004 );
+ 		if ( !c )
+ 			return;
+ 		
+-		Oscar::Message response = Oscar::Message( msg );
++		Oscar::Message response ( msg );
+ 		if ( msg.hasProperty( Oscar::Message::StatusMessageRequest ) )
+-			response.setText( statusMessage() );
++		{
++			QTextCodec* codec = d->codecProvider->codecForContact( msg.sender() );
++			response.setText( Oscar::Message::UserDefined, statusMessage(), codec );
++		}
+ 		else
+-			response.setText( "" );
++		{
++			response.setEncoding( Oscar::Message::UserDefined );
++			response.setTextArray( QByteArray() );
++		}
+ 		response.setReceiver( msg.sender() );
+ 		response.addProperty( Oscar::Message::AutoResponse );
+ 		SendMessageTask *sendMsgTask = new SendMessageTask( c->rootTask() );
+@@ -483,11 +552,12 @@
+ 		if ( msg.hasProperty( Oscar::Message::AutoResponse ) )
+ 		{
+ 			// we got a response to a status message request.
+-			kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Received an away message." << endl;
+-			emit receivedAwayMessage( msg );
++			QString awayMessage( msg.text( d->codecProvider->codecForContact( msg.sender() ) ) );
++			kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Received an away message: " << awayMessage << endl;
++			emit receivedAwayMessage( msg.sender(), awayMessage );
+ 		}
+ 	}
+-	else
++	else if ( ! msg.hasProperty( Oscar::Message::AutoResponse ) )
+ 	{
+ 		// let application handle it
+ 		kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Emitting receivedMessage" << endl;
+@@ -745,6 +815,16 @@
+ 	return d->icqInfoTask->shortInfoFor( contact );
+ }
+ 
++QValueList<int> Client::chatExchangeList() const
++{
++    return d->exchanges;
++}
++
++void Client::setChatExchangeList( const QValueList<int>& exchanges )
++{
++	d->exchanges = exchanges;
++}
++
+ void Client::requestAIMProfile( const QString& contact )
+ {
+ 	d->userInfoTask->requestInfoFor( contact, UserInfoTask::Profile );
+@@ -915,6 +995,54 @@
+ 	return;
+ }
+ 
++void Client::setIgnore( const QString& user, bool ignore )
++{
++	Oscar::SSI item = ssiManager()->findItem( user,  ROSTER_IGNORE );
++	if ( item && !ignore )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << user << " from ignore list" << endl;
++		this->modifySSIItem( item, Oscar::SSI() );
++	}
++	else if ( !item && ignore )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Adding " << user << " to ignore list" << endl;
++		Oscar::SSI s( user, 0, ssiManager()->nextContactId(), ROSTER_IGNORE, QValueList<TLV>() );
++		this->modifySSIItem( Oscar::SSI(), s );
++	}
++}
++
++void Client::setVisibleTo( const QString& user, bool visible )
++{
++	Oscar::SSI item = ssiManager()->findItem( user,  ROSTER_VISIBLE );
++	if ( item && !visible )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << user << " from visible list" << endl;
++		this->modifySSIItem( item, Oscar::SSI() );
++	}
++	else if ( !item && visible )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Adding " << user << " to visible list" << endl;
++		Oscar::SSI s( user, 0, ssiManager()->nextContactId(), ROSTER_VISIBLE, QValueList<TLV>() );
++		this->modifySSIItem( Oscar::SSI(), s );
++	}
++}
++
++void Client::setInvisibleTo( const QString& user, bool invisible )
++{
++	Oscar::SSI item = ssiManager()->findItem( user,  ROSTER_INVISIBLE );
++	if ( item && !invisible )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing " << user << " from invisible list" << endl;
++		this->modifySSIItem( item, Oscar::SSI() );
++	}
++	else if ( !item && invisible )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Adding " << user << " to invisible list" << endl;
++		Oscar::SSI s( user, 0, ssiManager()->nextContactId(), ROSTER_INVISIBLE, QValueList<TLV>() );
++		this->modifySSIItem( Oscar::SSI(), s );
++	}
++}
++
+ void Client::requestBuddyIcon( const QString& user, const QByteArray& hash, BYTE hashType )
+ {
+ 	Connection* c = d->connections.connectionForFamily( 0x0010 );
+@@ -930,12 +1058,14 @@
+ 	bit->go( true );
+ }
+ 
+-void Client::requestServerRedirect( WORD family )
++void Client::requestServerRedirect( WORD family, WORD exchange,
++                                    QByteArray cookie, WORD instance,
++                                    const QString& room )
+ {
+ 	//making the assumption that family 2 will always be the BOS connection
+ 	//use it instead since we can't query for family 1
+ 	Connection* c = d->connections.connectionForFamily( family );
+-	if ( c )
++	if ( c && family != 0x000E )
+ 		return; //we already have the connection
+ 
+ 	c = d->connections.connectionForFamily( 0x0002 );
+@@ -950,7 +1080,15 @@
+ 
+ 	d->currentRedirect = family;
+ 
++    //FIXME. this won't work if we have to defer the connection because we're
++    //already connecting to something
+ 	ServerRedirectTask* srt = new ServerRedirectTask( c->rootTask() );
++    if ( family == 0x000E )
++    {
++        srt->setChatParams( exchange, cookie, instance );
++        srt->setChatRoom( room );
++    }
++
+ 	connect( srt, SIGNAL( haveServer( const QString&, const QByteArray&, WORD ) ),
+ 	         this, SLOT( haveServerForRedirect( const QString&, const QByteArray&, WORD ) ) );
+ 	srt->setService( family );
+@@ -959,6 +1097,10 @@
+ 
+ void Client::haveServerForRedirect( const QString& host, const QByteArray& cookie, WORD )
+ {
++    //nasty sender() usage to get the task with chat room info
++	QObject* o = const_cast<QObject*>( sender() );
++    ServerRedirectTask* srt = dynamic_cast<ServerRedirectTask*>( o );
++
+ 	//create a new connection and set it up
+ 	int colonPos = host.find(':');
+ 	QString realHost, realPort;
+@@ -981,7 +1123,10 @@
+ 
+ 	//connect
+ 	connectToServer( c, d->host, false );
+-	QObject::connect( c, SIGNAL( connected() ), this, SLOT( streamConnected() ) );
++  	QObject::connect( c, SIGNAL( connected() ), this, SLOT( streamConnected() ) );
++
++    if ( srt )
++        d->connections.addChatInfoForConnection( c, srt->chatExchange(), srt->chatRoomName() );
+ }
+ 
+ void Client::serverRedirectFinished()
+@@ -1009,7 +1154,35 @@
+ 		emit chatNavigationConnected();
+ 	}
+ 
++    if ( d->currentRedirect == 0x000E )
++    {
++        //HACK! such abuse! think of a better way
++        if ( !m_loginTaskTwo )
++        {
++            kdWarning(OSCAR_RAW_DEBUG) << k_funcinfo << "no login task to get connection from!" << endl;
++            emit redirectionFinished( d->currentRedirect );
++            return;
++        }
++
++        Connection* c = m_loginTaskTwo->client();
++        QString roomName = d->connections.chatRoomForConnection( c );
++        WORD exchange = d->connections.exchangeForConnection( c );
++        if ( c )
++        {
++            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "setting up chat connection" << endl;
++            ChatServiceTask* cst = new ChatServiceTask( c->rootTask(), exchange, roomName );
++            connect( cst, SIGNAL( userJoinedChat( Oscar::WORD, const QString&, const QString& ) ),
++                     this, SIGNAL( userJoinedChat( Oscar::WORD, const QString&, const QString& ) ) );
++            connect( cst, SIGNAL( userLeftChat( Oscar::WORD, const QString&, const QString& ) ),
++                     this, SIGNAL( userLeftChat( Oscar::WORD, const QString&, const QString& ) ) );
++            connect( cst, SIGNAL( newChatMessage( const Oscar::Message& ) ),
++                     this, SIGNAL( messageReceived( const Oscar::Message& ) ) );
++        }
++        emit chatRoomConnected( exchange, roomName );
++    }
++
+ 	emit redirectionFinished( d->currentRedirect );
++
+ }
+ 
+ void Client::checkRedirectionQueue( WORD family )
+@@ -1034,6 +1207,8 @@
+ 	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting chat nav service limits" << endl;
+ 	ChatNavServiceTask* cnst = new ChatNavServiceTask( c->rootTask() );
+     cnst->setRequestType( ChatNavServiceTask::Limits );
++    QObject::connect( cnst, SIGNAL( haveChatExchanges( const QValueList<int>& ) ),
++                      this, SLOT( setChatExchangeList( const QValueList<int>& ) ) );
+ 	cnst->go( true ); //autodelete
+ 
+ }
+@@ -1049,11 +1224,11 @@
+     if ( !c )
+         return;
+ 
+-    if ( c->isSupported( 0x0002 ) ||
+-         d->stage == ClientPrivate::StageOne ) //emit on login
+-    {
+-        emit socketError( code, string );
+-    }
++	if ( c->isSupported( 0x0002 ) ||
++	     d->stage == ClientPrivate::StageOne ) //emit on login
++	{
++		emit socketError( code, string );
++	}
+ 
+     //connection is deleted. deleteLater() is used
+     d->connections.remove( c );
+@@ -1072,6 +1247,40 @@
+ 	bit->go( true );
+ }
+ 
++void Client::joinChatRoom( const QString& roomName, int exchange )
++{
++    Connection* c = d->connections.connectionForFamily( 0x000D );
++    if ( !c )
++        return;
++
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "joining the chat room '" << roomName
++                             << "' on exchange " << exchange << endl;
++    ChatNavServiceTask* cnst = new ChatNavServiceTask( c->rootTask() );
++    connect( cnst, SIGNAL( connectChat( WORD, QByteArray, WORD, const QString& ) ),
++             this, SLOT( setupChatConnection( WORD, QByteArray, WORD, const QString& ) ) );
++    cnst->createRoom( exchange, roomName );
++
++}
++
++void Client::setupChatConnection( WORD exchange, QByteArray cookie, WORD instance, const QString& room )
++{
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "cookie is:" << cookie << endl;
++    QByteArray realCookie( cookie );
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "connection to chat room" << endl;
++    requestServerRedirect( 0x000E, exchange, realCookie, instance, room );
++}
++
++void Client::disconnectChatRoom( WORD exchange, const QString& room )
++{
++    Connection* c = d->connections.connectionForChatRoom( exchange, room );
++    if ( !c )
++        return;
++
++    d->connections.remove( c );
++    c = 0;
++}
++
++
+ Connection* Client::createConnection( const QString& host, const QString& port )
+ {
+ 	KNetworkConnector* knc = new KNetworkConnector( 0 );
+--- kopete/protocols/oscar/liboscar/serverredirecttask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/serverredirecttask.h	(revision 586398)
+@@ -36,7 +36,12 @@
+ 	ServerRedirectTask( Task* parent );
+ 
+ 	void setService( WORD family );
++    void setChatParams( WORD exchange, QByteArray cookie, WORD instance );
++    void setChatRoom( const QString& roomName );
+ 
++    WORD chatExchange() const;
++    QString chatRoomName() const;
++
+ 	//Task implementation
+ 	void onGo();
+ 	bool forMe( const Transfer* transfer );
+@@ -56,6 +61,11 @@
+ 	WORD m_service;
+ 	QString m_newHost;
+ 	QByteArray m_cookie;
++
++    WORD m_chatExchange;
++    QByteArray m_chatCookie;
++    WORD m_chatInstance;
++    QString m_chatRoom;
+ };
+ 
+ 
+--- kopete/protocols/oscar/liboscar/oscarmessage.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscarmessage.h	(revision 586398)
+@@ -26,7 +26,10 @@
+ #include <qcstring.h>
+ #include <qdatetime.h>
+ #include "kopete_export.h"
++#include "oscartypes.h"
+ 
++class QTextCodec;
++
+ namespace Oscar
+ {
+ 
+@@ -46,16 +49,23 @@
+ 		AutoResponse = 0x0001,
+ 		WWP = 0x0002,
+ 		EMail = 0x0004,
+-		UCS2 = 0x0010,
+-		NotDecoded = 0x0020,
++		ChatRoom = 0x0008,
+ 		Request = 0x0100,
+ 		StatusMessageRequest = 0x0200
+ 	};
+ 
++	enum Encoding {
++		UserDefined,
++		UTF8,
++		UCS2
++	};
++
+ 	Message();
+-	Message( const QString& messageText, int channel, int properties = 0, QDateTime timestamp = QDateTime() );
+-	Message( const Oscar::Message& m );
+ 
++	Message( Encoding messageEncoding, const QByteArray& messageText, int channel, int properties, QDateTime timestamp );
++	Message( Encoding messageEncoding, const QCString& messageText, int channel, int properties, QDateTime timestamp );
++	Message( Encoding messageEncoding, const QString& messageText, int channel, int properties, QDateTime timestamp, QTextCodec* codec = 0 );
++
+ 	/** Get the sender of the message */
+ 	QString sender() const;
+ 
+@@ -69,17 +79,20 @@
+ 	void setReceiver( const QString& receiver);
+ 
+ 	/** get the message text */
+-	QString text() const;
++	QString text( QTextCodec* codec ) const;
+ 
+ 	/** set the message text */
+-	void setText( const QString& newText );
++	void setText( Encoding newEncoding, const QString& newText, QTextCodec* codec  = 0);
+ 
+ 	/** get the message text as a bytearray for decoding */
+ 	QByteArray textArray() const;
+-	
+-	/** set the mesasge text as a bytearray for decoding */
++
++	/** set the message text as a bytearray for decoding */
+ 	void setTextArray( const QByteArray& newTextArray );
+ 
++	/** set the mesasge text as a bytearray for decoding */
++	void setTextArray( const QCString& newTextArray );
++
+ 	/** get the message properties */
+ 	int properties() const;
+ 
+@@ -125,9 +138,28 @@
+ 	/** set the message (content) type */
+ 	void setMessageType( int type );
+ 
++    /** get the exchange for the chat room this message is for */
++    Oscar::WORD exchange() const;
++
++    /** set the exchange for the chat room this message is for */
++    void setExchange( Oscar::WORD );
++
++    /** get the chat room that this message is for */
++    QString chatRoom() const;
++
++    /** set the chat room that this message is for */
++    void setChatRoom( const QString& );
++
++	/** get the message encoding */
++	Encoding encoding() const;
++
++	/** set the message encoding */
++	void setEncoding( Encoding newEncoding );
++
+ 	operator bool() const;
+ 
+ private:
++    //TODO d-pointer
+ 	QString m_sender;
+ 	QString m_receiver;
+ 	int m_channel;
+@@ -135,10 +167,12 @@
+ 	int m_messageType;
+ 	int m_protocolVersion;
+ 	int m_channel2Counter;
+-	QString m_text;
+ 	QByteArray m_icbmCookie;
+-    QByteArray m_textArray;
++	QByteArray m_textArray;
+ 	QDateTime m_timestamp;
++	Oscar::WORD m_exchange;
++	QString m_chatRoom;
++	Encoding m_encoding;
+ };
+ 
+ }
+@@ -146,4 +180,3 @@
+ //kate: indent-mode csands; auto-insert-doxygen on; tab-width 4;
+ 
+ #endif
+-
+--- kopete/protocols/oscar/liboscar/chatservicetask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/chatservicetask.h	(revision 586398)
+@@ -29,7 +29,7 @@
+ {
+ Q_OBJECT
+ public:
+-    ChatServiceTask( Task* parent );
++    ChatServiceTask( Task* parent, Oscar::WORD exchange, const QString& room );
+     ~ChatServiceTask();
+ 
+     void onGo();
+@@ -43,13 +43,23 @@
+     void parseChatMessage();
+     void parseChatError();
+ 
+-    void sendChatMessage();
++    void setMessage( const Oscar::Message& msg );
++    void setEncoding( const QCString &enc );
+ 
+ signals:
+-    void newChatMessage( Oscar::Message msg );
++    void userJoinedChat( Oscar::WORD, const QString& r, const QString& u );
++    void userLeftChat( Oscar::WORD, const QString& r, const QString& u );
++    void newChatMessage( const Oscar::Message& msg );
+ 
+ protected:
+     bool forMe( const Transfer* t ) const;
++
++private:
++    WORD m_exchange;
++    QString m_room;
++    QString m_internalRoom;
++    Oscar::Message m_message;
++    QCString m_encoding;
+ };
+ 
+ #endif
+--- kopete/protocols/oscar/liboscar/chatnavservicetask.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/chatnavservicetask.h	(revision 586398)
+@@ -19,6 +19,9 @@
+ 
+ #include "task.h"
+ 
++#include <qvaluelist.h>
++#include <oscartypes.h>
++
+ class Transfer;
+ 
+ /**
+@@ -26,6 +29,7 @@
+  */
+ class ChatNavServiceTask : public Task
+ {
++Q_OBJECT
+ public:
+ 	ChatNavServiceTask( Task* parent );
+ 	~ChatNavServiceTask();
+@@ -41,13 +45,19 @@
+ 	virtual void onGo();
+     void createRoom( WORD exchange, const QString& name ); //create a room. sends the packet as well
+ 
++    QValueList<int> exchangeList() const;
++
++signals:
++    void haveChatExchanges( const QValueList<int>& );
++    void connectChat( WORD, QByteArray, WORD, const QString& );
++
+ private:
+ 	void handleExchangeInfo( const TLV& t );
+ 	void handleBasicRoomInfo( const TLV& t );
+     void handleCreateRoomInfo( const TLV& t );
+ 
+ private:
+-
++    QValueList<int> m_exchanges;
+ 	RequestType m_type;
+ };
+ 
+--- kopete/protocols/oscar/liboscar/offlinemessagestask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/offlinemessagestask.cpp	(revision 586398)
+@@ -30,7 +30,6 @@
+  : ICQTask( parent )
+ {
+ 	tzset();
+-	m_msgCount = 0;
+ 	m_sequence = 0;
+ }
+ 
+@@ -127,19 +126,12 @@
+ 	time = time.addSecs( tz );
+ 	
+ 	QDateTime hackyTime( date, time );
+-	Oscar::Message message;
+-	message.setType( type );
+-	message.addProperty( flags );
+-	message.addProperty( Oscar::Message::NotDecoded );
+-	message.setTextArray( msg );
+-	message.setTimestamp( hackyTime );
++	Oscar::Message message( Oscar::Message::UserDefined, msg, type, flags, hackyTime );
+ 	message.setSender( QString::number( senderUin ) );
+ 	message.setReceiver( QString::number( receiverUin ) );
+ 	
+ 	kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Received offline message '" << msg.data() << "' from " << senderUin << endl;
+ 	
+-	m_msgCount++;
+-	
+ 	emit receivedOfflineMessage( message );
+ }
+ 
+@@ -153,8 +145,7 @@
+ 	buffer->skipBytes( 8 );
+ 	m_sequence = buffer->getLEWord();
+ 	
+-	if ( m_msgCount > 0 )
+-		deleteOfflineMessages();
++	deleteOfflineMessages();
+ 	
+ 	setSuccess( true );
+ }
+--- kopete/protocols/oscar/liboscar/serverredirecttask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/serverredirecttask.cpp	(revision 586398)
+@@ -36,6 +36,20 @@
+ 	m_service = family;
+ }
+ 
++void ServerRedirectTask::setChatParams( WORD exchange, QByteArray cookie, WORD instance )
++{
++    m_chatExchange = exchange;
++    m_chatCookie.duplicate( cookie );
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "cookie is" << m_chatCookie << endl;
++    m_chatInstance = instance;
++}
++
++void ServerRedirectTask::setChatRoom( const QString& roomName )
++{
++    m_chatRoom = roomName;
++}
++
++
+ void ServerRedirectTask::onGo()
+ {
+ 	if ( m_service != 0 )
+@@ -66,15 +80,26 @@
+ 	return value;
+ }
+ 
++
+ void ServerRedirectTask::requestNewService()
+ {
+ 	FLAP f = { 0x02, 0, 0x00 };
+ 	SNAC s = { 0x0001, 0x0004, 0x0000, client()->snacSequence() };
+ 	Buffer* b = new Buffer();
+ 	b->addWord( m_service );
+-	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Requesting server for service " << m_service << endl;
+-	Transfer* t = createTransfer( f, s, b );
+-	send( t );
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Requesting server for service " << m_service << endl;
++    if ( m_service == 0x000E )
++    {
++        b->addWord( 0x0001 );
++        b->addWord( m_chatCookie.size() + 5 );
++        b->addWord( m_chatExchange );
++        b->addByte( m_chatCookie.size() );
++        b->addString( m_chatCookie );
++        b->addWord( m_chatInstance );
++    }
++
++    Transfer* t = createTransfer( f, s, b );
++    send( t );
+ }
+ 
+ bool ServerRedirectTask::handleRedirect()
+@@ -133,6 +158,16 @@
+ 	return m_service;
+ }
+ 
++WORD ServerRedirectTask::chatExchange() const
++{
++    return m_chatExchange;
++}
++
++QString ServerRedirectTask::chatRoomName() const
++{
++    return m_chatRoom;
++}
++
+ #include "serverredirecttask.moc"
+ //kate: indent-mode csands; tab-width 4;
+ 
+--- kopete/protocols/oscar/liboscar/sendmessagetask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/sendmessagetask.cpp	(revision 586398)
+@@ -16,7 +16,6 @@
+ 
+ #include "sendmessagetask.h"
+ 
+-#include <qtextcodec.h>
+ #include <kapplication.h>
+ #include <kdebug.h>
+ #include "connection.h"
+@@ -27,6 +26,7 @@
+ SendMessageTask::SendMessageTask(Task* parent): Task(parent)
+ {
+ 	m_autoResponse = false;
++	m_cookieCount = 0x7FFF;
+ }
+ 
+ 
+@@ -46,112 +46,87 @@
+ 
+ void SendMessageTask::onGo()
+ {
+-	if ( m_message.text().isEmpty() && m_message.type() == 1 ) // at least channel 2 needs to send empty messages
++	if ( m_message.textArray().isEmpty() && m_message.type() == 1 ) // at least channel 2 needs to send empty messages
+ 	{
+ 		setError(-1, "No message to send");
+ 		return;
+ 	}
+-	
+-	const uint CHUNK_LENGTH = 450;
+-	uint msgPostion = 0;
+-	
+-	do
+-	{
+-		// Check Message to see what SNAC to use
+-		int snacSubfamily = 0x0006;
+-		if ( ( m_message.type() == 2 ) && m_message.hasProperty( Oscar::Message::AutoResponse ) )
+-		{ // an auto response is send for ack of channel 2 messages
+-			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending SNAC 0x0B instead of 0x06 " << endl;
+-			snacSubfamily = 0x000B;
+-		}
+-		FLAP f = { 0x02, 0, 0 };
+-		SNAC s = { 0x0004, snacSubfamily, 0x0000, client()->snacSequence() };
+-		Buffer* b = new Buffer();
+ 
+-		if ( snacSubfamily == 0x0006 )
+-		{
+-			DWORD cookie1 = KApplication::random();
+-			DWORD cookie2 = KApplication::random();
+-			
+-			b->addDWord( cookie1 );
+-			b->addDWord( cookie2 );
+-		}
+-		else
+-		{
+-			b->addString( m_message.icbmCookie() ); // in automated response, we need the same cookie as in the request
+-		}
++	// Check Message to see what SNAC to use
++	int snacSubfamily = 0x0006;
++	if ( ( m_message.type() == 2 ) && m_message.hasProperty( Oscar::Message::AutoResponse ) )
++	{ // an auto response is send for ack of channel 2 messages
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending SNAC 0x0B instead of 0x06 " << endl;
++		snacSubfamily = 0x000B;
++	}
++	FLAP f = { 0x02, 0, 0 };
++	SNAC s = { 0x0004, snacSubfamily, 0x0000, client()->snacSequence() };
++	Buffer* b = new Buffer();
++
++	if ( snacSubfamily == 0x0006 )
++	{
++		DWORD cookie1 = KApplication::random();
++		DWORD cookie2 = KApplication::random();
+ 		
+-		b->addWord( m_message.type() );
+-		
+-		b->addByte( m_message.receiver().length() );
+-		b->addString( m_message.receiver().latin1(), m_message.receiver().length() );
+-		
+-		QString msgChunk = m_message.text().mid( msgPostion, CHUNK_LENGTH );
+-		// Try to split on space if needed
+-		if ( msgChunk.length() == CHUNK_LENGTH )
+-		{
+-			for ( int i = 0; i < 100; i++ )
+-			{
+-				if ( msgChunk[CHUNK_LENGTH - i].isSpace() )
+-				{
+-					msgChunk = msgChunk.left(CHUNK_LENGTH - i);
+-					msgPostion++;
+-					break;
+-				}
+-			}
+-		}
+-		msgPostion += msgChunk.length();
++		b->addDWord( cookie1 );
++		b->addDWord( cookie2 );
++	}
++	else
++	{
++		b->addString( m_message.icbmCookie() ); // in automated response, we need the same cookie as in the request
++	}
+ 
++	b->addWord( m_message.type() );
+ 
+-		if ( snacSubfamily == 0x0006 )
++	b->addByte( m_message.receiver().length() );
++	b->addString( m_message.receiver().latin1(), m_message.receiver().length() );
++
++
++	if ( snacSubfamily == 0x0006 )
++	{
++		/* send a regular message */
++		switch ( m_message.type() )
+ 		{
+-			/* send a regular message */
+-			switch ( m_message.type() )
+-			{
+-			case 1:
+-				addChannel1Data( b, msgChunk );
+-				break;
+-			case 2:
+-				addChannel2Data( b, msgChunk );
+-				break;
+-			case 4:
+-				addChannel4Data( b, msgChunk );
+-				break;
+-			}
++		case 1:
++			addChannel1Data( b );
++			break;
++		case 2:
++			addChannel2Data( b );
++			break;
++		case 4:
++			addChannel4Data( b );
++			break;
++		}
+ 
+-			// Add the TLV to indicate if this is an autoresponse: 0x00040000
+-			// Right now, only supported for the AIM client, I'm not sure about ICQ
+-			// For some reason you can't have both a 0x0004 and 0x0003 TLV in the same
+-			// SNAC, if you do the AIM server complains
+-			if ( !client()->isIcq() && (m_autoResponse == true) )
+-			{
+-				TLV tlv4( 0x0004, 0, NULL);
+-				b->addTLV( tlv4 );
+-			}
+-			else
+-			{
+-				b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server
+-			}
+-			
+-			if ( client()->isIcq() && ( ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) ) )
+-				b->addDWord( 0x00060000 ); //empty TLV 6 to store message on the server if not online
++		// Add the TLV to indicate if this is an autoresponse: 0x00040000
++		// Right now, only supported for the AIM client, I'm not sure about ICQ
++		// For some reason you can't have both a 0x0004 and 0x0003 TLV in the same
++		// SNAC, if you do the AIM server complains
++		if ( !client()->isIcq() && (m_autoResponse == true) )
++		{
++			TLV tlv4( 0x0004, 0, NULL);
++			b->addTLV( tlv4 );
+ 		}
+ 		else
+ 		{
+-			/* send an autoresponse */
+-			b->addWord( 0x0003 ); // reason code: 1: channel not supported; 2: busted payload; 3: channel specific;
+-			//TODO: i hardcoded it for now, since we don't suppoert error messages atm anyway
+-			addRendezvousMessageData( b, msgChunk );
++			b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server
+ 		}
+-		
+ 
+-	
+-		Transfer* t = createTransfer( f, s, b );
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SENDING: " << t->toString() << endl;
+-		send( t );
+-		
+-	} while ( msgPostion < m_message.text().length() );
+-	
++		if ( client()->isIcq() && m_message.type() != 2 && ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) )
++			b->addDWord( 0x00060000 ); //empty TLV 6 to store message on the server if not online
++	}
++	else
++	{
++		/* send an autoresponse */
++		b->addWord( 0x0003 ); // reason code: 1: channel not supported; 2: busted payload; 3: channel specific;
++		//TODO: i hardcoded it for now, since we don't suppoert error messages atm anyway
++		addRendezvousMessageData( b );
++	}
++
++	Transfer* t = createTransfer( f, s, b );
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SENDING: " << t->toString() << endl;
++	send( t );
++
+ 	setSuccess(true);
+ }
+ 
+@@ -162,10 +137,10 @@
+ }
+ 
+ 
+-void SendMessageTask::addChannel1Data( Buffer* b, const QString& message )
++void SendMessageTask::addChannel1Data( Buffer* b )
+ {
+ 	Buffer tlv2buffer;
+-	
++
+ 	//Send features TLV using data from gaim. Features are different
+ 	//depending on whether we're ICQ or AIM
+ 	if ( client()->isIcq() )
+@@ -181,45 +156,29 @@
+ 	//we only send one message part. There's only one client that actually uses
+ 	//them and it's quite old and infrequently used
+ 	tlv2buffer.addWord( 0x0101 ); //add TLV(0x0101) also known as TLV(257)
+-	
+-	/* If we can encode in Latin1, do that, otherwise send Unicode */
+-	QTextCodec* codec = QTextCodec::codecForMib( 4 ); //4 is the MIBEnum for ISO-8859-1
+-	if ( codec->canEncode( message ) )
++	tlv2buffer.addWord( m_message.textArray().size() + 4 ); // add TLV length
++
++	if ( m_message.encoding() == Oscar::Message::UserDefined )
+ 	{
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Latin-1 encoding successful. Sending outgoing message as "
+-			<< "ISO-8859-1" << endl;
+-		tlv2buffer.addWord( message.length() + 4 ); // add TLV length
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending outgoing message in "
++			<< "per-contact encoding" << endl;
+ 		tlv2buffer.addWord( 0x0000 );
+ 		tlv2buffer.addWord( 0x0000 );
+-		tlv2buffer.addString( message.latin1(), message.length() );
+ 	}
+ 	else
+ 	{
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Latin-1 encoding not successful. Sending outgoing message as "
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending outgoing message as "
+ 			<< "UCS-2" << endl;
+-		
+-		int length = message.length() * 2;
+-		unsigned char* utfMessage = new unsigned char[length];
+-		for ( unsigned int l = 0; l < message.length(); l++ )
+-		{
+-			utfMessage[l * 2] = message.unicode()[l].row();
+-			utfMessage[( l * 2 ) + 1] = message.unicode()[l].cell();
+-		}
+-		
+-		tlv2buffer.addWord( length + 4 ); // add TLV length
+ 		tlv2buffer.addWord( 0x0002 );
+ 		tlv2buffer.addWord( 0x0000 );
+-		tlv2buffer.addString( utfMessage, length );
+-		
+-		delete [] utfMessage;
+ 	}
+-	
+-		// Add the actual message TLV
++	tlv2buffer.addString( m_message.textArray() );
++
+ 	TLV tlv2( 0x0002, tlv2buffer.length(), tlv2buffer.buffer() );
+ 	b->addTLV( tlv2 );
+ }
+ 
+-void SendMessageTask::addChannel2Data( Buffer* b, const QString& message )
++void SendMessageTask::addChannel2Data( Buffer* b )
+ {
+ 	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Trying to send type 2 message!" << endl;
+ 
+@@ -268,7 +227,7 @@
+ // 	tlv5buffer.addWord( 0x0002 ); // TLV Length
+ // 	tlv5buffer.addWord( 0x0000 ); // TLV Data: listening port
+ 
+-	// add TLV 0A: unknown
++	// add TLV 0A: acktype (1 = normal message)
+ 	tlv5buffer.addWord( 0x000A ); // TLV Type
+ 	tlv5buffer.addWord( 0x0002 ); // TLV Length
+ 	tlv5buffer.addWord( 0x0001 ); // TLV Data: unknown, usually 1
+@@ -285,25 +244,23 @@
+ 	
+ 		
+ 	
+-	/* now comes the important TLV 0x271 */
++	/* now comes the important TLV 0x2711 */
+ 	
+-	int tlv2711DataLength = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+message.length()+1 /*+ 4+4+4+16+1*/;
+-	
+-	tlv5buffer.addWord( 0x2711 ); // start extended data TLV
+-	tlv5buffer.addWord( tlv2711DataLength ); // the calculated length
+-	//TODO: might change when changing message encoding to utf?
+-	
+-	addRendezvousMessageData( &tlv5buffer, message );
++	Buffer tlv2711buffer;
++	addRendezvousMessageData( &tlv2711buffer );
++	TLV tlv2711( 0x2711, tlv2711buffer.length(), tlv2711buffer.buffer() );
++	tlv5buffer.addTLV( tlv2711 );
++
+ 	TLV tlv5( 0x0005, tlv5buffer.length(), tlv5buffer.buffer() );
+ 	b->addTLV( tlv5 );
+ }
+ 
+-void SendMessageTask::addChannel4Data( Buffer* b, const QString& message )
++void SendMessageTask::addChannel4Data( Buffer* b )
+ {
+ 	//TODO
+ }
+ 
+-void SendMessageTask::addRendezvousMessageData( Buffer* b, const QString& message )
++void SendMessageTask::addRendezvousMessageData( Buffer* b )
+ {
+ 	// first data segment
+ 	b->addLEWord( 0x001B ); // length of this data segment, always 27
+@@ -326,6 +283,8 @@
+ 	int channel2Counter = 0xBEEF; // just some number for now
+ 	if ( m_message.hasProperty( Oscar::Message::AutoResponse ) )
+ 		channel2Counter = m_message.channel2Counter();
++	else
++		channel2Counter = (m_cookieCount--) & 0x7FFF;
+ 	
+ 	b->addLEWord( channel2Counter ); // channel 2 counter
+ 	
+@@ -346,7 +305,7 @@
+ 	else
+ 		b->addByte( m_message.messageType() );
+ 	
+-	int messageFlags = 0x01; // Normal
++	int messageFlags = 0x00; // Normal
+ 	if ( m_message.hasProperty( Oscar::Message::StatusMessageRequest ) )
+ 		messageFlags = 0x03; // Auto message. required for both requesting and sending status messages
+ 	else if ( m_message.hasProperty( Oscar::Message::AutoResponse ) )
+@@ -369,21 +328,17 @@
+ 	}
+ 	
+ 
+-	//! UTF in away messages doesnt work. using latin1 for now
+-	// need to append message itself now. i am not sure about how encoding is handled, so i use utf for now
+-// 	int length = msgChunk.length() * 2;
+-// 	unsigned char* utfMessage = new unsigned char[length];
+-// 	for ( unsigned int l = 0; l < msgChunk.length(); l++ )
+-// 	{
+-// 		utfMessage[l*2] = msgChunk.unicode()[l].row();
+-// 		utfMessage[(l*2)+1] = msgChunk.unicode()[l].cell();
+-// 	}
+-// 	b->addLEWord( length + 1 ); // length of string + zero termination
+-// 	b->addString( utfMessage, length ); // string itself
+-	
+-	b->addLEWord( message.length() + 1 ); // length of string + zero termination
+-	b->addString( message.latin1(), message.length() ); // string itself
++	b->addLEWord( m_message.textArray().size() + 1 ); // length of string + zero termination
++	b->addString( m_message.textArray() ); // string itself
+ 	b->addByte( 0x00 ); // zero termination
++	b->addLEDWord( 0x00000000 ); // foreground
++	b->addLEDWord( 0x00FFFFFF ); // foreground
++
++	if ( m_message.encoding() == Oscar::Message::UTF8 )
++	{
++		b->addLEDWord( 38 );
++		b->addString( "{0946134E-4C7F-11D1-8222-444553540000}", 38 );
++	}
+ }
+ 
+ 
+@@ -415,7 +370,7 @@
+ 	}
+ }
+ 
+-// if we couldn't encode it as ascii, and either the client says it can do UTF8, or we have no 
++// if we couldn't encode it as ascii, and either the client says it can do UTF8, or we have no
+ // contact specific encoding set, might as well send it as UTF-16BE as as ISO-8859-1
+ if ( !codec && ( contact->hasCap(CAP_UTF8) || !contact->encoding() ) )
+ {
+--- kopete/protocols/oscar/liboscar/client.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/client.h	(revision 586398)
+@@ -40,6 +40,7 @@
+ class UserDetails;
+ class QString;
+ class Task;
++class QTextCodec;
+ 
+ namespace Oscar
+ {
+@@ -52,6 +53,13 @@
+ 
+ public:
+ 
++	class CodecProvider {
++	public:
++		virtual ~CodecProvider() {}
++		virtual QTextCodec* codecForContact( const QString& contactName ) const = 0;
++		virtual QTextCodec* codecForAccount() const = 0;
++	};
++
+ 	enum ErrorCodes {
+ 		NoError = 0,
+ 		NotConnectedError = 1,
+@@ -93,7 +101,6 @@
+ 
+ 	/** Logout and disconnect */
+ 	void close();
+-	
+ 	/** Set our status for AIM */
+ 	void setStatus( AIMStatus status, const QString &message = QString::null );
+ 	/** Set our status for ICQ */
+@@ -227,6 +234,11 @@
+ 	 */
+ 	ICQShortInfo getShortInfo( const QString& contact );
+ 
++    /**
++     * Get the list of chat room exchanges we have
++     */
++    QValueList<int> chatExchangeList() const;
++
+ 	/**
+ 	 * Request the aim profile
+ 	 * \param contact the contact to get info for
+@@ -267,11 +279,20 @@
+ 	void requestBuddyIcon( const QString& user, const QByteArray& hash, BYTE hashType );
+ 
+ 	//! Start a server redirect for a different service
+-	void requestServerRedirect( WORD family );
++	void requestServerRedirect( WORD family, WORD e = 0, QByteArray c = QByteArray(),
++                                WORD instance = 0, const QString& room = QString::null );
+ 
+ 	//! Start uploading a buddy icon
+ 	void sendBuddyIcon( const QByteArray& imageData );
+ 
++    void joinChatRoom( const QString& roomName, int exchange );
++
++	void setIgnore( const QString& user, bool ignore );
++	
++	void setVisibleTo( const QString& user, bool visible );
++	
++	void setInvisibleTo( const QString& user, bool invisible );
++	
+ 	/** Accessors needed for login */
+ 	QString host();
+ 	int port();
+@@ -284,7 +305,15 @@
+ 
+ 	bool hasIconConnection() const;
+ 
++    /** We've finished chatting in a chat room, disconnect from it */
++    void disconnectChatRoom( WORD exchange, const QString& room );
+ 
++	/** Set codec provider */
++	void setCodecProvider( CodecProvider* codecProvider );
++	
++	/** Set pointer to version info */
++	void setVersion( const Oscar::ClientVersion* version );
++
+ 	/*************
+ 	  INTERNAL (FOR USE BY TASKS OR CONNECTIONS) METHODS
+ 	 *************/
+@@ -298,6 +327,9 @@
+ 
+ 	/** Accessor for the SSI Manager */
+ 	SSIManager* ssiManager() const;
++	
++	/** Return version info */
++	const Oscar::ClientVersion* version() const;
+ 
+ 	/** The current user's user ID */
+ 	QString userId() const;
+@@ -396,6 +428,9 @@
+ 
+ 	/* Chat rooms */
+ 	void chatNavigationConnected();
++    void chatRoomConnected( WORD, const QString& );
++    void userJoinedChat( Oscar::WORD, const QString& room, const QString& contact );
++    void userLeftChat( Oscar::WORD, const QString& room, const QString& contact );
+ 
+ 	/* service redirection */
+ 	void redirectionFinished( WORD );
+@@ -439,7 +474,17 @@
+ 	void checkRedirectionQueue( WORD );
+ 
+ 	void requestChatNavLimits();
++    /**
++     * Set the list of chat room exchanges we have
++     */
++    void setChatExchangeList( const QValueList<int>& exchanges );
+ 
++    /**
++     * set up the connection to a chat room
++     */
++    void setupChatConnection( WORD, QByteArray, WORD, const QString& );
++
++
+     void determineDisconnection( int, const QString& );
+ 
+ 	void nextICQAwayMessageRequest();
+--- kopete/protocols/oscar/liboscar/chatservicetask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/chatservicetask.cpp	(revision 586398)
+@@ -20,17 +20,21 @@
+ 
+ #include "chatservicetask.h"
+ 
++#include <qstring.h>
++#include <kapplication.h>
+ #include <kdebug.h>
++#include <qtextcodec.h>
+ 
+ #include "connection.h"
+ #include "transfer.h"
+ #include "buffer.h"
+ #include "oscartypes.h"
+ 
+-ChatServiceTask::ChatServiceTask( Task* parent )
+-	: Task( parent )
++ChatServiceTask::ChatServiceTask( Task* parent, Oscar::WORD exchange, const QString& room )
++	: Task( parent ), m_encoding( "us-ascii" )
+ {
+-
++    m_exchange = exchange;
++    m_room = room;
+ }
+ 
+ ChatServiceTask::~ChatServiceTask()
+@@ -38,9 +42,60 @@
+ 
+ }
+ 
++void ChatServiceTask::setMessage( const Oscar::Message& msg )
++{
++    m_message = msg;
++}
++
++void ChatServiceTask::setEncoding( const QCString& enc )
++{
++    m_encoding = enc;
++}
++
+ void ChatServiceTask::onGo()
+ {
++    if ( !m_message )
++    {
++        setSuccess( true, QString::null );
++        return;
++    }
+ 
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending '" << m_message.textArray() << "' to the "
++                             << m_room << " room" << endl;
++    Buffer* b = new Buffer();
++    b->addDWord( KApplication::random() ); //use kapp since it's convenient
++    b->addDWord( KApplication::random() );
++    b->addWord( 0x0003 ); //this be message channel 3 mateys! arrr!!
++    b->addDWord( 0x00010000 ); //TLV 1 - this means it's a public message
++    b->addDWord( 0x00060000 ); //TLV 6 - enables the server sending you your message back
++
++    Buffer tlv5;
++    TLV type2, type3, type1;
++
++    type2.type = 0x0002;
++    type2.length = 0x0008;
++    type2.data = m_encoding;
++
++    type3.type = 0x0003;
++    type3.length = 0x0002;
++    type3.data = QCString( "en" ); //hardcode for right now. don't know that we can do others
++
++    type1.type = 0x0001;
++    type1.length = m_message.textArray().size();
++    type1.data = m_message.textArray();
++    tlv5.addWord( 0x0005 );
++    tlv5.addWord( 12 + type1.length + type2.length + type3.length );
++    tlv5.addTLV( type1 );
++    tlv5.addTLV( type2 );
++    tlv5.addTLV( type3 );
++
++    b->addString( tlv5.buffer(), tlv5.length() );
++
++    FLAP f = { 0x02, 0, 0 };
++    SNAC s = { 0x000E, 0x0005, 0x0000, client()->snacSequence() };
++    Transfer* t = createTransfer( f, s, b );
++    send( t );
++    setSuccess( true );
+ }
+ 
+ bool ChatServiceTask::forMe( const Transfer* t ) const
+@@ -49,11 +104,22 @@
+ 	if ( !st )
+ 		return false;
+ 
+-	if ( !st->snacService() != 0x000E )
++	if ( st->snacService() != 0x000E )
+ 		return false;
+ 
+-	if ( st->snacSubtype() == 0x0001 )
++	switch ( st->snacSubtype() )
++    {
++    case 0x0003:
++    case 0x0002:
++    case 0x0006:
++    case 0x0009:
++    case 0x0004:
++        return true;
++        break;
++    default:
+ 		return false;
++        break;
++    }
+ 
+ 	return true;
+ }
+@@ -63,21 +129,29 @@
+ 	if ( !forMe( t ) )
+ 		return false;
+ 
+-	setTransfer( t );
+ 	SnacTransfer* st = dynamic_cast<SnacTransfer*>( t );
++    if ( !st )
++        return false;
++
++    setTransfer( t );
++
+ 	switch ( st->snacSubtype() )
+ 	{
+ 	case 0x0002:
+ 		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Parse room info" << endl;
++        parseRoomInfo();
+ 		break;
+ 	case 0x0003:
+         kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user joined notification" << endl;
++        parseJoinNotification();
+         break;
+     case 0x0004:
+         kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user left notification" << endl;
++        parseLeftNotification();
+         break;
+     case 0x0006:
+         kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message from room to client" << endl;
++        parseChatMessage();
+         break;
+     case 0x0009:
+         kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "chat error or data" << endl;
+@@ -91,13 +165,13 @@
+ 
+ void ChatServiceTask::parseRoomInfo()
+ {
+-    WORD exchange, instance;
++    WORD instance;
+     BYTE detailLevel;
+     Buffer* b = transfer()->buffer();
+ 
+-    exchange = b->getWord();
+-    QString name( b->getBUIN() );
+-    instance = b->getByte();
++    m_exchange = b->getWord();
++    QByteArray cookie( b->getBlock( b->getByte() ) );
++    instance = b->getWord();
+ 
+     detailLevel = b->getByte();
+ 
+@@ -113,7 +187,8 @@
+         switch ( ( *it ).type )
+         {
+         case 0x006A:
+-            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "room name: " << QString( ( *it ).data ) << endl;
++            m_internalRoom = QString( ( *it ).data );
++            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "room name: " << m_room << endl;
+             break;
+         case 0x006F:
+             kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "num occupants: " << ( *it ).data << endl;
+@@ -166,7 +241,10 @@
+                 break;
+             }
+         }
++        kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "emitted userJoinedChat" << endl;
++        emit userJoinedChat( m_exchange, m_room, sender );
+     }
++
+ }
+ 
+ void ChatServiceTask::parseLeftNotification()
+@@ -194,14 +272,17 @@
+                 break;
+             }
+         }
++        emit userLeftChat( m_exchange, m_room, sender );
+     }
+ }
+ 
+ void ChatServiceTask::parseChatMessage()
+ {
++    kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "have new chat room message" << endl;
+     Buffer* b = transfer()->buffer();
+     bool whisper = true, reflection = false;
+-    QString language, encoding, message;
++    QByteArray language, encoding, message;
++    QString sender;
+     QByteArray icbmCookie( b->getBlock( 8 ) );
+     b->skipBytes( 2 ); //message channel always 0x03
+     QValueList<Oscar::TLV> chatTLVs = b->getTLVList();
+@@ -218,24 +299,24 @@
+             break;
+         case 0x0005: //the good stuff - the actual message
+         {
++            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "parsing the message" << endl;
+             //oooh! look! more TLVS! i love those!
+             Buffer b( ( *it ).data );
+-            QValueList<Oscar::TLV> messageTLVs = b.getTLVList();
+-            QValueList<Oscar::TLV>::iterator mit,  mitEnd = messageTLVs.end();
+-            for ( mit = messageTLVs.begin(); mit != mitEnd; ++mit )
++            while ( b.length() >= 4 )
+             {
+-                switch( ( *it ).type )
++                TLV t = b.getTLV();
++                switch( t.type )
+                 {
+                 case 0x0003:
+-                    language = QString( ( *it ).data );
++                    language = t.data;
+                     kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "language: " << language << endl;
+                     break;
+                 case 0x0002:
+-                    encoding = QString( ( *it ).data );
++                    encoding = t.data;
+                     kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "encoding: " << encoding << endl;
+                     break;
+                 case 0x0001:
+-                    message = QString( ( *it ).data );
++                    message = t.data;
+                     kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message: " << message << endl;
+                     break;
+                 }
+@@ -243,16 +324,29 @@
+         }
+         break;
+         case 0x0003: //user info
+-            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "got user info" << endl;
+-            break;
++        {
++            Buffer b( ( *it ).data );
++            sender = QString( b.getBUIN() );
++            kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "got user info. sender is " << sender << endl;
+         }
++        break;
++
++        }
+     }
+ 
++    QTextCodec* codec = QTextCodec::codecForName( encoding );
++    if ( ! codec )
++        codec = QTextCodec::codecForMib( 4 );
++    QString msgText( codec->toUnicode( message ) );
+     Oscar::Message omessage;
+     omessage.setReceiver( client()->userId() );
++    omessage.setSender( sender );
+     omessage.setTimestamp( QDateTime::currentDateTime() );
+-    omessage.setText( message );
++    omessage.setText( Oscar::Message::UTF8, msgText );
+     omessage.setType( 0x03 );
++    omessage.setExchange( m_exchange );
++    omessage.setChatRoom( m_room );
++    emit newChatMessage( omessage );
+ }
+ 
+ void ChatServiceTask::parseChatError()
+--- kopete/protocols/oscar/liboscar/buddyicontask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/buddyicontask.cpp	(revision 586398)
+@@ -67,14 +67,15 @@
+ 	if ( m_action == Receive && ( m_user.isEmpty() || m_hash.count() == 0 ) )
+ 		return;
+ 
+-	if ( !client()->isIcq() )
++	if ( m_action == Receive )
+ 	{
+-		if ( m_action == Receive )
++		if ( client()->isIcq() )
++			sendICQBuddyIconRequest();
++		else
+ 			sendAIMBuddyIconRequest();
+-		else
+-			sendIcon();
+ 	}
+-	
++	else
++		sendIcon();
+ }
+ 
+ bool BuddyIconTask::forMe( const Transfer* transfer )
+@@ -119,10 +120,10 @@
+ 	setTransfer( transfer );
+ 	if ( st->snacSubtype() == 0x0003 )
+ 		handleUploadResponse();
+-	if ( st->snacSubtype() == 0x0005 )
++	else if ( st->snacSubtype() == 0x0005 )
+ 		handleAIMBuddyIconResponse();
+-// else
+-// 		handleICQBuddyIconResponse();
++	else
++		handleICQBuddyIconResponse();
+ 
+ 	setSuccess( 0, QString::null );
+ 	setTransfer( 0 );
+@@ -191,6 +192,54 @@
+ 	emit haveIcon( user, icon );
+ }
+ 
++void BuddyIconTask::sendICQBuddyIconRequest()
++{
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting buddy icon for " << m_user << endl;
++	FLAP f = { 0x02, 0, 0 };
++	m_seq = client()->snacSequence();
++	SNAC s = { 0x0010, 0x0006, 0x0000, m_seq };
++	Buffer* b = new Buffer;
++
++	b->addBUIN( m_user.latin1() ); //TODO: check encoding
++	b->addByte( 0x01 );
++	b->addWord( 0x0001 );
++	b->addByte( m_hashType );
++	b->addByte( m_hash.size() ); //MD5 Hash Size
++	b->addString( m_hash, m_hash.size() ); //MD5 Hash
++	Transfer* t = createTransfer( f, s, b );
++	send( t );
++}
++
++void BuddyIconTask::handleICQBuddyIconResponse()
++{
++	Buffer* b = transfer()->buffer();
++	QString user = b->getBUIN();
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Receiving buddy icon for " << user << endl;
++	
++	b->skipBytes(2); //not used
++	BYTE iconType = b->getByte();
++	Q_UNUSED( iconType );
++	
++	BYTE hashSize = b->getByte();
++	QByteArray iconHash;
++	iconHash.duplicate( b->getBlock(hashSize) );
++	
++	b->skipBytes(1); //not used
++	b->skipBytes(2); //not used
++	BYTE iconType2 = b->getByte();
++	Q_UNUSED( iconType2 );
++	
++	BYTE hashSize2 = b->getByte();
++	QByteArray iconHash2;
++	iconHash2.duplicate( b->getBlock(hashSize2) );
++	
++	WORD iconSize = b->getWord();
++	QByteArray icon;
++	icon.duplicate( b->getBlock(iconSize) );
++	
++	emit haveIcon( user, icon );
++}
++
+ #include "buddyicontask.moc"
+ 
+ 
+--- kopete/protocols/oscar/liboscar/connection.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/connection.h	(revision 586398)
+@@ -40,8 +40,8 @@
+ }
+ 
+ /**
+- * This class encapsulates both the low level network layer code and the high 
+- * level OSCAR protocol code required to create a single independent 
++ * This class encapsulates both the low level network layer code and the high
++ * level OSCAR protocol code required to create a single independent
+  * connection to an OSCAR server
+  * @author Matt Rogers
+  */
+@@ -52,35 +52,35 @@
+ 
+ 	Connection( Connector* connector, ClientStream* cs, const char* name = 0 );
+ 	~Connection();
+-	
++
+ 	void setClient( Client* );
+-	
++
+ 	void connectToServer( const QString& server, bool auth = true );
+ 	/**
+ 	 * Close the connection and reset the connection data
+ 	 */
+ 	void close();
+-	
++
+ 	/**
+ 	 * Check to see if the family specified by @p family is supported by this
+ 	 * connection.
+ 	 * @param family the family number to check
+ 	 */
+ 	bool isSupported( int family ) const;
+-	
++
+ 	/**
+ 	 * Get the list of supported families
+ 	 * @return The list of families supported on this connection
+ 	 */
+ 	QValueList<int> supportedFamilies() const;
+-	
++
+ 	/**
+ 	 * Add the SNAC families in \p familyList to the list of supported families for
+ 	 * this connection
+ 	 * \param familyList the list of families to add
+ 	 */
+ 	void addToSupportedFamilies( const QValueList<int>& familyList );
+-	
++
+ 	/**
+ 	 * Add the SNAC family in \p family to the list of supported families for
+ 	 * this connection
+@@ -88,112 +88,118 @@
+ 	 * \param family the single family to add to the list
+ 	 */
+ 	void addToSupportedFamilies( int family );
+-	
++
+ 	/**
+ 	 * Add the rate classes in \p rateClassList to the list of rate classes packets
+ 	 * need to be filtered on
+ 	 * \param rateClassList the list of rate classes to add
+ 	 */
+ 	void addToRateClasses( const QValueList<RateClass*> rateClassList );
+-	
++
+ 	/**
+ 	 * Add the rate class in \p rc to the list of rate classes packets
+ 	 * need to be filtered on
+-	 * \overload 
++	 * \overload
+ 	 * \param rc the list rate class to add
+ 	 */
+ 	void addToRateClasses( RateClass* rc );
+-	
++
+ 	/**
+ 	 * Indicate to the connection that there has been an error in a task. The
+ 	 * error won't require us to go offline, but the user should be notified
+ 	 * about the error
+ 	 * \param s the SNAC the error occured from
+-	 * \param errCode the error code 
++	 * \param errCode the error code
+ 	 */
+ 	void taskError( const Oscar::SNAC& s, int errCode );
+-	
++
+ 	/**
+ 	 * Indicate to the connection that there has been a fatal error in a task.
+ 	 * This error will require a disconnection from the OSCAR service and if
+ 	 * necessary, the user should be prompted to reconnect manually or an
+ 	 * automatic reconnection should be attempted.
+ 	 * \param s the SNAC the error occured from
+-	 * \param errCode the error code 
++	 * \param errCode the error code
+ 	 */
+ 	void fatalTaskError( const Oscar::SNAC& s, int errCode );
+-	
++
++    /**
++     * Get the chat room name for this connection.
++     * @return the name of the room or QString::null if not connected to a room
++     */
++
+ 	/** Get the user settings object */
+ 	Oscar::Settings* settings() const;
+-	
++
+ 	/** Get the current FLAP sequence for this connection */
+ 	Q_UINT16 flapSequence();
+-	
++
+ 	/** Get the current SNAC sequence for this connection */
+ 	Q_UINT32 snacSequence();
+-	
++
+ 	/** Get the cookie for this connection */
+ 	QByteArray cookie() const;
+-	
++
+ 	QString userId() const;
+ 	QString password() const;
+ 	bool isIcq() const;
+ 	SSIManager* ssiManager() const;
++	const Oscar::ClientVersion* version() const;
+ 	RateClassManager* rateManager() const;
+ 	bool isLoggedIn() const;
+-	
++
+ 	/** Convenience function to get the root task for use in Tasks */
+ 	Task* rootTask() const;
+-	
++
+ 	/** Get the raw connector for this connection, in case we need it */
+ 	Connector* connector();
+-	
++
+ 	/** Get the byte stream for this connection, in case we need it */
+ 	ByteStream* byteStream();
+-	
++
+ 	void send( Transfer* t ) const;
+ 	void forcedSend( Transfer* t ) const;
+-	
++
+ signals:
+ 
+ 	/** There's data ready to read */
+ 	void readyRead();
+-	
++
+ 	/** We've connected */
+ 	void connected();
+-	
++
+ 	/** We were disconnected */
+ 	void disconnected();
+-	
++
+ 	/**
+ 	 * There was an error on the socket and we've disconnected
+ 	 * \param errCode the error code from the operating system
+ 	 * \param errString the i18n'ed string that describes the error
+ 	 */
+ 	void socketError( int errCode, const QString& errString );
+-	
+-	
++
++
+ private:
+ 	/** Seed the sequence numbers with random values */
+ 	void initSequence();
+-	
++
+ 	/** Distribute the transfer among the connection's tasks */
+ 	void distribute( Transfer* t ) const;
+-	
++
+ private slots:
+ 	/** Reset the data for the connection.*/
+ 	void reset();
+-	
++
+ 	/** We've got something from the stream */
+ 	void streamReadyRead();
+-	
++
+ 	/** We've finished logging in */
+ 	void loggedIn();
+-	
++
+ 	void streamSocketError( int );
+-	
++
+ private:
+-	
++
+ 	ConnectionPrivate* d;
+ 	bool m_loggedIn;
+ };
+--- kopete/protocols/oscar/liboscar/TODO	(revision 568672)
++++ kopete/protocols/oscar/liboscar/TODO	(revision 586398)
+@@ -14,27 +14,6 @@
+ - Test moving contacts from one group to another
+ 
+ 
+-Type 2 Messaging
+-====================================
+-
+-This is the area of OSCAR that I know the least about. Snac family 4 is used for messaging. Not much to tell you here other than to
+-use oscarsocket for a reference and see the docs on iserverd. Also, http://joust.kano.net/wiki/oscar/moin.cgi/InstantMessages might have some useful info
+-but i haven't looked at it to see if it's worth anything. This will be by far the hardest part of OSCAR to implement and do right.
+-
+-Here's what I know:
+-
+-We usually refer to channels in the docs as types.
+-
+-Basic instant messages are type-1 messages. AFAIK, AIM uses this for nearly all (if not all) of its messages. ICQ might use this for the simpler messages.
+-ICQ RTF, ICQ away messages, and rendevous (direct connection stuff) is all handled via type-2 messages. 
+-
+-We may need to use gaim's code for reference on some things, but the last time i checked it wasn't very readable and thus not easy to use for reference.
+-
+-Be sure to test different encodings!! Russian especially has been a problem. See bugs 43701, 88033, 91808, 93057
+-
+-for things to look for when dealing with messages.
+-
+-
+ Direct Connections
+ ====================================
+ When/If we get around to it. Matt knows absolutely nothing about direct connections and the only online source of documentation is no longer online. :(
+--- kopete/protocols/oscar/liboscar/oscartypeclasses.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/oscartypeclasses.cpp	(revision 586398)
+@@ -179,7 +179,7 @@
+ 	TLV aliasTLV = findTLV( m_tlvList, 0x0131 );
+ 	if ( aliasTLV )
+ 	{
+-		m_alias.insert( 0, aliasTLV.data );
++		m_alias = QString::fromUtf8( aliasTLV.data, aliasTLV.length );
+ 		kdDebug( 14151 ) << k_funcinfo << "Got an alias '" << m_alias << "' for contact '" << m_name << "'" << endl;
+ 	}
+ 
+@@ -253,8 +253,18 @@
+ Oscar::SSI::operator QByteArray() const
+ {
+ 	Buffer b;
+-	b.addWord( m_name.length() );
+-	b.addString( m_name.latin1(), m_name.length() ); //TODO check encoding
++	QCString name( m_name.utf8() );
++	uint namelen = name.length();
++	const char *namedata = name;
++	b.addWord( namelen );
++	// Using namedata instead of name because
++	// Buffer::addString(QByteArray, DWORD) ignores it's second argument,
++	// while Buffer::addString(const char*, DWORD) does not ignore it.
++	// We must provide the explicit length argument to addString() because
++	// we don't need trailing null byte to be added when automatic
++	// conversion from QCString to QByteArray is performed.
++	// This hack will not be needed with Qt 4.
++	b.addString( namedata, namelen );
+ 	b.addWord( m_gid );
+ 	b.addWord( m_bid );
+ 	b.addWord( m_type );
+--- kopete/protocols/oscar/liboscar/ssimanager.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/ssimanager.cpp	(revision 586398)
+@@ -86,6 +86,7 @@
+ 		d->nextContactId++;
+ 	
+ 	d->nextContactId = findFreeId( d->itemIdList, d->nextContactId );
++	
+ 	if ( d->nextContactId == 0xFFFF )
+ 	{
+ 		kdWarning(OSCAR_RAW_DEBUG) << k_funcinfo << "No free id!" << endl;
+@@ -104,6 +105,7 @@
+ 		d->nextGroupId++;
+ 	
+ 	d->nextGroupId = findFreeId( d->groupIdList, d->nextGroupId );
++	
+ 	if ( d->nextGroupId == 0xFFFF )
+ 	{
+ 		kdWarning(OSCAR_RAW_DEBUG) << k_funcinfo << "No free group id!" << endl;
+@@ -301,6 +303,17 @@
+ 	return m_dummyItem;	
+ }
+ 
++Oscar::SSI SSIManager::findItem( const QString &contact, int type ) const
++{
++	QValueList<Oscar::SSI>::const_iterator it,  listEnd = d->SSIList.end();
++	
++	for ( it = d->SSIList.begin(); it!= listEnd; ++it )
++		if ( ( *it ).type() == type && ( *it ).name() == contact )
++			return ( *it );
++	
++	return m_dummyItem;
++}
++
+ QValueList<Oscar::SSI> SSIManager::groupList() const
+ {
+ 	QValueList<Oscar::SSI> list;
+@@ -419,6 +432,29 @@
+ 	return false;
+ }
+ 
++bool SSIManager::updateGroup( const Oscar::SSI& oldGroup, const Oscar::SSI& newGroup )
++{
++	removeID( oldGroup );
++	if ( d->SSIList.remove( oldGroup ) == 0 )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "No group were removed." << endl;
++		return false;
++	}
++	
++	if ( d->SSIList.findIndex( newGroup ) != -1 )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "New group is already in list." << endl;
++		return false;
++	}
++	
++	kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Updating group '" << newGroup.name() << "' in SSI list" << endl;
++	d->SSIList.append( newGroup );
++	addID( newGroup );
++	emit groupUpdated( newGroup );
++	
++	return true;
++}
++
+ bool SSIManager::removeGroup( const Oscar::SSI& group )
+ {
+ 	QString groupName = group.name();
+@@ -464,6 +500,29 @@
+ 	return true;
+ }
+ 
++bool SSIManager::updateContact( const Oscar::SSI& oldContact, const Oscar::SSI& newContact )
++{
++	removeID( oldContact );
++	if ( d->SSIList.remove( oldContact ) == 0 )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "No contacts were removed." << endl;
++		return false;
++	}
++	
++	if ( d->SSIList.findIndex( newContact ) != -1 )
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "New contact is already in list." << endl;
++		return false;
++	}
++	
++	kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Updating contact '" << newContact.name() << "' in SSI list" << endl;
++	addID( newContact );
++	d->SSIList.append( newContact );
++	emit contactUpdated( newContact );
++	
++	return true;
++}
++
+ bool SSIManager::removeContact( const Oscar::SSI& contact )
+ {
+ 	QString contactName = contact.name();
+--- kopete/protocols/oscar/liboscar/icquserinfo.h	(revision 568672)
++++ kopete/protocols/oscar/liboscar/icquserinfo.h	(revision 586398)
+@@ -19,7 +19,7 @@
+ #ifndef _ICQUSERINFO_H_
+ #define _ICQUSERINFO_H_
+ 
+-#include <qstring.h>
++#include <qcstring.h>
+ #include <qvaluelist.h>
+ #include <qdatetime.h>
+ #include "kopete_export.h"
+@@ -56,10 +56,10 @@
+ 	
+ public:
+ 	unsigned long uin;
+-	QString nickname;
+-	QString firstName;
+-	QString lastName;
+-	QString email;
++	QCString nickname;
++	QCString firstName;
++	QCString lastName;
++	QCString email;
+ 	bool needsAuth;
+ 	unsigned int gender; // 0=offline, 1=online, 2=not webaware
+ };
+@@ -73,17 +73,17 @@
+ 	
+ public:
+ 	unsigned long uin;
+-	QString nickname;
+-	QString firstName;
+-	QString lastName;
+-	QString email;
+-	QString city;
+-	QString state;
+-	QString phoneNumber;
+-	QString faxNumber;
+-	QString address;
+-	QString cellNumber;
+-	QString zip;
++	QCString nickname;
++	QCString firstName;
++	QCString lastName;
++	QCString email;
++	QCString city;
++	QCString state;
++	QCString phoneNumber;
++	QCString faxNumber;
++	QCString address;
++	QCString cellNumber;
++	QCString zip;
+ 	int country;
+ 	char timezone;
+ 	bool publishEmail;
+@@ -99,18 +99,18 @@
+ 	void fill( Buffer* buffer );
+ 	
+ public:
+-	QString city;
+-	QString state;
+-	QString phone;
+-	QString fax;
+-	QString address;
+-	QString zip;
++	QCString city;
++	QCString state;
++	QCString phone;
++	QCString fax;
++	QCString address;
++	QCString zip;
+ 	int country;
+-	QString company;
+-	QString department;
+-	QString position;
++	QCString company;
++	QCString department;
++	QCString position;
+ 	int occupation;
+-	QString homepage;
++	QCString homepage;
+ };
+ 
+ class KOPETE_EXPORT ICQMoreUserInfo : public ICQInfoBase
+@@ -123,13 +123,13 @@
+ public:
+ 	int age;
+ 	unsigned int gender;
+-	QString homepage;
++	QCString homepage;
+ 	QDate birthday;
+ 	unsigned int lang1;
+ 	unsigned int lang2;
+ 	unsigned int lang3;
+-	QString ocity;
+-	QString ostate;
++	QCString ocity;
++	QCString ostate;
+ 	int ocountry;
+ 	int marital;
+ };
+@@ -142,7 +142,7 @@
+ 	void fill( Buffer* buffer );
+ 	
+ public:
+-	QValueList<QString> emailList;
++	QValueList<QCString> emailList;
+ };
+ 
+ class KOPETE_EXPORT ICQInterestInfo : public ICQInfoBase
+@@ -155,7 +155,7 @@
+ public:
+ 	int count;
+ 	int topics[4];
+-	QString descriptions[4];
++	QCString descriptions[4];
+ };
+ 
+ 
+@@ -165,10 +165,10 @@
+ 	ICQSearchResult();
+ 	void fill( Buffer* buffer );
+ 	Q_UINT32 uin;
+-	QString firstName;
+-	QString lastName;
+-	QString nickName;
+-	QString email;
++	QCString firstName;
++	QCString lastName;
++	QCString nickName;
++	QCString email;
+ 	bool auth;
+ 	bool online;
+ 	char gender;
+@@ -180,19 +180,19 @@
+ public:
+ 	ICQWPSearchInfo();
+ 	
+-	QString firstName;
+-	QString lastName;
+-	QString nickName;
+-	QString email;
++	QCString firstName;
++	QCString lastName;
++	QCString nickName;
++	QCString email;
+ 	int age;
+ 	int gender;
+ 	int language;
+-	QString city;
+-	QString state;
++	QCString city;
++	QCString state;
+ 	int country;
+-	QString company;
+-	QString department;
+-	QString position;
++	QCString company;
++	QCString department;
++	QCString position;
+ 	int occupation;
+ 	bool onlineOnly;
+ };
+@@ -202,7 +202,7 @@
+ {
+ public:
+ 	int category;
+-	QString description;
++	QCString description;
+ };
+ 
+ 
+--- kopete/protocols/oscar/liboscar/messagereceivertask.cpp	(revision 568672)
++++ kopete/protocols/oscar/liboscar/messagereceivertask.cpp	(revision 586398)
+@@ -21,7 +21,6 @@
+ #include "transfer.h"
+ #include "buffer.h"
+ #include "connection.h"
+-
+ #include "oscarutils.h"
+ #include "userdetails.h"
+ 
+@@ -149,24 +148,17 @@
+ 			m_subCharSet = message.getWord();
+ 			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Message charset: " << m_charSet
+ 				<< " message subcharset: " << m_subCharSet << endl;
+-            if ( m_charSet == 0x0002 )
+-			{
+-				msg.addProperty( Oscar::Message::UCS2 );
+-				int messageLength = ( ( *it ).length - 4 ) / 2;
+-				kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message length: " << messageLength << endl;
+-				msg.setText( QString::fromUcs2( message.getWordBlock( messageLength ) ) );
+-				kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message is: " << msg.text() << endl;
+-			}
+-            else
+-            {
+-                msg.addProperty( Oscar::Message::NotDecoded );
+-                //message length is buffer length - length of ( charset + subcharset ) */
+-                int msgLength = ( *it ).length - 4;
+-                QByteArray msgArray( message.getBlock( msgLength ) );
+-                msg.setTextArray( msgArray );
+-            }
++			if ( m_charSet == 0x0002 )
++				msg.setEncoding( Oscar::Message::UCS2 );
++			else
++				msg.setEncoding( Oscar::Message::UserDefined );
+ 
+-            break;
++			//message length is buffer length - length of ( charset + subcharset ) */
++			int msgLength = ( *it ).length - 4;
++			QByteArray msgArray( message.getBlock( msgLength ) );
++			msg.setTextArray( msgArray );
++
++			break;
+ 		} //end case
+ 		default:
+ 			kdDebug(OSCAR_RAW_DEBUG) << "Ignoring TLV of type " << ( *it ).type << endl;
+@@ -310,7 +302,7 @@
+ 		break;
+ 	};
+ 
+-	QByteArray msgText = tlv5buffer.getLNTS();
++	QCString msgText = tlv5buffer.getLNTS();
+ 	int msgLength = msgText.size();
+ 	if ( msgType == 0x0D || msgType == 0x0E )
+ 	{
+@@ -321,7 +313,6 @@
+ 		}
+ 	}
+ 
+-	msg.addProperty( Oscar::Message::NotDecoded );
+ 	switch ( msgFlags )
+ 	{
+ 	case 0x03:
+@@ -339,6 +330,7 @@
+ 	msg.setTimestamp( QDateTime::currentDateTime() );
+ 	msg.setSender( msgSender );
+ 	msg.setReceiver( client()->userId() );
++	msg.setEncoding( Oscar::Message::UserDefined );
+ 	msg.setTextArray( msgText );
+ 	emit receivedMessage( msg );
+ }
+@@ -407,30 +399,30 @@
+ 
+ 		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Message type is: " << messageType << endl;
+ 		
+-		QCString msgtext( b->getLELNTS() );
+-		int prop = Oscar::Message::NotDecoded;
+-		if ( messageType == 0x01 )
++		QCString msgText( b->getLELNTS() );
++		Oscar::Message::Encoding encoding = Oscar::Message::UserDefined;
++		int fgcolor = 0x00000000;
++		int bgcolor = 0x00ffffff;
++
++		if ( b->length() >= 8 )
+ 		{
+-			int fgcolor = b->getLEDWord();
+-			int bgcolor = b->getLEDWord();
+-			
++			fgcolor = b->getLEDWord();
++			bgcolor = b->getLEDWord();
++
+ 			while ( b->length() >= 4 )
+ 			{
+ 				int capLength = b->getLEDWord();
+ 				if ( b->length() < capLength )
+ 					break;
+-	
++
+ 				QByteArray cap( b->getBlock( capLength ) );
+ 				if ( qstrncmp ( cap.data(), "{0946134E-4C7F-11D1-8222-444553540000}", capLength ) == 0 )
+-					prop = Oscar::Message::UCS2;
++					encoding = Oscar::Message::UTF8;
+ 			}
+ 		}
+ 
+-		msg->addProperty( prop );
+-		if ( prop == Oscar::Message::UCS2 )
+-			msg->setText( QString::fromUtf8( msgtext ) );
+-		else
+-			msg->setTextArray( msgtext );
++		msg->setEncoding( encoding );
++		msg->setTextArray( msgText );
+ 		
+ 		if ( ( messageType & 0xF0 ) == 0xE0 ) // check higher byte for value E -> status message request
+ 			msg->addProperty( Oscar::Message::StatusMessageRequest );
+--- kopete/protocols/oscar/oscarcontact.cpp	(revision 568672)
++++ kopete/protocols/oscar/oscarcontact.cpp	(revision 586398)
+@@ -19,6 +19,7 @@
+ #include <time.h>
+ 
+ #include <qapplication.h>
++#include <qtextcodec.h>
+ 
+ #include <kaction.h>
+ #include <kdebug.h>
+@@ -132,46 +133,29 @@
+ void OscarContact::sync(unsigned int flags)
+ {
+ 	/* 
+-	 * If the contact is waiting for auth, we do nothing
+ 	 * If the contact has changed groups, then we update the server
+ 	 *   adding the group if it doesn't exist, changing the ssi item
+ 	 *   contained in the client and updating the contact's ssi item
+ 	 * Otherwise, we don't do much
+ 	 */
++	
++	if( !metaContact() || metaContact()->isTemporary() )
++		return;
++	
+ 	if ( flags & Kopete::Contact::MovedBetweenGroup == Kopete::Contact::MovedBetweenGroup )
+ 	{
+-
+-		if ( m_ssiItem.waitingAuth() )
+-		{
+-			kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Contact still requires auth. Doing nothing" << endl;
+-			return;
+-		}
+-		
+ 		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Moving a contact between groups" << endl;
+ 		SSIManager* ssiManager = mAccount->engine()->ssiManager();
++		
+ 		SSI oldGroup = ssiManager->findGroup( m_ssiItem.gid() );
+ 		Kopete::Group* newGroup = metaContact()->groups().first();
+ 		if ( newGroup->displayName() == oldGroup.name() )
+ 			return; //we didn't really move
+ 		
+-		if ( !ssiManager->findGroup( newGroup->displayName() ) )
+-		{ //we don't have the group on the server
+-			kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "the group '" << newGroup->displayName() << "' is not on the server"
+-				<< "adding it" << endl;
+-			mAccount->engine()->addGroup( newGroup->displayName() );
+-		}
+-		
+-		SSI newSSIGroup = ssiManager->findGroup( newGroup->displayName() );
+-		if ( !newSSIGroup )
+-		{
+-			kdWarning(OSCAR_GEN_DEBUG) << k_funcinfo << newSSIGroup.name() << " not found on SSI list after addition!" << endl;
+-			return;
+-		}
+-		
+-		mAccount->engine()->changeContactGroup( contactId(), newGroup->displayName() );
+-		SSI newItem( m_ssiItem.name(), newSSIGroup.gid(), m_ssiItem.bid(), m_ssiItem.type(),
+-		             m_ssiItem.tlvList(), m_ssiItem.tlvListLength() );
+-		setSSIItem( newItem );
++		if ( m_ssiItem.isValid() )
++			mAccount->changeContactGroupInSSI( contactId(), newGroup->displayName(), true );
++		else
++			mAccount->addContactToSSI( contactId(), newGroup->displayName(), true );
+ 	}
+ 	return;
+ }
+@@ -241,5 +225,13 @@
+ 		account()->engine()->sendTyping( contactId(), typing );
+ }
+ 
++QTextCodec* OscarContact::contactCodec() const
++{
++	if ( hasProperty( "contactEncoding" ) )
++		return QTextCodec::codecForMib( property( "contactEncoding" ).value().toInt() );
++	else
++		return mAccount->defaultCodec();
++}
++
+ #include "oscarcontact.moc"
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/oscaraccount.cpp	(revision 568672)
++++ kopete/protocols/oscar/oscaraccount.cpp	(revision 586398)
+@@ -37,12 +37,16 @@
+ #include <qstylesheet.h>
+ #include <qtimer.h>
+ #include <qptrlist.h>
++#include <qtextcodec.h>
++#include <qimage.h>
++#include <qfile.h>
+ 
+ #include <kdebug.h>
+ #include <kconfig.h>
+ #include <klocale.h>
+ #include <kmessagebox.h>
+ #include <kpassivepopup.h>
++#include <kstandarddirs.h>
+ 
+ #include "client.h"
+ #include "connection.h"
+@@ -53,11 +57,14 @@
+ #include "oscarconnector.h"
+ #include "ssimanager.h"
+ #include "oscarlistnonservercontacts.h"
+-#include <qtextcodec.h>
++#include "oscarversionupdater.h"
+ 
+-class OscarAccountPrivate
++class OscarAccountPrivate : public Client::CodecProvider
+ {
++	// Backreference
++	OscarAccount& account;
+ public:
++	OscarAccountPrivate( OscarAccount& a ): account( a ) {}
+ 
+ 	//The liboscar hook for the account
+ 	Client* engine;
+@@ -69,9 +76,22 @@
+ 
+ 	//contacts waiting on their group to be added
+ 	QMap<QString, QString> contactAddQueue;
++	QMap<QString, QString> contactChangeQueue;
+ 
+     OscarListNonServerContacts* olnscDialog;
++	
++	unsigned int versionUpdaterStamp;
++	bool versionAlreadyUpdated;
+ 
++	virtual QTextCodec* codecForContact( const QString& contactName ) const
++	{
++		return account.contactCodec( Oscar::normalize( contactName ) );
++	}
++
++	virtual QTextCodec* codecForAccount() const
++	{
++		return account.defaultCodec();
++	}
+ };
+ 
+ OscarAccount::OscarAccount(Kopete::Protocol *parent, const QString &accountID, const char *name, bool isICQ)
+@@ -80,8 +100,18 @@
+ 	kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << " accountID='" << accountID <<
+ 		"', isICQ=" << isICQ << endl;
+ 
+-	d = new OscarAccountPrivate;
++	d = new OscarAccountPrivate( *this );
+ 	d->engine = new Client( this );
++	d->engine->setIsIcq( isICQ );
++	
++	d->versionAlreadyUpdated = false;
++	d->versionUpdaterStamp = OscarVersionUpdater::self()->stamp();
++	if ( isICQ )
++		d->engine->setVersion( OscarVersionUpdater::self()->getICQVersion() );
++	else
++		d->engine->setVersion( OscarVersionUpdater::self()->getAIMVersion() );
++
++	d->engine->setCodecProvider( d );
+     d->olnscDialog = 0L;
+     QObject::connect( d->engine, SIGNAL( loggedIn() ), this, SLOT( loginActions() ) );
+ 	QObject::connect( d->engine, SIGNAL( messageReceived( const Oscar::Message& ) ),
+@@ -94,6 +124,8 @@
+ 	                  this, SLOT( userStartedTyping( const QString& ) ) );
+ 	QObject::connect( d->engine, SIGNAL( userStoppedTyping( const QString& ) ),
+ 	                  this, SLOT( userStoppedTyping( const QString& ) ) );
++	QObject::connect( d->engine, SIGNAL( iconNeedsUploading() ),
++	                  this, SLOT( slotSendBuddyIcon() ) );
+ }
+ 
+ OscarAccount::~OscarAccount()
+@@ -120,15 +152,16 @@
+ 	                     this, SLOT( ssiContactAdded( const Oscar::SSI& ) ) );
+ 	QObject::disconnect( d->engine->ssiManager(), SIGNAL( groupAdded( const Oscar::SSI& ) ),
+ 	                     this, SLOT( ssiGroupAdded( const Oscar::SSI& ) ) );
++	QObject::disconnect( d->engine->ssiManager(), SIGNAL( groupUpdated( const Oscar::SSI& ) ),
++	                     this, SLOT( ssiGroupUpdated( const Oscar::SSI& ) ) );
++	QObject::disconnect( d->engine->ssiManager(), SIGNAL( contactUpdated( const Oscar::SSI& ) ),
++	                     this, SLOT( ssiContactUpdated( const Oscar::SSI& ) ) );
+ 
+ 	d->engine->close();
+ 	myself()->setOnlineStatus( Kopete::OnlineStatus::Offline );
+ 
+-	QDictIterator<Kopete::Contact> it( contacts() );
+-	for( ; it.current(); ++it )
+-	{
+-		it.current()->setOnlineStatus(Kopete::OnlineStatus::Offline);
+-	}
++	d->contactAddQueue.clear();
++	d->contactChangeQueue.clear();
+ 
+ 	disconnected( reason );
+ }
+@@ -143,19 +176,6 @@
+ 	return password().isWrong();
+ }
+ 
+-void OscarAccount::updateContact( Oscar::SSI item )
+-{
+-	Kopete::Contact* contact = contacts()[item.name()];
+-	if ( !contact )
+-		return;
+-	else
+-	{
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Updating SSI Item" << endl;
+-		OscarContact* oc = static_cast<OscarContact*>( contact );
+-		oc->setSSIItem( item );
+-	}
+-}
+-
+ void OscarAccount::loginActions()
+ {
+     password().setWrong( false );
+@@ -169,12 +189,9 @@
+ 		d->engine->requestServerRedirect( 0x000D );
+ 	}
+ 
+-	//ICQ handles icons but we don't support those right now
+-	if ( !engine()->isIcq() )
+-	{
+-		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending request for icon service" << endl;
+-		d->engine->requestServerRedirect( 0x0010 );
+-	}
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending request for icon service" << endl;
++	d->engine->requestServerRedirect( 0x0010 );
++
+ }
+ 
+ void OscarAccount::processSSIList()
+@@ -239,6 +256,10 @@
+ 	                  this, SLOT( ssiContactAdded( const Oscar::SSI& ) ) );
+ 	QObject::connect( listManager, SIGNAL( groupAdded( const Oscar::SSI& ) ),
+ 	                  this, SLOT( ssiGroupAdded( const Oscar::SSI& ) ) );
++	QObject::connect( listManager, SIGNAL( groupUpdated( const Oscar::SSI& ) ),
++	                  this, SLOT( ssiGroupUpdated( const Oscar::SSI& ) ) );
++	QObject::connect( listManager, SIGNAL( contactUpdated( const Oscar::SSI& ) ),
++	                  this, SLOT( ssiContactUpdated( const Oscar::SSI& ) ) );
+ 
+     //TODO: check the kopete contact list and handle non server side contacts appropriately.
+     QDict<Kopete::Contact> nonServerContacts = contacts();
+@@ -306,18 +327,7 @@
+                 continue;
+             }
+ 
+-            SSIManager* listManager = d->engine->ssiManager();
+-            if ( !listManager->findGroup( group->displayName() ) )
+-            {
+-                kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "adding non-existant group "
+-                                         << group->displayName() << endl;
+-                d->contactAddQueue[Oscar::normalize( ( *it ) )] = group->displayName();
+-                d->engine->addGroup( group->displayName() );
+-            }
+-            else
+-            {
+-                d->engine->addContact( ( *it ), group->displayName() );
+-            }
++	        addContactToSSI( ( *it ), group->displayName(), true );
+         }
+ 
+ 
+@@ -365,7 +375,7 @@
+ 	if ( Oscar::normalize( message.receiver() ) != Oscar::normalize( accountId() ) )
+ 	{
+ 		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "got a message but we're not the receiver: "
+-			<< message.text() << endl;
++			<< message.textArray() << endl;
+ 		return;
+ 	}
+ 
+@@ -387,7 +397,7 @@
+ 	if ( !ocSender )
+ 	{
+ 		kdWarning(OSCAR_RAW_DEBUG) << "Temporary contact creation failed for '"
+-			<< sender << "'! Discarding message: " << message.text() << endl;
++			<< sender << "'! Discarding message: " << message.textArray() << endl;
+ 		return;
+ 	}
+ 	else
+@@ -402,21 +412,12 @@
+ 	chatSession->receivedTypingMsg( ocSender, false ); //person is done typing
+ 
+ 
+-    //decode message
+-    //HACK HACK HACK! Until AIM supports per contact encoding, just decode as ISO-8559-1
+-    QTextCodec* codec = 0L;
+-    if ( ocSender->hasProperty( "contactEncoding" ) )
+-        codec = QTextCodec::codecForMib( ocSender->property( "contactEncoding" ).value().toInt() );
+-    else
+-        codec = QTextCodec::codecForMib( 4 );
++	//decode message
++	QString realText( message.text( contactCodec( ocSender ) ) );
+ 
+-    QString realText = message.text();
+-    if ( message.properties() & Oscar::Message::NotDecoded )
+-        realText = codec->toUnicode( message.textArray() );
++	//sanitize;
++	QString sanitizedMsg = sanitizedMessage( realText );
+ 
+-    //sanitize;
+-    QString sanitizedMsg = sanitizedMessage( realText );
+-
+ 	Kopete::ContactPtrList me;
+ 	me.append( myself() );
+ 	Kopete::Message chatMessage( message.timestamp(), ocSender, me, sanitizedMsg,
+@@ -439,6 +440,104 @@
+ 		configGroup()->writeEntry( QString::fromLatin1( "Port" ), 5190 );
+ }
+ 
++QTextCodec* OscarAccount::defaultCodec() const
++{
++	return QTextCodec::codecForMib( configGroup()->readNumEntry( "DefaultEncoding", 4 ) );
++}
++
++QTextCodec* OscarAccount::contactCodec( const OscarContact* contact ) const
++{
++	if ( contact )
++		return contact->contactCodec();
++	else
++		return defaultCodec();
++}
++
++QTextCodec* OscarAccount::contactCodec( const QString& contactName ) const
++{
++	// XXX  Need const_cast because Kopete::Account::contacts()
++	// XXX  method is not const for some strange reason.
++	OscarContact* contact = static_cast<OscarContact *> ( const_cast<OscarAccount *>(this)->contacts()[contactName] );
++	return contactCodec( contact );
++}
++
++void OscarAccount::setBuddyIcon( KURL url )
++{
++	if ( url.path().isEmpty() )
++	{
++		myself()->removeProperty( Kopete::Global::Properties::self()->photo() );
++	}
++	else
++	{
++		QImage image( url.path() );
++		if ( image.isNull() )
++			return;
++		
++		const QSize size = ( d->engine->isIcq() ) ? QSize( 52, 64 ) : QSize( 48, 48 );
++		
++		image = image.smoothScale( size, QImage::ScaleMax );
++		if( image.width() > size.width())
++			image = image.copy( ( image.width() - size.width() ) / 2, 0, size.width(), image.height() );
++		
++		if( image.height() > size.height())
++			image = image.copy( 0, ( image.height() - size.height() ) / 2, image.width(), size.height() );
++		
++		QString newlocation( locateLocal( "appdata", "oscarpictures/"+ accountId() + ".jpg" ) );
++		
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Saving buddy icon: " << newlocation << endl;
++		if ( !image.save( newlocation, "JPEG" ) )
++			return;
++		
++		myself()->setProperty( Kopete::Global::Properties::self()->photo() , newlocation );
++	}
++	
++	emit buddyIconChanged();
++}
++
++bool OscarAccount::addContactToSSI( const QString& contactName, const QString& groupName, bool autoAddGroup )
++{
++	SSIManager* listManager = d->engine->ssiManager();
++	if ( !listManager->findGroup( groupName ) )
++	{
++		if ( !autoAddGroup )
++			return false;
++
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "adding non-existant group "
++			<< groupName << endl;
++
++		d->contactAddQueue[Oscar::normalize( contactName )] = groupName;
++		d->engine->addGroup( groupName );
++	}
++	else
++	{
++		d->engine->addContact( contactName, groupName );
++	}
++
++	return true;
++}
++
++bool OscarAccount::changeContactGroupInSSI( const QString& contact, const QString& newGroupName, bool autoAddGroup )
++{
++	SSIManager* listManager = d->engine->ssiManager();
++	if ( !listManager->findGroup( newGroupName ) )
++	{
++		if ( !autoAddGroup )
++			return false;
++		
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "adding non-existant group " 
++				<< newGroupName << endl;
++			
++		d->contactChangeQueue[Oscar::normalize( contact )] = newGroupName;
++		d->engine->addGroup( newGroupName );
++	}
++	else
++	{
++		d->engine->changeContactGroup( contact, newGroupName );
++	}
++	
++	return true;
++}
++
+ Connection* OscarAccount::setupConnection( const QString& server, uint port )
+ {
+ 	//set up the connector
+@@ -532,20 +631,17 @@
+ 			return false;
+ 		}
+ 
+-		if ( !d->engine->ssiManager()->findGroup( groupName ) )
+-		{ //group isn't on SSI
+-			d->contactAddQueue[Oscar::normalize( contactId )] = groupName;
+-			d->addContactMap[Oscar::normalize( contactId )] = parentContact;
+-			d->engine->addGroup( groupName );
+-			return true;
+-		}
+-
+ 		d->addContactMap[Oscar::normalize( contactId )] = parentContact;
+-		d->engine->addContact( Oscar::normalize( contactId ), groupName );
++		addContactToSSI( Oscar::normalize( contactId ), groupName, true );
+ 		return true;
+ 	}
+ }
+ 
++void OscarAccount::updateVersionUpdaterStamp()
++{
++	d->versionUpdaterStamp = OscarVersionUpdater::self()->stamp();
++}
++
+ void OscarAccount::ssiContactAdded( const Oscar::SSI& item )
+ {
+ 	if ( d->addContactMap.contains( Oscar::normalize( item.name() ) ) )
+@@ -554,6 +650,12 @@
+ 			<< " to the contact list" << endl;
+ 		createNewContact( item.name(), d->addContactMap[Oscar::normalize( item.name() )], item );
+ 	}
++	else if ( contacts()[item.name()] )
++	{
++		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Received confirmation from server. modifying " << item.name() << endl;
++		OscarContact* oc = static_cast<OscarContact*>( contacts()[item.name()] );
++		oc->setSSIItem( item );
++	}
+ 	else
+ 		kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "Got addition for contact we weren't waiting on" << endl;
+ }
+@@ -568,13 +670,40 @@
+ 	{
+ 		if ( Oscar::normalize( it.data() ) == Oscar::normalize( item.name() ) )
+ 		{
+-			kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "starting delayed add of contact '" << it.key() << "' to group "
+-				<< item.name() << endl;
+-			d->engine->addContact( Oscar::normalize( it.key() ), item.name() ); //already in the map
++			kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "starting delayed add of contact '" << it.key()
++				<< "' to group " << item.name() << endl;
++			
++			d->engine->addContact( Oscar::normalize( it.key() ), item.name() );
++			d->contactAddQueue.remove( it );
+ 		}
+ 	}
++	
++	for ( it = d->contactChangeQueue.begin(); it != d->contactChangeQueue.end(); ++it )
++	{
++		if ( Oscar::normalize( it.data() ) == Oscar::normalize( item.name() ) )
++		{
++			kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "starting delayed change of contact '" << it.key()
++				<< "' to group " << item.name() << endl;
++			
++			d->engine->changeContactGroup( it.key(),  item.name() );
++			d->contactChangeQueue.remove( it );
++		}
++	}
+ }
+ 
++void OscarAccount::ssiContactUpdated( const Oscar::SSI& item )
++{
++	Kopete::Contact* contact = contacts()[item.name()];
++	if ( !contact )
++		return;
++	else
++	{
++		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Updating SSI Item" << endl;
++		OscarContact* oc = static_cast<OscarContact*>( contact );
++		oc->setSSIItem( item );
++	}
++}
++
+ void OscarAccount::userStartedTyping( const QString & contact )
+ {
+ 	Kopete::Contact * ct = contacts()[ Oscar::normalize( contact ) ];
+@@ -649,6 +778,31 @@
+ 		logOff( Kopete::Account::ConnectionReset );
+ }
+ 
++void OscarAccount::slotSendBuddyIcon()
++{
++	//need to disconnect because we could end up with many connections
++	QObject::disconnect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotSendBuddyIcon() ) );
++	QString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
++	if ( photoPath.isEmpty() )
++		return;
++	
++	kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << photoPath << endl;
++	QFile iconFile( photoPath );
++	
++	if ( iconFile.open( IO_ReadOnly ) )
++	{
++		if ( !engine()->hasIconConnection() )
++		{
++			//will send icon when we connect to icon server
++			QObject::connect( engine(), SIGNAL( iconServerConnected() ),
++			                  this, SLOT( slotSendBuddyIcon() ) );
++			return;
++		}
++		QByteArray imageData = iconFile.readAll();
++		engine()->sendBuddyIcon( imageData );
++	}
++}
++
+ QString OscarAccount::getFLAPErrorMessage( int code )
+ {
+ 	bool isICQ = d->engine->isIcq();
+@@ -725,9 +879,20 @@
+ 		}
+ 		break;
+ 	case 0x001C:
+-		reason = i18n("The %1 server thinks the client you are using is " \
+-		              "too old. Please report this as a bug at http://bugs.kde.org")
+-			.arg( acctType );
++		OscarVersionUpdater::self()->update( d->versionUpdaterStamp );
++		if ( !d->versionAlreadyUpdated )
++		{
++			reason = i18n("Sign on to %1 with your account %2 failed.")
++				.arg( acctType ).arg( accountId() );
++			
++			d->versionAlreadyUpdated = true;
++		}
++		else
++		{
++			reason = i18n("The %1 server thinks the client you are using is " \
++						  "too old. Please report this as a bug at http://bugs.kde.org")
++				.arg( acctType );
++		}
+ 		break;
+ 	case 0x0022: // Account suspended because of your age (age < 13)
+ 		reason = i18n("Account %1 was disabled on the %2 server because " \
+@@ -744,5 +909,6 @@
+ 	}
+ 	return reason;
+ }
++
+ #include "oscaraccount.moc"
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/TODO	(revision 568672)
++++ kopete/protocols/oscar/TODO	(revision 586398)
+@@ -12,16 +12,12 @@
+ 
+ ====== Catching up to OscarSocket =====
+ 
+-- Support for invisible and visible lists (see liboscar/TODO)
+-- Messaging - Type 2
+ - Fill in all the ICQ user info
+ - Add preferences for "Requires Auth", "Web Aware", etc.
+ 
+ 
+-
+ ====== Adding new features not in oscarsocket ======
+ 
+-Support buddy icon connections
+ Support direct connections
+ Support file transfers
+ A bunch of other stuff i'm probably forgetting.
+@@ -42,8 +38,6 @@
+ - honor encodings for both sides (I need more knowledge about this!)
+ - Option: Allow access from contacts on my contact list only
+ - group handling in general
+-- ignore lists (needs proper group-handling)
+-- invisible list (needs proper group-handling)
+ - error handling on channel 0x04 messages. properly disconnect and emit a
+   signal in oscarsocket.
+ - save groupID in KopeteGroups
+--- kopete/protocols/oscar/aim/aimchatsession.cpp	(revision 0)
++++ kopete/protocols/oscar/aim/aimchatsession.cpp	(revision 586398)
+@@ -0,0 +1,73 @@
++// aimchatsession.cpp
++
++// Copyright (C)  2005  Matt Rogers <mattr at 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.
++
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
++// 02110-1301, USA.
++
++
++#include "aimchatsession.h"
++#include "kopetecontact.h"
++#include "kopetechatsessionmanager.h"
++#include "kopeteprotocol.h"
++#include "client.h"
++
++AIMChatSession::AIMChatSession( const Kopete::Contact* user,  Kopete::ContactPtrList others,
++                                Kopete::Protocol* protocol, Oscar::WORD exchange,
++                                const QString& room )
++
++    : Kopete::ChatSession( user, others, protocol, "AIMChatSession" )
++{
++    Kopete::ChatSessionManager::self()->registerChatSession( this );
++    setInstance( protocol->instance() );
++    setMayInvite( false );
++    m_exchange = exchange;
++    m_roomName = room;
++    m_engine = 0;
++}
++
++AIMChatSession::~AIMChatSession()
++{
++    m_engine->disconnectChatRoom( m_exchange, m_roomName );
++}
++
++void AIMChatSession::setEngine( Client* engine )
++{
++    m_engine = engine;
++}
++
++QString AIMChatSession::roomName() const
++{
++
++    return m_roomName;
++}
++
++void AIMChatSession::setRoomName( const QString& room )
++{
++    m_roomName = room;
++}
++
++Oscar::WORD AIMChatSession::exchange() const
++{
++    return m_exchange;
++}
++
++void AIMChatSession::setExchange( Oscar::WORD exchange )
++{
++    m_exchange = exchange;
++}
++
++
++#include "aimchatsession.moc"
+--- kopete/protocols/oscar/aim/aimchatsession.h	(revision 0)
++++ kopete/protocols/oscar/aim/aimchatsession.h	(revision 586398)
+@@ -0,0 +1,77 @@
++// aimchatsession.h
++// Copyright (C)  2005  Matt Rogers <mattr at 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.
++
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
++// 02110-1301, USA.
++
++#ifndef AIMCHATSESSION_H
++#define AIMCHATSESSION_H
++
++#include "kopetechatsession.h"
++#include "oscartypes.h"
++
++class Client;
++
++class AIMChatSession : public Kopete::ChatSession
++{
++Q_OBJECT
++public:
++    AIMChatSession( const Kopete::Contact* contact, Kopete::ContactPtrList others,
++                    Kopete::Protocol* protocol, Oscar::WORD exchange = 0,
++                    const QString& room = QString::null );
++    virtual ~AIMChatSession();
++
++    /**
++     * Set the engine to use so that we can disconnect from the chat service
++     * properly
++     */
++    void setEngine( Client* engine );
++
++    /**
++     * Get the name of the AIM chat room represented by
++     * this ChatSession object
++     * @return the name of the chat room
++     */
++    QString roomName() const;
++
++    /**
++     * Set the name of the AIM chat room represented by
++     * this ChatSession object
++     * @param room the name of the AIM chat room
++     */
++    void setRoomName( const QString& room );
++
++    /**
++     * Get the exchange of the AIM chat room represented by
++     * this ChatSession object
++     * @return the exchange of the chat room
++     */
++    Oscar::WORD exchange() const;
++
++    /**
++     * Set the exchange of the AIM chat room represented by
++     * this ChatSession object
++     * @param exchange the exchange of the AIM chat room
++     */
++    void setExchange( Oscar::WORD exchange );
++
++private:
++    QString m_roomName;
++    Oscar::WORD m_exchange;
++    Client* m_engine;
++};
++
++
++#endif
+--- kopete/protocols/oscar/aim/aimuserinfo.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/aimuserinfo.cpp	(revision 586398)
+@@ -40,7 +40,7 @@
+                                       QWidget *parent, const char* name )
+ 	: KDialogBase( parent, name, modal, i18n( "User Information on %1" )
+ 	               .arg( c->property( Kopete::Global::Properties::self()->nickName() ).value().toString() ),
+-	               Cancel | Ok | User1, Ok, true, i18n("&Update Nickname") )
++	               Cancel | Ok , Ok, true )
+ {
+ 	kdDebug(14200) << k_funcinfo << "for contact '" << c->contactId() << "'" << endl;
+ 
+@@ -168,7 +168,6 @@
+ void AIMUserInfoDialog::slotUpdateProfile()
+ {
+ 	kdDebug(14152) << k_funcinfo << "Got User Profile." << endl;
+-	
+ 	AIMProtocol* p = static_cast<AIMProtocol*>( mAccount->protocol() );
+ 	QString awayMessage = m_contact->property( p->awayMessage ).value().toString();
+ 	mMainWidget->txtAwayMessage->setText( awayMessage );
+--- kopete/protocols/oscar/aim/aimcontact.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/aimcontact.cpp	(revision 586398)
+@@ -19,6 +19,7 @@
+ #include <qimage.h>
+ #include <qregexp.h>
+ #include <qtimer.h>
++#include <qtextcodec.h>
+ 
+ #include <kapplication.h>
+ #include <kactionclasses.h>
+@@ -35,6 +36,7 @@
+ #include "client.h"
+ #include "oscartypes.h"
+ #include "oscarutils.h"
++#include "ssimanager.h"
+ 
+ #include "aimprotocol.h"
+ #include "aimuserinfo.h"
+@@ -52,6 +54,7 @@
+ 	m_warnUserAction = 0L;
+ 	mUserProfile="";
+ 	m_haveAwayMessage = false;
++	m_mobile = false;
+ 	// Set the last autoresponse time to the current time yesterday
+ 	m_lastAutoresponseTime = QDateTime::currentDateTime().addDays(-1);
+ 
+@@ -89,10 +92,28 @@
+ 	{
+ 		m_warnUserAction = new KAction( i18n( "&Warn User" ), 0, this, SLOT( warnUser() ), this, "warnAction" );
+ 	}
++	m_actionVisibleTo = new KToggleAction(i18n("Always &Visible To"), "", 0,
++	                                      this, SLOT(slotVisibleTo()), this, "actionVisibleTo");
++	m_actionInvisibleTo = new KToggleAction(i18n("Always &Invisible To"), "", 0,
++	                                        this, SLOT(slotInvisibleTo()), this, "actionInvisibleTo");
++	
++	bool on = account()->isConnected();
+ 
+-	m_warnUserAction->setEnabled( account()->isConnected() );
++	m_warnUserAction->setEnabled( on );
+ 
++	m_actionVisibleTo->setEnabled(on);
++	m_actionInvisibleTo->setEnabled(on);
++
++	SSIManager* ssi = account()->engine()->ssiManager();
++	m_actionVisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_VISIBLE ));
++	m_actionInvisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_INVISIBLE ));
++
+ 	actionCollection->append( m_warnUserAction );
++
++	actionCollection->append(m_actionVisibleTo);
++	actionCollection->append(m_actionInvisibleTo);
++
++
+ 	return actionCollection;
+ }
+ 
+@@ -166,14 +187,44 @@
+ 	if ( nickname.isEmpty() || Oscar::normalize( nickname ) == Oscar::normalize( contact ) )
+ 		setNickName( contact );
+ 
+-	if ( ( details.userClass() & 32 ) == 0 )
++	( details.userClass() & CLASS_WIRELESS ) ? m_mobile = true : m_mobile = false;
++
++	if ( ( details.userClass() & CLASS_AWAY ) == STATUS_ONLINE )
+ 	{
+-		setOnlineStatus( mProtocol->statusOnline ); //we're online
++		if ( m_mobile ) 
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is mobile-online." << endl;
++			setOnlineStatus( mProtocol->statusWirelessOnline );
++    	}
++		else 
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is online." << endl;
++			setOnlineStatus( mProtocol->statusOnline ); //we're online
++		}
+ 		removeProperty( mProtocol->awayMessage );
+ 		m_haveAwayMessage = false;
+ 	}
++	else if ( ( details.userClass() & CLASS_AWAY ) ) // STATUS_AWAY
++	{
++		if ( m_mobile ) 
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is mobile-away." << endl;
++			setOnlineStatus( mProtocol->statusWirelessOnline );
++		}
++		else 
++		{
++			kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is away." << endl;
++			setOnlineStatus( mProtocol->statusAway ); //we're away
++		}
++		if ( !m_haveAwayMessage ) //prevent cyclic away message requests
++		{
++			mAccount->engine()->requestAIMAwayMessage( contactId() );
++			m_haveAwayMessage = true;
++		}
++	}
+ 	else
+ 	{
++        kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " class " << details.userClass() << " is unhandled... defaulting to away." << endl;
+ 		setOnlineStatus( mProtocol->statusAway ); //we're away
+ 		if ( !m_haveAwayMessage ) //prevent cyclic away message requests
+ 		{
+@@ -222,14 +273,20 @@
+ 		if ( message.isEmpty() )
+ 		{
+ 			removeProperty( mProtocol->awayMessage );
+-			setOnlineStatus( mProtocol->statusOnline );
++			if ( !m_mobile )
++				setOnlineStatus( mProtocol->statusOnline );
++			else
++				setOnlineStatus( mProtocol->statusWirelessOnline );
+ 			m_haveAwayMessage = false;
+ 		}
+ 		else
+ 		{
+ 			m_haveAwayMessage = true;
+ 			setAwayMessage( message );
+-			setOnlineStatus( mProtocol->statusAway );
++			if ( !m_mobile )
++				setOnlineStatus( mProtocol->statusAway );
++			else
++				setOnlineStatus( mProtocol->statusWirelessAway );
+ 		}
+ 	}
+ 
+@@ -307,6 +364,16 @@
+ 		mAccount->engine()->sendWarning( contactId(), false);
+ }
+ 
++void AIMContact::slotVisibleTo()
++{
++	account()->engine()->setVisibleTo( contactId(), m_actionVisibleTo->isChecked() );
++}
++
++void AIMContact::slotInvisibleTo()
++{
++	account()->engine()->setInvisibleTo( contactId(), m_actionInvisibleTo->isChecked() );
++}
++
+ void AIMContact::slotSendMsg(Kopete::Message& message, Kopete::ChatSession *)
+ {
+ 	Oscar::Message msg;
+@@ -374,7 +441,13 @@
+ 	kdDebug(14190) << k_funcinfo << "sending "
+ 		<< s << endl;
+ 
+-	msg.setText(s);
++	// XXX Need to check for message size?
++
++	if ( m_details.hasCap( CAP_UTF8 ) )
++		msg.setText( Oscar::Message::UCS2, s );
++	else
++		msg.setText( Oscar::Message::UserDefined, s, contactCodec() );
++
+ 	msg.setReceiver(mName);
+ 	msg.setTimestamp(message.timestamp());
+ 	msg.setType(0x01);
+@@ -402,11 +475,20 @@
+ 	if(delta > 120)
+ 	{
+ 		kdDebug(14152) << k_funcinfo << "Sending auto response" << endl;
++
+ 		// This code was yoinked straight from OscarContact::slotSendMsg()
+ 		// If only that slot wasn't private, but I'm not gonna change it right now.
+ 		Oscar::Message message;
+ 
+-		message.setText( msg.plainBody() );
++		if ( m_details.hasCap( CAP_UTF8 ) )
++		{
++			message.setText( Oscar::Message::UCS2, msg.plainBody() );
++		}
++		else
++		{
++			QTextCodec* codec = contactCodec();
++			message.setText( Oscar::Message::UserDefined, msg.plainBody(), codec );
++		}
+ 
+ 		message.setTimestamp( msg.timestamp() );
+ 		message.setSender( mAccount->accountId() );
+--- kopete/protocols/oscar/aim/aimaccount.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/aimaccount.cpp	(revision 586398)
+@@ -15,6 +15,7 @@
+ 
+ #include <qdom.h>
+ #include <qfile.h>
++
+ #include <kdebug.h>
+ #include <kconfig.h>
+ #include <kdialogbase.h>
+@@ -29,14 +30,19 @@
+ #include "kopeteuiglobal.h"
+ #include "kopetecontactlist.h"
+ #include "kopetemetacontact.h"
++#include "kopeteprotocol.h"
++#include "kopetechatsessionmanager.h"
++#include "kopeteview.h"
+ #include <kopeteuiglobal.h>
+ 
+ #include "aimprotocol.h"
+ #include "aimaccount.h"
++#include "aimchatsession.h"
+ #include "aimcontact.h"
+ #include "aimuserinfo.h"
+ #include "aimjoinchat.h"
+ #include "oscarmyselfcontact.h"
++#include "oscarvisibilitydialog.h"
+ 
+ #include "oscarutils.h"
+ #include "client.h"
+@@ -74,7 +80,124 @@
+ 	return m_profileString;
+ }
+ 
++Kopete::ChatSession* AIMMyselfContact::manager( Kopete::Contact::CanCreateFlags canCreate,
++                                                Oscar::WORD exchange, const QString& room )
++{
++    kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << endl;
++    Kopete::ContactPtrList chatMembers;
++    chatMembers.append( this );
++    Kopete::ChatSession* genericManager = 0L;
++    genericManager = Kopete::ChatSessionManager::self()->findChatSession( account()->myself(), chatMembers, protocol() );
++    AIMChatSession* session = dynamic_cast<AIMChatSession*>( genericManager );
+ 
++    if ( !session && canCreate == Contact::CanCreate )
++    {
++        session = new AIMChatSession( this, chatMembers, account()->protocol(), exchange, room );
++        session->setEngine( m_acct->engine() );
++
++        connect( session, SIGNAL( messageSent( Kopete::Message&, Kopete::ChatSession* ) ),
++                 this, SLOT( sendMessage( Kopete::Message&, Kopete::ChatSession* ) ) );
++        m_chatRoomSessions.append( session );
++    }
++    return session;
++}
++
++void AIMMyselfContact::chatSessionDestroyed( Kopete::ChatSession* session )
++{
++    m_chatRoomSessions.remove( session );
++}
++
++void AIMMyselfContact::sendMessage( Kopete::Message& message, Kopete::ChatSession* session )
++{
++    kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "sending a message" << endl;
++    //TODO: remove duplication - factor into a message utils class or something
++    Oscar::Message msg;
++    QString s;
++
++    if (message.plainBody().isEmpty()) // no text, do nothing
++        return;
++    //okay, now we need to change the message.escapedBody from real HTML to aimhtml.
++    //looking right now for docs on that "format".
++    //looks like everything except for alignment codes comes in the format of spans
++
++    //font-style:italic -> <i>
++    //font-weight:600 -> <b> (anything > 400 should be <b>, 400 is not bold)
++    //text-decoration:underline -> <u>
++    //font-family: -> <font face="">
++    //font-size:xxpt -> <font ptsize=xx>
++
++    s=message.escapedBody();
++    s.replace ( QRegExp( QString::fromLatin1("<span style=\"([^\"]*)\">([^<]*)</span>")),
++            QString::fromLatin1("<style>\\1;\"\\2</style>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-style:italic;([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<i><style>\\1\\2\"\\3</style></i>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-weight:600;([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<b><style>\\1\\2\"\\3</style></b>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)text-decoration:underline;([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<u><style>\\1\\2\"\\3</style></u>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-family:([^;]*);([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<font face=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)font-size:([^p]*)pt;([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<font ptsize=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)color:([^;]*);([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("<font color=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
++
++    s.replace ( QRegExp( QString::fromLatin1("<style>([^\"]*)\"([^<]*)</style>")),
++                QString::fromLatin1("\\2"));
++
++    //okay now change the <font ptsize="xx"> to <font size="xx">
++
++    //0-9 are size 1
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"\\d\">")),
++                QString::fromLatin1("<font size=\"1\">"));
++    //10-11 are size 2
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[01]\">")),
++                QString::fromLatin1("<font size=\"2\">"));
++    //12-13 are size 3
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[23]\">")),
++                QString::fromLatin1("<font size=\"3\">"));
++    //14-16 are size 4
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"1[456]\">")),
++                QString::fromLatin1("<font size=\"4\">"));
++    //17-22 are size 5
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"(?:1[789]|2[012])\">")),
++                QString::fromLatin1("<font size=\"5\">"));
++    //23-29 are size 6
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"2[3456789]\">")),QString::fromLatin1("<font size=\"6\">"));
++    //30- (and any I missed) are size 7
++    s.replace ( QRegExp ( QString::fromLatin1("<font ptsize=\"[^\"]*\">")),QString::fromLatin1("<font size=\"7\">"));
++
++    kdDebug(14190) << k_funcinfo << "sending "
++        << s << endl;
++
++    msg.setSender( contactId() );
++    msg.setText( Oscar::Message::UserDefined, s, m_acct->defaultCodec() );
++    msg.setTimestamp(message.timestamp());
++    msg.setType(0x03);
++    msg.addProperty( Oscar::Message::ChatRoom );
++
++    AIMChatSession* aimSession = dynamic_cast<AIMChatSession*>( session );
++    if ( !aimSession )
++    {
++        kdWarning(OSCAR_AIM_DEBUG) << "couldn't convert to AIM chat room session!" << endl;
++        session->messageSucceeded();
++        return;
++    }
++    msg.setExchange( aimSession->exchange() );
++    msg.setChatRoom( aimSession->roomName() );
++
++    m_acct->engine()->sendMessage( msg );
++    //session->appendMessage( message );
++    session->messageSucceeded();
++}
++
++
+ AIMAccount::AIMAccount(Kopete::Protocol *parent, QString accountID, const char *name)
+ 	: OscarAccount(parent, accountID, name, false)
+ {
+@@ -87,13 +210,23 @@
+ 	mc->setOwnProfile( profile );
+ 
+     m_joinChatDialog = 0;
++	m_visibilityDialog = 0;
+ 	QObject::connect( Kopete::ContactList::self(),
+ 	                  SIGNAL( globalIdentityChanged( const QString&, const QVariant& ) ),
+ 	                  this,
+-	                  SLOT( globalIdentityChanged( const QString&, const QVariant& ) ) );
++	                  SLOT( slotGlobalIdentityChanged( const QString&, const QVariant& ) ) );
+ 
+-	QObject::connect( engine(), SIGNAL( iconNeedsUploading() ), this,
+-	                  SLOT( sendBuddyIcon() ) );
++    QObject::connect( engine(), SIGNAL( chatRoomConnected( WORD, const QString& ) ),
++                      this, SLOT( connectedToChatRoom( WORD, const QString& ) ) );
++
++    QObject::connect( engine(), SIGNAL( userJoinedChat( Oscar::WORD, const QString&, const QString& ) ),
++                      this, SLOT( userJoinedChat( Oscar::WORD, const QString&, const QString& ) ) );
++
++    QObject::connect( engine(), SIGNAL( userLeftChat( Oscar::WORD, const QString&, const QString& ) ),
++                      this, SLOT( userLeftChat( Oscar::WORD, const QString&, const QString& ) ) );
++
++	QObject::connect( this, SIGNAL( buddyIconChanged() ), this, SLOT( slotBuddyIconChanged() ) );
++
+ }
+ 
+ AIMAccount::~AIMAccount()
+@@ -187,11 +320,20 @@
+ 	mActionMenu->insert( mActionOffline );
+ 	mActionMenu->popupMenu()->insertSeparator();
+ 
+-//    KAction* m_joinChatAction = new KAction( i18n( "Join Chat..." ), QString::null,  0,  this,
+-//                                             SLOT( slotJoinChat() ), mActionMenu, "join_a_chat" );
+-//    mActionMenu->insert( m_joinChatAction );
+-	//mActionMenu->insert( KopeteStdAction::contactInfo( this, SLOT( slotEditInfo() ), mActionMenu, "AIMAccount::mActionEditInfo" ) );
++    KAction* m_joinChatAction = new KAction( i18n( "Join Chat..." ), QString::null,  0,  this,
++                                             SLOT( slotJoinChat() ), mActionMenu, "join_a_chat" );
+ 
++	mActionMenu->insert( new KToggleAction( i18n( "Set Visibility..." ), 0, 0,
++	                                       this, SLOT( slotSetVisiblility() ), this,
++	                                       "AIMAccount::mActionSetVisibility") );
++
++    mActionMenu->insert( m_joinChatAction );
++    
++    KAction* m_editInfoAction = new KAction( i18n( "Edit User Info..." ), "identity", 0,
++                                             this, SLOT( slotEditInfo() ), mActionMenu, "actionEditInfo");
++    
++    mActionMenu->insert( m_editInfoAction );
++
+ 	return mActionMenu;
+ }
+ 
+@@ -235,107 +377,151 @@
+ 
+ void AIMAccount::slotEditInfo()
+ {
++    if ( !isConnected() )
++    {
++        KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
++                            i18n( "Editing your user info is not possible because "
++                                  "you are not connected." ),
++                            i18n( "Unable to edit user info" ) );
++        return;
++    }
+ 	AIMUserInfoDialog *myInfo = new AIMUserInfoDialog(static_cast<AIMContact *>( myself() ), this, true, 0L, "myInfo");
+ 	myInfo->exec(); // This is a modal dialog
+ }
+ 
+-void AIMAccount::globalIdentityChanged( const QString& key, const QVariant& value )
++void AIMAccount::slotGlobalIdentityChanged( const QString& key, const QVariant& value )
+ {
+ 	//do something with the photo
+ 	kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Global identity changed" << endl;
+ 	kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "key: " << key << endl;
+ 	kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "value: " << value << endl;
+-	if ( key == Kopete::Global::Properties::self()->nickName().key() )
++	
++	if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
+ 	{
+-		//edit ssi item to change alias (if possible)
++		if ( key == Kopete::Global::Properties::self()->nickName().key() )
++		{
++			//edit ssi item to change alias (if possible)
++		}
++	
++		if ( key == Kopete::Global::Properties::self()->photo().key() )
++		{
++			setBuddyIcon( value.toString() );
++		}
+ 	}
++}
+ 
+-	if ( key == Kopete::Global::Properties::self()->photo().key() )
++void AIMAccount::slotBuddyIconChanged()
++{
++	// need to disconnect because we could end up with many connections
++	QObject::disconnect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
++	if ( !engine()->isActive() )
+ 	{
+-		//yay for brain damage. since i have no way to access the global
+-		//properties outside of this slot, i've got to set them somewhere
+-		//else so i can get at them later.
+-		myself()->setProperty( Kopete::Global::Properties::self()->photo(), value.toString() );
+-
+-		//generate a new icon hash
+-		//photo is a url, gotta load it first.
+-		QFile iconFile( value.toString() );
++		QObject::connect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
++		return;
++	}
++	
++	QString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
++	
++	SSIManager* ssi = engine()->ssiManager();
++	Oscar::SSI item = ssi->findItemForIconByRef( 1 );
++	
++	if ( photoPath.isEmpty() )
++	{
++		if ( item )
++		{
++			kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Removing icon hash item from ssi" << endl;
++			Oscar::SSI s(item);
++			
++			//remove hash and alias
++			QValueList<TLV> tList( item.tlvList() );
++			TLV t = Oscar::findTLV( tList, 0x00D5 );
++			if ( t )
++				tList.remove( t );
++			
++			item.setTLVList( tList );
++			//s is old, item is new. modification will occur
++			engine()->modifySSIItem( s, item );
++		}
++	}
++	else
++	{
++		QFile iconFile( photoPath );
+ 		iconFile.open( IO_ReadOnly );
+-		kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "hashing global identity image" << endl;
++		
+ 		KMD5 iconHash;
+ 		iconHash.update( iconFile );
+ 		kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo  << "hash is :" << iconHash.hexDigest() << endl;
++			
+ 		//find old item, create updated item
+-		if ( engine()->isActive() )
++		if ( !item )
+ 		{
+-			SSIManager* ssi = engine()->ssiManager();
+-			Oscar::SSI item = ssi->findItemForIconByRef( 1 );
+-
+-			if ( !item )
+-			{
+-				kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "no existing icon hash item in ssi. creating new"
+-					<< endl;
+-				TLV t;
++			kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "no existing icon hash item in ssi. creating new" << endl;
++			
++			TLV t;
++			t.type = 0x00D5;
++			t.data.resize( 18 );
++			t.data[0] = 0x00;
++			t.data[1] = 0x10;
++			memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
++			t.length = t.data.size();
++			
++			QValueList<Oscar::TLV> list;
++			list.append( t );
++			
++			Oscar::SSI s( "1", 0, ssi->nextContactId(), ROSTER_BUDDYICONS, list );
++			
++			//item is a non-valid ssi item, so the function will add an item
++			kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "setting new icon item" << endl;
++			engine()->modifySSIItem( item, s );
++		}
++		else
++		{ //found an item
++			Oscar::SSI s(item);
++			kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "modifying old item in ssi." << endl;
++			QValueList<TLV> tList( item.tlvList() );
++			
++			TLV t = Oscar::findTLV( tList, 0x00D5 );
++			if ( t )
++				tList.remove( t );
++			else
+ 				t.type = 0x00D5;
+-				t.data.resize( 18 );
+-				t.data[0] = 0x00;
+-				t.data[1] = 0x10;
+-				memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
+-				t.length = t.data.size();
+-
+-				QValueList<Oscar::TLV> list;
+-				list.append( t );
+-
+-				Oscar::SSI s( "1", 0, ssi->nextContactId(), ROSTER_BUDDYICONS, list );
+-
+-				//item is a non-valid ssi item, so the function will add an item
+-				kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "setting new icon item" << endl;
+-				engine()->modifySSIItem( item, s );
+-			}
+-			else
+-			{ //found an item
+-				Oscar::SSI s(item);
+-				kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "modifying old item in ssi."
+-					<< endl;
+-				QValueList<TLV> tList( item.tlvList() );
+-				TLV t = Oscar::findTLV( tList, 0x00D5 );
+-				if ( !t )
+-					return;
+-				tList.remove( t );
+-				t.data.resize( 18 );
+-				t.data[0] = 0x00;
+-				t.data[1] = 0x10;
+-				memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
+-				t.length = t.data.size();
+-				tList.append( t );
+-				item.setTLVList( tList );
+-				//s is old, item is new. modification will occur
+-				engine()->modifySSIItem( s, item );
+-			}
++				
++			t.data.resize( 18 );
++			t.data[0] = 0x00;
++			t.data[1] = 0x10;
++			memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
++			t.length = t.data.size();
++			tList.append( t );
++			
++			item.setTLVList( tList );
++			//s is old, item is new. modification will occur
++			engine()->modifySSIItem( s, item );
+ 		}
+ 		iconFile.close();
+ 	}
+ }
+ 
+-
+-void AIMAccount::sendBuddyIcon()
++void AIMAccount::slotJoinChat()
+ {
+-	QString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
+-	kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << photoPath << endl;
+-	QFile iconFile( photoPath );
+-	iconFile.open( IO_ReadOnly );
+-	QByteArray imageData = iconFile.readAll();
+-	engine()->sendBuddyIcon( imageData );
+-}
++	if ( !isConnected() )
++	{
++		KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
++		                    i18n( "Joining an AIM chat room is not possible because "
++		                          "you are not connected." ),
++		                    i18n( "Unable to Join AIM Chat Room" ) );
++		return;
++	}
+ 
+-void AIMAccount::slotJoinChat()
+-{
+     //get the exchange info
+     //create the dialog
+     //join the chat room
+     if ( !m_joinChatDialog )
+     {
+         m_joinChatDialog = new AIMJoinChatUI( this, false, Kopete::UI::Global::mainWidget() );
++	    QObject::connect( m_joinChatDialog, SIGNAL( closing( int ) ),
++	                      this, SLOT( joinChatDialogClosed( int ) ) );
++        QValueList<int> list = engine()->chatExchangeList();
++        m_joinChatDialog->setExchangeList( list );
+         m_joinChatDialog->show();
+     }
+     else
+@@ -367,16 +553,42 @@
+ 	setAway(true, message);
+ }
+ 
+-void AIMAccount::joinChatDialogClosed()
++void AIMAccount::joinChatDialogClosed( int code )
+ {
++    if ( code == QDialog::Accepted )
++    {
++        //join the chat
++	    kdDebug(14152) << k_funcinfo << "chat accepted." << endl;
++	    engine()->joinChatRoom( m_joinChatDialog->roomName(),
++	                            m_joinChatDialog->exchange().toInt() );
++    }
++
+     m_joinChatDialog->delayedDestruct();
+     m_joinChatDialog = 0L;
+ }
+ 
++void AIMAccount::loginActions()
++{
++	OscarAccount::loginActions();
++
++	using namespace AIM::PrivacySettings;
++	int privacySetting = this->configGroup()->readNumEntry( "PrivacySetting", AllowAll );
++	this->setPrivacySettings( privacySetting );
++}
++
+ void AIMAccount::disconnected( DisconnectReason reason )
+ {
+ 	kdDebug( OSCAR_AIM_DEBUG ) << k_funcinfo << "Attempting to set status offline" << endl;
+ 	myself()->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOffline );
++
++	QDictIterator<Kopete::Contact> it( contacts() );
++	for( ; it.current(); ++it )
++	{
++		OscarContact* oc = dynamic_cast<OscarContact*>( it.current() );
++		if ( oc )
++			oc->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOffline );
++	}
++
+ 	OscarAccount::disconnected( reason );
+ }
+ 
+@@ -384,38 +596,161 @@
+ {
+ 	kdDebug(14152) << k_funcinfo << " Got a message, calling OscarAccount::messageReceived" << endl;
+ 	// Want to call the parent to do everything else
+-	OscarAccount::messageReceived(message);
++    if ( message.type() != 0x0003 )
++    {
++        OscarAccount::messageReceived(message);
+ 
+-	// Check to see if our status is away, and send an away message
+-	// Might be duplicate code from the parent class to get some needed information
+-	// Perhaps a refactoring is needed.
+-	kdDebug(14152) << k_funcinfo << "Checking to see if I'm online.." << endl;
+-	if( myself()->onlineStatus().status() == Kopete::OnlineStatus::Away )
+-	{
+-		QString sender = Oscar::normalize( message.sender() );
+-		AIMContact* aimSender = static_cast<AIMContact *> ( contacts()[sender] ); //should exist now
+-		if ( !aimSender )
+-		{
+-			kdWarning(OSCAR_RAW_DEBUG) << "For some reason, could not get the contact "
+-				<< "That this message is from: " << message.sender() << ", Discarding message" << endl;
+-			return;
+-		}
+-		// Create, or get, a chat session with the contact
+-		Kopete::ChatSession* chatSession = aimSender->manager( Kopete::Contact::CanCreate );
++        // Check to see if our status is away, and send an away message
++        // Might be duplicate code from the parent class to get some needed information
++        // Perhaps a refactoring is needed.
++        kdDebug(14152) << k_funcinfo << "Checking to see if I'm online.." << endl;
++        if( myself()->onlineStatus().status() == Kopete::OnlineStatus::Away )
++        {
++            QString sender = Oscar::normalize( message.sender() );
++            AIMContact* aimSender = static_cast<AIMContact *> ( contacts()[sender] ); //should exist now
++            if ( !aimSender )
++            {
++                kdWarning(OSCAR_RAW_DEBUG) << "For some reason, could not get the contact "
++                                           << "That this message is from: " << message.sender() << ", Discarding message" << endl;
++                return;
++            }
++            // Create, or get, a chat session with the contact
++            Kopete::ChatSession* chatSession = aimSender->manager( Kopete::Contact::CanCreate );
+ 
+-		// get the away message we have set
+-		AIMMyselfContact* myContact = static_cast<AIMMyselfContact *> ( myself() );
+-		QString msg = myContact->lastAwayMessage();
+-		kdDebug(14152) << k_funcinfo << "Got away message: " << msg << endl;
+-		// Create the message
+-		Kopete::Message chatMessage( myself(), aimSender, msg, Kopete::Message::Outbound,
+-		                             Kopete::Message::RichText );
+-		kdDebug(14152) << k_funcinfo << "Sending autoresponse" << endl;
+-		// Send the message
+-		aimSender->sendAutoResponse( chatMessage );
+-	}
++            // get the away message we have set
++            AIMMyselfContact* myContact = static_cast<AIMMyselfContact *> ( myself() );
++            QString msg = myContact->lastAwayMessage();
++            kdDebug(14152) << k_funcinfo << "Got away message: " << msg << endl;
++            // Create the message
++            Kopete::Message chatMessage( myself(), aimSender, msg, Kopete::Message::Outbound,
++                                         Kopete::Message::RichText );
++            kdDebug(14152) << k_funcinfo << "Sending autoresponse" << endl;
++            // Send the message
++            aimSender->sendAutoResponse( chatMessage );
++        }
++    }
++
++    if ( message.type() == 0x0003 )
++    {
++        kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "have chat message" << endl;
++        //handle chat room messages seperately
++        QValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
++        QValueList<Kopete::ChatSession*>::iterator it,  itEnd = chats.end();
++        for ( it = chats.begin(); it != itEnd; ++it )
++        {
++            Kopete::ChatSession* kcs = ( *it );
++            AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
++            if ( !session )
++                continue;
++
++            if ( session->exchange() == message.exchange() &&
++                 Oscar::normalize( session->roomName() ) ==
++                 Oscar::normalize( message.chatRoom() ) )
++            {
++                kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "found chat session for chat room" << endl;
++                Kopete::Contact* ocSender = contacts()[Oscar::normalize( message.sender() )];
++                //sanitize;
++                QString sanitizedMsg = sanitizedMessage( message.text( defaultCodec() ) );
++
++                Kopete::ContactPtrList me;
++                me.append( myself() );
++                Kopete::Message chatMessage( message.timestamp(), ocSender, me, sanitizedMsg,
++                                             Kopete::Message::Inbound, Kopete::Message::RichText );
++
++                session->appendMessage( chatMessage );
++            }
++        }
++    }
+ }
+ 
++void AIMAccount::connectedToChatRoom( WORD exchange, const QString& room )
++{
++    kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Creating chat room session" << endl;
++    Kopete::ContactPtrList emptyList;
++    AIMMyselfContact* me = static_cast<AIMMyselfContact*>( myself() );
++    AIMChatSession* session = dynamic_cast<AIMChatSession*>( me->manager( Kopete::Contact::CanCreate,
++                                                                          exchange, room ) );
++    session->setDisplayName( room );
++    if ( session->view( true ) )
++        session->raiseView();
++}
++
++void AIMAccount::userJoinedChat( WORD exchange, const QString& room, const QString& contact )
++{
++    if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
++        return;
++
++    kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "user " << contact << " has joined the chat" << endl;
++    QValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
++    QValueList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
++    for ( it = chats.begin(); it != itEnd; ++it )
++    {
++        Kopete::ChatSession* kcs = ( *it );
++        AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
++        if ( !session )
++            continue;
++
++        kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << session->exchange() << " " << exchange << endl;
++        kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << session->roomName() << " " << room << endl;
++        if ( session->exchange() == exchange && session->roomName() == room )
++        {
++            kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "found correct chat session" << endl;
++            Kopete::Contact* c;
++            if ( contacts()[Oscar::normalize( contact )] )
++                c = contacts()[Oscar::normalize( contact )];
++            else
++            {
++                Kopete::MetaContact* mc = addContact( Oscar::normalize( contact ),
++                                                      contact, 0, Kopete::Account::Temporary );
++                if ( !mc )
++                    kdWarning(OSCAR_AIM_DEBUG) << "Unable to add contact for chat room" << endl;
++
++                c = mc->contacts().first();
++                c->setNickName( contact );
++            }
++
++            kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "adding contact" << endl;
++            session->addContact( c, static_cast<AIMProtocol*>( protocol() )->statusOnline, true /* suppress */ );
++        }
++    }
++}
++
++void AIMAccount::userLeftChat( WORD exchange, const QString& room, const QString& contact )
++{
++    if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
++        return;
++
++    QValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
++    QValueList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
++    for ( it = chats.begin(); it != itEnd; ++it )
++    {
++        Kopete::ChatSession* kcs = ( *it );
++        AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
++        if ( !session )
++            continue;
++
++        if ( session->exchange() == exchange && session->roomName() == room )
++        {
++            //delete temp contact
++            Kopete::Contact* c = contacts()[Oscar::normalize( contact )];
++            if ( !c )
++            {
++                kdWarning(OSCAR_AIM_DEBUG) << k_funcinfo << "couldn't find the contact that's left the chat!" << endl;
++                continue;
++            }
++            session->removeContact( c );
++            Kopete::MetaContact* mc = c->metaContact();
++            if ( mc->isTemporary() )
++            {
++                mc->removeContact( c );
++                delete c;
++                delete mc;
++            }
++        }
++    }
++}
++
++
+ void AIMAccount::connectWithPassword( const QString & )
+ {
+ 	kdDebug(14152) << k_funcinfo << "accountId='" << accountId() << "'" << endl;
+@@ -437,11 +772,151 @@
+ 	else if ( myself()->onlineStatus() == static_cast<AIMProtocol*>( protocol() )->statusOffline )
+ 	{
+ 		kdDebug(14152) << k_funcinfo << "Logging in as " << accountId() << endl ;
++		updateVersionUpdaterStamp();
+ 		engine()->start( server, port, accountId(), _password );
+ 		engine()->connectToServer( c, server, true /* doAuth */ );
+ 		myself()->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusConnecting );
+ 	}
+ }
+ 
++void AIMAccount::slotSetVisiblility()
++{
++	if( !isConnected() )
++	{
++		KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
++		                    i18n("You must be online to set users visibility."),
++		                    i18n("ICQ Plugin") );
++		return;
++	}
++	
++	if ( !m_visibilityDialog )
++	{
++		m_visibilityDialog = new OscarVisibilityDialog( engine(), Kopete::UI::Global::mainWidget() );
++		QObject::connect( m_visibilityDialog, SIGNAL( closing() ),
++		                  this, SLOT( slotVisibilityDialogClosed() ) );
++		
++		//add all contacts;
++		OscarVisibilityDialog::ContactMap contactMap;
++		QMap<QString, QString> revContactMap;
++	
++		QValueList<Oscar::SSI> contactList = engine()->ssiManager()->contactList();
++		QValueList<Oscar::SSI>::const_iterator it, cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++		{
++			QString contactId = ( *it ).name();
++			
++			OscarContact* oc = dynamic_cast<OscarContact*>( contacts()[( *it ).name()] );
++			if ( oc )
++			{
++				contactMap.insert( oc->nickName(), contactId );
++				revContactMap.insert( contactId, oc->nickName() );
++			}
++			else
++			{
++				contactMap.insert( contactId, contactId );
++				revContactMap.insert( contactId, contactId );
++			}
++		}
++		m_visibilityDialog->addContacts( contactMap );
++		
++		//add contacts from visible list
++		QStringList tmpList;
++		
++		contactList = engine()->ssiManager()->visibleList();
++		cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++			tmpList.append( revContactMap[( *it ).name()] );
++		
++		m_visibilityDialog->addVisibleContacts( tmpList );
++		
++		//add contacts from invisible list
++		tmpList.clear();
++		
++		contactList = engine()->ssiManager()->invisibleList();
++		cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++			tmpList.append( revContactMap[( *it ).name()] );
++		
++		m_visibilityDialog->addInvisibleContacts( tmpList );
++		
++		m_visibilityDialog->resize( 550, 350 );
++		m_visibilityDialog->show();
++	}
++	else
++	{
++		m_visibilityDialog->raise();
++	}
++}
++
++void AIMAccount::slotVisibilityDialogClosed()
++{
++	m_visibilityDialog->delayedDestruct();
++	m_visibilityDialog = 0L;
++}
++
++void AIMAccount::setPrivacySettings( int privacy )
++{
++	using namespace AIM::PrivacySettings;
++
++	BYTE privacyByte = 0x01;
++	DWORD userClasses = 0xFFFFFFFF;
++
++	switch ( privacy )
++	{
++	case AllowAll:
++		privacyByte = 0x01;
++		break;
++	case BlockAll:
++		privacyByte = 0x02;
++		break;
++	case AllowPremitList:
++		privacyByte = 0x03;
++		break;
++	case BlockDenyList:
++		privacyByte = 0x04;
++		break;
++	case AllowMyContacts:
++		privacyByte = 0x05;
++		break;
++	case BlockAIM:
++		privacyByte = 0x01;
++		userClasses = 0x00000004;
++		break;
++	}
++
++	this->setPrivacyTLVs( privacyByte, userClasses );
++}
++
++void AIMAccount::setPrivacyTLVs( BYTE privacy, DWORD userClasses )
++{
++	SSIManager* ssi = engine()->ssiManager();
++	Oscar::SSI item = ssi->findItem( QString::null, ROSTER_VISIBILITY );
++
++	QValueList<Oscar::TLV> tList;
++
++	tList.append( TLV( 0x00CA, 1, (char *)&privacy ) );
++	tList.append( TLV( 0x00CB, sizeof(userClasses), (char *)&userClasses ) );
++
++	if ( !item )
++	{
++		kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Adding new privacy TLV item" << endl;
++		Oscar::SSI s( QString::null, 0, ssi->nextContactId(), ROSTER_VISIBILITY, tList );
++		engine()->modifySSIItem( item, s );
++	}
++	else
++	{ //found an item
++		Oscar::SSI s(item);
++
++		if ( Oscar::uptateTLVs( s, tList ) == true )
++		{
++			kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Updating privacy TLV item" << endl;
++			engine()->modifySSIItem( item, s );
++		}
++	}
++}
++
+ #include "aimaccount.moc"
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/aim/aimjoinchat.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/aimjoinchat.cpp	(revision 586398)
+@@ -19,20 +19,20 @@
+ 
+ #include "aimjoinchat.h"
+ 
++#include <qlineedit.h>
++#include <qcombobox.h>
+ #include <klocale.h>
+ 
+ #include "aimjoinchatbase.h"
+ #include "aimaccount.h"
+ 
+-
+-
+-
+ AIMJoinChatUI::AIMJoinChatUI( AIMAccount* account,  bool modal,
+                               QWidget* parent, const char* name )
+     : KDialogBase( parent, name, modal, i18n( "Join AIM Chat Room" ),
+                    Cancel | User1, User1, true, i18n( "Join" ) )
+ {
+-    kdDebug(14200) << k_funcinfo << "Account " << account->accountId()
++
++    kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Account " << account->accountId()
+                    << " joining a chat room" << endl;
+ 
+     m_account = account;
+@@ -43,25 +43,52 @@
+ 
+     QObject::connect( this, SIGNAL( user1Clicked() ), this, SLOT( joinChat() ) );
+     QObject::connect( this, SIGNAL( cancelClicked() ), this, SLOT( closeClicked() ) );
+-
+-
+-    //add exchanges to the spin box
+ }
+ 
+ AIMJoinChatUI::~AIMJoinChatUI()
+ {
++    m_exchanges.clear();
++}
+ 
++void AIMJoinChatUI::setExchangeList( const QValueList<int>& list )
++{
++    m_exchanges = list;
++    QStringList exchangeList;
++    QValueList<int>::const_iterator it = list.begin();
++    while ( it != list.end() )
++    {
++        exchangeList.append( QString::number( ( *it ) ) );
++        ++it;
++    }
++
++
++    m_joinUI->exchange->insertStringList( exchangeList );
+ }
+ 
+ void AIMJoinChatUI::joinChat()
+ {
+-    //join a chat room
++    m_roomName = m_joinUI->roomName->text();
++    int item = m_joinUI->exchange->currentItem();
++    m_exchange = m_joinUI->exchange->text( item );
++
++    emit closing( QDialog::Accepted );
+ }
+ 
+ void AIMJoinChatUI::closeClicked()
+ {
+     //hmm, do nothing?
+-    emit closing();
++    emit closing( QDialog::Rejected );
+ }
+ 
++QString AIMJoinChatUI::roomName() const
++{
++    return m_roomName;
++}
++
++QString AIMJoinChatUI::exchange() const
++{
++    return m_exchange;
++}
++
+ #include "aimjoinchat.moc"
++//kate: space-indent on; indent-width 4;
+--- kopete/protocols/oscar/aim/aimcontact.h	(revision 568672)
++++ kopete/protocols/oscar/aim/aimcontact.h	(revision 586398)
+@@ -83,14 +83,20 @@
+ 	void closeUserInfoDialog();
+ 	void warnUser();
+ 
++	void slotVisibleTo();
++	void slotInvisibleTo();
++
+ private:
+ 	AIMProtocol* mProtocol;
+ 	AIMUserInfoDialog* m_infoDialog;
+ 	QString mUserProfile;
+ 	bool m_haveAwayMessage;
++	bool m_mobile; // Is this user mobile (i.e. do they have message forwarding on, or mobile AIM)
+ 	QDateTime m_lastAutoresponseTime;
+ 	
+ 	KAction* m_warnUserAction;
++	KToggleAction *m_actionVisibleTo;
++	KToggleAction *m_actionInvisibleTo;
+ };
+ #endif 
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/aim/aimprotocol.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/aimprotocol.cpp	(revision 586398)
+@@ -15,7 +15,7 @@
+   *************************************************************************
+   */
+ 
+-
++#include <qstringlist.h>
+ #include <kgenericfactory.h>
+ #include <kdebug.h>
+ 
+@@ -30,6 +30,7 @@
+ #include "kopeteonlinestatusmanager.h"
+ #include "kopeteglobal.h"
+ #include "kopeteuiglobal.h"
++#include "kopetemetacontact.h"
+ 
+ #include <kdialogbase.h>
+ #include <kmessagebox.h>
+@@ -69,84 +70,149 @@
+  * aim:RegisterUser?ScreenName=sn&Password=pw&SignonNow=False
+  * Away Message  ===================================================
+  * aim:goaway?message=brb+or+something
++ * Chat Rooms  =====================================================
++ * aim:GoChat?RoomName=room+name&Exchange=number
+  **/
+ 
+ 	AIMProtocol *proto = AIMProtocol::protocol();
+ 	kdDebug(14152) << k_funcinfo << "URL url   : '" << url.url() << "'" << endl;
++	kdDebug(14152) << k_funcinfo << "URL path  : '" << url.path() << "'" << endl;
+ 	QString command = url.path();
+-
+-	if (command.startsWith("goim") || command.startsWith("addbuddy"))
++	QString realCommand, firstParam, secondParam;
++	bool needContactAddition = false;
++	if ( command.find( "goim", 0, false ) != -1 )
+ 	{
+-		if (command.startsWith("goim"))
+-			command.remove(0,4);
+-		else
+-			command.remove(0,8);
+-
+-		if (!command.startsWith("?screenname="))
++		realCommand = "goim";
++		kdDebug(14152) << k_funcinfo << "Handling send IM request" << endl;
++		command.remove(0,4);
++		if ( command.find( "?screenname=", 0, false ) == -1 )
+ 		{
+-			kdWarning(14152) << "Unhandled aim URI : " << url.url() << endl;
++		kdWarning(14152) << k_funcinfo << "Unhandled AIM URI:" << url.url() << endl;
+ 			return;
+ 		}
++		command.remove( 0, 12 );
++		int andSign = command.find( "&" );
++		if ( andSign > 0 )
++			command = command.left( andSign );
+ 
+-		command.remove(0, 12);
+-
+-		int andSign = command.find("&");
+-		if (andSign > 0) // strip off anything else for now
+-			command = command.left(andSign);
+-		command.replace("+", " ");
+-
+-		QString screenname = command;
+-
+-		Kopete::Account *account = 0;
+-		QDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts(proto);
+-		// do not show chooser if we only have one account to "choose" from
+-		if (accounts.count() == 1)
++		firstParam = command;
++		firstParam.replace( "+", " " );
++		needContactAddition = true;
++	}
++	else
++		if ( command.find( "addbuddy", 0, false ) != -1 )
+ 		{
+-			QDictIterator<Kopete::Account> it(accounts);
+-			account = it.current();
+-
+-			if (KMessageBox::questionYesNo(Kopete::UI::Global::mainWidget(),
+-				i18n("Do you want to add '%1' to your contact list?").arg(command), QString::null, i18n("Add"), i18n("Do Not Add"))
+-				!= KMessageBox::Yes)
++			realCommand = "addbuddy";
++			kdDebug(14152) << k_funcinfo << "Handling AIM add buddy request" << endl;
++			command.remove( 0, 8 );
++			if ( command.find( "?screenname=", 0, false ) == -1 )
+ 			{
+-				kdDebug(14152) << k_funcinfo << "Cancelled" << endl;
++			kdWarning(14152) << k_funcinfo << "Unhandled AIM URI:" << url.url() << endl;
+ 				return;
+ 			}
++			
++			command.remove(0, 12);
++			int andSign = command.find("&");
++			if ( andSign > 0 )
++				command = command.left(andSign);
++			command.replace("+", " ");
++			
++			firstParam = command;
++			needContactAddition = true;
+ 		}
+-		else
++	else
++	if ( command.find( "gochat", 0, false ) != -1 )
++	{
++		realCommand = "gochat";
++		kdDebug(14152) << k_funcinfo << "Handling AIM chat room request" << endl;
++		command.remove( 0, 6 );
++		
++		if ( command.find( "?RoomName=", 0, false ) == -1 )
+ 		{
+-			KDialogBase *chooser = new KDialogBase(0, "chooser", true,
+-				i18n("Choose Account"), KDialogBase::Ok|KDialogBase::Cancel,
+-				KDialogBase::Ok, false);
+-			AccountSelector *accSelector = new AccountSelector(proto, chooser,
+-				"accSelector");
+-			chooser->setMainWidget(accSelector);
+-
+-			int ret = chooser->exec();
+-			Kopete::Account *account = accSelector->selectedItem();
+-
+-			delete chooser;
+-			if (ret == QDialog::Rejected || account == 0)
+-			{
+-				kdDebug(14152) << k_funcinfo << "Cancelled" << endl;
+-				return;
+-			}
++		kdWarning(14152) << "Unhandled AIM URI: " << url.url() << endl;
++			return;
+ 		}
+-
+-
+-		kdDebug(14152) << k_funcinfo <<
+-			"Adding Contact; screenname = " << screenname << endl;
+-		if ( account->addContact(screenname, command, 0L, Kopete::Account::Temporary) )
++		
++		command.remove( 0, 10 );
++		
++		int andSign = command.find("&");
++		if (andSign > 0) // strip off anything else for now
+ 		{
+-			//Kopete::Contact *contact = account->contacts()[screenname];
++			firstParam = command.left(andSign);
+ 		}
+-
+-
++		command.remove( 0, andSign );
++		kdDebug(14152) << "command is now: " << command << endl;
++		command.remove( 0, 10 ); //remove "&Exchange="
++		secondParam = command;
++		kdDebug(14152) << k_funcinfo << firstParam << " " << secondParam << endl;
++		firstParam.replace("+", " ");
+ 	}
++	
++	Kopete::Account *account = 0;
++	QDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts(proto);
++	
++	if (accounts.count() == 1)
++	{
++		QDictIterator<Kopete::Account> it(accounts);
++		account = it.current();
++		
++	}
+ 	else
+ 	{
+-		kdWarning(14152) << "Unhandled aim URI : " << url.url() << endl;
++		KDialogBase *chooser = new KDialogBase(0, "chooser", true,
++		                                       i18n("Choose Account"), KDialogBase::Ok|KDialogBase::Cancel,
++		                                       KDialogBase::Ok, false);
++		AccountSelector *accSelector = new AccountSelector(proto, chooser, "accSelector");
++		chooser->setMainWidget(accSelector);
++		
++		int ret = chooser->exec();
++		Kopete::Account *account = accSelector->selectedItem();
++		
++		delete chooser;
++		if (ret == QDialog::Rejected || account == 0)
++		{
++			kdDebug(14152) << k_funcinfo << "Cancelled" << endl;
++			return;
++		}
+ 	}
++	
++	Kopete::MetaContact* mc = 0;
++	if ( needContactAddition || realCommand == "addbuddy" )
++	{
++		if (KMessageBox::questionYesNo(Kopete::UI::Global::mainWidget(),
++		                               i18n("Do you want to add '%1' to your contact list?").arg(command),
++		                               QString::null, i18n("Add"), i18n("Do Not Add"))
++		    != KMessageBox::Yes)
++		{
++			kdDebug(14152) << k_funcinfo << "Cancelled" << endl;
++			return;
++		}
++		
++		kdDebug(14152) << k_funcinfo <<
++			"Adding Contact; screenname = " << firstParam << endl;
++		mc = account->addContact(firstParam, command, 0L, Kopete::Account::Temporary);
++	}
++
++	if ( realCommand == "gochat" )
++	{
++		AIMAccount* aimAccount = dynamic_cast<AIMAccount*>( account );
++		if ( aimAccount && aimAccount->isConnected() )
++		{
++			aimAccount->engine()->joinChatRoom( firstParam, secondParam.toInt() );
++		}
++		else
++			KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
++			                    i18n( "Unable to connect to the chat room %1 because the account"
++			                          " for %2 is not connected." ).arg( firstParam ).arg( aimAccount->accountId() ),
++			                    QString::null );
++		
++	}
++
++	if ( realCommand == "goim" )
++	{
++		mc->execute();
++	}
++	
+ }
+ 
+ 
+@@ -154,10 +220,14 @@
+ 
+ AIMProtocol::AIMProtocol(QObject *parent, const char *name, const QStringList &)
+   : Kopete::Protocol( AIMProtocolFactory::instance(), parent, name ),
+-	statusOnline( Kopete::OnlineStatus::Online, 1, this, 0, QString::null, i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online ),
+-	statusOffline( Kopete::OnlineStatus::Offline, 1, this, 10, QString::null, i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline ),
+-	statusAway( Kopete::OnlineStatus::Away, 1, this, 20, "contact_away_overlay", i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away, 
++	statusOnline( Kopete::OnlineStatus::Online, 2, this, 0, QString::null, i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online ),
++	statusOffline( Kopete::OnlineStatus::Offline, 2, this, 10, QString::null, i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline ),
++	statusAway( Kopete::OnlineStatus::Away, 2, this, 20, "contact_away_overlay", i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away,
+ 							Kopete::OnlineStatusManager::HasAwayMessage ),
++	statusWirelessOnline( Kopete::OnlineStatus::Online, 1, this, 30, "contact_phone_overlay", i18n("Mobile"), i18n("Mobile"),
++	Kopete::OnlineStatusManager::Online, Kopete::OnlineStatusManager::HideFromMenu ),
++	statusWirelessAway( Kopete::OnlineStatus::Away, 1, this, 31, QStringList::split( " ", "contact_phone_overlay contact_away_overlay"),
++	i18n("Mobile Away"), i18n("Mobile Away"), Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HideFromMenu ),
+ 	statusConnecting(Kopete::OnlineStatus::Connecting, 99, this, 99, "aim_connecting", i18n("Connecting...")),
+ 	awayMessage(Kopete::Global::Properties::self()->awayMessage()),
+ 	clientFeatures("clientFeatures", i18n("Client Features"), 0, false),
+@@ -214,10 +284,10 @@
+ 		ssiBid = serializedData["ssi_bid"].toUInt();
+ 		ssiType = serializedData["ssi_type"].toUInt();
+ 	}
+-	
++
+ 	Oscar::SSI item( ssiName, ssiGid, ssiBid, ssiType, QValueList<TLV>(), 0 );
+ 	item.setWaitingAuth( ssiWaitingAuth );
+-	
++
+ 	AIMContact *c = new AIMContact( account, contactId, metaContact, QString::null, item );
+ 	return c;
+ }
+--- kopete/protocols/oscar/aim/aimaccount.h	(revision 568672)
++++ kopete/protocols/oscar/aim/aimaccount.h	(revision 586398)
+@@ -27,11 +27,19 @@
+ #include "oscaraccount.h"
+ #include "oscarmyselfcontact.h"
+ 
++namespace AIM
++{
++	namespace PrivacySettings
++	{
++		enum { AllowAll = 0, AllowMyContacts, AllowPremitList, BlockAll, BlockAIM, BlockDenyList };
++	}
++}
+ 
+ namespace Kopete
+ {
+ class Contact;
+ class Group;
++class ChatSession;
+ }
+ 
+ class KAction;
+@@ -39,9 +47,12 @@
+ class AIMContact;
+ class AIMAccount;
+ class AIMJoinChatUI;
++class AIMChatSession;
++class OscarVisibilityDialog;
+ 
+ class AIMMyselfContact : public OscarMyselfContact
+ {
++Q_OBJECT
+ public:
+ 	AIMMyselfContact( AIMAccount *acct );
+ 	void userInfoUpdated();
+@@ -50,6 +61,13 @@
+ 	void setLastAwayMessage( const QString& msg) {m_lastAwayMessage = msg;}
+ 	QString lastAwayMessage() { return m_lastAwayMessage; };
+ 
++    virtual Kopete::ChatSession* manager( Kopete::Contact::CanCreateFlags = Kopete::Contact::CannotCreate,
++                                          WORD exchange = 0, const QString& room = QString::null);
++
++public slots:
++    void sendMessage( Kopete::Message&, Kopete::ChatSession* session );
++    void chatSessionDestroyed( Kopete::ChatSession* );
++
+ private:
+ 	QString m_profileString;
+ 	AIMAccount* m_acct;
+@@ -57,7 +75,9 @@
+ 	 * There has GOT to be a better way to get this away message
+ 	 */
+ 	QString m_lastAwayMessage;
++    QValueList<Kopete::ChatSession*> m_chatRoomSessions;
+ 
++
+ };
+ 
+ class AIMAccount : public OscarAccount
+@@ -77,25 +97,34 @@
+ 
+ 	void setUserProfile(const QString &profile);
+ 	
++	void setPrivacySettings( int privacy );
++
+ public slots:
+ 	/** Reimplementation from Kopete::Account */
+ 	void setOnlineStatus( const Kopete::OnlineStatus& status, const QString& reason = QString::null );
+ 	void slotEditInfo();
+ 	void slotGoOnline();
+ 
+-	void globalIdentityChanged( const QString&, const QVariant& );
+-	void sendBuddyIcon();
+-    void slotJoinChat();
++	void slotGlobalIdentityChanged( const QString&, const QVariant& );
++	void slotBuddyIconChanged();
+ 
++	void slotJoinChat();
+ 
+ protected slots:
+ 	void slotGoAway(const QString&);
+-    void joinChatDialogClosed();
++    void joinChatDialogClosed( int );
+ 
++	virtual void loginActions();
+ 	virtual void disconnected( Kopete::Account::DisconnectReason reason );
+-
+ 	virtual void messageReceived( const Oscar::Message& message );
+ 
++    void connectedToChatRoom( WORD exchange, const QString& roomName );
++    void userJoinedChat( Oscar::WORD exchange, const QString& room, const QString& contact );
++    void userLeftChat( Oscar::WORD exchange, const QString& room, const QString& contact );
++
++	void slotSetVisiblility();
++	void slotVisibilityDialogClosed();
++
+ protected:
+ 
+ 	/**
+@@ -107,7 +136,11 @@
+ 	QString sanitizedMessage( const QString& message );
+ 
+ private:
++	// Set privacy tlv item
++	void setPrivacyTLVs( BYTE privacy, DWORD userClasses );
++
+     AIMJoinChatUI* m_joinChatDialog;
++	OscarVisibilityDialog* m_visibilityDialog;
+ };
+ #endif
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/aim/Makefile.am	(revision 568672)
++++ kopete/protocols/oscar/aim/Makefile.am	(revision 586398)
+@@ -8,7 +8,7 @@
+ 
+ kde_module_LTLIBRARIES = kopete_aim.la
+ 
+-kopete_aim_la_SOURCES = aimprotocol.cpp aimaccount.cpp aimcontact.cpp aimuserinfo.cpp aimjoinchat.cpp
++kopete_aim_la_SOURCES = aimprotocol.cpp aimaccount.cpp aimcontact.cpp aimuserinfo.cpp aimjoinchat.cpp aimchatsession.cpp
+ 
+ kopete_aim_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries)
+ kopete_aim_la_LIBADD  = ../libkopete_oscar.la ui/libkopeteaimui.la \
+--- kopete/protocols/oscar/aim/aimjoinchat.h	(revision 568672)
++++ kopete/protocols/oscar/aim/aimjoinchat.h	(revision 586398)
+@@ -22,6 +22,8 @@
+ 
+ #include <kdialogbase.h>
+ 
++#include "oscartypes.h"
++
+ class AIMAccount;
+ class AIMJoinChatBase;
+ 
+@@ -33,17 +35,28 @@
+ 	               const char* name = 0 );
+ 	~AIMJoinChatUI();
+ 
++    void setExchangeList( const QValueList<int>& );
++    QValueList<int> exchangeList() const;
++
++    QString roomName() const;
++    QString exchange() const;
++
++
+ protected slots:
+ 	void joinChat();
+ 	void closeClicked();
+ 
+ signals:
+-	void closing();
++	void closing( int );
+ 
+ private:
+ 	AIMJoinChatBase* m_joinUI;
+ 	AIMAccount* m_account;
++    QValueList<int> m_exchanges;
++    QString m_roomName;
++    QString m_exchange;
+ 
+ };
+ 
+ #endif
++//kate: space-indent on; indent-width 4;
+--- kopete/protocols/oscar/aim/ui/aimeditaccountui.ui	(revision 568672)
++++ kopete/protocols/oscar/aim/ui/aimeditaccountui.ui	(revision 586398)
+@@ -9,7 +9,7 @@
+             <x>0</x>
+             <y>0</y>
+             <width>560</width>
+-            <height>473</height>
++            <height>583</height>
+         </rect>
+     </property>
+     <property name="sizePolicy">
+@@ -53,7 +53,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>B&amp;asic Setup</string>
++                    <string>&amp;Basic Setup</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -66,11 +66,11 @@
+                         <property name="title">
+                             <string>Account Information</string>
+                         </property>
+-                        <vbox>
++                        <grid>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLayoutWidget">
++                            <widget class="QLayoutWidget" row="0" column="0">
+                                 <property name="name">
+                                     <cstring>layout4</cstring>
+                                 </property>
+@@ -83,7 +83,7 @@
+                                             <cstring>lblAccountId</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>&amp;AIM screen name:</string>
++                                            <string>AIM &amp;screen name:</string>
+                                         </property>
+                                         <property name="buddy" stdset="0">
+                                             <cstring>edtAccountId</cstring>
+@@ -108,13 +108,21 @@
+                                     </widget>
+                                 </hbox>
+                             </widget>
+-                            <widget class="Kopete::UI::PasswordWidget">
++                            <widget class="Kopete::UI::PasswordWidget" row="1" column="0">
+                                 <property name="name">
+                                     <cstring>mPasswordWidget</cstring>
+                                 </property>
+                             </widget>
+-                            <widget class="QCheckBox">
++                            <widget class="QCheckBox" row="3" column="0">
+                                 <property name="name">
++                                    <cstring>mGlobalIdentity</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Exclu&amp;de from Global Identity</string>
++                                </property>
++                            </widget>
++                            <widget class="QCheckBox" row="2" column="0">
++                                <property name="name">
+                                     <cstring>mAutoLogon</cstring>
+                                 </property>
+                                 <property name="text">
+@@ -124,7 +132,7 @@
+                                     <string>If you check that case, the account will not be connected when you press the "Connect All" button, or at startup even if you selected to automatically connect at startup</string>
+                                 </property>
+                             </widget>
+-                        </vbox>
++                        </grid>
+                     </widget>
+                     <widget class="QGroupBox">
+                         <property name="name">
+@@ -204,7 +212,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>A&amp;ccount Preferences</string>
++                    <string>Accou&amp;nt Preferences</string>
+                 </attribute>
+                 <grid>
+                     <property name="name">
+@@ -365,6 +373,97 @@
+                     </widget>
+                 </grid>
+             </widget>
++            <widget class="QWidget">
++                <property name="name">
++                    <cstring>tab</cstring>
++                </property>
++                <attribute name="title">
++                    <string>Pri&amp;vacy</string>
++                </attribute>
++                <grid>
++                    <property name="name">
++                        <cstring>unnamed</cstring>
++                    </property>
++                    <widget class="QButtonGroup" row="0" column="0">
++                        <property name="name">
++                            <cstring>buttonGroup1</cstring>
++                        </property>
++                        <property name="title">
++                            <string>Visibility settings</string>
++                        </property>
++                        <grid>
++                            <property name="name">
++                                <cstring>unnamed</cstring>
++                            </property>
++                            <widget class="QRadioButton" row="2" column="0">
++                                <property name="name">
++                                    <cstring>rbAllowPerimtList</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Allow only from visible list</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton" row="0" column="1">
++                                <property name="name">
++                                    <cstring>rbBlockAll</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Block all users</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton" row="1" column="1">
++                                <property name="name">
++                                    <cstring>rbBlockAIM</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Block AIM users</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton" row="2" column="1">
++                                <property name="name">
++                                    <cstring>rbBlockDenyList</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Block only from invisible list</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton" row="0" column="0">
++                                <property name="name">
++                                    <cstring>rbAllowAll</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Allow all users</string>
++                                </property>
++                            </widget>
++                            <widget class="QRadioButton" row="1" column="0">
++                                <property name="name">
++                                    <cstring>rbAllowMyContacts</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Allow only contact list's users</string>
++                                </property>
++                            </widget>
++                        </grid>
++                    </widget>
++                    <spacer row="1" column="0">
++                        <property name="name">
++                            <cstring>spacer3</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Expanding</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>31</width>
++                                <height>225</height>
++                            </size>
++                        </property>
++                    </spacer>
++                </grid>
++            </widget>
+         </widget>
+     </grid>
+ </widget>
+@@ -426,6 +525,16 @@
+     <tabstop>optionOverrideServer</tabstop>
+     <tabstop>edtServerAddress</tabstop>
+     <tabstop>sbxServerPort</tabstop>
++    <tabstop>encodingCombo</tabstop>
++    <tabstop>rbAllowAll</tabstop>
++    <tabstop>rbAllowMyContacts</tabstop>
++    <tabstop>rbAllowPerimtList</tabstop>
++    <tabstop>rbBlockAll</tabstop>
++    <tabstop>rbBlockAIM</tabstop>
++    <tabstop>rbBlockDenyList</tabstop>
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kopetepasswordwidget.h</includehint>
++</includehints>
+ </UI>
+--- kopete/protocols/oscar/aim/ui/Makefile.am	(revision 568672)
++++ kopete/protocols/oscar/aim/ui/Makefile.am	(revision 586398)
+@@ -7,8 +7,8 @@
+ 
+ noinst_LTLIBRARIES = libkopeteaimui.la
+ 
+-libkopeteaimui_la_SOURCES = aimaddcontactui.ui aimeditaccountui.ui aiminfobase.ui aimjoinchatbase.ui \
+-	aimaddcontactpage.cpp aimeditaccountwidget.cpp 
++libkopeteaimui_la_SOURCES = aimaddcontactui.ui aimeditaccountui.ui \
++	aiminfobase.ui aimjoinchatbase.ui aimaddcontactpage.cpp aimeditaccountwidget.cpp
+ 
+ libkopeteaimui_la_LIBADD = $(top_builddir)/kopete/libkopete/libkopete.la
+ 
+--- kopete/protocols/oscar/aim/ui/aimjoinchatbase.ui	(revision 568672)
++++ kopete/protocols/oscar/aim/ui/aimjoinchatbase.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>326</width>
+-            <height>119</height>
++            <width>343</width>
++            <height>99</height>
+         </rect>
+     </property>
+     <grid>
+@@ -83,19 +83,6 @@
+                 <cstring>exchange</cstring>
+             </property>
+         </widget>
+-        <widget class="QSpinBox" row="3" column="2">
+-            <property name="name">
+-                <cstring>exchange</cstring>
+-            </property>
+-            <property name="sizePolicy">
+-                <sizepolicy>
+-                    <hsizetype>4</hsizetype>
+-                    <vsizetype>0</vsizetype>
+-                    <horstretch>0</horstretch>
+-                    <verstretch>0</verstretch>
+-                </sizepolicy>
+-            </property>
+-        </widget>
+         <widget class="QLineEdit" row="2" column="2">
+             <property name="name">
+                 <cstring>roomName</cstring>
+@@ -109,6 +96,11 @@
+                 </sizepolicy>
+             </property>
+         </widget>
++        <widget class="QComboBox" row="3" column="2">
++            <property name="name">
++                <cstring>exchange</cstring>
++            </property>
++        </widget>
+         <spacer row="4" column="2">
+             <property name="name">
+                 <cstring>spacer2</cstring>
+--- kopete/protocols/oscar/aim/ui/aimeditaccountwidget.cpp	(revision 568672)
++++ kopete/protocols/oscar/aim/ui/aimeditaccountwidget.cpp	(revision 586398)
+@@ -4,6 +4,7 @@
+ #include <qlayout.h>
+ #include <qcheckbox.h>
+ #include <qpushbutton.h>
++#include <qradiobutton.h>
+ #include <qlineedit.h>
+ #include <qspinbox.h>
+ 
+@@ -49,6 +50,35 @@
+ 		mGui->edtServerAddress->setText( serverEntry );
+ 		mGui->sbxServerPort->setValue( portEntry );
+ 
++		using namespace AIM::PrivacySettings;
++
++		int privacySetting = mAccount->configGroup()->readNumEntry( "PrivacySetting", AllowAll );
++		switch( privacySetting )
++		{
++			case AllowAll:
++				mGui->rbAllowAll->setChecked( true );
++				break;
++			case AllowMyContacts:
++				mGui->rbAllowMyContacts->setChecked( true );
++				break;
++			case AllowPremitList:
++				mGui->rbAllowPerimtList->setChecked( true );
++				break;
++			case BlockAll:
++				mGui->rbBlockAll->setChecked( true );
++				break;
++			case BlockAIM:
++				mGui->rbBlockAIM->setChecked( true );
++				break;
++			case BlockDenyList:
++				mGui->rbBlockDenyList->setChecked( true );
++				break;
++			default:
++				mGui->rbAllowAll->setChecked( true );
++		}
++
++		// Global Identity
++		mGui->mGlobalIdentity->setChecked( account->configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) );
+     }
+ 	QObject::connect( mGui->buttonRegister, SIGNAL( clicked() ), this, SLOT( slotOpenRegister() ) );
+ 
+@@ -87,6 +117,27 @@
+ 		static_cast<OscarAccount *>( mAccount )->setServerPort( 5190 );
+ 	}
+ 
++	using namespace AIM::PrivacySettings;
++	int privacySetting = AllowAll;
++
++	if ( mGui->rbAllowAll->isChecked() )
++		privacySetting = AllowAll;
++	else if ( mGui->rbAllowMyContacts->isChecked() )
++		privacySetting = AllowMyContacts;
++	else if ( mGui->rbAllowPerimtList->isChecked() )
++		privacySetting = AllowPremitList;
++	else if ( mGui->rbBlockAll->isChecked() )
++		privacySetting = BlockAll;
++	else if ( mGui->rbBlockAIM->isChecked() )
++		privacySetting = BlockAIM;
++	else if ( mGui->rbBlockDenyList->isChecked() )
++		privacySetting = BlockDenyList;
++
++	mAccount->configGroup()->writeEntry( "PrivacySetting", privacySetting );
++	mAccount->setPrivacySettings( privacySetting );
++
++	// Global Identity
++	mAccount->configGroup()->writeEntry( "ExcludeGlobalIdentity", mGui->mGlobalIdentity->isChecked() );
+ 	return mAccount;
+ }
+ 
+--- kopete/protocols/oscar/aim/aimprotocol.h	(revision 568672)
++++ kopete/protocols/oscar/aim/aimprotocol.h	(revision 586398)
+@@ -2,7 +2,7 @@
+  oscarprotocol.h  -  Oscar Protocol Plugin
+ 
+  Copyright (c) 2002 by Tom Linsky <twl6 at po.cwru.edu>
+-
++ Copyright (c) 2005 by Matt Rogers <mattr at kde.org>
+  Kopete    (c) 2002 by the Kopete developers  <kopete-devel at kde.org>
+ 
+  *************************************************************************
+@@ -66,6 +66,8 @@
+ 	const Kopete::OnlineStatus statusOnline;
+ 	const Kopete::OnlineStatus statusOffline;
+ 	const Kopete::OnlineStatus statusAway;
++	const Kopete::OnlineStatus statusWirelessOnline;
++	const Kopete::OnlineStatus statusWirelessAway;
+ 	const Kopete::OnlineStatus statusConnecting;
+ 
+ 	const Kopete::ContactPropertyTmpl awayMessage;
+--- kopete/protocols/oscar/oscarcontact.h	(revision 568672)
++++ kopete/protocols/oscar/oscarcontact.h	(revision 586398)
+@@ -34,6 +34,7 @@
+ 
+ class OscarAccount;
+ class QTimer;
++class QTextCodec;
+ class KToggleAction;
+ 
+ /**
+@@ -81,7 +82,13 @@
+ 	/** we received a typing notification from this contact, tell any message manager */
+ 	void startedTyping();
+ 	void stoppedTyping();
+-	
++
++	/**
++	 * Returns codec for contact's encoding or default one
++	 * if contact has no encoding
++	 */
++	QTextCodec *contactCodec() const;
++
+ public slots:
+ 	/** slot so that properties can be updated based on a new SSI item */
+ 	virtual void updateSSIItem() = 0;
+--- kopete/protocols/oscar/Makefile.am	(revision 568672)
++++ kopete/protocols/oscar/Makefile.am	(revision 586398)
+@@ -8,6 +8,8 @@
+ 
+ libkopete_oscar_la_SOURCES = oscaraccount.cpp oscarcontact.cpp oscarmyselfcontact.cpp \
+ 	oscarencodingselectionbase.ui oscarencodingselectiondialog.cpp \
+-	oscarlistcontactsbase.ui oscarlistnonservercontacts.cpp
++	oscarlistcontactsbase.ui oscarlistnonservercontacts.cpp \
++	oscarvisibilitybase.ui oscarvisibilitydialog.cpp \
++	oscarversionupdater.cpp
+ libkopete_oscar_la_LDFLAGS = -no-undefined -version-info 2:0:0 $(all_libraries)
+ libkopete_oscar_la_LIBADD  = $(LIB_KIO) $(top_builddir)/kopete/libkopete/libkopete.la ./liboscar/liboscar.la
+--- kopete/protocols/oscar/oscaraccount.h	(revision 568672)
++++ kopete/protocols/oscar/oscaraccount.h	(revision 586398)
+@@ -37,6 +37,7 @@
+ class Connection;
+ class OscarContact;
+ class OscarAccountPrivate;
++class QTextCodec;
+ 
+ class KDE_EXPORT OscarAccount : public Kopete::PasswordedAccount
+ {
+@@ -79,6 +80,44 @@
+ 	/** Set the server port */
+ 	void setServerPort( int port );
+ 
++	/** Returns codec for account's default encoding */
++	QTextCodec* defaultCodec() const;
++
++	/**
++	 * Returns codec for given contact's encoding or default one
++	 * if contact has no encoding
++	 */
++	QTextCodec* contactCodec( const OscarContact* contact ) const;
++
++	/**
++	 * Returns codec for given contact's encoding or default one
++	 * if contact has no encoding
++	 */
++	QTextCodec* contactCodec( const QString& contactName ) const;
++
++	/**
++	 * Sets buddy icon
++	 */
++	void setBuddyIcon( KURL url );
++
++	/**
++	 * Add a contact to the server site list
++	 * \param contactName the screen name of the new contact to add
++	 * \param groupName the group of the new contact
++	 * \param autoAddGroup if the group doesn't exist add that group
++	 * \return true if the contact will be added
++	 */
++	bool addContactToSSI( const QString& contactName, const QString& groupName, bool autoAddGroup );
++
++	/**
++	 * Change a contact's group on the server
++	 * \param contact the contact to change
++	 * \param newGroup the new group to move the contact to
++	 * \param autoAddGroup if the new group doesn't exist add that group
++	 * \return true if the contact will be added
++	 */
++	bool changeContactGroupInSSI( const QString& contact, const QString& newGroupName, bool autoAddGroup );
++
+ public slots:
+ 	void slotGoOffline();
+ 
+@@ -107,10 +146,12 @@
+ 
+ 	virtual QString sanitizedMessage( const QString& message ) = 0;
+ 
++	void updateVersionUpdaterStamp();
++
+ protected slots:
+ 
+ 	//! do stuff on login
+-	void loginActions();
++	virtual void loginActions();
+ 
+     void processSSIList();
+ 
+@@ -120,11 +161,11 @@
+ 
+ 	virtual void messageReceived( const Oscar::Message& message );
+ 
+-	void updateContact( Oscar::SSI );
+-
+ 	void ssiGroupAdded( const Oscar::SSI& );
++	void ssiGroupUpdated( const Oscar::SSI& ) {}
+ 	void ssiGroupRemoved( const Oscar::SSI& ) {}
+ 	void ssiContactAdded( const Oscar::SSI& );
++	void ssiContactUpdated( const Oscar::SSI& );
+ 	void ssiContactRemoved( const Oscar::SSI& ) {}
+ 
+ 	/* slots for receiving typing notifications, and notify the appropriate OscarContact */
+@@ -137,6 +178,8 @@
+ 
+ 	void accountDisconnected( Kopete::Account::DisconnectReason reason );
+ 
++	void buddyIconChanged();
++
+ private:
+ 	QString getFLAPErrorMessage( int code );
+ 
+@@ -147,6 +190,9 @@
+ 	/** Handle task errors from the client */
+ 	void slotTaskError( const Oscar::SNAC& s, int errCode, bool fatal ) ;
+ 
++	/** Sends buddy icon to server */
++	void slotSendBuddyIcon();
++
+ private:
+ 	OscarAccountPrivate *d;
+ 
+--- kopete/protocols/oscar/icq/icqaccount.h	(revision 568672)
++++ kopete/protocols/oscar/icq/icqaccount.h	(revision 586398)
+@@ -29,6 +29,8 @@
+ namespace Kopete { class AwayAction; }
+ class ICQProtocol;
+ class ICQAccount;
++class OscarVisibilityDialog;
++
+ class ICQMyselfContact : public OscarMyselfContact
+ {
+ Q_OBJECT
+@@ -85,9 +87,18 @@
+ private slots:
+ 	void slotToggleInvisible();
+ 
++	void slotSetVisiblility();
++	void slotVisibilityDialogClosed();
++
++	void slotGlobalIdentityChanged( const QString& key, const QVariant& value );
++
++	void slotBuddyIconChanged();
++
+ private:
+ 	bool mWebAware;
+ 	bool mHideIP;
++	QString mInitialStatusMessage;
++	OscarVisibilityDialog* m_visibilityDialog;
+ };
+ 
+ #endif
+--- kopete/protocols/oscar/icq/icqprotocol.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/icqprotocol.cpp	(revision 586398)
+@@ -269,7 +269,7 @@
+ 	mCountries.insert(385, kl->twoAlphaToCountryName("hr"));
+ 	mCountries.insert(53, kl->twoAlphaToCountryName("cu"));
+ 	mCountries.insert(357, kl->twoAlphaToCountryName("cy"));
+-	mCountries.insert(420, kl->twoAlphaToCountryName("cz"));
++	mCountries.insert(42, kl->twoAlphaToCountryName("cz"));
+ 	mCountries.insert(45, kl->twoAlphaToCountryName("dk"));
+ 	mCountries.insert(246, i18n("Diego Garcia"));
+ 	mCountries.insert(253, kl->twoAlphaToCountryName("dj"));
+@@ -336,7 +336,7 @@
+ 	mCountries.insert(965, kl->twoAlphaToCountryName("kw"));
+ 	mCountries.insert(706, kl->twoAlphaToCountryName("kg"));
+ 	mCountries.insert(856, kl->twoAlphaToCountryName("la"));
+-	mCountries.insert(371, kl->twoAlphaToCountryName("kv"));
++	mCountries.insert(371, kl->twoAlphaToCountryName("lv"));
+ 	mCountries.insert(961, kl->twoAlphaToCountryName("kb"));
+ 	mCountries.insert(266, kl->twoAlphaToCountryName("ls"));
+ 	mCountries.insert(231, kl->twoAlphaToCountryName("lr"));
+@@ -406,7 +406,7 @@
+ 	mCountries.insert(248, kl->twoAlphaToCountryName("sc"));
+ 	mCountries.insert(232, kl->twoAlphaToCountryName("sl"));
+ 	mCountries.insert(65, kl->twoAlphaToCountryName("sg"));
+-	mCountries.insert(421, kl->twoAlphaToCountryName("sk"));
++	mCountries.insert(4201, kl->twoAlphaToCountryName("sk"));
+ 	mCountries.insert(386, kl->twoAlphaToCountryName("si"));
+ 	mCountries.insert(677, kl->twoAlphaToCountryName("sb"));
+ 	mCountries.insert(252, kl->twoAlphaToCountryName("so"));
+@@ -571,6 +571,9 @@
+ 
+ 	mEncodings.insert(2259, i18n("TIS-620 Thai"));
+ 
++	mEncodings.insert(106, i18n("UTF-8 Unicode"));
++	mEncodings.insert(1015, i18n("UTF-16 Unicode"));
++
+ /*
+ Missing ones (copied from qtextcodec doc):
+ TSCII -- Tamil
+--- kopete/protocols/oscar/icq/icqpresence.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/icqpresence.cpp	(revision 586398)
+@@ -69,8 +69,8 @@
+ 	static const PresenceTypeData data[] =
+ 	{
+ 		{ Presence::Offline,      OnlineStatus::Offline, OFFLINE,  OFFLINE, i18n( "O&ffline" ),        i18n("Offline"),        i18n("Offline"),                    0,                      "contact_invisible_overlay", Kopete::OnlineStatusManager::Offline,      0 },
+-		{ Presence::DoNotDisturb, OnlineStatus::Away,    SET_DND,  IS_DND,  i18n( "&Do Not Disturb" ), i18n("Do Not Disturb"), i18n("Do Not Disturb (Invisible)"), "contact_busy_overlay", "contact_invisible_overlay", 0,                                         Kopete::OnlineStatusManager::HasAwayMessage },
+-		{ Presence::Occupied,     OnlineStatus::Away,    SET_OCC,  IS_OCC,  i18n( "O&ccupied" ),       i18n("Occupied"),       i18n("Occupied (Invisible)"),       "contact_busy_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::Busy,         Kopete::OnlineStatusManager::HasAwayMessage },
++		{ Presence::DoNotDisturb, OnlineStatus::Away,    SET_DND,  IS_DND,  i18n( "&Do Not Disturb" ), i18n("Do Not Disturb"), i18n("Do Not Disturb (Invisible)"), "contact_busy_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::Busy,         Kopete::OnlineStatusManager::HasAwayMessage },
++		{ Presence::Occupied,     OnlineStatus::Away,    SET_OCC,  IS_OCC,  i18n( "O&ccupied" ),       i18n("Occupied"),       i18n("Occupied (Invisible)"),       "contact_busy_overlay", "contact_invisible_overlay", 0,                                         Kopete::OnlineStatusManager::HasAwayMessage },
+ 		{ Presence::NotAvailable, OnlineStatus::Away,    SET_NA,   IS_NA,   i18n( "Not A&vailable" ),  i18n("Not Available"),  i18n("Not Available (Invisible)"),  "contact_xa_overlay",   "contact_invisible_overlay", Kopete::OnlineStatusManager::ExtendedAway, Kopete::OnlineStatusManager::HasAwayMessage },
+ 		{ Presence::Away,         OnlineStatus::Away,    SET_AWAY, IS_AWAY, i18n( "&Away" ),           i18n("Away"),           i18n("Away (Invisible)"),           "contact_away_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::Away,         Kopete::OnlineStatusManager::HasAwayMessage },
+ 		{ Presence::FreeForChat,  OnlineStatus::Online,  SET_FFC,  IS_FFC,  i18n( "&Free for Chat" ),  i18n("Free For Chat"),  i18n("Free For Chat (Invisible)"),  "icq_ffc",              "contact_invisible_overlay", Kopete::OnlineStatusManager::FreeForChat,  0 },
+@@ -186,6 +186,11 @@
+ {
+ }
+ 
++OnlineStatusManager::~OnlineStatusManager()
++{
++	delete d;
++}
++
+ Presence OnlineStatusManager::presenceOf( uint internalStatus )
+ {
+ 	if ( internalStatus < Presence::TypeCount )
+@@ -232,7 +237,7 @@
+ 
+ Presence Presence::fromOnlineStatus( const Kopete::OnlineStatus &status )
+ {
+-	if ( status != Kopete::OnlineStatus() )
++	if ( status.protocol() == ICQProtocol::protocol() )
+ 	{
+ 		OnlineStatusManager *store = ICQProtocol::protocol()->statusManager();
+ 		return store->presenceOf( status.internalStatus() );
+--- kopete/protocols/oscar/icq/icqpresence.h	(revision 568672)
++++ kopete/protocols/oscar/icq/icqpresence.h	(revision 586398)
+@@ -75,6 +75,7 @@
+ {
+ public:
+ 	OnlineStatusManager();
++	~OnlineStatusManager();
+ 	ICQ::Presence presenceOf( uint internalStatus );
+ 	Kopete::OnlineStatus onlineStatusOf( const ICQ::Presence &presence );
+ 	Kopete::OnlineStatus connectingStatus();
+--- kopete/protocols/oscar/icq/icqcontact.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/icqcontact.cpp	(revision 586398)
+@@ -18,6 +18,8 @@
+ #include "icqcontact.h"
+ 
+ #include <qtimer.h>
++#include <qimage.h>
++#include <qfile.h>
+ 
+ #include <kaction.h>
+ #include <kactionclasses.h>
+@@ -29,6 +31,8 @@
+ #include <knotifyclient.h>
+ #include <kpassivepopup.h>
+ #include <kinputdialog.h>
++#include <kmdcodec.h>
++#include <kstandarddirs.h>
+ 
+ #include "kopetechatsessionmanager.h"
+ #include "kopeteuiglobal.h"
+@@ -45,6 +49,7 @@
+ #include "client.h"
+ #include "oscarutils.h"
+ #include "oscarencodingselectiondialog.h"
++#include "ssimanager.h"
+ 
+ ICQContact::ICQContact( ICQAccount *account, const QString &name, Kopete::MetaContact *parent,
+ 						const QString& icon, const Oscar::SSI& ssiItem )
+@@ -54,6 +59,7 @@
+ 	m_infoWidget = 0L;
+ 	m_requestingNickname = false;
+     m_oesd = 0;
++	m_buddyIconDirty = false;
+ 
+ 	if ( ssiItem.waitingAuth() )
+ 		setOnlineStatus( mProtocol->statusManager()->waitingForAuth() );
+@@ -78,6 +84,10 @@
+ 	QObject::connect( mAccount->engine(), SIGNAL( receivedAwayMessage( const Oscar::Message& ) ),
+ 	                  this, SLOT( receivedStatusMessage( const Oscar::Message& ) ) );
+ 	QObject::connect( this, SIGNAL( featuresUpdated() ), this, SLOT( updateFeatures() ) );
++	QObject::connect( mAccount->engine(), SIGNAL( iconServerConnected() ),
++	                  this, SLOT( requestBuddyIcon() ) );
++	QObject::connect( mAccount->engine(), SIGNAL( haveIconForContact( const QString&, QByteArray ) ),
++	                  this, SLOT( haveIcon( const QString&, QByteArray ) ) );
+ 
+ }
+ 
+@@ -107,6 +117,10 @@
+ 	if ( Oscar::normalize( contact  ) != Oscar::normalize( contactId() ) )
+ 		return;
+ 
++	// invalidate old away message if user was offline
++	if ( !isOnline() )
++		removeProperty( mProtocol->awayMessage );
++
+ 	kdDebug( OSCAR_ICQ_DEBUG ) << k_funcinfo << "extendedStatus is " << details.extendedStatus() << endl;
+ 	ICQ::Presence presence = ICQ::Presence::fromOscarStatus( details.extendedStatus() & 0xffff );
+ 	setOnlineStatus( presence.toOnlineStatus() );
+@@ -165,6 +179,25 @@
+ 			setProperty( mProtocol->clientFeatures, details.clientName() );
+ 	}
+ 
++	if ( details.buddyIconHash().size() > 0 && details.buddyIconHash() != m_details.buddyIconHash() )
++	{
++		m_buddyIconDirty = true;
++		if ( cachedBuddyIcon( details.buddyIconHash() ) == false )
++		{
++			if ( !mAccount->engine()->hasIconConnection() )
++			{
++				mAccount->engine()->connectToIconServer();
++			}
++			else
++			{
++				int time = ( KApplication::random() % 10 ) * 1000;
++				kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "updating buddy icon in "
++				                         << time/1000 << " seconds" << endl;
++				QTimer::singleShot( time, this, SLOT( requestBuddyIcon() ) );
++			}
++		}
++	}
++
+ 	OscarContact::userInfoUpdated( contact, details );
+ }
+ 
+@@ -290,11 +323,13 @@
+ 		return;
+ 	}
+ 
++	QTextCodec* codec = contactCodec();
++
+ 	kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "received long info from engine" << endl;
+ 
+ 	ICQGeneralUserInfo genInfo = mAccount->engine()->getGeneralInfo( contact );
+ 	if ( m_ssiItem.alias().isEmpty() && !genInfo.nickname.isEmpty() )
+-		setNickName( genInfo.nickname );
++		setNickName( codec->toUnicode( genInfo.nickname ) );
+ 	emit haveBasicInfo( genInfo );
+ 
+ 	ICQWorkUserInfo workInfo = mAccount->engine()->getWorkInfo( contact );
+@@ -313,16 +348,18 @@
+ 	if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
+ 		return;
+ 
++	QTextCodec* codec = contactCodec();
++
+ 	m_requestingNickname = false; //done requesting nickname
+ 	ICQShortInfo shortInfo = mAccount->engine()->getShortInfo( contact );
+ 	/*
+ 	if(!shortInfo.firstName.isEmpty())
+-		setProperty(mProtocol->firstName, shortInfo.firstName);
++		setProperty( mProtocol->firstName, codec->toUnicode( shortInfo.firstName ) );
+ 	else
+ 		removeProperty(mProtocol->firstName);
+ 
+ 	if(!shortInfo.lastName.isEmpty())
+-		setProperty(mProtocol->lastName, shortInfo.lastName);
++		setProperty( mProtocol->lastName, codec->toUnicode( shortInfo.lastName ) );
+ 	else
+ 		removeProperty(mProtocol->lastName);
+ 	*/
+@@ -330,7 +367,7 @@
+ 	{
+ 		kdDebug(14153) << k_funcinfo <<
+ 			"setting new displayname for former UIN-only Contact" << endl;
+-		setProperty( Kopete::Global::Properties::self()->nickName(), shortInfo.nickname );
++		setProperty( Kopete::Global::Properties::self()->nickName(), codec->toUnicode( shortInfo.nickname ) );
+ 	}
+ 
+ }
+@@ -352,13 +389,10 @@
+ 		return;
+ 	
+ 	//decode message
+-    QTextCodec* codec = QTextCodec::codecForMib( this->property( "contactEncoding" ).value().toInt() );
++	QTextCodec* codec = contactCodec();
+ 	
+-	QString realText = message.text();
+-	if ( message.properties() & Oscar::Message::NotDecoded )
+-		realText = codec->toUnicode( message.textArray() );
+-	
+-	
++	QString realText = message.text(codec);
++
+ 	if ( !realText.isEmpty() )
+ 		setProperty( mProtocol->awayMessage, realText );
+ 	else
+@@ -369,23 +403,45 @@
+ {
+ 	//Why is this unused?
+ 	Q_UNUSED( session );
+-	Oscar::Message message;
+ 
+-	message.setText( msg.plainBody() );
++	QTextCodec* codec = contactCodec();
+ 
+-	message.setTimestamp( msg.timestamp() );
+-	message.setSender( mAccount->accountId() );
+-	message.setReceiver( mName );
+-	message.setType( 0x01 );
++	int messageChannel = 0x01;
++	Oscar::Message::Encoding messageEncoding;
+ 
+-	//TODO add support for type 2 messages
+-	/*if ( msg.type() == Kopete::Message::PlainText )
+-		message.setType( 0x01 );
++	if ( isOnline() && m_details.hasCap( CAP_UTF8 ) )
++		messageEncoding = Oscar::Message::UCS2;
+ 	else
+-		message.setType( 0x02 );*/
+-	//TODO: we need to check for channel 0x04 messages too;
++		messageEncoding = Oscar::Message::UserDefined;
+ 
+-	mAccount->engine()->sendMessage( message );
++	QString msgText( msg.plainBody() );
++	// TODO: More intelligent handling of message length.
++	uint chunk_length = !isOnline() ? 450 : 4096;
++	uint msgPosition = 0;
++
++	do
++	{
++		QString msgChunk( msgText.mid( msgPosition, chunk_length ) );
++		// Try to split on space if needed
++		if ( msgChunk.length() == chunk_length )
++		{
++			for ( int i = 0; i < 100; i++ )
++			{
++				if ( msgChunk[chunk_length - i].isSpace() )
++				{
++					msgChunk = msgChunk.left( chunk_length - i );
++					msgPosition++;
++				}
++			}
++		}
++		msgPosition += msgChunk.length();
++
++		Oscar::Message message( messageEncoding, msgChunk, messageChannel, 0, msg.timestamp(), codec );
++		message.setSender( mAccount->accountId() );
++		message.setReceiver( mName );
++		mAccount->engine()->sendMessage( message );
++	} while ( msgPosition < msgText.length() );
++
+ 	manager(Kopete::Contact::CanCreate)->appendMessage(msg);
+ 	manager(Kopete::Contact::CanCreate)->messageSucceeded();
+ }
+@@ -395,6 +451,76 @@
+ 	setProperty( static_cast<ICQProtocol*>(protocol())->clientFeatures, m_clientFeatures );
+ }
+ 
++void ICQContact::requestBuddyIcon()
++{
++	if ( m_buddyIconDirty && m_details.buddyIconHash().size() > 0 )
++	{
++		account()->engine()->requestBuddyIcon( contactId(), m_details.buddyIconHash(),
++		                                       m_details.iconCheckSumType() );
++	}
++}
++
++void ICQContact::haveIcon( const QString& user, QByteArray icon )
++{
++	if ( Oscar::normalize( user ) != Oscar::normalize( contactId() ) )
++		return;
++	
++	kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "Updating icon for " << contactId() << endl;
++	
++	KMD5 buddyIconHash( icon );
++	if ( memcmp( buddyIconHash.rawDigest(), m_details.buddyIconHash().data(), 16 ) == 0 )
++	{
++		QString iconLocation( locateLocal( "appdata", "oscarpictures/"+ contactId() ) );
++		
++		QFile iconFile( iconLocation );
++		if ( !iconFile.open( IO_WriteOnly ) )
++		{
++			kdDebug(14153) << k_funcinfo << "Cannot open file"
++			               << iconLocation << " for writing!" << endl;
++			return;
++		}
++		
++		iconFile.writeBlock( icon );
++		iconFile.close();
++		
++		setProperty( Kopete::Global::Properties::self()->photo(), QString::null );
++		setProperty( Kopete::Global::Properties::self()->photo(), iconLocation );
++		m_buddyIconDirty = false;
++	}
++	else
++	{
++		kdDebug(14153) << k_funcinfo << "Buddy icon hash does not match!" << endl;
++		removeProperty( Kopete::Global::Properties::self()->photo() );
++	}
++}
++
++bool ICQContact::cachedBuddyIcon( QByteArray hash )
++{
++	QString iconLocation( locateLocal( "appdata", "oscarpictures/"+ contactId() ) );
++	
++	QFile iconFile( iconLocation );
++	if ( !iconFile.open( IO_ReadOnly ) )
++		return false;
++	
++	KMD5 buddyIconHash;
++	buddyIconHash.update( iconFile );
++	iconFile.close();
++	
++	if ( memcmp( buddyIconHash.rawDigest(), hash.data(), 16 ) == 0 )
++	{
++		kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "Updating icon for "
++		                         << contactId() << " from local cache" << endl;
++		setProperty( Kopete::Global::Properties::self()->photo(), QString::null );
++		setProperty( Kopete::Global::Properties::self()->photo(), iconLocation );
++		m_buddyIconDirty = false;
++		return true;
++	}
++	else
++	{
++		return false;
++	}
++}
++
+ #if 0
+ void ICQContact::slotContactChanged(const UserInfo &u)
+ {
+@@ -566,12 +692,6 @@
+ 		actionSendAuth = new KAction(i18n("&Grant Authorization"), "mail_forward", 0,
+ 			this, SLOT(slotSendAuth()), this, "actionSendAuth");
+ 		/*
+-		actionIgnore = new KToggleAction(i18n("&Ignore"), "", 0,
+-			this, SLOT(slotIgnore()), this, "actionIgnore");
+-		actionVisibleTo = new KToggleAction(i18n("Always &Visible To"), "", 0,
+-			this, SLOT(slotVisibleTo()), this, "actionVisibleTo");
+-		actionInvisibleTo = new KToggleAction(i18n("Always &Invisible To"), "", 0,
+-			this, SLOT(slotInvisibleTo()), this, "actionInvisibleTo");
+ 	}
+ 	else
+ 	{
+@@ -580,16 +700,13 @@
+ 	}
+ 
+ */
++	m_actionIgnore = new KToggleAction(i18n("&Ignore"), "", 0,
++	                                   this, SLOT(slotIgnore()), this, "actionIgnore");
++	m_actionVisibleTo = new KToggleAction(i18n("Always &Visible To"), "", 0,
++	                                      this, SLOT(slotVisibleTo()), this, "actionVisibleTo");
++	m_actionInvisibleTo = new KToggleAction(i18n("Always &Invisible To"), "", 0,
++	                                        this, SLOT(slotInvisibleTo()), this, "actionInvisibleTo");
+ 
+-	QString i1 = i18n("&Ignore");
+-	QString i2 = i18n("Always &Visible To");
+-	QString i3 = i18n("Always &Invisible To");
+-
+-	Q_UNUSED( i1 );
+-	Q_UNUSED( i2 );
+-	Q_UNUSED( i3 );
+-
+-
+ 	bool on = account()->isConnected();
+ 	if ( m_ssiItem.waitingAuth() )
+ 		actionRequestAuth->setEnabled(on);
+@@ -604,24 +721,26 @@
+ 
+ /*
+ 	actionReadAwayMessage->setEnabled(status != OSCAR_OFFLINE && status != OSCAR_ONLINE);
+-	actionIgnore->setEnabled(on);
+-	actionVisibleTo->setEnabled(on);
+-	actionInvisibleTo->setEnabled(on);
++*/
++	m_actionIgnore->setEnabled(on);
++	m_actionVisibleTo->setEnabled(on);
++	m_actionInvisibleTo->setEnabled(on);
+ 
+-	actionIgnore->setChecked(mIgnore);
+-	actionVisibleTo->setChecked(mVisibleTo);
+-	actionInvisibleTo->setChecked(mInvisibleTo);
++	SSIManager* ssi = account()->engine()->ssiManager();
++	m_actionIgnore->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_IGNORE ));
++	m_actionVisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_VISIBLE ));
++	m_actionInvisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_INVISIBLE ));
+ 
+-*/
+ 	actionCollection->append(actionRequestAuth);
+ 	actionCollection->append(actionSendAuth);
+     actionCollection->append( m_selectEncoding );
+-/*
+-	actionCollection->append(actionIgnore);
+-	actionCollection->append(actionVisibleTo);
+-	actionCollection->append(actionInvisibleTo);
+-	actionCollection->append(actionReadAwayMessage);
+-*/
++
++	actionCollection->append(m_actionIgnore);
++	actionCollection->append(m_actionVisibleTo);
++	actionCollection->append(m_actionInvisibleTo);
++
++//	actionCollection->append(actionReadAwayMessage);
++
+ 	return actionCollection;
+ }
+ 
+@@ -656,12 +775,22 @@
+ 
+ void ICQContact::changeEncodingDialogClosed( int result )
+ {
+-    if ( result == QDialog::Accepted )
+-    {
+-        kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "setting encoding mib to "
+-                                 << m_oesd->selectedEncoding() << endl;
+-        setProperty( mProtocol->contactEncoding, m_oesd->selectedEncoding() );
+-    }
++	if ( result == QDialog::Accepted )
++	{
++		int mib = m_oesd->selectedEncoding();
++		if ( mib != 0 )
++		{
++			kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "setting encoding mib to "
++			                         << m_oesd->selectedEncoding() << endl;
++			setProperty( mProtocol->contactEncoding, m_oesd->selectedEncoding() );
++		}
++		else
++		{
++			kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo
++			                         << "setting encoding to default" << endl;
++			removeProperty( mProtocol->contactEncoding );
++		}
++	}
+ 
+     if ( m_oesd )
+     {
+@@ -670,6 +799,22 @@
+     }
+ }
+ 
++
++void ICQContact::slotIgnore()
++{
++	account()->engine()->setIgnore( contactId(), m_actionIgnore->isChecked() );
++}
++
++void ICQContact::slotVisibleTo()
++{
++	account()->engine()->setVisibleTo( contactId(), m_actionVisibleTo->isChecked() );
++}
++
++void ICQContact::slotInvisibleTo()
++{
++	account()->engine()->setInvisibleTo( contactId(), m_actionInvisibleTo->isChecked() );
++}
++
+ #if 0
+ 
+ void ICQContact::slotReadAwayMessage()
+--- kopete/protocols/oscar/icq/icqaccount.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/icqaccount.cpp	(revision 586398)
+@@ -15,23 +15,32 @@
+   *************************************************************************
+ */
+ 
++#include <qfile.h>
++
+ #include <kconfig.h>
+ #include <kdebug.h>
+ #include <klocale.h>
+ #include <kpopupmenu.h>
++#include <kmdcodec.h>
++#include <kmessagebox.h>
+ 
+ #include "kopeteawayaction.h"
+ #include "kopetemessage.h"
++#include "kopetecontactlist.h"
++#include "kopeteuiglobal.h"
+ 
+ #include "client.h"
+ #include "icquserinfo.h"
+ #include "oscarsettings.h"
+ #include "oscarutils.h"
++#include "ssimanager.h"
+ 
+ #include "icqcontact.h"
+ #include "icqprotocol.h"
+ #include "icqaccount.h"
+ 
++#include "oscarvisibilitydialog.h"
++
+ ICQMyselfContact::ICQMyselfContact( ICQAccount *acct ) : OscarMyselfContact( acct )
+ {
+ 	QObject::connect( acct->engine(), SIGNAL( loggedIn() ), this, SLOT( fetchShortInfo() ) );
+@@ -45,6 +54,7 @@
+ 	kdDebug( OSCAR_ICQ_DEBUG ) << k_funcinfo << "extendedStatus is " << QString::number( extendedStatus, 16 ) << endl;
+ 	ICQ::Presence presence = ICQ::Presence::fromOscarStatus( extendedStatus & 0xffff );
+ 	setOnlineStatus( presence.toOnlineStatus() );
++	setProperty( Kopete::Global::Properties::self()->awayMessage(), static_cast<ICQAccount*>( account() )->engine()->statusMessage() );
+ }
+ 
+ void ICQMyselfContact::receivedShortInfo( const QString& contact )
+@@ -54,7 +64,9 @@
+ 
+ 	ICQShortInfo shortInfo = static_cast<ICQAccount*>( account() )->engine()->getShortInfo( contact );
+ 	if ( !shortInfo.nickname.isEmpty() )
+-		setProperty( Kopete::Global::Properties::self()->nickName(), shortInfo.nickname );
++	{
++		setProperty( Kopete::Global::Properties::self()->nickName(), static_cast<ICQAccount*>( account() )->defaultCodec()->toUnicode( shortInfo.nickname ) );
++	}
+ }
+ 
+ void ICQMyselfContact::fetchShortInfo()
+@@ -69,11 +81,18 @@
+ 	setMyself( new ICQMyselfContact( this ) );
+ 	myself()->setOnlineStatus( ICQ::Presence( ICQ::Presence::Offline, ICQ::Presence::Visible ).toOnlineStatus() );
+ 
++	m_visibilityDialog = 0;
++
+ 	QString nickName = configGroup()->readEntry("NickName", QString::null);
+ 	mWebAware = configGroup()->readBoolEntry( "WebAware", false );
+ 	mHideIP = configGroup()->readBoolEntry( "HideIP", true );
++	mInitialStatusMessage = QString::null;
+ 
++	QObject::connect( Kopete::ContactList::self(), SIGNAL( globalIdentityChanged( const QString&, const QVariant& ) ),
++	                  this, SLOT( slotGlobalIdentityChanged( const QString&, const QVariant& ) ) );
+ 
++	QObject::connect( this, SIGNAL( buddyIconChanged() ), this, SLOT( slotBuddyIconChanged() ) );
++
+ 	//setIgnoreUnknownContacts(pluginData(protocol(), "IgnoreUnknownContacts").toUInt() == 1);
+ 
+ 	/* FIXME: need to do this when web aware or hide ip change
+@@ -114,7 +133,10 @@
+ 	actionInvisible->setChecked( presence().visibility() == ICQ::Presence::Invisible );
+ 	actionMenu->insert( actionInvisible );
+ 
+-	//actionMenu->popupMenu()->insertSeparator();
++	actionMenu->popupMenu()->insertSeparator();
++	actionMenu->insert( new KToggleAction( i18n( "Set Visibility..." ), 0, 0,
++	                                       this, SLOT( slotSetVisiblility() ), this,
++	                                       "ICQAccount::mActionSetVisibility") );
+ 	//actionMenu->insert( new KToggleAction( i18n( "Send &SMS..." ), 0, 0, this, SLOT( slotSendSMS() ), this, "ICQAccount::mActionSendSMS") );
+ 
+ 	return actionMenu;
+@@ -160,11 +182,12 @@
+ 		if ( mWebAware )
+ 			status |= ICQ::StatusCode::WEBAWARE;
+ 
+-		engine()->setIsIcq( true );
+-		engine()->setStatus( status );
++		engine()->setStatus( status, mInitialStatusMessage );
++		updateVersionUpdaterStamp();
+ 		engine()->start( server, port, accountId(), password );
+ 		engine()->connectToServer( c, server, true /* doAuth */ );
+ 
++		mInitialStatusMessage = QString::null;
+ 	}
+ }
+ 
+@@ -173,6 +196,20 @@
+ 	kdDebug(14153) << k_funcinfo << "Attempting to set status offline" << endl;
+ 	ICQ::Presence presOffline = ICQ::Presence( ICQ::Presence::Offline, presence().visibility() );
+ 	myself()->setOnlineStatus( presOffline.toOnlineStatus() );
++
++	QDictIterator<Kopete::Contact> it( contacts() );
++	for( ; it.current(); ++it )
++	{
++		OscarContact* oc = dynamic_cast<OscarContact*>( it.current() );
++		if ( oc )
++		{
++			if ( oc->ssiItem().waitingAuth() )
++				oc->setOnlineStatus( protocol()->statusManager()->waitingForAuth() );
++			else
++				oc->setOnlineStatus( ICQ::Presence( ICQ::Presence::Offline, ICQ::Presence::Visible ).toOnlineStatus() );
++		}
++	}
++
+ 	OscarAccount::disconnected( reason );
+ }
+ 
+@@ -183,6 +220,87 @@
+ 	setInvisible( (presence().visibility() == Presence::Visible) ? Presence::Invisible : Presence::Visible );
+ }
+ 
++void ICQAccount::slotSetVisiblility()
++{
++	if( !isConnected() )
++	{
++		KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
++		                    i18n("You must be online to set users visibility."),
++		                    i18n("ICQ Plugin") );
++		return;
++	}
++	
++	if ( !m_visibilityDialog )
++	{
++		m_visibilityDialog = new OscarVisibilityDialog( engine(), Kopete::UI::Global::mainWidget() );
++		QObject::connect( m_visibilityDialog, SIGNAL( closing() ),
++		                  this, SLOT( slotVisibilityDialogClosed() ) );
++		
++		//add all contacts;
++		OscarVisibilityDialog::ContactMap contactMap;
++		//temporary map for faster lookup of contactId
++		QMap<QString, QString> revContactMap;
++		
++		QValueList<Oscar::SSI> contactList = engine()->ssiManager()->contactList();
++		QValueList<Oscar::SSI>::const_iterator it, cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++		{
++			QString contactId = ( *it ).name();
++			
++			OscarContact* oc = dynamic_cast<OscarContact*>( contacts()[( *it ).name()] );
++			if ( oc )
++			{	//for better orientation in lists use nickName and icq number
++				QString screenName( "%1 (%2)" );
++				screenName = screenName.arg( oc->nickName(), contactId);
++				contactMap.insert( screenName, contactId );
++				revContactMap.insert( contactId, screenName );
++			}
++			else
++			{
++				contactMap.insert( contactId, contactId );
++				revContactMap.insert( contactId, contactId );
++			}
++		}
++		m_visibilityDialog->addContacts( contactMap );
++		
++		//add contacts from visible list
++		QStringList tmpList;
++		
++		contactList = engine()->ssiManager()->visibleList();
++		cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++			tmpList.append( revContactMap[( *it ).name()] );
++		
++		m_visibilityDialog->addVisibleContacts( tmpList );
++		
++		//add contacts from invisible list
++		tmpList.clear();
++		
++		contactList = engine()->ssiManager()->invisibleList();
++		cEnd = contactList.constEnd();
++		
++		for ( it = contactList.constBegin(); it != cEnd; ++it )
++			tmpList.append( revContactMap[( *it ).name()] );
++		
++		m_visibilityDialog->addInvisibleContacts( tmpList );
++		
++		m_visibilityDialog->resize( 550, 350 );
++		m_visibilityDialog->show();
++	}
++	else
++	{
++		m_visibilityDialog->raise();
++	}
++}
++
++void ICQAccount::slotVisibilityDialogClosed()
++{
++	m_visibilityDialog->delayedDestruct();
++	m_visibilityDialog = 0L;
++}
++
+ void ICQAccount::setAway( bool away, const QString &awayReason )
+ {
+ 	kdDebug(14153) << k_funcinfo << "account='" << accountId() << "'" << endl;
+@@ -205,12 +323,10 @@
+ 
+ void ICQAccount::setPresenceType( ICQ::Presence::Type type, const QString &message )
+ {
+-	Q_UNUSED( message );
+ 	ICQ::Presence pres = presence();
+-	kdDebug(14153) << k_funcinfo << "new type=" << (int)type << ", old type=" << (int)pres.type() << endl;
++	kdDebug(14153) << k_funcinfo << "new type=" << (int)type << ", old type=" << (int)pres.type() << ", new message=" << message << endl;
+ 	//setAwayMessage(awayMessage);
+ 	setPresenceTarget( ICQ::Presence( type, pres.visibility() ), message );
+-	myself()->setProperty( Kopete::Global::Properties::self()->awayMessage(), message );
+ }
+ 
+ void ICQAccount::setPresenceTarget( const ICQ::Presence &newPres, const QString &message )
+@@ -227,9 +343,7 @@
+ 	}
+ 	else if ( accountIsOffline )
+ 	{
+-		// set status message if given
+-		if ( ! message.isEmpty() )
+-			engine()->setStatusMessage( message );
++		mInitialStatusMessage = message;
+ 		OscarAccount::connect( newPres.toOnlineStatus() );
+ 	}
+ 	else
+@@ -281,6 +395,137 @@
+ }
+ 
+ 
++void ICQAccount::slotGlobalIdentityChanged( const QString& key, const QVariant& value )
++{
++	//do something with the photo
++	kdDebug(14153) << k_funcinfo << "Global identity changed" << endl;
++	kdDebug(14153) << k_funcinfo << "key: " << key << endl;
++	kdDebug(14153) << k_funcinfo << "value: " << value << endl;
++	
++	if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
++	{
++		if ( key == Kopete::Global::Properties::self()->nickName().key() )
++		{
++			//edit ssi item to change alias (if possible)
++		}
++		
++		if ( key == Kopete::Global::Properties::self()->photo().key() )
++		{
++			setBuddyIcon( value.toString() );
++		}
++	}
++}
++
++void ICQAccount::slotBuddyIconChanged()
++{
++	// need to disconnect because we could end up with many connections
++	QObject::disconnect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
++	if ( !engine()->isActive() )
++	{
++		QObject::connect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
++		return;
++	}
++	
++	QString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
++	
++	SSIManager* ssi = engine()->ssiManager();
++	Oscar::SSI item = ssi->findItemForIconByRef( 1 );
++	
++	if ( photoPath.isEmpty() )
++	{
++		if ( item )
++		{
++			kdDebug(14153) << k_funcinfo << "Removing icon hash item from ssi" << endl;
++			Oscar::SSI s(item);
++			
++			//remove hash and alias
++			QValueList<TLV> tList( item.tlvList() );
++			TLV t = Oscar::findTLV( tList, 0x00D5 );
++			if ( t )
++				tList.remove( t );
++			
++			t = Oscar::findTLV( tList, 0x0131 );
++			if ( t )
++				tList.remove( t );
++			
++			item.setTLVList( tList );
++			//s is old, item is new. modification will occur
++			engine()->modifySSIItem( s, item );
++		}
++	}
++	else
++	{
++		QFile iconFile( photoPath );
++		iconFile.open( IO_ReadOnly );
++		
++		KMD5 iconHash;
++		iconHash.update( iconFile );
++		kdDebug(14153) << k_funcinfo  << "hash is :" << iconHash.hexDigest() << endl;
++	
++		//find old item, create updated item
++		if ( !item )
++		{
++			kdDebug(14153) << k_funcinfo << "no existing icon hash item in ssi. creating new" << endl;
++			
++			TLV t;
++			t.type = 0x00D5;
++			t.data.resize( 18 );
++			t.data[0] = 0x01;
++			t.data[1] = 0x10;
++			memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
++			t.length = t.data.size();
++			
++			//alias, it's always empty
++			TLV t2;
++			t2.type = 0x0131;
++			t2.length = 0;
++			
++			QValueList<Oscar::TLV> list;
++			list.append( t );
++			list.append( t2 );
++			
++			Oscar::SSI s( "1", 0, ssi->nextContactId(), ROSTER_BUDDYICONS, list );
++			
++			//item is a non-valid ssi item, so the function will add an item
++			kdDebug(14153) << k_funcinfo << "setting new icon item" << endl;
++			engine()->modifySSIItem( item, s );
++		}
++		else
++		{ //found an item
++			Oscar::SSI s(item);
++			kdDebug(14153) << k_funcinfo << "modifying old item in ssi." << endl;
++			QValueList<TLV> tList( item.tlvList() );
++			
++			TLV t = Oscar::findTLV( tList, 0x00D5 );
++			if ( t )
++				tList.remove( t );
++			else
++				t.type = 0x00D5;
++			
++			t.data.resize( 18 );
++			t.data[0] = 0x01;
++			t.data[1] = 0x10;
++			memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
++			t.length = t.data.size();
++			tList.append( t );
++			
++			//add empty alias
++			t = Oscar::findTLV( tList, 0x0131 );
++			if ( !t )
++			{
++				t.type = 0x0131;
++				t.length = 0;
++				tList.append( t );
++			}
++			
++			item.setTLVList( tList );
++			//s is old, item is new. modification will occur
++			engine()->modifySSIItem( s, item );
++		}
++		iconFile.close();
++	}
++}
++
+ #include "icqaccount.moc"
+ 
+ //kate: tab-width 4; indent-mode csands;
+--- kopete/protocols/oscar/icq/ui/icqaddcontactpage.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/ui/icqaddcontactpage.cpp	(revision 586398)
+@@ -109,7 +109,7 @@
+ 	{
+ 		m_searchDialog = new ICQSearchDialog( mAccount, this, "icqSearchDialog" );
+ 		m_searchDialog->show();
+-		connect( m_searchDialog, SIGNAL( closeClicked() ), this, SLOT( searchDialogDestroyed() ) );
++		connect( m_searchDialog, SIGNAL( finished() ), this, SLOT( searchDialogDestroyed() ) );
+ 	}
+ }
+ 
+--- kopete/protocols/oscar/icq/ui/icqeditaccountwidget.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/ui/icqeditaccountwidget.cpp	(revision 586398)
+@@ -92,8 +92,15 @@
+                                       mProtocol->encodings(),
+                                       encodingValue );
+ 
+-
++		// Global Identity
++		mAccountSettings->chkGlobalIdentity->setChecked( mAccount->configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) );
+ 	}
++	else
++	{
++		mProtocol->setComboFromTable( mAccountSettings->encodingCombo,
++		                              mProtocol->encodings(),
++		                              4 );
++	}
+ 
+ 	QObject::connect(mAccountSettings->buttonRegister, SIGNAL(clicked()), this, SLOT(slotOpenRegister()));
+ 
+@@ -146,6 +153,9 @@
+ 		mAccount->setServerAddress("login.oscar.aol.com");
+ 		mAccount->setServerPort(5190);
+ 	}
++	
++	// Global Identity
++	mAccount->configGroup()->writeEntry( "ExcludeGlobalIdentity", mAccountSettings->chkGlobalIdentity->isChecked() );
+ 
+ 	return mAccount;
+ }
+@@ -156,7 +166,7 @@
+ 
+ 	QString userName = mAccountSettings->edtAccountId->text();
+ 
+-	if (userName.contains(" ") || (userName.length() < 4))
++	if (userName.contains(" ")) 
+ 		return false;
+ 
+ 	for (unsigned int i=0; i<userName.length(); i++)
+--- kopete/protocols/oscar/icq/ui/icqsearchdialog.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/ui/icqsearchdialog.cpp	(revision 586398)
+@@ -22,6 +22,8 @@
+ #include <qcheckbox.h>
+ #include <qcombobox.h>
+ #include <qlayout.h>
++#include <qtextcodec.h>
++#include <qtabwidget.h>
+ #include <kdebug.h>
+ #include <kiconloader.h>
+ #include <klistview.h>
+@@ -93,10 +95,12 @@
+ 				this, SLOT( newResult( const ICQSearchResult& ) ) );
+ 		connect( m_account->engine(), SIGNAL( endOfSearch( int ) ),
+ 				this, SLOT( searchFinished( int ) ) );
+-		
+-		if ( !m_searchUI->uin->text().isEmpty() )
++
++		const QWidget* currentPage = m_searchUI->tabWidget3->currentPage();
++
++		if ( currentPage == m_searchUI->tab )
+ 		{
+-			if(m_searchUI->uin->text().toULong() == 0)
++			if( m_searchUI->uin->text().isEmpty() || m_searchUI->uin->text().toULong() == 0 )
+ 			{
+ 				// Invalid UIN
+ 				stopSearch();
+@@ -110,16 +114,17 @@
+ 				m_account->engine()->uinSearch( m_searchUI->uin->text() );
+ 			}
+ 		}
+-		else
++		else if ( currentPage == m_searchUI->tab_2 )
+ 		{
+ 			//create a ICQWPSearchInfo struct and send it
+ 			ICQProtocol* p = ICQProtocol::protocol();
+ 			ICQWPSearchInfo info;
+-			info.firstName = m_searchUI->firstName->text();
+-			info.lastName = m_searchUI->lastName->text();
+-			info.nickName = m_searchUI->nickName->text();
+-			info.email = m_searchUI->email->text();
+-			info.city = m_searchUI->city->text(); // City
++			QTextCodec* codec = m_account->defaultCodec();
++			info.firstName = codec->fromUnicode( m_searchUI->firstName->text() );
++			info.lastName = codec->fromUnicode( m_searchUI->lastName->text() );
++			info.nickName = codec->fromUnicode( m_searchUI->nickName->text() );
++			info.email = codec->fromUnicode( m_searchUI->email->text() );
++			info.city = codec->fromUnicode( m_searchUI->city->text() ); // City
+ 			info.gender = p->getCodeForCombo(m_searchUI->gender, p->genders()); // Gender
+ 			info.language = p->getCodeForCombo(m_searchUI->language, p->languages()); // Lang
+ 			info.country =p->getCodeForCombo(m_searchUI->country, p->countries()); // country code
+@@ -236,7 +241,7 @@
+ 	clearResults();
+ 	clearFields();
+ 
+-	closeClicked();
++	slotClose();
+ }
+ 
+ void ICQSearchDialog::resultSelectionChanged()
+@@ -260,11 +265,16 @@
+ 		//TODO update progress
+ 		return;
+ 	}
+-		
++
++	QTextCodec* codec = m_account->defaultCodec();
++
+ 	QListViewItem *item = new QListViewItem( m_searchUI->searchResults, QString::number( info.uin ),
+-	                                         info.nickName, info.firstName, info.lastName, info.email,
++	                                         codec->toUnicode( info.nickName ),
++	                                         codec->toUnicode( info.firstName ),
++	                                         codec->toUnicode( info.lastName ),
++	                                         codec->toUnicode( info.email ),
+ 	                                         info.auth ? i18n( "Yes" ) : i18n( "No" ) );
+-	
++
+ 	if ( !item )
+ 		return;
+ 	
+--- kopete/protocols/oscar/icq/ui/icqeditaccountui.ui	(revision 568672)
++++ kopete/protocols/oscar/icq/ui/icqeditaccountui.ui	(revision 586398)
+@@ -8,7 +8,7 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>499</width>
++            <width>592</width>
+             <height>404</height>
+         </rect>
+     </property>
+@@ -34,7 +34,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>B&amp;asic Setup</string>
++                    <string>&amp;Basic Setup</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -108,6 +108,14 @@
+                                     <string>If you check that case, the account will not be connected when you press the "Connect All" button, or at startup even if you selected to automatically connect at startup</string>
+                                 </property>
+                             </widget>
++                            <widget class="QCheckBox">
++                                <property name="name">
++                                    <cstring>chkGlobalIdentity</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Exclu&amp;de from Global Identity</string>
++                                </property>
++                            </widget>
+                         </vbox>
+                     </widget>
+                     <widget class="QGroupBox">
+@@ -189,7 +197,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>A&amp;ccount Preferences</string>
++                    <string>Accou&amp;nt Preferences</string>
+                 </attribute>
+                 <grid>
+                     <property name="name">
+@@ -384,7 +392,7 @@
+                             <cstring>encodingCombo</cstring>
+                         </property>
+                         <property name="enabled">
+-                            <bool>false</bool>
++                            <bool>true</bool>
+                         </property>
+                     </widget>
+                     <widget class="QLabel" row="2" column="0">
+@@ -392,7 +400,7 @@
+                             <cstring>textLabel1</cstring>
+                         </property>
+                         <property name="enabled">
+-                            <bool>false</bool>
++                            <bool>true</bool>
+                         </property>
+                         <property name="text">
+                             <string>Default to the following &amp;encoding for messages:</string>
+@@ -480,4 +488,7 @@
+     <tabstop>chkWebAware</tabstop>
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>kopetepasswordwidget.h</includehint>
++</includehints>
+ </UI>
+--- kopete/protocols/oscar/icq/ui/icquserinfowidget.cpp	(revision 568672)
++++ kopete/protocols/oscar/icq/ui/icquserinfowidget.cpp	(revision 586398)
+@@ -23,6 +23,7 @@
+ #include <qspinbox.h>
+ #include <qcombobox.h>
+ #include <qobject.h>
++#include <qtextcodec.h>
+ 
+ #include <kdatewidget.h>
+ #include <kdebug.h>
+@@ -91,18 +92,19 @@
+ 
+ void ICQUserInfoWidget::fillBasicInfo( const ICQGeneralUserInfo& ui )
+ {
++	QTextCodec* codec = m_contact->contactCodec();
+ 	m_genInfoWidget->uinEdit->setText( m_contact->contactId() );
+-	m_genInfoWidget->nickNameEdit->setText( ui.nickname );
+-	m_genInfoWidget->fullNameEdit->setText( ui.firstName + " " + ui.lastName );
++	m_genInfoWidget->nickNameEdit->setText( codec->toUnicode( ui.nickname ) );
++	m_genInfoWidget->fullNameEdit->setText( codec->toUnicode( ui.firstName ) + " " + codec->toUnicode( ui.lastName ) );
+ 	m_genInfoWidget->ipEdit->setText( m_contact->property( "ipAddress" ).value().toString() );
+-	m_genInfoWidget->emailEdit->setText( ui.email );
+-	m_genInfoWidget->cityEdit->setText( ui.city );
+-	m_genInfoWidget->stateEdit->setText( ui.state );
+-	m_genInfoWidget->phoneEdit->setText( ui.phoneNumber );
+-	m_genInfoWidget->faxEdit->setText( ui.faxNumber );
+-	m_genInfoWidget->addressEdit->setText( ui.address );
+-	m_genInfoWidget->cellEdit->setText( ui.cellNumber );
+-	m_genInfoWidget->zipEdit->setText(  ui.zip );
++	m_genInfoWidget->emailEdit->setText( codec->toUnicode( ui.email ) );
++	m_genInfoWidget->cityEdit->setText( codec->toUnicode( ui.city ) );
++	m_genInfoWidget->stateEdit->setText( codec->toUnicode( ui.state ) );
++	m_genInfoWidget->phoneEdit->setText( codec->toUnicode( ui.phoneNumber ) );
++	m_genInfoWidget->faxEdit->setText( codec->toUnicode( ui.faxNumber ) );
++	m_genInfoWidget->addressEdit->setText( codec->toUnicode( ui.address ) );
++	m_genInfoWidget->cellEdit->setText( codec->toUnicode( ui.cellNumber ) );
++	m_genInfoWidget->zipEdit->setText(  codec->toUnicode( ui.zip ) );
+ 	
+ 	QString country = static_cast<ICQProtocol*>( m_contact->protocol() )->countries()[ui.country];
+ 	m_genInfoWidget->countryEdit->setText( country );
+@@ -110,16 +112,17 @@
+ 
+ void ICQUserInfoWidget::fillWorkInfo( const ICQWorkUserInfo& ui )
+ {
+-	m_workInfoWidget->cityEdit->setText( ui.city );
+-	m_workInfoWidget->stateEdit->setText( ui.state );
+-	m_workInfoWidget->phoneEdit->setText( ui.phone );
+-	m_workInfoWidget->faxEdit->setText( ui.fax );
+-	m_workInfoWidget->addressEdit->setText( ui.address );
+-	m_workInfoWidget->zipEdit->setText( ui.zip );
+-	m_workInfoWidget->companyEdit->setText( ui.company );
+-	m_workInfoWidget->departmentEdit->setText( ui.department );
+-	m_workInfoWidget->positionEdit->setText( ui.position );
+-	m_workInfoWidget->homepageEdit->setText( ui.homepage );
++	QTextCodec* codec = m_contact->contactCodec();
++	m_workInfoWidget->cityEdit->setText( codec->toUnicode( ui.city ) );
++	m_workInfoWidget->stateEdit->setText( codec->toUnicode( ui.state ) );
++	m_workInfoWidget->phoneEdit->setText( codec->toUnicode( ui.phone ) );
++	m_workInfoWidget->faxEdit->setText( codec->toUnicode( ui.fax ) );
++	m_workInfoWidget->addressEdit->setText( codec->toUnicode( ui.address ) );
++	m_workInfoWidget->zipEdit->setText( codec->toUnicode( ui.zip ) );
++	m_workInfoWidget->companyEdit->setText( codec->toUnicode( ui.company ) );
++	m_workInfoWidget->departmentEdit->setText( codec->toUnicode( ui.department ) );
++	m_workInfoWidget->positionEdit->setText( codec->toUnicode( ui.position ) );
++	m_workInfoWidget->homepageEdit->setText( codec->toUnicode( ui.homepage ) );
+ 
+ 	ICQProtocol* p = static_cast<ICQProtocol*>( m_contact->protocol() );
+ 	QString country = p->countries()[ui.country];
+@@ -134,43 +137,45 @@
+ 
+ void ICQUserInfoWidget::fillInterestInfo( const ICQInterestInfo& info)
+ {
++	QTextCodec* codec = m_contact->contactCodec();
+ 	if (info.count>0) {
+ 		QString topic = static_cast<ICQProtocol*>( m_contact->protocol() )->interests()[info.topics[0]];
+ 		m_interestInfoWidget->topic1->setText( topic );
+-		m_interestInfoWidget->desc1->setText(info.descriptions[0]);
++		m_interestInfoWidget->desc1->setText( codec->toUnicode( info.descriptions[0] ) );
+ 	}
+ 	if (info.count>1) {
+ 		QString topic = static_cast<ICQProtocol*>( m_contact->protocol() )->interests()[info.topics[1]];
+ 		m_interestInfoWidget->topic2->setText( topic );
+-		m_interestInfoWidget->desc2->setText(info.descriptions[1]);
++		m_interestInfoWidget->desc2->setText( codec->toUnicode( info.descriptions[1] ) );
+ 	}
+ 	if (info.count>2) {
+ 		QString topic = static_cast<ICQProtocol*>( m_contact->protocol() )->interests()[info.topics[2]];
+ 		m_interestInfoWidget->topic3->setText( topic );
+-		m_interestInfoWidget->desc3->setText(info.descriptions[2]);
++		m_interestInfoWidget->desc3->setText( codec->toUnicode( info.descriptions[2] ) );
+ 	}
+ 	if (info.count>3) {
+ 		QString topic = static_cast<ICQProtocol*>( m_contact->protocol() )->interests()[info.topics[3]];
+ 		m_interestInfoWidget->topic4->setText( topic );
+-		m_interestInfoWidget->desc4->setText(info.descriptions[3]);
++		m_interestInfoWidget->desc4->setText( codec->toUnicode( info.descriptions[3] ) );
+ 	}
+ }
+ 
+ void ICQUserInfoWidget::fillMoreInfo( const ICQMoreUserInfo& ui )
+ {
++	QTextCodec* codec = m_contact->contactCodec();
+ 	m_genInfoWidget->ageSpinBox->setValue( ui.age );
+ 	if ( ui.birthday.isValid() )
+ 		m_genInfoWidget->birthday->setText( KGlobal::locale()->formatDate( ui.birthday,true ) );
+ 		
+ 	QString gender = static_cast<ICQProtocol*>( m_contact->protocol() )->genders()[ui.gender];
+ 	m_genInfoWidget->genderEdit->setText( gender );
+-	m_genInfoWidget->homepageEdit->setText( ui.homepage );
++	m_genInfoWidget->homepageEdit->setText( codec->toUnicode( ui.homepage ) );
+ 
+ 	QString ms = static_cast<ICQProtocol*>( m_contact->protocol() )->maritals()[ui.marital];
+ 	m_genInfoWidget->marital->setText( ms );
+ 
+-	m_genInfoWidget->oCityEdit->setText(ui.ocity);
+-	m_genInfoWidget->oStateEdit->setText(ui.ostate);
++	m_genInfoWidget->oCityEdit->setText( codec->toUnicode( ui.ocity) );
++	m_genInfoWidget->oStateEdit->setText( codec->toUnicode( ui.ostate) );
+ 	
+ 	QString ocountry = static_cast<ICQProtocol*>( m_contact->protocol() )->countries()[ui.ocountry];
+ 	m_genInfoWidget->oCountryEdit->setText( ocountry );
+--- kopete/protocols/oscar/icq/icqcontact.h	(revision 568672)
++++ kopete/protocols/oscar/icq/icqcontact.h	(revision 586398)
+@@ -87,6 +87,9 @@
+ 	void haveInterestInfo( const ICQInterestInfo& );
+ 
+ private:
++	bool cachedBuddyIcon( QByteArray hash );
++	bool m_buddyIconDirty;
++	
+ 	bool m_requestingNickname;
+ 	ICQProtocol *mProtocol;
+ 	ICQUserInfoWidget* m_infoWidget;
+@@ -97,10 +100,12 @@
+ 	KAction *actionRequestAuth;
+ 	KAction *actionSendAuth;
+     KAction *m_selectEncoding;
++	
++	KToggleAction *m_actionIgnore;
++	KToggleAction *m_actionVisibleTo;
++	KToggleAction *m_actionInvisibleTo;
++
+ 	/*
+-	KToggleAction *actionIgnore;
+-	KToggleAction *actionVisibleTo;
+-
+ 	bool mInvisible;
+ 	*/
+ 
+@@ -133,14 +138,17 @@
+     void changeContactEncoding();
+     void changeEncodingDialogClosed( int );
+ 
++	void requestBuddyIcon();
++	void haveIcon( const QString&, QByteArray );
+ 	void receivedStatusMessage( const QString &contact, const QString &message );
+ 	void receivedStatusMessage( const Oscar::Message &message );
+ 
+ //void slotCloseAwayMessageDialog();
+ 	//void slotReadAwayMessage();
+ 
+-	//void slotIgnore();
+-	//void slotVisibleTo();
++	void slotIgnore();
++	void slotVisibleTo();
++	void slotInvisibleTo();
+ };
+ 
+ #endif
+--- kopete/protocols/Makefile.am	(revision 568672)
++++ kopete/protocols/Makefile.am	(revision 586398)
+@@ -14,4 +14,8 @@
+ TESTBED=testbed
+ endif
+ 
+-SUBDIRS = $(TESTBED) groupwise msn irc oscar yahoo sms $(JABBER) $(GADU) $(MEANWHILE)
++if include_smsgsm
++SMS=sms
++endif
++
++SUBDIRS = $(TESTBED) groupwise msn irc oscar yahoo winpopup $(SMS) $(JABBER) $(GADU) $(MEANWHILE)
+--- kopete/protocols/configure.in.bot	(revision 568672)
++++ kopete/protocols/configure.in.bot	(revision 586398)
+@@ -2,14 +2,6 @@
+ # include_jabber_TRUE = #
+ # the following test will then issue a warning at the end of configure output
+ # so users see it more easily
+-if test -n "$include_jabber_TRUE"; then
+-  echo ""
+-  echo "You're missing libidn(-dev). The Kopete Jabber plugin has been"
+-  echo "excluded from compilation."
+-  echo ""
+-  all_tests=bad
+-fi
+-
+ if test "$have_glib" = no; then
+   echo ""
+   echo "You're missing glib >= 2.0 and its development files. Kopete's MSN"
+--- kopete/protocols/meanwhile/meanwhilelibrary.cpp	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhilelibrary.cpp	(revision 586398)
+@@ -1,777 +0,0 @@
+-/*
+-    meanwhilelibrary.cpp - interface to the 'C' meanwhile library
+-
+-    Copyright (c) 2003-2004 by Sivaram Gottimukkala  <suppandi at gmail.com>
+-    Copyright (c) 2005      by Jeremy Kerr <jk at ozlabs.org>
+-
+-    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at 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 <string.h>
+-#include <stdlib.h>
+-#include <kmessagebox.h>
+-#include <klocale.h>
+-
+-#include <kopetepassword.h>
+-#include "meanwhilelibrary.h"
+-#include "meanwhileprotocol.h"
+-
+-extern "C"
+-{
+-#include <meanwhile/mw_channel.h>
+-#include <meanwhile/mw_message.h>
+-#include <meanwhile/mw_error.h>
+-#include <meanwhile/mw_service.h>
+-#include <meanwhile/mw_session.h>
+-#include <meanwhile/mw_srvc_aware.h>
+-#include <meanwhile/mw_srvc_conf.h>
+-#include <meanwhile/mw_srvc_im.h>
+-#include <meanwhile/mw_cipher.h>
+-}
+-
+-#define ADVERTISE_KOPETE(s) (s+" *using kopete")
+-
+-/* for these macros:
+- *  func - the name of the function
+- *  args - the full arguments (including type) of the member (and static)
+- *         function. Must be enclosed in brackets. The first argument will be
+- *         used to get a reference to the library - it must be named as per
+- *         the last word of the macro name (but in lower case)
+- *  call - the arguments to the call to the non-static function. This is the
+- *         same as 'args', but without the type delcarations
+- */
+- 
+-#define MEANWHILE_HOOK_SESSION(func, args, call)                     \
+-void MeanwhileLibrary::_ ## func args                                \
+-{                                                                    \
+-    MeanwhileLibrary *lib = (MeanwhileLibrary *)                     \
+-        mwSession_getClientData(session);                            \
+-    if (lib)                                                         \
+-        lib-> func call;                                             \
+-    else                                                             \
+-        mwDebug() << "No client data for session in " #func << endl; \
+-}                                                                    \
+-void MeanwhileLibrary:: func args 
+-
+-#define MEANWHILE_HOOK_SERVICE(func, args, call)                     \
+-void MeanwhileLibrary::_ ## func args                                \
+-{                                                                    \
+-    MeanwhileLibrary *lib = (MeanwhileLibrary *)                     \
+-        mwService_getClientData((struct mwService *)service);        \
+-    if (lib)                                                         \
+-        lib-> func call;                                             \
+-    else                                                             \
+-        mwDebug() << "No client data for service in " #func << endl; \
+-}                                                                    \
+-void MeanwhileLibrary:: func args 
+-
+-#define MEANWHILE_HOOK_CONVERSATION(func, args, call)                \
+-void MeanwhileLibrary::_ ## func args                                \
+-{                                                                    \
+-    struct mwService *service = (struct mwService *)                 \
+-        mwConversation_getService(conv);                             \
+-    MeanwhileLibrary *lib = (MeanwhileLibrary *)                     \
+-        mwService_getClientData(service);                            \
+-    if (lib)                                                         \
+-        lib-> func call;                                             \
+-    else                                                             \
+-        mwDebug() << "No client data for conv. in " #func << endl;   \
+-}                                                                    \
+-void MeanwhileLibrary:: func args 
+-
+-void MeanwhileLibrary::_stateChange(struct mwSession *session,
+-        enum mwSessionState state, guint32 data)
+-{
+-    HERE;
+-    MeanwhileLibrary *lib =
+-        (MeanwhileLibrary *)mwSession_getClientData(session);
+-
+-    if (lib == 0L) {
+-        mwDebug() << "Invalid handler in stateChange callback"
+-            << endl;
+-        return;
+-    }
+-
+-    switch (state) {
+-        case mwSession_LOGIN_ACK:
+-            lib->session_loginAck(session);
+-            break;
+-
+-        case mwSession_STOPPED:
+-            lib->session_stop(session, data);
+-            break;
+-
+-        default:
+-            mwDebug() << "Unhandled state change " << state << endl;
+-    }
+-
+-}
+-
+-void MeanwhileLibrary::_handler_clear(struct mwSession *)
+-{
+-    HERE;
+-}
+-
+-void MeanwhileLibrary::session_loginAck(struct mwSession *s)
+-{
+-    HERE;
+-    connected = true;
+-    struct mwUserStatus stat = { mwStatus_ACTIVE, 0, 0L };
+-    mwSession_setUserStatus(s, &stat);
+-
+-    /* get own nickname */
+-    struct mwLoginInfo *logininfo = mwSession_getLoginInfo(s);
+-    if (logininfo) {
+-        mwDebug() << "got login info. username: " << logininfo->user_name <<
+-            ", nickname: " << getNickName(logininfo) << endl;
+-        account->myself()->setNickName(getNickName(logininfo));
+-    } else
+-        mwDebug() << "no login info" << endl;
+-
+-    emit loginDone();
+-}
+-
+-void MeanwhileLibrary::session_stop(struct mwSession *, unsigned int status)
+-{
+-    HERE;
+-    connected = false;
+-    if (status & ERR_FAILURE) {
+-        if (status == INCORRECT_LOGIN)
+-            account->password().setWrong();
+-        char *reason = mwError(status);
+-        emit serverNotification(QString(reason));
+-        free(reason);
+-    }
+-
+-    emit connectionLost();
+-}
+-
+-/* aware attribute handlers */
+-void MeanwhileLibrary::_on_attrib(struct mwServiceAware *,
+-        struct mwAwareAttribute *)
+-{
+-    HERE;
+-}
+-void MeanwhileLibrary::_attrib_clear(struct mwServiceAware *)
+-{
+-    HERE;
+-}
+-
+-/* aware list handlers */
+-void MeanwhileLibrary::_on_aware(struct mwAwareList *list,
+-        struct mwAwareSnapshot *id)
+-{
+-    HERE;
+-    MeanwhileLibrary *lib = (MeanwhileLibrary *)
+-        mwAwareList_getClientData(list);
+-    if (lib)
+-        lib->on_aware(list, id);
+-}
+-
+-#define STATUS(VALUE,onlinestatus)                        \
+-    (snapshot->status.status==MeanwhileLibrary::VALUE)?                    \
+-            MeanwhileProtocol::protocol()->onlinestatus:
+-void MeanwhileLibrary::on_aware(struct mwAwareList *,
+-        struct mwAwareSnapshot *snapshot)
+-{
+-    HERE;
+-    MeanwhileContact *contact = static_cast<MeanwhileContact *>
+-        (account->contacts()[snapshot->id.user]);
+-
+-    if (!contact)
+-        return;
+-    
+-    contact->setProperty(MeanwhileProtocol::protocol()->statusMessage, 
+-            snapshot->status.desc);
+-    contact->setProperty(MeanwhileProtocol::protocol()->awayMessage,
+-            snapshot->status.desc);
+-
+-    Kopete::OnlineStatus status;
+-    if (snapshot->online) {
+-        switch (snapshot->status.status) {
+-        case MeanwhileLibrary::Away:
+-            status = MeanwhileProtocol::protocol()->meanwhileAway;
+-            break;
+-        case MeanwhileLibrary::Active:
+-            status = MeanwhileProtocol::protocol()->meanwhileOnline;
+-            break;
+-        case MeanwhileLibrary::Idle:
+-            status = MeanwhileProtocol::protocol()->meanwhileIdle;
+-            break;
+-        case MeanwhileLibrary::Busy:
+-            status = MeanwhileProtocol::protocol()->meanwhileBusy;
+-            break;
+-        default:
+-            status = MeanwhileProtocol::protocol()->meanwhileUnknown;
+-        }
+-    } else {
+-        status = MeanwhileProtocol::protocol()->meanwhileOffline;
+-    }
+-    contact->setOnlineStatus(status);
+-
+-#if 0
+-    /* Commented out in previous kopete/meanwhile plugin for some reason,
+-     * but has still been ported to the new API.
+-     */
+-    time_t idletime = 0;
+-    if (snapshot->status.status == mwStatus_IDLE) {
+-    	idletime = (snapshot->status.time == 0xdeadbeef) ?
+-            0 : snapshot->status.time;
+-        if (idletime != 0) {
+-        contact->setStatusDescription(statusDesc + "[" +
+-                QString::number(idletime/60)+" mins]");
+-        }
+-    } else
+-        contact->setStatusDescription(snapshot->status.desc);
+-#endif
+-}
+-
+-void MeanwhileLibrary::_on_aware_attrib(struct mwAwareList *,
+-        struct mwAwareIdBlock *,
+-        struct mwAwareAttribute *)
+-{
+-    mwDebug() << "_on_aware_attrib() called" << endl;
+-}
+-void MeanwhileLibrary::_aware_clear(struct mwAwareList *)
+-{
+-    mwDebug() << "_aware_clear() called" << endl;
+-}
+-
+-QString MeanwhileLibrary::getNickName(struct mwLoginInfo *logininfo)
+-{
+-    if (logininfo == 0L || logininfo->user_name == 0L)
+-        return QString::null;
+-
+-    /* try to find a friendly name. From what I've seen, usernames are in
+-     * the format:
+-     *  <userid> - <name>/<domain>/<domain>
+-     */
+-    QString name = logininfo->user_name;
+-    int index = name.find(" - ");
+-    if (index != -1)
+-        name = name.remove(0, index + 3);
+-    index = name.find('/');
+-    if (index != -1)
+-        name = name.left(index);
+-    
+-    return name;
+-}
+-
+-MeanwhileContact *MeanwhileLibrary::convContact(
+-        struct mwConversation *conv)
+-{
+-    struct mwIdBlock *target = mwConversation_getTarget(conv);
+-    if (target == 0L || target->user == 0L) {
+-        return 0L;
+-    }
+-    QString user(target->user);
+-
+-    MeanwhileContact *contact =
+-        static_cast<MeanwhileContact *>(account->contacts()[user]);
+-
+-    if (!contact) {
+-        struct mwLoginInfo *logininfo = mwConversation_getTargetInfo(conv);
+-        QString name = getNickName(logininfo);
+-	account->addContact(user, name, 0L, Kopete::Account::Temporary);
+-        contact = static_cast<MeanwhileContact *>(account->contacts()[user]);
+-    }
+-
+-    return contact;
+-}
+-
+-struct MeanwhileLibrary::conv_data *MeanwhileLibrary::initConvData(
+-        struct mwConversation *conv, MeanwhileContact *contact)
+-{
+-    struct conv_data *conv_data = (struct conv_data *)malloc(sizeof *conv_data);
+-    if (!conv_data)
+-        return 0L;
+-
+-    conv_data->library = this;
+-    /* grab a manager from the factory instead? */
+-    conv_data->chat = contact->manager();
+-    conv_data->chat->ref();
+-    conv_data->queue = new QValueList<Kopete::Message>();
+-
+-    mwConversation_setClientData(conv, conv_data, 0L);
+-
+-    return conv_data;
+-}
+-
+-/* conversation */
+-MEANWHILE_HOOK_CONVERSATION(conversation_opened,
+-    (struct mwConversation *conv),
+-    (conv))
+-{
+-    HERE;
+-    MeanwhileContact *contact = convContact(conv);
+-    if (!contact) {
+-        mwDebug() << "Couldn't find contact!" << endl;
+-        return;
+-    }
+-
+-    struct conv_data *conv_data =
+-        (struct conv_data *)mwConversation_getClientData(conv);
+-
+-    if (!conv_data && !(conv_data = initConvData(conv, contact))) {
+-        return;
+-
+-    } else if (conv_data->queue && !conv_data->queue->isEmpty()) {
+-        /* send any messages that were waiting for the conversation to open */
+-        QValueList<Kopete::Message>::iterator it;
+-        for (it = conv_data->queue->begin(); it != conv_data->queue->end();
+-                ++it) {
+-            mwConversation_send(conv, mwImSend_PLAIN,
+-                    (*it).plainBody().ascii());
+-            conv_data->chat->appendMessage(*it);
+-            conv_data->chat->messageSucceeded();
+-        }
+-        conv_data->queue->clear();
+-    }
+-}
+-
+-MEANWHILE_HOOK_CONVERSATION(conversation_closed,
+-    (struct mwConversation *conv, guint32 err),
+-    (conv, err))
+-{
+-    HERE;
+-    /* @todo err is unused. This'll eat the warning */
+-    err = 0;
+-    struct conv_data *conv_data =
+-        (struct conv_data *)mwConversation_getClientData(conv);
+-
+-    if (!conv_data)
+-        return;
+-
+-    mwConversation_setClientData(conv, 0L, 0L);
+-    MeanwhileContact *contact = convContact(conv);
+-    if (!contact) {
+-        mwDebug() << "Couldn't find contact!" << endl;
+-        return;
+-    }
+-
+-    conv_data->chat->removeContact(contact);
+-    conv_data->chat->deref();
+-    conv_data->chat = 0L;
+-    free(conv_data);
+-}
+-
+-MEANWHILE_HOOK_CONVERSATION(conversation_recv,
+-    (struct mwConversation *conv, enum mwImSendType type,
+-        gconstpointer msg),
+-    (conv, type, msg))
+-{
+-    HERE;
+-    struct conv_data *conv_data =
+-        (struct conv_data *)mwConversation_getClientData(conv);
+-
+-    if (!conv_data)
+-        return;
+-
+-    MeanwhileContact *contact = convContact(conv);
+-    if (!contact) {
+-        mwDebug() << "Couldn't find contact!" << endl;
+-        return;
+-    }
+-
+-    switch (type) {
+-    case mwImSend_PLAIN:
+-        {
+-            Kopete::Message message(contact, account->myself(),
+-                    QString((char *)msg), Kopete::Message::Inbound);
+-            conv_data->chat->appendMessage(message);
+-        }
+-        break;
+-    case mwImSend_TYPING:
+-        conv_data->chat->receivedTypingMsg(contact);
+-        break;
+-    default:
+-        mwDebug() << "Unable to handle message type " << type << endl;
+-    }
+-}
+-
+-MEANWHILE_HOOK_SESSION(setUserStatus,
+-        (struct mwSession *session),
+-        (session))
+-{
+-    struct mwLoginInfo *login;
+-    struct mwUserStatus *status;
+-
+-    HERE;
+-    login = mwSession_getLoginInfo(session);
+-    status = mwSession_getUserStatus(session);
+-
+-    mwDebug() << "meanwhile status for " <<
+-        ((login->user_id==0L) ?
+-             "null" : login->user_id) <<
+-        " changed to " << (status->status) << endl;
+-
+-    struct mwAwareIdBlock id = { 
+-        mwAware_USER,
+-        login->user_id, 
+-        login->community 
+-    };
+-
+-    mwServiceAware_setStatus(srvc_aware, &id, status);
+-}
+-
+-MeanwhileLibrary::MeanwhileLibrary(MeanwhileAccount *a)
+-{
+-    HERE;
+-    account = a;
+-    session = 0L;
+-    connected = false;
+-}
+-
+-MeanwhileLibrary::~MeanwhileLibrary()
+-{
+-    HERE;
+-    if (connected)
+-        logoff();
+-    if (session)
+-        mwSession_free(session);
+-    if (socket)
+-        delete socket; 
+-}
+-
+-bool MeanwhileLibrary::isConnected()
+-{
+-    HERE;
+-    return connected;
+-}
+-
+-void MeanwhileLibrary::login()
+-{
+-    HERE;
+-    socket = getConnectedSocket();
+-    if (socket == 0L) {
+-        mwDebug() << "getConnectedSocket failed" << endl;
+-        return;
+-    }
+-
+-    newSession();
+-    mwSession_setProperty(session, mwSession_AUTH_USER_ID,
+-                    strdup(account->accountId().ascii()), 0L);
+-    mwSession_setProperty(session, mwSession_AUTH_PASSWORD,
+-                    strdup(account->password().cachedValue().ascii()), 0L);
+-
+-    mwSession_start(session);
+-}
+-
+-void MeanwhileLibrary::logoff()
+-{
+-    HERE;
+-    if (connected) {
+-        mwSession_stop(session, ERR_SUCCESS);
+-    }
+-}
+-
+-int MeanwhileLibrary::_writeToSocket(struct mwSession *session,
+-    const char *buffer, gsize count)
+-{
+-    HERE;
+-    MeanwhileLibrary *lib = 
+-        (MeanwhileLibrary *)mwSession_getClientData(session);
+-    return lib->writeToSocket(buffer, count);
+-}
+-
+-int MeanwhileLibrary::writeToSocket(const char *buffer, unsigned int count)
+-{
+-    HERE;
+-    int remaining, retval = 0;
+-    for (remaining = count; remaining > 0; remaining -= retval) {
+-        retval = socket->writeBlock(buffer, count);
+-        if (retval <= 0)
+-            return 1;
+-    }
+-    socket->flush();
+-    return 0;
+-}
+-
+-void MeanwhileLibrary::_closeSocket(struct mwSession *session) 
+-{
+-    HERE;
+-    MeanwhileLibrary *lib = 
+-        (MeanwhileLibrary *)mwSession_getClientData(session);
+-    return lib->closeSocket();
+-}
+-
+-void MeanwhileLibrary::closeSocket()
+-{
+-    HERE;
+-    QObject::disconnect(socket, SIGNAL(closed(int)),
+-                     this, SLOT(slotSocketClosed(int)));
+-    socket->flush();
+-    socket->closeNow();
+-}
+-
+-void MeanwhileLibrary::newSession()
+-{
+-    HERE;
+-    /* set up the session handler */
+-    memset(&session_handler, 0, sizeof(session_handler));
+-    session_handler.io_write       = _writeToSocket;
+-    session_handler.io_close       = _closeSocket;
+-    session_handler.clear          = _handler_clear;
+-    session_handler.on_stateChange = _stateChange;
+-
+-    /* create the session */
+-    session = mwSession_new(&session_handler);
+-    mwSession_setClientData(session, this, 0L);
+-
+-#if 0
+-    session->on_setUserStatus = _on_setUserStatus;
+-#endif
+-
+-    /* awareness service setup */
+-    aware_handler.on_attrib = _on_attrib;
+-    aware_handler.clear     = _attrib_clear;
+-    srvc_aware = mwServiceAware_new(session, &aware_handler);
+-
+-    aware_list_handler.on_aware = _on_aware;
+-    aware_list_handler.on_attrib = _on_aware_attrib;
+-    aware_list_handler.clear = _aware_clear;
+-
+-    aware_list = mwAwareList_new(srvc_aware, &aware_list_handler);
+-    mwAwareList_setClientData(aware_list, this, 0L);
+-
+-    mwService_setClientData((struct mwService *)srvc_aware, this, 0L);
+-    mwSession_addService(session, (struct mwService *) srvc_aware);
+-
+-    /* im service setup */
+-    im_handler.conversation_opened = _conversation_opened;
+-    im_handler.conversation_closed = _conversation_closed;
+-    im_handler.conversation_recv = _conversation_recv;
+-    im_handler.place_invite = 0L;
+-    im_handler.clear = 0L;
+-    
+-    srvc_im = mwServiceIm_new(session, &im_handler);
+-    mwService_setClientData((struct mwService *)srvc_im, this, 0L);
+-    mwSession_addService(session, (struct mwService *) srvc_im);
+-
+-#if 0
+-    /* FIXME: port to new API */
+-    /* conference */
+-    struct mwServiceConf *srvc_conf;
+-    srvc_conf = mwServiceConf_new(session);
+-    srvc_conf->got_invite = _got_invite;
+-    srvc_conf->got_welcome = _got_welcome;
+-    srvc_conf->got_closed = _got_closed;
+-    srvc_conf->got_join = _got_join;
+-    srvc_conf->got_part = _got_part;
+-    srvc_conf->got_text = _got_conf_text;
+-    srvc_conf->got_typing = _got_conf_typing;
+-    mwSession_putService(session, (struct mwService *) srvc_conf);
+-#endif
+-
+-    /* add a necessary cipher */
+-    mwSession_addCipher(session, mwCipher_new_RC2_40(session));
+-}
+-
+-KExtendedSocket *MeanwhileLibrary::getConnectedSocket()
+-{
+-    HERE;
+-    KExtendedSocket *sock = new KExtendedSocket(account->serverName(),
+-            account->serverPort(), KExtendedSocket::bufferedSocket);
+-    int error = sock->connect();
+-    if (error)
+-    {
+-        KMessageBox::queuedMessageBox( 
+-                        0, KMessageBox::Error , 
+-                        i18n( "Could not connect to server"),
+-                        i18n( "Meanwhile Plugin" ), 
+-                        KMessageBox::Notify );
+-        delete sock;
+-        return 0L;
+-    }
+-    /* we want to receive signals when there is data to read */
+-    sock->enableRead(true);
+-    QObject::connect(sock, SIGNAL(readyRead()) , 
+-                     SLOT(slotSocketReader()));
+-    QObject::connect(sock, SIGNAL(closed(int)),
+-                     SLOT(slotSocketClosed(int)));
+-    return sock;
+-}
+-
+-void MeanwhileLibrary::slotSocketReader()
+-{
+-    HERE;
+-    char buffer[4000];
+-    int readAmount;
+-    readAmount = socket->readBlock(buffer,4000);
+-    if (readAmount < 0)
+-        return;
+-    mwSession_recv(session, buffer, (unsigned int) readAmount);
+-}
+-
+-void MeanwhileLibrary::slotSocketClosed(int reason)
+-{
+-    HERE;
+-    connected = false;
+-    if (reason == KExtendedSocket::involuntary) { 
+-        emit serverNotification(
+-                QString("Lost connection with Meanwhile server"));
+-        emit connectionLost();
+-    }
+-}
+-
+-static void free_iter(void *data, void *p)
+-{
+-    if (p != 0L)
+-        return;
+-    free(data);
+-}
+-
+-void MeanwhileLibrary::addContacts(const QDict<Kopete::Contact>& contacts)
+-{
+-    HERE;
+-    QDictIterator<Kopete::Contact> it(contacts); 
+-    GList *buddies = 0L;
+-
+-    /** Convert our QDict of kopete contact to a GList of meanwhile buddies */
+-    for( ; it.current(); ++it) {
+-        struct mwAwareIdBlock *buddy = (struct mwAwareIdBlock *)
+-            malloc(sizeof(*buddy));
+-        MeanwhileContact *contact = 
+-                static_cast<MeanwhileContact *>(it.current());
+-        if (buddy == 0L)
+-            continue;
+-        buddy->user = (gchar*)contact->meanwhileId.ascii();
+-        buddy->community = 0L;
+-        buddy->type = mwAware_USER;
+-        mwDebug() << "Adding contact: '" << buddy->user << "'" << endl;
+-        buddies = g_list_append(buddies, buddy);
+-    }
+-
+-    mwAwareList_addAware(aware_list, buddies);
+-
+-    g_list_foreach(buddies, free_iter, 0L);
+-    g_list_free(buddies);
+-}
+-
+-void MeanwhileLibrary::addContact(const Kopete::Contact *contact)
+-{
+-    HERE;
+-    char *targetID = strdup(static_cast<const MeanwhileContact*>(contact)
+-            ->meanwhileId.ascii());
+-    struct mwAwareIdBlock buddy = 
+-		{ mwAware_USER, targetID, 0L };
+-    GList *buddies = 0L;
+-    g_list_insert(buddies, &buddy, 0);
+-    
+-    mwDebug() << "Adding contact: '" << buddy.user << "'" << endl;
+-    mwAwareList_addAware(aware_list, buddies);
+-    g_list_free(buddies);
+-    free(targetID);
+-}
+-
+-int MeanwhileLibrary::sendMessage(Kopete::Message &message)
+-{
+-    HERE;
+-    MeanwhileContact *contact =
+-        static_cast<MeanwhileContact *>(message.to().first());
+-    if (!contact) {
+-        mwDebug() << "No target for message!" <<endl;
+-        return 0;
+-    }
+-
+-    char *targetID = strdup(contact->meanwhileId.ascii());
+-    struct mwIdBlock target = { targetID, 0L };
+-    struct mwConversation *conv;
+-
+-    conv = mwServiceIm_getConversation(srvc_im, &target);
+-    if (conv == 0L) {
+-        mwDebug() << "No target for conversation with '" << targetID
+-            << "'" << endl;
+-        free(targetID);
+-        return 0;
+-    }
+-    free(targetID);
+-
+-    struct conv_data *conv_data = (struct conv_data *)
+-        mwConversation_getClientData(conv);
+-    if (!conv_data && !(conv_data = initConvData(conv, contact)))
+-        return 0;
+-
+-    /* if there's other messages in the queue, or the conversation isn't open,
+-     * then append to the queue instead of sending right away */
+-    if ((conv_data->queue && !conv_data->queue->isEmpty()) || 
+-            !mwConversation_isOpen(conv)) {
+-        conv_data->queue->append(message);
+-        mwConversation_open(conv);
+-
+-    } else if (!mwConversation_send(conv, mwImSend_PLAIN,
+-                message.plainBody().ascii())) {
+-        conv_data->chat->appendMessage(message);
+-        conv_data->chat->messageSucceeded();
+-    }
+-    return 1;
+-}
+-
+-void MeanwhileLibrary::sendTyping(MeanwhileContact *contact, bool isTyping)
+-{
+-    HERE;
+-    char *targetID = strdup(contact->meanwhileId.ascii());
+-    struct mwIdBlock target = { targetID, 0L };
+-    struct mwConversation *conv;
+-
+-    conv = mwServiceIm_getConversation(srvc_im, &target);
+-    if (conv == 0L) {
+-        mwDebug() << "No target for typing flag with '" << targetID << "'"
+-            << endl;
+-        free(targetID);
+-        return;
+-    }
+-    free(targetID);
+-
+-    if (mwConversation_isOpen(conv))
+-        mwConversation_send(conv, mwImSend_TYPING, (void *)isTyping);
+-}
+-
+-void MeanwhileLibrary::setState(Kopete::OnlineStatus state,
+-        const QString msg)
+-{
+-    HERE;
+-    if (state.internalStatus() == MeanwhileLibrary::Offline ||
+-            state.internalStatus() == 0)
+-        return;
+-
+-    struct mwUserStatus stat;
+-    mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
+-
+-    free(stat.desc);
+-
+-    stat.status = (mwStatusType)state.internalStatus();
+-    if (msg.isNull() || msg.isEmpty())
+-        stat.desc = (gchar*)strdup(state.description().ascii());
+-    else
+-        stat.desc = (gchar*)strdup(msg.ascii());
+-
+-    mwSession_setUserStatus(session,&stat);
+-    mwUserStatus_clear(&stat);
+-}
+-
+-void MeanwhileLibrary::setStatusMesg(const QString &statusMesg)
+-{
+-    HERE;
+-    if(statusMesg.isNull())
+-        return;
+-    struct mwUserStatus stat;
+-    mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
+-
+-    free(stat.desc);
+-    stat.desc = (gchar*)strdup(ADVERTISE_KOPETE(statusMesg).ascii());
+-
+-    mwSession_setUserStatus(session,&stat);
+-    mwUserStatus_clear(&stat);
+-}
+-
+-#include "meanwhilelibrary.moc"
+--- kopete/protocols/meanwhile/meanwhilelibrary.h	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhilelibrary.h	(revision 586398)
+@@ -1,295 +0,0 @@
+-/*
+-    meanwhilelibrary.h - interface to the 'C' meanwhile library
+-
+-    Copyright (c) 2003-2004 by Sivaram Gottimukkala  <suppandi at gmail.com>
+-    Copyright (c) 2005      by Jeremy Kerr <jk at ozlabs.org>
+-
+-    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at 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 MEANWHILELIBRARY_H
+-#define MEANWHILELIBRARY_H
+-
+-#include <qptrlist.h>
+-#include <qdict.h>
+-#include <qobject.h>
+-
+-#include <glib/ghash.h>
+-#include <kextsock.h>
+-
+-#include <kopetecontact.h>
+-#include <kopetechatsession.h>
+-#include <kopetemessage.h>
+-
+-#include "meanwhileaccount.h"
+-#include "meanwhilecontact.h"
+-
+-extern "C" {
+-#include <meanwhile/mw_session.h>
+-#include <meanwhile/mw_srvc_conf.h>
+-#include <meanwhile/mw_srvc_im.h>
+-#include <meanwhile/mw_srvc_aware.h>
+-}
+-
+-/**
+- * A class to handle the interface to the libmeanwhile code, currently using
+- * version 0.4.2
+- */
+-class MeanwhileLibrary : public QObject
+-{
+-    Q_OBJECT
+-
+-public:
+-    /**
+-     * Create a library. By default, the library is not connected - you will
+-     * need to call login() to initiate the connection process.
+-     * @param account The account that the connection is for
+-     */
+-    MeanwhileLibrary(MeanwhileAccount *account);
+-    
+-    /**
+-     * Destroy the library
+-     */
+-    ~MeanwhileLibrary();
+-
+-    /**
+-     * Determine whether the library is connected and logged in
+-     * @return true if there is a logged-in session with the meanwhile server
+-     */
+-    bool isConnected();
+-
+-    /**
+-     * Log in to the server. This will open a socket and start login. Note that
+-     * the connection process is ascychronous - a loginDone() signal will be
+-     * emitted when sucessfully logged in.
+-     */
+-    void login();
+-
+-    /**
+-     * Log off
+-     */
+-    void logoff();
+-
+-    /**
+-     * Register contacts for presence updates
+-     * @param contacts A set of contacts to add
+-     */
+-    void addContacts(const QDict<Kopete::Contact> &contacts);
+-
+-    /**
+-     * Register a single contact for presence awareness
+-     * @param contact a contact to add
+-     */
+-    void addContact(const Kopete::Contact *contact);
+-
+-    /**
+-     * Send a typing notification to a single contact
+-     * @param contact The contact that is being typed to
+-     * @param isTyping true if a typing message is to be sent
+-     */
+-    void sendTyping(MeanwhileContact *contact, bool isTyping);
+-
+-    /**
+-     * Send a message to a contact. If a conversation is not yet open to the
+-     * message's recipient, the message will be queued until a conversation has
+-     * become open (we also tell the conversation to open, so it should happen
+-     * in the near future). The library will call appendMessage() and
+-     * messageSuccceeded() when the message has been sent.
+-     * @param message The message to send
+-     * @return non-zero if the message was sent OK
+-     */
+-    int sendMessage(Kopete::Message &message);
+-
+-    /**
+-     * Set our (the local contact's) online status. The internalStatus of the
+-     * state argument will be used to define the state message we send - it
+-     * should be one of the Status enum fields (and not Offline)
+-     * @param state the new state of the local user
+-     * @param msg a custom message to use, if required
+-     */
+-    void setState(Kopete::OnlineStatus state,
+-            const QString msg = QString::null);
+-
+-    /**
+-     * Set the status description of the local user
+-     * @param statusMesg a description of the local sataus
+-     */
+-    void setStatusMesg(const QString &statusMesg);
+-
+-    /**
+-     * Allowed states for the meanwhile protocol.
+-     */
+-    enum Status {
+-        Active  = mwStatus_ACTIVE, /**< active/online */
+-        Away    = mwStatus_AWAY,   /**< away */
+-        Idle    = mwStatus_IDLE,   /**< idle */
+-        Busy    = mwStatus_BUSY,   /**< busy */
+-        Offline = 0xffff           /**< offline. */
+-    };
+-
+-signals:
+-    /**
+-     * Emitted when the login process is complete
+-     */
+-    void loginDone();
+-
+-    /**
+-     * Emitted when the connection to the server has been lost
+-     */
+-    void connectionLost();
+-
+-    /**
+-     * Emitted when a notification is received from the server, or other
+-     * out-of-band data (eg, the password is incorrect).
+-     * @param mesgString A description of the notification
+-     */
+-    void serverNotification(const QString &mesgString);
+-
+-
+-private:
+-    /** Session handler for general calls */
+-    struct mwSessionHandler   session_handler;
+-    /** Aware list changes */
+-    struct mwAwareListHandler aware_list_handler;
+-    /** Aware attribute changes */
+-    struct mwAwareHandler     aware_handler;
+-    /** Instant message handler */
+-    struct mwImHandler        im_handler;
+-
+-
+-    /* session handler callbacks */
+-    static void _stateChange(struct mwSession *s,
+-                    enum mwSessionState state, guint32 info);
+-
+-    static void _handler_clear(struct mwSession *s);
+-
+-    /* individual state change functions */
+-    void session_loginAck(mwSession *s);
+-    void session_stop(mwSession *s, unsigned int status);
+-
+-    static int _writeToSocket(struct mwSession *session,
+-                    const char *buffer, gsize count);
+-    int writeToSocket(const char *buffer, unsigned int count);
+-
+-    static void _closeSocket(struct mwSession *session);
+-    void closeSocket();
+-
+-#define DEFINE_MW_HOOK(func) \
+-static void _ ## func;   \
+-void func
+-
+-    DEFINE_MW_HOOK(setUserStatus(mwSession *s));
+-
+-    /* aware attribute handlers */
+-    static void _on_attrib(struct mwServiceAware *srvc,
+-            struct mwAwareAttribute *attrib);
+-    static void _attrib_clear(struct mwServiceAware *srvc);
+-
+-    /* aware list handlers */
+-    DEFINE_MW_HOOK(on_aware(struct mwAwareList *list,
+-            struct mwAwareSnapshot *id));
+-    static void _on_aware_attrib(struct mwAwareList *list,
+-            struct mwAwareIdBlock *id,
+-            struct mwAwareAttribute *attrib);
+-    static void _aware_clear(struct mwAwareList *list);
+-
+-    /* conversation handlers */
+-    DEFINE_MW_HOOK(conversation_opened(struct mwConversation *conv));
+-    DEFINE_MW_HOOK(conversation_closed(struct mwConversation *conv,
+-        guint32 err));
+-    DEFINE_MW_HOOK(conversation_recv(struct mwConversation *conv,
+-        enum mwImSendType type, gconstpointer msg));
+-
+-    /**
+-     * A structure to put into the private data of a conversation (and a
+-     * conference, later). Since the callbacks that we give to the
+-     * meanwhile library need to be static, we put a pointer to one of
+-     * these in the conversation's private data.
+-     */
+-    struct conv_data {
+-        MeanwhileLibrary  *library; /**< The library for this conv. */
+-        Kopete::ChatSession *chat;  /**< The chatsession for this conv. */
+-        QValueList<Kopete::Message> *queue; /**< Unsent message queue */
+-    };
+-
+-    /**
+-     * Convenience method to set a conversation's private data, with a new
+-     * conv_data struct. The conv_data should be free()ed when no longer
+-     * required.
+-     * @param conv The new conversation
+-     * @param contact The remote contact for this conversation
+-     * @return The new conv_data structure for this conversation
+-     */
+-    struct conv_data *initConvData(struct mwConversation *conv,
+-        MeanwhileContact *contact);
+-
+-    /**
+-     * Find the MeanwhileContact for a conversation
+-     * @param conv The conversation
+-     * @return the MeanwhileContact on the other side of this conversation
+-     */
+-    MeanwhileContact *convContact(struct mwConversation *conv);
+-
+-    /**
+-     * Parse a friendly name from a mwLoginInfo struct
+-     * @param logininfo The login info struct for the user
+-     * @return the user name (ie full name), or QString::null if none could
+-     *   be parsed.
+-     */
+-    static QString getNickName(struct mwLoginInfo *logininfo);
+-
+-    /**
+-     * Initialise the session handlers for a library.
+-     */
+-    void newSession();
+-
+-    /**
+-     * Create a connected socket to the server (defined by the account object)
+-     * @return a connected socket
+-     */
+-    KExtendedSocket *getConnectedSocket();
+-
+-
+-    /** The kopete account that this library is for */
+-    MeanwhileAccount *account;
+-
+-    /** The meanwhile session that we're connected to */
+-    struct mwSession *session;
+-
+-    /** The aware service */
+-    struct mwServiceAware *srvc_aware;
+-
+-    /** Aware list */
+-    struct mwAwareList *aware_list; 
+-
+-    /** IM service */
+-    struct mwServiceIm *srvc_im;
+-
+-    /** socket to the server */
+-    KExtendedSocket *socket;
+-
+-    /** connected (& logged in) flag */
+-    bool connected;
+-
+-private slots:
+-
+-    /** Notify the library that data is available on the socket */
+-    void slotSocketReader();
+-
+-    /**
+-     * Notify the library that the socket has been closed
+-     * @param reason the reason for closing
+-     */
+-    void slotSocketClosed(int reason);
+-};
+-
+-#endif
+-
+--- kopete/protocols/meanwhile/meanwhileprotocol.h	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhileprotocol.h	(revision 586398)
+@@ -1,6 +1,7 @@
+ /*
+     meanwhileprotocl.h - the meanwhile protocol definition
+ 
++    Copyright (c) 2005      by Jeremy Kerr <jk at ozlabs.org>
+     Copyright (c) 2003-2004 by Sivaram Gottimukkala  <suppandi at gmail.com>
+ 
+     Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
+@@ -22,6 +23,7 @@
+ #include "kopetecontact.h"
+ #include "kopetemetacontact.h"
+ #include "kopeteonlinestatus.h"
++#include "kopeteonlinestatusmanager.h"
+ #include "addcontactpage.h"
+ 
+ #include <kdebug.h>
+@@ -37,44 +39,39 @@
+ {
+     Q_OBJECT
+ public:
+-/* const */
+-    MeanwhileProtocol(QObject *parent, 
+-                      const char *name, 
+-                      const QStringList &args);
+-/* destructor */
++    MeanwhileProtocol(QObject *parent, const char *name,
++            const QStringList &args);
++
+     ~MeanwhileProtocol();
+-    
+-    virtual AddContactPage * createAddContactWidget( 
+-                                    QWidget *parent, 
+-                                    Kopete::Account *account );
+-                                    
+-    virtual KopeteEditAccountWidget * createEditAccountWidget( 
+-                                    Kopete::Account *account, 
+-                                    QWidget *parent );     
+ 
+-    virtual Kopete::Account * createNewAccount( 
+-                                    const QString &accountId );                               
++    virtual AddContactPage *createAddContactWidget(QWidget *parent,
++            Kopete::Account *account);
+ 
++    virtual KopeteEditAccountWidget *createEditAccountWidget(
++            Kopete::Account *account, QWidget *parent);
++
++    virtual Kopete::Account *createNewAccount(const QString &accountId);
++
+     virtual Kopete::Contact *deserializeContact(
+-                Kopete::MetaContact *metaContact,
+-                const QMap<QString,QString> &serializedData,
+-                const QMap<QString, QString> &addressBookData );
++            Kopete::MetaContact *metaContact,
++            const QMap<QString,QString> &serializedData,
++            const QMap<QString, QString> &addressBookData);
+ 
+-    /* kopete doesnt know about these funcs */
+-    static MeanwhileProtocol *protocol();
++    const Kopete::OnlineStatus accountOfflineStatus();
+ 
+-    const Kopete::OnlineStatus meanwhileOffline;
+-    const Kopete::OnlineStatus meanwhileOnline;
+-    const Kopete::OnlineStatus meanwhileAway;
+-    const Kopete::OnlineStatus meanwhileBusy;
+-    const Kopete::OnlineStatus meanwhileIdle;
+-    const Kopete::OnlineStatus meanwhileUnknown;
++    const Kopete::OnlineStatus lookupStatus(
++            enum Kopete::OnlineStatusManager::Categories cats);
+ 
+-    const Kopete::ContactPropertyTmpl statusMessage;
+-    const Kopete::ContactPropertyTmpl awayMessage;
++    const Kopete::OnlineStatus statusOffline;
++    const Kopete::OnlineStatus statusOnline;
++    const Kopete::OnlineStatus statusAway;
++    const Kopete::OnlineStatus statusBusy;
++    const Kopete::OnlineStatus statusIdle;
++    const Kopete::OnlineStatus statusAccountOffline;
+ 
+-protected:
+-    static MeanwhileProtocol *s_protocol;
++    Kopete::ContactPropertyTmpl statusMessage;
++    Kopete::ContactPropertyTmpl awayMessage;
++
+ };
+ 
+ #endif
+--- kopete/protocols/meanwhile/meanwhileeditaccountwidget.cpp	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhileeditaccountwidget.cpp	(revision 586398)
+@@ -48,8 +48,8 @@
+         mPasswordWidget->load(&static_cast<MeanwhileAccount*>(account())->password());
+         mAutoConnect->setChecked(account()->excludeConnect());
+         MeanwhileAccount *myAccount = static_cast<MeanwhileAccount *>(account());
+-        mServerName->setText(myAccount->serverName());
+-        mServerPort->setValue(myAccount->serverPort());
++        mServerName->setText(myAccount->getServerName());
++        mServerPort->setValue(myAccount->getServerPort());
+     }
+     else
+     {
+@@ -70,9 +70,7 @@
+ Kopete::Account* MeanwhileEditAccountWidget::apply()
+ {
+     if(!account())
+-        setAccount(
+-                new MeanwhileAccount( 
+-                        MeanwhileProtocol::protocol(), mScreenName->text()));
++        setAccount(new MeanwhileAccount(protocol, mScreenName->text()));
+ 
+     MeanwhileAccount *myAccount = static_cast<MeanwhileAccount *>(account());
+ 
+--- kopete/protocols/meanwhile/kopete_meanwhile.desktop	(revision 568672)
++++ kopete/protocols/meanwhile/kopete_meanwhile.desktop	(revision 586398)
+@@ -6,8 +6,8 @@
+ ServiceTypes=Kopete/Protocol
+ X-KDE-Library=kopete_meanwhile
+ X-Kopete-Messaging-Protocol=messaging/meanwhile
+-X-KDE-PluginInfo-Author=Sivaram Gottimukkala
+-X-KDE-PluginInfo-Email=sivaram at somewhere.net
++X-KDE-PluginInfo-Author=Jeremy Kerr
++X-KDE-PluginInfo-Email=jk at ozlabs.org
+ X-KDE-PluginInfo-Name=kopete_meanwhile
+ X-KDE-PluginInfo-Version=0.0.1
+ X-KDE-PluginInfo-Website=http://kopete.kde.org
+@@ -21,46 +21,22 @@
+ Name[nb]=Imens
+ Name[sk]=Medzitým
+ Name[ta]=இடைப்பட்ட பொழுதில்
+-Comment=Meanwhile protocol plugin
+-Comment[bg]=Протокол за връзка с Meanwhile
+-Comment[bn]=Meanwhile প্রোটোকল প্লাগিন
+-Comment[bs]=Dodatak za Meanwhile protokol
+-Comment[ca]=Connector de protocol Meanwhile
+-Comment[cs]=Modul protokolu Meanwhile
+-Comment[da]=Meanwhile-protokol-plugin
+-Comment[de]=Meanwhile Protokoll-Modul
+-Comment[el]=Πρόσθετο του πρωτοκόλλου Meanwhile
+-Comment[es]=Plugin del protocolo de Meanwhile
+-Comment[et]=Meanwhile protokolli plugin
+-Comment[eu]=Meanwhile protokolo plugin-a
+-Comment[fi]=Meanwhile-yhteyskäytäntöliitännäinen
+-Comment[fr]=Module du protocole Meanwhile
+-Comment[gl]=Plugin para o protocolo Meanwhile
+-Comment[he]=תוסף פרוטוקול של Meanwhile
+-Comment[hu]=Meanwhile modul
+-Comment[is]=Á meðan samskiptureglu íforrit
+-Comment[it]=Plugin del protocollo di Meanwhile
+-Comment[ja]=Meanwhile プロトコル プラグイン
+-Comment[km]=កម្មវិធី​ជំនួយ​ពិធីការ Meanwhile
+-Comment[lt]=Meanwhile protokolo įskiepis
+-Comment[nb]=Programtillegg for Imens-protokoll
+-Comment[nds]=Protokoll-Moduul för Meanwhile
+-Comment[nl]=Procotol voor Meanwhile
+-Comment[nn]=Programtillegg for Meanwhile-protokollen
+-Comment[pl]=Wtyczka protokołu Meanwhile
+-Comment[pt]='Plugin' de protocolo Meanwhile
+-Comment[pt_BR]=Plugin para o protocolo Meanwhile
+-Comment[ro]=Modul de protocol Meanwhile
+-Comment[ru]=Модуль протокола Meanwhile
+-Comment[sk]=Modul protokolu Medzitým
+-Comment[sl]=Vstavek za protokol Meanwhile
+-Comment[sr]=Прикључак за протокол Meanwhile
+-Comment[sr at Latn]=Priključak za protokol Meanwhile
+-Comment[sv]=Meanwhile-protokollinsticksprogram
+-Comment[ta]=இடைப்பட்ட நெறிமுறை சொருகுப்பொருள்
+-Comment[tr]=Meanwhile iletişim kuralı eklentisi
+-Comment[uk]=Втулок протоколу для Meanwhile
+-Comment[uz]=Meanwhile учун протокол
+-Comment[zh_CN]=Meanwhile 协议插件
+-Comment[zh_HK]=Meanwhile 通訊協定插件
+-Comment[zh_TW]=Meanwhile 協定外掛程式
++Comment=Meanwhile (Lotus Sametime) Protocol
++Comment[ca]=Protocol Meanwhile (Lotus Sametime)
++Comment[da]=Meanwhile-protokol (Lotus Sametime)
++Comment[el]=Πρρωτόκολλο Meanwhile (Lotus Sametime)
++Comment[es]=Protocolo Meanwhile (Lotus Sametime)
++Comment[et]=Meanwhile (Lotus Sametime) protokoll
++Comment[fr]=Protocole Meanwhile (Lotus Sametime)
++Comment[he]=פרוטוקול Meanwhile
++Comment[is]="Meanwhile" (Lotus Sametimr) samskipturegla
++Comment[ja]=Meanwhile (Lotus Sametime) プロトコル
++Comment[nds]=Meanwhile-Protokoll (Lotus Sametime)
++Comment[nl]=Procotol voor Meanwhile (Lotus Sametime)
++Comment[pt]=Protocolo Meanwhile (Lotus Sametime)
++Comment[pt_BR]=Protocolo Meanwhile (Lotus Sametime)
++Comment[sk]=Meanwhile (Lotus Sametime) Protokol
++Comment[sl]=Protokol Meanwhile (Lotus Sametime)
++Comment[sv]=Meanwhile-protokoll (Lotus Sametime)
++Comment[uk]=Протокол Meanwhile (Lotus Sametime)
++Comment[zh_TW]=Meanwhile (Lotus Sametime)協定外掛程式
+--- kopete/protocols/meanwhile/meanwhilesession.cpp	(revision 0)
++++ kopete/protocols/meanwhile/meanwhilesession.cpp	(revision 586398)
+@@ -0,0 +1,899 @@
++/*
++    meanwhilesession.cpp - interface to the 'C' meanwhile library
++
++    Copyright (c) 2003-2004 by Sivaram Gottimukkala  <suppandi at gmail.com>
++    Copyright (c) 2005      by Jeremy Kerr <jk at ozlabs.org>
++
++    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at 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 <string.h>
++#include <stdlib.h>
++#include <kmessagebox.h>
++#include <klocale.h>
++
++#include <kopetepassword.h>
++#include <kopetechatsession.h>
++#include <kopetegroup.h>
++#include <kopetecontactlist.h>
++#include "meanwhilesession.h"
++#include "meanwhileprotocol.h"
++
++#include <mw_channel.h>
++#include <mw_message.h>
++#include <mw_error.h>
++#include <mw_service.h>
++#include <mw_session.h>
++#include <mw_srvc_aware.h>
++#include <mw_srvc_conf.h>
++#include <mw_srvc_im.h>
++#include <mw_srvc_store.h>
++#include <mw_cipher.h>
++#include <mw_st_list.h>
++
++#define set_session_handler(a,b) sessionHandler.a = _handleSession ## b
++#define set_aware_handler(a,b)   awareHandler.a = _handleAware ## b
++#define set_aware_list_handler(a,b) \
++    awareListHandler.a = _handleAwareList ## b
++#define set_im_handler(a,b)   imHandler.a = _handleIm ## b
++
++#define get_protocol() (static_cast<MeanwhileProtocol *>(account->protocol()))
++
++MeanwhileSession::MeanwhileSession(MeanwhileAccount *account)
++{
++    HERE;
++    this->account = account;
++    session = 0L;
++    socket = 0L;
++    state = mwSession_STOPPED;
++
++    /* set up main session hander */
++    memset(&sessionHandler, 0, sizeof(sessionHandler));
++    set_session_handler(io_write,          IOWrite);
++    set_session_handler(io_close,          IOClose);
++    set_session_handler(on_stateChange,    StateChange);
++    set_session_handler(on_setPrivacyInfo, SetPrivacyInfo);
++    set_session_handler(on_setUserStatus,  SetUserStatus);
++    set_session_handler(on_admin,          Admin);
++    set_session_handler(on_announce,       Announce);
++    set_session_handler(clear,             Clear);
++
++    session = mwSession_new(&sessionHandler);
++    mwSession_setClientData(session, this, 0L);
++
++    /* set up the aware service */
++    memset(&awareHandler, 0, sizeof(awareHandler));
++    set_aware_handler(on_attrib, Attrib);
++
++    awareService = mwServiceAware_new(session, &awareHandler);
++    mwSession_addService(session, (struct mwService *)awareService);
++
++    /* create an aware list */
++    memset(&awareListHandler, 0, sizeof(awareListHandler));
++    set_aware_list_handler(on_aware,  Aware);
++    set_aware_list_handler(on_attrib, Attrib);
++    awareList = mwAwareList_new(awareService, &awareListHandler);
++    mwAwareList_setClientData(awareList, this, 0L);
++
++    /* set up an im service */
++    memset(&imHandler, 0, sizeof(imHandler));
++    set_im_handler(conversation_opened, ConvOpened);
++    set_im_handler(conversation_closed, ConvClosed);
++    set_im_handler(conversation_recv,   ConvReceived);
++    imHandler.place_invite = 0L;
++    imHandler.clear = 0L;
++
++    imService = mwServiceIm_new(session, &imHandler);
++    mwService_setClientData((struct mwService *)imService, this, 0L);
++    mwSession_addService(session, (struct mwService *) imService);
++
++    /* add resolve service */
++    resolveService = mwServiceResolve_new(session);
++    mwService_setClientData((struct mwService *)resolveService, this, 0L);
++    mwSession_addService(session, (struct mwService *) resolveService);
++
++    /* storage service */
++    storageService = mwServiceStorage_new(session);
++    mwService_setClientData((struct mwService *)storageService, this, 0L);
++    mwSession_addService(session, (struct mwService *) storageService);
++
++#if 0
++    /* conference service setup - just declines invites for now. */
++    memset(&conf_handler, 0, sizeof(conf_handler));
++    conf_handler.on_invited = _conference_invite;
++
++    srvc_conf = mwServiceConference_new(session, &conf_handler);
++    mwService_setClientData((struct mwService *)srvc_conf, this, 0L);
++    mwSession_addService(session, (struct mwService *) srvc_conf);
++#endif
++
++    /* add a necessary cipher */
++    mwSession_addCipher(session, mwCipher_new_RC2_40(session));
++}
++
++MeanwhileSession::~MeanwhileSession()
++{
++    HERE;
++    if (isConnected() || isConnecting())
++        disconnect();
++
++    mwSession_removeService(session, mwService_STORAGE);
++    mwSession_removeService(session, mwService_RESOLVE);
++    mwSession_removeService(session, mwService_IM);
++    mwSession_removeService(session, mwService_AWARE);
++
++    mwAwareList_free(awareList);
++    mwService_free(MW_SERVICE(storageService));
++    mwService_free(MW_SERVICE(resolveService));
++    mwService_free(MW_SERVICE(imService));
++    mwService_free(MW_SERVICE(awareService));
++    mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
++
++    mwSession_free(session);
++
++    if (socket)
++        delete socket;
++}
++
++/* external interface called by meanwhileaccount */
++void MeanwhileSession::connect(QString host, int port,
++        QString account, QString password)
++{
++    HERE;
++
++    KExtendedSocket *sock = new KExtendedSocket(host, port,
++            KExtendedSocket::bufferedSocket);
++
++    if (sock->connect()) {
++        KMessageBox::queuedMessageBox(0, KMessageBox::Error,
++                i18n( "Could not connect to server"), i18n("Meanwhile Plugin"),
++                KMessageBox::Notify);
++        delete sock;
++        return;
++    }
++    socket = sock;
++    /* we want to receive signals when there is data to read */
++    sock->enableRead(true);
++    QObject::connect(sock, SIGNAL(readyRead()), this,
++                     SLOT(slotSocketDataAvailable()));
++    QObject::connect(sock, SIGNAL(closed(int)), this,
++                     SLOT(slotSocketClosed(int)));
++
++    mwSession_setProperty(session, mwSession_AUTH_USER_ID,
++                    g_strdup(account.ascii()), g_free);
++    mwSession_setProperty(session, mwSession_AUTH_PASSWORD,
++                    g_strdup(password.ascii()), g_free);
++
++    /* go!! */
++    mwSession_start(session);
++}
++
++void MeanwhileSession::disconnect()
++{
++    HERE;
++    if (state == mwSession_STOPPED || state == mwSession_STOPPING)
++        return;
++
++    mwSession_stop(session, ERR_SUCCESS);
++}
++
++bool MeanwhileSession::isConnected()
++{
++	return mwSession_isStarted(session);
++}
++
++bool MeanwhileSession::isConnecting()
++{
++	return mwSession_isStarting(session);
++}
++
++static void free_id_block(void *data, void *p)
++{
++    if (p != 0L || data == 0L)
++        return;
++    struct mwAwareIdBlock *id = (struct mwAwareIdBlock *)data;
++    free(id->user);
++    free(id);
++}
++
++void MeanwhileSession::addContacts(const QDict<Kopete::Contact>& contacts)
++{
++    HERE;
++    QDictIterator<Kopete::Contact> it(contacts);
++    GList *buddies = 0L;
++
++    /** Convert our QDict of kopete contact to a GList of meanwhile buddies */
++    for( ; it.current(); ++it) {
++        MeanwhileContact *contact =
++                static_cast<MeanwhileContact *>(it.current());
++        struct mwAwareIdBlock *id = (struct mwAwareIdBlock *)
++            malloc(sizeof(*id));
++        if (id == 0L)
++            continue;
++        id->user = strdup(contact->meanwhileId().ascii());
++        id->community = 0L;
++        id->type = mwAware_USER;
++        buddies = g_list_append(buddies, id);
++    }
++
++    mwAwareList_addAware(awareList, buddies);
++
++    g_list_foreach(buddies, free_id_block, 0L);
++    g_list_free(buddies);
++}
++
++/* private functions used only by the meanwhile session object */
++void MeanwhileSession::addContact(const Kopete::Contact *contact)
++{
++    HERE;
++    struct mwAwareIdBlock id = { mwAware_USER,
++        strdup(static_cast<const MeanwhileContact *>(contact)
++                ->meanwhileId().ascii()),
++        0L };
++
++    GList *buddies = g_list_prepend(0L, &id);
++    mwAwareList_addAware(awareList, buddies);
++    g_list_free(buddies);
++    free(id.user);
++}
++
++int MeanwhileSession::sendMessage(Kopete::Message &message)
++{
++    HERE;
++    MeanwhileContact *contact =
++        static_cast<MeanwhileContact *>(message.to().first());
++    if (!contact) {
++        mwDebug() << "No target for message!" <<endl;
++        return 0;
++    }
++
++    struct mwIdBlock target = { strdup(contact->meanwhileId().ascii()), 0L };
++    struct mwConversation *conv;
++
++    conv = mwServiceIm_getConversation(imService, &target);
++    free(target.user);
++    if (conv == 0L) {
++        mwDebug() << "No target for conversation with '"
++            << contact->meanwhileId() << "'" << endl;
++        return 0;
++    }
++
++    struct ConversationData *convdata = (struct ConversationData *)
++        mwConversation_getClientData(conv);
++
++    if (convdata == 0L) {
++        convdata = createConversationData(conv, contact, true);
++        if (convdata == 0L) {
++            mwDebug() << "No memory for conversation data!" << endl;
++            return 0;
++        }
++    }
++
++    /* if there's other messages in the queue, or the conversation isn't open,
++     * then append to the queue instead of sending right away */
++    if ((convdata->queue && !convdata->queue->isEmpty()) ||
++            !mwConversation_isOpen(conv)) {
++        convdata->queue->append(message);
++        mwConversation_open(conv);
++
++    } else if (!mwConversation_send(conv, mwImSend_PLAIN,
++                message.plainBody().ascii())) {
++        convdata->chat->appendMessage(message);
++        convdata->chat->messageSucceeded();
++    }
++    return 1;
++}
++
++void MeanwhileSession::sendTyping(MeanwhileContact *contact, bool isTyping)
++{
++    HERE;
++    struct mwIdBlock target = { strdup(contact->meanwhileId().ascii()), 0L };
++    struct mwConversation *conv;
++
++    conv = mwServiceIm_getConversation(imService, &target);
++    free(target.user);
++    if (conv == 0L)
++        return;
++
++    if (mwConversation_isOpen(conv))
++        mwConversation_send(conv, mwImSend_TYPING, (void *)isTyping);
++}
++
++void MeanwhileSession::setStatus(Kopete::OnlineStatus status,
++        const QString msg)
++{
++    HERE;
++    mwDebug() << "setStatus: " << status.description() << "("
++        << status.internalStatus() << ")" << endl;
++    if (status.internalStatus() == 0)
++        return;
++
++    struct mwUserStatus stat;
++    mwUserStatus_clone(&stat, mwSession_getUserStatus(session));
++
++    free(stat.desc);
++
++    stat.status = (mwStatusType)status.internalStatus();
++    if (msg.isNull() || msg.isEmpty())
++        stat.desc = strdup(status.description().ascii());
++    else
++        stat.desc = strdup(msg.ascii());
++
++    mwSession_setUserStatus(session, &stat);
++    /* will free stat.desc */
++    mwUserStatus_clear(&stat);
++}
++
++void MeanwhileSession::syncContactsToServer()
++{
++    HERE;
++    struct mwSametimeList *list = mwSametimeList_new();
++
++    /* set up a fallback group for top-level contacts */
++    struct mwSametimeGroup *topstgroup = mwSametimeGroup_new(list,
++            mwSametimeGroup_DYNAMIC, "People");
++    mwSametimeGroup_setOpen(topstgroup, true);
++
++    QDictIterator<Kopete::Contact> it(account->contacts());
++    for( ; it.current(); ++it ) {
++        MeanwhileContact *contact =
++            static_cast<MeanwhileContact *>(it.current());
++
++        /* Find the group that the metacontact is in */
++        Kopete::MetaContact *mc = contact->metaContact();
++        /* myself doesn't have a metacontact */
++        if (mc == 0L)
++            continue;
++
++        Kopete::Group *contactgroup = mc->groups().getFirst();
++        if (contactgroup == 0L)
++            continue;
++
++        if (contactgroup->type() == Kopete::Group::Temporary)
++            continue;
++
++        struct mwSametimeGroup *stgroup;
++        if (contactgroup->type() == Kopete::Group::TopLevel) {
++            stgroup = topstgroup;
++        } else  {
++            /* find (or create) a matching sametime list group */
++            stgroup = mwSametimeList_findGroup(list,
++                        contactgroup->displayName().ascii());
++            if (stgroup == 0L) {
++                stgroup = mwSametimeGroup_new(list, mwSametimeGroup_DYNAMIC,
++                        contactgroup->displayName().ascii());
++            }
++            mwSametimeGroup_setOpen(stgroup, contactgroup->isExpanded());
++            mwSametimeGroup_setAlias(stgroup,
++                    contactgroup->pluginData(account->protocol(), "alias")
++                    .ascii());
++        }
++
++        /* now add the user (by IDBlock) */
++        struct mwIdBlock id =
++            { (gchar*)contact->meanwhileId().ascii(), 0L };
++        struct mwSametimeUser *stuser = mwSametimeUser_new(stgroup,
++                mwSametimeUser_NORMAL, &id);
++
++        mwSametimeUser_setAlias(stuser, contact->nickName().ascii());
++    }
++
++    /* store! */
++    struct mwPutBuffer *buf = mwPutBuffer_new();
++    struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
++    struct mwOpaque *opaque = mwStorageUnit_asOpaque(unit);
++
++    mwSametimeList_put(buf, list);
++    mwPutBuffer_finalize(opaque, buf);
++
++    mwServiceStorage_save(storageService, unit, NULL, NULL, NULL);
++
++    mwSametimeList_free(list);
++}
++
++void MeanwhileSession::syncContactsFromServer()
++{
++    struct mwStorageUnit *unit = mwStorageUnit_new(mwStore_AWARE_LIST);
++    mwServiceStorage_load(storageService, unit, &_handleStorageLoad, 0L, 0L);
++}
++
++#define MEANWHILE_SESSION_BUFSIZ 4096
++
++void MeanwhileSession::slotSocketDataAvailable()
++{
++    HERE;
++    guchar *buf;
++    Q_LONG bytesRead;
++
++    if (socket == 0L)
++        return;
++
++    if (!(buf = (guchar *)malloc(MEANWHILE_SESSION_BUFSIZ))) {
++        mwDebug() << "buffer malloc failed" << endl;
++        return;
++    }
++
++    while (socket && socket->bytesAvailable() > 0) {
++        bytesRead = socket->readBlock((char *)buf, MEANWHILE_SESSION_BUFSIZ);
++        if (bytesRead < 0)
++            break;
++        mwSession_recv(session, buf, (unsigned int)bytesRead);
++    }
++    free(buf);
++}
++
++void MeanwhileSession::slotSocketClosed(int reason)
++{
++    HERE;
++
++    if (reason & KExtendedSocket::involuntary)
++        emit serverNotification(
++                QString("Lost connection with Meanwhile server"));
++
++    if (socket) {
++        delete socket;
++        socket = 0L;
++    }
++
++    mwSession_stop(session, 0x00);
++}
++
++
++Kopete::OnlineStatus MeanwhileSession::convertStatus(int mstatus)
++{
++    MeanwhileProtocol *protocol =
++        static_cast<MeanwhileProtocol *>(account->protocol());
++
++    switch (mstatus) {
++    case mwStatus_ACTIVE:
++        return protocol->statusOnline;
++        break;
++    case mwStatus_IDLE:
++        return protocol->statusIdle;
++        break;
++    case mwStatus_AWAY:
++        return protocol->statusAway;
++        break;
++    case mwStatus_BUSY:
++        return protocol->statusBusy;
++        break;
++    case 0:
++        return protocol->statusOffline;
++        break;
++    default:
++        mwDebug() << "unknown status lookup: " << mstatus << endl;
++    }
++    return protocol->statusOffline;
++}
++
++void MeanwhileSession::resolveContactNickname(MeanwhileContact *contact)
++{
++    /* @todo: FIXME: leak! */
++    char *id = strdup(contact->meanwhileId().ascii());
++    GList *query = g_list_prepend(NULL, id);
++    mwServiceResolve_resolve(resolveService, query, mwResolveFlag_USERS,
++            _handleResolveLookupResults, contact, NULL);
++}
++
++QString MeanwhileSession::getNickName(struct mwLoginInfo *logininfo)
++{
++    if (logininfo == 0L || logininfo->user_name == 0L)
++        return QString::null;
++    return getNickName(logininfo->user_name);
++}
++
++QString MeanwhileSession::getNickName(QString name)
++{
++
++    int index = name.find(" - ");
++    if (index != -1)
++        name = name.remove(0, index + 3);
++    index = name.find('/');
++    if (index != -1)
++        name = name.left(index);
++
++    return name;
++}
++
++MeanwhileContact *MeanwhileSession::conversationContact(
++        struct mwConversation *conv)
++{
++    struct mwIdBlock *target = mwConversation_getTarget(conv);
++    if (target == 0L || target->user == 0L) {
++        return 0L;
++    }
++    QString user(target->user);
++
++    MeanwhileContact *contact =
++        static_cast<MeanwhileContact *>(account->contacts()[user]);
++
++    struct mwLoginInfo *logininfo = mwConversation_getTargetInfo(conv);
++    QString name = getNickName(logininfo);
++
++    if (!contact) {
++	account->addContact(user, name, 0L, Kopete::Account::Temporary);
++        contact = static_cast<MeanwhileContact *>(account->contacts()[user]);
++    } else
++        contact->setNickName(name);
++
++    return contact;
++}
++
++/* priave session handling functions, called by libmeanwhile callbacks */
++void MeanwhileSession::handleSessionStateChange(
++        enum mwSessionState state, gpointer data)
++{
++    HERE;
++    this->state = state;
++
++    switch (state) {
++        case mwSession_STARTING:
++        case mwSession_HANDSHAKE:
++        case mwSession_HANDSHAKE_ACK:
++        case mwSession_LOGIN:
++        case mwSession_LOGIN_REDIR:
++        case mwSession_LOGIN_CONT:
++        case mwSession_LOGIN_ACK:
++            break;
++
++        case mwSession_STARTED:
++            {
++                struct mwUserStatus stat = { mwStatus_ACTIVE, 0, 0L };
++                mwSession_setUserStatus(session, &stat);
++                struct mwLoginInfo *logininfo = mwSession_getLoginInfo(session);
++                if (logininfo) {
++                    account->myself()->setNickName(getNickName(logininfo));
++                }
++                syncContactsFromServer();
++            }
++            break;
++
++        case mwSession_STOPPING:
++            {
++                unsigned int info = GPOINTER_TO_UINT(data);
++                if (info & ERR_FAILURE) {
++                    if (info == INCORRECT_LOGIN)
++                        account->password().setWrong();
++                    char *reason = mwError(info);
++                    emit serverNotification(QString(reason));
++                    free(reason);
++                }
++            }
++
++            emit sessionStateChange(
++                    static_cast<MeanwhileProtocol *>(account->protocol())
++		    ->statusOffline);
++            break;
++
++        case mwSession_STOPPED:
++            break;
++
++        case mwSession_UNKNOWN:
++        default:
++            mwDebug() << "Unhandled state change " << state << endl;
++    }
++}
++
++int MeanwhileSession::handleSessionIOWrite(const guchar *buffer,
++        gsize count)
++{
++    HERE;
++
++    if (socket == 0L)
++        return 1;
++
++    int remaining, retval = 0;
++    for (remaining = count; remaining > 0; remaining -= retval) {
++        retval = socket->writeBlock((char *)buffer, count);
++        if (retval <= 0)
++            return 1;
++    }
++    socket->flush();
++    return 0;
++}
++
++void MeanwhileSession::handleSessionAdmin(const char *text)
++{
++    HERE;
++    emit serverNotification(QString(text));
++}
++
++void MeanwhileSession::handleSessionAnnounce(struct mwLoginInfo *from,
++        gboolean /* may_reply */, const char *text)
++{
++    HERE;
++    QString message;
++    message.sprintf("Announcement from %s:\n%s", from->user_id, text);
++    emit serverNotification(message);
++}
++
++void MeanwhileSession::handleSessionSetUserStatus()
++{
++    struct mwUserStatus *userstatus = mwSession_getUserStatus(session);
++    emit sessionStateChange(convertStatus((unsigned int)userstatus->status));
++}
++
++void MeanwhileSession::handleSessionSetPrivacyInfo()
++{
++}
++
++void MeanwhileSession::handleSessionIOClose()
++{
++    HERE;
++
++    if (socket == 0L)
++        return;
++
++    QObject::disconnect(socket, SIGNAL(closed(int)),
++                     this, SLOT(slotSocketClosed(int)));
++    socket->flush();
++    socket->closeNow();
++
++    delete socket;
++    socket = 0L;
++}
++
++void MeanwhileSession::handleSessionClear()
++{
++}
++
++void MeanwhileSession::handleAwareAttrib(struct mwAwareAttribute * /* attrib */)
++{
++    HERE;
++}
++
++void MeanwhileSession::handleAwareListAware(struct mwAwareSnapshot *snapshot)
++{
++    HERE;
++    MeanwhileContact *contact = static_cast<MeanwhileContact *>
++        (account->contacts()[snapshot->id.user]);
++
++    if (contact == 0L)
++        return;
++
++    /* use the setUserStatus callback for status updates for myself. */
++    if (contact == account->myself())
++        return;
++
++    contact->setProperty(get_protocol()->statusMessage, snapshot->status.desc);
++    contact->setProperty(get_protocol()->awayMessage, snapshot->status.desc);
++
++    Kopete::OnlineStatus onlinestatus;
++    if (snapshot->online) {
++        onlinestatus = convertStatus(snapshot->status.status);
++        resolveContactNickname(contact);
++    } else {
++        onlinestatus = convertStatus(0);
++    }
++
++    contact->setOnlineStatus(onlinestatus);
++
++#if 0
++    /* Commented out in previous kopete/meanwhile plugin for some reason,
++     * but has still been ported to the new API.
++     */
++    time_t idletime = 0;
++    if (snapshot->status.status == mwStatus_IDLE) {
++	idletime = (snapshot->status.time == 0xdeadbeef) ?
++            0 : snapshot->status.time;
++        if (idletime != 0) {
++        contact->setStatusDescription(statusDesc + "[" +
++                QString::number(idletime/60)+" mins]");
++        }
++    } else
++        contact->setStatusDescription(snapshot->status.desc);
++#endif
++}
++
++void MeanwhileSession::handleAwareListAttrib(struct mwAwareIdBlock * /* id */,
++        struct mwAwareAttribute * /* attrib */)
++{
++    HERE;
++}
++
++struct MeanwhileSession::ConversationData
++    *MeanwhileSession::createConversationData(
++        struct mwConversation *conv, MeanwhileContact *contact,
++        bool createQueue)
++{
++    struct ConversationData *cd = new ConversationData();
++
++    if (cd == 0L)
++        return 0L;
++
++    cd->contact = contact;
++    cd->chat    = contact->manager(Kopete::Contact::CanCreate);
++    cd->chat->ref();
++    if (createQueue)
++        cd->queue = new QValueList<Kopete::Message>();
++
++    mwConversation_setClientData(conv, cd, 0L);
++
++    return cd;
++}
++
++void MeanwhileSession::handleImConvOpened(struct mwConversation *conv)
++{
++    HERE;
++
++    struct ConversationData *convdata =
++        (struct ConversationData *)mwConversation_getClientData(conv);
++
++    if (convdata == 0L) {
++        /* a new conversation */
++        convdata = createConversationData(conv, conversationContact(conv));
++
++        if (convdata == 0L) {
++            mwDebug() << "No memory for conversation data!" << endl;
++            return;
++        }
++
++    } else if (convdata->queue && !convdata->queue->isEmpty()) {
++        /* send any messages that were waiting for the conversation to open */
++        QValueList<Kopete::Message>::iterator it;
++        for (it = convdata->queue->begin(); it != convdata->queue->end();
++                ++it) {
++            mwConversation_send(conv, mwImSend_PLAIN,
++                    (*it).plainBody().ascii());
++            convdata->chat->appendMessage(*it);
++            convdata->chat->messageSucceeded();
++        }
++        convdata->queue->clear();
++        delete convdata->queue;
++        convdata->queue = 0L;
++    }
++    resolveContactNickname(convdata->contact);
++}
++
++void MeanwhileSession::handleImConvClosed(struct mwConversation *conv,
++        guint32)
++{
++    HERE;
++
++    ConversationData *convdata =
++        (ConversationData *)mwConversation_getClientData(conv);
++
++    if (!convdata)
++        return;
++
++    mwConversation_setClientData(conv, 0L, 0L);
++
++    convdata->chat->removeContact(convdata->contact);
++    convdata->chat->deref();
++    convdata->chat = 0L;
++    if (convdata->queue != 0L) {
++        convdata->queue->clear();
++        delete convdata->queue;
++        convdata->queue = 0L;
++    }
++    free(convdata);
++}
++
++void MeanwhileSession::handleImConvReceived(struct mwConversation *conv,
++        enum mwImSendType type, gconstpointer msg)
++{
++    HERE;
++    ConversationData *convdata =
++        (ConversationData *)mwConversation_getClientData(conv);
++
++    if (!convdata)
++        return;
++
++    switch (type) {
++    case mwImSend_PLAIN:
++        {
++            Kopete::Message message(convdata->contact, account->myself(),
++                    QString((char *)msg), Kopete::Message::Inbound);
++            convdata->chat->appendMessage(message);
++        }
++        break;
++    case mwImSend_TYPING:
++        convdata->chat->receivedTypingMsg(convdata->contact);
++        break;
++    default:
++        mwDebug() << "Unable to handle message type: " << type << endl;
++    }
++}
++
++void MeanwhileSession::handleResolveLookupResults(
++        struct mwServiceResolve * /* srvc */, guint32 /* id */,
++        guint32 /* code */, GList *results, gpointer data)
++{
++    struct mwResolveResult *result;
++    struct mwResolveMatch *match;
++
++    if (results == 0L)
++        return;
++    if ((result = (struct mwResolveResult *)results->data) == 0L)
++        return;
++
++    if (result->matches == 0L)
++        return;
++    if ((match = (struct mwResolveMatch *)result->matches->data) == 0L)
++        return;
++
++    mwDebug() << "resolve lookup returned '" << match->name << "'" << endl;
++
++    MeanwhileContact *contact = (MeanwhileContact *)data;
++    if (contact == 0L)
++        return;
++
++    contact->setNickName(getNickName(match->name));
++}
++
++void MeanwhileSession::handleStorageLoad(struct mwServiceStorage * /* srvc */,
++        guint32 result, struct mwStorageUnit *item, gpointer /* data */)
++{
++    HERE;
++    if (result != ERR_SUCCESS) {
++        mwDebug() << "contact list load returned " << result << endl;
++        return;
++    }
++
++    struct mwGetBuffer *buf = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
++    struct mwSametimeList *list = mwSametimeList_new();
++    mwSametimeList_get(buf, list);
++
++    GList *gl, *glf, *cl, *clf;
++
++    Kopete::ContactList *contactlist = Kopete::ContactList::self();
++
++    for (glf = gl = mwSametimeList_getGroups(list); gl; gl = gl->next) {
++        struct mwSametimeGroup *stgroup = (struct mwSametimeGroup *)gl->data;
++
++        Kopete::Group *group =
++            contactlist->findGroup(mwSametimeGroup_getName(stgroup));
++        group->setPluginData(account->protocol(), "alias",
++                mwSametimeGroup_getAlias(stgroup));
++
++        for (clf = cl = mwSametimeGroup_getUsers(stgroup); cl; cl = cl->next) {
++            struct mwSametimeUser *stuser = (struct mwSametimeUser *)cl->data;
++
++            MeanwhileContact *contact = static_cast<MeanwhileContact *>
++                (account->contacts()[mwSametimeUser_getUser(stuser)]);
++
++            if (contact != 0L)
++                continue;
++
++            account->addContact(mwSametimeUser_getUser(stuser),
++                    mwSametimeUser_getAlias(stuser), group,
++                    Kopete::Account::ChangeKABC);
++        }
++        g_list_free(clf);
++    }
++    g_list_free(glf);
++
++    mwSametimeList_free(list);
++}
++
++#if 0
++MEANWHILE_HOOK_CONFERENCE(conference_invite,
++        (struct mwConference *conf, struct mwLoginInfo *inviter,
++         const char *invite),
++        (conf, inviter, invite))
++{
++    HERE;
++    QString message;
++
++    message.sprintf("%s has invited you to a conference called \"%s\"\n"
++        "However, this version of the meanwhile plugin does "
++        "not support conferences, so the invitiation has been declined.",
++        inviter->user_id, invite);
++
++    mwConference_reject(conf, ERR_SUCCESS,
++            "Sorry, my client doesn't support conferences!");
++    KMessageBox::queuedMessageBox(0, KMessageBox::Sorry , message,
++            i18n("Meanwhile Plugin: Conference invitation"),
++            KMessageBox::Notify);
++}
++#endif
++#include "meanwhilesession.moc"
+--- kopete/protocols/meanwhile/meanwhilesession.h	(revision 0)
++++ kopete/protocols/meanwhile/meanwhilesession.h	(revision 586398)
+@@ -0,0 +1,341 @@
++/*
++    meanwhilesession.h - interface to the 'C' meanwhile session
++
++    Copyright (c) 2005      by Jeremy Kerr <jk at ozlabs.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 MEANWHILESESSION_H
++#define MEANWHILESESSION_H
++
++#include "meanwhileaccount.h"
++#include "meanwhilecontact.h"
++#include <kextendedsocket.h>
++
++#include <mw_session.h>
++#include <mw_service.h>
++#include <mw_srvc_aware.h>
++#include <mw_srvc_im.h>
++#include <mw_srvc_resolve.h>
++
++/**
++ * A class to handle libmeanwhile session management.
++ */
++class MeanwhileSession : public QObject
++{
++    Q_OBJECT
++
++public:
++    /**
++     * Create a session. By default, the session is not connected - you will
++     * need to call login() to initiate the connection process.
++     * @param account The account that the connection is for
++     */
++    MeanwhileSession(MeanwhileAccount *account);
++
++    /**
++     * Destroy the session
++     */
++    ~MeanwhileSession();
++
++    /**
++     * Connect to the server. This will open a socket and start login. Note that
++     * the connection process is ascychronous - a loginDone() signal will be
++     * emitted when sucessfully logged in.
++     */
++    void connect(QString host, int port, QString account, QString password);
++
++    /**
++     * Disconnect from the server.
++     */
++    void disconnect();
++
++    /**
++     * Set our (the local contact's) online status. The internalStatus of the
++     * state argument will be used to define the state message we send - it
++     * should be one of the Status enum fields (and not Offline)
++     * @param state the new state of the local user
++     * @param msg a custom message to use, if required
++     */
++    void setStatus(Kopete::OnlineStatus status,
++            const QString msg = QString::null);
++
++    /**
++     * Add a single contact to be registered for status updates
++     * @param contact The contact to register
++     */
++    void addContact(const Kopete::Contact *contact);
++
++    /**
++     * Add a list of contacts to be registered for status updates
++     * @param contact The list of contacts to register
++     */
++    void addContacts(const QDict<Kopete::Contact>& contacts);
++
++    /**
++     * Send a message (with recipient specified).
++     * @param message The message to send
++     * @return non-zero if  the message could be sent
++     */
++    int sendMessage(Kopete::Message &message);
++
++    /**
++     * Send a typing notification to a contact
++     * @param contact  The contact to notify
++     * @param isTyping If true, the typing notification is set
++     */
++    void sendTyping(MeanwhileContact *contact, bool isTyping);
++
++    /**
++     * Determine if the session is connected to the server
++     * @return true if the session is connected
++     */
++    bool isConnected();
++
++    /**
++     * Determine if the session is in the process of connecting to the server
++     * @return true if the session is connecting
++     */
++    bool isConnecting();
++
++signals:
++    /**
++     * Emitted when the status of the connection changes
++     * @param status The new status of the session
++     */
++    void sessionStateChange(Kopete::OnlineStatus status);
++
++    /**
++     * Emitted when a notification is received from the server, or other
++     * out-of-band data (eg, the password is incorrect).
++     * @param mesgString A description of the notification
++     */
++    void serverNotification(const QString &mesgString);
++
++private:
++    /** Main libmeanwhile session object */
++    struct mwSession *session;
++
++    /** Session handler */
++    struct mwSessionHandler sessionHandler;
++
++    /** Aware service */
++    struct mwServiceAware *awareService;
++
++    /** Aware handler */
++    struct mwAwareHandler awareHandler;
++
++    /** Aware List Handler */
++    struct mwAwareListHandler awareListHandler;
++
++    /** The aware list */
++    struct mwAwareList *awareList;
++
++    /** Aware service */
++    struct mwServiceIm *imService;
++
++    /** Aware handler */
++    struct mwImHandler imHandler;
++
++    /** Resolve service */
++    struct mwServiceResolve *resolveService;
++
++    /** Storage service, for contact list */
++    struct mwServiceStorage *storageService;
++
++    /** Last recorded meanwhile state */
++    enum mwSessionState state;
++
++    /** The kopete account that this library is for */
++    MeanwhileAccount *account;
++
++    /** socket to the server */
++    KExtendedSocket *socket;
++
++    /* These structures are stored in the libmeanwhile 'ClientData' fields */
++
++    /** Stored in the mwConversation struct */
++    struct ConversationData {
++        MeanwhileContact *contact;
++        Kopete::ChatSession *chat;
++        QValueList<Kopete::Message> *queue;
++    };
++
++    /** (To be) stored in the mwConference struct */
++    struct ConferenceData {
++        Kopete::ChatSession *chatsession;
++    };
++
++    /**
++     * Initialise the conversation data struct for a conversation, and store it 
++     * in the meanwhile conversation object
++     * @param conv        the meanwhile conversation object
++     * @param contact     the contact that the conversation is with
++     * @param createQueue whether a message queue is required for this
++     *                    conversation
++     * @return The created conversation data struct
++     */
++    struct ConversationData *createConversationData(
++            struct mwConversation *conv, MeanwhileContact *contact,
++            bool createQueue = false);
++
++    /**
++     * Get the contact for a conversation
++     * @param conv the meanwhile conversation
++     * @return the contact that this conversation is held with
++     */
++    MeanwhileContact *conversationContact(struct mwConversation *conv);
++
++    /**
++     * Convert a libmeanwhile-type status into one of the MeanwhileProtocol
++     * statuses
++     * @param mstatus The internal status to convert
++     * @return The Meanwhile status
++     */
++    Kopete::OnlineStatus convertStatus(int mstatus);
++
++    /**
++     * Parse the nickname of a libmeanwhile contact. From what I've seen,
++     * usernames are in the format:
++     *  <userid> - <name>/<domain>/<domain>
++     * @param name the extened username to parse
++     * @return just the name part of the username info
++     */
++    QString getNickName(QString name);
++
++    /**
++     * Convenience method to call the above from a mwLoginInfo struct. All is
++     * checked for null.
++     * @param logininfo the login info for a contact
++     * @return just the name part of the login info data
++     */
++    QString getNickName(struct mwLoginInfo *logininfo);
++
++    /**
++     * Resolve a contact to find (and set) the display name. This requires the
++     * session to be connected to use the meanwhile resolve service.
++     * @param contact The contact to resolve
++     */
++     void resolveContactNickname(MeanwhileContact *contact);
++
++public:
++    void syncContactsToServer();
++    void syncContactsFromServer();
++
++private slots:
++
++    /** Notify the library that data is available on the socket */
++    void slotSocketDataAvailable();
++
++    /**
++     * Notify the library that the socket has been closed
++     * @param reason the reason for closing
++     */
++    void slotSocketClosed(int reason);
++
++private:
++    /* ugly callbacks for libmeanwhile interface. These declare a static method
++     * to proxy the callback from libmeanwhile to a call to the MeanwhileSession
++     */
++
++#define declare_session_handler_type(type, func, args, ...)                    \
++    static type _handleSession ## func (                                       \
++            struct mwSession *mwsession, __VA_ARGS__) {                        \
++        MeanwhileSession *session =                                            \
++            (MeanwhileSession *)mwSession_getClientData(mwsession);            \
++        return session->handleSession ## func args;                            \
++    };                                                                         \
++    type handleSession ## func(__VA_ARGS__)
++#define declare_session_handler(func, args, ...)                               \
++    static void _handleSession ## func (                                       \
++            struct mwSession *mwsession, ## __VA_ARGS__) {                     \
++        MeanwhileSession *session =                                            \
++            (MeanwhileSession *)mwSession_getClientData(mwsession);            \
++        session->handleSession ## func args;                                   \
++    };                                                                         \
++    void handleSession ## func(__VA_ARGS__)
++
++    declare_session_handler_type(int, IOWrite, (buf, len),
++            const guchar *buf, gsize len);
++    declare_session_handler(IOClose,());
++    declare_session_handler(Clear,());
++    declare_session_handler(StateChange, (state, info),
++            enum mwSessionState state, gpointer info);
++    declare_session_handler(SetPrivacyInfo,());
++    declare_session_handler(SetUserStatus,());
++    declare_session_handler(Admin, (text), const char *text);
++    declare_session_handler(Announce, (from, may_reply, text),
++            struct mwLoginInfo *from, gboolean may_reply, const char *text);
++
++#define declare_aware_handler(func, args, ...)                                 \
++    static void _handleAware ## func (                                         \
++            struct mwServiceAware *srvc, ## __VA_ARGS__) {                     \
++        MeanwhileSession *session = (MeanwhileSession *)                       \
++            mwService_getClientData((struct mwService *)srvc);                 \
++        return session->handleAware ## func args;                              \
++    }; \
++    void handleAware ## func(__VA_ARGS__)
++
++    declare_aware_handler(Attrib, (attrib), struct mwAwareAttribute *attrib);
++    declare_aware_handler(Clear,());
++
++#define declare_aware_list_handler(func, args, ...)                            \
++    static void _handleAwareList ## func (                                     \
++            struct mwAwareList *list, ## __VA_ARGS__){                         \
++        MeanwhileSession *session = (MeanwhileSession *)                       \
++            mwAwareList_getClientData(list);                                   \
++        return session->handleAwareList ## func args;                          \
++    }; \
++    void handleAwareList ## func(__VA_ARGS__)
++
++    declare_aware_list_handler(Aware, (snapshot),
++            struct mwAwareSnapshot *snapshot);
++    declare_aware_list_handler(Attrib, (id, attrib),
++            struct mwAwareIdBlock *id, struct mwAwareAttribute *attrib);
++    declare_aware_list_handler(Clear,());
++
++#define declare_im_handler(func, args, ...)                                    \
++    static void _handleIm ## func (                                            \
++            struct mwConversation *conv, ## __VA_ARGS__) {                     \
++        MeanwhileSession *session = (MeanwhileSession *)                       \
++            mwService_getClientData(                                           \
++                (struct mwService *)mwConversation_getService(conv));          \
++        return session->handleIm ## func args;                                 \
++    }; \
++    void handleIm ## func (struct mwConversation *conv, ## __VA_ARGS__)
++
++    declare_im_handler(ConvOpened, (conv));
++    declare_im_handler(ConvClosed, (conv, err), guint32 err);
++    declare_im_handler(ConvReceived, (conv, type, msg),
++            enum mwImSendType type, gconstpointer msg);
++
++    /* resolve service */
++    static void _handleResolveLookupResults(struct mwServiceResolve *srvc,
++            guint32 id, guint32 code, GList *results, gpointer data) {
++        MeanwhileSession *session = (MeanwhileSession *)
++            mwService_getClientData(MW_SERVICE(srvc));
++        session->handleResolveLookupResults(srvc, id, code, results, data);
++    };
++    void handleResolveLookupResults(struct mwServiceResolve *srvc, guint32 id,
++            guint32 code, GList *results, gpointer data);
++
++    /* storage service */
++    static void _handleStorageLoad(struct mwServiceStorage *srvc,
++            guint32 result, struct mwStorageUnit *item, gpointer data) {
++        MeanwhileSession *session = (MeanwhileSession *)
++            mwService_getClientData(MW_SERVICE(srvc));
++        session->handleStorageLoad(srvc, result, item, data);
++    };
++    void handleStorageLoad(struct mwServiceStorage *srvc,
++            guint32 result, struct mwStorageUnit *item, gpointer data);
++};
++
++#endif
++
+--- kopete/protocols/meanwhile/meanwhilecontact.cpp	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhilecontact.cpp	(revision 586398)
+@@ -24,19 +24,20 @@
+ #include "kopetemetacontact.h"
+ 
+ #include "meanwhileprotocol.h"
+-#include "meanwhilelibrary.h"
++#include "meanwhilesession.h"
+ #include "meanwhileaccount.h"
+ #include "meanwhilecontact.h"
+ #include "meanwhileplugin.h"
+ 
+-MeanwhileContact::MeanwhileContact(QString _userId, QString _nickname,
+-		MeanwhileAccount *_account, Kopete::MetaContact *_parent)
+-		: Kopete::Contact(_account, _userId, _parent)
++MeanwhileContact::MeanwhileContact(QString userId, QString nickname,
++		MeanwhileAccount *account, Kopete::MetaContact *parent)
++		: Kopete::Contact(account, userId, parent)
+ {
+-	setNickName(_nickname);
++	setNickName(nickname);
+ 	m_msgManager = 0L;
+-	meanwhileId = _userId;
+-	setOnlineStatus( MeanwhileProtocol::protocol()->meanwhileOffline );
++	m_meanwhileId = userId;
++	setOnlineStatus(static_cast<MeanwhileProtocol *>(account->protocol())
++			->statusOffline);
+ }
+ 
+ MeanwhileContact::~MeanwhileContact()
+@@ -45,23 +46,15 @@
+ 
+ bool MeanwhileContact::isReachable()
+ {
+-    return true;
++    return isOnline();
+ }
+ 
+-void MeanwhileContact::serialize( 
+-			QMap< QString, 
+-			QString > &serializedData, 
+-			QMap< QString, 
+-			QString > & addressBookData )
++void MeanwhileContact::serialize(QMap<QString, QString> &serializedData,
++		QMap<QString, QString> &addressBookData)
+ {
+ 	Kopete::Contact::serialize(serializedData, addressBookData);
+ }
+ 
+-QPtrList<KAction> *MeanwhileContact::customContextMenuActions() 
+-{
+-	return 0L;
+-}
+-
+ void MeanwhileContact::showContactSettings()
+ {
+ }
+@@ -69,12 +62,12 @@
+ void MeanwhileContact::slotUserInfo()
+ {
+ 	MeanwhileAccount *theAccount = static_cast<MeanwhileAccount *>( account());
+-	theAccount->infoPlugin->showUserInfo(meanwhileId);
++	theAccount->infoPlugin->showUserInfo(m_meanwhileId);
+ }
+ 
+ Kopete::ChatSession* MeanwhileContact::manager(CanCreateFlags canCreate)
+ {
+-	if (m_msgManager || canCreate == Kopete::Contact::CannotCreate)
++	if (m_msgManager != 0L || canCreate == Kopete::Contact::CannotCreate)
+ 		return m_msgManager;
+ 
+ 	QPtrList<Kopete::Contact> contacts;
+@@ -95,36 +88,41 @@
+ 	return m_msgManager;
+ }
+ 
++QString MeanwhileContact::meanwhileId() const
++{
++	return m_meanwhileId;
++}
++
+ void MeanwhileContact::sendMessage(Kopete::Message &message)
+ {
+-	/*
+-	Kopete::ChatSession *manager = this->manager(Kopete::Contact::CanCreate);
+-	*/
+-	static_cast<MeanwhileAccount *>(account())->library()->sendMessage(message);
++	static_cast<MeanwhileAccount *>(account())->session()->sendMessage(message);
+ }
+ 
+ void MeanwhileContact::slotSendTyping(bool isTyping)
+ {
+-	static_cast<MeanwhileAccount *>(account())->library()->
++	static_cast<MeanwhileAccount *>(account())->session()->
+ 		sendTyping(this, isTyping);
+ }
+-	
+-void MeanwhileContact::receivedMessage( const QString &message )
++
++void MeanwhileContact::receivedMessage(const QString &message)
+ {
+-	Kopete::Message *newMessage;
+ 	Kopete::ContactPtrList contactList;
+-	account();
+-	contactList.append( account()->myself() );
+-	newMessage = new Kopete::Message( this, contactList, 
+-							message, Kopete::Message::Inbound );
++	contactList.append(account()->myself());
++	Kopete::Message kmessage(this, contactList, message,
++			Kopete::Message::Inbound);
+ 
+-	manager(Kopete::Contact::CanCreate)->appendMessage (*newMessage);
++	manager(Kopete::Contact::CanCreate)->appendMessage(kmessage);
++}
+ 
+-	delete newMessage;
++void MeanwhileContact::sync(unsigned int changed)
++{
++	if (changed)
++		static_cast<MeanwhileAccount *>(account())->syncContactsToServer();
+ }
+ 
+ void MeanwhileContact::slotChatSessionDestroyed()
+ {
++	m_msgManager->deref();
+ 	m_msgManager = 0L;
+ }
+ 
+--- kopete/protocols/meanwhile/meanwhileaccount.cpp	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhileaccount.cpp	(revision 586398)
+@@ -20,8 +20,9 @@
+ #include "meanwhileplugin.h"
+ #include "meanwhileaccount.h"
+ #include "meanwhilecontact.h"
+-#include "meanwhilelibrary.h"
++#include "meanwhilesession.h"
+ #include "kopetechatsession.h"
++#include "kopetecontactlist.h"
+ #include "kopetepassword.h"
+ 
+ #include <kaction.h>
+@@ -40,27 +41,18 @@
+     : Kopete::PasswordedAccount(parent, accountID, 0, name)
+ {
+     HERE;
+-    //signal(SIGSEGV,SIG_DFL);
+-    setMyself(new MeanwhileContact(accountId(), accountId(), this, 0L));
+-    myself()->setOnlineStatus(MeanwhileProtocol::protocol()->meanwhileOffline);
+-    m_library = 0L;
++    m_meanwhileId = accountID;
++    m_session = 0L;
++    setMyself(new MeanwhileContact(m_meanwhileId, m_meanwhileId, this,
++                Kopete::ContactList::self()->myself()));
++    setOnlineStatus(parent->statusOffline);
+     infoPlugin = new MeanwhilePlugin();
+ }
+ 
+-void MeanwhileAccount::initLibrary()
+-{
+-}
+-
+-MeanwhileLibrary *MeanwhileAccount::library()
+-{
+-    return m_library;
+-}
+-
+ MeanwhileAccount::~MeanwhileAccount()
+ {
+-    meanwhileGoOffline();
+-    if (m_library)
+-        delete m_library;
++    if (m_session)
++        delete m_session;
+ }
+ 
+ void MeanwhileAccount::setPlugin(MeanwhilePlugin *plugin)
+@@ -73,15 +65,15 @@
+                         const QString & contactId ,
+                         Kopete::MetaContact * parentContact)
+ {
+-    MeanwhileContact* newContact =
+-            new MeanwhileContact(contactId,
+-                                 parentContact->displayName(),
+-                                 this,
+-                                 parentContact);
+-    if ((newContact != 0L) && (m_library != 0L)
++    MeanwhileContact* newContact = new MeanwhileContact(contactId,
++            parentContact->displayName(), this, parentContact);
++
++    MeanwhileProtocol *p = static_cast<MeanwhileProtocol *>(protocol());
++
++    if ((newContact != 0L) && (m_session != 0L)
+         && (myself()->onlineStatus() !=
+-                MeanwhileProtocol::protocol()->meanwhileOffline))
+-        m_library->addContact(newContact);
++                p->statusOffline))
++        m_session->addContact(newContact);
+ 
+     return newContact != 0L;
+ }
+@@ -93,25 +85,33 @@
+         return;
+     }
+ 
+-    if (m_library == 0L) {
+-        m_library = new MeanwhileLibrary(this);
+-        if (!m_library) {
+-            mwDebug() << "library creation failed" << endl;
++    if (m_session == 0L) {
++        m_session = new MeanwhileSession(this);
++        if (m_session == 0L) {
++            mwDebug() << "session creation failed" << endl;
+             return;
+         }
+ 
+-        QObject::connect(m_library, SIGNAL(loginDone()),
+-                this, SLOT(slotLoginDone()));
+-        QObject::connect(m_library, SIGNAL(connectionLost()),
+-                this, SLOT(slotConnectionLost()));
+-        QObject::connect(m_library,
++        QObject::connect(m_session,
++                SIGNAL(sessionStateChange(Kopete::OnlineStatus)),
++                this, SLOT(slotSessionStateChange(Kopete::OnlineStatus)));
++        QObject::connect(m_session,
+                 SIGNAL(serverNotification(const QString &)),
+                 this, SLOT(slotServerNotification(const QString&)));
++
+     }
+-        
+-    if (!m_library->isConnected()) {
+-        m_library->login();
++
++    if (m_session == 0L) {
++        mwDebug() << "No memory for session" << endl;
++        return;
+     }
++
++    if (!m_session->isConnected() && !m_session->isConnecting())
++        m_session->connect(configGroup()->readEntry("Server"),
++                configGroup()->readNumEntry("Port"),
++                m_meanwhileId, password);
++
++    m_session->setStatus(initialStatus());
+ }
+ 
+ void MeanwhileAccount::disconnect()
+@@ -121,177 +121,124 @@
+ 
+ void MeanwhileAccount::disconnect(Kopete::Account::DisconnectReason reason)
+ {
+-    if (m_library != 0L  && m_library->isConnected())
+-        m_library->logoff();
++    if (m_session == 0L)
++        return;
+ 
+-    if (m_library != 0L) {
+-        delete m_library;
+-        m_library = 0L;
+-    }
+-
+-    myself()->setOnlineStatus(MeanwhileProtocol::protocol()->meanwhileOffline);
+-    setAllContactsStatus(MeanwhileProtocol::protocol()->meanwhileOffline);
++    MeanwhileProtocol *p = static_cast<MeanwhileProtocol *>(protocol());
++    setAllContactsStatus(p->statusOffline);
+     disconnected(reason);
+     emit isConnectedChanged();
+-}
+ 
+-void MeanwhileAccount::setAway(bool away, const QString &reason)
+-{
+-    if (away)
+-        meanwhileGoAway(reason);
+-    else
+-        meanwhileGoOnline();
++    delete m_session;
++    m_session = 0L;
+ }
+ 
+ KActionMenu * MeanwhileAccount::actionMenu()
+ {
+-    KActionMenu * theMenu =
+-            new KActionMenu(accountId(),
+-                            myself()->onlineStatus().iconFor(this),
+-                            this);
+-    theMenu->popupMenu()->insertTitle(
+-                            myself()->icon(),
+-                            i18n("Meanwhile (%1)").arg(accountId()));
+-    theMenu->insert(
+-           new KAction( i18n( "Go Online" ),
+-                        MeanwhileProtocol::protocol()->meanwhileOnline.iconFor(this),
+-                        0, this, SLOT(meanwhileGoOnline()), this, "meanwhileGoOnline"));
++    KActionMenu *menu = Kopete::Account::actionMenu();
+ 
+-    theMenu->insert(
+-           new KAction( i18n( "Go Offline" ),
+-                        MeanwhileProtocol::protocol()->meanwhileOffline.iconFor(this),
+-                        0, this, SLOT(meanwhileGoOffline()), this, "meanwhileGoOffline"));
++    menu->popupMenu()->insertSeparator();
+ 
+-    theMenu->insert(
+-           new KAction( i18n( "Go Away" ),
+-                        MeanwhileProtocol::protocol()->meanwhileAway.iconFor(this),
+-                        0, this, SLOT(meanwhileGoAway()), this, "meanwhileGoAway"));
+-
+-    theMenu->insert(
+-           new KAction( i18n( "Mark as Busy" ),
+-                        MeanwhileProtocol::protocol()->meanwhileBusy.iconFor(this),
+-                        0, this, SLOT(meanwhileGoDND()), this, "meanwhileGoDND"));
+-
+-    theMenu->popupMenu()->insertSeparator();
+-
+-    theMenu->insert(
+-           new KAction( i18n("&Change Status Message"), QString::null,
+-                        0, this, SLOT(meanwhileChangeStatus()), this,
+-                        "meanwhileChangeStatus"));
+-
+-    infoPlugin->addCustomMenus(theMenu);
+-
+-    return theMenu;
++#if 0
++    menu->insert(new KAction(i18n("&Change Status Message"), QString::null, 0,
++                this, SLOT(meanwhileChangeStatus()), this,
++                "meanwhileChangeStatus"));
++    //infoPlugin->addCustomMenus(theMenu);
++#endif
++    return menu;
+ }
+ 
+-void MeanwhileAccount::meanwhileGoOnline()
++QString MeanwhileAccount::getServerName()
+ {
+-    HERE;
+-    if (m_library != 0L && m_library->isConnected())
+-        m_library->setState(MeanwhileProtocol::protocol()->meanwhileOnline);
+-    else
+-        connect(MeanwhileProtocol::protocol()->meanwhileOnline);
++    return configGroup()->readEntry("Server");
+ }
+ 
+-void MeanwhileAccount::meanwhileGoOffline()
++int MeanwhileAccount::getServerPort()
+ {
+-    disconnect();
++    return configGroup()->readNumEntry("Port");
+ }
+ 
+-void MeanwhileAccount::meanwhileGoAway()
++void MeanwhileAccount::setServerName(const QString &server)
+ {
+-    meanwhileGoAway(Kopete::Away::getInstance()->message());
++    configGroup()->writeEntry("Server", server);
+ }
+ 
+-void MeanwhileAccount::meanwhileGoAway(const QString &statusmsg)
++void MeanwhileAccount::setServerPort(int port)
+ {
+-    if ((m_library != 0L) && (myself()->onlineStatus() !=
+-            MeanwhileProtocol::protocol()->meanwhileOffline))
+-        m_library->setState(MeanwhileProtocol::protocol()->meanwhileAway,
+-                statusmsg);
++    configGroup()->writeEntry("Port", port);
+ }
+ 
+-void MeanwhileAccount::meanwhileGoDND()
++void MeanwhileAccount::slotServerNotification(const QString &mesg)
+ {
+-    if ((m_library != 0L) && (myself()->onlineStatus() !=
+-            MeanwhileProtocol::protocol()->meanwhileOffline))
+-        m_library->setState(MeanwhileProtocol::protocol()->meanwhileBusy);
++    KMessageBox::queuedMessageBox(0, KMessageBox::Error , mesg,
++            i18n("Meanwhile Plugin: Message from server"), KMessageBox::Notify);
+ }
+ 
+-void MeanwhileAccount::slotLoginDone()
++QString MeanwhileAccount::meanwhileId() const
+ {
+-    myself()->setOnlineStatus(MeanwhileProtocol::protocol()->meanwhileOnline);
+-    statusMesg = QString("I am active");
+-    m_library->setState(MeanwhileProtocol::protocol()->meanwhileOnline);
+-    m_library->addContacts(contacts());
+-    emit isConnectedChanged();
++    return m_meanwhileId;
+ }
+ 
+-QString MeanwhileAccount::serverName()
++void MeanwhileAccount::setAway(bool away, const QString &reason)
+ {
+-    return configGroup()->readEntry("Server");
++    MeanwhileProtocol *p = static_cast<MeanwhileProtocol *>(protocol());
++    setOnlineStatus(away ? p->statusIdle : p->statusOnline, reason);
+ }
+ 
+-int MeanwhileAccount::serverPort()
++void MeanwhileAccount::setOnlineStatus(const Kopete::OnlineStatus &status,
++        const QString &reason)
+ {
+-    return configGroup()->readNumEntry("Port");
+-}
++    HERE;
++    Kopete::OnlineStatus oldstatus = myself()->onlineStatus();
+ 
+-void MeanwhileAccount::setServerName(const QString &server)
+-{
+-    configGroup()->writeEntry("Server", server);
+-}
++    mwDebug() << "From: " << oldstatus.description() << "(" <<
++        oldstatus.internalStatus() << "):" << oldstatus.isDefinitelyOnline()
++                                              << endl;
++    mwDebug() << "To:   " << status.description() << "(" <<
++        status.internalStatus() << "):" << status.isDefinitelyOnline() << endl;
+ 
+-void MeanwhileAccount::setServerPort(int port)
+-{
+-    configGroup()->writeEntry("Port", port);
+-}
++    if (oldstatus == status)
++        return;
+ 
+-void MeanwhileAccount::meanwhileChangeStatus()
+-{
+-    bool ok;
+-    statusMesg = KInputDialog::getText(
+-            i18n("Change Status Message - Meanwhile Plugin"),
+-            i18n("Enter the message to show under your status:"),
+-            statusMesg, &ok);
++    if (!oldstatus.isDefinitelyOnline() && status.isDefinitelyOnline()) {
++        connect();
+ 
+-    if (ok && m_library != 0L)
+-        m_library->setStatusMesg(statusMesg);
+-}
++    } else if (oldstatus.isDefinitelyOnline() && !status.isDefinitelyOnline()) {
++        disconnect(Kopete::Account::Manual);
+ 
+-void MeanwhileAccount::slotServerNotification(const QString &mesg)
+-{
+-    KMessageBox::queuedMessageBox(
+-                        0, KMessageBox::Error ,
+-                        mesg,
+-                        i18n( "Meanwhile Plugin: Message from server" ),
+-                        KMessageBox::Notify );
++    } else if (m_session)
++        /* todo: check session state? */
++        m_session->setStatus(status, reason);
++
++    else
++        mwDebug() << "Trying to set status, but no session exists" << endl;
++
++    /* we should set this on the callback below */
++    //myself()->setOnlineStatus(status);
+ }
+ 
+-void MeanwhileAccount::slotConnectionLost()
++void MeanwhileAccount::syncContactsToServer()
+ {
+-    delete m_library;
+-    m_library = 0L;
+-    meanwhileGoOffline();
++    if (m_session != 0L)
++        m_session->syncContactsToServer();
+ }
+ 
+-void MeanwhileAccount::setOnlineStatus(const Kopete::OnlineStatus & status,
+-        const QString &reason)
++void MeanwhileAccount::slotSessionStateChange(Kopete::OnlineStatus status)
+ {
+-    Kopete::OnlineStatus mystatus = myself()->onlineStatus().status();
++    HERE;
++    Kopete::OnlineStatus oldstatus = myself()->onlineStatus();
++    myself()->setOnlineStatus(status);
+ 
+-    if (mystatus == Kopete::OnlineStatus::Offline
+-            && status.status() == Kopete::OnlineStatus::Online )
+-        connect(status);
++    if (status.isDefinitelyOnline() != oldstatus.isDefinitelyOnline()) {
++        if (status.isDefinitelyOnline())
++            m_session->addContacts(contacts());
++        emit isConnectedChanged();
++    }
++}
+ 
+-    else if (mystatus != Kopete::OnlineStatus::Offline
+-            && status.status() == Kopete::OnlineStatus::Offline )
+-        disconnect();
+-
+-    else if (mystatus != Kopete::OnlineStatus::Offline
+-            && status.status() == Kopete::OnlineStatus::Away )
+-        setAway(true, reason);
++MeanwhileSession *MeanwhileAccount::session()
++{
++    return m_session;
+ }
+ 
+-
+ #include "meanwhileaccount.moc"
+--- kopete/protocols/meanwhile/Makefile.am	(revision 568672)
++++ kopete/protocols/meanwhile/Makefile.am	(revision 586398)
+@@ -5,7 +5,6 @@
+ 	-I$(srcdir)/ui \
+ 	-I./ui \
+ 	$(all_includes) \
+-	$(GLIB_CFLAGS) \
+ 	$(MEANWHILE_CFLAGS)
+ 
+ noinst_HEADERS = \
+@@ -14,7 +13,7 @@
+ 	meanwhileeditaccountwidget.h \
+ 	meanwhileaccount.h \
+ 	meanwhilecontact.h \
+-	meanwhilelibrary.h \
++	meanwhilesession.h \
+ 	meanwhileplugin.h
+ 
+ kde_module_LTLIBRARIES =  kopete_meanwhile.la
+@@ -25,14 +24,14 @@
+ 	meanwhileeditaccountwidget.cpp \
+ 	meanwhileaccount.cpp \
+ 	meanwhilecontact.cpp \
+-	meanwhilelibrary.cpp \
++	meanwhilesession.cpp \
+ 	meanwhileplugin.cpp
+ 
+ kopete_meanwhile_la_LDFLAGS = -no-undefined -module \
+ 	$(KDE_PLUGIN) $(all_libraries) 
+ 
+ kopete_meanwhile_la_LIBADD = $(top_builddir)/kopete/libkopete/libkopete.la \
+-	ui/libkopetemeanwhileui.la $(GLIB_LIBS) $(MEANWHILE_LIBS)
++	ui/libkopetemeanwhileui.la $(MEANWHILE_LIBS)
+ 
+ service_DATA = kopete_meanwhile.desktop
+ servicedir= $(kde_servicesdir)
+--- kopete/protocols/meanwhile/meanwhilecontact.h	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhilecontact.h	(revision 586398)
+@@ -30,40 +30,39 @@
+ 
+ class MeanwhileContact : public Kopete::Contact
+ {
+-	Q_OBJECT
++    Q_OBJECT
+ public:
+ 
+-	MeanwhileContact( QString userId,
+-	                  QString nickname,
+-	                  MeanwhileAccount *account,
+-	                  Kopete::MetaContact *parent);
+-	~MeanwhileContact();
++    MeanwhileContact(QString userId, QString nickname,
++            MeanwhileAccount *account, Kopete::MetaContact *parent);
++    ~MeanwhileContact();
+ 
+-	virtual bool isReachable();
++    virtual bool isReachable();
+ 
+-	virtual void serialize(QMap<QString, QString> &serializedData, QMap<QString, QString> &addressBookData);
++    virtual void serialize(QMap<QString, QString> &serializedData,
++            QMap<QString, QString> &addressBookData);
+ 
+-	virtual QPtrList<KAction> *customContextMenuActions();
++    virtual Kopete::ChatSession *manager(
++            CanCreateFlags canCreate = CanCreate);
+ 
+-	virtual Kopete::ChatSession *manager( CanCreateFlags canCreate = CanCreate );
++    QString meanwhileId() const;
+ 
+-	QString meanwhileId;
++        virtual void sync(unsigned int changed = 0xff);
+ 
+ public slots:
+ 
+-	void sendMessage( Kopete::Message &message );
+-	void receivedMessage( const QString &message );
+-	virtual void slotUserInfo();
++    void sendMessage( Kopete::Message &message );
++    void receivedMessage( const QString &message );
++    virtual void slotUserInfo();
+ 
+ protected slots:
+-	void showContactSettings();
+-	void slotChatSessionDestroyed();
+-	void slotSendTyping(bool isTyping);
++    void showContactSettings();
++    void slotChatSessionDestroyed();
++    void slotSendTyping(bool isTyping);
+ 	
+-protected:
+-        Kopete::ChatSession *m_msgManager;
+-	KActionCollection *m_actionCollection;
+-	KAction* m_actionPrefs;
++private:
++    QString m_meanwhileId;
++    Kopete::ChatSession *m_msgManager;
+ };
+ 
+ #endif
+--- kopete/protocols/meanwhile/meanwhileprotocol.cpp	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhileprotocol.cpp	(revision 586398)
+@@ -18,91 +18,78 @@
+ #include "meanwhileaddcontactpage.h"
+ #include "meanwhileeditaccountwidget.h"
+ #include "meanwhileaccount.h"
+-#include "meanwhilelibrary.h"
+ #include <kgenericfactory.h>
+ #include "kopeteaccountmanager.h"
+ #include "kopeteglobal.h"
+ #include "kopeteonlinestatusmanager.h"
+ 
+-MeanwhileProtocol *MeanwhileProtocol::s_protocol = 0L;
++#include "mw_common.h"
+ 
+ typedef KGenericFactory<MeanwhileProtocol> MeanwhileProtocolFactory;
+-K_EXPORT_COMPONENT_FACTORY( 
+-                kopete_meanwhile, 
+-                MeanwhileProtocolFactory( "kopete_meanwhile" ))
++K_EXPORT_COMPONENT_FACTORY(kopete_meanwhile,
++    MeanwhileProtocolFactory("kopete_meanwhile"))
+ 
+-MeanwhileProtocol::MeanwhileProtocol( QObject* parent, 
+-                                      const char *name, 
+-                                      const QStringList &/*args*/)
+-    : Kopete::Protocol(MeanwhileProtocolFactory::instance(), 
+-                     parent, name),
++MeanwhileProtocol::MeanwhileProtocol(QObject* parent, const char *name,
++        const QStringList &/*args*/)
++: Kopete::Protocol(MeanwhileProtocolFactory::instance(), parent, name),
+ 
+-      meanwhileOffline(Kopete::OnlineStatus::Offline,  25, this, 
+-              MeanwhileLibrary::Offline,
+-              QString::null, i18n( "Offline" ), i18n( "Go Offline" ),
+-              Kopete::OnlineStatusManager::Offline),
++    statusOffline(Kopete::OnlineStatus::Offline, 25, this, 0, QString::null,
++            i18n("Offline"), i18n("Offline"),
++            Kopete::OnlineStatusManager::Offline,
++	    Kopete::OnlineStatusManager::DisabledIfOffline),
+ 
+-      meanwhileOnline(Kopete::OnlineStatus::Online, 25, this, 
+-              MeanwhileLibrary::Active, QString::null, i18n( "Online" ),
+-              i18n( "Go Online" ), Kopete::OnlineStatusManager::Online),
++    statusOnline(Kopete::OnlineStatus::Online, 25, this, mwStatus_ACTIVE,
++            QString::null, i18n("Online"), i18n("Online"),
++            Kopete::OnlineStatusManager::Online, 0),
+ 
+-      meanwhileAway(Kopete::OnlineStatus::Away, 25, this, 
+-              MeanwhileLibrary::Away, "meanwhile_away", i18n( "Away" ),
+-              i18n( "Go Away" ), Kopete::OnlineStatusManager::Away),
++    statusAway(Kopete::OnlineStatus::Away, 20, this, mwStatus_AWAY,
++            "meanwhile_away", i18n("Away"), i18n("Away"),
++            Kopete::OnlineStatusManager::Away,
++	    Kopete::OnlineStatusManager::HasAwayMessage),
+ 
+-      meanwhileBusy(Kopete::OnlineStatus::Away, 25, this, 
+-              MeanwhileLibrary::Busy, "meanwhile_dnd",
+-              i18n( "Busy" ) , i18n( "Mark as Busy" ),
+-              Kopete::OnlineStatusManager::Busy),
++    statusBusy(Kopete::OnlineStatus::Away, 25, this, mwStatus_BUSY,
++            "meanwhile_dnd", i18n("Busy"), i18n("Busy"),
++          Kopete::OnlineStatusManager::Busy,
++	  Kopete::OnlineStatusManager::HasAwayMessage),
+ 
+-      meanwhileIdle(Kopete::OnlineStatus::Away, 25, this, 
+-              MeanwhileLibrary::Idle, "meanwhile_idle",
+-              i18n( "Idle" ), i18n( "Marked as Idle" ),
+-              Kopete::OnlineStatusManager::Idle),
++    statusIdle(Kopete::OnlineStatus::Away, 30, this, mwStatus_AWAY,
++            "meanwhile_idle", i18n("Idle"), i18n("Idle"),
++            Kopete::OnlineStatusManager::Idle, 0),
+ 
+-      meanwhileUnknown(Kopete::OnlineStatus::Unknown, 25, this, 0,
+-              "meanwhile_unknown", i18n( "Catch me if you can" )),
++    statusAccountOffline(Kopete::OnlineStatus::Offline, 0, this, 0,
++            QString::null, i18n("Account Offline")),
+ 
+-      statusMessage(QString::fromLatin1("statusMessage"),
+-              i18n("Status Message"), QString::null, false, true),
+-	  awayMessage(Kopete::Global::Properties::self()->awayMessage())
++    statusMessage(QString::fromLatin1("statusMessage"),
++        i18n("Status Message"), QString::null, false, true),
++
++    awayMessage(Kopete::Global::Properties::self()->awayMessage())
+ {
+-//    LOG("MeanwhileProtocol()");
+-    s_protocol = this;
++    HERE;
+ 
+-    addAddressBookField( "messaging/meanwhile", Kopete::Plugin::MakeIndexField );
++    addAddressBookField("messaging/meanwhile", Kopete::Plugin::MakeIndexField);
+ }
+ 
+ MeanwhileProtocol::~MeanwhileProtocol()
+ {
+ }
+ 
+-AddContactPage * MeanwhileProtocol::createAddContactWidget(
+-                                    QWidget *parent, 
+-                                    Kopete::Account * account )
++AddContactPage * MeanwhileProtocol::createAddContactWidget(QWidget *parent,
++        Kopete::Account *account )
+ {
+ 	return new MeanwhileAddContactPage(parent, account);
+ }
+ 
+-KopeteEditAccountWidget * MeanwhileProtocol::createEditAccountWidget( 
+-                                    Kopete::Account *account, 
+-                                    QWidget *parent )
++KopeteEditAccountWidget * MeanwhileProtocol::createEditAccountWidget(
++        Kopete::Account *account, QWidget *parent )
+ {
+-//    LOG("createEditAccountWidget");
+-	return new MeanwhileEditAccountWidget( parent, account, this );
++	return new MeanwhileEditAccountWidget(parent, account, this);
+ }
+ 
+-Kopete::Account *MeanwhileProtocol::createNewAccount( 
+-                                    const QString &accountId )
++Kopete::Account *MeanwhileProtocol::createNewAccount(const QString &accountId)
+ {
+-	return new MeanwhileAccount( this, accountId, accountId.ascii() );
++	return new MeanwhileAccount(this, accountId, accountId.ascii());
+ }
+ 
+-MeanwhileProtocol *MeanwhileProtocol::protocol()
+-{
+-    return s_protocol;
+-}
+-
+ Kopete::Contact *MeanwhileProtocol::deserializeContact( 
+                             Kopete::MetaContact *metaContact,
+                             const QMap<QString, 
+@@ -115,7 +102,7 @@
+     MeanwhileAccount *theAccount = 
+             static_cast<MeanwhileAccount*>(
+                             Kopete::AccountManager::self()->
+-                                    findAccount(protocol()->pluginId(), accountId));
++                                    findAccount(pluginId(), accountId));
+ 
+     if(!theAccount)
+     {
+@@ -126,5 +113,14 @@
+     return theAccount->contacts()[contactId];
+ }
+ 
++const Kopete::OnlineStatus MeanwhileProtocol::accountOfflineStatus()
++{
++    return statusAccountOffline;
++}
+ 
++const Kopete::OnlineStatus MeanwhileProtocol::lookupStatus(
++            enum Kopete::OnlineStatusManager::Categories cats)
++{
++    return Kopete::OnlineStatusManager::self()->onlineStatus(this, cats);
++}
+ #include "meanwhileprotocol.moc"
+--- kopete/protocols/meanwhile/meanwhileaccount.h	(revision 568672)
++++ kopete/protocols/meanwhile/meanwhileaccount.h	(revision 586398)
+@@ -22,15 +22,23 @@
+ #include "meanwhileprotocol.h"
+ #include "meanwhileplugin.h"
+ 
+-class MeanwhileLibrary;
++class MeanwhileSession;
+ 
++/**
++ * A class to handle a single Meanwhile Account.
++ */
+ class MeanwhileAccount : public Kopete::PasswordedAccount
+ {
+     Q_OBJECT
+ public:
+-    MeanwhileAccount(   MeanwhileProtocol *parent,
+-                        const QString &accountID,
+-                        const char *name = 0L);
++    /**
++     * Create a new Meanwhile account
++     * @param protocol  The MeanwhileProtocol that this acccount is for
++     * @param accountID The (meanwhile) account id of this account
++     * @param name      The name of this account
++     */
++    MeanwhileAccount(MeanwhileProtocol *protocol, const QString &accountID,
++            const char *name = 0L);
+ 
+     ~MeanwhileAccount();
+ 
+@@ -40,49 +48,65 @@
+     virtual void connectWithPassword(const QString &password);
+ 
+     virtual void disconnect();
++
+     virtual void disconnect(Kopete::Account::DisconnectReason reason);
+ 
+-    virtual void setAway(bool away,
+-                        const QString &reason);
+-
+     virtual KActionMenu *actionMenu();
+ 
+-    QString serverName();
+-    int     serverPort();
++    /** Get the server host name */
++    QString getServerName();
++    /** Get the server port */
++    int     getServerPort();
++    /** Set the server host name */
+     void    setServerName(const QString &server);
++    /** Set the server port */
+     void    setServerPort(int port);
++    /** Provide an information plugin for this account */
+     void    setPlugin(MeanwhilePlugin *plugin);
+ 
+     MeanwhilePlugin *infoPlugin;
+ 
+     /**
+-     * Get a reference to the meanwhile library object
++     * Save the current contact list to the server
+      */
+-    MeanwhileLibrary *library();
++    void syncContactsToServer();
+ 
+-protected slots:
+-    void meanwhileGoOnline();
+-    void meanwhileGoAway();
+-    void meanwhileGoOffline();
+-    void meanwhileGoDND();
+-    void meanwhileChangeStatus();
++    /**
++     * Get a reference to the meanwhile session object, if one exists
++     */
++    MeanwhileSession *session();
+ 
++    /**
++     * Get the meanwhile id for this account
++     * @return The meanwhile ID for the account
++     */
++    QString meanwhileId() const;
++
+ public slots:
+-    void slotLoginDone();
++    /**
++     * Called by the session to notify that the state has changed
++     */
++    void slotSessionStateChange(Kopete::OnlineStatus status);
++
++    /**
++     * Called by the session when a notification message has been received
++     */
+     void slotServerNotification(const QString &mesg);
+-    void slotConnectionLost();
+ 
+     /** Reimplemented from Kopete::Account */
+     void setOnlineStatus(const Kopete::OnlineStatus& status,
+             const QString &reason = QString::null);
++    void setAway(bool away, const QString&reason = QString::null);
+ 
+ private:
+-    void initLibrary();
+-    void meanwhileGoAway(const QString &statusmsg);
+-    QString statusMesg;
++    /** Current online status */
++    Kopete::OnlineStatus status;
+ 
+-    /** The interface to the libmeanwhile library */
+-    MeanwhileLibrary *m_library;
++    /** A meanwhile session */
++    MeanwhileSession *m_session;
++
++    /* The user id for this account */
++    QString m_meanwhileId;
+ };
+ 
+ #endif
+--- kopete/protocols/meanwhile/ui/meanwhileeditaccountbase.ui	(revision 568672)
++++ kopete/protocols/meanwhile/ui/meanwhileeditaccountbase.ui	(revision 586398)
+@@ -107,31 +107,6 @@
+                             </widget>
+                         </vbox>
+                     </widget>
+-                    <widget class="QLabel">
+-                        <property name="name">
+-                            <cstring>textLabel14</cstring>
+-                        </property>
+-                        <property name="sizePolicy">
+-                            <sizepolicy>
+-                                <hsizetype>3</hsizetype>
+-                                <vsizetype>3</vsizetype>
+-                                <horstretch>0</horstretch>
+-                                <verstretch>0</verstretch>
+-                            </sizepolicy>
+-                        </property>
+-                        <property name="minimumSize">
+-                            <size>
+-                                <width>600</width>
+-                                <height>0</height>
+-                            </size>
+-                        </property>
+-                        <property name="text">
+-                            <string>&lt;i&gt;contact suppandi at gmail.com if you have any problems.&lt;/i&gt;</string>
+-                        </property>
+-                        <property name="alignment">
+-                            <set>WordBreak|AlignTop</set>
+-                        </property>
+-                    </widget>
+                 </vbox>
+             </widget>
+             <widget class="QWidget">
+--- kopete/protocols/testbed/testbedaccount.cpp	(revision 568672)
++++ kopete/protocols/testbed/testbedaccount.cpp	(revision 586398)
+@@ -22,6 +22,7 @@
+ #include <kpopupmenu.h>
+ 
+ #include "kopetemetacontact.h"
++#include "kopetecontactlist.h"
+ 
+ #include "testbedcontact.h"
+ #include "testbedfakeserver.h"
+@@ -32,8 +33,7 @@
+ : Kopete::Account ( parent, accountID , name )
+ {
+ 	// Init the myself contact
+-	// FIXME: I think we should add a global self metaContact (Olivier)
+-	setMyself( new TestbedContact( this, accountId(), TestbedContact::Null, accountId(), 0L ) );
++	setMyself( new TestbedContact( this, accountId(), TestbedContact::Null, accountId(), Kopete::ContactList::self()->myself() ) );
+ 	myself()->setOnlineStatus( TestbedProtocol::protocol()->testbedOffline );
+ 	m_server = new TestbedFakeServer();;
+ }
+@@ -46,6 +46,15 @@
+ KActionMenu* TestbedAccount::actionMenu()
+ {
+ 	KActionMenu *mActionMenu = Kopete::Account::actionMenu();
++
++	mActionMenu->popupMenu()->insertSeparator();
++
++	KAction *action;
++	
++	action = new KAction (i18n ("Show my own video..."), "testbed_showvideo", 0, this, SLOT (slotShowVideo ()), this, "actionShowVideo");
++	mActionMenu->insert(action);
++	action->setEnabled( isConnected() );
++
+ 	return mActionMenu;
+ }
+ 
+@@ -129,6 +138,15 @@
+ 	updateContactStatus();
+ }
+ 
++void TestbedAccount::slotShowVideo ()
++{
++	kdDebug ( 14210 ) << k_funcinfo << endl;
++
++	if (isConnected ())
++		TestbedWebcamDialog *testbedWebcamDialog = new TestbedWebcamDialog(0, 0, "Testbed video window");
++	updateContactStatus();
++}
++
+ void TestbedAccount::receivedMessage( const QString &message )
+ {
+ 	// Look up the contact the message is from
+@@ -136,12 +154,15 @@
+ 	TestbedContact* messageSender;
+ 
+ 	from = message.section( ':', 0, 0 );
+-	//from = QString::fromLatin1("echo");
+-	messageSender = static_cast<TestbedContact *>( contacts ()[ from ] );
++	Kopete::Contact* contact = contacts()[from];
++	messageSender = dynamic_cast<TestbedContact *>( contact );
+ 
+ 	kdDebug( 14210 ) << k_funcinfo << " got a message from " << from << ", " << messageSender << ", is: " << message << endl;
+ 	// Pass it on to the contact to process and display via a KMM
+-	messageSender->receivedMessage( message );
++	if ( messageSender )
++		messageSender->receivedMessage( message );
++	else
++		kdWarning(14210) << k_funcinfo << "unable to look up contact for delivery" << endl;
+ }
+ 
+ void TestbedAccount::updateContactStatus()
+--- kopete/protocols/testbed/testbedfakeserver.cpp	(revision 568672)
++++ kopete/protocols/testbed/testbedfakeserver.cpp	(revision 586398)
+@@ -34,17 +34,13 @@
+ 	// see what contact the message is for
+ 	// if it's for Echo, respond immediately
+ 	kdDebug( 14210 ) << k_funcinfo << "Message for: " << contactId << ", is: " << message << endl;
+-	if ( contactId == QString::fromLatin1( "echo" ) )
+-	{
+-		kdDebug( 14210 ) << "recipient is echo, coming back at you." << endl;
+-		// put the message in a map and start a timer to tell it to deliver itself.
+-		//emit messageReceived( QString::fromLatin1( "echo: " ) + message );
+-		TestbedIncomingMessage* msg = new TestbedIncomingMessage( this, QString::fromLatin1( "echo: " ) + message );
+-		m_incomingMessages.append( msg );
+-		QTimer::singleShot( 3000, msg, SLOT( deliver() ) );
+-	}
+-	else
+-		kdWarning( 14210 ) << "message recipient: " << contactId << " is unknown." << endl;
++	kdDebug( 14210 ) << "recipient is echo, coming back at you." << endl;
++	// put the message in a map and start a timer to tell it to deliver itself.
++	//emit messageReceived( QString::fromLatin1( "echo: " ) + message );
++	QString messageId = contactId + QString::fromLatin1(": ");
++	TestbedIncomingMessage* msg = new TestbedIncomingMessage( this, messageId + message );
++	m_incomingMessages.append( msg );
++	QTimer::singleShot( 1000, msg, SLOT( deliver() ) );
+ 	
+ 	// This removes any delivered messages 
+ 	purgeMessages();
+--- kopete/protocols/testbed/testbedaddcontactpage.cpp	(revision 568672)
++++ kopete/protocols/testbed/testbedaddcontactpage.cpp	(revision 586398)
+@@ -18,6 +18,7 @@
+ 
+ #include <qlayout.h>
+ #include <qradiobutton.h>
++#include <qlineedit.h>
+ #include <kdebug.h>
+ 
+ #include "kopeteaccount.h"
+@@ -46,7 +47,7 @@
+ 		QString name;
+ 		if ( m_testbedAddUI->m_rbEcho->isOn() )
+ 		{
+-			type = QString::fromLatin1( "echo" );
++			type = m_testbedAddUI->m_uniqueName->text();
+ 			name = QString::fromLatin1( "Echo Contact" );
+ 			ok = true;
+ 		}
+--- kopete/protocols/testbed/testbedaccount.h	(revision 568672)
++++ kopete/protocols/testbed/testbedaccount.h	(revision 586398)
+@@ -18,6 +18,7 @@
+ #define TESTBEDACCOUNT_H
+ 
+ #include <kopeteaccount.h>
++#include "testbedwebcamdialog.h"
+ 
+ class KActionMenu;
+ namespace Kopete { class Contact; }
+@@ -94,6 +95,10 @@
+ 	 * Change the account's status.  Called by KActions and internally.
+ 	 */
+ 	void slotGoOffline();
++	/**
++	 * Show webcam.  Called by KActions and internally.
++	 */
++	void slotShowVideo();
+ 
+ };
+ 
+--- kopete/protocols/testbed/Makefile.am	(revision 568672)
++++ kopete/protocols/testbed/Makefile.am	(revision 586398)
+@@ -1,14 +1,15 @@
+ METASOURCES = AUTO
+ 
+-SUBDIRS = . icons
++SUBDIRS = ui . icons
+ 
+-AM_CPPFLAGS = $(KOPETE_INCLUDES) $(all_includes)
++AM_CPPFLAGS = $(KOPETE_INCLUDES) -I$(srcdir)/ui -Iui $(all_includes)
+ 
+ noinst_HEADERS = testbedprotocol.h testbedcontact.h testbedaccount.h testbedaddcontactpage.h testbededitaccountwidget.h testbedfakeserver.h testbedincomingmessage.h
+ kde_module_LTLIBRARIES =  kopete_testbed.la
+ kopete_testbed_la_SOURCES = testbedprotocol.cpp testbedcontact.cpp testbedaccount.cpp testbedaddcontactpage.cpp testbedaddui.ui testbededitaccountwidget.cpp testbedaccountpreferences.ui testbedfakeserver.cpp testbedincomingmessage.cpp
+-kopete_testbed_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries)
+-kopete_testbed_la_LIBADD = ../../libkopete/libkopete.la $(LIB_KIO)
++kopete_testbed_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
++kopete_testbed_la_LIBADD = ../../libkopete/avdevice/libkopete_videodevice.la \
++	ui/libkopetetestbedui.la ../../libkopete/libkopete.la $(LIB_KIO)
+ 
+ service_DATA = kopete_testbed.desktop
+ servicedir= $(kde_servicesdir)
+--- kopete/protocols/testbed/ui/testbedwebcamdialog.h	(revision 0)
++++ kopete/protocols/testbed/ui/testbedwebcamdialog.h	(revision 586398)
+@@ -0,0 +1,60 @@
++/*
++    Kopete Testbed Protocol
++
++    Copyright (c) 2006 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at 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 TESTBEDWEBCAMDIALOG_H
++#define TESTBEDWEBCAMDIALOG_H
++
++#include <qstring.h>
++#include <qimage.h>
++#include <qtimer.h>
++#include <qpixmap.h>
++#include <kdialogbase.h>
++
++/**
++	@author Kopete Developers <kopete-devel at kde.org>
++*/
++class QPixmap;
++class QWidget;
++class TestbedContact;
++
++namespace Kopete { 
++	namespace AV	{
++		class VideoDevicePool;
++	}
++	class WebcamWidget;
++}
++
++class TestbedWebcamDialog : public KDialogBase
++{
++Q_OBJECT
++public:
++	TestbedWebcamDialog( const QString &, QWidget* parent = 0, const char* name = 0 );
++	~TestbedWebcamDialog();
++	
++public slots:
++	void slotUpdateImage();
++//signals:
++//	void closingWebcamDialog();
++	
++private:
++	Kopete::WebcamWidget *mImageContainer;
++	QImage mImage;
++	QTimer qtimer;
++	QPixmap mPixmap;
++	Kopete::AV::VideoDevicePool *mVideoDevicePool;
++};
++
++#endif
+--- kopete/protocols/testbed/ui/Makefile.am	(revision 0)
++++ kopete/protocols/testbed/ui/Makefile.am	(revision 586398)
+@@ -0,0 +1,7 @@
++INCLUDES = 
++METASOURCES = AUTO
++AM_CPPFLAGS = $(KOPETE_INCLUDES) -I$(srcdir)/.. $(all_includes)
++libkopetetestbedui_la_LDFLAGS = $(all_libraries)
++noinst_LTLIBRARIES = libkopetetestbedui.la
++noinst_HEADERS = testbedwebcamdialog.h
++libkopetetestbedui_la_SOURCES = testbedwebcamdialog.cpp
+--- kopete/protocols/testbed/ui/testbedwebcamdialog.cpp	(revision 0)
++++ kopete/protocols/testbed/ui/testbedwebcamdialog.cpp	(revision 586398)
+@@ -0,0 +1,80 @@
++/*
++    Kopete Testbed Protocol
++
++    Copyright (c) 2006 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at 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 "testbedwebcamdialog.h"
++#include <webcamwidget.h>
++#include "avdevice/videodevicepool.h"
++
++#include <qframe.h>
++#include <qobject.h>
++#include <qwidget.h>
++#include <qlabel.h>
++#include <qlayout.h>
++#include <qvbox.h>
++#include <kdebug.h>
++#include <klocale.h>
++
++TestbedWebcamDialog::TestbedWebcamDialog( const QString &contactId, QWidget * parent, const char * name )
++: KDialogBase( KDialogBase::Plain, Qt::WDestructiveClose, parent, name, false, i18n( "Webcam for %1" ).arg( contactId ),
++                   KDialogBase::Close, KDialogBase::Close, true /*seperator*/ )
++{
++	setInitialSize( QSize(320,290), false );
++	
++	setEscapeButton( KDialogBase::Close );
++//	QObject::connect( this, SIGNAL( closeClicked() ), this, SIGNAL( closingWebcamDialog() ) );
++
++	QWidget *page = plainPage();
++	setMainWidget(page);
++
++	QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );	
++	mImageContainer = new Kopete::WebcamWidget( page );
++	mImageContainer->setMinimumSize(320,240);
++	mImageContainer->setText( i18n( "No webcam image received" ) );
++	mImageContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
++	topLayout->add( mImageContainer );
++	
++	show();
++	
++	mVideoDevicePool = Kopete::AV::VideoDevicePool::self();
++	mVideoDevicePool->open();
++	mVideoDevicePool->setSize(320, 240);
++	mVideoDevicePool->startCapturing();
++	mVideoDevicePool->getFrame();
++	mVideoDevicePool->getImage(&mImage);
++kdDebug() << "Just captured 1st frame" << endl;
++
++	mPixmap=QPixmap(320,240,-1, QPixmap::DefaultOptim);
++	if (mPixmap.convertFromImage(mImage,0) == true)
++		mImageContainer->updatePixmap(mPixmap);
++	connect(&qtimer, SIGNAL(timeout()), this, SLOT(slotUpdateImage()) );
++	qtimer.start(0,FALSE);
++}
++
++TestbedWebcamDialog::~ TestbedWebcamDialog( )
++{
++	mVideoDevicePool->stopCapturing();
++	mVideoDevicePool->close();
++}
++
++void TestbedWebcamDialog::slotUpdateImage()
++{
++	mVideoDevicePool->getFrame();
++	mVideoDevicePool->getImage(&mImage);
++	mImageContainer->updatePixmap( QPixmap( mImage ) );
++}
++
++
++#include "testbedwebcamdialog.moc"
+--- kopete/protocols/configure.in.in	(revision 568672)
++++ kopete/protocols/configure.in.in	(revision 586398)
+@@ -1,10 +1,3 @@
+-AC_DEFUN([AC_LIBGADU_DEFINE],
+-[
+-sed -e "s/#undef __GG_LIBGADU_$1/#define __GG_LIBGADU_$1/" \
+-${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h > ${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h.1
+-mv ${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h.1 ${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h
+-])
+-	 
+ LIBGG_INCLUDES=""
+ LIBGG_LIBS=""
+ ac_libgadu_includes=""
+@@ -56,7 +49,7 @@
+ 			return 1;
+ 		}
+ 
+-		if ( min == 5 ){
++		if ( min == 5 || min == 6 ){
+ 			return 0;
+ 		}
+ 			     
+@@ -99,18 +92,20 @@
+ AM_CONDITIONAL(include_libggcopy, test -n "$use_libgadu_copy")
+ 
+ if test "$use_libgadu_copy" = "yes"; then
++	AM_CONFIG_HEADER(kopete/protocols/gadu/libgadu/libgadu-config.h)
++
+ 	cp ${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h.in \
+ 	${srcdir}/kopete/protocols/gadu/libgadu/libgadu-config.h
+ 	if test "$ac_cv_c_bigendian" = "yes"; then
+-		AC_LIBGADU_DEFINE([BIGENDIAN])	
++		AC_DEFINE_UNQUOTED([__GG_LIBGADU_BIGENDIAN], 1, [Define if big endian])
+ 	fi
+ 	KDE_CHECK_LONG_LONG()
+ 	if test "$kde_cv_c_long_long" = "yes"; then
+-	AC_LIBGADU_DEFINE([HAVE_LONG_LONG])
++		AC_DEFINE_UNQUOTED([__GG_LIBGADU_HAVE_LONG_LONG], 1, [long long support])
+ 	fi
+ 	KDE_CHECK_SSL()
+ 	if test  "$have_ssl" = "yes"; then
+-	AC_LIBGADU_DEFINE([HAVE_OPENSSL])
++	AC_DEFINE_UNQUOTED([__GG_LIBGADU_HAVE_OPENSSL], 1, [Define if SSL support is available])
+ 	fi
+ 	AC_MSG_CHECKING([for C99-compatible vsnprintf()])
+ 	AC_TRY_RUN(
+@@ -123,105 +118,83 @@
+ 		}
+ 	],[
+ 		AC_MSG_RESULT([yes])
+-		AC_LIBGADU_DEFINE([HAVE_C99_VSNPRINTF])
++		AC_DEFINE_UNQUOTED([__GG_LIBGADU_HAVE_C99_VSNPRINTF], 1, [C99 vsnprintf() available])
+ 	], [
+ 		 AC_MSG_RESULT([no])
+ 	])
+ 	AC_CHECK_FUNCS([va_copy],
+-		       [AC_LIBGADU_DEFINE([HAVE_VA_COPY])],[])
++		       [AC_DEFINE_UNQUOTED([__GG_LIBGADU_HAVE_VA_COPY], 1, [va_copy])],[])
+ 	AC_CHECK_FUNCS([_va_copy],
+-		       [AC_LIBGADU_DEFINE([HAVE__VA_COPY])],[])
++		       [AC_DEFINE_UNQUOTED([__GG_LIBGADU_HAVE__VA_COPY], 1, [__va_copy])],[])
+ fi
+ 
+-
+-AC_ARG_WITH(libidn, AC_HELP_STRING([--with-libidn=DIR],
+-            [Support IDN (needs GNU Libidn)]),
+-            libidn=$withval, libidn=yes)
+-
+-if test "$libidn" != "no"; then
+-	if test "$libidn" != "yes"; then
+-		IDN_LDFLAGS="${LDFLAGS} -L$libidn/lib"
+-		IDN_CPPFLAGS="${CPPFLAGS} -I$libidn/include"
+-	fi
+-fi
+-
+-KDE_CHECK_HEADER(idna.h,, libidn=no)
+-
+-if test "$libidn" != "no" ; then
+-	KDE_CHECK_LIB(idn, stringprep_check_version,
+-		[libidn=yes; IDN_LIBS="-lidn"], libidn=no)
+-fi
+-
+-if test "$libidn" != "no" ; then
++KDE_PKG_CHECK_MODULES(IDN, libidn, have_libidn=yes, have_libidn=no)
++if test x$have_libidn = xno; then
++	AC_MSG_WARN([Libidn not found, Kopete Jabber plugin will not be compiled])
++else
+ 	AC_DEFINE(LIBIDN, 1, [Define to 1 if you want IDN support.])
+-else
+-	AC_MSG_WARN([Libidn not found, Kopete Jabber plugin will not be compiled])
+ fi
++AC_SUBST(IDN_CFLAGS)
++AC_SUBST(IDN_LIBS)
+ 
+ AC_MSG_CHECKING([if Libidn can be used])
+-AC_MSG_RESULT($libidn)
++AC_MSG_RESULT($have_libidn)
+ 
+-AM_CONDITIONAL(include_jabber, test "$libidn" = "yes")
++AM_CONDITIONAL(include_jabber, test "$have_libidn" = "yes")
+ 
+-AC_SUBST(IDN_LDFLAGS)
+-AC_SUBST(IDN_CPPFLAGS)
+-AC_SUBST(IDN_LIBS)
+-
+-
+-#
+ # Sametime support
+-#
+ 
+ # lower and upper-bound versions of Meanwhile library
+-m4_define(meanwhile_version_min,        0.4.2)
+-m4_define(meanwhile_version_max,        0.5.0)
++m4_define(libmeanwhile_version_min, 1.0.1)
++m4_define(libmeanwhile_version_max, 1.1.0)
+ 
+ # Let the user disable the plugin
+-AC_ARG_ENABLE(sametime-plugin,
+-      AC_HELP_STRING([--enable-sametime-plugin], [build the Kopete Sametime plugin @<:@default=no@:>@]),
+-      [compile_meanwhile=$enableval],
+-      [compile_meanwhile=no]
++AC_ARG_ENABLE(meanwhile,
++      AC_HELP_STRING([--disable-meanwhile],
++      [disable the Kopete Meanwhile plugin (Lotus Sametime support) @<:@default=enabled@:>@]),
+       )
+ 
+-# Check and setup for Meanwhile library
+-KDE_PKG_CHECK_MODULES(MEANWHILE,
+-      [meanwhile >= meanwhile_version_min meanwhile < meanwhile_version_max],
+-      [have_meanwhile=yes],
+-      [have_meanwhile=no]
+-      )
++if test "x$enable_meanwhile" != "xno"; then
++    # Check and setup for libmeanwhile
++    KDE_PKG_CHECK_MODULES(MEANWHILE,
++        [meanwhile >= libmeanwhile_version_min meanwhile < libmeanwhile_version_max],
++        [have_libmeanwhile=yes], [have_libmeanwhile=no])
++
++    if test "x$have_libmeanwhile" = "xno"; then
++        enable_meanwhile=no
++        AC_MSG_RESULT([not found])
++    else
++        AC_MSG_RESULT([found])
++    fi
++fi
++
+ AC_SUBST(MEANWHILE_CFLAGS)
+ AC_SUBST(MEANWHILE_LIBS)
+ 
+-# Check and setup for GLib library
+-KDE_PKG_CHECK_MODULES(GLIB,
+-      [glib-2.0 >= 2.0.0],
+-      [have_glib=yes],
+-      [have_glib=no]
+-      )
+-AC_SUBST(GLIB_CFLAGS)
+-AC_SUBST(GLIB_LIBS)
+-
+-# Do we everything we need to compile the plugin
+-if test "x$have_meanwhile" != "xyes" || test "x$have_glib" != "xyes"; then
+-    compile_meanwhile=no
++AC_MSG_CHECKING([if Meanwhile plugin should be compiled])
++if test "x$enable_meanwhile" != "xno"; then
++    AC_MSG_RESULT([yes])
++else
++    AC_MSG_RESULT([no])
+ fi
+ 
+-# Let the user know
+-AC_MSG_CHECKING([if Sametime Plugin should be compiled])
+-AC_MSG_RESULT($compile_meanwhile)
++# Set the flag to compile meanwhile
++AM_CONDITIONAL(include_meanwhile, [test "x$enable_meanwhile" != "xno"])
+ 
+-# Here we go
+-AM_CONDITIONAL(include_meanwhile, [test "x$compile_meanwhile" = "xyes"])
+-
+-#
+-# End of Sametime support
+-#
+-
+ # testbed protocol
+ dnl define the configure option that disables testbed protocol
+ AC_ARG_ENABLE(testbed, [  --disable-testbed     disable kopete testbed protocol compilation ],  with_testbed=$enableval, with_testbed=yes)
+ 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 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
+@@ -235,3 +208,38 @@
+ 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]),
++      [compile_smsgsm=$enableval],
++      [compile_smsgsm=yes]
++      )
++
++AC_LANG_PUSH(C++)
++ac_save_LIBS="$LIBS"
++LIBS="-lgsmme $LIBS"
++AC_TRY_LINK([#include <gsmlib/gsm_util.h>],[(void)gsmlib::latin1ToGsm("text");], 
++	[have_smsgsm_lib=yes],
++	[have_smsgsm_lib=no])
++LIBS=$ac_save_LIBS
++
++AC_CHECK_HEADER(gsmlib/gsm_util.h, 
++	[have_smsgsm_inc=yes],
++	[have_smsgsm_inc=no])
++
++if test "x$have_smsgsm_lib" != "xyes" || test "x$have_smsgsm_inc" != "xyes"; then
++    compile_smsgsm=no
++fi
++AC_LANG_POP(C++)
++
++# Let the user know
++AC_MSG_CHECKING([if SMSGSM Plugin should be compiled])
++AC_MSG_RESULT($compile_smsgsm)
++
++# Here we go
++AM_CONDITIONAL(include_smsgsm, [test "x$compile_smsgsm" = "xyes"])
++
++if test "x$compile_smsgsm" = "xyes"; then
++	AC_DEFINE(INCLUDE_SMSGSM, 1, [Define to compile with GSM SMS support])
++fi
+--- kopete/protocols/irc/irccontact.h	(revision 568672)
++++ kopete/protocols/irc/irccontact.h	(revision 586398)
+@@ -1,11 +1,12 @@
+ /*
+     irccontact.h - IRC Contact
+ 
++    Copyright (c) 2005      by Tommi Rantala <tommi.rantala at cs.helsinki.fi>
+     Copyright (c) 2003-2004 by Michel Hermier <michel.hermier at wanadoo.fr>
+     Copyright (c) 2003      by Jason Keirstead <jason at keirstead.org>
+     Copyright (c) 2002      by Nick Betcher <nbetcher at kde.org>
+ 
+-    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -94,7 +95,7 @@
+ 	 * return true if the contact is in a chat. false if the contact is in no chats
+ 	 * that loop over all manager, and checks the presence of the user
+ 	 */
+-	bool isChatting( Kopete::ChatSession *avoid = 0L ) const;
++	bool isChatting( const Kopete::ChatSession *avoid = 0L ) const;
+ 
+ 	virtual const QString caption() const;
+ //	virtual const QString formatedName() const;
+@@ -123,7 +124,7 @@
+ 
+ protected slots:
+ 	virtual void slotSendMsg(Kopete::Message &message, Kopete::ChatSession *);
+-	QString sendMessage( const QString &msg );
++	QStringList sendMessage( const QString &msg );
+ 
+ 	virtual void chatSessionDestroyed();
+ 
+--- kopete/protocols/irc/ircprotocol.cpp	(revision 568672)
++++ kopete/protocols/irc/ircprotocol.cpp	(revision 586398)
+@@ -107,25 +107,48 @@
+ IRCProtocol::IRCProtocol( QObject *parent, const char *name, const QStringList & /* args */ )
+ : Kopete::Protocol( IRCProtocolFactory::instance(), parent, name ),
+ 
+-	m_ServerStatusOnline(Kopete::OnlineStatus::Online, 100, this, OnlineServer, QString::null, i18n("Online")),
+-	m_ServerStatusOffline(Kopete::OnlineStatus::Offline, 90, this, OfflineServer, QString::null, i18n("Offline")),
++	m_ServerStatusOnline(Kopete::OnlineStatus::Online,
++			100, this, OnlineServer, QString::null, i18n("Online")),
++	m_ServerStatusOffline(Kopete::OnlineStatus::Offline,
++			90, this, OfflineServer, QString::null, i18n("Offline")),
+ 
+-	m_ChannelStatusOnline(Kopete::OnlineStatus::Online, 80, this, OnlineChannel, QString::null, i18n("Online")),
+-	m_ChannelStatusOffline(Kopete::OnlineStatus::Offline, 70, this, OfflineChannel, QString::null, i18n("Offline")),
++	m_ChannelStatusOnline(Kopete::OnlineStatus::Online,
++			80, this, OnlineChannel, QString::null, i18n("Online")),
++	m_ChannelStatusOffline(Kopete::OnlineStatus::Offline,
++			70, this, OfflineChannel, QString::null, i18n("Offline")),
+ 
+-	m_UserStatusOpVoice(Kopete::OnlineStatus::Online, 60, this, Operator | Voiced, QStringList::split(' ',"irc_voice irc_op"), i18n("Op")),
+-	m_UserStatusOpVoiceAway(Kopete::OnlineStatus::Away, 55, this, Operator | Voiced | Away, QStringList::split(' ',"irc_voice irc_op contact_away_overlay"), i18n("Away")),
+-	m_UserStatusOp(Kopete::OnlineStatus::Online, 50, this, Operator, "irc_op", i18n("Op")),
+-	m_UserStatusOpAway(Kopete::OnlineStatus::Away, 45, this, Operator | Away, QStringList::split(' ',"irc_op contact_away_overlay"), i18n("Away")),
+-	m_UserStatusVoice(Kopete::OnlineStatus::Online, 30, this, Voiced, "irc_voice", i18n("Voice")),
+-	m_UserStatusVoiceAway(Kopete::OnlineStatus::Away, 35, this, Voiced | Away, QStringList::split(' ',"irc_voice contact_away_overlay"),  i18n("Away")),
+-	m_UserStatusOnline(Kopete::OnlineStatus::Online, 25, this, Online, QString::null, i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online),
+-	m_UserStatusAway(Kopete::OnlineStatus::Away, 2, this, Away, "contact_away_overlay", i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away),
+-	m_UserStatusConnecting(Kopete::OnlineStatus::Connecting, 1, this, Connecting, "irc_connecting", i18n("Connecting")),
+-	m_UserStatusOffline(Kopete::OnlineStatus::Offline, 0, this, Offline, QString::null, i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline),
++	m_UserStatusOpVoice(Kopete::OnlineStatus::Online,
++			60, this, Online | Operator | Voiced, QStringList::split(' ',"irc_voice irc_op"), i18n("Op")),
++	m_UserStatusOpVoiceAway(Kopete::OnlineStatus::Away,
++			55, this, Online | Operator | Voiced | Away,
++			QStringList::split(' ',"irc_voice irc_op contact_away_overlay"), i18n("Away")),
+ 
+-	m_StatusUnknown(Kopete::OnlineStatus::Unknown, 999, this, 999, "status_unknown", i18n("Status not available")),
++	m_UserStatusOp(Kopete::OnlineStatus::Online,
++			50, this, Online | Operator, "irc_op", i18n("Op")),
++	m_UserStatusOpAway(Kopete::OnlineStatus::Away,
++			45, this, Online | Operator | Away,
++			QStringList::split(' ',"irc_op contact_away_overlay"), i18n("Away")),
+ 
++	m_UserStatusVoice(Kopete::OnlineStatus::Online,
++			40, this, Online | Voiced, "irc_voice", i18n("Voice")),
++	m_UserStatusVoiceAway(Kopete::OnlineStatus::Away,
++			35, this, Online | Voiced | Away,
++			QStringList::split(' ',"irc_voice contact_away_overlay"),  i18n("Away")),
++
++	m_UserStatusOnline(Kopete::OnlineStatus::Online,
++			25, this, Online, QString::null, i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online),
++
++	m_UserStatusAway(Kopete::OnlineStatus::Away,
++			2, this, Online | Away, "contact_away_overlay",
++			i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away),
++	m_UserStatusConnecting(Kopete::OnlineStatus::Connecting,
++			1, this, Connecting, "irc_connecting", i18n("Connecting")),
++	m_UserStatusOffline(Kopete::OnlineStatus::Offline,
++			0, this, Offline, QString::null, i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline),
++
++	m_StatusUnknown(Kopete::OnlineStatus::Unknown,
++			999, this, 999, "status_unknown", i18n("Status not available")),
++
+ 	propChannelTopic(QString::fromLatin1("channelTopic"), i18n("Topic"), QString::null, false, true ),
+ 	propChannelMembers(QString::fromLatin1("channelMembers"), i18n("Members")),
+ 	propHomepage(QString::fromLatin1("homePage"), i18n("Home Page")),
+@@ -296,43 +319,47 @@
+ 
+ 	switch( status )
+ 	{
+-		case Offline:
+-			return m_UserStatusOffline;
+-		case Connecting:
+-			return m_UserStatusConnecting;
+-		case Online:
+-			return m_UserStatusOnline;
+-		case Away:
+-		case Online | Away:
+-			return m_UserStatusAway;
+-		case Voiced:
+-		case Online | Voiced:
+-			return m_UserStatusVoice;
+-		case Away | Voiced:
+-		case Online | Away | Voiced:
+-			return m_UserStatusVoiceAway;
+-		case Operator:
+-		case Online | Operator:
+-			return m_UserStatusOp;
+-		case Away | Operator:
+-		case Online | Away | Operator:
+-			return m_UserStatusOpAway;
+-		case Operator | Voiced:
+-		case Online | Operator | Voiced:
+-			return m_UserStatusOpVoice;
+-		case Operator | Voiced | Away:
+-		case Online | Operator | Voiced | Away:
+-		 	return m_UserStatusOpVoiceAway;
+-		case OnlineServer:
+-			return m_ServerStatusOnline;
+-		case OfflineServer:
+-			return m_ServerStatusOffline;
+-		case OnlineChannel:
+-			return m_ChannelStatusOnline;
+-		case OfflineChannel:
+-			return m_ChannelStatusOffline;
+-		default:
+-			return m_StatusUnknown;
++	case Offline:
++		return m_UserStatusOffline;
++	case Connecting:
++		return m_UserStatusConnecting;
++
++	// Regular user
++	case Online:
++		return m_UserStatusOnline;
++	case Online | Away:
++		return m_UserStatusAway;
++
++	// Voiced
++	case Online | Voiced:
++		return m_UserStatusVoice;
++	case Online | Away | Voiced:
++		return m_UserStatusVoiceAway;
++
++	// Operator
++	case Online | Operator:
++		return m_UserStatusOp;
++	case Online | Away | Operator:
++		return m_UserStatusOpAway;
++	case Online | Operator | Voiced:
++		return m_UserStatusOpVoice;
++	case Online | Operator | Voiced | Away:
++		return m_UserStatusOpVoiceAway;
++
++	// Server
++	case OnlineServer:
++		return m_ServerStatusOnline;
++	case OfflineServer:
++		return m_ServerStatusOffline;
++
++	// Channel
++	case OnlineChannel:
++		return m_ChannelStatusOnline;
++	case OfflineChannel:
++		return m_ChannelStatusOffline;
++
++	default:
++		return m_StatusUnknown;
+ 	}
+ }
+ 
+@@ -419,27 +446,31 @@
+ 
+ void IRCProtocol::slotRawCommand( const QString &args, Kopete::ChatSession *manager )
+ {
++	IRCAccount *account = static_cast<IRCAccount*>( manager->account() );
++
+ 	if (!args.isEmpty())
+ 	{
+-		static_cast<IRCAccount*>(manager->account())->engine()->writeRawMessage(args);
++		account->engine()->writeRawMessage(args);
+ 	}
+ 	else
+ 	{
+-		static_cast<IRCAccount*>(manager->account())->appendMessage(
+-			i18n("You must enter some text to send to the server."), IRCAccount::ErrorReply );
++		account->appendMessage(i18n("You must enter some text to send to the server."),
++				IRCAccount::ErrorReply );
+ 	}
+ }
+ 
+ void IRCProtocol::slotQuoteCommand( const QString &args, Kopete::ChatSession *manager )
+ {
++	IRCAccount *account = static_cast<IRCAccount*>( manager->account() );
++
+ 	if( !args.isEmpty() )
+ 	{
+-		static_cast<IRCAccount*>( manager->account() )->engine()->writeMessage( args );
++		account->engine()->writeMessage( args );
+ 	}
+ 	else
+ 	{
+-		static_cast<IRCAccount*>( manager->account() )->appendMessage(
+-			i18n("You must enter some text to send to the server."), IRCAccount::ErrorReply );
++		account->appendMessage(i18n("You must enter some text to send to the server."),
++				IRCAccount::ErrorReply );
+ 	}
+ }
+ 
+@@ -682,7 +713,7 @@
+ 		else
+ 			chan->part();
+ 		if( manager->view() )
+-			manager->view()->closeView();
++			manager->view()->closeView(true);
+ 	}
+ 	else
+ 	{
+@@ -860,7 +891,9 @@
+ 		{
+ 			netConf->host->setText( host->host );
+ 			netConf->password->setText( host->password );
++			disconnect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ 			netConf->port->setValue( host->port );
++			connect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ 			netConf->useSSL->setChecked( host->ssl );
+ 
+ 			netConf->upButton->setEnabled( netConf->hostList->currentItem() > 0 );
+@@ -935,6 +968,8 @@
+ 
+ void IRCProtocol::slotNewNetwork()
+ {
++	// create a new network struct
++	IRCNetwork *net = new IRCNetwork;
+ 	// give it the name of 'New Network' (incrementing number if needed)
+ 	QString netName = QString::fromLatin1( "New Network" );
+ 	if ( m_networks.find( netName ) )
+@@ -947,8 +982,6 @@
+ 		if ( newIdx == 100 ) // pathological case
+ 			return;
+ 	}
+-	// create a new network struct
+-	IRCNetwork *net = new IRCNetwork;
+ 	net->name = netName;
+ 	// and add it to the networks dict and list
+ 	m_networks.insert( net->name, net );
+@@ -960,6 +993,8 @@
+ 
+ void IRCProtocol::slotNewHost()
+ {
++	// create a new host
++	IRCHost *host = new IRCHost;
+ 	// prompt for a name
+ 	bool ok;
+ 	QString name = KInputDialog::getText(
+@@ -974,8 +1009,6 @@
+ 			KMessageBox::sorry(netConf, i18n( "A host already exists with that name" ) );
+ 			return;
+ 		}
+-		// create a new host
+-		IRCHost *host = new IRCHost;
+ 		// set defaults on others
+ 		host->host = name;
+ 		host->port = 6667;
+@@ -1170,8 +1203,8 @@
+ 	if( currentPos > 0 )
+ 	{
+ 		netConf->hostList->removeItem( currentPos );
+-		kdDebug(14121) << k_funcinfo << selectedHost->host << endl;
+-		netConf->hostList->insertItem( selectedHost->host, --currentPos );
++		QString entryText = selectedHost->host + QString::fromLatin1(":") + QString::number( selectedHost->port );
++		netConf->hostList->insertItem( entryText, --currentPos );
+ 		netConf->hostList->setSelected( currentPos, true );
+ 	}
+ }
+@@ -1195,7 +1228,8 @@
+ 	if( currentPos < ( netConf->hostList->count() - 1 ) )
+ 	{
+ 		netConf->hostList->removeItem( currentPos );
+-		netConf->hostList->insertItem( selectedHost->host, ++currentPos );
++		QString entryText = selectedHost->host + QString::fromLatin1(":") + QString::number( selectedHost->port );
++		netConf->hostList->insertItem( entryText, ++currentPos );
+ 		netConf->hostList->setSelected( currentPos, true );
+ 	}
+ }
+--- kopete/protocols/irc/ircservercontact.cpp	(revision 568672)
++++ kopete/protocols/irc/ircservercontact.cpp	(revision 586398)
+@@ -143,13 +143,28 @@
+ 
+ void IRCServerContact::slotIncomingNotice( const QString &orig, const QString &notice )
+ {
+-	QString originator = orig.contains('!') ? orig.section('!',0,1) : orig;
+-	ircAccount()->appendMessage(
+-		i18n("NOTICE from %1: %2").arg(
+-			originator == ircAccount()->mySelf()->nickName() ? kircEngine()->currentHost() : originator, notice
+-		),
+-		IRCAccount::NoticeReply
+-	);
++	if (orig.isEmpty()) {
++		// Prefix missing.
++		// NOTICE AUTH :*** Checking Ident
++
++		ircAccount()->appendMessage(i18n("NOTICE from %1: %2").arg(kircEngine()->currentHost(), notice),
++				IRCAccount::NoticeReply);
++
++	} else {
++		// :Global!service at rizon.net NOTICE foobar :[Logon News - Oct 12 2005] Due to growing problems ...
++		// :somenick!~fooobar at somehostname.fi NOTICE foobar :hello
++
++		if (orig.contains('!')) {
++			ircAccount()->appendMessage(i18n("NOTICE from %1 (%2): %3").arg(
++						orig.section('!', 0, 0),
++						orig.section('!', 1, 1),
++						notice),
++					IRCAccount::NoticeReply);
++		} else {
++			ircAccount()->appendMessage(i18n("NOTICE from %1: %2").arg(
++						orig, notice), IRCAccount::NoticeReply);
++		}
++	}
+ }
+ 
+ void IRCServerContact::slotIncomingUnknown(const QString &message)
+--- kopete/protocols/irc/ircchannelcontact.h	(revision 568672)
++++ kopete/protocols/irc/ircchannelcontact.h	(revision 586398)
+@@ -110,7 +110,7 @@
+ 	void setMode( const QString &mode = QString::null );
+ 
+ 	void part();
+-
++	void partAction();
+ 	void join();
+ 
+ protected slots:
+@@ -127,9 +127,9 @@
+ 	void slotUpdateInfo();
+ 	void slotHomepage();
+ 	void slotChannelListed(const QString &channel, uint members, const QString &topic);
++	void slotOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus);
+ 
+ private:
+-	// KAction stuff:
+ 	KAction *actionJoin;
+ 	KAction *actionPart;
+ 	KAction *actionTopic;
+@@ -137,21 +137,20 @@
+ 	KActionMenu *actionModeMenu;
+ 	KCodecAction *codecAction;
+ 
+-	KToggleAction *actionModeT;
+-	KToggleAction *actionModeN;
+-	KToggleAction *actionModeS;
+-	KToggleAction *actionModeI;
+-	KToggleAction *actionModeP;
+-	KToggleAction *actionModeM;
+-	KToggleAction *actionModeB;
++	KToggleAction *actionModeT;    // Only Operators Can Change Topic
++	KToggleAction *actionModeN;    // No Outside Messages
++	KToggleAction *actionModeS;    // Secret
++	KToggleAction *actionModeI;    // Invite Only
++	KToggleAction *actionModeM;    // Moderated
+ 
+ 	QString mTopic;
+ 	QString mPassword;
+ 	QStringList mJoinedNicks;
+-	QMap<QString,bool> modeMap;
++	QMap<QString, bool> modeMap;
+ 	QTimer *mInfoTimer;
+ 
+ 	void toggleMode( QChar mode, bool enabled, bool update );
++	void toggleOperatorActions( bool enabled );
+ };
+ 
+ #endif
+--- kopete/protocols/irc/ircnetworks.xml	(revision 568672)
++++ kopete/protocols/irc/ircnetworks.xml	(revision 586398)
+@@ -771,10 +771,15 @@
+         <description>The Open and Free Technology Community</description>
+         <servers>
+             <server>
+-                <host>irc.debian.org</host>
++                <host>irc.oftc.org</host>
+                 <port>6667</port>
+                 <useSSL>false</useSSL>
+             </server>
++            <server>
++                <host>ircs.oftc.org</host>
++                <port>9999</port>
++                <useSSL>true</useSSL>
++            </server>
+         </servers>
+     </network>
+     <network>
+--- kopete/protocols/irc/irccontact.cpp	(revision 568672)
++++ kopete/protocols/irc/irccontact.cpp	(revision 586398)
+@@ -3,8 +3,9 @@
+ 
+     Copyright (c) 2002      by Nick Betcher <nbetcher at kde.org>
+     Copyright (c) 2004      by Michel Hermier <michel.hermier at wanadoo.fr>
++    Copyright (c) 2005      by Tommi Rantala <tommi.rantala at cs.helsinki.fi>
+ 
+-    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -220,6 +221,14 @@
+ {
+ 	QString htmlString = message.escapedBody();
+ 
++	// Messages we get with RichText enabled:
++	//
++	// Hello world in bold and color:
++	//   <span style="font-weight:600;color:#403897">Hello World</span>
++	// 
++	// Two-liner in color:
++	//   <span style="color:#403897">Hello<br />World</span>
++
+ 	if (htmlString.find(QString::fromLatin1("</span")) > -1)
+ 	{
+ 		QRegExp findTags( QString::fromLatin1("<span style=\"(.*)\">(.*)</span>") );
+@@ -246,10 +255,15 @@
+ 						if( ircColor > -1 )
+ 							replacement.prepend( QString( QChar(0x03) ).append( QString::number(ircColor) ) ).append( QChar( 0x03 ) );
+ 					}
+-					else if( attribute == QString::fromLatin1("font-weight") && value == QString::fromLatin1("600") )
++					else if( attribute == QString::fromLatin1("font-weight") &&
++					             value == QString::fromLatin1("600") ) {
++						// Bolding
+ 						replacement.prepend( QChar(0x02) ).append( QChar(0x02) );
+-					else if( attribute == QString::fromLatin1("text-decoration")  && value == QString::fromLatin1("underline") )
++					}
++					else if( attribute == QString::fromLatin1("text-decoration") &&
++					             value == QString::fromLatin1("underline") ) {
+ 						replacement.prepend( QChar(31) ).append( QChar(31) );
++					}
+ 				}
+ 
+ 				htmlString = htmlString.left( pos ) + replacement + htmlString.mid( pos + findTags.matchedLength() );
+@@ -259,48 +273,62 @@
+ 
+ 	htmlString = Kopete::Message::unescape(htmlString);
+ 
+-	if (htmlString.find('\n') > -1)
++	QStringList messages = QStringList::split( '\n', htmlString );
++
++	for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it )
+ 	{
+-		QStringList messages = QStringList::split( '\n', htmlString );
++		// Dont use the resulting string(s). The problem is that we'd have to parse them
++		// back to format that would be suitable for appendMessage().
++		//
++		// TODO: If the given message was plaintext, we could easily show what was
++		// actually sent.
+ 
+-		for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it )
+-		{
+-			Kopete::Message msg(message.from(), message.to(), Kopete::Message::escape(sendMessage(*it)), message.direction(),
+-			                    Kopete::Message::RichText, CHAT_VIEW, message.type());
++		sendMessage(*it);
++	}
+ 
+-			msg.setBg(QColor());
+-			msg.setFg(QColor());
++	if (message.requestedPlugin() != CHAT_VIEW) {
++		Kopete::Message msg(message.from(), message.to(), message.escapedBody(), message.direction(),
++				Kopete::Message::RichText, CHAT_VIEW, message.type());
+ 
+-			appendMessage(msg);
+-			manager(Kopete::Contact::CanCreate)->messageSucceeded();
+-		}
++		msg.setBg(QColor());
++		msg.setFg(QColor());
++
++		appendMessage(msg);
++	} else {
++		// Lets not modify the given message object.
++		Kopete::Message msg = message;
++		msg.setBg(QColor());
++		appendMessage(msg);
+ 	}
+-	else
+-	{
+-		message.setBody( Kopete::Message::escape(sendMessage( htmlString )), Kopete::Message::RichText );
+ 
+-		message.setBg( QColor() );
+-		message.setFg( QColor() );
+-
+-		appendMessage(message);
+-		manager(Kopete::Contact::CanCreate)->messageSucceeded();
+-	}
++	manager(Kopete::Contact::CanCreate)->messageSucceeded();
+ }
+ 
+-QString IRCContact::sendMessage( const QString &msg )
++QStringList IRCContact::sendMessage( const QString &msg )
+ {
++	QStringList messages;
++
+ 	QString newMessage = msg;
+-	uint trueLength = msg.length() + m_nickName.length() + 12;
+-	if( trueLength > 512 )
+-	{
+-		//TODO: tell them it is truncated
+-		kdWarning() << "Message was to long (" << trueLength << "), it has been truncated to 512 characters" << endl;
+-		newMessage.truncate( 512 - ( m_nickName.length() + 12 ) );
+-	}
+ 
+-	kircEngine()->privmsg(m_nickName, newMessage );
++	// IRC limits the message size to 512 characters. So split the given
++	// message into pieces.
++	//
++	// This can of course give nasty results, but most of us dont write
++	// that long lines anyway ;-)... And this is how other clients also
++	// seem to behave.
+ 
+-	return newMessage;
++	int l = 500 - m_nickName.length();
++
++	do {
++		messages.append(newMessage.mid(0, l));
++		newMessage.remove(0, l);
++	} while (!newMessage.isEmpty());
++
++	for (QStringList::const_iterator it = messages.begin();
++	     it != messages.end(); ++it)
++		kircEngine()->privmsg(m_nickName, *it);
++
++	return messages;
+ }
+ 
+ Kopete::Contact *IRCContact::locateUser(const QString &nick)
+@@ -324,7 +352,7 @@
+ 	return 0;
+ }
+ 
+-bool IRCContact::isChatting(Kopete::ChatSession *avoid) const
++bool IRCContact::isChatting(const Kopete::ChatSession *avoid) const
+ {
+ 	IRCAccount *account = ircAccount();
+ 
+--- kopete/protocols/irc/ircusercontact.h	(revision 568672)
++++ kopete/protocols/irc/ircusercontact.h	(revision 586398)
+@@ -46,6 +46,7 @@
+ 	bool isOperator;
+ 	bool isIdentified;
+ 	bool away;
++	bool online;
+ 	uint hops;
+ 	QDateTime lastOnline;
+ 	QTime lastUpdate;
+@@ -90,6 +91,8 @@
+ 		const QString &realName );
+ 
+ public slots:
++	/** \brief Updates online status for channels based on current internal status.
++	 */
+ 	virtual void updateStatus();
+ 
+ 	virtual void sendFile(const KURL &sourceURL, const QString&, unsigned int);
+@@ -111,14 +114,23 @@
+ 	void slotKick();
+ 	void slotUserOffline();
+ 
++	void slotBanHostOnce();
++	void slotBanUserHostOnce();
++	void slotBanDomainOnce();
++	void slotBanUserDomainOnce();
++
+ 	virtual void slotUserInfo();
+ 
+ 	//This can't be handled by the contact manager since
+ 	void slotIncomingModeChange(const QString &nick, const QString &channel, const QString &mode);
+ 
+ private:
+-	void setManagerStatus(IRCChannelContact *channel, int statusAdjustment );
++	enum bitAdjustment { RemoveBits, AddBits };
++	void adjustInternalOnlineStatusBits(IRCChannelContact *channel, unsigned statusAdjustment, bitAdjustment adj);
+ 
++	void contactMode(const QString &mode);
++	void updateInfo();
++
+ 	KActionMenu *actionModeMenu;
+ 	KActionMenu *actionCtcpMenu;
+ 	KAction *actionKick;
+@@ -127,15 +139,8 @@
+ 	Kopete::ChatSession *mActiveManager;
+ 	QTimer *mOnlineTimer;
+ 	IRCUserInfo mInfo;
+-
+-	bool m_isAway;
+-	bool m_isOnline;
+-
+-	void contactMode(const QString &mode);
+-	void updateInfo();
+ };
+ 
+ #endif
+ 
+ // vim: set noet ts=4 sts=4 tw=4:
+-
+--- kopete/protocols/irc/libkirc/kircengine_commands.cpp	(revision 568672)
++++ kopete/protocols/irc/libkirc/kircengine_commands.cpp	(revision 586398)
+@@ -300,7 +300,7 @@
+ void Engine::notice(Message &msg)
+ {
+ 	if(!msg.suffix().isEmpty())
+-		emit incomingNotice(msg.arg(0), msg.suffix());
++		emit incomingNotice(msg.prefix(), msg.suffix());
+ 
+ 	if(msg.hasCtcpMessage())
+ 		invokeCtcpCommandOfMessage(m_ctcpReplies, msg);
+--- kopete/protocols/irc/libkirc/kircmessage.h	(revision 568672)
++++ kopete/protocols/irc/libkirc/kircmessage.h	(revision 586398)
+@@ -40,11 +40,10 @@
+ class Engine;
+ 
+ class Message
+-	: public QObject
+ {
+-	Q_OBJECT
+-
+ public:
++	/** \brief Sends the message as-is to the server.
++	 */
+ 	static void writeRawMessage(KIRC::Engine *engine, const QTextCodec *codec, const QString &str);
+ 
+ 	static void writeMessage(KIRC::Engine *engine, const QTextCodec *codec, const QString &str);
+@@ -71,23 +70,65 @@
+ 
+ 	QString toString() const;
+ 
++	/** \brief Returns true if the message command is numeric.
++	 */
+ 	bool isNumeric() const;
++
++	/** \brief Message is valid if it was parsed correctly.
++	 */
+ 	bool isValid() const;
++
++	/** \brief Writes internal message information about this message through kdDebug().
++	 */
+ 	void dump() const;
++
++	/** \brief Re-decodes the message with given codec.
++	 */
+ 	void decodeAgain( const QTextCodec *codec );
+ 
++	/** \brief The whole message as received.
++	 */
+ 	inline const QCString &raw() const
+ 		{ return m_raw; }
++
++	/** \brief Prefix of this message.
++	 *
++	 * Returns the prefix of the message. Note that it can be empty.
++	 *
++	 * Prefix is the server name or the nick name of the sender.
++	 *
++	 * message    =  [ ":" prefix SPACE ] command [ params ] crlf
++	 * prefix     =  servername / ( nickname [ [ "!" user ] "@" host ] )
++	 */
+ 	inline const QString &prefix() const
+ 		{ return m_prefix; }
++
++	/** \brief The command part of this message.
++	 *
++	 * Returns the command of this message. Can be numerical.
++	 *
++	 * Examples: "MODE", "PRIVMSG", 303, 001, ...
++	 */
+ 	inline const QString &command() const
+ 		{ return m_command; }
++
++	/** \brief The number of command arguments this message contains.
++	 */
+ 	inline size_t argsSize() const
+ 		{ return m_args.size(); }
++
++	/** \brief i:th command argument.
++	 */
+ 	inline const QString &arg(size_t i) const
+ 		{ return m_args[i]; }
++
++	/** \brief All command arguments.
++	 */
+ 	inline const QStringList &args() const
+ 		{ return m_args; }
++
++	/** \brief Message suffix.
++	 */
+ 	inline const QString &suffix() const
+ 		{ return m_suffix; }
+ 	inline const QString &ctcpRaw() const
+--- kopete/protocols/irc/libkirc/kircengine.cpp	(revision 568672)
++++ kopete/protocols/irc/libkirc/kircengine.cpp	(revision 586398)
+@@ -448,7 +448,9 @@
+ 		else
+ 		{
+ 			kdDebug(14120) << "Unknow IRC/CTCP command for line:" << ctcpMsg.raw() << endl;
+-			writeCtcpErrorMessage(msg.prefix(), msg.ctcpRaw(), "Unknown CTCP command");
++			// Don't send error message on unknown CTCP command
++			// None of the client send it, and it makes the client as infected by virus for IRC network scanners
++			// writeCtcpErrorMessage(msg.prefix(), msg.ctcpRaw(), "Unknown CTCP command");
+ 
+ 			emit incomingUnknownCtcp(msg.ctcpRaw());
+ 		}
+--- kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp	(revision 568672)
++++ kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp	(revision 586398)
+@@ -412,21 +412,24 @@
+ 
+ /* 352:
+  * WHO Reply
++ * 
++ * "<channel> <user> <host> <server> <nick> ("H" / "G") ["*"] [("@" / "+")] :<hopcount> <real name>"
++ *
++ * :efnet.cs.hut.fi 352 userNick #foobar username some.host.name efnet.cs.hut.fi someNick H :0 foobar
++ * :efnet.cs.hut.fi 352 userNick #foobar ~fooobar other.hostname irc.dkom.at anotherNick G+ :3 Unknown
+  */
+ void Engine::numericReply_352(Message &msg)
+ {
+-	QStringList suffix = QStringList::split( ' ', msg.suffix() );
+-
+ 	emit incomingWhoReply(
+-		Kopete::Message::unescape(msg.arg(5)),
+-		Kopete::Message::unescape(msg.arg(1)),
+-		msg.arg(2),
+-		msg.arg(3),
+-		msg.arg(4),
+-		msg.arg(6)[0] != 'H',
+-		msg.arg(7),
+-		msg.suffix().section(' ', 0, 1 ).toUInt(),
+-		msg.suffix().section(' ', 1 )
++		Kopete::Message::unescape(msg.arg(5)),       // nick name
++		Kopete::Message::unescape(msg.arg(1)),       // channel name
++		msg.arg(2),                                  // user name
++		msg.arg(3),                                  // host name
++		msg.arg(4),                                  // server name
++		msg.arg(6)[0] != 'H',                        // G=away (true), H=not away (false)
++		msg.arg(7),                                  // @ (op), + (voiced)
++		msg.suffix().section(' ', 0, 1 ).toUInt(),   // hopcount
++		msg.suffix().section(' ', 1 )                // real name
+ 	);
+ }
+ 
+--- kopete/protocols/irc/libkirc/kircmessage.cpp	(revision 568672)
++++ kopete/protocols/irc/libkirc/kircmessage.cpp	(revision 586398)
+@@ -53,7 +53,7 @@
+ }
+ 
+ Message::Message(const Message &obj)
+-        : QObject(), m_ctcpMessage(0)
++        : m_ctcpMessage(0)
+ {
+ 	m_raw = obj.m_raw;
+ 
+@@ -123,7 +123,7 @@
+ 		msg += QChar(' ') + args.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here
+ 
+ 	if (!suffix.isNull())
+-          msg = msg.stripWhiteSpace() + QString::fromLatin1(" :") + suffix;
++		msg = msg.stripWhiteSpace() + QString::fromLatin1(" :") + suffix;
+ 
+ 	writeMessage(engine, codec, msg);
+ }
+@@ -368,5 +368,3 @@
+ 		m_ctcpMessage->dump();
+ 	}
+ }
+-
+-#include "kircmessage.moc"
+--- kopete/protocols/irc/ircprotocol.h	(revision 568672)
++++ kopete/protocols/irc/ircprotocol.h	(revision 586398)
+@@ -26,7 +26,7 @@
+ #include <dom/dom_node.h>
+ #include <qdict.h>
+ 
+-#define m_protocol ((IRCProtocol*)IRCProtocol::protocol())
++#define m_protocol (IRCProtocol::protocol())
+ 
+ namespace Kopete
+ {
+@@ -68,17 +68,17 @@
+ public:
+ 	enum IRCStatus
+ 	{
+-		Offline = 1,
+-		Connecting = 2,
+-		Away = 4,
+-		Online = 8,
+-		Voiced = 16,
+-		Operator = 32,
+-		ServerOperator = 1024,
+-		OfflineChannel = 4096,
+-		OnlineChannel = 8192,
+-		OfflineServer = 16384,
+-		OnlineServer = 32768
++		Offline        = 1,                 //! An offline user.
++		Connecting     = 2,                 //! User that is connecting.
++		Away           = 4,                 //! User that is away. May be regular user, voiced user or (server) operator.
++		Online         = 8,                 //! This user is online.
++		Voiced         = 16,                //! This user is voiced.
++		Operator       = 32,                //! This user is a channel operator.
++		ServerOperator = 1024,              //! This user is a server operator.
++		OfflineChannel = 4096,              //! This channel is offline.
++		OnlineChannel  = 8192,              //! This channel is online.
++		OfflineServer  = 16384,             //! This server is offline.
++		OnlineServer   = 32768              //! This server is online.
+ 	};
+ 
+ 	IRCProtocol( QObject *parent, const char *name, const QStringList &args );
+@@ -101,6 +101,9 @@
+ 
+ 	static IRCProtocol *protocol();
+ 
++	/**
++	 * Maps the given IRC status to Kopete::OnlineStatus.
++	 */
+ 	const Kopete::OnlineStatus statusLookup( IRCStatus status ) const;
+ 
+ 	const Kopete::OnlineStatus m_ServerStatusOnline;
+--- kopete/protocols/irc/ircchannelcontact.cpp	(revision 568672)
++++ kopete/protocols/irc/ircchannelcontact.cpp	(revision 586398)
+@@ -111,6 +111,36 @@
+ 	}
+ }
+ 
++void IRCChannelContact::toggleOperatorActions(bool enabled)
++{
++	if (enabled) {
++		actionTopic->setEnabled(true);
++	} else if (modeEnabled('t')) {
++		actionTopic->setEnabled(false);
++	}
++
++	actionModeT->setEnabled(enabled);
++	actionModeN->setEnabled(enabled);
++	actionModeS->setEnabled(enabled);
++	actionModeM->setEnabled(enabled);
++	actionModeI->setEnabled(enabled);
++}
++
++void IRCChannelContact::slotOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus)
++{
++	Q_UNUSED(oldStatus);
++
++	if (c == account()->myself()) {
++		if (status.internalStatus() & IRCProtocol::Operator) { 
++			kdDebug(14120) << k_funcinfo << "WE NOW HAVE OP STATUS" << endl;
++			toggleOperatorActions(true);
++		} else {
++			kdDebug(14120) << k_funcinfo << "WE NOW dont HAVE OP STATUS" << endl;
++			toggleOperatorActions(false);
++		}
++	}
++}
++
+ void IRCChannelContact::updateStatus()
+ {
+ 	KIRC::Engine::Status status = kircEngine()->status();
+@@ -185,21 +215,33 @@
+ 
+ 	for( uint i = 0; !mJoinedNicks.isEmpty() && i < NICK_BATCH_LENGTH; ++i )
+ 	{
++		// Pick a nick from the front of the list.
++
+ 		QString nickToAdd = mJoinedNicks.front();
+ 		QChar firstChar = nickToAdd[0];
+ 		if( firstChar == '@' || firstChar == '%' || firstChar == '+' )
+ 			nickToAdd = nickToAdd.remove(0, 1);
+ 
+-		IRCContact *user;
++		IRCUserContact *user;
+ 
+ 		if ( nickToAdd.lower() != account->mySelf()->nickName().lower() )
+ 		{
+-			//kdDebug(14120) << k_funcinfo << m_nickName << " NICK: " << nickToAdd << endl;
++			//kdDebug(14120) << k_funcinfo << m_nickName << " nick to add: " << nickToAdd << endl;
++
+ 			user = account->contactManager()->findUser(nickToAdd);
+-			user->setOnlineStatus(m_protocol->m_UserStatusOnline);
++
++			// If the user is already present in some channel, dont flip the status
++			// back to online, because the other channels listen to
++			// onlineStatusChanged() emits, and they would adjust their statuses.
++
++			if (account->contactManager()->findChannelsByMember(user).isEmpty()) {
++				//kdDebug(14120) << k_funcinfo << "Setting nick ONLINE" << endl;
++				user->setOnlineStatus(m_protocol->m_UserStatusOnline);
++			}
+ 		}
+ 		else
+ 		{
++			// Handling my nick in the list.
+ 			user = account->mySelf();
+ 		}
+ 
+@@ -212,9 +254,9 @@
+ 			status = user->onlineStatus();
+ 
+ 		if( user != account->mySelf() )
+-			manager()->addContact(static_cast<Kopete::Contact*>(user) , status, true);
++			manager()->addContact(user , status, true);
+ 		else
+-			manager()->setContactOnlineStatus( static_cast<Kopete::Contact*>(user), status );
++			manager()->setContactOnlineStatus(user, status);
+ 
+ 		mJoinedNicks.pop_front();
+ 	}
+@@ -227,9 +269,18 @@
+ 	mTopic = topic;
+ 	setProperty( m_protocol->propChannelTopic, mTopic );
+ 	manager()->setDisplayName(caption());
+-	Kopete::Message msg((Kopete::Contact*)this, mMyself, i18n("Topic for %1 is %2").arg(m_nickName).arg(mTopic),
+-	                    Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
+-	appendMessage(msg);
++
++	if (mTopic.isEmpty()) {
++		Kopete::Message msg((Kopete::Contact*)this, mMyself,
++				i18n("Topic for %1 is set empty.").arg(m_nickName),
++				Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
++		appendMessage(msg);
++	} else {
++		Kopete::Message msg((Kopete::Contact*)this, mMyself,
++				i18n("Topic for %1 is %2").arg(m_nickName).arg(mTopic),
++				Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
++		appendMessage(msg);
++	}
+ }
+ 
+ void IRCChannelContact::channelHomePage(const QString &url)
+@@ -249,12 +300,26 @@
+ 			kdDebug() << k_funcinfo << "My view:" << manager(Kopete::Contact::CannotCreate)->view(false) << endl;
+ 		startChat();
+ 	}
++
++	if (manager()) {
++		connect(manager(),
++			SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &,
++					const Kopete::OnlineStatus &)),
++			SLOT(slotOnlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &,
++					const Kopete::OnlineStatus &)));
++	}
+ }
+ 
++void IRCChannelContact::partAction()
++{
++	if (manager())
++		manager()->view()->closeView();
++}
++
+ void IRCChannelContact::part()
+ {
+-	if (manager(Kopete::Contact::CannotCreate))
+-	  kircEngine()->part(m_nickName, ircAccount()->defaultPart());
++	if (manager() && !kircEngine()->isDisconnected())
++		kircEngine()->part(m_nickName, ircAccount()->defaultPart());
+ }
+ 
+ void IRCChannelContact::slotIncomingUserIsAway( const QString &nick, const QString & )
+@@ -264,7 +329,7 @@
+ 	if( nick.lower() == account->mySelf()->nickName().lower() )
+ 	{
+ 		IRCUserContact *c = account->mySelf();
+-		if (manager(Kopete::Contact::CannotCreate) && manager()->members().contains(c))
++		if (manager() && manager()->members().contains(c))
+ 		{
+ 			Kopete::OnlineStatus status = manager()->contactOnlineStatus(c);
+ 			if (status == m_protocol->m_UserStatusOp)
+@@ -292,6 +357,7 @@
+ 		kdDebug() << k_funcinfo << "Me:" << this << endl;
+ 		kdDebug() << k_funcinfo << "My nickname:" << m_nickName << endl;
+ 		kdDebug() << k_funcinfo << "My manager:" << manager(Kopete::Contact::CannotCreate) << endl;
++
+ 		if (manager(Kopete::Contact::CannotCreate))
+ 			kdDebug() << k_funcinfo << "My view:" << manager(Kopete::Contact::CannotCreate)->view(false) << endl;
+ 
+@@ -304,6 +370,10 @@
+ 	}
+ 	else
+ 	{
++		// If we have lag or huge channels, we might receive a JOIN after we have left a channel.
++		if (!manager())
++			return;
++
+ 		IRCUserContact *contact = account->contactManager()->findUser( nickname );
+ 		contact->setOnlineStatus( m_protocol->m_UserStatusOnline );
+ 		manager()->addContact((Kopete::Contact *)contact, true);
+@@ -335,26 +405,40 @@
+ {
+ 	IRCAccount *account = ircAccount();
+ 
+-	QString r = i18n("Kicked by %1.").arg(nick);
+-	if (reason != nick)
+-		r.append( i18n(" Reason: %2").arg( reason ) );
+-
+ 	if( nickKicked.lower() != account->engine()->nickName().lower() )
+ 	{
+ 		Kopete::Contact *c = locateUser( nickKicked );
+ 		if (c)
+ 		{
++			QString r;
++
++			if ((reason != nick) && (reason != nickKicked)) {
++				r = i18n( "%1 was kicked by %2. Reason: %3" ).arg(nickKicked, nick, reason);
++			} else {
++				r = i18n( "%1 was kicked by %2." ).arg(nickKicked, nick);
++			}
++
+ 			manager()->removeContact( c, r );
+-			Kopete::Message msg( (Kopete::Contact *)this, mMyself,
+-					      r, Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
++			Kopete::Message msg( this, mMyself, r,
++					Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ 			msg.setImportance(Kopete::Message::Low);
+ 			appendMessage(msg);
+-			if( c->metaContact()->isTemporary() && !static_cast<IRCContact*>(c)->isChatting( manager(Kopete::Contact::CannotCreate) ) )
++
++			if( c->metaContact()->isTemporary() &&
++			    !static_cast<IRCContact*>(c)->isChatting( manager() ) )
+ 				c->deleteLater();
+ 		}
+ 	}
+ 	else
+ 	{
++		QString r;
++
++		if ((reason != nick) && (reason != nickKicked)) {
++			r = i18n( "You were kicked from %1 by %2. Reason: %3" ).arg(m_nickName, nickKicked, reason);
++		} else {
++			r = i18n( "You were kicked from %1 by %2." ).arg(m_nickName, nickKicked);
++		}
++
+ 		KMessageBox::error(Kopete::UI::Global::mainWidget(), r, i18n("IRC Plugin"));
+ 		manager()->view()->closeView();
+ 	}
+@@ -419,7 +503,7 @@
+ 
+ void IRCChannelContact::incomingModeChange( const QString &nick, const QString &mode )
+ {
+-	Kopete::Message msg((Kopete::Contact *)this, mMyself, i18n("%1 sets mode %2 on  %3").arg(nick).arg(mode).arg(m_nickName), Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
++	Kopete::Message msg(this, mMyself, i18n("%1 sets mode %2 on %3").arg(nick).arg(mode).arg(m_nickName), Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ 	msg.setImportance( Kopete::Message::Low); //set the importance manualy to low
+ 	appendMessage(msg);
+ 
+@@ -522,21 +606,28 @@
+ 	{
+ 		switch( mode )
+ 		{
+-			case 't':
+-   				actionModeT->setChecked( enabled );
+-				break;
+-			case 'n':
+-				actionModeN->setChecked( enabled );
+-				break;
+-			case 's':
+-				actionModeS->setChecked( enabled );
+-				break;
+-			case 'm':
+-				actionModeM->setChecked( enabled );
+-				break;
+-			case 'i':
+-				actionModeI->setChecked( enabled );
+-				break;
++		case 't':
++			actionModeT->setChecked( enabled );
++
++			// If someones sets +t and we're not channel operators, disable the action.
++			if (enabled && !(manager()->contactOnlineStatus(ircAccount()->myself()).internalStatus() & IRCProtocol::Operator)) {
++				actionTopic->setEnabled( false );
++			} else {
++				actionTopic->setEnabled( true );
++			}
++			break;
++		case 'n':
++			actionModeN->setChecked( enabled );
++			break;
++		case 's':
++			actionModeS->setChecked( enabled );
++			break;
++		case 'm':
++			actionModeM->setChecked( enabled );
++			break;
++		case 'i':
++			actionModeI->setChecked( enabled );
++			break;
+ 		}
+ 	}
+ 
+@@ -564,12 +655,11 @@
+ 
+ QPtrList<KAction> *IRCChannelContact::customContextMenuActions()
+ {
+-	// KAction stuff
+ 	QPtrList<KAction> *mCustomActions = new QPtrList<KAction>();
+ 	if( !actionJoin )
+ 	{
+ 		actionJoin = new KAction(i18n("&Join"), 0, this, SLOT(join()), this, "actionJoin");
+-		actionPart = new KAction(i18n("&Part"), 0, this, SLOT(part()), this, "actionPart");
++		actionPart = new KAction(i18n("&Part"), 0, this, SLOT(partAction()), this, "actionPart");
+ 		actionTopic = new KAction(i18n("Change &Topic..."), 0, this, SLOT(setTopic()), this, "actionTopic");
+ 		actionModeMenu = new KActionMenu(i18n("Channel Modes"), 0, this, "actionModeMenu");
+ 
+@@ -605,17 +695,13 @@
+ 		mCustomActions->append( actionHomePage );
+ 
+ 	bool isOperator = manager(Kopete::Contact::CannotCreate) &&
+-	    (manager()->contactOnlineStatus(ircAccount()->myself()) == m_protocol->m_UserStatusOp);
++	    (manager()->contactOnlineStatus(ircAccount()->myself()).internalStatus() & IRCProtocol::Operator);
+ 
+ 	actionJoin->setEnabled( !manager(Kopete::Contact::CannotCreate) );
+ 	actionPart->setEnabled( manager(Kopete::Contact::CannotCreate) );
+ 	actionTopic->setEnabled( manager(Kopete::Contact::CannotCreate) && ( !modeEnabled('t') || isOperator ) );
+ 
+-	actionModeT->setEnabled(isOperator);
+-	actionModeN->setEnabled(isOperator);
+-	actionModeS->setEnabled(isOperator);
+-	actionModeM->setEnabled(isOperator);
+-	actionModeI->setEnabled(isOperator);
++	toggleOperatorActions(isOperator);
+ 
+ 	return mCustomActions;
+ }
+--- kopete/protocols/irc/ircusercontact.cpp	(revision 568672)
++++ kopete/protocols/irc/ircusercontact.cpp	(revision 586398)
+@@ -35,31 +35,31 @@
+ 
+ IRCUserContact::IRCUserContact(IRCContactManager *contactManager, const QString &nickname, Kopete::MetaContact *m )
+ 	: IRCContact(contactManager, nickname, m ),
+-	  m_isAway(false)
++	actionCtcpMenu(0L)
+ {
+ 	setFileCapable(true);
+ 
+ 	mOnlineTimer = new QTimer( this );
+-	m_isOnline = metaContact()->isTemporary();
+ 
+ 	QObject::connect(mOnlineTimer, SIGNAL(timeout()), this, SLOT( slotUserOffline() ) );
+ 
+ 	QObject::connect(kircEngine(), SIGNAL(incomingChannelModeChange(const QString&, const QString&, const QString&)),
+ 		this, SLOT(slotIncomingModeChange(const QString&,const QString&, const QString&)));
+ 
+-	actionCtcpMenu = 0L;
+-
+ 	mInfo.isOperator = false;
+ 	mInfo.isIdentified = false;
+ 	mInfo.idle = 0;
+ 	mInfo.hops = 0;
+ 	mInfo.away = false;
++	mInfo.online = metaContact()->isTemporary();
+ 
+ 	updateStatus();
+ }
+ 
+ void IRCUserContact::updateStatus()
+ {
++	//kdDebug(14120) << k_funcinfo << endl;
++
+         Kopete::OnlineStatus newStatus;
+ 
+ 	switch (kircEngine()->status())
+@@ -78,9 +78,9 @@
+ 
+ 		case KIRC::Engine::Connected:
+ 		case KIRC::Engine::Closing:
+-			if (m_isAway)
++			if (mInfo.away)
+ 				newStatus = m_protocol->m_UserStatusAway;
+-			else if (m_isOnline)
++			else if (mInfo.online)
+ 				newStatus = m_protocol->m_UserStatusOnline;
+ 			break;
+ 
+@@ -88,6 +88,15 @@
+ 			newStatus = m_protocol->m_StatusUnknown;
+ 	}
+ 
++	// Try hard not to emit several onlineStatusChanged() signals.
++	bool onlineStatusChanged = false;
++
++
++	/* The away status is global, so if the user goes away, we must set
++	 * the new status on all channels.
++	 */
++
++
+ 	// This may not be created yet ( for myself() on startup )
+ 	if( ircAccount()->contactManager() )
+ 	{
+@@ -98,33 +107,38 @@
+ 			IRCChannelContact *channel = *it;
+ 			Kopete::OnlineStatus currentStatus = channel->manager()->contactOnlineStatus(this);
+ 
+-			if( currentStatus.internalStatus() > IRCProtocol::Online )
++			//kdDebug(14120) << k_funcinfo << "iterating channel " << channel->nickName() << " internal status: " << currentStatus.internalStatus() << endl;
++
++			if( currentStatus.internalStatus() >= IRCProtocol::Online )
+ 			{
++				onlineStatusChanged = true;
++
+ 				if( !(currentStatus.internalStatus() & IRCProtocol::Away) && newStatus == m_protocol->m_UserStatusAway )
+ 				{
+-					channel->manager()->setContactOnlineStatus(
+-						this, m_protocol->statusLookup(
+-							(IRCProtocol::IRCStatus)(currentStatus.internalStatus()+IRCProtocol::Away)
+-						)
+-					);
++					setOnlineStatus( newStatus );
++					//kdDebug(14120) << k_funcinfo << "was NOT away, but is now, channel " << channel->nickName() << endl;
++					adjustInternalOnlineStatusBits(channel, IRCProtocol::Away, AddBits);
+ 				}
+ 				else if( (currentStatus.internalStatus() & IRCProtocol::Away) && newStatus == m_protocol->m_UserStatusOnline )
+ 				{
+-					channel->manager()->setContactOnlineStatus(
+-						this, m_protocol->statusLookup(
+-							(IRCProtocol::IRCStatus)(currentStatus.internalStatus()-IRCProtocol::Away)
+-						)
+-					);
++					setOnlineStatus( newStatus );
++					//kdDebug(14120) << k_funcinfo << "was away, but not anymore, channel " << channel->nickName() << endl;
++					adjustInternalOnlineStatusBits(channel, IRCProtocol::Away, RemoveBits);
++
+ 				}
+ 				else if( newStatus.internalStatus() < IRCProtocol::Away )
+ 				{
++					//kdDebug(14120) << k_funcinfo << "offline or connecting?" << endl;
+ 					channel->manager()->setContactOnlineStatus( this, newStatus );
+ 				}
+ 			}
+ 		}
+ 	}
+ 
+-	setOnlineStatus( newStatus );
++	if (!onlineStatusChanged) {
++		//kdDebug(14120) << k_funcinfo << "setting status at last" << endl;
++		setOnlineStatus( newStatus );
++	}
+ }
+ 
+ void IRCUserContact::sendFile(const KURL &sourceURL, const QString&, unsigned int)
+@@ -145,8 +159,9 @@
+ 
+ void IRCUserContact::slotUserOffline()
+ {
+-	m_isOnline = false;
+-	m_isAway = false;
++	mInfo.online = false;
++	mInfo.away   = false;
++
+ 	updateStatus();
+ 
+ 	if( !metaContact()->isTemporary() )
+@@ -159,7 +174,9 @@
+ 
+ void IRCUserContact::setAway(bool isAway)
+ {
+-	m_isAway = isAway;
++	//kdDebug(14120) << k_funcinfo << isAway << endl;
++
++	mInfo.away = isAway;
+ 	updateStatus();
+ }
+ 
+@@ -176,7 +193,7 @@
+ 
+ void IRCUserContact::userOnline()
+ {
+-	m_isOnline = true;
++	mInfo.online = true;
+ 	updateStatus();
+ 	if (this != ircAccount()->mySelf() && !metaContact()->isTemporary() && ircAccount()->isConnected())
+ 	{
+@@ -224,24 +241,104 @@
+ 
+ void IRCUserContact::slotBanHost()
+ {
+-	slotKick();
++	// MODE #foofoofoo +b *!*@host.domain.net
++
++	if (mInfo.hostName.isEmpty()) {
++		if (kircEngine()->isConnected()) {
++			kircEngine()->whois(m_nickName);
++			QTimer::singleShot( 750, this, SLOT( slotBanHostOnce() ) );
++		}
++	} else {
++		slotBanHostOnce();
++	}
+ }
++void IRCUserContact::slotBanHostOnce()
++{
++	if (mInfo.hostName.isEmpty())
++		return;
+ 
++	Kopete::ContactPtrList members = mActiveManager->members();
++	QString channelName = static_cast<IRCContact*>(members.first())->nickName();
++
++	kircEngine()->mode(channelName, QString::fromLatin1("+b *!*@%1").arg(mInfo.hostName));
++}
++
+ void IRCUserContact::slotBanUserHost()
+ {
+-	slotKick();
++	// MODE #foofoofoo +b *!*user at host.domain.net
++
++	if (mInfo.hostName.isEmpty()) {
++		if (kircEngine()->isConnected()) {
++			kircEngine()->whois(m_nickName);
++			QTimer::singleShot( 750, this, SLOT( slotBanUserHostOnce() ) );
++		}
++	} else {
++		slotBanUserHostOnce();
++	}
+ }
++void IRCUserContact::slotBanUserHostOnce()
++{
++	if (mInfo.hostName.isEmpty())
++		return;
+ 
++	Kopete::ContactPtrList members = mActiveManager->members();
++	QString channelName = static_cast<IRCContact*>(members.first())->nickName();
++
++	kircEngine()->mode(channelName, QString::fromLatin1("+b *!*%1@%2").arg(mInfo.userName, mInfo.hostName));
++}
++
+ void IRCUserContact::slotBanDomain()
+ {
+-	slotKick();
++	// MODE #foofoofoo +b *!*@*.domain.net
++
++	if (mInfo.hostName.isEmpty()) {
++		if (kircEngine()->isConnected()) {
++			kircEngine()->whois(m_nickName);
++			QTimer::singleShot( 750, this, SLOT( slotBanDomainOnce() ) );
++		}
++	} else {
++		slotBanDomainOnce();
++	}
+ }
++void IRCUserContact::slotBanDomainOnce()
++{
++	if (mInfo.hostName.isEmpty())
++		return;
+ 
++	Kopete::ContactPtrList members = mActiveManager->members();
++	QString channelName = static_cast<IRCContact*>(members.first())->nickName();
++
++	QString domain = mInfo.hostName.section('.', 1);
++
++	kircEngine()->mode(channelName, QString::fromLatin1("+b *!*@*.%1").arg(domain));
++}
++
+ void IRCUserContact::slotBanUserDomain()
+ {
+-	slotKick();
++	// MODE #foofoofoo +b *!*user@*.domain.net
++
++	if (mInfo.hostName.isEmpty()) {
++		if (kircEngine()->isConnected()) {
++			kircEngine()->whois(m_nickName);
++			QTimer::singleShot( 750, this, SLOT( slotBanUserDomainOnce() ) );
++		}
++	} else {
++		slotBanUserDomainOnce();
++	}
+ }
++void IRCUserContact::slotBanUserDomainOnce()
++{
++	if (mInfo.hostName.isEmpty())
++		return;
+ 
++	Kopete::ContactPtrList members = mActiveManager->members();
++	QString channelName = static_cast<IRCContact*>(members.first())->nickName();
++
++	QString domain = mInfo.hostName.section('.', 1);
++
++	kircEngine()->mode(channelName, QString::fromLatin1("+b *!*%1@*.%2").arg(mInfo.userName, domain));
++}
++
+ void IRCUserContact::slotKick()
+ {
+ 	Kopete::ContactPtrList members = mActiveManager->members();
+@@ -459,13 +556,13 @@
+ 			actionKick->setEnabled( false );
+ 
+ 			actionBanMenu = new KActionMenu(i18n("&Ban"), 0, this, "actionBanMenu");
+-			actionBanMenu->insert( new KAction(i18n("Ban *!*@*.host"), 0, this,
++			actionBanMenu->insert( new KAction(i18n("Host (*!*@host.domain.net)"), 0, this,
+ 				SLOT(slotBanHost()), actionBanMenu ) );
+-			actionBanMenu->insert( new KAction(i18n("Ban *!*@domain"), 0, this,
++			actionBanMenu->insert( new KAction(i18n("Domain (*!*@*.domain.net)"), 0, this,
+ 				SLOT(slotBanDomain()), actionBanMenu ) );
+-			actionBanMenu->insert( new KAction(i18n("Ban *!*user@*.host"), 0, this,
++			actionBanMenu->insert( new KAction(i18n("User at Host (*!*user at host.domain.net)"), 0, this,
+ 				 SLOT(slotBanUserHost()), actionBanMenu ) );
+-			actionBanMenu->insert( new KAction(i18n("Ban *!*user at domain"), 0, this,
++			actionBanMenu->insert( new KAction(i18n("User at Domain (*!*user@*.domain.net)"), 0, this,
+ 				 SLOT(slotBanUserDomain()), actionBanMenu ) );
+ 			actionBanMenu->setEnabled( false );
+ 
+@@ -497,35 +594,104 @@
+ 	return 0L;
+ }
+ 
+-void IRCUserContact::slotIncomingModeChange( const QString &channel, const QString &, const QString &mode )
++void IRCUserContact::slotIncomingModeChange( const QString &channel, const QString &, const QString &mode_ )
+ {
++	kdDebug(14120) << k_funcinfo << "channel: " << channel << " mode: " << mode_ << endl;
++
+ 	IRCChannelContact *chan = ircAccount()->contactManager()->findChannel( channel );
+-	if( chan->locateUser( m_nickName ) )
++
++	if( !chan->locateUser( m_nickName ) )
++		return;
++
++	// :foobar_!~fooobar at dhcp.inet.fi MODE #foofoofoo2 +o kakkonen
++	// :foobar_!~fooobar at dhcp.inet.fi MODE #foofoofoo2 +o-o foobar001 kakkonen
++	// :foobar_!~fooobar at dhcp.inet.fi MODE #foofoofoo2 +oo kakkonen foobar001
++	// :foobar_!~fooobar at dhcp.inet.fi MODE #foofoofoo2 +o-ov foobar001 kakkonen foobar001
++	//
++	// irssi manual example: /MODE #channel +nto-o+v nick1 nick2 nick3
++
++	QStringList users = QStringList::split(' ', mode_);
++	users.pop_front();
++
++	const QString mode = mode_.section(' ', 0, 0);
++
++	bitAdjustment adjMode = RemoveBits;
++	QStringList::iterator user = users.begin();
++
++	//kdDebug(14120) << "me: " << m_nickName << " users: " << users << " mode: " << mode << endl;
++
++	for( uint i=0; i < mode.length(); i++ )
+ 	{
+-		QString user = mode.section(' ', 1, 1);
+-		kdDebug(14120) << k_funcinfo << mode << ", " << user << ", " << m_nickName << endl;
+-		if( user == m_nickName )
++		switch( mode[i] )
+ 		{
+-			QString modeChange = mode.section(' ', 0, 0);
+-			if(modeChange == QString::fromLatin1("+o"))
+-				setManagerStatus( chan, m_protocol->m_UserStatusOp.internalStatus() );
+-			else if(modeChange == QString::fromLatin1("-o"))
+-				setManagerStatus( chan, -m_protocol->m_UserStatusOp.internalStatus() );
+-			else if(modeChange == QString::fromLatin1("+v"))
+-				setManagerStatus( chan, m_protocol->m_UserStatusVoice.internalStatus() );
+-			else if(modeChange == QString::fromLatin1("-v"))
+-				setManagerStatus( chan, -m_protocol->m_UserStatusVoice.internalStatus() );
++		case '+':
++			adjMode = AddBits;
++			break;
++
++		case '-':
++			adjMode = RemoveBits;
++			break;
++
++		default:
++			//kdDebug(14120) << "got " << mode[i] << ", user: " << *user << endl;
++
++			if (mode[i] == 'o') {
++				if (user == users.end())
++					return;
++
++				if ((*user).lower() == m_nickName.lower())
++					adjustInternalOnlineStatusBits(chan, IRCProtocol::Operator, adjMode);
++
++				++user;
++			}
++			else if (mode[i] == 'v') {
++				if (user == users.end())
++					return;
++
++				if ((*user).lower() == m_nickName.lower())
++					adjustInternalOnlineStatusBits(chan, IRCProtocol::Voiced, adjMode);
++
++				++user;
++			}
++
++			break;
+ 		}
+ 	}
+ }
+ 
+-void IRCUserContact::setManagerStatus(IRCChannelContact *channel, int statusAdjustment)
++
++/* Remove or add the given bits for the given channel from the current internal online status.
++ *
++ * You could fiddle with bits like IRCProtocol::Operator, IRCProtocol::Voiced, etc.
++ */
++
++void IRCUserContact::adjustInternalOnlineStatusBits(IRCChannelContact *channel, unsigned statusAdjustment, bitAdjustment adj)
+ {
+ 	Kopete::OnlineStatus currentStatus = channel->manager()->contactOnlineStatus(this);
+-	Kopete::OnlineStatus newStatus = m_protocol->statusLookup(
+-		(IRCProtocol::IRCStatus)(currentStatus.internalStatus() + statusAdjustment)
+-	);
++	Kopete::OnlineStatus newStatus;
+ 
++	if (adj == RemoveBits) {
++
++		// If the bit is not set in the current internal status, stop here.
++		if ((currentStatus.internalStatus() & ~statusAdjustment) == currentStatus.internalStatus())
++			return;
++
++		newStatus = m_protocol->statusLookup(
++				(IRCProtocol::IRCStatus)(currentStatus.internalStatus() & ~statusAdjustment)
++				);
++
++	} else if (adj == AddBits) {
++
++		// If the bit is already set in the current internal status, stop here.
++		if ((currentStatus.internalStatus() | statusAdjustment) == currentStatus.internalStatus())
++			return;
++
++		newStatus = m_protocol->statusLookup(
++				(IRCProtocol::IRCStatus)(currentStatus.internalStatus() | statusAdjustment)
++				);
++
++	}
++
+ 	channel->manager()->setContactOnlineStatus(this, newStatus);
+ }
+ 
+--- kopete/protocols/irc/ui/networkconfig.ui	(revision 568672)
++++ kopete/protocols/irc/ui/networkconfig.ui	(revision 586398)
+@@ -114,7 +114,7 @@
+                         <number>65536</number>
+                     </property>
+                     <property name="minValue">
+-                        <number>1024</number>
++                        <number>1</number>
+                     </property>
+                     <property name="value">
+                         <number>6667</number>
+--- kopete/protocols/irc/ui/irceditaccount.ui	(revision 568672)
++++ kopete/protocols/irc/ui/irceditaccount.ui	(revision 586398)
+@@ -543,9 +543,6 @@
+                                 <property name="text">
+                                     <string>Auto-show anonymous windows</string>
+                                 </property>
+-                                <property name="disabled" stdset="0">
+-                                    <bool>true</bool>
+-                                </property>
+                             </widget>
+                             <widget class="QCheckBox" row="1" column="0">
+                                 <property name="name">
+--- kopete/protocols/msn/p2p.cpp	(revision 568672)
++++ kopete/protocols/msn/p2p.cpp	(revision 586398)
+@@ -44,7 +44,7 @@
+ 			+ QString::number((unsigned long int)rand()%0xAAFF+0x1111, 16)).upper();
+ }
+ 
+-TransferContext::TransferContext(const QString &contact, P2P::Dispatcher *dispatcher, Q_UINT32 sessionId) 
++TransferContext::TransferContext(const QString &contact, P2P::Dispatcher *dispatcher, Q_UINT32 sessionId)
+ 	: QObject(dispatcher) ,
+ 	   m_sessionId(sessionId) ,
+ 	   m_identifier(0) ,
+@@ -70,7 +70,7 @@
+ TransferContext::~TransferContext()
+ {
+ 	m_transfer = 0l;
+-	
++
+ 	if(m_file){
+ 		delete m_file;
+ 		m_file = 0l;
+@@ -80,10 +80,10 @@
+ void TransferContext::acknowledge(const Message& message)
+ {
+ 	kdDebug(14140) << k_funcinfo << m_dispatcher<< endl;
+-	
++
+ 	Message outbound;
+ 	outbound.header.sessionId = message.header.sessionId;
+-	
++
+ 	if(m_identifier == 0){
+ 		m_identifier = m_baseIdentifier;
+ 	}
+@@ -95,7 +95,7 @@
+ 	}
+ 	else
+ 		++m_identifier;
+-		
++
+ 	outbound.header.identifier    = m_identifier;
+ 	outbound.header.dataOffset    = 0l;
+ 	outbound.header.totalDataSize = message.header.totalDataSize;
+@@ -107,7 +107,7 @@
+ // 	}
+ // 	else
+ 		outbound.header.flag = 2;
+-		
++
+ 	outbound.header.ackSessionIdentifier = message.header.identifier;
+ 	outbound.header.ackUniqueIdentifier  = message.header.ackSessionIdentifier;
+ 	outbound.header.ackDataSize   = message.header.totalDataSize;
+@@ -148,7 +148,7 @@
+ 	}
+ 	else
+ 		outbound.header.totalDataSize = m_totalDataSize;
+-	
++
+ 	outbound.header.dataSize = bytes.size();
+ 	if(m_type == UserDisplayIcon){
+ 		outbound.header.flag = 0x20;
+@@ -157,13 +157,13 @@
+ 		outbound.header.flag = 0x01000030;
+ 	}
+ 	else  outbound.header.flag = 0;
+-		 
++
+ 	outbound.header.ackSessionIdentifier = rand()%0x8FFFFFF0 + 4;
+ 	outbound.header.ackUniqueIdentifier  = 0;
+ 	outbound.header.ackDataSize = 0l;
+ 	outbound.body = bytes;
+ 	outbound.applicationIdentifier = (uint)m_type;
+-	
++
+ 	outbound.destination = m_recipient;
+ 
+ 	QByteArray stream;
+@@ -183,7 +183,7 @@
+ void TransferContext::sendDataPreparation()
+ {
+ 	kdDebug(14140) << k_funcinfo << endl;
+-	
++
+ 	Message outbound;
+ 	outbound.header.sessionId  = m_sessionId;
+ 	outbound.header.identifier = ++m_identifier;
+@@ -228,7 +228,7 @@
+ 	}
+ 	else
+ 		++m_identifier;
+-		
++
+ 	outbound.header.identifier = m_identifier;
+ 	outbound.header.flag = flag;
+ 	outbound.header.ackSessionIdentifier = m_ackSessionIdentifier;
+@@ -236,7 +236,7 @@
+ 	outbound.header.ackDataSize = 0l;
+ 	outbound.applicationIdentifier = appId;
+ 	outbound.destination = m_recipient;
+-	
++
+ 	QString contentType, cSeq, method;
+ 
+ 	switch(m_state)
+@@ -265,7 +265,7 @@
+ 			}
+ 			break;
+ 	}
+-	
++
+ 	switch(type)
+ 	{
+ 		case BYE:
+--- kopete/protocols/msn/transport.h	(revision 0)
++++ kopete/protocols/msn/transport.h	(revision 586398)
+@@ -0,0 +1,167 @@
++/*
++    transport.h - Peer to peer transport
++
++    Copyright (c) 2005 by Gregg Edghill     <gregg.edghill at gmail.com>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef PEERTOPEERTRANSPORT_H
++#define PEERTOPEERTRANSPORT_H
++
++//BEGIN QT Includes
++#include <qobject.h>
++#include <qguardedptr.h>
++#include <qvaluelist.h>
++//END
++
++//BEGIN KDE Includes
++#include <ksocketaddress.h>
++//END
++
++namespace KNetwork {
++class KClientSocketBase;
++}
++
++class MSNSwitchBoardSocket;
++
++namespace PeerToPeer {
++
++class MessageFormatter;
++class TransportBridge;
++
++enum TransportBridgeType
++{
++	Tcp = 1,
++	Udp = 2
++};
++	
++/**
++ @author Gregg Edghill <gregg.edghill at gmail.com> */
++/** @brief Represents the protocol used to send and receive message between peers. */
++class Transport : public QObject
++{
++	Q_OBJECT
++public:
++	/** @brief Creates a new instance of the class Transport. */
++    Transport(QObject* parent, const char* name = 0l);
++    ~Transport();
++	/** @brief Get a transport bridge with the specified address, port, type and identifier. */
++    TransportBridge* getBridge(const QString& address, Q_UINT16 port, TransportBridgeType type, const QString& identifier);
++    /** @brief Sets the default transport bridge. */
++	void setDefaultBridge(MSNSwitchBoardSocket* mss);
++	
++private slots:
++	/** @brief Invokes when a message is received on a transport bridge. */
++// 	void slotOnReceive(Message& message);
++	/** @brief Invokes when a message is received on the default transport bridge (relay). */
++	void slotOnReceive(const QString& contact, const QByteArray& bytes);
++
++private:
++	/** @brief Known SocketAddresses of peers. */
++	QMap<QString, KNetwork::KInetSocketAddress> mAddresses;
++	/** @brief The list the connected transport bridges. */
++	QValueList<TransportBridge*> mBridges;
++	/** @brief The default transport bridge (relay). */
++	QGuardedPtr<MSNSwitchBoardSocket> mDefaultBridge;
++	/** @brief Message formatter used to ser/deser message. */
++	MessageFormatter *mFormatter;
++};
++
++/** @brief Represents the channel connecting two peers. */
++class TransportBridge : public QObject
++{
++	Q_OBJECT
++public:
++	virtual ~TransportBridge();
++
++protected:
++	/** @brief Creates a new instance of the class TransportBridge with the specified address and formatter. */
++	TransportBridge(const KNetwork::KInetSocketAddress& to, MessageFormatter* formatter, QObject* parent, const char* name = 0l);
++	/** @brief Creates a new instance of the class TransportBridge with the specified socket and formatter. */
++	TransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, QObject* parent, const char* name = 0l);
++
++public:
++	/** @brief Creates a connection between two peers. */
++	void connect();
++	/** @brief Disconnects the connection between two peers. */
++	void disconnect();
++
++protected slots:
++	virtual void slotOnConnect();
++	virtual void slotOnDisconnect();
++	virtual void slotOnError(int);
++	virtual void slotOnSocketClose();
++	virtual void slotOnSocketConnect();
++	virtual void slotOnSocketReceive();
++
++signals:
++	void bridgeConnect();
++	void bridgeDisconnect();
++	void bridgeError(const QString& e);
++	void bytesReceived(const QByteArray&);
++	
++protected:
++	
++	KNetwork::KInetSocketAddress mAddress;
++	bool mConnected;
++	MessageFormatter *mFormatter;
++	Q_UINT32 mLength;
++	KNetwork::KClientSocketBase *mSocket;
++	bool mVerified;
++};
++
++class TcpTransportBridge : public TransportBridge
++{
++	Q_OBJECT
++	friend class Transport;
++	
++public:
++	virtual ~TcpTransportBridge();
++
++private:
++	TcpTransportBridge(const KNetwork::KInetSocketAddress& to, MessageFormatter* formatter, QObject* parent, const char* name = 0l);
++	TcpTransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, QObject* parent, const char* name = 0l);
++	
++protected slots:
++	virtual void slotOnConnect();
++	virtual void slotOnDisconnect();
++	virtual void slotOnError(int);
++	virtual void slotOnSocketClose();
++	virtual void slotOnSocketConnect();
++	virtual void slotOnSocketReceive();
++	
++private slots:
++	void slotOnSocketConnectTimeout();
++
++signals:
++	void bridgeConnectTimeout();
++	
++private:
++	class Buffer : public QByteArray
++	{
++	public:
++		Buffer(Q_UINT32 length = 0);
++		~Buffer();
++		
++	public:
++		void write(const QByteArray& bytes);
++		QByteArray read(Q_UINT32 length);
++	};
++	
++	Buffer mBuffer;
++	Q_UINT32 mLength;
++};
++
++
++}
++
++#endif
+--- kopete/protocols/msn/webcam.h	(revision 568672)
++++ kopete/protocols/msn/webcam.h	(revision 586398)
+@@ -50,6 +50,7 @@
+ 		QString m_content;
+ 		
+ 		QString xml(uint session , uint rid);
++    int getAvailablePort();
+ 
+ 		
+ 		KNetwork::KServerSocket   *m_listener;
+--- kopete/protocols/msn/msnnotifysocket.h	(revision 568672)
++++ kopete/protocols/msn/msnnotifysocket.h	(revision 586398)
+@@ -75,8 +75,12 @@
+ 
+ 	bool setUseHttpMethod( bool useHttpMethod );
+ 
++	bool isLogged() const { return m_isLogged; }
++
+ public slots:
+ 	void slotOpenInbox();
++	void slotMSNAlertLink(unsigned int action);
++	void slotMSNAlertUnwanted();
+ 
+ signals:
+ 	void newContactList();
+@@ -153,6 +157,7 @@
+ 
+ 	MSNAccount *m_account;
+ 	QString m_password;
++	QStringList m_msnAlertURLs;
+ 
+ 	unsigned int mailCount;
+ 
+@@ -195,6 +200,14 @@
+ 	 * The personalMessage is built into @ref changePersonalMessage
+ 	 */
+ 	QString m_propertyPersonalMessage;
++
++	/**
++	 * Used to tell when we are logged in to MSN Messeger service.
++	 * Logged when we receive the initial profile message from Hotmail.
++	 *
++	 * Some commands only make sense to be done when logged.
++	 */
++	bool m_isLogged;
+ };
+ 
+ #endif
+--- kopete/protocols/msn/msnchatsession.h	(revision 568672)
++++ kopete/protocols/msn/msnchatsession.h	(revision 586398)
+@@ -92,6 +92,7 @@
+ 	void slotSendNudge();
+ 	void slotWebcamReceive();
+ 	void slotWebcamSend();
++	void slotSendFile();
+ 
+ 	void slotNudgeReceived(const QString& handle);
+ 
+--- kopete/protocols/msn/msnsocket.cpp	(revision 568672)
++++ kopete/protocols/msn/msnsocket.cpp	(revision 586398)
+@@ -773,12 +773,19 @@
+ 	QString result = QString(new_segment, new_length);
+ 	delete [] new_segment;
+ 	return result;
++
+ }
+ 
+ QString MSNSocket::unescape( const QString &str )
+ {
+-	//GRRRRR F*CKING MSN PLUS USERS! They insert these stupid color codes in their nickname, and messages are not correctly shown
+-	return KURL::decode_string( str, 106 ).replace( QRegExp("[\\x1-\\x8]"), "" );
++	QString str2 = KURL::decode_string( str, 106 );
++	//remove msn+ colors code
++	str2 = str2.replace( QRegExp("[\\x1-\\x8]"), "" ); // old msn+ colors
++	// added by kaoul <erwin.kwolek at gmail.com>
++	str2 = str2.replace( QRegExp("\\xB7[&@\'#0]"),""); // dot ...
++	str2 = str2.replace( QRegExp("\\xB7\\$,?\\d{1,2}"),""); // dot dollar (comma)? 0-99
++
++	return str2;
+ }
+ 
+ void MSNSocket::slotConnectionSuccess()
+--- kopete/protocols/msn/msncontact.cpp	(revision 568672)
++++ kopete/protocols/msn/msncontact.cpp	(revision 586398)
+@@ -84,6 +84,7 @@
+ 
+ MSNContact::~MSNContact()
+ {
++	kdDebug(14140) << k_funcinfo << endl;
+ }
+ 
+ bool MSNContact::isReachable()
+@@ -142,6 +143,12 @@
+ 		// Send mail (only available if it is an hotmail account)
+ 		actionSendMail = new KAction( i18n("Send Email...") , "mail_generic",0, this, SLOT( slotSendMail() ),
+ 			this, "actionSendMail" );
++
++		// Invite to receive webcam
++		actionWebcamReceive = new KAction( i18n( "View Contact's Webcam" ), "webcamreceive",  0, this, SLOT(slotWebcamReceive() ), this, "msnWebcamReceive" ) ;
++
++		//Send webcam action
++		actionWebcamSend = new KAction( i18n( "Send Webcam" ), "webcamsend",  0, this, SLOT(slotWebcamSend() ), this, "msnWebcamSend" ) ;
+ 	}
+ 	else
+ 		actionBlock->setText( label );
+@@ -151,7 +158,10 @@
+ 	m_actionCollection->append( actionBlock );
+ 	m_actionCollection->append( actionShowProfile );
+ 	m_actionCollection->append( actionSendMail );
++	m_actionCollection->append( actionWebcamReceive );
++	m_actionCollection->append( actionWebcamSend );
+ 
++
+ 	return m_actionCollection;
+ }
+ 
+@@ -215,28 +225,25 @@
+ 	MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
+ 	if( notify )
+ 	{
+-		if( m_serverGroups.isEmpty() || onlineStatus() == MSNProtocol::protocol()->UNK )
++		if( hasProperty(MSNProtocol::protocol()->propGuid.key()) )
+ 		{
+-			if( hasProperty(MSNProtocol::protocol()->propGuid.key()) )
++			// Remove from all groups he belongs (if applicable)
++			for( QMap<QString, Kopete::Group*>::Iterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it )
+ 			{
+-				kdDebug( 14140 ) << k_funcinfo << "Removing contact from top-level." << endl;
+-				notify->removeContact( contactId(), MSNProtocol::FL, guid(), QString::null );
++				kdDebug(14140) << k_funcinfo << "Removing contact from group \"" << it.key() << "\"" << endl;
++				notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() );
+ 			}
+-			else
+-			{
+-				kdDebug( 14140 ) << k_funcinfo << "The contact is already removed from server, just delete it" << endl;
+-				deleteLater();
+-			}
+-			return;
++	
++			// Then trully remove it from server contact list, 
++			// because only removing the contact from his groups isn't sufficent from MSNP11.
++			kdDebug( 14140 ) << k_funcinfo << "Removing contact from top-level." << endl;
++			notify->removeContact( contactId(), MSNProtocol::FL, guid(), QString::null);
+ 		}
+-
+-		// Remove from all groups he belongs (if applicable)
+-		for( QMap<QString, Kopete::Group*>::Iterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it )
+-			notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() );
+-
+-		// Then trully remove it from server contact list, 
+-		// because only removing the contact from his groups isn't sufficent from MSNP11.
+-		notify->removeContact( contactId(), MSNProtocol::FL, guid(), QString::null);
++		else
++		{
++			kdDebug( 14140 ) << k_funcinfo << "The contact is already removed from server, just delete it" << endl;
++			deleteLater();
++		}
+ 	}
+ 	else
+ 	{
+@@ -570,7 +577,7 @@
+ 
+ void MSNContact::slotShowProfile()
+ {
+-	KRun::runURL( KURL( QString::fromLatin1("http://members.msn.com/default.msnw?mem=") + contactId())  , "text/html" );
++	KRun::runURL( KURL( QString::fromLatin1("http://members.msn.com/?pgmarket=it-it&mem=") + contactId())  , "text/html" );
+ }
+ 
+ 
+--- kopete/protocols/msn/msnaccount.cpp	(revision 568672)
++++ kopete/protocols/msn/msnaccount.cpp	(revision 586398)
+@@ -283,29 +283,44 @@
+ 
+ void MSNAccount::setOnlineStatus( const Kopete::OnlineStatus &status , const QString &reason)
+ {
+-	// Only update the personal/status message, don't change the online status
+-	// since it's the same.
+-	if( reason.contains("[Music]") )
++	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() )
+ 	{
+-		QString personalMessage = reason.section("[Music]", 1);
+-		setPersonalMessage( MSNProtocol::PersonalMessageMusic, personalMessage );
+-	}
+-	else
+-	{
+-		setPersonalMessage( MSNProtocol::PersonalMessageNormal, reason );
++		// Only update the personal/status message, don't change the online status
++		// since it's the same.
++		if( reason.contains("[Music]") )
++		{
++			QString personalMessage = reason.section("[Music]", 1);
++			setPersonalMessage( MSNProtocol::PersonalMessageMusic, personalMessage );
+ 
+-		if(status.status()== Kopete::OnlineStatus::Offline)
+-			disconnect();
+-		else if ( m_notifySocket )
+-		{
+-			m_notifySocket->setStatus( status );
++			// Don't send un-needed status change.
++			return;
+ 		}
+ 		else
+ 		{
+-			m_connectstatus = status;
+-			connect();
++			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()
+@@ -443,10 +458,9 @@
+ 					c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ 					addContactServerside( c->contactId() , c->metaContact()->groups() );
+ 				}
+-				else //the contact had been deleted, give him the unknown status
++				else //the contact had been deleted, remove it.
+ 				{
+-					c->clearServerGroups();
+-					c->setOnlineStatus( MSNProtocol::protocol()->UNK );
++					c->deleteLater();
+ 				}
+ 			}
+ 		}
+@@ -1012,6 +1026,7 @@
+ 
+ void MSNAccount::slotContactRemoved( const QString& handle, const QString& list, const QString& contactGuid, const QString& groupGuid )
+ {
++	kdDebug( 14140 ) << k_funcinfo << "handle: " << handle << " list: " << list << " contact-uid: " << contactGuid << endl;
+ 	MSNContact *c=static_cast<MSNContact *>( contacts()[ handle ] );
+ 	if ( list == "BL" )
+ 	{
+@@ -1060,16 +1075,17 @@
+ 	{
+ 		// The FL list only use the contact GUID, use the contact referenced by the GUID.
+ 		MSNContact *contactRemoved = findContactByGuid(contactGuid);
+-
+ 		QStringList 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)
+ 			{
+ 				QPtrList<Kopete::Group> groupList = contactRemoved->metaContact()->groups();
+-				for( Kopete::Group *group = groupList.first(); group; groupList.next() )
++				for( QPtrList<Kopete::Group>::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" ) );
+@@ -1111,6 +1127,11 @@
+ 				}
+ 			}
+ 		}
++		if(deleteContact && contactRemoved)
++		{
++			kdDebug(14140) << k_funcinfo << "Deleting the MSNContact " << contactRemoved->contactId() << endl;
++			contactRemoved->deleteLater();
++		}
+ 	}
+ }
+ 
+@@ -1206,7 +1227,7 @@
+ 	{
+ 		Kopete::MetaContact *mc=dialog->addContact();
+ 		if(mc)
+-		{ //if the contact has been added this way, it's because the other user added us.²
++		{ //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<MSNContact*>(mc->contacts().first());
+ 			if(c && c->contactId() == handle )
+@@ -1236,22 +1257,25 @@
+ 
+ void MSNAccount::slotGlobalIdentityChanged( const QString &key, const QVariant &value )
+ {
+-	if(key == Kopete::Global::Properties::self()->nickName().key())
++	if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
+ 	{
+-		QString oldNick = myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString();
+-		QString newNick = value.toString();
+-	
+-		if(newNick != oldNick)
++		if(key == Kopete::Global::Properties::self()->nickName().key())
+ 		{
+-			setPublicName( value.toString() );
++			QString oldNick = myself()->property( Kopete::Global::Properties::self()->nickName()).value().toString();
++			QString 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);
++		}
+ 	}
+-	else if(key == Kopete::Global::Properties::self()->photo().key())
+-	{
+-		m_pictureFilename = value.toString();
+-		kdDebug( 14140 ) << k_funcinfo << m_pictureFilename << endl;
+-		resetPictureObject(false);
+-	}
+ }
+ 
+ void MSNAccount::slotErrorMessageReceived( int type, const QString &msg )
+@@ -1367,13 +1391,13 @@
+ 
+ MSNContact *MSNAccount::findContactByGuid(const QString &contactGuid)
+ {
+-	kdDebug(14140) << k_funcinfo << endl;
++	kdDebug(14140) << k_funcinfo << "Looking for " << contactGuid << endl;
+ 	QDictIterator<Kopete::Contact> it( contacts() );
+ 	for ( ; it.current(); ++it )
+ 	{
+-		MSNContact *c = static_cast<MSNContact *>( *it );
++		MSNContact *c = dynamic_cast<MSNContact *>( it.current() );
+ 
+-		if(c && c->property( MSNProtocol::protocol()->propGuid ).value().toString() == contactGuid )
++		if(c && c->guid() == contactGuid )
+ 		{
+ 			kdDebug(14140) << k_funcinfo << "OK found a contact. " << endl;
+ 			// Found the contact GUID
+--- kopete/protocols/msn/msnchatui.rc	(revision 568672)
++++ kopete/protocols/msn/msnchatui.rc	(revision 586398)
+@@ -1,27 +1,27 @@
+ <!DOCTYPE kpartgui>
+-<kpartgui version="5" name="kopete_msn_chat">
++<kpartgui version="12" name="kopete_msn_chat">
+ 	<MenuBar>
+ 		<Menu noMerge="1" name="file">
+ 			<text>&amp;Chat</text>
++			<Action name="msnWebcamReceive" />
++			<Action name="msnWebcamSend" />
++			<Action name="msnSendFile" />		
++			<Action name="msnSendNudge" />
++			<Action name="msnRequestDisplayPicture" />
+ 			<Action name="msnInvite" />
+-			<Action name="msnRequestDisplayPicture" />
+-			<Action name="msnSendNudge" />
+ <!--			<Menu name="debug">
+ 				<text>&amp;Debug</text>
+ 				<Action name="msnDebugRawCommand" />
+ 			</Menu> -->
+-			<Menu name="webcam">
+-				<text>&amp;Webcam</text>
+-				<Action name="msnWebcamSend" />
+-				<Action name="msnWebcamReceive" />
+-			</Menu> 
+ 		</Menu>
+ 	</MenuBar>
+ 
+ 
+ 	<ToolBar name="statusToolBar">
+ 		<Action name="msnDisplayPicture" />
++		<Action name="msnWebcamReceive" />	
++		<Action name="msnWebcamSend" />
++		<Action name="msnSendFile" />		
++		<Action name="msnSendNudge" />
+ 	</ToolBar>
+-
+-
+ </kpartgui>
+--- kopete/protocols/msn/transport.cpp	(revision 0)
++++ kopete/protocols/msn/transport.cpp	(revision 586398)
+@@ -0,0 +1,356 @@
++/*
++    transport.cpp - Peer to peer transport
++
++    Copyright (c) 2005 by Gregg Edghill     <gregg.edghill at gmail.com>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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; version 2 of the License.               *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "transport.h"
++#include "messageformatter.h"
++
++//BEGIN QT Includes
++//END
++
++//BEGIN KDE Includes
++#include <kclientsocketbase.h>
++#include <kdebug.h>
++#include <kstreamsocket.h>
++//END
++
++//BEGIN Using Directives
++using namespace KNetwork;
++//END
++
++#include "msnswitchboardsocket.h"
++
++namespace PeerToPeer {
++
++Transport::Transport(QObject* parent, const char* name)
++ : QObject(parent, name)
++{
++	mFormatter = new PeerToPeer::MessageFormatter(this);
++}
++
++
++Transport::~Transport()
++{
++}
++
++//BEGIN Public Methods
++
++TransportBridge* Transport::getBridge (const QString& to, Q_UINT16 port, TransportBridgeType type, const QString& identifier)
++{
++	TransportBridge *bridge = 0l;
++	KInetSocketAddress address;
++	if (mAddresses.contains(to))
++	{
++		address = mAddresses[to];
++	}
++	else
++	{
++		address = KInetSocketAddress(KIpAddress(to), port);
++		mAddresses[to] = address;
++	}
++
++	if (PeerToPeer::Tcp == type){
++		bridge = new TcpTransportBridge(address, mFormatter, this, identifier.ascii());
++	}
++
++	if (PeerToPeer::Udp == type){
++// TODO Add class UdpTransportBridge
++// 		bridge = new UdpTransportBridge(address, this, mFormatter, identifier.ascii());
++	}
++
++	if (bridge != 0l)
++	{
++		QObject::connect(bridge, SIGNAL(readyRead(const QByteArray&)), SLOT(slotOnReceive(const QByteArray&)));
++	}
++	
++	return 0l;
++}
++
++void Transport::setDefaultBridge(MSNSwitchBoardSocket* mss)
++{
++	mDefaultBridge = mss;
++	QObject::connect((MSNSwitchBoardSocket*)mDefaultBridge, SIGNAL(messageReceived(const QString&, const QByteArray&)), SLOT(slotOnReceive(const QString&, const QByteArray&)));
++}
++
++//END
++
++//BEGIN Private Slot Methods
++
++// void Transport::slotOnReceive(Message& message)
++// {
++// }
++
++void Transport::slotOnReceive(const QString& contact, const QByteArray& bytes)
++{
++	kdDebug (14140) << k_funcinfo << " >> RECEIVED " << bytes.size() << " bytes." << endl;
++// 	Message message = mFormatter->readMessage(bytes);
++}
++
++//END
++
++
++
++
++TransportBridge::TransportBridge(const KNetwork::KInetSocketAddress& to, MessageFormatter* formatter, QObject* parent, const char* name)
++: QObject(parent, name)
++{
++	mAddress = to;
++	mFormatter = formatter;
++}
++
++TransportBridge::TransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, QObject* parent, const char* name)
++: QObject(parent, name)
++{
++	mSocket = socket;
++	mAddress = mSocket->peerAddress();
++}
++
++TransportBridge::~TransportBridge()
++{
++}
++
++//BEGIN Public Methods
++
++void TransportBridge::connect()
++{
++	slotOnConnect();
++}
++
++void TransportBridge::disconnect()
++{
++	slotOnDisconnect();
++}
++
++//END
++
++//BEGIN Protected Slot Methods
++
++void TransportBridge::slotOnConnect()
++{
++}
++
++void TransportBridge::slotOnDisconnect()
++{
++}
++
++void TransportBridge::slotOnError(int)
++{
++}
++
++void TransportBridge::slotOnSocketClose()
++{
++}
++
++void TransportBridge::slotOnSocketConnect()
++{
++}
++
++void TransportBridge::slotOnSocketReceive()
++{
++}
++
++
++//END
++
++
++
++TcpTransportBridge::TcpTransportBridge(const KNetwork::KInetSocketAddress& to, MessageFormatter* formatter, QObject* parent, const char* name)
++: TransportBridge(to, formatter, parent, name)
++{	
++	mSocket = new KStreamSocket(mAddress.ipAddress().toString(), QString::number(mAddress.port()), this);
++	mSocket->setBlocking(false);
++	QObject::connect(mSocket, SIGNAL(connected(const KResolverEntry&)), SLOT(slotOnSocketConnect()));
++	QObject::connect(mSocket, SIGNAL(gotError(int)), SLOT(slotOnError(int)));
++	mConnected = false;
++}
++
++TcpTransportBridge::TcpTransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, QObject* parent, const char* name)
++: TransportBridge(socket, formatter, parent, name)
++{
++	mConnected = (mSocket->state() == KStreamSocket::Open) ? true : false;
++	mSocket->setBlocking(false);
++}
++
++TcpTransportBridge::~TcpTransportBridge()
++{
++}
++
++//BEGIN Protected Slot Methods
++
++void TcpTransportBridge::slotOnConnect()
++{
++	if (mConnected)
++	{
++		kdDebug(14140) << k_funcinfo << "Bridge (" << name() << ") ALREADY CONNECTED " << mSocket->peerAddress().toString() << " <-> " << mSocket->localAddress().toString() << endl;
++		return;
++	}
++
++	KStreamSocket *socket = static_cast<KStreamSocket*>(mSocket);
++	socket->setTimeout(5000);
++	QObject::connect(socket, SIGNAL(timeOut()), SLOT(slotOnSocketConnectTimeout()));
++	mSocket->connect();
++}
++
++void TcpTransportBridge::slotOnDisconnect()
++{
++	if (mConnected){
++		mSocket->close();
++	}
++}
++
++void TcpTransportBridge::slotOnError(int errorCode)
++{
++	kdDebug(14140) << k_funcinfo << "Bridge (" << name() << ") ERROR occurred on {" << mSocket->localAddress().toString() << " <-> " << mSocket->peerAddress().toString() << "} - " << mSocket->errorString() << endl;
++	emit bridgeError(QString("Bridge ERROR %1: %2").arg(errorCode).arg(mSocket->errorString()));
++	if (mConnected){
++		mSocket->disconnect();
++		mConnected = false;
++	}
++	mSocket->deleteLater();
++	mSocket = 0l;
++}
++
++void TcpTransportBridge::slotOnSocketClose()
++{
++	mSocket->disconnect();
++	kdDebug(14140) << k_funcinfo << "Bridge (" << name() << ") DISCONNECTED {" << mSocket->peerAddress().toString() << " <-> " << mSocket->localAddress().toString() << "}" << endl;
++	mConnected = false;
++	mSocket->deleteLater();
++	mSocket = 0l;
++
++	emit bridgeDisconnect();
++}
++
++void TcpTransportBridge::slotOnSocketConnect()
++{
++	kdDebug(14140) << k_funcinfo << "Bridge (" << name() << ") CONNECTED to " << mSocket->peerAddress().toString() << " from "
++		<< mSocket->localAddress().toString() << endl;
++	mConnected = true;
++
++	QObject::connect(mSocket, SIGNAL(readyRead()), SLOT(slotOnSocketReceive()));
++	QObject::connect(mSocket, SIGNAL(closed()), SLOT(slotOnSocketClose()));
++
++	mVerified = true;
++	QString foo = "foo\0";
++	mSocket->writeBlock(foo.ascii(), foo.length());
++	foo = QString::null;
++
++	emit bridgeConnect();
++}
++
++void TcpTransportBridge::slotOnSocketReceive()
++{
++	kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") RECEIVED " << mSocket->bytesAvailable() << " bytes." << endl;
++	
++	QByteArray bytes(mSocket->bytesAvailable());
++	mSocket->readBlock(bytes.data(), bytes.size());
++	// Write the data to the buffer.
++	mBuffer.write(bytes);
++
++	if (mVerified == false && mBuffer.size() >= 4)
++	{
++		QByteArray foo = mBuffer.read(4);
++		if (QString(foo) == "foo"){
++			kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") CONNECTION verified." << endl;
++			mVerified = true;
++		}
++	}
++
++	while(mBuffer.size() > 0)
++	{
++		if (mBuffer.size() >= 4 && mLength == 0)
++		{
++			QByteArray array = mBuffer.read(4);
++			for (int i=0; i < 4; i++){
++				((char*)mLength)[i] = array[i];
++			}
++		}
++
++		if (mLength > 0 && mBuffer.size() >= mLength)
++		{
++			kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") read " << mLength << " bytes." << endl;
++			bytes = mBuffer.read(mLength);
++			mLength = 0;
++// 			Message message = mFormatter->readMessage(bytes, true);
++// 			emit messageReceived(message);
++		}
++		else
++		{
++			kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") waiting for " << mLength << " bytes." << endl;
++			break;
++		}
++	}
++}
++
++//END
++
++//BEGIN Private Slot Methods
++
++void TcpTransportBridge::slotOnSocketConnectTimeout()
++{
++	kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") CONNECT timeout." << endl;
++	emit bridgeConnectTimeout();
++	mSocket->deleteLater();
++	mSocket = 0l;
++}
++
++//END
++
++
++
++
++TcpTransportBridge::Buffer::Buffer(Q_UINT32 length)
++: QByteArray(length)
++{
++}
++
++TcpTransportBridge::Buffer::~Buffer()
++{
++}
++
++//BEGIN Public Methods
++
++void TcpTransportBridge::Buffer::write(const QByteArray& bytes)
++{
++	resize(size() + bytes.size());
++	for (uint i=0; i < bytes.size(); i++){
++		(*this)[size() + i] = bytes[i];
++	}
++}
++
++QByteArray TcpTransportBridge::Buffer::read(Q_UINT32 length)
++{
++	if (length > size()) return QByteArray();
++
++	QByteArray buffer;
++	buffer.duplicate(data(), length);
++
++	char *bytes = new char[size() - length];
++	for(uint i=0; i < size() - length; i++){
++		bytes[i] = data()[length + i];
++	}
++
++	duplicate(bytes, size() - length);
++	delete[] bytes;
++	
++	return buffer;
++}
++
++//END
++
++}
++
++#include "transport.moc"
++
+--- kopete/protocols/msn/webcam.cpp	(revision 568672)
++++ kopete/protocols/msn/webcam.cpp	(revision 586398)
+@@ -499,13 +499,9 @@
+ 		ip+=QString("<tcpipaddress%1>%2</tcpipaddress%3>").arg(ip_number).arg(*it).arg(ip_number);
+ 		++ip_number;
+ 	}
++
++        QString port = QString::number(getAvailablePort());
+ 	
+-	KConfig *config = KGlobal::config();
+-	config->setGroup( "MSN" );
+-	QString port=config->readEntry("WebcamPort" );
+-	if(port.isEmpty() || port == "0" )
+-		port="6891";
+-	
+ 	m_listener = new KServerSocket(port, this) ;
+ 	
+ 	return "<" + who + "><version>2.0</version><rid>"+QString::number(rid)+"</rid><udprid>"+QString::number(rid+1)+"</udprid><session>"+QString::number(session)+"</session><ctypes>0</ctypes><cpu>2931</cpu>" +
+@@ -514,6 +510,40 @@
+ 			"<codec></codec><channelmode>1</channelmode></"+who+">\r\n\r\n";
+ }
+ 
++int Webcam::getAvailablePort()
++{
++    KConfig *config = KGlobal::config();
++    config->setGroup( "MSN" );
++    QString basePort=config->readEntry("WebcamPort");
++    if(basePort.isEmpty() || basePort == "0" )
++		basePort="6891";
++	
++    uint firstport = basePort.toInt();
++    uint maxOffset=config->readUnsignedNumEntry("WebcamMaxPortOffset", 10);
++    uint lastport = firstport + maxOffset;
++
++	// try to find an available port
++	//
++    KServerSocket *ss = new KServerSocket();
++    ss->setFamily(KResolver::InetFamily);
++    bool found = false;
++	unsigned int port = firstport;
++    for( ; port <= lastport; ++port) {
++		ss->setAddress( QString::number( port ) );
++		bool success = ss->listen();
++		if( found = ( success && ss->error() == KSocketBase::NoError ) )
++			break;
++		ss->close();
++    }
++	delete ss;
++	
++
++    kdDebug(14140) << k_funcinfo<< "found available port : " << port << endl;
++
++	return port;
++}
++
++
+ /* ---------- Now functions about the dirrect connection  --------- */
+ 
+ void Webcam::slotSocketConnected()
+@@ -623,10 +653,8 @@
+ 				if(m_who==wProducer)
+ 				{
+ 					Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
+-					videoDevice->scanDevices();
+-					videoDevice->open(0);
++					videoDevice->open();
+ 					videoDevice->setSize(320, 240);
+-					videoDevice->selectInput(0);
+ 					videoDevice->startCapturing();
+ 					
+ 					m_timerId=startTimer(1000);
+@@ -675,10 +703,8 @@
+ 				if(m_who==wProducer)
+ 				{
+ 					Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
+-					videoDevice->scanDevices();
+-					videoDevice->open(0);
++					videoDevice->open();
+ 					videoDevice->setSize(320, 240);
+-					videoDevice->selectInput(0);
+ 					videoDevice->startCapturing();
+ 					
+ 					m_timerId=startTimer(1000);
+--- kopete/protocols/msn/msnnotifysocket.cpp	(revision 568672)
++++ kopete/protocols/msn/msnnotifysocket.cpp	(revision 586398)
+@@ -30,6 +30,7 @@
+ 
+ #include <qdatetime.h>
+ #include <qregexp.h>
++#include <qdom.h>
+ 
+ #include <kdebug.h>
+ #include <kdeversion.h>
+@@ -44,12 +45,12 @@
+ #include <kconfig.h>
+ #include <knotification.h>
+ 
+-
+ #include "kopeteuiglobal.h"
+ #include "kopeteglobal.h"
+ 
+ #include <ctime>
+ 
++
+ MSNNotifySocket::MSNNotifySocket( MSNAccount *account, const QString& /*msnId*/, const QString &password )
+ : MSNSocket( account )
+ {
+@@ -66,6 +67,7 @@
+ 	QObject::connect( this, SIGNAL( blockRead( const QByteArray & ) ),
+ 		this, SLOT( slotReadMessage( const QByteArray & ) ) );
+ 	m_keepaliveTimer = 0L;
++	m_isLogged = false;
+ }
+ 
+ MSNNotifySocket::~MSNNotifySocket()
+@@ -85,6 +87,7 @@
+ 
+ void MSNNotifySocket::disconnect()
+ {
++	m_isLogged = false;
+ 	if(	m_disconnectReason==Kopete::Account::Unknown )
+ 		m_disconnectReason=Kopete::Account::Manual;
+ 	if( onlineStatus() == Connected )
+@@ -658,6 +661,11 @@
+ 		KRun::runURL( KURL::fromPathOrURL( tmpMailFile.name() ), "text/html" , true );
+ 
+ 	}
++	else if ( cmd == "NOT" )
++	{
++		kdDebug( 14140 ) << k_funcinfo << "Received NOT command, issueing read block for '" << id << " more bytes" << endl;
++		readBlock( id );		
++	}	
+ 	else
+ 	{
+ 		// Let the base class handle the rest
+@@ -687,7 +695,20 @@
+ 	m_secureLoginHandler = 0L;
+ }
+ 
++void MSNNotifySocket::slotMSNAlertUnwanted()
++{
++	// user not interested .. clean up the list of actions
++	m_msnAlertURLs.clear();
++}
+ 
++void MSNNotifySocket::slotMSNAlertLink(unsigned int action)
++{
++	// index into our action list and pull out the URL that was clicked ..
++	KURL tempURLForLaunch(m_msnAlertURLs[action-1]);
++	
++	KRun* urlToRun = new KRun(tempURLForLaunch);
++}
++
+ void MSNNotifySocket::slotOpenInbox()
+ {
+ 	sendCommand("URL", "INBOX" );
+@@ -812,8 +833,99 @@
+ 			rx.search(msg);
+ 			m_localIP = rx.cap(1);
+ 		}
++
++		// We are logged when we receive the initial profile from Hotmail.
++		m_isLogged = true;
+ 	}
++	else if (msg.contains("NOTIFICATION"))
++	{
++		// MSN alert (i.e. NOTIFICATION) [for docs see http://www.hypothetic.org/docs/msn/client/notification.php]
++		// format of msg is as follows:
++		//
++		// <NOTIFICATION ver="2" id="1342902633" siteid="199999999" siteurl="http://alerts.msn.com">
++		// <TO pid="0x0006BFFD:0x8582C0FB" name="example at passport.com"/>
++		// <MSG pri="1" id="1342902633">
++		// 	<SUBSCR url="http://g.msn.com/3ALMSNTRACKING/199999999ToastChange?http://alerts.msn.com/Alerts/MyAlerts.aspx?strela=1"/>
++		// 	<ACTION url="http://g.msn.com/3ALMSNTRACKING/199999999ToastAction?http://alerts.msn.com/Alerts/MyAlerts.aspx?strela=1"/>
++		// 	<BODY lang="3076" icon="">
++		// 		<TEXT>utf8-encoded text</TEXT>
++		//	</BODY>
++		// </MSG>
++		// </NOTIFICATION>
+ 
++		// MSN sends out badly formed XML .. fix it for them (thanks MS!)
++		QString notificationDOMAsString(msg);
++
++		QRegExp rx( "&(?!amp;)" );      // match ampersands but not &amp;
++		notificationDOMAsString.replace(rx, "&amp;");
++		QDomDocument alertDOM;
++		alertDOM.setContent(notificationDOMAsString);
++
++		QDomNodeList msgElements = alertDOM.elementsByTagName("MSG");
++		for (uint i = 0 ; i < msgElements.count() ; i++)
++		{
++			QString subscString;
++			QString actionString;
++			QString textString;
++
++			QDomNode msgDOM = msgElements.item(i);
++
++			QDomNodeList msgChildren = msgDOM.childNodes();
++			for (uint i = 0 ; i < msgChildren.length() ; i++) {
++				QDomNode child = msgChildren.item(i);
++				QDomElement element = child.toElement();
++				if (element.tagName() == "SUBSCR")
++				{
++					QDomAttr subscElementURLAttribute;
++					if (element.hasAttribute("url"))
++					{
++						subscElementURLAttribute = element.attributeNode("url");
++						subscString = subscElementURLAttribute.value();
++					}
++				}
++				else if (element.tagName() == "ACTION")
++				{
++					// process ACTION node to pull out URL the alert is tied to
++					QDomAttr actionElementURLAttribute;
++					if (element.hasAttribute("url"))
++					{
++						actionElementURLAttribute = element.attributeNode("url");
++						actionString = actionElementURLAttribute.value();
++					}
++				}
++				else if (element.tagName() == "BODY")
++				{
++					// process BODY node to get the text of the alert
++					QDomNodeList textElements = element.elementsByTagName("TEXT");
++					if (textElements.count() >= 1)
++					{
++						QDomElement textElement = textElements.item(0).toElement();
++						textString = textElement.text();
++					}
++				}
++
++
++			}
++
++//			kdDebug( 14140 ) << "subscString " << subscString << " actionString " << actionString << " textString " << textString << endl;
++			// build an internal list of actions ... we'll need to index into this list when we receive an event
++			QStringList actions;
++			actions.append(i18n("More Information"));
++			m_msnAlertURLs.append(actionString);
++
++			actions.append(i18n("Manage Subscription"));
++			m_msnAlertURLs.append(subscString);
++
++			// Don't do any MSN alerts notification for new blog updates
++			if( subscString != QString::fromLatin1("s.htm") && actionString != QString::fromLatin1("a.htm") )
++			{
++				KNotification* notification = KNotification::event("msn_alert", textString, 0L, 0L, actions);
++				QObject::connect(notification, SIGNAL(activated(unsigned int)), this, SLOT(slotMSNAlertLink(unsigned int)));
++				QObject::connect(notification, SIGNAL(closed()), this, SLOT(slotMSNAlertUnwanted()));
++			}
++		} // end for each MSG tag
++	}
++
+ 	if(!m_configFile.isNull())
+ 	{
+ 		// TODO Get client features.
+@@ -1198,6 +1310,7 @@
+ 		return MSNProtocol::protocol()->UNK;
+ }
+ 
++
+ #include "msnnotifysocket.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/protocols/msn/outgoingtransfer.cpp	(revision 568672)
++++ kopete/protocols/msn/outgoingtransfer.cpp	(revision 586398)
+@@ -53,14 +53,14 @@
+ 
+ void OutgoingTransfer::sendImage(const QByteArray& image)
+ {
+-	
++
+ // 	TODO QByteArray base64 = KCodecs::base64Encode(image);
+-// 
++//
+ // 	QCString body = "MIME-Version: 1.0\r\n"
+ // 		"Content-Type: image/gif\r\n"
+ // 		"\r\n"
+ // 		"base64:" +
+-// 
++//
+ // 	Message outbound;
+ // 	outbound.header.sessionId  = m_sessionId;
+ // 	outbound.header.identifier = m_baseIdentifier;
+@@ -77,12 +77,12 @@
+ // 	outbound.applicationIdentifier = 0;
+ // 	outbound.attachApplicationId = false;
+ // 	outbound.destination = m_recipient;
+-// 
++//
+ // 	sendMessage(outbound, body);
+ }
+ 
+ void OutgoingTransfer::slotSendData()
+-{		
++{
+ 	Q_INT32 bytesRead = 0;
+ 	QByteArray buffer(1202);
+ 	if(!m_file)
+@@ -91,27 +91,34 @@
+ 	// Read a chunk from the source file.
+ 	bytesRead = m_file->readBlock(buffer.data(), buffer.size());
+ 	
+-	if(bytesRead < 1202){
+-		buffer.resize(bytesRead);
++	if (bytesRead < 0) {
++		m_file->close();
++                // ### error handling
++        }
++	else {
++
++		if(bytesRead < 1202){
++			buffer.resize(bytesRead);
++		}
++
++		kdDebug(14140) << k_funcinfo << QString("Sending, %1 bytes").arg(bytesRead) << endl;
++
++		if((m_offset + bytesRead) < m_file->size())
++		{
++			sendData(buffer);
++			m_offset += bytesRead;
++		}
++		else
++		{
++			m_isComplete = true;
++			// Send the last chunk of the file.
++			sendData(buffer);
++			m_offset += buffer.size();
++			// Close the file.
++			m_file->close();
++		}
+ 	}
+ 
+-	kdDebug(14140) << k_funcinfo << QString("Sending, %1 bytes").arg(bytesRead) << endl;
+-	
+-	if((m_offset + bytesRead) < m_file->size())
+-	{
+-		sendData(buffer);
+-		m_offset += bytesRead;
+-	}
+-	else
+-	{
+-		m_isComplete = true;
+-		// Send the last chunk of the file.
+-		sendData(buffer);
+-		m_offset += buffer.size();
+-		// Close the file.
+-		m_file->close();
+-	}
+-	
+ 	if(m_transfer){
+ 		m_transfer->slotProcessed(m_offset);
+ 		if(m_isComplete){
+@@ -124,7 +131,7 @@
+ void OutgoingTransfer::acknowledged()
+ {
+ 	kdDebug(14140) << k_funcinfo << endl;
+-	
++
+ 	switch(m_state)
+ 	{
+ 		case Invitation:
+@@ -150,7 +157,7 @@
+ 			}
+ 			break;
+ 		}
+-		
++
+ 		case DataTransfer:
+ 			// NOTE <<< Data acknowledged message.
+ 			// <<< Bye message should follow.
+@@ -170,7 +177,7 @@
+ 					sendMessage(BYE, "\r\n");
+ 				}
+ 			}
+-			
++
+ 			break;
+ 
+ 		case Finished:
+@@ -179,7 +186,7 @@
+ 				// BYE acknowledge message.
+ 				m_dispatcher->detach(this);
+ 			}
+-			
++
+ 			break;
+ 	}
+ }
+@@ -235,16 +242,16 @@
+ 				error();
+ 				return;
+ 			}
+-			
++
+ 			m_transfer =
+ 				Kopete::TransferManager::transferManager()->addTransfer(contact, m_file->name(), m_file->size(), m_recipient, Kopete::FileTransferInfo::Outgoing);
+ 
+ 			QObject::connect(m_transfer , SIGNAL(transferCanceled()), this, SLOT(abort()));
+-			
++
+ 			m_state = Negotiation;
+ 
+ 			m_branch = P2P::Uid::createUid();
+-			
++
+ 			// Send the direct connection invitation message.
+ 			QString content = "Bridges: TRUDPv1 TCPv1\r\n" +
+ 				QString("NetID: %1\r\n").arg("-123657987") +
+@@ -270,7 +277,7 @@
+ 
+ #if 1
+ 			isListening = false; // TODO complete direct connection.
+-#endif				
++#endif
+ 			if(isListening)
+ 			{
+ 				// Retrieve the hashed nonce for this direct connection instance.
+@@ -325,7 +332,7 @@
+ 		// Ignore, do nothing.
+ 		return;
+ 	}
+-		
++
+ 	slotSendData();
+ }
+ 
+--- kopete/protocols/msn/msnchatsession.cpp	(revision 568672)
++++ kopete/protocols/msn/msnchatsession.cpp	(revision 586398)
+@@ -21,7 +21,9 @@
+ #include <qimage.h>
+ #include <qtooltip.h>
+ #include <qfile.h>
++#include <qiconset.h>
+ 
++
+ #include <kconfig.h>
+ #include <kdebug.h>
+ #include <kinputdialog.h>
+@@ -73,7 +75,7 @@
+ 		protocol,  SIGNAL( invitation(MSNInvitation*& ,  const QString & , long unsigned int , MSNChatSession*  , MSNContact*  ) ) );
+ 
+ 
+-	m_actionInvite = new KActionMenu( i18n( "&Invite" ), actionCollection() , "msnInvite" );
++	m_actionInvite = new KActionMenu( i18n( "&Invite" ), "kontact_contacts", actionCollection(), "msnInvite" );
+ 	connect ( m_actionInvite->popupMenu() , SIGNAL( aboutToShow() ) , this , SLOT(slotActionInviteAboutToShow() ) ) ;
+ 
+ 	#if !defined NDEBUG
+@@ -81,15 +83,16 @@
+ 	#endif
+ 
+ 
+-	m_actionNudge=new KAction( i18n( "Send Nudge" ), 0, this, SLOT(slotSendNudge() ), actionCollection(), "msnSendNudge" ) ;
+-	m_actionNudge->setEnabled(false);
++	m_actionNudge=new KAction( i18n( "Send Nudge" ), "bell", 0, this, SLOT(slotSendNudge() ), actionCollection(), "msnSendNudge" ) ;
+ #if MSN_WEBCAM
+-	m_actionWebcamReceive=new KAction( i18n( "View Contact's Webcam" ), 0, this, SLOT(slotWebcamReceive() ), actionCollection(), "msnWebcamReceive" ) ;
+-	m_actionWebcamReceive->setEnabled(false);
+-	m_actionWebcamSend=new KAction( i18n( "Send Webcam" ), 0, this, SLOT(slotWebcamSend() ), actionCollection(), "msnWebcamSend" ) ;
++	// Invite to receive webcam action
++	m_actionWebcamReceive=new KAction( i18n( "View Contact's Webcam" ), "webcamreceive",  0, this, SLOT(slotWebcamReceive()), actionCollection(), "msnWebcamReceive" ) ;
++	
++	//Send webcam action
++	m_actionWebcamSend=new KAction( i18n( "Send Webcam" ), "webcamsend",  0, this, SLOT(slotWebcamSend()), actionCollection(), "msnWebcamSend" ) ;
+ #endif
+ 	
+-	
++	new KAction( i18n( "Send File" ),"attach", 0, this, SLOT( slotSendFile() ), actionCollection(), "msnSendFile" );
+ 
+ 	MSNContact *c = static_cast<MSNContact*>( others.first() );
+ 	(new KAction( i18n( "Request Display Picture" ), "image", 0,  this, SLOT( slotRequestPicture() ), actionCollection(), "msnRequestDisplayPicture" ))->setEnabled(!c->object().isEmpty());
+@@ -676,6 +679,12 @@
+ }
+ 
+ 
++void MSNChatSession::slotSendFile()
++      {
++              QPtrList<Kopete::Contact>contacts = members();
++              static_cast<MSNContact *>(contacts.first())->sendFile();
++      }
++
+ void MSNChatSession::startChatSession()
+ {
+ 	QPtrList<Kopete::Contact> mb=members();
+--- kopete/protocols/msn/webcam/msnwebcamdialog.h	(revision 568672)
++++ kopete/protocols/msn/webcam/msnwebcamdialog.h	(revision 586398)
+@@ -21,7 +21,8 @@
+ #ifndef YAHOOWEBCAMDIALOG_H_
+ #define YAHOOWEBCAMDIALOG_H_
+ 
+-#include <qlabel.h>
++//#include <qlabel.h>
++#include <webcamwidget.h>
+ #include <kdialogbase.h>
+ 
+ #include "kopete_export.h"
+@@ -46,7 +47,7 @@
+ 	void closingWebcamDialog();
+ 	
+ private:
+-	QLabel m_imageContainer;
++	Kopete::WebcamWidget m_imageContainer;
+ 	
+ };
+ 
+--- kopete/protocols/msn/webcam/msnwebcamdialog.cpp	(revision 568672)
++++ kopete/protocols/msn/webcam/msnwebcamdialog.cpp	(revision 586398)
+@@ -47,8 +47,8 @@
+ 	if ( page )
+ 	{
+ 		kdDebug(14180) << k_funcinfo << "Adding webcam image container" << endl;
+-		m_imageContainer.setText( i18n( "No webcam image received" ) );
+-		m_imageContainer.setAlignment( Qt::AlignCenter );
++		//m_imageContainer.setText( i18n( "No webcam image received" ) );
++		//m_imageContainer.setAlignment( Qt::AlignCenter );
+ 		m_imageContainer.setMinimumSize(320,240);
+ 	}
+ 	show();
+@@ -63,18 +63,18 @@
+ {
+ 	kdDebug(14180) << k_funcinfo << "New image received" << endl;
+ 	//	kdDebug(14180) << image << endl;
+-	m_imageContainer.clear();
+-	m_imageContainer.setPixmap( image );
+-	show();
++	//m_imageContainer.clear();
++	m_imageContainer.updatePixmap( image );
++	//show();
+ }
+ 
+ void MSNWebcamDialog::webcamClosed( int reason  )
+ {
+ 	kdDebug(14180) << k_funcinfo << "webcam closed with reason?? " <<  reason <<endl;
+-	m_imageContainer.clear();
+-	m_imageContainer.setText( i18n( "Webcam closed with reason %1" ).arg( QString::number( reason ) ) );
+-	m_imageContainer.setAlignment( Qt::AlignCenter );
+-	show();
++	//m_imageContainer.clear();
++	//m_imageContainer.setText( i18n( "Webcam closed with reason %1" ).arg( QString::number( reason ) ) );
++	//m_imageContainer.setAlignment( Qt::AlignCenter );
++	//show();
+ }
+ 
+ // kate: indent-mode csands; tab-width 4;
+--- kopete/protocols/msn/msncontact.h	(revision 568672)
++++ kopete/protocols/msn/msncontact.h	(revision 586398)
+@@ -178,6 +178,8 @@
+ 	KAction *actionBlock;
+ 	KAction *actionShowProfile;
+ 	KAction *actionSendMail;
++	KAction *actionWebcamReceive;
++	KAction *actionWebcamSend;
+ 
+ 	QString m_obj; //the MSNObject
+ 
+--- kopete/protocols/msn/msnprotocol.cpp	(revision 568672)
++++ kopete/protocols/msn/msnprotocol.cpp	(revision 586398)
+@@ -160,15 +160,15 @@
+ QImage MSNProtocol::scalePicture(const QImage &picture)
+ {
+ 	QImage img(picture);
+-	img = img.smoothScale( 96, 96, QImage::ScaleMax );
++	img = img.smoothScale( 96, 96, QImage::ScaleMin );
+ 	// crop image if not square
+-	if(img.width() > img.height()) 
++	if(img.width() < img.height())
+ 	{
+-		img = img.copy((img.width()-img.height())/2, 0, img.height(), img.height());
++		img = img.copy((img.width()-img.height())/2, 0, 96, 96);
+ 	}
+-	else 
++	else if(img.width() > img.height())
+ 	{
+-		img = img.copy(0, (img.height()-img.width())/2, img.width(), img.width());
++		img = img.copy(0, (img.height()-img.width())/2, 96, 96);
+ 	}
+ 
+ 	return img;
+--- kopete/protocols/msn/ui/msneditaccountwidget.cpp	(revision 568672)
++++ kopete/protocols/msn/ui/msneditaccountwidget.cpp	(revision 586398)
+@@ -163,6 +163,9 @@
+ 		d->ui->m_displayPicture->setPixmap( d->pictureUrl );
+ 
+ 		d->ui->m_useDisplayPicture->setChecked( config->readBoolEntry( "exportCustomPicture" ));
++
++		// Global Identity
++		d->ui->m_globalIdentity->setChecked( config->readBoolEntry("ExcludeGlobalIdentity", false) );
+ 	}
+ 	else
+ 	{
+@@ -217,6 +220,9 @@
+ 	else
+ 		config->writeEntry( "WebcamPort" , 0 );
+ 
++	// Global Identity
++	config->writeEntry( "ExcludeGlobalIdentity", d->ui->m_globalIdentity->isChecked() );
++
+ 	// Save the avatar image
+ 	if( d->ui->m_useDisplayPicture->isChecked() && !d->pictureData.isNull() )
+ 	{
+--- kopete/protocols/msn/ui/msneditaccountui.ui	(revision 568672)
++++ kopete/protocols/msn/ui/msneditaccountui.ui	(revision 586398)
+@@ -9,8 +9,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>698</width>
+-            <height>479</height>
++            <width>604</width>
++            <height>437</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -40,22 +40,93 @@
+                 <attribute name="title">
+                     <string>&amp;Basic Setup</string>
+                 </attribute>
+-                <vbox>
++                <grid>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QGroupBox">
++                    <spacer row="2" column="0">
+                         <property name="name">
++                            <cstring>spacer41</cstring>
++                        </property>
++                        <property name="orientation">
++                            <enum>Vertical</enum>
++                        </property>
++                        <property name="sizeType">
++                            <enum>Expanding</enum>
++                        </property>
++                        <property name="sizeHint">
++                            <size>
++                                <width>20</width>
++                                <height>146</height>
++                            </size>
++                        </property>
++                    </spacer>
++                    <widget class="QGroupBox" row="1" column="0">
++                        <property name="name">
++                            <cstring>groupBox5</cstring>
++                        </property>
++                        <property name="sizePolicy">
++                            <sizepolicy>
++                                <hsizetype>3</hsizetype>
++                                <vsizetype>1</vsizetype>
++                                <horstretch>0</horstretch>
++                                <verstretch>0</verstretch>
++                            </sizepolicy>
++                        </property>
++                        <property name="title">
++                            <string>Registration</string>
++                        </property>
++                        <hbox>
++                            <property name="name">
++                                <cstring>unnamed</cstring>
++                            </property>
++                            <widget class="QLabel">
++                                <property name="name">
++                                    <cstring>textLabel6</cstring>
++                                </property>
++                                <property name="sizePolicy">
++                                    <sizepolicy>
++                                        <hsizetype>3</hsizetype>
++                                        <vsizetype>1</vsizetype>
++                                        <horstretch>0</horstretch>
++                                        <verstretch>0</verstretch>
++                                    </sizepolicy>
++                                </property>
++                                <property name="minimumSize">
++                                    <size>
++                                        <width>0</width>
++                                        <height>0</height>
++                                    </size>
++                                </property>
++                                <property name="text">
++                                    <string>To connect to the Microsoft network, you will need a Microsoft Passport.&lt;br&gt;&lt;br&gt;If you do not currently have a Passport, please click the button to create one.</string>
++                                </property>
++                                <property name="alignment">
++                                    <set>WordBreak|AlignVCenter</set>
++                                </property>
++                            </widget>
++                            <widget class="QPushButton">
++                                <property name="name">
++                                    <cstring>buttonRegister</cstring>
++                                </property>
++                                <property name="text">
++                                    <string>Re&amp;gister New Account</string>
++                                </property>
++                            </widget>
++                        </hbox>
++                    </widget>
++                    <widget class="QGroupBox" row="0" column="0">
++                        <property name="name">
+                             <cstring>m_accountInfo</cstring>
+                         </property>
+                         <property name="title">
+                             <string>Account Information</string>
+                         </property>
+-                        <vbox>
++                        <grid>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLayoutWidget">
++                            <widget class="QLayoutWidget" row="0" column="0">
+                                 <property name="name">
+                                     <cstring>layout14</cstring>
+                                 </property>
+@@ -104,12 +175,12 @@
+                                     </widget>
+                                 </hbox>
+                             </widget>
+-                            <widget class="Kopete::UI::PasswordWidget">
++                            <widget class="Kopete::UI::PasswordWidget" row="1" column="0">
+                                 <property name="name">
+                                     <cstring>m_password</cstring>
+                                 </property>
+                             </widget>
+-                            <widget class="QCheckBox">
++                            <widget class="QCheckBox" row="2" column="0">
+                                 <property name="name">
+                                     <cstring>m_autologin</cstring>
+                                 </property>
+@@ -123,80 +194,17 @@
+                                     <string>If you check this checkbox, the account will not be connected when you press the "Connect All" button, or at startup when automatic connection at startup is enabled.</string>
+                                 </property>
+                             </widget>
+-                        </vbox>
+-                    </widget>
+-                    <widget class="QGroupBox">
+-                        <property name="name">
+-                            <cstring>groupBox5</cstring>
+-                        </property>
+-                        <property name="sizePolicy">
+-                            <sizepolicy>
+-                                <hsizetype>3</hsizetype>
+-                                <vsizetype>1</vsizetype>
+-                                <horstretch>0</horstretch>
+-                                <verstretch>0</verstretch>
+-                            </sizepolicy>
+-                        </property>
+-                        <property name="title">
+-                            <string>Registration</string>
+-                        </property>
+-                        <hbox>
+-                            <property name="name">
+-                                <cstring>unnamed</cstring>
+-                            </property>
+-                            <widget class="QLabel">
++                            <widget class="QCheckBox" row="3" column="0">
+                                 <property name="name">
+-                                    <cstring>textLabel6</cstring>
++                                    <cstring>m_globalIdentity</cstring>
+                                 </property>
+-                                <property name="sizePolicy">
+-                                    <sizepolicy>
+-                                        <hsizetype>3</hsizetype>
+-                                        <vsizetype>1</vsizetype>
+-                                        <horstretch>0</horstretch>
+-                                        <verstretch>0</verstretch>
+-                                    </sizepolicy>
+-                                </property>
+-                                <property name="minimumSize">
+-                                    <size>
+-                                        <width>0</width>
+-                                        <height>0</height>
+-                                    </size>
+-                                </property>
+                                 <property name="text">
+-                                    <string>To connect to the Microsoft network, you will need a Microsoft Passport.&lt;br&gt;&lt;br&gt;If you do not currently have a Passport, please click the button to create one.</string>
++                                    <string>Exclu&amp;de from Global Identity</string>
+                                 </property>
+-                                <property name="alignment">
+-                                    <set>WordBreak|AlignVCenter</set>
+-                                </property>
+                             </widget>
+-                            <widget class="QPushButton">
+-                                <property name="name">
+-                                    <cstring>buttonRegister</cstring>
+-                                </property>
+-                                <property name="text">
+-                                    <string>Re&amp;gister New Account</string>
+-                                </property>
+-                            </widget>
+-                        </hbox>
++                        </grid>
+                     </widget>
+-                    <spacer>
+-                        <property name="name">
+-                            <cstring>spacer41</cstring>
+-                        </property>
+-                        <property name="orientation">
+-                            <enum>Vertical</enum>
+-                        </property>
+-                        <property name="sizeType">
+-                            <enum>Expanding</enum>
+-                        </property>
+-                        <property name="sizeHint">
+-                            <size>
+-                                <width>20</width>
+-                                <height>146</height>
+-                            </size>
+-                        </property>
+-                    </spacer>
+-                </vbox>
++                </grid>
+             </widget>
+             <widget class="QWidget">
+                 <property name="name">
+@@ -1089,7 +1097,7 @@
+                     <cstring>TabPage</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>&amp;Connection</string>
++                    <string>Co&amp;nnection</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -1239,10 +1247,10 @@
+                                             <cstring>m_useWebcamPort</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>S&amp;pecify a port for incoming webcam connection:</string>
++                                            <string>S&amp;pecify a base port for incoming webcam connections:</string>
+                                         </property>
+                                         <property name="whatsThis" stdset="0">
+-                                            <string>If you are behind a firewall, you may specify a port to use for the incoming connection, and configure your firewall to accept connections on this port. Incoming connections are used for the webcam. If you don't specify a port yourself, the operating system will choose an available port for you. It is recommended to leave the checkbox unchecked.</string>
++                                            <string>If you are behind a firewall, you may specify a base port to use for the incoming connection, and configure your firewall to accept connections on a range of 10 ports, starting at this one. Incoming connections are used for the webcam. If you don't specify a port yourself, the operating system will choose an available port for you. It is recommended to leave the checkbox unchecked.</string>
+                                         </property>
+                                     </widget>
+                                     <widget class="QSpinBox">
+@@ -1262,7 +1270,7 @@
+                                             <number>6891</number>
+                                         </property>
+                                         <property name="whatsThis" stdset="0">
+-                                            <string>If you are behind a firewall, you may specify a port to use for the incoming connection, and configure your firewall to accept connections on this port. Incoming connections are used for the webcam. If you don't specify a port yourself, the operating system will choose an available port for you. It is recommended to leave the checkbox unchecked.</string>
++                                            <string>If you are behind a firewall, you may specify a base port to use for the incoming connection, and configure your firewall to accept connections on a range of 10 ports, starting at this one. Incoming connections are used for the webcam. If you don't specify a port yourself, the operating system will choose an available port for you. It is recommended to leave the checkbox unchecked.</string>
+                                         </property>
+                                     </widget>
+                                 </hbox>
+@@ -1406,6 +1414,7 @@
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
++    <includehint>kopetepasswordwidget.h</includehint>
+     <includehint>kcombobox.h</includehint>
+     <includehint>klineedit.h</includehint>
+ </includehints>
+--- kopete/VERSION	(revision 568672)
++++ kopete/VERSION	(revision 586398)
+@@ -1 +1 @@
+-Kopete v0.11.1
++Kopete v0.12.2
+--- kopete/AUTHORS	(revision 568672)
++++ kopete/AUTHORS	(revision 586398)
+@@ -7,9 +7,6 @@
+ Duncan Mac-Vicar Prett <duncan at kde.org> (irc: duncanmv)
+ - Original author, main app work & design, original MSN Plugin, hacks in all plugins
+ 
+-Jason Keirstead <jason at keirstead.org> (irc: brunes)
+-- Kopete API developer, co-maintainer of the IRC plugin, website
+-
+ Martijn Klingens <klingens at kde.org> (irc: spaze)
+ - Kopete API and main application core developer, co-maintainer of the MSN plugin,
+   misc changes and fixes in the other plugins
+@@ -47,7 +44,7 @@
+ - Gadu-Gadu maintainer
+ 
+ Michel Hermier <michel.hermier at wanadoo.fr> (irc: slayer)
+-- IRC plugin co-maintainer
++- IRC plugin maintainer
+ 
+ Till Gerken <till at tantalo.net> (irc: tigloo)
+ - Jabber maintainer
+--- kopete/kopete/kopeteballoon.cpp	(revision 568672)
++++ kopete/kopete/kopeteballoon.cpp	(revision 586398)
+@@ -3,7 +3,7 @@
+ 
+     Copyright (c) 2002      by Duncan Mac-Vicar Prett <duncan at kde.org>
+ 
+-    Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005      by the Kopete developers  <kopete-devel at kde.org>
+ 
+     Portions of this code based on Kim Applet code
+     Copyright (c) 2000-2002 by Malte Starostik        <malte at kde.org>
+@@ -22,6 +22,7 @@
+ #include <qpushbutton.h>
+ #include <qtooltip.h>
+ #include <qlayout.h>
++#include <qtimer.h>
+ 
+ #include <kdeversion.h>
+ #include <kglobalsettings.h>
+@@ -36,6 +37,7 @@
+ 
+ #include "kopeteballoon.h"
+ #include "systemtray.h"
++#include "kopeteprefs.h"
+ 
+ KopeteActiveLabel::KopeteActiveLabel( QWidget *parent, const char *name )
+ 	: KActiveLabel( parent, name ) 
+@@ -119,6 +121,11 @@
+ 		this, SIGNAL(signalIgnoreButtonClicked()));
+ 	connect(mCaption, SIGNAL(linkClicked(const QString &)),
+ 		this, SLOT(deleteLater()));
++	
++	KopetePrefs *p = KopetePrefs::prefs();
++	// Autoclose balloon 
++	if (p->balloonClose())
++		QTimer::singleShot( p->balloonCloseDelay() * 1000, this, SIGNAL( signalTimeout( ) ) );
+ }
+ 
+ void KopeteBalloon::setAnchor(const QPoint &anchor)
+--- kopete/kopete/contactlist/kopetegroupviewitem.h	(revision 568672)
++++ kopete/kopete/contactlist/kopetegroupviewitem.h	(revision 586398)
+@@ -21,8 +21,8 @@
+ #include "kopetelistviewitem.h"
+ #include <qpixmap.h>
+ 
+-#define KOPETE_GROUP_DEFAULT_OPEN_ICON "folder_green_open"
+-#define KOPETE_GROUP_DEFAULT_CLOSED_ICON "folder_green"
++#define KOPETE_GROUP_DEFAULT_OPEN_ICON "folder_open"
++#define KOPETE_GROUP_DEFAULT_CLOSED_ICON "folder"
+ 
+ namespace Kopete
+ {
+--- kopete/kopete/contactlist/kopetemetacontactlvi.cpp	(revision 568672)
++++ kopete/kopete/contactlist/kopetemetacontactlvi.cpp	(revision 586398)
+@@ -542,13 +542,8 @@
+ 					effect->fade(photoImg, 0.8, Qt::white);
+ 			}
+ 			delete effect;
++			
+ 			photoPixmap = photoImg;
+-			QPainter p(&photoPixmap);
+-			p.setPen(Qt::black);
+-			p.drawLine(0, 0, photoPixmap.width()-1, 0);
+-			p.drawLine(0, photoPixmap.height()-1, photoPixmap.width()-1, photoPixmap.height()-1);
+-			p.drawLine(0, 0, 0, photoPixmap.height()-1);
+-			p.drawLine(photoPixmap.width()-1, 0, photoPixmap.width()-1, photoPixmap.height()-1);
+ 		}
+ 		else
+ 		{
+@@ -568,7 +563,7 @@
+ 
+ 	if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
+ 		i18n( "Are you sure you want to remove %1 from your contact list?" ).
+-		arg( m_metaContact->displayName() ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"),"editdelete") )
++		arg( m_metaContact->displayName() ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"),"delete_user") )
+ 		== KMessageBox::Continue )
+ 	{
+ 		Kopete::ContactList::self()->removeMetaContact( m_metaContact );
+--- kopete/kopete/contactlist/kopetelviprops.cpp	(revision 568672)
++++ kopete/kopete/contactlist/kopetelviprops.cpp	(revision 586398)
+@@ -53,6 +53,7 @@
+ #include "kopetemetacontactlvi.h"
+ #include "kopeteaccount.h"
+ #include "kopeteprotocol.h"
++#include "addressbooklinkwidget.h"
+ #include "addressbookselectordialog.h"
+ 
+ #include "customnotificationprops.h"
+@@ -176,10 +177,12 @@
+ 	connect( mainWidget->radioPhotoContact, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ 	connect( mainWidget->radioPhotoCustom, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ 	connect( mainWidget->cmbPhotoUrl, SIGNAL(urlSelected(const QString &)), SLOT(slotEnableAndDisableWidgets()));
++	connect( mainWidget->cmbAccountPhoto, SIGNAL(activated ( int )), SLOT(slotEnableAndDisableWidgets()));
++	
+ 
+-	mainWidget->btnClear->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) );
+-	connect( mainWidget->btnClear, SIGNAL( clicked() ), this, SLOT( slotClearAddresseeClicked() ) );
+-		
++	mainWidget->btnClearPhoto->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) );
++	connect( mainWidget->btnClearPhoto, SIGNAL( clicked() ), this, SLOT( slotClearPhotoClicked() ) );
++	connect( mainWidget->widAddresseeLink, SIGNAL( addresseeChanged( const KABC::Addressee & ) ), SLOT( slotAddresseeChanged( const KABC::Addressee & ) ) );
+ 	mainWidget->chkUseCustomIcons->setChecked( item->metaContact()->useCustomIcon() );
+ 
+ 	QString offlineName = item->metaContact()->icon( Kopete::ContactListElement::Offline );
+@@ -203,6 +206,8 @@
+ 	mainWidget->icnbAway->setIcon( awayName );
+ 	mainWidget->icnbUnknown->setIcon( unknownName );
+ 
++	mainWidget->widAddresseeLink->setMetaContact( lvi->metaContact() );
++
+ 	mAddressBookUid = item->metaContact()->metaContactId();
+ 
+ 	mExport = 0L;
+@@ -211,14 +216,12 @@
+ 	{
+ 		KABC::AddressBook *ab = Kopete::KABCPersistence::self()->addressBook();
+ 		KABC::Addressee a = ab->findByUid( mAddressBookUid );
++		mainWidget->widAddresseeLink->setAddressee( a );
+ 
+ 		if ( !a.isEmpty() )
+ 		{
+-			mainWidget->edtAddressee->setText( a.realName() );
+-			mainWidget->btnSelectAddressee->setEnabled( true );
+ 			mainWidget->btnImportKABC->setEnabled( true );
+ 			mainWidget->btnExportKABC->setEnabled( true );
+-			mainWidget->edtAddressee->setEnabled( true );
+ 			mExport = new KopeteAddressBookExport( this, item->metaContact() );
+ 			
+ 			mSound = a.sound();
+@@ -232,8 +235,6 @@
+ 	connect( this, SIGNAL(okClicked()), this, SLOT( slotOkClicked() ) );
+ 	connect( mainWidget->chkUseCustomIcons, SIGNAL( toggled( bool ) ),
+ 		this, SLOT( slotUseCustomIconsToggled( bool ) ) );
+-	connect( mainWidget->btnSelectAddressee, SIGNAL( clicked() ),
+-		this, SLOT( slotSelectAddresseeClicked() ) );
+ 	connect( mainWidget->btnImportKABC, SIGNAL( clicked() ),
+ 		this, SLOT( slotImportClicked() ) );
+ 	connect( mainWidget->btnExportKABC, SIGNAL( clicked() ),
+@@ -364,7 +365,7 @@
+ 		photo = Kopete::photoFromKABC(mAddressBookUid);
+ 		break;
+ 		case Kopete::MetaContact::SourceContact:
+-		photo = Kopete::photoFromContact(selectedNameSourceContact());
++		photo = Kopete::photoFromContact(selectedPhotoSourceContact());
+ 		break;
+ 		case Kopete::MetaContact::SourceCustom:
+ 		photo = QImage(KURL::decode_string(mainWidget->cmbPhotoUrl->url()));
+@@ -372,6 +373,8 @@
+ 	}
+ 	if( !photo.isNull() )
+ 		mainWidget->photoLabel->setPixmap(QPixmap(photo.smoothScale( 64, 92, QImage::ScaleMin )));
++	else
++		mainWidget->photoLabel->setPixmap( QPixmap() );
+ }
+ 
+ Kopete::MetaContact::PropertySource KopeteMetaLVIProps::selectedNameSource() const
+@@ -471,31 +474,25 @@
+ 	mainWidget->icnbUnknown->setEnabled( on );
+ }
+ 
+-void KopeteMetaLVIProps::slotClearAddresseeClicked()
++void KopeteMetaLVIProps::slotAddresseeChanged( const KABC::Addressee & a )
+ {
+-	mainWidget->edtAddressee->setText( QString::null );
+-	mAddressBookUid = QString::null;
+-	mainWidget->btnExportKABC->setEnabled( false );
+-	mainWidget->btnImportKABC->setEnabled( false );
+-	
+-	slotEnableAndDisableWidgets();
+-}
+-
+-void KopeteMetaLVIProps::slotSelectAddresseeClicked()
+-{
+-	KABC::Addressee a = Kopete::UI::AddressBookSelectorDialog::getAddressee( i18n("Addressbook Association"), i18n("Choose the person who '%1' is.").arg(item->metaContact()->displayName() ), item->metaContact()->metaContactId() , this);
+-
+ 	if ( !a.isEmpty() )
+ 	{
+ 		mSound = a.sound();
+ 		mFromKABC->setEnabled( !( mSound.isIntern() || mSound.url().isEmpty() ) );
+ 		mainWidget->btnExportKABC->setEnabled( true );
+ 		mainWidget->btnImportKABC->setEnabled( true );
+-		// set the lineedit to the Addressee's name
+-		mainWidget->edtAddressee->setText( a.realName() );
+ 		// set/update the MC's addressee uin field
+ 		mAddressBookUid = a.uid();
+ 	}
++	else
++	{
++		mainWidget->btnExportKABC->setEnabled( false );
++		mainWidget->btnImportKABC->setEnabled( false );
++		mAddressBookUid = QString::null;
++		mainWidget->radioNameContact->setChecked( true );
++		mainWidget->radioPhotoContact->setChecked( true );
++	}
+ 	slotEnableAndDisableWidgets();
+ }
+ 
+@@ -558,4 +555,16 @@
+ 	}
+ }
+ 
++void KopeteMetaLVIProps::slotClearPhotoClicked()
++{
++#if KDE_IS_VERSION(3,4,0)
++	mainWidget->cmbPhotoUrl->setKURL( KURL() );
++#else
++	mainWidget->cmbPhotoUrl->setURL( QString::null );
++#endif
++	item->metaContact()->setPhoto( KURL() );
++
++	slotEnableAndDisableWidgets();
++}
++
+ #include "kopetelviprops.moc"
+--- kopete/kopete/contactlist/kopetecontactlistview.cpp	(revision 568672)
++++ kopete/kopete/contactlist/kopetecontactlistview.cpp	(revision 586398)
+@@ -246,7 +246,6 @@
+ 	 : ContactListViewStrategy( view )
+ 	 , m_onlineItem( new KopeteStatusGroupViewItem( Kopete::OnlineStatus::Online, listView() ) )
+ 	 , m_offlineItem( new KopeteStatusGroupViewItem( Kopete::OnlineStatus::Offline, listView() ) )
+-	 , m_temporaryItem( 0 )
+ 	{
+ 		m_onlineItem->setOpen( true );
+ 		m_offlineItem->setOpen( true );
+@@ -259,7 +258,7 @@
+ 		removeMetaContactFromGroupInner( mc, m_onlineItem );
+ 		removeMetaContactFromGroupInner( mc, m_offlineItem );
+ 		if ( m_temporaryItem )
+-			removeMetaContactFromGroupInner( mc, m_temporaryItem );
++			removeMetaContactFromGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+ 	}
+ 
+ 	void addMetaContact( Kopete::MetaContact *mc )
+@@ -311,20 +310,19 @@
+ 				m_temporaryItem->setOpen( true );
+ 			}
+ 
+-			addMetaContactToGroupInner( mc, m_temporaryItem );
++			addMetaContactToGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+ 			return;
+ 		}
+ 
+ 		// if it's not temporary, it should not be in the temporary group
+ 		if ( m_temporaryItem )
+ 		{
+-			removeMetaContactFromGroupInner( mc, m_temporaryItem );
++			removeMetaContactFromGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+ 
+ 			// remove temporary item if empty
+ 			if ( m_temporaryItem && m_temporaryItem->childCount() == 0 )
+ 			{
+-				delete m_temporaryItem;
+-				m_temporaryItem = 0;
++				delete (KopeteGroupViewItem*)m_temporaryItem;
+ 			}
+ 		}
+ 
+@@ -356,7 +354,7 @@
+ 	}
+ 
+ 	KopeteStatusGroupViewItem *m_onlineItem, *m_offlineItem;
+-	KopeteGroupViewItem *m_temporaryItem;
++	QGuardedPtr<KopeteGroupViewItem> m_temporaryItem;
+ };
+ 
+ void KopeteContactListViewPrivate::updateViewStrategy( KListView *view )
+@@ -486,16 +484,17 @@
+ 		ac, "contactRemove" );
+ 	actionSendEmail = new KAction( i18n( "Send Email..." ), QString::fromLatin1( "mail_generic" ),
+ 		0, this, SLOT(  slotSendEmail() ), ac, "contactSendEmail" );
++	/* this actionRename is buggy, and useless with properties, removed in kopeteui.rc*/
+ 	actionRename = new KAction( i18n( "Rename" ), "filesaveas", 0,
+ 		this, SLOT( slotRename() ), ac, "contactRename" );
+ 	actionSendFile = KopeteStdAction::sendFile( this, SLOT( slotSendFile() ),
+ 		ac, "contactSendFile" );
+ 
+ 	actionAddContact = new KActionMenu( i18n( "&Add Contact" ),
+-		QString::fromLatin1( "bookmark_add" ), ac , "contactAddContact" );
++		QString::fromLatin1( "add_user" ), ac , "contactAddContact" );
+ 	actionAddContact->popupMenu()->insertTitle( i18n("Select Account") );
+ 
+-	actionAddTemporaryContact = new KAction( i18n( "Add to Your Contact List" ), "bookmark_add", 0,
++	actionAddTemporaryContact = new KAction( i18n( "Add to Your Contact List" ), "add_user", 0,
+ 		this, SLOT( slotAddTemporaryContact() ), ac, "contactAddTemporaryContact" );
+ 
+ 	connect( Kopete::ContactList::self(), SIGNAL( metaContactSelected( bool ) ), this, SLOT( slotMetaContactSelected( bool ) ) );
+@@ -503,7 +502,7 @@
+ 	connect( Kopete::AccountManager::self(), SIGNAL(accountRegistered( Kopete::Account* )), SLOT(slotAddSubContactActionNewAccount(Kopete::Account*)));
+ 	connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered( const Kopete::Account* )), SLOT(slotAddSubContactActionAccountDeleted(const Kopete::Account *)));
+ 
+-	actionProperties = new KAction( i18n( "&Properties" ), "", Qt::Key_Alt + Qt::Key_Return,
++	actionProperties = new KAction( i18n( "&Properties" ), "edit_user", Qt::Key_Alt + Qt::Key_Return,
+ 		this, SLOT( slotProperties() ), ac, "contactProperties" );
+ 
+ 	// Update enabled/disabled actions
+--- kopete/kopete/contactlist/kopetelviprops.h	(revision 568672)
++++ kopete/kopete/contactlist/kopetelviprops.h	(revision 586398)
+@@ -29,6 +29,7 @@
+ 
+ class QButtonGroup;
+ 
++class AddressBookLinkWidget;
+ class CustomNotificationProps;
+ class KPushButton;
+ class KopeteGroupViewItem;
+@@ -36,6 +37,7 @@
+ class KopeteAddressBookExport;
+ class KURLRequester;
+ 
++namespace KABC { class Addressee; }
+ namespace Kopete { class Contact; }
+ 
+ class KopeteGVIProps: public KDialogBase
+@@ -71,6 +73,7 @@
+ 		CustomNotificationProps * mNotificationProps;
+ 		QPushButton *mFromKABC;
+ 		KopeteMetaLVIPropsWidget *mainWidget;
++		AddressBookLinkWidget *linkWidget;
+ 		KopeteMetaContactLVI *item;
+ 		KopeteAddressBookExport *mExport;
+ 		KABC::Sound mSound;
+@@ -85,8 +88,8 @@
+ 	private slots:
+ 		void slotOkClicked();
+ 		void slotUseCustomIconsToggled( bool on );
+-		void slotClearAddresseeClicked();
+-		void slotSelectAddresseeClicked();
++		void slotClearPhotoClicked();
++		void slotAddresseeChanged( const KABC::Addressee & );
+ 		void slotExportClicked();
+ 		void slotImportClicked();
+ 		void slotFromKABCClicked();
+--- kopete/kopete/contactlist/kopetemetalvipropswidget.ui	(revision 568672)
++++ kopete/kopete/contactlist/kopetemetalvipropswidget.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>470</width>
+-            <height>429</height>
++            <width>530</width>
++            <height>457</height>
+         </rect>
+     </property>
+     <property name="toolTip" stdset="0">
+@@ -30,11 +30,11 @@
+                 <attribute name="title">
+                     <string>&amp;General</string>
+                 </attribute>
+-                <vbox>
++                <grid>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QGroupBox">
++                    <widget class="QGroupBox" row="0" column="0">
+                         <property name="name">
+                             <cstring>grpAddressbook</cstring>
+                         </property>
+@@ -53,54 +53,10 @@
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLayoutWidget">
++                            <widget class="Kopete::UI::AddressBookLinkWidget">
+                                 <property name="name">
+-                                    <cstring>layout9</cstring>
++                                    <cstring>widAddresseeLink</cstring>
+                                 </property>
+-                                <hbox>
+-                                    <property name="name">
+-                                        <cstring>unnamed</cstring>
+-                                    </property>
+-                                    <widget class="KLineEdit">
+-                                        <property name="name">
+-                                            <cstring>edtAddressee</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string></string>
+-                                        </property>
+-                                        <property name="readOnly">
+-                                            <bool>true</bool>
+-                                        </property>
+-                                        <property name="toolTip" stdset="0">
+-                                            <string>The KDE Address Book entry associated with this Kopete Contact</string>
+-                                        </property>
+-                                    </widget>
+-                                    <widget class="KPushButton">
+-                                        <property name="name">
+-                                            <cstring>btnClear</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string></string>
+-                                        </property>
+-                                        <property name="toolTip" stdset="0">
+-                                            <string>Clear</string>
+-                                        </property>
+-                                    </widget>
+-                                    <widget class="QPushButton">
+-                                        <property name="name">
+-                                            <cstring>btnSelectAddressee</cstring>
+-                                        </property>
+-                                        <property name="enabled">
+-                                            <bool>true</bool>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string>Change...</string>
+-                                        </property>
+-                                        <property name="toolTip" stdset="0">
+-                                            <string>Select an address book entry</string>
+-                                        </property>
+-                                    </widget>
+-                                </hbox>
+                             </widget>
+                             <widget class="QLayoutWidget">
+                                 <property name="name">
+@@ -159,7 +115,7 @@
+                             </widget>
+                         </vbox>
+                     </widget>
+-                    <widget class="QButtonGroup">
++                    <widget class="QButtonGroup" row="1" column="0">
+                         <property name="name">
+                             <cstring>buttonGroup1</cstring>
+                         </property>
+@@ -175,7 +131,7 @@
+                                     <cstring>radioNameKABC</cstring>
+                                 </property>
+                                 <property name="text">
+-                                    <string>Use addressbook name (needs addressbook link)</string>
++                                    <string>Use addressbook &amp;name (needs addressbook link)</string>
+                                 </property>
+                             </widget>
+                             <widget class="QLayoutWidget">
+@@ -242,7 +198,7 @@
+                                             <cstring>radioNameCustom</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>Custom:</string>
++                                            <string>Cus&amp;tom:</string>
+                                         </property>
+                                     </widget>
+                                     <spacer>
+@@ -271,7 +227,7 @@
+                             </widget>
+                         </vbox>
+                     </widget>
+-                    <widget class="QButtonGroup">
++                    <widget class="QButtonGroup" row="2" column="0">
+                         <property name="name">
+                             <cstring>buttonGroup2</cstring>
+                         </property>
+@@ -282,7 +238,7 @@
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QLabel" row="0" column="1">
++                            <widget class="QLabel" row="0" column="1" rowspan="3" colspan="1">
+                                 <property name="name">
+                                     <cstring>photoLabel</cstring>
+                                 </property>
+@@ -311,118 +267,130 @@
+                                     <bool>false</bool>
+                                 </property>
+                             </widget>
+-                            <widget class="QLayoutWidget" row="0" column="0">
++                            <widget class="QRadioButton" row="0" column="0">
+                                 <property name="name">
+-                                    <cstring>layout20</cstring>
++                                    <cstring>radioPhotoKABC</cstring>
+                                 </property>
+-                                <vbox>
++                                <property name="text">
++                                    <string>U&amp;se addressbook photo (needs addressbook link)</string>
++                                </property>
++                            </widget>
++                            <widget class="QLayoutWidget" row="1" column="0">
++                                <property name="name">
++                                    <cstring>layout13</cstring>
++                                </property>
++                                <hbox>
+                                     <property name="name">
+                                         <cstring>unnamed</cstring>
+                                     </property>
+                                     <widget class="QRadioButton">
+                                         <property name="name">
+-                                            <cstring>radioPhotoKABC</cstring>
++                                            <cstring>radioPhotoContact</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>Use addressbook photo (needs addressbook link)</string>
++                                            <string>From contact:</string>
+                                         </property>
+                                     </widget>
+-                                    <widget class="QLayoutWidget">
++                                    <spacer>
+                                         <property name="name">
+-                                            <cstring>layout13</cstring>
++                                            <cstring>spacer9</cstring>
+                                         </property>
+-                                        <hbox>
+-                                            <property name="name">
+-                                                <cstring>unnamed</cstring>
+-                                            </property>
+-                                            <widget class="QRadioButton">
+-                                                <property name="name">
+-                                                    <cstring>radioPhotoContact</cstring>
+-                                                </property>
+-                                                <property name="text">
+-                                                    <string>From contact:</string>
+-                                                </property>
+-                                            </widget>
+-                                            <spacer>
+-                                                <property name="name">
+-                                                    <cstring>spacer9</cstring>
+-                                                </property>
+-                                                <property name="orientation">
+-                                                    <enum>Horizontal</enum>
+-                                                </property>
+-                                                <property name="sizeType">
+-                                                    <enum>Fixed</enum>
+-                                                </property>
+-                                                <property name="sizeHint">
+-                                                    <size>
+-                                                        <width>20</width>
+-                                                        <height>20</height>
+-                                                    </size>
+-                                                </property>
+-                                            </spacer>
+-                                            <widget class="QComboBox">
+-                                                <property name="name">
+-                                                    <cstring>cmbAccountPhoto</cstring>
+-                                                </property>
+-                                                <property name="sizePolicy">
+-                                                    <sizepolicy>
+-                                                        <hsizetype>7</hsizetype>
+-                                                        <vsizetype>0</vsizetype>
+-                                                        <horstretch>0</horstretch>
+-                                                        <verstretch>0</verstretch>
+-                                                    </sizepolicy>
+-                                                </property>
+-                                                <property name="toolTip" stdset="0">
+-                                                    <string>Contact to synchronize the displayname with.</string>
+-                                                </property>
+-                                            </widget>
+-                                        </hbox>
++                                        <property name="orientation">
++                                            <enum>Horizontal</enum>
++                                        </property>
++                                        <property name="sizeType">
++                                            <enum>Fixed</enum>
++                                        </property>
++                                        <property name="sizeHint">
++                                            <size>
++                                                <width>20</width>
++                                                <height>20</height>
++                                            </size>
++                                        </property>
++                                    </spacer>
++                                    <widget class="QComboBox">
++                                        <property name="name">
++                                            <cstring>cmbAccountPhoto</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>7</hsizetype>
++                                                <vsizetype>0</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="toolTip" stdset="0">
++                                            <string>Contact to synchronize the displayname with.</string>
++                                        </property>
+                                     </widget>
+-                                    <widget class="QLayoutWidget">
++                                </hbox>
++                            </widget>
++                            <widget class="QLayoutWidget" row="2" column="0">
++                                <property name="name">
++                                    <cstring>layout7</cstring>
++                                </property>
++                                <hbox>
++                                    <property name="name">
++                                        <cstring>unnamed</cstring>
++                                    </property>
++                                    <widget class="QRadioButton">
+                                         <property name="name">
+-                                            <cstring>layout19</cstring>
++                                            <cstring>radioPhotoCustom</cstring>
+                                         </property>
+-                                        <hbox>
+-                                            <property name="name">
+-                                                <cstring>unnamed</cstring>
+-                                            </property>
+-                                            <widget class="QRadioButton">
+-                                                <property name="name">
+-                                                    <cstring>radioPhotoCustom</cstring>
+-                                                </property>
+-                                                <property name="text">
+-                                                    <string>Custom:</string>
+-                                                </property>
+-                                            </widget>
+-                                            <spacer>
+-                                                <property name="name">
+-                                                    <cstring>spacer9_2</cstring>
+-                                                </property>
+-                                                <property name="orientation">
+-                                                    <enum>Horizontal</enum>
+-                                                </property>
+-                                                <property name="sizeType">
+-                                                    <enum>Fixed</enum>
+-                                                </property>
+-                                                <property name="sizeHint">
+-                                                    <size>
+-                                                        <width>20</width>
+-                                                        <height>20</height>
+-                                                    </size>
+-                                                </property>
+-                                            </spacer>
+-                                            <widget class="KURLComboRequester">
+-                                                <property name="name">
+-                                                    <cstring>cmbPhotoUrl</cstring>
+-                                                </property>
+-                                            </widget>
+-                                        </hbox>
++                                        <property name="text">
++                                            <string>Custom:</string>
++                                        </property>
+                                     </widget>
+-                                </vbox>
++                                    <spacer>
++                                        <property name="name">
++                                            <cstring>spacer9_2</cstring>
++                                        </property>
++                                        <property name="orientation">
++                                            <enum>Horizontal</enum>
++                                        </property>
++                                        <property name="sizeType">
++                                            <enum>Fixed</enum>
++                                        </property>
++                                        <property name="sizeHint">
++                                            <size>
++                                                <width>20</width>
++                                                <height>20</height>
++                                            </size>
++                                        </property>
++                                    </spacer>
++                                    <widget class="KURLComboRequester">
++                                        <property name="name">
++                                            <cstring>cmbPhotoUrl</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>7</hsizetype>
++                                                <vsizetype>5</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                    </widget>
++                                    <widget class="KPushButton">
++                                        <property name="name">
++                                            <cstring>btnClearPhoto</cstring>
++                                        </property>
++                                        <property name="maximumSize">
++                                            <size>
++                                                <width>32</width>
++                                                <height>32</height>
++                                            </size>
++                                        </property>
++                                        <property name="text">
++                                            <string></string>
++                                        </property>
++                                    </widget>
++                                </hbox>
+                             </widget>
+                         </grid>
+                     </widget>
+-                    <widget class="QCheckBox">
++                    <widget class="QCheckBox" row="3" column="0">
+                         <property name="name">
+                             <cstring>chkSyncPhoto</cstring>
+                         </property>
+@@ -430,14 +398,14 @@
+                             <string>S&amp;ync photo to addressbook</string>
+                         </property>
+                     </widget>
+-                </vbox>
++                </grid>
+             </widget>
+             <widget class="QWidget">
+                 <property name="name">
+                     <cstring>TabPage</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>&amp;Advanced</string>
++                    <string>Ad&amp;vanced</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -584,9 +552,6 @@
+ </widget>
+ <tabstops>
+     <tabstop>tabWidget</tabstop>
+-    <tabstop>edtAddressee</tabstop>
+-    <tabstop>btnClear</tabstop>
+-    <tabstop>btnSelectAddressee</tabstop>
+     <tabstop>btnExportKABC</tabstop>
+     <tabstop>btnImportKABC</tabstop>
+     <tabstop>edtDisplayName</tabstop>
+@@ -599,13 +564,21 @@
+     <tabstop>icnbOffline</tabstop>
+     <tabstop>icnbUnknown</tabstop>
+ </tabstops>
++<customwidgets>
++    <customwidget>
++      <class>Kopete::UI::AddressBookLinkWidget</class>
++        <header>addressbooklinkwidget.h</header>
++    </customwidget>
++</customwidgets>				     
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
++    <includehint>addressbooklinkwidget.h</includehint>
+     <includehint>klineedit.h</includehint>
+     <includehint>kpushbutton.h</includehint>
+     <includehint>kurlrequester.h</includehint>
+     <includehint>kcombobox.h</includehint>
+     <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
+     <includehint>kicondialog.h</includehint>
+     <includehint>kicondialog.h</includehint>
+     <includehint>kicondialog.h</includehint>
+--- kopete/kopete/groupkabcselectorwidget.ui	(revision 0)
++++ kopete/kopete/groupkabcselectorwidget.ui	(revision 586398)
+@@ -0,0 +1,91 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>GroupKABCSelectorWidget</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>GroupKABCSelectorWidget</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>487</width>
++            <height>80</height>
++        </rect>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <property name="margin">
++            <number>0</number>
++        </property>
++        <widget class="Line">
++            <property name="name">
++                <cstring>line1</cstring>
++            </property>
++            <property name="frameShape">
++                <enum>HLine</enum>
++            </property>
++            <property name="frameShadow">
++                <enum>Sunken</enum>
++            </property>
++            <property name="orientation">
++                <enum>Horizontal</enum>
++            </property>
++        </widget>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout13</cstring>
++            </property>
++            <grid>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>kabcLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Addressbook entry:</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>kabcCombo</cstring>
++                    </property>
++                </widget>
++                <widget class="Kopete::UI::AddressBookLinkWidget" row="1" column="1">
++                    <property name="name">
++                        <cstring>widAddresseeLink</cstring>
++                    </property>
++                </widget>
++                <widget class="QLabel" row="0" column="0">
++                    <property name="name">
++                        <cstring>groupLabel</cstring>
++                    </property>
++                    <property name="text">
++                        <string>&amp;Group</string>
++                    </property>
++                    <property name="buddy" stdset="0">
++                        <cstring>groupCombo</cstring>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="0" column="1">
++                    <property name="name">
++                        <cstring>groupCombo</cstring>
++                    </property>
++                </widget>
++            </grid>
++        </widget>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<customwidgets>
++    <customwidget>
++      <class>Kopete::UI::AddressBookLinkWidget</class>
++      <header>addressbooklinkwidget.h</header>
++    </customwidget>
++</customwidgets>				     
++<includehints>
++    <includehint>klineedit.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/kopete/kopetewindow.h	(revision 568672)
++++ kopete/kopete/kopetewindow.h	(revision 586398)
+@@ -23,15 +23,21 @@
+ #include <qptrdict.h>
+ 
+ #include <kmainwindow.h>
++#include <qlabel.h>
+ 
+ class QHBox;
+ class QTimer;
++class QSignalMapper;
+ 
++class QMouseEvent;
++class QPoint;
++
+ class KAction;
+ class KActionMenu;
+ 
+ class KGlobalAccel;
+ class KSelectAction;
++class KSqueezedTextLabel;
+ class KToggleAction;
+ 
+ class KopeteAccountStatusBarIcon;
+@@ -60,7 +66,7 @@
+ 	KopeteWindow ( QWidget *parent = 0, const char *name = 0 );
+ 	~KopeteWindow();
+ 
+-    virtual bool eventFilter( QObject* o, QEvent* e );
++	virtual bool eventFilter( QObject* o, QEvent* e );
+ 
+ protected:
+ 	virtual void closeEvent( QCloseEvent *ev );
+@@ -81,6 +87,10 @@
+ 	void slotShowHide();
+ 	void slotToggleAway();
+ 
++	/* show the global status message selector menu
++	 */
++	void setStatusMessage( const QString & );
++	
+ 	/**
+ 	 * Checks if the mousecursor is in the contact list.
+ 	 * If not, the window will be hidden.
+@@ -95,15 +105,14 @@
+ 	void slotContactListAppearanceChanged();
+ 
+ 	/**
+-	 * This slot will show an away dialog and then
+-	 * set all the protocols to away
++	 * This slot will set all the protocols to away
+ 	 */
+-	void slotGlobalAwayMessageSelect( const QString & );
+-	void slotGlobalBusyMessageSelect( const QString & );
+-	void slotGlobalAvailableMessageSelect( const QString & );
+-	void slotSetInvisibleAll(  );
++	void slotGlobalAway();
++	void slotGlobalBusy();
++	void slotGlobalAvailable();
++	void slotSetInvisibleAll();
++	void slotDisconnectAll();
+ 
+-
+ 	void slotQuit();
+ 
+ 	/**
+@@ -150,7 +159,7 @@
+ 	/**
+ 	 * Show the Add Contact wizard
+ 	 */
+-	void showAddContactDialog();
++	void showAddContactDialog( Kopete::Account * );
+ 
+ 	/**
+ 	 * Show the Export Contacts wizards
+@@ -163,12 +172,32 @@
+ 	 * signals.
+ 	 */
+ 	void slotAllPluginsLoaded();
++	
++	/**
++	 * Protected slot to setup the Set Global Status Message menu.
++	 */
++	void slotBuildStatusMessageMenu();
++	void slotStatusMessageSelected( int i );
++	void slotNewStatusMessageEntered();
+ 
++        /**
++         * Show the set global status message menu when clicking on the icon in the status bar.
++         */
++        void slotGlobalStatusMessageIconClicked( const QPoint &position );
++
++	/**
++	 * Extracts protocolId and accountId from the single QString argument signalled by a QSignalMapper,
++	 * get the account, and call showAddContactDialog.
++	 * @param accountIdentifer QString of protocolId and accountId, concatenated with QChar( 0xE000 )
++	 * We need both to uniquely identify an account, but QSignalMapper only emits one QString.
++	 */
++	void slotAddContactDialogInternal( const QString & accountIdentifier );
++	
+ public:
+ 	KopeteContactListView *contactlist;
+ 
+ 	// Some Actions
+-	KAction* actionAddContact;
++	KActionMenu* actionAddContact;
+ 
+ 	//KActionMenu* actionConnectionMenu;
+ 	//KAction* actionConnect;
+@@ -177,8 +206,8 @@
+ 
+ 	KActionMenu* actionAwayMenu;
+ 	KActionMenu* actionDockMenu;
+-	Kopete::AwayAction* selectAway;
+-	Kopete::AwayAction* selectBusy;
++	KAction* selectAway;
++	KAction* selectBusy;
+ 	KAction* actionSetAvailable;
+ 	KAction* actionSetInvisible;
+ 
+@@ -215,6 +244,7 @@
+ 	bool m_autoHide;
+ 	unsigned int m_autoHideTimeout;
+ 	QTimer* m_autoHideTimer;
++	QSignalMapper* addContactMapper;
+ 
+ 	KopetePluginConfig *m_pluginConfig;
+ 
+@@ -225,6 +255,26 @@
+ 	 * use QObject instead.
+ 	 */
+ 	QPtrDict<QObject> m_accountStatusBarIcons;
++	KSqueezedTextLabel * m_globalStatusMessage;
++	KPopupMenu * m_globalStatusMessageMenu;
++	QLineEdit * m_newMessageEdit;
++	QString m_globalStatusMessageStored;
+ };
++
++
++class GlobalStatusMessageIconLabel : public QLabel
++{
++      Q_OBJECT
++public:
++      GlobalStatusMessageIconLabel(QWidget *parent = 0, const char *name = 0);
++
++protected:
++      void mouseReleaseEvent(QMouseEvent *event);
++
++signals:
++      void iconClicked(const QPoint &position);
++
++};
++
+ #endif
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/main.cpp	(revision 568672)
++++ kopete/kopete/main.cpp	(revision 586398)
+@@ -53,28 +53,32 @@
+ 		KOPETE_VERSION_STRING, description, KAboutData::License_GPL,
+ 		I18N_NOOP("(c) 2001-2004, Duncan Mac-Vicar Prett\n(c) 2002-2005, Kopete Development Team"), "kopete-devel at kde.org", "http://kopete.kde.org");
+ 
+-	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Project founder and original author"), "duncan at kde.org", "http://www.mac-vicar.org/~duncan" );
++	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Developer and Project founder"), "duncan at kde.org", "http://www.mac-vicar.org/~duncan" );
+ 	aboutData.addAuthor ( "Andre Duffeck", I18N_NOOP("Developer, Yahoo plugin maintainer"), "andre at duffeck.de" );
+-	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till at tantalo.net");
+-	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Lead Developer, MSN plugin maintainer"), "ogoffart @ kde.org");
+ 	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens at telenet.be" );
+-	aboutData.addAuthor ( "Michel Hermier", I18N_NOOP("IRC plugin maintainer"), "michel.hermier at wanadoo.fr" );
++	aboutData.addAuthor ( "Chetan Reddy", I18N_NOOP("Developer, Yahoo"), "chetan13 at gmail.com" );
+ 	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Developer, Connection status plugin author"), "howells at kde.org", "http://chrishowells.co.uk");
++	aboutData.addAuthor ( "Cláudio da Silveira Pinheiro", I18N_NOOP("Developer, Video device support"), "taupter at gmail.com", "http://taupter.homelinux.org" );
++	aboutData.addAuthor ( "Gregg Edghill", I18N_NOOP("Developer, MSN"), "gregg.edghill at gmail.com");
+ 	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj at pointblue.com.pl" );
+ 	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer"), "jason at keirstead.org", "http://www.keirstead.org");
+-	aboutData.addAuthor ( "Chetan Reddy", I18N_NOOP("Developer, Yahoo"), "chetan13 at gmail.com" );
+-	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Project Maintainer, Lead Developer, AIM and ICQ plugin maintainer"), "mattr at kde.org" );
++	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Lead Developer, AIM and ICQ plugin maintainer"), "mattr at kde.org" );
++	aboutData.addAuthor ( "Michel Hermier", I18N_NOOP("IRC plugin maintainer"), "michel.hermier at wanadoo.fr" );
++	aboutData.addAuthor ( "Michaël Larouche", I18N_NOOP("Lead Developer"), "michael.larouche at kdemail.net", "http://mlarouche.blogspot.com" );
++	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Lead Developer, MSN plugin maintainer"), "ogoffart @ kde.org");
++	aboutData.addAuthor ( "Ollivier Lapeyre Johann", I18N_NOOP("Artist / Developer, Artwork maintainer"), "johann.ollivierlapeyre at gmail.com" );
+ 	aboutData.addAuthor ( "Richard Smith", I18N_NOOP("Developer, UI maintainer"), "kde at metafoo.co.uk" );
+-	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, GroupWise maintainer"), "lists at stevello.free-online.co.uk" );
+-	aboutData.addAuthor ( "Michaël Larouche", I18N_NOOP("Developer, MSN"), "michael.larouche at kdemail.net", "http://mlarouche.blogspot.com" );
+-	aboutData.addAuthor ( "Cláudio da Silveira Pinheiro", I18N_NOOP("Developer, Video device support"), "taupter at gmail.com", "http://taupter.homelinux.org" );
+-
++	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till at tantalo.net");
++	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Lead Developer, GroupWise maintainer"), "lists at stevello.free-online.co.uk" );
++	
++	aboutData.addCredit ( "Vally8", I18N_NOOP("Konki style author"), "vally8 at gmail.com", "http://vally8.free.fr/" );
++	aboutData.addCredit ( "Tm_T", I18N_NOOP("Hacker style author"), "jussi.kekkonen at gmail.com");
+ 	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
+ 	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );
++	aboutData.addCredit ( "Jessica Hall", I18N_NOOP("Kopete Docugoddess, Bug and Patch Testing.") );
+ 	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Iris Jabber Backend Library") );
+ 	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6 at po.cwru.edu" );
+ 	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );
+-	
+ 	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher at kde.org");
+ 	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan at kde.org" );
+ 	aboutData.addCredit ( "Stefan Gehn", I18N_NOOP("Former developer"), "metz at gehn.net", "http://metz.gehn.net" );
+@@ -99,7 +103,7 @@
+ 	new KIMIfaceImpl();
+ 	kapp->dcopClient()->registerAs( "kopete", false );
+ 	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec
+-	
++
+ 	kopete.exec();
+ }
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/systemtray.cpp	(revision 568672)
++++ kopete/kopete/systemtray.cpp	(revision 586398)
+@@ -5,7 +5,7 @@
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+     Copyright (c) 2003-2004 by Olivier Goffart        <ogoffart @ kde.org>
+ 
+-    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -194,7 +194,17 @@
+ 
+ void KopeteSystemTray::slotNewEvent( Kopete::MessageEvent *event )
+ {
+-	mEventList.append( event );
++	if( KopetePrefs::prefs()->useStack() )
++	{
++		mEventList.prepend( event );
++		mBalloonEventList.prepend( event );
++	}
++	else
++	{
++		mEventList.append( event );
++		mBalloonEventList.append( event );
++	}
++
+ 	connect(event, SIGNAL(done(Kopete::MessageEvent*)),
+ 		this, SLOT(slotEventDone(Kopete::MessageEvent*)));
+ 
+@@ -218,28 +228,48 @@
+ 
+ 	// tray animation
+ 	if ( KopetePrefs::prefs()->trayflashNotify() )
+-		startBlink();
++		if( mBalloonEventList.count() == mEventList.count() )
++			startBlink();
++		else
++			stopBlink();
+ }
+ 
+ void KopeteSystemTray::slotEventDone(Kopete::MessageEvent *event)
+ {
+-	bool current= event==mEventList.first();
+ 	mEventList.remove(event);
+ 
++	removeBalloonEvent(event);
++
++	if(mEventList.isEmpty())
++		stopBlink();
++}
++
++void KopeteSystemTray::slotRemoveBalloon()
++{
++	removeBalloonEvent(mBalloonEventList.first());
++}
++
++void KopeteSystemTray::removeBalloonEvent(Kopete::MessageEvent *event)
++{
++	bool current= event==mBalloonEventList.first();
++	mBalloonEventList.remove(event);
++
+ 	if(current && m_balloon)
+ 	{
+ 		m_balloon->deleteLater();
+ 		m_balloon=0l;
+-		if(!mEventList.isEmpty())
++		if(!mBalloonEventList.isEmpty())
+ 		{
+ 			//delay the addBalloon to let the time to event be deleted
+ 			//in case a contact has been deleted   cf Bug 100196
+ 			QTimer::singleShot(0, this, SLOT(addBalloon()));
+ 		}
++		else
++		{
++			if(KopetePrefs::prefs()->trayflashNotify() && !mEventList.isEmpty())
++				startBlink();
++		}
+ 	}
+-
+-	if(mEventList.isEmpty())
+-		stopBlink();
+ }
+ 
+ void KopeteSystemTray::addBalloon()
+@@ -247,12 +277,18 @@
+ 	/*kdDebug(14010) << k_funcinfo <<
+ 		m_balloon << ":" << KopetePrefs::prefs()->showTray() <<
+ 		":" << KopetePrefs::prefs()->balloonNotify()
+-		<< ":" << !mEventList.isEmpty() << endl;*/
++		<< ":" << !mBalloonEventList.isEmpty() << endl;*/
+ 
+-	if( !m_balloon && KopetePrefs::prefs()->showTray() && KopetePrefs::prefs()->balloonNotify() && !mEventList.isEmpty() )
++	if( m_balloon && KopetePrefs::prefs()->useStack() )
+ 	{
+-		Kopete::Message msg = mEventList.first()->message();
++		m_balloon->deleteLater();
++		m_balloon=0l;
++	}
+ 
++	if( !m_balloon && KopetePrefs::prefs()->showTray() && KopetePrefs::prefs()->balloonNotify() && !mBalloonEventList.isEmpty() )
++	{
++		Kopete::Message msg = mBalloonEventList.first()->message();
++
+ 		if ( msg.from() )
+ 		{
+ 			QString msgText = squashMessage( msg );
+@@ -267,9 +303,10 @@
+ 			m_balloon = new KopeteBalloon(
+ 				i18n( "<qt><nobr><b>New Message from %1:</b></nobr><br><nobr>\"%2\"</nobr></qt>" )
+ 					.arg( msgFrom, msgText ), QString::null );
+-			connect(m_balloon, SIGNAL(signalBalloonClicked()), mEventList.first() , SLOT(apply()));
+-			connect(m_balloon, SIGNAL(signalButtonClicked()), mEventList.first() , SLOT(apply()));
+-			connect(m_balloon, SIGNAL(signalIgnoreButtonClicked()), mEventList.first() , SLOT(ignore()));
++			connect(m_balloon, SIGNAL(signalBalloonClicked()), mBalloonEventList.first() , SLOT(apply()));
++			connect(m_balloon, SIGNAL(signalButtonClicked()), mBalloonEventList.first() , SLOT(apply()));
++			connect(m_balloon, SIGNAL(signalIgnoreButtonClicked()), mBalloonEventList.first() , SLOT(ignore()));
++			connect(m_balloon, SIGNAL(signalTimeout()), this , SLOT(slotRemoveBalloon()));
+ 			m_balloon->setAnchor(mapToGlobal(pos()));
+ 			m_balloon->show();
+ 			KWin::setOnAllDesktops(m_balloon->winId(), true);
+--- kopete/kopete/kopeteballoon.h	(revision 568672)
++++ kopete/kopete/kopeteballoon.h	(revision 586398)
+@@ -3,7 +3,7 @@
+ 
+     Copyright (c) 2002      by Duncan Mac-Vicar Prett <duncan at kde.org>
+ 
+-    Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005      by the Kopete developers  <kopete-devel at kde.org>
+ 
+     Portions of this code based on Kim Applet code
+     Copyright (c) 2000-2002 by Malte Starostik        <malte at kde.org>
+@@ -62,6 +62,7 @@
+ 	void signalButtonClicked();
+ 	void signalIgnoreButtonClicked();
+ 	void signalBalloonClicked();
++	void signalTimeout();
+ 
+ protected:
+ 	virtual void updateMask();
+--- kopete/kopete/addcontactwizard/addcontactwizard_base.ui	(revision 568672)
++++ kopete/kopete/addcontactwizard/addcontactwizard_base.ui	(revision 586398)
+@@ -202,7 +202,7 @@
+                     <cstring>mDisplayName</cstring>
+                 </property>
+                 <property name="toolTip" stdset="0">
+-                    <string>Leave this blank to use any display name set by the contact themself</string>
++                    <string>Leave this blank to use any display name set by the contact</string>
+                 </property>
+             </widget>
+             <spacer row="3" column="1">
+--- kopete/kopete/kopeteaccountstatusbaricon.cpp	(revision 568672)
++++ kopete/kopete/kopeteaccountstatusbaricon.cpp	(revision 586398)
+@@ -16,6 +16,7 @@
+ */
+ 
+ #include "kopeteaccountstatusbaricon.h"
++#include "qcursor.h"
+ 
+ #include <kdebug.h>
+ 
+@@ -31,6 +32,7 @@
+ 	//setPixmap( proto->status().protocolIcon() );
+ 
+ 	setFixedSize ( 16, 16 );
++	setCursor(QCursor(Qt::PointingHandCursor));
+ 	show();
+ 
+ 	m_account = acc;
+--- kopete/kopete/kopeteui.rc	(revision 568672)
++++ kopete/kopete/kopeteui.rc	(revision 586398)
+@@ -1,10 +1,11 @@
+ <!DOCTYPE kpartgui>
+-<kpartgui name="kopete" version="22">
++<kpartgui name="kopete" version="25">
+ 	<MenuBar>
+ 		<Menu name="file" noMerge="1">
+ 			<text>&amp;File</text>
+ 			<!-- <Action name="Connection"/> -->
+ 			<Action name="Status"/>
++			<Action name="SetStatusMessage"/>
+ 			<Separator lineSeparator="true"/>
+ 			<Action name="AddContact"/>
+ 			<Action name="AddGroup"/>
+@@ -20,13 +21,10 @@
+ 			<Separator lineSeparator="true" />
+ 			<Action name="contactMove" />
+ 			<Action name="contactCopy" />
+-			<Action name="contactRemove" />
+-			<Action name="contactRename" />
+ 			<Action name="contactAddContact" />
+ 			<Action name="contactAddTemporaryContact" />
+-			<Separator lineSeparator="true" />
++			<Action name="contactRemove" />
+ 			<Merge />
+-			<Separator lineSeparator="true" />
+ 			<Action name="contactProperties" />
+ 
+ 		</Menu>
+@@ -48,6 +46,7 @@
+ 
+ 	<ToolBar fullWidth="true" name="mainToolBar" noMerge="1"><Text>Main Toolbar</Text>
+ 		<Action name="Status"/>
++		<Action name="SetStatusMessage"/>
+ 		<Action name="AddContact"/>
+ 		<Action name="settings_show_offliners"/>
+ 		<Action name="settings_show_empty_groups"/>
+@@ -79,13 +78,10 @@
+ 			  <Action name="contactMove" />
+ 			  <Action name="contactCopy" />
+ 		</Menu>
+-		<Action name="contactRemove" />
+-		<Action name="contactRename" />
+ 		<Action name="contactAddContact" />
+ 		<Action name="contactAddTemporaryContact" />
+-		<Separator lineSeparator="true" />
++		<Action name="contactRemove" />
+ 		<Merge />
+-		<Separator lineSeparator="true" />
+ 		<Action name="contactProperties" />
+ 		<Separator lineSeparator="true" />
+ 	</Menu>
+--- kopete/kopete/eventsrc	(revision 568672)
++++ kopete/kopete/eventsrc	(revision 586398)
+@@ -737,8 +737,51 @@
+ Comment[zh_TW]=接收到一個標記為低優先權的訊息
+ default_presentation=0
+ 
++[kopete_authorization]
++Name=Authorization
++Name[ca]=Autorització
++Name[da]=Godkendelse
++Name[el]=Πιστοποίηση
++Name[es]=Autorización
++Name[et]=Autoriseerimine
++Name[fi]=Hyväksyminen
++Name[fr]=Autorisation
++Name[he]=הזדהות
++Name[is]=Auðkenning
++Name[ja]=許可
++Name[nds]=Identifikatschoon
++Name[nl]=Autorisatie
++Name[pt]=Autorização
++Name[pt_BR]=Autorização
++Name[sk]=Autorizácia
++Name[sl]=Odobritev
++Name[sv]=Behörighetskontroll
++Name[uk]=Авторизація
++Name[zh_CN]=身份验证
++Name[zh_TW]=認證
++Comment=An user has accepted/declined your authorization request
++Comment[ca]=Un usuari ha autoritzat/declinat la vostra petició d'autorització
++Comment[da]=En bruger har godkendt/afslået din godkendelsesforespørgsel
++Comment[el]=Ένας χρήστης έχει πιστοποιήσει/απορρίψει την αίτησή σας για πιστοποίηση
++Comment[es]=Un usuario ha aceptado/declinado su petición de autorización
++Comment[et]=Kasutaja autoriseeris/lükkas tagasi sinu autoriseerimissoovi
++Comment[fi]=Käyttäjä on hyväksynyt/hylännyt hyväksymispyyntösi
++Comment[fr]=Un utilisateur a accepté ou refusé votre demande d'autorisation
++Comment[he]=משתמש אישר/דחה את בקשתך לזיהוי
++Comment[is]=Notandi hefur heimilað eða hafnað beiðni þinni um auðkenningu auðkenningabeiðni þinni
++Comment[ja]=ユーザはあなたの許可要求を承諾/拒絶しました
++Comment[nds]=En Bruker hett Dien Identifikatschoonanfraag tolaten/afwiest
++Comment[nl]=Een gebruiker heeft uw autorisatieverzoek geaccepteerd/afgewezen
++Comment[pt]=Um utilizador autorizou/rejeitou o seu pedido de autorização
++Comment[pt_BR]=Um utilizador autorizou/rejeitou o seu pedido de autorização
++Comment[sk]=Užívateľ prijal/odmietol vašu požiadavku o autorizáciu
++Comment[sl]=Uporabnik je spejel/zavrnil vaš zahtevek za odobritev
++Comment[sv]=En användare har tillåtit eller nekat till din begäran om behörighetskontroll
++Comment[uk]=Користувач прийняв/відхилив ваш запит на авторизацію
++Comment[zh_CN]=用户同意/拒绝了您的身份验证请求
++Comment[zh_TW]=已有一名使用者接受/拒絕了您的認證要求
++default_presentation=16
+ 
+-
+ [yahoo_mail]
+ Name=Yahoo Mail
+ Name[be]=Пошта Yahoo
+@@ -818,6 +861,50 @@
+ Comment[zh_TW]=新郵件送達您的 Yahoo 收件匣
+ default_presentation=16
+ 
++[msn_alert]
++Name=MSN Alert
++Name[ca]=Alerta del MSN
++Name[da]=MSN-alarm
++Name[el]=Ειδοποίηση του MSN
++Name[es]=Alerta MSN
++Name[et]=MSN teade
++Name[fi]=MSN-varoitus
++Name[fr]=Alerte MSN
++Name[he]=אזהרה של MSN
++Name[is]=MSN skeyti
++Name[nds]=MSN-Alarm
++Name[nl]=MSN-melding
++Name[pt]=Alerta MSN
++Name[pt_BR]=Alerta MSN
++Name[sk]=MSN Upozornenie
++Name[sl]=Alarm MSN
++Name[sv]=MSN-larm
++Name[uk]=Сигнал MSN
++Name[zh_CN]=MSN 提醒
++Name[zh_TW]=MSN 警告
++Comment=A new alert has been sent to you
++Comment[ca]=Se us ha enviat una nova alerta
++Comment[da]=En ny alarm er sendt til dig
++Comment[el]=Σας στάλθηκε μια νέα ειδοποίηση
++Comment[es]=Se le ha enviado una nueva alerta
++Comment[et]=Sulle saadeti uus teade
++Comment[fi]=Sinulle on lähetetty uusi varoitus
++Comment[fr]=Une nouvelle alerte vous a été envoyée
++Comment[he]=אזהרה חדשה נשלחה אליך
++Comment[is]=Þér hefur verið sent nýtt skeyti
++Comment[ja]=新しいアラートを受信しました
++Comment[nds]=Een hett Di en niegen Alarm sendt
++Comment[nl]=U hebt een nieuwe melding ontvangen
++Comment[pt]=Foi enviada um novo alerta
++Comment[pt_BR]=Foi enviada um novo alerta
++Comment[sk]=Bolo vám poslané nové upozornenie
++Comment[sl]=Poslan vam je bil alarm
++Comment[sv]=Ett nytt larm har skickats till dig
++Comment[uk]=Вам було відіслано новий сигнал
++Comment[zh_CN]=您收到了新提醒
++Comment[zh_TW]=一個新的警告已送達給您
++default_presentation=16
++
+ [msn_mail]
+ Name=MSN Mail
+ Name[ar]=بريد MSN
+@@ -878,7 +965,7 @@
+ 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]=Nýr póstur kominn í MSN innhólfið
++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[km]=អ៊ីមែល​ថ្មី​បាន​មក​ដល់​ក្នុង​ប្រអប់​ទទួល MSN របស់​អ្នក​​ហើយ
+@@ -1094,9 +1181,11 @@
+ Name[es]=Error en la conexión
+ Name[et]=Ãœhenduse viga
+ Name[eu]=Konexio-errorea
++Name[fi]=Yhteysvirhe
+ Name[fr]=Erreur de connexion
+ Name[ga]=Earráid Naisc
+ Name[gl]=Erro de Conexión
++Name[he]=שגיאה בחיבור
+ Name[hu]=Csatlakozási hiba
+ Name[is]=Villa í tengingu
+ Name[it]=Errore di connessione
+@@ -1134,8 +1223,10 @@
+ Comment[es]=Ocurrio un error en la conexión
+ Comment[et]=Ãœhendusega tekkis viga
+ Comment[eu]=Errore bat gertatu da konexioan
++Comment[fi]=Yhteydessä tapahtui virhe
+ Comment[fr]=Une erreur de connexion est apparue
+ Comment[gl]=Ocorreu un erro na conexión
++Comment[he]=התרחשה שגיאה בחיבור
+ Comment[hu]=Hiba történt csatlakozás közben
+ Comment[is]=Villa kom upp þegar reynt var að tengjast
+ Comment[it]=Si è verificato un errore di connessione
+@@ -1178,9 +1269,11 @@
+ Name[es]=Conexión perdida
+ Name[et]=Ãœhendus kadus
+ Name[eu]=Konexioa galdu da
++Name[fi]=Yhteys hävisi
+ Name[fr]=Connexion perdue
+ Name[ga]=Cailleadh an Nasc
+ Name[gl]=Conexión Perdida
++Name[he]=חיבור נסגר
+ Name[hu]=A kapcsolat megszakadt
+ Name[is]=Tengingu tapað
+ Name[it]=Connessione chiusa
+@@ -1217,8 +1310,10 @@
+ Comment[es]=Se perdió la conexión
+ Comment[et]=Ãœhendus kadus
+ Comment[eu]=Konexioa galdu da
++Comment[fi]=Yhteys on hävinnyt
+ Comment[fr]=La connexion a été perdue
+ Comment[ga]=Cailleadh an nasc
++Comment[he]=החיבור נסגר
+ Comment[hu]=A kapcsolat megszakadt
+ Comment[is]=Tengingin tapaðist
+ Comment[it]=La connessione è stata chiusa
+@@ -1258,9 +1353,11 @@
+ Name[es]=No se pudo conectar
+ Name[et]=Ühendumine ebaõnnestus
+ Name[eu]=Ezin da konektatu
++Name[fi]=Ei voitu yhdistää
+ Name[fr]=Impossible de se connecter
+ Name[ga]=Ní Féidir Nasc a Dhéanamh
+ Name[gl]=Non se pode conectar
++Name[he]=אין אפשרות להתחבר
+ Name[hu]=Nem sikerült csatlakozni
+ Name[is]=Get ekki tengst
+ Name[it]=Impossibile connettersi
+@@ -1298,8 +1395,10 @@
+ Comment[es]=Kopete no se puede conectar al servicio
+ Comment[et]=Kopetel ebaõnnestus ühendumine teenusega
+ Comment[eu]=Kopete-k ezin du zerbitzuarekin konektatu
++Comment[fi]=Kopete ei voi yhdistää palveluun
+ Comment[fr]=Kopete ne peut pas se connecter à ce service
+ Comment[gl]=Kopete non pode conectar co servicio
++Comment[he]=Kopete לא יכול להתחבר לשירות
+ Comment[hu]=A Kopete nem tudott csatlakozni a szolgáltatóhoz
+ Comment[is]=Kopete gat ekki tengst þjónustunni
+ Comment[it]=Kopete non è in grado di connettersi al servizio
+@@ -1307,7 +1406,7 @@
+ Comment[km]=Kopete មិន​អាច​ត​ភ្ជាប់​ទៅ​សេវា​បាន​ឡើយ
+ Comment[lt]=Kopete nepavyko prisijungti prie tarnybos
+ Comment[nb]=Kopete kan ikke koble til tjenesten
+-Comment[nds]=Kopete kann sik nich na de Deenst tokoppeln
++Comment[nds]=Kopete kann sik nich na den Deenst tokoppeln
+ Comment[nl]=Kopete kan geen verbinding met de dienst maken
+ Comment[nn]=Kopete klarar ikkje kopla til tenesta
+ Comment[pl]=Kopete nie może się połączyć z usługą
+@@ -1340,9 +1439,11 @@
+ Name[es]=Problemas de red
+ Name[et]=Võrguprobleemid
+ Name[eu]=Sare-arazoak
++Name[fi]=Verkko-ongelma
+ Name[fr]=Problèmes réseaux
+ Name[ga]=Fadhbanna Líonra
+ Name[gl]=Problemas na rede
++Name[he]=בעיות רשת
+ Name[hu]=Hálózati hibák
+ Name[is]=Netvandamál
+ Name[it]=Problemi di rete
+@@ -1380,8 +1481,10 @@
+ Comment[es]=La red sufre problemas
+ Comment[et]=Võrguga on mingeid probleeme
+ Comment[eu]=Sareak arazoak ditu
++Comment[fi]=Verkossa on ongelmia
+ Comment[fr]=Le réseau rencontre des problèmes
+ Comment[gl]=A rede está experimentando problemas
++Comment[he]=הרשת חווה בעיות
+ Comment[hu]=Hiba lépett fel a hálózaton
+ Comment[is]=Það er vandamál með netið
+ Comment[it]=Ci sono dei problemi di rete
+@@ -1420,6 +1523,7 @@
+ Name[es]=Error interno del servidor
+ Name[et]=Serveri sisemine viga
+ Name[eu]=Zerbitzariaren barne-errorea
++Name[fi]=Palvelimen sisäinen virhe
+ Name[fr]=Erreur interne du serveur
+ Name[gl]=Erro Interno do Servidor
+ Name[hu]=Belső kiszolgálóhiba
+@@ -1457,6 +1561,7 @@
+ Comment[es]=Ocurrió un error interno en el servicio
+ Comment[et]=Tekkis teenuse sisemine viga
+ Comment[eu]=Zerbitzuaren barne-errore bat gertatu da
++Comment[fi]=Tapahtui palvelun sisäinen virhe
+ Comment[fr]=Une erreur interne au service s'est produite
+ Comment[hu]=Belső hiba történt a szolgáltatásban
+ Comment[is]=Innri villa í þjónustu hefur átt sér stað
+--- kopete/kopete/kopetewindow.cpp	(revision 568672)
++++ kopete/kopete/kopetewindow.cpp	(revision 586398)
+@@ -5,6 +5,7 @@
+     Copyright (c) 2001-2002 by Stefan Gehn            <metz AT gehn.net>
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+     Copyright (c) 2002-2005 by Olivier Goffart        <ogoffart at kde.org>
++    Copyright (c) 2005-2006 by Will Stephenson        <wstephenson at kde.org>
+ 
+     Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -23,8 +24,11 @@
+ #include <qcursor.h>
+ #include <qlayout.h>
+ #include <qhbox.h>
++#include <qvbox.h>
+ #include <qtooltip.h>
+ #include <qtimer.h>
++#include <qevent.h>
++#include <qsignalmapper.h>
+ 
+ #include <kaction.h>
+ #include <kactionclasses.h>
+@@ -44,9 +48,15 @@
+ #include <kwin.h>
+ #include <kdeversion.h>
+ #include <kinputdialog.h>
++#include <kplugininfo.h>
++#include <ksqueezedtextlabel.h>
++#include <kstringhandler.h>
+ #include <kurl.h>
+ 
++#include "addcontactpage.h"
+ #include "addcontactwizard.h"
++#include "addressbooklinkwidget.h"
++#include "groupkabcselectorwidget.h"
+ #include "kabcexport.h"
+ #include "kopeteapplication.h"
+ #include "kopeteaccount.h"
+@@ -56,6 +66,8 @@
+ #include "kopetecontact.h"
+ #include "kopetecontactlist.h"
+ #include "kopetecontactlistview.h"
++#include "kopetegroup.h"
++#include <kdialogbase.h>
+ #include "kopetelistviewsearchline.h"
+ #include "kopetechatsessionmanager.h"
+ #include "kopetepluginconfig.h"
+@@ -69,6 +81,21 @@
+ #include "kopeteonlinestatusmanager.h"
+ #include "kopeteeditglobalidentitywidget.h"
+ 
++//BEGIN GlobalStatusMessageIconLabel
++GlobalStatusMessageIconLabel::GlobalStatusMessageIconLabel(QWidget *parent, const char *name)
++ : QLabel(parent, name)
++{}
++
++void GlobalStatusMessageIconLabel::mouseReleaseEvent( QMouseEvent *event )
++{
++      if( event->button() == Qt::LeftButton || event->button() == Qt::RightButton )
++      {
++              emit iconClicked( event->globalPos() );
++              event->accept();
++      }
++}
++//END GlobalStatusMessageIconLabel
++
+ /* KMainWindow is very broken from our point of view - it deref()'s the app
+  * when the last visible KMainWindow is destroyed. But when our main window is
+  * hidden when it's in the tray,closing the last chatwindow would cause the app
+@@ -92,7 +119,7 @@
+  * queryClose() is honoured so group chats and chats receiving recent messages can interrupt
+  * (session) quit.
+  */
+-
++ 
+ KopeteWindow::KopeteWindow( QWidget *parent, const char *name )
+ : KMainWindow( parent, name, WType_TopLevel )
+ {
+@@ -101,11 +128,24 @@
+ 	// a MacOS-style MenuBar.
+ 	// This fixes a "statusbar drawn over the top of the toolbar" bug
+ 	// e.g. it can happen when you switch desktops on Kopete startup
++
+ 	m_statusBarWidget = new QHBox(statusBar(), "m_statusBarWidget");
+ 	m_statusBarWidget->setMargin( 2 );
+ 	m_statusBarWidget->setSpacing( 1 );
+-	statusBar()->addWidget(m_statusBarWidget, 0, true);
++	statusBar()->addWidget(m_statusBarWidget, 0, true );
++	QHBox *statusBarMessage = new QHBox(statusBar(), "m_statusBarWidget");
++	m_statusBarWidget->setMargin( 2 );
++	m_statusBarWidget->setSpacing( 1 );
+ 
++	GlobalStatusMessageIconLabel *label = new GlobalStatusMessageIconLabel( statusBarMessage, "statusmsglabel" );
++	label->setFixedSize( 16, 16 );
++	label->setPixmap( SmallIcon( "kopetestatusmessage" ) );
++	connect(label, SIGNAL(iconClicked( const QPoint& )),
++		this, SLOT(slotGlobalStatusMessageIconClicked( const QPoint& )));
++	QToolTip::add( label, i18n( "Global status message" ) );
++	m_globalStatusMessage = new KSqueezedTextLabel( statusBarMessage );
++	statusBar()->addWidget(statusBarMessage, 1, false );
++
+ 	m_pluginConfig = 0L;
+ 	m_autoHideTimer = new QTimer( this );
+ 
+@@ -164,9 +204,14 @@
+ 
+ void KopeteWindow::initActions()
+ {
+-	actionAddContact = new KAction( i18n( "&Add Contact..." ), "bookmark_add",
+-		0, this, SLOT( showAddContactDialog() ),
++	// this action menu contains one action per account and is updated when accounts are registered/unregistered
++	actionAddContact = new KActionMenu( i18n( "&Add Contact" ), "add_user",
+ 		actionCollection(), "AddContact" );
++	actionAddContact->setDelayed( false );
++	// this signal mapper is needed to call slotAddContact with the correct arguments
++	addContactMapper = new QSignalMapper( this );
++	connect( addContactMapper, SIGNAL( mapped( const QString & ) ),
++		 this, SLOT( slotAddContactDialogInternal( const QString & ) ) );
+ 
+ 	/* ConnectAll is now obsolete.  "Go online" has replaced it.
+ 	actionConnect = new KAction( i18n( "&Connect Accounts" ), "connect_creating",
+@@ -175,7 +220,7 @@
+ 	*/
+ 
+ 	actionDisconnect = new KAction( i18n( "O&ffline" ), "connect_no",
+-		0, Kopete::AccountManager::self(), SLOT( disconnectAll() ),
++		0, this, SLOT( slotDisconnectAll() ),
+ 		actionCollection(), "DisconnectAll" );
+ 
+ 	actionExportContacts = new KAction( i18n( "&Export Contacts..." ), "", 0, this,
+@@ -192,12 +237,12 @@
+ 	*/
+ 	actionDisconnect->setEnabled(false);
+ 
+-	selectAway = new Kopete::AwayAction( i18n("&Away"), SmallIcon("kopeteaway"), 0,
+-		this, SLOT( slotGlobalAwayMessageSelect( const QString & ) ), actionCollection(),
++	selectAway = new KAction( i18n("&Away"), SmallIcon("kopeteaway"), 0,
++		this, SLOT( slotGlobalAway() ), actionCollection(),
+ 		"SetAwayAll" );
+ 
+-	selectBusy = new Kopete::AwayAction( i18n("&Busy"), SmallIcon("kopeteaway"), 0,
+-					 this, SLOT( slotGlobalBusyMessageSelect( const QString & ) ), actionCollection(),
++	selectBusy = new KAction( i18n("&Busy"), SmallIcon("kopeteaway"), 0,
++					 this, SLOT( slotGlobalBusy() ), actionCollection(),
+ 					 "SetBusyAll" );
+ 
+ 
+@@ -212,12 +257,12 @@
+ 		SLOT( setAvailableAll() ), actionCollection(),
+ 		"SetAvailableAll" );*/
+ 
+-	actionSetAvailable = new Kopete::AwayAction( i18n("&Online"),
++	actionSetAvailable = new KAction( i18n("&Online"),
+ 		SmallIcon("kopeteavailable"), 0, this,
+-		SLOT( slotGlobalAvailableMessageSelect( const QString & ) ), actionCollection(),
++		SLOT( slotGlobalAvailable() ), actionCollection(),
+ 		"SetAvailableAll" );
+ 
+-	actionAwayMenu = new KActionMenu( i18n("&Set Status"), "kopeteaway",
++	actionAwayMenu = new KActionMenu( i18n("&Set Status"), "kopeteavailable",
+ 							actionCollection(), "Status" );
+ 	actionAwayMenu->setDelayed( false );
+ 	actionAwayMenu->insert(actionSetAvailable);
+@@ -243,9 +288,9 @@
+ 	KStdAction::configureToolbars( this, SLOT(slotConfToolbar()), actionCollection() );
+ 	KStdAction::configureNotifications(this, SLOT(slotConfNotifications()), actionCollection(), "settings_notifications" );
+ 
+-	actionShowOffliners = new KToggleAction( i18n( "Show Offline &Users" ), "viewmag", CTRL + Key_U,
++	actionShowOffliners = new KToggleAction( i18n( "Show Offline &Users" ), "show_offliners", CTRL + Key_U,
+ 			this, SLOT( slotToggleShowOffliners() ), actionCollection(), "settings_show_offliners" );
+-	actionShowEmptyGroups = new KToggleAction( i18n( "Show Empty &Groups" ), "folder_green", CTRL + Key_G,
++	actionShowEmptyGroups = new KToggleAction( i18n( "Show Empty &Groups" ), "folder", CTRL + Key_G,
+ 			this, SLOT( slotToggleShowEmptyGroups() ), actionCollection(), "settings_show_empty_groups" );
+ 
+ 	actionShowOffliners->setCheckedState(i18n("Hide Offline &Users"));
+@@ -267,9 +312,15 @@
+ 
+ 	// Edit global identity widget/bar
+ 	editGlobalIdentityWidget = new KopeteEditGlobalIdentityWidget(this, "editglobalBar");
++	editGlobalIdentityWidget->hide();
+ 	KWidgetAction *editGlobalAction = new KWidgetAction( editGlobalIdentityWidget, i18n("Edit Global Identity Widget"), 0, 0, 0, actionCollection(), "editglobal_widget");
+ 	editGlobalAction->setAutoSized( true );
+ 
++	// KActionMenu for selecting the global status message(kopeteonlinestatus_0)
++	KActionMenu * setStatusMenu = new KActionMenu( i18n( "Set Status Message" ), "kopeteeditstatusmessage", actionCollection(), "SetStatusMessage" );
++	setStatusMenu->setDelayed( false );
++	connect( setStatusMenu->popupMenu(), SIGNAL( aboutToShow() ), SLOT(slotBuildStatusMessageMenu() ) );
++	connect( setStatusMenu->popupMenu(), SIGNAL( activated( int ) ), SLOT(slotStatusMessageSelected( int ) ) );
+ 
+ 	// sync actions, config and prefs-dialog
+ 	connect ( KopetePrefs::prefs(), SIGNAL(saved()), this, SLOT(slotConfigChanged()) );
+@@ -321,7 +372,7 @@
+ 	else
+ 	{
+ 		QString awayReason = mAway->getMessage( 0 );
+-		slotGlobalAwayMessageSelect(awayReason);
++		slotGlobalAway();
+ 	}
+ }
+ 
+@@ -537,30 +588,34 @@
+ 	applyMainWindowSettings(KGlobal::config(), "General Options");
+ }
+ 
+-void KopeteWindow::slotGlobalAwayMessageSelect( const QString &awayReason )
++void KopeteWindow::slotGlobalAway()
+ {
+-	Kopete::Away::getInstance()->setGlobalAwayMessage( awayReason );
+-	Kopete::AccountManager::self()->setAwayAll( awayReason );
++	Kopete::AccountManager::self()->setAwayAll( m_globalStatusMessageStored );
+ }
+ 
+-void KopeteWindow::slotGlobalBusyMessageSelect( const QString &awayReason )
++void KopeteWindow::slotGlobalBusy()
+ {
+-	Kopete::Away::getInstance()->setGlobalAwayMessage( awayReason );
+ 	Kopete::AccountManager::self()->setOnlineStatus(
+-			Kopete::OnlineStatusManager::Busy , awayReason );
++			Kopete::OnlineStatusManager::Busy, m_globalStatusMessageStored );
+ }
+ 
+-void KopeteWindow::slotGlobalAvailableMessageSelect( const QString &awayReason )
++void KopeteWindow::slotGlobalAvailable()
+ {
+-	Kopete::Away::getInstance()->setGlobalAwayMessage( awayReason );
+-	Kopete::AccountManager::self()->setAvailableAll( awayReason );
++	Kopete::AccountManager::self()->setAvailableAll( m_globalStatusMessageStored );
+ }
+ 
+-void KopeteWindow::slotSetInvisibleAll(  )
++void KopeteWindow::slotSetInvisibleAll()
+ {
+ 	Kopete::AccountManager::self()->setOnlineStatus( Kopete::OnlineStatusManager::Invisible  );
+ }
+ 
++void KopeteWindow::slotDisconnectAll()
++{
++	m_globalStatusMessage->setText( "" );
++	m_globalStatusMessageStored = QString();
++	Kopete::AccountManager::self()->disconnectAll();
++}
++
+ bool KopeteWindow::queryClose()
+ {
+ 	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
+@@ -669,6 +724,13 @@
+ 
+ 	m_accountStatusBarIcons.insert( account, sbIcon );
+ 	slotAccountStatusIconChanged( account->myself() );
++	
++	// add an item for this account to the add contact actionmenu
++	QString s = "actionAdd%1Contact";
++	s.arg( account->accountId() );
++	KAction *action = new KAction( account->accountLabel(), account->accountIcon(), 0 , addContactMapper, SLOT( map() ), account, s.latin1() );
++	addContactMapper->setMapping( action, account->protocol()->pluginId() + QChar(0xE000) + account->accountId() );
++	actionAddContact->insert( action );
+ }
+ 
+ void KopeteWindow::slotAccountUnregistered( const Kopete::Account *account)
+@@ -691,6 +753,19 @@
+ 	delete sbIcon;
+ 
+ 	makeTrayToolTip();
++	
++	// update add contact actionmenu
++	QString s = "actionAdd%1Contact";
++	s.arg( account->accountId() );
++// 	KAction * action = actionCollection()->action( account->accountId() );
++	Kopete::Account * myAccount = const_cast< Kopete::Account * > ( account );
++	KAction * action = static_cast< KAction *>( myAccount->child( s.latin1() ) );
++	if ( action )
++	{
++		kdDebug(14000) << " found KAction " << action << " with name: " << action->name() << endl;
++		addContactMapper->removeMappings( action );
++		actionAddContact->remove( action );
++	}
+ }
+ 
+ void KopeteWindow::slotAccountStatusIconChanged()
+@@ -701,10 +776,46 @@
+ 
+ void KopeteWindow::slotAccountStatusIconChanged( Kopete::Contact *contact )
+ {
++	kdDebug( 14000 ) << k_funcinfo << contact->property( Kopete::Global::Properties::self()->awayMessage() ).value() << endl;
++	// update the global status label if the change doesn't 
++//	QString newAwayMessage = contact->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
+ 	Kopete::OnlineStatus status = contact->onlineStatus();
++/*	if ( status.status() != Kopete::OnlineStatus::Connecting )
++	{
++		QString globalMessage = m_globalStatusMessage->text();
++		if ( newAwayMessage != globalMessage )
++			m_globalStatusMessage->setText( "" /* i18n("status message to show when different accounts have different status messages", "(multiple)" )*/ /*);
++	}*/
+ //	kdDebug(14000) << k_funcinfo << "Icons: '" <<
+ //		status.overlayIcons() << "'" << endl;
+ 
++	if ( status != Kopete::OnlineStatus::Connecting )
++	{
++		if(contact->hasProperty(Kopete::Global::Properties::self()->awayMessage().key()))
++		{
++			m_globalStatusMessageStored = contact->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
++			m_globalStatusMessage->setText( m_globalStatusMessageStored );
++		}
++		else //If the account has not status message, it may be because the protocol doesn't support it (Bug 132609)
++		{    // or because the user just set an empty status to this account.
++			// We will check if another account has still a status message, if yes, we will use it, if not, we will clear it.
++			QString statusMessageToUse;
++			QPtrList<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts();
++			for(Kopete::Account *a = accounts.first(); a; a = accounts.next())
++			{
++				Kopete::Contact *self = a->myself();
++				if(self->hasProperty(Kopete::Global::Properties::self()->awayMessage().key()))
++				{
++					statusMessageToUse = self->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
++					if(statusMessageToUse == m_globalStatusMessageStored )
++						break; //keep this one
++				}
++			}
++			m_globalStatusMessageStored = statusMessageToUse;
++			m_globalStatusMessage->setText( m_globalStatusMessageStored );
++		}
++	}
++	
+ 	KopeteAccountStatusBarIcon *i = static_cast<KopeteAccountStatusBarIcon *>( m_accountStatusBarIcons[ contact->account() ] );
+ 	if( !i )
+ 		return;
+@@ -803,11 +914,6 @@
+ 	}
+ }*/
+ 
+-void KopeteWindow::showAddContactDialog()
+-{
+-	(new AddContactWizard(this))->show();
+-}
+-
+ void KopeteWindow::showExportDialog()
+ {
+ 	( new KabcExportWizard( this, "export_contact_dialog" ) )->show();
+@@ -840,5 +946,167 @@
+ 		m_autoHideTimer->start( m_autoHideTimeout * 1000 );
+ }
+ 
++// Iterate each connected account, updating its status message bug keeping the 
++// same onlinestatus.  Then update Kopete::Away and the UI.
++void KopeteWindow::setStatusMessage( const QString & message )
++{
++	bool changed = false;
++	for ( QPtrListIterator<Kopete::Account> it( Kopete::AccountManager::self()->accounts() ); it.current(); ++it )
++	{
++		Kopete::Contact *self = it.current()->myself();
++		bool isInvisible = self && self->onlineStatus().status() == Kopete::OnlineStatus::Invisible;
++		if ( it.current()->isConnected() && !isInvisible )
++		{
++			changed = true;
++			it.current()->setOnlineStatus( self->onlineStatus(), message );
++		}
++	}
++	Kopete::Away::getInstance()->setGlobalAwayMessage( message );
++	m_globalStatusMessageStored = message;
++	m_globalStatusMessage->setText( message );
++}
++
++void KopeteWindow::slotBuildStatusMessageMenu()
++{
++	QObject * senderObj = const_cast<QObject *>( sender() );
++	m_globalStatusMessageMenu = static_cast<KPopupMenu *>( senderObj );
++	m_globalStatusMessageMenu->clear();
++// pop up a menu containing the away messages, and a lineedit
++// see kopeteaway
++	//messageMenu = new KPopupMenu( this );
++//	messageMenu->insertTitle( i18n( "Status Message" ) );
++	QHBox * newMessageBox = new QHBox( 0 );
++	newMessageBox->setMargin( 1 );
++	QLabel * newMessagePix = new QLabel( newMessageBox );
++	newMessagePix->setPixmap( SmallIcon( "edit" ) );
++/*	QLabel * newMessageLabel = new QLabel( i18n( "Add " ), newMessageBox );*/
++	m_newMessageEdit = new QLineEdit( newMessageBox, "newmessage" );
++	
++	newMessageBox->setFocusProxy( m_newMessageEdit );
++	newMessageBox->setFocusPolicy( QWidget::ClickFocus );
++/*	newMessageLabel->setFocusProxy( newMessageEdit );
++	newMessageLabel->setBuddy( newMessageEdit );
++	newMessageLabel->setFocusPolicy( QWidget::ClickFocus );*/
++	newMessagePix->setFocusProxy( m_newMessageEdit );
++	newMessagePix->setFocusPolicy( QWidget::ClickFocus );
++	connect( m_newMessageEdit, SIGNAL( returnPressed() ), SLOT( slotNewStatusMessageEntered() ) );
++
++	m_globalStatusMessageMenu->insertItem( newMessageBox );
++
++	int i = 0;
++	
++	m_globalStatusMessageMenu->insertItem( SmallIcon( "remove" ), i18n( "No Message" ), i++ );
++	m_globalStatusMessageMenu->insertSeparator();
++	
++	QStringList awayMessages = Kopete::Away::getInstance()->getMessages();
++	for( QStringList::iterator it = awayMessages.begin(); it != awayMessages.end(); ++it, ++i )
++	{
++		m_globalStatusMessageMenu->insertItem( KStringHandler::rsqueeze( *it ), i );
++	}
++//	connect( m_globalStatusMessageMenu, SIGNAL( activated( int ) ), SLOT( slotStatusMessageSelected( int ) ) );
++//	connect( messageMenu, SIGNAL( aboutToHide() ), messageMenu, SLOT( deleteLater() ) );
++
++	m_newMessageEdit->setFocus();
++
++	//messageMenu->popup( e->globalPos(), 1 );
++}
++
++void KopeteWindow::slotStatusMessageSelected( int i )
++{
++	Kopete::Away *away = Kopete::Away::getInstance();
++	if ( 0 == i )
++		setStatusMessage( "" );
++	else
++		setStatusMessage( away->getMessage( i - 1 ) );
++}
++
++void KopeteWindow::slotNewStatusMessageEntered()
++{
++	m_globalStatusMessageMenu->close();
++	QString newMessage = m_newMessageEdit->text();
++	if ( !newMessage.isEmpty() )
++		Kopete::Away::getInstance()->addMessage( newMessage );
++	setStatusMessage( m_newMessageEdit->text() );
++}
++
++void KopeteWindow::slotGlobalStatusMessageIconClicked( const QPoint &position )
++{
++	KPopupMenu *statusMessageIconMenu = new KPopupMenu(this, "statusMessageIconMenu");
++	connect(statusMessageIconMenu, SIGNAL( aboutToShow() ),
++		this, SLOT(slotBuildStatusMessageMenu()));
++	connect( statusMessageIconMenu, SIGNAL( activated( int ) ),
++				SLOT( slotStatusMessageSelected( int ) ) );
++
++	statusMessageIconMenu->popup(position);
++}
++
++void KopeteWindow::slotAddContactDialogInternal( const QString & accountIdentifier )
++{
++	QString protocolId = accountIdentifier.section( QChar(0xE000), 0, 0 );
++	QString accountId = accountIdentifier.section( QChar(0xE000), 1, 1 );
++	Kopete::Account *account = Kopete::AccountManager::self()->findAccount( protocolId, accountId );
++ 	showAddContactDialog( account );
++}
++
++void KopeteWindow::showAddContactDialog( Kopete::Account * account )
++{
++	if ( !account ) {
++		kdDebug( 14000 ) << k_funcinfo << "no account given" << endl; 
++		return;
++	}
++
++	KDialogBase *addDialog = new KDialogBase( this, "addDialog", true,
++		i18n( "Add Contact" ), KDialogBase::Ok|KDialogBase::Cancel,
++		KDialogBase::Ok, true );
++
++	QVBox * mainWid = new QVBox( addDialog );
++	
++	AddContactPage *addContactPage =
++		account->protocol()->createAddContactWidget( mainWid, account );
++
++	GroupKABCSelectorWidget * groupKABC = new GroupKABCSelectorWidget( mainWid, "groupkabcwidget" );
++
++	// Populate the groups list
++	Kopete::GroupList groups=Kopete::ContactList::self()->groups();
++	QDict<Kopete::Group> groupItems;
++	for( Kopete::Group *it = groups.first(); it; it = groups.next() )
++	{
++		QString groupname = it->displayName();
++		if ( !groupname.isEmpty() )
++		{
++			groupItems.insert( groupname, it );
++			groupKABC->groupCombo->insertItem( groupname );
++		}
++	}
++
++	if (!addContactPage)
++	{
++		kdDebug(14000) << k_funcinfo <<
++			"Error while creating addcontactpage" << endl;
++	}
++	else
++	{
++		addDialog->setMainWidget( mainWid );
++		if( addDialog->exec() == QDialog::Accepted )
++		{
++			if( addContactPage->validateData() )
++			{
++				Kopete::MetaContact * metacontact = new Kopete::MetaContact();
++				metacontact->addToGroup( groupItems[ groupKABC->groupCombo->currentText() ] );
++				metacontact->setMetaContactId( groupKABC->widAddresseeLink->uid() );
++				if (addContactPage->apply( account, metacontact ))
++				{
++					Kopete::ContactList::self()->addMetaContact( metacontact );
++				}
++				else
++				{
++					delete metacontact;
++				}
++			}
++		}
++	}
++	addDialog->deleteLater();
++}
++
+ #include "kopetewindow.moc"
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/x-kopete-emoticons.desktop	(revision 568672)
++++ kopete/kopete/x-kopete-emoticons.desktop	(revision 586398)
+@@ -22,6 +22,7 @@
+ Comment[fi]=Kopeten hymiöarkisto
+ Comment[fr]=Archive d'émoticônes pour Kopete
+ Comment[gl]=Arquivo de Emoticonas de Kopete
++Comment[he]=ארכיון ערכת רגשות של Kopete
+ Comment[hr]=Kopete Emoticon arhiva
+ Comment[hu]=Kopete emotikon-archívum
+ Comment[is]=Tilfynningatákn fyrir Kopete
+--- kopete/kopete/config/accounts/kopeteaccountconfig.cpp	(revision 568672)
++++ kopete/kopete/config/accounts/kopeteaccountconfig.cpp	(revision 586398)
+@@ -20,6 +20,7 @@
+ 
+ #include <qcheckbox.h>
+ #include <qlayout.h>
++#include <qguardedptr.h>
+ 
+ #include <kcolorbutton.h>
+ #include <kpushbutton.h>
+@@ -45,7 +46,8 @@
+ 		Kopete::Account *account() { return m_account; }
+ 
+ 	private:
+-		Kopete::Account *m_account;
++		//need to be guarded because some accounts may be linked (that's the case of jabber transports)
++		QGuardedPtr<Kopete::Account> m_account;
+ };
+ 
+ typedef KGenericFactory<KopeteAccountConfig, QWidget> KopeteAccountConfigFactory;
+@@ -84,8 +86,10 @@
+ 	KopeteAccountLVI *i = static_cast<KopeteAccountLVI*>( m_view->mAccountList->firstChild() );
+ 	while( i )
+ 	{
+-		  i->account()->setPriority( priority-- );
+-		  i = static_cast<KopeteAccountLVI*>( i->nextSibling() );
++		if(!i->account())
++			continue;
++		i->account()->setPriority( priority-- );
++		i = static_cast<KopeteAccountLVI*>( i->nextSibling() );
+ 	}
+ 
+ 	QMap<Kopete::Account *, QColor>::Iterator it;
+@@ -126,7 +130,7 @@
+ 	m_view->mButtonEdit->setEnabled( itemSelected );
+ 	m_view->mButtonRemove->setEnabled( itemSelected );
+ 
+-	if ( itemSelected )
++	if ( itemSelected &&  itemSelected->account() )
+ 	{
+ 		m_view->mButtonUp->setEnabled( itemSelected->itemAbove() );
+ 		m_view->mButtonDown->setEnabled( itemSelected->itemBelow() );
+@@ -184,7 +188,7 @@
+ void KopeteAccountConfig::slotEditAccount()
+ {
+ 	KopeteAccountLVI *lvi = static_cast<KopeteAccountLVI*>( m_view->mAccountList->selectedItem() );
+-	if ( !lvi )
++	if ( !lvi || !lvi->account() )
+ 		return;
+ 
+ 	Kopete::Account *ident = lvi->account();
+@@ -223,7 +227,7 @@
+ void KopeteAccountConfig::slotRemoveAccount()
+ {
+ 	KopeteAccountLVI *lvi = static_cast<KopeteAccountLVI*>( m_view->mAccountList->selectedItem() );
+-	if ( !lvi )
++	if ( !lvi || !lvi->account() )
+ 		return;
+ 
+ 	Kopete::Account *i = lvi->account();
+@@ -248,7 +252,7 @@
+ 		return;      // color because another account has been selected
+ 
+ 	KopeteAccountLVI *lvi = static_cast<KopeteAccountLVI*>( m_view->mAccountList->selectedItem() );
+-	if ( !lvi )
++	if ( !lvi || !lvi->account() )
+ 		return;
+ 	Kopete::Account *account = lvi->account();
+ 
+--- kopete/kopete/config/appearance/appearanceconfig.cpp	(revision 568672)
++++ kopete/kopete/config/appearance/appearanceconfig.cpp	(revision 586398)
+@@ -2,8 +2,10 @@
+     appearanceconfig.cpp  -  Kopete Look Feel Config
+ 
+     Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan at kde.org>
+-    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel at kde.org>
++    Copyright (c) 2005-2006 by Michaël Larouche       <michael.larouche at kdemail.net>
+ 
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at kde.org>
++
+     *************************************************************************
+     *                                                                       *
+     * This program is free software; you can redistribute it and/or modify  *
+@@ -44,9 +46,8 @@
+ #include <kdebug.h>
+ #include <kfontrequester.h>
+ #include <kgenericfactory.h>
+-#include <khtmlview.h>
+-#include <khtml_part.h>
+ #include <kio/netaccess.h>
++#include <khtmlview.h>
+ #include <klineedit.h>
+ #include <klocale.h>
+ #include <kmessagebox.h>
+@@ -56,28 +57,29 @@
+ #include <kurl.h> // KNewStuff
+ #include <kurlrequesterdlg.h>
+ #include <krun.h>
+-#include <ktar.h> // for extracting tarballed chatwindow styles fetched with KNewStuff
+-#include <kdirwatch.h>
++#include <kfiledialog.h>
+ 
+ #include <knewstuff/downloaddialog.h> // knewstuff emoticon and chatwindow fetching
+ #include <knewstuff/engine.h>         // "
+ #include <knewstuff/entry.h>          // "
+ #include <knewstuff/knewstuff.h>      // "
+ #include <knewstuff/provider.h>       // "
+-#include <kfilterdev.h>               // knewstuff gzipped file support
+ 
+-#include <ktexteditor/highlightinginterface.h>
+-#include <ktexteditor/editinterface.h>
+-#include <ktexteditor/document.h>
+-#include <ktexteditor/view.h>
++// For Kopete Chat Window Style configuration and preview.
++#include <kopetechatwindowstylemanager.h>
++#include <kopetechatwindowstyle.h>
++#include <chatmessagepart.h>
+ 
+ // Things we fake to get the message preview to work
+-#include "kopetemetacontact.h"
+-#include "kopetecontact.h"
+-#include "kopetemessage.h"
++#include <kopeteprotocol.h>
++#include <kopetemetacontact.h>
++#include <kopeteaccount.h>
++#include <kopetecontact.h>
++#include <kopetemessage.h>
++#include <kopetechatsession.h>
++#include <kopetechatsessionmanager.h>
+ 
+ #include "kopeteprefs.h"
+-#include "kopetexsl.h"
+ #include "kopeteemoticons.h"
+ #include "kopeteglobal.h"
+ 
+@@ -86,383 +88,241 @@
+ typedef KGenericFactory<AppearanceConfig, QWidget> KopeteAppearanceConfigFactory;
+ K_EXPORT_COMPONENT_FACTORY( kcm_kopete_appearanceconfig, KopeteAppearanceConfigFactory( "kcm_kopete_appearanceconfig" ) )
+ 
+-class KopeteAppearanceConfigPrivate
++class FakeProtocol;
++class FakeAccount;
++class FakeContact;
++
++class AppearanceConfig::Private
+ {
+ public:
+-	Kopete::XSLT *xsltParser;
++	Private()
++	 : mAppearanceTabCtl(0L), preview(0L), mPrfsEmoticons(0L),mPrfsChatWindow(0L),
++	   mPrfsColors(0L), mPrfsContactList(0L), currentStyle(0L), loading(false),
++	   styleChanged(false)
++	{}
++
++	QTabWidget *mAppearanceTabCtl;
++
++	ChatMessagePart *preview;
++	AppearanceConfig_Emoticons *mPrfsEmoticons;
++	AppearanceConfig_ChatWindow *mPrfsChatWindow;
++	AppearanceConfig_Colors *mPrfsColors;
++	AppearanceConfig_ContactList *mPrfsContactList;
++
++	// value is the style path
++	QMap<QListBoxItem*,QString> styleItemMap;
++	ChatWindowStyle::StyleVariants currentVariantMap;
++	ChatWindowStyle *currentStyle;
++	bool loading;
++	bool styleChanged;
++
++	// For style preview
++	FakeProtocol *previewProtocol;
++	FakeAccount *previewAccount;
++	Kopete::MetaContact *myselfMetaContact;
++	Kopete::MetaContact *jackMetaContact;
++	FakeContact *myself;
++	FakeContact *jack;
++	Kopete::ChatSession *previewChatSession;
+ };
+ 
+ class KopeteStyleNewStuff : public KNewStuff
+ {
+-	public:
+-	KopeteStyleNewStuff(const QString &type, AppearanceConfig * ac, QWidget *parentWidget=0) 
+-         : KNewStuff( type, parentWidget ), mAppearanceConfig( ac ), m_integrity( false )
+-	{ }
++public:
++	KopeteStyleNewStuff(const QString &type, QWidget *parentWidget = 0)
++	 : KNewStuff( type, parentWidget)
++	{}
+ 
+-	bool createUploadFile(const QString&)
+-	{ return false; }
++	bool createUploadFile(const QString &)
++	{
++		return false;
++	}
+ 
+-	bool install( const QString & fileName)
++	bool install(const QString &styleFilename)
+ 	{
+-		QString origFileName = mFilenameMap[ fileName ];
+-		if ( origFileName.endsWith( ".xsl" ) )
++		int styleInstallReturn = 0;
++		styleInstallReturn = ChatWindowStyleManager::self()->installStyle( styleFilename );
++
++		switch(styleInstallReturn)
+ 		{
+-			// copy to apps/kopete/styles
+-			kdDebug(14000) << k_funcinfo << " installing simple style file: " << origFileName << endl;
+-			/*
+-			if( !m_integrity )
++			case ChatWindowStyleManager::StyleInstallOk:
+ 			{
+-				KMessageBox::queuedMessageBox( parentWidget(), KMessageBox::Error,
+-					i18n( "Package could not be verified. Please contact to author of the package. [Error: 7]" ),
+-					i18n( "Package Verification Failed" ) );
+-				return false;
++				KMessageBox::queuedMessageBox( this->parentWidget(), KMessageBox::Information, i18n("The Chat Window style was successfully installed."), i18n("Install successful") );
++				return true;
+ 			}
+-			*/
+-			QString styleSheet = mAppearanceConfig->fileContents(fileName);
+-			if ( Kopete::XSLT( styleSheet ).isValid() )
+-				mAppearanceConfig->addStyle( origFileName.section( '.', 0, 0 ), styleSheet );
+-			QFile::remove( fileName );
+-			mAppearanceConfig->loadStyles();
+-			return true;
+-		}
+-		else if ( origFileName.endsWith( ".tar.gz" ) )
+-		{
+-			/* If KNewStuff is forced to be enabled from config file, then no verification is necessary.
+-			int r;
+-			if( ( r = verify( fileName ) ) != 0 )
++			case ChatWindowStyleManager::StyleCannotOpen:
+ 			{
+-				KMessageBox::queuedMessageBox( parentWidget(), KMessageBox::Error,
+-					i18n( "Package could not be verified. Please contact to author of the package. [Error: %1]" ).arg( r ),
+-					i18n( "Package Verification Failed" ) );
+-				return false;
++				KMessageBox::queuedMessageBox( this->parentWidget(), KMessageBox::Error, i18n("The specified archive cannot be opened.\nMake sure that the archive is valid ZIP or TAR archive."), i18n("Cannot open archive") );
++				break;
+ 			}
+-			*/
+-			// install a tar.gz
+-			kdDebug(14000) << k_funcinfo << " extracting gzipped tarball: " << origFileName << endl;
+-			QString uncompress = "application/x-gzip";
+-			KTar tar(fileName, uncompress);
+-			tar.open(IO_ReadOnly);
+-			const KArchiveDirectory *dir = tar.directory();
+-			dir->copyTo( locateLocal( "appdata", QString::fromLatin1( "styles" ) ) );
+-			tar.close();
+-			QFile::remove(fileName);
+-			mAppearanceConfig->loadStyles();
+-			return true;
+-		}
+-		else if ( origFileName.endsWith( ".xsl.gz" ) )
+-		{
+-			kdDebug(14000) << k_funcinfo << " installing gzipped single style file: " << origFileName << endl;
+-			/*
+-			if( !m_integrity )
++			case ChatWindowStyleManager::StyleNoDirectoryValid:
+ 			{
+-				KMessageBox::queuedMessageBox( parentWidget(), KMessageBox::Error,
+-					i18n( "Package could not be verified. Please contact to author of the package. [Error: 7]" ),
+-					i18n( "Package Verification Failed" ) );
+-				return false;
++				KMessageBox::queuedMessageBox( this->parentWidget(), KMessageBox::Error, i18n("Could not find a suitable place to install the Chat Window style in user directory."), i18n("Cannot find styles directory") );
++				break;
+ 			}
+-			*/
+-			QIODevice * iod = KFilterDev::deviceForFile( fileName, "application/x-gzip" );
+-			iod->open( IO_ReadOnly );
+-			QTextStream stream( iod );
+-			QString styleSheet = stream.read();
+-			iod->close();
+-			if ( Kopete::XSLT( styleSheet ).isValid() )
+-				mAppearanceConfig->addStyle( origFileName.section( '.', 0, 0 ), styleSheet );
+-			QFile::remove( fileName );
+-			mAppearanceConfig->loadStyles();
+-			return true;
+-
+-		}
+-		else
+-		{
+-			/* Commented out due to string freeze.
+-			KMessageBox::queuedMessageBox( parentWidget(), KMessageBox::Error,
+-				i18n( "Only allowed package extensions are .xsl, .tar.gz and .xsl.gz" ),
+-				i18n( "Extension not supported" ) );
+-			*/
+-			return false;
+-		}
+-	}
+-
+-	/**
+-	 * A package named Foo must be packaged as Foo.tar.gz use alphanumeric package
+-	 * names (i.e. do not use a . in the file name ).
+-	 * content should be like as follows:
+-	 * /Foo.xsl
+-	 * /data/Foo/file1.png
+-	 * /data/Foo/file2.png
+-	 * /data/Foo/bar/zoo/boo.png ...
+-	 *
+-	 * @param file file name to be verified
+-	 * @return 0 on success<br>
+-	 *         1 if root directory contains garbage<br>
+-	 *         2 data directory does not exists<br>
+-	 *         3 data directory contains garbage files/dirs<br>
+-	 *         4 the directory under data/ is not the same name as package<br>
+-	 *         5 Style file does not exist.<br>
+-	 *         6 data directory does not contain any files<br>
+-	 *         7 file does not even exists!
+-	 *         8 package name must be same with basename of the file
+-	 */
+-	int verify( const QString& file )
+-	{
+-		QFileInfo i( file );
+-		if( !i.exists() )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: Could not open file [" << file << "] This should never have happened." << endl;
+-			return 7; // actually it's pointless to return this, since this is a sign of internal error.
+-		}
+-
+-		if( !m_integrity )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: Package name is not the same with basename of the filename." << endl;
+-			return 8;
+-		}
+-
+-		QString base = i.baseName();
+-
+-		KTar tar( file, "application/x-gzip" );
+-		tar.open( IO_ReadOnly );
+-		const KArchiveDirectory *dir = tar.directory();
+-		QStringList list = dir->entries();
+-
+-		if( list.count() != 2 )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: Garbage file or directory in root directory of the package" << endl;
+-			return 1;
+-		}
+-
+-		const KArchiveEntry *data = dir->entry( "data" );
+-		if( !data || !data->isDirectory()  )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: data directory does not exist" << endl;
+-			return 2;
+-		}
+-		else
+-		{
+-			list = ((KArchiveDirectory*)data)->entries();
+-			if( list.count() == 0 )
++			case ChatWindowStyleManager::StyleNotValid:
+ 			{
+-				kdDebug( 14000 ) << k_funcinfo << "ERROR: There is no file in the data directory. So why use a tarball?" << endl;
+-				return 6;
++				KMessageBox::queuedMessageBox( this->parentWidget(), KMessageBox::Error, i18n("The specified archive does not contain a valid Chat Window style."), i18n("Invalid Style") );
++				break;
+ 			}
+-			else if( list.count() != 1 )
++
++			case ChatWindowStyleManager::StyleUnknow:
++			default:
+ 			{
+-				kdDebug( 14000 ) << k_funcinfo << "ERROR: data directory contains garbage entries" << endl;
+-				return 3;
++				KMessageBox::queuedMessageBox( this->parentWidget(), KMessageBox::Error, i18n("An unknow error occurred while trying to install the Chat Window style."), i18n("Unknow error") );
++				break;
+ 			}
+-			data = ((KArchiveDirectory*)data)->entry( base );
+-			if( !data || !data->isDirectory() )
+-			{
+-				kdDebug( 14000 ) << k_funcinfo << "ERROR: directory under data dir should have the same name as package" << endl;
+-				return 4;
+-			}
+ 		}
+-
+-		const KArchiveEntry *xsl = dir->entry( base + ".xsl" );
+-		if( !xsl || !xsl->isFile() )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: Style file does not exist." << endl;
+-			return 5;
+-		}
+-
+-		return 0;
+-
++		return false;
+ 	}
+-
+-	QString downloadDestination( KNS::Entry * e )
+-	{
+-		QString filename = e->payload().fileName();
+-		QFileInfo i( filename );
+-		if( e->name() != i.baseName() )
+-		{
+-			kdDebug( 14000 ) << k_funcinfo << "ERROR: Package name is not the basename of the file." << endl;
+-			m_integrity = false;
+-		}
+-		else
+-		{
+-			m_integrity = true;
+-		}
+-		QString tempDestination = KNewStuff::downloadDestination( e );
+-		mFilenameMap.insert( tempDestination, filename );
+-		return tempDestination;
+-	}
+-
+-	QMap<QString, QString > mFilenameMap;
+-	AppearanceConfig * mAppearanceConfig;
+-private:
+-	bool m_integrity;
+ };
+ 
++// TODO: Someday, this configuration dialog must(not should) use KConfigXT
+ AppearanceConfig::AppearanceConfig(QWidget *parent, const char* /*name*/, const QStringList &args )
+ : KCModule( KopeteAppearanceConfigFactory::instance(), parent, args )
+ {
+-	editedItem = 0L;
++	d = new Private;
+ 
+-	d = new KopeteAppearanceConfigPrivate;
+-
+-	d->xsltParser = new Kopete::XSLT( KopetePrefs::prefs()->styleContents(), this );
+-
+ 	(new QVBoxLayout(this))->setAutoAdd(true);
+-	mAppearanceTabCtl = new QTabWidget(this, "mAppearanceTabCtl");
++	d->mAppearanceTabCtl = new QTabWidget(this, "mAppearanceTabCtl");
+ 
+-
+ 	KConfig *config = KGlobal::config();
+ 	config->setGroup( "ChatWindowSettings" );
+ 
+ 	// "Emoticons" TAB ==========================================================
+-	mPrfsEmoticons = new AppearanceConfig_Emoticons(mAppearanceTabCtl);
+-	connect(mPrfsEmoticons->chkUseEmoticons, SIGNAL(toggled(bool)),
++	d->mPrfsEmoticons = new AppearanceConfig_Emoticons(d->mAppearanceTabCtl);
++	connect(d->mPrfsEmoticons->chkUseEmoticons, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-    connect(mPrfsEmoticons->chkUseEmoticons, SIGNAL(toggled(bool)),
+-                    this, SLOT(updateEmoticonsButton(bool)));
+-	connect(mPrfsEmoticons->chkRequireSpaces, SIGNAL(toggled(bool)),
++	connect(d->mPrfsEmoticons->chkRequireSpaces, SIGNAL(toggled(bool)),
+ 			this, SLOT(emitChanged()));
+-	connect(mPrfsEmoticons->icon_theme_list, SIGNAL(selectionChanged()),
++	connect(d->mPrfsEmoticons->icon_theme_list, SIGNAL(selectionChanged()),
+ 		this, SLOT(slotSelectedEmoticonsThemeChanged()));
+-	connect(mPrfsEmoticons->btnInstallTheme, SIGNAL(clicked()),
+-		this, SLOT(installNewTheme()));
++	connect(d->mPrfsEmoticons->btnInstallTheme, SIGNAL(clicked()),
++		this, SLOT(installEmoticonTheme()));
+ 
+-	// Since KNewStuff is incomplete and buggy we'll disable it by default.
+-    m_allowDownloadTheme = config->readBoolEntry( "ForceNewStuff", false );
+-    mPrfsEmoticons->btnGetThemes->setEnabled( m_allowDownloadTheme );	
+-	connect(mPrfsEmoticons->btnGetThemes, SIGNAL(clicked()),
+-		this, SLOT(slotGetThemes()));
+-	connect(mPrfsEmoticons->btnRemoveTheme, SIGNAL(clicked()),
+-		this, SLOT(removeSelectedTheme()));
++	connect(d->mPrfsEmoticons->btnGetThemes, SIGNAL(clicked()),
++		this, SLOT(slotGetEmoticonThemes()));
++	connect(d->mPrfsEmoticons->btnRemoveTheme, SIGNAL(clicked()),
++		this, SLOT(removeSelectedEmoticonTheme()));
+ 
+-	mAppearanceTabCtl->addTab(mPrfsEmoticons, i18n("&Emoticons"));
++	d->mAppearanceTabCtl->addTab(d->mPrfsEmoticons, i18n("&Emoticons"));
+ 
+ 	// "Chat Window" TAB ========================================================
+-	mPrfsChatWindow = new AppearanceConfig_ChatWindow(mAppearanceTabCtl);
+-	connect(mPrfsChatWindow->mTransparencyEnabled, SIGNAL(toggled(bool)),
+-		this, SLOT(slotTransparencyChanged(bool)));
+-	connect(mPrfsChatWindow->styleList, SIGNAL(selectionChanged(QListBoxItem *)),
+-		this, SLOT(slotStyleSelected()));
+-	connect(mPrfsChatWindow->addButton, SIGNAL(clicked()),
+-		this, SLOT(slotAddStyle()));
+-	connect(mPrfsChatWindow->editButton, SIGNAL(clicked()),
+-		this, SLOT(slotEditStyle()));
+-	connect(mPrfsChatWindow->deleteButton, SIGNAL(clicked()),
+-		this, SLOT(slotDeleteStyle()));
+-	connect(mPrfsChatWindow->importButton, SIGNAL(clicked()),
+-		this, SLOT(slotImportStyle()));
+-	connect(mPrfsChatWindow->copyButton, SIGNAL(clicked()),
+-		this, SLOT(slotCopyStyle()));
+-	connect(mPrfsChatWindow->btnGetStyles, SIGNAL(clicked()),
+-		this, SLOT(slotGetStyles()));
++	d->mPrfsChatWindow = new AppearanceConfig_ChatWindow(d->mAppearanceTabCtl);
+ 
+-	// Since KNewStuff is incomplete and buggy we'll disable it by default.
+-	mPrfsChatWindow->btnGetStyles->setEnabled( config->readBoolEntry( "ForceNewStuff", false ) );
+-
+-	connect(mPrfsChatWindow->mTransparencyTintColor, SIGNAL(activated (const QColor &)),
++	connect(d->mPrfsChatWindow->styleList, SIGNAL(selectionChanged(QListBoxItem *)),
++		this, SLOT(slotChatStyleSelected()));
++	connect(d->mPrfsChatWindow->variantList, SIGNAL(activated(const QString&)),
++		this, SLOT(slotChatStyleVariantSelected(const QString &)));
++	connect(d->mPrfsChatWindow->deleteButton, SIGNAL(clicked()),
++		this, SLOT(slotDeleteChatStyle()));
++	connect(d->mPrfsChatWindow->installButton, SIGNAL(clicked()),
++		this, SLOT(slotInstallChatStyle()));
++	connect(d->mPrfsChatWindow->btnGetStyles, SIGNAL(clicked()),
++		this, SLOT(slotGetChatStyles()));
++	connect(d->mPrfsChatWindow->groupConsecutiveMessages, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsChatWindow->mTransparencyValue, SIGNAL(valueChanged(int)),
+-		this, SLOT(emitChanged()));
++	// Show the available styles when the Manager has finish to load the styles.
++	connect(ChatWindowStyleManager::self(), SIGNAL(loadStylesFinished()), this, SLOT(slotLoadChatStyles()));
+ 
+-	mPrfsChatWindow->htmlFrame->setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+-	QVBoxLayout *l = new QVBoxLayout(mPrfsChatWindow->htmlFrame);
+-	preview = new KHTMLPart(mPrfsChatWindow->htmlFrame, "preview");
+-	preview->setJScriptEnabled(false);
+-	preview->setJavaEnabled(false);
+-	preview->setPluginsEnabled(false);
+-	preview->setMetaRefreshEnabled(false);
+-	KHTMLView *htmlWidget = preview->view();
++	d->mPrfsChatWindow->htmlFrame->setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
++	// Create the fake Chat Session
++	createPreviewChatSession();
++	QVBoxLayout *l = new QVBoxLayout(d->mPrfsChatWindow->htmlFrame);
++	d->preview = new ChatMessagePart(d->previewChatSession, d->mPrfsChatWindow->htmlFrame, "preview");
++	d->preview->setJScriptEnabled(false);
++	d->preview->setJavaEnabled(false);
++	d->preview->setPluginsEnabled(false);
++	d->preview->setMetaRefreshEnabled(false);
++	KHTMLView *htmlWidget = d->preview->view();
+ 	htmlWidget->setMarginWidth(4);
+ 	htmlWidget->setMarginHeight(4);
+ 	htmlWidget->setFocusPolicy(NoFocus);
+ 	htmlWidget->setSizePolicy(
+ 		QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ 	l->addWidget(htmlWidget);
++	// Add the preview message to the ChatMessagePart
++	createPreviewMessages();
+ 
+-	mAppearanceTabCtl->addTab( mPrfsChatWindow, i18n("Chat Window") );
++	d->mAppearanceTabCtl->addTab( d->mPrfsChatWindow, i18n("Chat Window") );
+ 
+-
+-	connect( KDirWatch::self() , SIGNAL(dirty(const QString&)) , this, SLOT( slotStyleModified( const QString &) ) );
+-
+-
+ 	// "Contact List" TAB =======================================================
+-	mPrfsContactList = new AppearanceConfig_ContactList(mAppearanceTabCtl);
+-	connect(mPrfsContactList->mTreeContactList, SIGNAL(toggled(bool)),
++	d->mPrfsContactList = new AppearanceConfig_ContactList(d->mAppearanceTabCtl);
++	connect(d->mPrfsContactList->mTreeContactList, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mSortByGroup, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mSortByGroup, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mEditTooltips, SIGNAL(clicked()),
++	connect(d->mPrfsContactList->mEditTooltips, SIGNAL(clicked()),
+ 		this, SLOT(slotEditTooltips()));
+-	connect(mPrfsContactList->mIndentContacts, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mIndentContacts, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mHideVerticalScrollBar, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mHideVerticalScrollBar, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()) );
+-	connect(mPrfsContactList->mDisplayMode, SIGNAL(clicked(int)),
++	connect(d->mPrfsContactList->mDisplayMode, SIGNAL(clicked(int)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mIconMode, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mIconMode, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mAnimateChanges, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mAnimateChanges, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mFadeVisibility, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mFadeVisibility, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mFoldVisibility, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mFoldVisibility, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mAutoHide, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mAutoHide, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mAutoHideVScroll, SIGNAL(toggled(bool)),
++	connect(d->mPrfsContactList->mAutoHideVScroll, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsContactList->mAutoHideTimeout, SIGNAL(valueChanged(int)),
++	connect(d->mPrfsContactList->mAutoHideTimeout, SIGNAL(valueChanged(int)),
+ 		this, SLOT(emitChanged()));
+ 
+ 	// don't enable the checkbox if XRender is not available
+ 	#ifdef HAVE_XRENDER
+-	mPrfsContactList->mFadeVisibility->setEnabled(true);
++	d->mPrfsContactList->mFadeVisibility->setEnabled(true);
+ 	#else
+-	mPrfsContactList->mFadeVisibility->setEnabled(false);
++	d->mPrfsContactList->mFadeVisibility->setEnabled(false);
+ 	#endif
+ 
+-	mAppearanceTabCtl->addTab(mPrfsContactList, i18n("Contact List"));
++	d->mAppearanceTabCtl->addTab(d->mPrfsContactList, i18n("Contact List"));
+ 
+ 	// "Colors and Fonts" TAB ===================================================
+-	mPrfsColors = new AppearanceConfig_Colors(mAppearanceTabCtl);
+-	connect(mPrfsColors->foregroundColor, SIGNAL(changed(const QColor &)),
++	d->mPrfsColors = new AppearanceConfig_Colors(d->mAppearanceTabCtl);
++	connect(d->mPrfsColors->foregroundColor, SIGNAL(changed(const QColor &)),
+ 		this, SLOT(slotHighlightChanged()));
+-	connect(mPrfsColors->backgroundColor, SIGNAL(changed(const QColor &)),
++	connect(d->mPrfsColors->backgroundColor, SIGNAL(changed(const QColor &)),
+ 		this, SLOT(slotHighlightChanged()));
+-	connect(mPrfsColors->fontFace, SIGNAL(fontSelected(const QFont &)),
++	connect(d->mPrfsColors->fontFace, SIGNAL(fontSelected(const QFont &)),
+ 		this, SLOT(slotChangeFont()));
+-	connect(mPrfsColors->textColor, SIGNAL(changed(const QColor &)),
+-		this, SLOT(slotUpdatePreview()));
+-	connect(mPrfsColors->bgColor, SIGNAL(changed(const QColor &)),
+-		this, SLOT(slotUpdatePreview()));
+-	connect(mPrfsColors->linkColor, SIGNAL(changed(const QColor &)),
+-		this, SLOT(slotUpdatePreview()));
+-	connect(mPrfsColors->mGreyIdleMetaContacts, SIGNAL(toggled(bool)),
++	connect(d->mPrfsColors->textColor, SIGNAL(changed(const QColor &)),
++		this, SLOT(slotUpdateChatPreview()));
++	connect(d->mPrfsColors->bgColor, SIGNAL(changed(const QColor &)),
++		this, SLOT(slotUpdateChatPreview()));
++	connect(d->mPrfsColors->linkColor, SIGNAL(changed(const QColor &)),
++		this, SLOT(slotUpdateChatPreview()));
++	connect(d->mPrfsColors->mGreyIdleMetaContacts, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->idleContactColor, SIGNAL(changed(const QColor &)),
++	connect(d->mPrfsColors->idleContactColor, SIGNAL(changed(const QColor &)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mUseCustomFonts, SIGNAL(toggled(bool)),
++	connect(d->mPrfsColors->mUseCustomFonts, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mSmallFont, SIGNAL(fontSelected(const QFont &)),
++	connect(d->mPrfsColors->mSmallFont, SIGNAL(fontSelected(const QFont &)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mNormalFont, SIGNAL(fontSelected(const QFont &)),
++	connect(d->mPrfsColors->mNormalFont, SIGNAL(fontSelected(const QFont &)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mGroupNameColor, SIGNAL(changed(const QColor &)),
++	connect(d->mPrfsColors->mGroupNameColor, SIGNAL(changed(const QColor &)),
+ 		this, SLOT(emitChanged()));
+ 
+-	connect(mPrfsColors->mBgOverride, SIGNAL(toggled(bool)),
++	connect(d->mPrfsColors->mBgOverride, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mFgOverride, SIGNAL(toggled(bool)),
++	connect(d->mPrfsColors->mFgOverride, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+-	connect(mPrfsColors->mRtfOverride, SIGNAL(toggled(bool)),
++	connect(d->mPrfsColors->mRtfOverride, SIGNAL(toggled(bool)),
+ 		this, SLOT(emitChanged()));
+ 
+-	mAppearanceTabCtl->addTab(mPrfsColors, i18n("Colors && Fonts"));
++	d->mAppearanceTabCtl->addTab(d->mPrfsColors, i18n("Colors && Fonts"));
+ 
+ 	// ==========================================================================
+ 
+-
+-	styleChanged = false;
+-	slotTransparencyChanged(mPrfsChatWindow->mTransparencyEnabled->isChecked());
+-
+ 	load();
+-	//EmitChanged when something change.
+ }
+ 
+ AppearanceConfig::~AppearanceConfig()
+@@ -472,10 +332,10 @@
+ 
+ void AppearanceConfig::updateEmoticonsButton(bool _b)
+ {
+-    QString themeName = mPrfsEmoticons->icon_theme_list->currentText();
++    QString themeName = d->mPrfsEmoticons->icon_theme_list->currentText();
+     QFileInfo fileInf(KGlobal::dirs()->findResource("emoticons", themeName+"/"));
+-    mPrfsEmoticons->btnRemoveTheme->setEnabled( _b && fileInf.isWritable());
+-    mPrfsEmoticons->btnGetThemes->setEnabled( m_allowDownloadTheme );
++    d->mPrfsEmoticons->btnRemoveTheme->setEnabled( _b && fileInf.isWritable());
++    d->mPrfsEmoticons->btnGetThemes->setEnabled( false );
+ }
+ 
+ void AppearanceConfig::save()
+@@ -484,79 +344,86 @@
+ 	KopetePrefs *p = KopetePrefs::prefs();
+ 
+ 	// "Emoticons" TAB ==========================================================
+-	p->setIconTheme( mPrfsEmoticons->icon_theme_list->currentText() );
+-	p->setUseEmoticons ( mPrfsEmoticons->chkUseEmoticons->isChecked() );
+-	p->setEmoticonsRequireSpaces( mPrfsEmoticons->chkRequireSpaces->isChecked() );
++	p->setIconTheme( d->mPrfsEmoticons->icon_theme_list->currentText() );
++	p->setUseEmoticons ( d->mPrfsEmoticons->chkUseEmoticons->isChecked() );
++	p->setEmoticonsRequireSpaces( d->mPrfsEmoticons->chkRequireSpaces->isChecked() );
+ 
+ 	// "Chat Window" TAB ========================================================
+-	p->setTransparencyColor( mPrfsChatWindow->mTransparencyTintColor->color() );
+-	p->setTransparencyEnabled( mPrfsChatWindow->mTransparencyEnabled->isChecked() );
+-	p->setTransparencyValue( mPrfsChatWindow->mTransparencyValue->value() );
+-	if( styleChanged || p->styleSheet() != mPrfsChatWindow->styleList->selectedItem()->text() )
+-		p->setStyleSheet(  mPrfsChatWindow->styleList->selectedItem()->text() );
+-	kdDebug(14000) << k_funcinfo << p->styleSheet()  << mPrfsChatWindow->styleList->selectedItem()->text() << endl;
++	p->setGroupConsecutiveMessages( d->mPrfsChatWindow->groupConsecutiveMessages->isChecked() );
+ 
++	// Get the stylePath
++	if(d->currentStyle)
++	{
++		kdDebug(14000) << k_funcinfo << d->currentStyle->getStylePath() << endl;
++		p->setStylePath(d->currentStyle->getStylePath());
++	}
++	// Get and save the styleVariant
++	if( !d->currentVariantMap.empty() )
++	{
++		kdDebug(14000) << k_funcinfo << d->currentVariantMap[ d->mPrfsChatWindow->variantList->currentText()] << endl;
++		p->setStyleVariant(d->currentVariantMap[ d->mPrfsChatWindow->variantList->currentText()]);
++	}
++
+ 	// "Contact List" TAB =======================================================
+-	p->setTreeView(mPrfsContactList->mTreeContactList->isChecked());
+-	p->setSortByGroup(mPrfsContactList->mSortByGroup->isChecked());
+-	p->setContactListIndentContacts(mPrfsContactList->mIndentContacts->isChecked());
+-	p->setContactListHideVerticalScrollBar(mPrfsContactList->mHideVerticalScrollBar->isChecked());
+-	p->setContactListDisplayMode(KopetePrefs::ContactDisplayMode(mPrfsContactList->mDisplayMode->selectedId()));
+-	p->setContactListIconMode(KopetePrefs::IconDisplayMode((mPrfsContactList->mIconMode->isChecked()) ? KopetePrefs::PhotoPic : KopetePrefs::IconPic));
+-	p->setContactListAnimation(mPrfsContactList->mAnimateChanges->isChecked());
+-	p->setContactListFading(mPrfsContactList->mFadeVisibility->isChecked());
+-	p->setContactListFolding(mPrfsContactList->mFoldVisibility->isChecked());
++	p->setTreeView(d->mPrfsContactList->mTreeContactList->isChecked());
++	p->setSortByGroup(d->mPrfsContactList->mSortByGroup->isChecked());
++	p->setContactListIndentContacts(d->mPrfsContactList->mIndentContacts->isChecked());
++	p->setContactListHideVerticalScrollBar(d->mPrfsContactList->mHideVerticalScrollBar->isChecked());
++	p->setContactListDisplayMode(KopetePrefs::ContactDisplayMode(d->mPrfsContactList->mDisplayMode->selectedId()));
++	p->setContactListIconMode(KopetePrefs::IconDisplayMode((d->mPrfsContactList->mIconMode->isChecked()) ? KopetePrefs::PhotoPic : KopetePrefs::IconPic));
++	p->setContactListAnimation(d->mPrfsContactList->mAnimateChanges->isChecked());
++	p->setContactListFading(d->mPrfsContactList->mFadeVisibility->isChecked());
++	p->setContactListFolding(d->mPrfsContactList->mFoldVisibility->isChecked());
+ 
+ 	// "Colors & Fonts" TAB =====================================================
+-	p->setHighlightBackground(mPrfsColors->backgroundColor->color());
+-	p->setHighlightForeground(mPrfsColors->foregroundColor->color());
+-	p->setBgColor(mPrfsColors->bgColor->color());
+-	p->setTextColor(mPrfsColors->textColor->color());
+-	p->setLinkColor(mPrfsColors->linkColor->color());
+-	p->setFontFace(mPrfsColors->fontFace->font());
+-	p->setIdleContactColor(mPrfsColors->idleContactColor->color());
+-	p->setGreyIdleMetaContacts(mPrfsColors->mGreyIdleMetaContacts->isChecked());
+-	p->setContactListUseCustomFonts(mPrfsColors->mUseCustomFonts->isChecked());
+-	p->setContactListCustomSmallFont(mPrfsColors->mSmallFont->font());
+-	p->setContactListCustomNormalFont(mPrfsColors->mNormalFont->font());
+-	p->setContactListGroupNameColor(mPrfsColors->mGroupNameColor->color());
+-	p->setContactListAutoHide(mPrfsContactList->mAutoHide->isChecked());
+-	p->setContactListAutoHideVScroll(mPrfsContactList->mAutoHideVScroll->isChecked());
+-	p->setContactListAutoHideTimeout(mPrfsContactList->mAutoHideTimeout->value());
++	p->setHighlightBackground(d->mPrfsColors->backgroundColor->color());
++	p->setHighlightForeground(d->mPrfsColors->foregroundColor->color());
++	p->setBgColor(d->mPrfsColors->bgColor->color());
++	p->setTextColor(d->mPrfsColors->textColor->color());
++	p->setLinkColor(d->mPrfsColors->linkColor->color());
++	p->setFontFace(d->mPrfsColors->fontFace->font());
++	p->setIdleContactColor(d->mPrfsColors->idleContactColor->color());
++	p->setGreyIdleMetaContacts(d->mPrfsColors->mGreyIdleMetaContacts->isChecked());
++	p->setContactListUseCustomFonts(d->mPrfsColors->mUseCustomFonts->isChecked());
++	p->setContactListCustomSmallFont(d->mPrfsColors->mSmallFont->font());
++	p->setContactListCustomNormalFont(d->mPrfsColors->mNormalFont->font());
++	p->setContactListGroupNameColor(d->mPrfsColors->mGroupNameColor->color());
++	p->setContactListAutoHide(d->mPrfsContactList->mAutoHide->isChecked());
++	p->setContactListAutoHideVScroll(d->mPrfsContactList->mAutoHideVScroll->isChecked());
++	p->setContactListAutoHideTimeout(d->mPrfsContactList->mAutoHideTimeout->value());
+ 
+-	p->setBgOverride( mPrfsColors->mBgOverride->isChecked() );
+-	p->setFgOverride( mPrfsColors->mFgOverride->isChecked() );
+-	p->setRtfOverride( mPrfsColors->mRtfOverride->isChecked() );
++	p->setBgOverride( d->mPrfsColors->mBgOverride->isChecked() );
++	p->setFgOverride( d->mPrfsColors->mFgOverride->isChecked() );
++	p->setRtfOverride( d->mPrfsColors->mRtfOverride->isChecked() );
+ 
+ 	p->save();
+-	styleChanged = false;
++	d->styleChanged = false;
+ }
+ 
+ void AppearanceConfig::load()
+ {
+ 	//we will change the state of somme controls, which will call some signals.
+ 	//so to don't refresh everything several times, we memorize we are loading.
+-	loading=true;
++	d->loading=true;
+ 
+ //	kdDebug(14000) << k_funcinfo << "called" << endl;
+ 	KopetePrefs *p = KopetePrefs::prefs();
+ 
+ 	// "Emoticons" TAB ==========================================================
+ 	updateEmoticonlist();
+-	mPrfsEmoticons->chkUseEmoticons->setChecked( p->useEmoticons() );
+-	mPrfsEmoticons->chkRequireSpaces->setChecked( p->emoticonsRequireSpaces() );
++	d->mPrfsEmoticons->chkUseEmoticons->setChecked( p->useEmoticons() );
++	d->mPrfsEmoticons->chkRequireSpaces->setChecked( p->emoticonsRequireSpaces() );
+ 
+ 	// "Chat Window" TAB ========================================================
+-	mPrfsChatWindow->mTransparencyEnabled->setChecked( p->transparencyEnabled() );
+-	mPrfsChatWindow->mTransparencyTintColor->setColor( p->transparencyColor() );
+-	mPrfsChatWindow->mTransparencyValue->setValue( p->transparencyValue() );
+-	loadStyles();
+-	
++	d->mPrfsChatWindow->groupConsecutiveMessages->setChecked( p->groupConsecutiveMessages() );
++	// Look for avaiable chat window styles.
++	slotLoadChatStyles();
++
+ 	// "Contact List" TAB =======================================================
+-	mPrfsContactList->mTreeContactList->setChecked( p->treeView() );
+-	mPrfsContactList->mSortByGroup->setChecked( p->sortByGroup() );
+-	mPrfsContactList->mIndentContacts->setChecked( p->contactListIndentContacts() );
+-	mPrfsContactList->mHideVerticalScrollBar->setChecked( p->contactListHideVerticalScrollBar() );
++	d->mPrfsContactList->mTreeContactList->setChecked( p->treeView() );
++	d->mPrfsContactList->mSortByGroup->setChecked( p->sortByGroup() );
++	d->mPrfsContactList->mIndentContacts->setChecked( p->contactListIndentContacts() );
++	d->mPrfsContactList->mHideVerticalScrollBar->setChecked( p->contactListHideVerticalScrollBar() );
+ 
+         // convert old single value display mode to dual display/icon modes
+         if (p->contactListDisplayMode() == KopetePrefs::Yagami) {
+@@ -564,60 +431,70 @@
+             	p->setContactListIconMode( KopetePrefs::PhotoPic );
+         }
+ 
+-	mPrfsContactList->mDisplayMode->setButton( p->contactListDisplayMode() );
+-	mPrfsContactList->mIconMode->setChecked( p->contactListIconMode() == KopetePrefs::PhotoPic);
++	d->mPrfsContactList->mDisplayMode->setButton( p->contactListDisplayMode() );
++	d->mPrfsContactList->mIconMode->setChecked( p->contactListIconMode() == KopetePrefs::PhotoPic);
+ 
+-            
+-	mPrfsContactList->mAnimateChanges->setChecked( p->contactListAnimation() );
++
++	d->mPrfsContactList->mAnimateChanges->setChecked( p->contactListAnimation() );
+ #ifdef HAVE_XRENDER
+-	mPrfsContactList->mFadeVisibility->setChecked( p->contactListFading() );
++	d->mPrfsContactList->mFadeVisibility->setChecked( p->contactListFading() );
+ #else
+-	mPrfsContactList->mFadeVisibility->setChecked( false );
++	d->mPrfsContactList->mFadeVisibility->setChecked( false );
+ #endif
+-	mPrfsContactList->mFoldVisibility->setChecked( p->contactListFolding() );
+-	mPrfsContactList->mAutoHide->setChecked( p->contactListAutoHide() );
+-	mPrfsContactList->mAutoHideVScroll->setChecked( p->contactListAutoHideVScroll() );
+-	mPrfsContactList->mAutoHideTimeout->setValue( p->contactListAutoHideTimeout() );
++	d->mPrfsContactList->mFoldVisibility->setChecked( p->contactListFolding() );
++	d->mPrfsContactList->mAutoHide->setChecked( p->contactListAutoHide() );
++	d->mPrfsContactList->mAutoHideVScroll->setChecked( p->contactListAutoHideVScroll() );
++	d->mPrfsContactList->mAutoHideTimeout->setValue( p->contactListAutoHideTimeout() );
+ 
+ 	// "Colors & Fonts" TAB =====================================================
+-	mPrfsColors->foregroundColor->setColor(p->highlightForeground());
+-	mPrfsColors->backgroundColor->setColor(p->highlightBackground());
+-	mPrfsColors->textColor->setColor(p->textColor());
+-	mPrfsColors->linkColor->setColor(p->linkColor());
+-	mPrfsColors->bgColor->setColor(p->bgColor());
+-	mPrfsColors->fontFace->setFont(p->fontFace());
+-	mPrfsColors->mGreyIdleMetaContacts->setChecked(p->greyIdleMetaContacts());
+-	mPrfsColors->idleContactColor->setColor(p->idleContactColor());
+-	mPrfsColors->mUseCustomFonts->setChecked(p->contactListUseCustomFonts());
+-	mPrfsColors->mSmallFont->setFont(p->contactListCustomSmallFont());
+-	mPrfsColors->mNormalFont->setFont(p->contactListCustomNormalFont());
+-	mPrfsColors->mGroupNameColor->setColor(p->contactListGroupNameColor());
++	d->mPrfsColors->foregroundColor->setColor(p->highlightForeground());
++	d->mPrfsColors->backgroundColor->setColor(p->highlightBackground());
++	d->mPrfsColors->textColor->setColor(p->textColor());
++	d->mPrfsColors->linkColor->setColor(p->linkColor());
++	d->mPrfsColors->bgColor->setColor(p->bgColor());
++	d->mPrfsColors->fontFace->setFont(p->fontFace());
++	d->mPrfsColors->mGreyIdleMetaContacts->setChecked(p->greyIdleMetaContacts());
++	d->mPrfsColors->idleContactColor->setColor(p->idleContactColor());
++	d->mPrfsColors->mUseCustomFonts->setChecked(p->contactListUseCustomFonts());
++	d->mPrfsColors->mSmallFont->setFont(p->contactListCustomSmallFont());
++	d->mPrfsColors->mNormalFont->setFont(p->contactListCustomNormalFont());
++	d->mPrfsColors->mGroupNameColor->setColor(p->contactListGroupNameColor());
+ 
+-	mPrfsColors->mBgOverride->setChecked( p->bgOverride() );
+-	mPrfsColors->mFgOverride->setChecked( p->fgOverride() );
+-	mPrfsColors->mRtfOverride->setChecked( p->rtfOverride() );
++	d->mPrfsColors->mBgOverride->setChecked( p->bgOverride() );
++	d->mPrfsColors->mFgOverride->setChecked( p->fgOverride() );
++	d->mPrfsColors->mRtfOverride->setChecked( p->rtfOverride() );
+ 
+-	loading=false;
+-	slotUpdatePreview();
++	d->loading=false;
++	slotUpdateChatPreview();
+ }
+ 
+-void AppearanceConfig::loadStyles()
++void AppearanceConfig::slotLoadChatStyles()
+ {
+-	// FIXME: Using the filename as user-visible name is not translatable! - Martijn
+-	mPrfsChatWindow->styleList->clear();
+-	QStringList chatStyles = KGlobal::dirs()->findAllResources( "appdata", QString::fromLatin1( "styles/*.xsl" ) );
+-	for ( QStringList::Iterator it = chatStyles.begin(); it != chatStyles.end(); ++it )
++	d->mPrfsChatWindow->styleList->clear();
++	d->styleItemMap.clear();
++
++	ChatWindowStyleManager::StyleList availableStyles;
++	availableStyles = ChatWindowStyleManager::self()->getAvailableStyles();
++	if( availableStyles.empty() )
++		kdDebug(14000) << k_funcinfo << "Warning, available styles is empty !" << endl;
++
++	ChatWindowStyleManager::StyleList::ConstIterator it, itEnd = availableStyles.constEnd();
++	for(it = availableStyles.constBegin(); it != itEnd; ++it)
+ 	{
+-		QFileInfo fi( *it );
+-		QString fileName = fi.fileName().section( '.', 0, 0 );
+-		mPrfsChatWindow->styleList->insertItem( fileName, 0 );
+-		itemMap.insert( mPrfsChatWindow->styleList->firstItem(), *it );
+-		KDirWatch::self()->addFile(*it);
++		// Insert style name into the listbox
++		d->mPrfsChatWindow->styleList->insertItem( it.key(), 0 );
++		// Insert the style class into the internal map for futher acces.
++		d->styleItemMap.insert( d->mPrfsChatWindow->styleList->firstItem(), it.data() );
+ 
+-		if ( fileName == KopetePrefs::prefs()->styleSheet() )
+-			mPrfsChatWindow->styleList->setSelected( mPrfsChatWindow->styleList->firstItem(), true );
++		if( it.data() == KopetePrefs::prefs()->stylePath() )
++		{
++			kdDebug(14000) << k_funcinfo << "Restoring saved style: " << it.key() << endl;
++
++			d->mPrfsChatWindow->styleList->setSelected( d->mPrfsChatWindow->styleList->firstItem(), true );
++		}
+ 	}
+-	mPrfsChatWindow->styleList->sort();
++
++	d->mPrfsChatWindow->styleList->sort();
+ }
+ 
+ void AppearanceConfig::updateEmoticonlist()
+@@ -625,7 +502,7 @@
+ 	KopetePrefs *p = KopetePrefs::prefs();
+ 	KStandardDirs dir;
+ 
+-	mPrfsEmoticons->icon_theme_list->clear(); // Wipe out old list
++	d->mPrfsEmoticons->icon_theme_list->clear(); // Wipe out old list
+ 	// Get a list of directories in our icon theme dir
+ 	QStringList themeDirs = KGlobal::dirs()->findDirs("emoticons", "");
+ 	// loop adding themes from all dirs into theme-list
+@@ -642,25 +519,25 @@
+ 			{
+ 				// Add ourselves to the list, using our directory name  FIXME:  use the first emoticon of the theme.
+ 				QPixmap previewPixmap = QPixmap(locate("emoticons", themeQDir[y]+"/smile.png"));
+-				mPrfsEmoticons->icon_theme_list->insertItem(previewPixmap,themeQDir[y]);
++				d->mPrfsEmoticons->icon_theme_list->insertItem(previewPixmap,themeQDir[y]);
+ 			}
+ 		}
+ 	}
+ 
+ 	// Where is that theme in our big-list-o-themes?
+-	QListBoxItem *item = mPrfsEmoticons->icon_theme_list->findItem( p->iconTheme() );
++	QListBoxItem *item = d->mPrfsEmoticons->icon_theme_list->findItem( p->iconTheme() );
+ 
+ 	if (item) // found it... make it the currently selected theme
+-		mPrfsEmoticons->icon_theme_list->setCurrentItem( item );
++		d->mPrfsEmoticons->icon_theme_list->setCurrentItem( item );
+ 	else // Er, it's not there... select the current item
+-		mPrfsEmoticons->icon_theme_list->setCurrentItem( 0 );
++		d->mPrfsEmoticons->icon_theme_list->setCurrentItem( 0 );
+ }
+ 
+ void AppearanceConfig::slotSelectedEmoticonsThemeChanged()
+ {
+-	QString themeName = mPrfsEmoticons->icon_theme_list->currentText();
++	QString themeName = d->mPrfsEmoticons->icon_theme_list->currentText();
+ 	QFileInfo fileInf(KGlobal::dirs()->findResource("emoticons", themeName+"/"));
+-	mPrfsEmoticons->btnRemoveTheme->setEnabled( fileInf.isWritable() );
++	d->mPrfsEmoticons->btnRemoveTheme->setEnabled( fileInf.isWritable() );
+ 
+ 	Kopete::Emoticons emoticons( themeName );
+ 	QStringList smileys = emoticons.emoticonAndPicList().values();
+@@ -670,329 +547,262 @@
+ 		newContentText += QString::fromLatin1("<img src=\"%1\"> ").arg(*it);
+ 
+ 	newContentText += QString::fromLatin1("</qt>");
+-	mPrfsEmoticons->icon_theme_preview->setText(newContentText);
++	d->mPrfsEmoticons->icon_theme_preview->setText(newContentText);
+ 	emitChanged();
+ }
+ 
+-void AppearanceConfig::slotTransparencyChanged ( bool checked )
+-{
+-	mPrfsChatWindow->mTransparencyTintColor->setEnabled( checked );
+-	mPrfsChatWindow->mTransparencyValue->setEnabled( checked );
+-	emitChanged();
+-}
+-
+ void AppearanceConfig::slotHighlightChanged()
+ {
+ //	bool value = mPrfsChatWindow->highlightEnabled->isChecked();
+ //	mPrfsChatWindow->foregroundColor->setEnabled ( value );
+ //	mPrfsChatWindow->backgroundColor->setEnabled ( value );
+-	slotUpdatePreview();
++	slotUpdateChatPreview();
+ }
+ 
+ void AppearanceConfig::slotChangeFont()
+ {
+-	currentStyle = QString::null; //force to update preview;
+-	slotUpdatePreview();
++	slotUpdateChatPreview();
+ 	emitChanged();
+ }
+ 
+-void AppearanceConfig::slotAddStyle()
++void AppearanceConfig::slotChatStyleSelected()
+ {
+-    QString styleName=KInputDialog::getText( i18n("Add Styles - Kopete") , i18n("Enter the name for the new style you want to add:") ,
+-				QString::null, 0L, this) ;
+-	if(styleName.isEmpty())
+-		return;
++	// Retrieve variant list.
++	QString stylePath = d->styleItemMap[d->mPrfsChatWindow->styleList->selectedItem()];
++	d->currentStyle = ChatWindowStyleManager::self()->getStyleFromPool( stylePath );
+ 
+-	if( addStyle( styleName ,
+-			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+-			"<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+-			"<xsl:output method=\"html\"/>\n"
+-			"<xsl:template match=\"message\">\n\n\n\n</xsl:template>\n</xsl:stylesheet>"  ) )
++	if(d->currentStyle)
+ 	{
+-		KRun::runURL( KURL(locateLocal("appdata", QString::fromLatin1("styles/%1.xsl").arg( styleName ) )) , "text/plain");
+-		currentStyle = QString::null; //force to update preview;
+-	}
+-}
++		d->currentVariantMap = d->currentStyle->getVariants();
++		kdDebug(14000) << k_funcinfo << "Loading style: " << d->currentStyle->getStylePath() << endl;
+ 
+-void AppearanceConfig::updateHighlight()
+-{
+-	KTextEditor::HighlightingInterface *hi = KTextEditor::highlightingInterface( editDocument );
+-	int count = hi->hlModeCount();
+-	for( int i=0; i < count; i++ )
+-	{
+-		if( hi->hlModeName(i) == QString::fromLatin1("XML") )
+-		{
+-			hi->setHlMode(i);
+-			break;
+-		}
+-	}
+-	emitChanged();
+-}
++		// Update the variant list based on current style.
++		d->mPrfsChatWindow->variantList->clear();
+ 
+-void AppearanceConfig::slotStyleSelected()
+-{
+-	QString filePath = itemMap[mPrfsChatWindow->styleList->selectedItem()];
+-	QFileInfo fi( filePath );
+-	if(fi.isWritable())
+-	{
+-		mPrfsChatWindow->editButton->setEnabled( true );
+-		mPrfsChatWindow->deleteButton->setEnabled( true );
+-	}
+-	else
+-	{
+-		mPrfsChatWindow->editButton->setEnabled( false );
+-		mPrfsChatWindow->deleteButton->setEnabled( false );
+-	}
+-	slotUpdatePreview();
+-	emitChanged();
+-}
++		// Add the no variant item to the list
++		// TODO: Use default name variant from Info.plist
++		// TODO: Select default variant from Info.plist
++		d->mPrfsChatWindow->variantList->insertItem( i18n("(No Variant)") );
+ 
+-void AppearanceConfig::slotImportStyle()
+-{
+-	KURL chosenStyle = KURLRequesterDlg::getURL( QString::null, this, i18n( "Choose Stylesheet" ) );
+-	if ( !chosenStyle.isEmpty() )
+-	{
+-		QString stylePath;
+-		// FIXME: Using NetAccess uses nested event loops with all associated problems.
+-		//        Better use normal KIO and an async API - Martijn
+-		if ( KIO::NetAccess::download( chosenStyle, stylePath, this ) )
++		ChatWindowStyle::StyleVariants::ConstIterator it, itEnd = d->currentVariantMap.constEnd();
++		int currentIndex = 0;
++		for(it = d->currentVariantMap.constBegin(); it != itEnd; ++it)
+ 		{
+-			QString styleSheet = fileContents( stylePath );
+-			if ( Kopete::XSLT( styleSheet ).isValid() )
+-			{
+-				QFileInfo fi( stylePath );
+-				addStyle( fi.fileName().section( '.', 0, 0 ), styleSheet );
+-			}
+-			else
+-			{
+-				KMessageBox::queuedMessageBox( this, KMessageBox::Error,
+-					i18n( "'%1' is not a valid XSLT document. Import canceled." ).arg( chosenStyle.path() ),
+-					i18n( "Invalid Style" ) );
+-			}
+-		}
+-		else
+-		{
+-			KMessageBox::queuedMessageBox( this, KMessageBox::Error,
+-				i18n( "Could not import '%1'. Check access permissions/network connection." ).arg( chosenStyle.path() ),
+-				i18n( "Import Error" ) );
+-		}
+-	}
+-}
++			// Insert variant name into the combobox.
++			d->mPrfsChatWindow->variantList->insertItem( it.key() );
+ 
+-void AppearanceConfig::slotCopyStyle()
+-{
+-	QListBoxItem *copiedItem = mPrfsChatWindow->styleList->selectedItem();
+-	if( copiedItem )
+-	{
+-		QString styleName =
+-			KInputDialog::getText( i18n( "New Style Name" ), i18n( "Enter the name of the new style:" ) );
++			if( it.data() == KopetePrefs::prefs()->styleVariant() )
++				d->mPrfsChatWindow->variantList->setCurrentItem(currentIndex+1);
+ 
+-		if ( !styleName.isEmpty() )
+-		{
+-			QString stylePath = itemMap[ copiedItem ];
+-			addStyle( styleName, fileContents( stylePath ) );
++			currentIndex++;
+ 		}
+-	}
+-	else
+-	{
+-		KMessageBox::queuedMessageBox( this, KMessageBox::Sorry,
+-			i18n("Please select a style to copy."), i18n("No Style Selected") );
+-	}
+-	emitChanged();
+-}
+ 
+-void AppearanceConfig::slotEditStyle()
+-{
+-	editedItem = mPrfsChatWindow->styleList->selectedItem();
+-	QString stylePath = itemMap[ editedItem ];
++		// Update the preview
++		slotUpdateChatPreview();
++		// Get the first variant to preview
++		// Check if the current style has variants.
++		if( !d->currentVariantMap.empty() )
++			d->preview->setStyleVariant(d->currentVariantMap[0]);
+ 
+-	KRun::runURL(stylePath, "text/plain");
++		emitChanged();
++	}
+ }
+ 
+-void AppearanceConfig::slotDeleteStyle()
++void AppearanceConfig::slotChatStyleVariantSelected(const QString &variantName)
+ {
+-	if( KMessageBox::warningContinueCancel( this, i18n("Are you sure you want to delete the style \"%1\"?")
+-		.arg( mPrfsChatWindow->styleList->selectedItem()->text() ),
+-		i18n("Delete Style"), KGuiItem(i18n("Delete Style"),"editdelete")) == KMessageBox::Continue )
+-	{
+-		QListBoxItem *style = mPrfsChatWindow->styleList->selectedItem();
+-		QString filePath = itemMap[ style ];
+-		itemMap.remove( style );
++// 	kdDebug(14000) << k_funcinfo << variantName << endl;
++// 	kdDebug(14000) << k_funcinfo << d->currentVariantMap[variantName] << endl;
+ 
+-		QFileInfo fi( filePath );
+-		if( fi.isWritable() )
+-			QFile::remove( filePath );
+-
+-		KConfig *config = KGlobal::config();
+-		config->setGroup("KNewStuffStatus");
+-		config->deleteEntry( style->text() );
+-		config->sync();
+-
+-		if( style->next() )
+-			mPrfsChatWindow->styleList->setSelected( style->next(), true );
+-		else
+-			mPrfsChatWindow->styleList->setSelected( style->prev(), true );
+-		delete style;
+-	}
++	// Update the preview
++	d->preview->setStyleVariant(d->currentVariantMap[variantName]);
+ 	emitChanged();
+ }
+ 
+-void AppearanceConfig::slotStyleModified(const QString &filename)
++void AppearanceConfig::slotInstallChatStyle()
+ {
+-	editedItem = mPrfsChatWindow->styleList->selectedItem();
+-	QString stylePath = itemMap[ editedItem ];
++	KURL styleToInstall = KFileDialog::getOpenURL( QString::null, QString::fromUtf8("application/x-zip application/x-tgz application/x-tbz"), this, i18n("Choose Chat Window style to install.") );
+ 
+-	if(filename == stylePath)
++	if( !styleToInstall.isEmpty() )
+ 	{
+-		currentStyle=QString::null;  //force to relead the preview
+-		slotUpdatePreview();
++		QString stylePath;
++		if( KIO::NetAccess::download( styleToInstall, stylePath, this ) )
++		{
++			int styleInstallReturn = 0;
++			styleInstallReturn = ChatWindowStyleManager::self()->installStyle( stylePath );
++			switch(styleInstallReturn)
++			{
++				case ChatWindowStyleManager::StyleCannotOpen:
++				{
++					KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("The specified archive cannot be opened.\nMake sure that the archive is valid ZIP or TAR archive."), i18n("Can't open archive") );
++					break;
++				}
++				case ChatWindowStyleManager::StyleNoDirectoryValid:
++				{
++					KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("Could not find a suitable place to install the Chat Window style in user directory."), i18n("Can't find styles directory") );
++					break;
++				}
++				case ChatWindowStyleManager::StyleNotValid:
++					KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("The specified archive does not contain a valid Chat Window style."), i18n("Invalid Style") );
++					break;
++				case ChatWindowStyleManager::StyleInstallOk:
++				{
++					KMessageBox::queuedMessageBox( this, KMessageBox::Information, i18n("The Chat Window style was successfully installed."), i18n("Install successful") );
++					break;
++				}
++				case ChatWindowStyleManager::StyleUnknow:
++				default:
++				{
++					KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("An unknow error occurred while trying to install the Chat Window style."), i18n("Unknow error") );
++					break;
++				}
++			}
+ 
+-		emitChanged();
++			// removeTempFile check if the file is a temp file, so it's ok for local files.
++			KIO::NetAccess::removeTempFile( stylePath );
++		}
+ 	}
+ }
+ 
+-bool AppearanceConfig::addStyle( const QString &styleName, const QString &styleSheet )
++void AppearanceConfig::slotDeleteChatStyle()
+ {
+-	bool newStyleName = !mPrfsChatWindow->styleList->findItem( styleName );
+-
+-	if ( newStyleName )
++	QString styleName = d->mPrfsChatWindow->styleList->selectedItem()->text();
++	QString stylePathToDelete = d->styleItemMap[d->mPrfsChatWindow->styleList->selectedItem()];
++	if( ChatWindowStyleManager::self()->removeStyle(stylePathToDelete) )
+ 	{
+-		QString filePath = locateLocal("appdata", QString::fromLatin1("styles/%1.xsl").arg( styleName ) );
+-		QFile out( filePath );
+-		if ( out.open( IO_WriteOnly ) )
+-		{
+-			QTextStream stream( &out );
+-			stream << styleSheet;
+-			out.close();
++		KMessageBox::queuedMessageBox(this, KMessageBox::Information, i18n("It's the deleted style name", "The style %1 was successfully deleted.").arg(styleName));
+ 
+-			KDirWatch::self()->addFile(filePath);
+-
+-			if ( newStyleName )
+-			{
+-				mPrfsChatWindow->styleList->insertItem( styleName, 0 );
+-				itemMap.insert( mPrfsChatWindow->styleList->firstItem(), filePath );
+-				mPrfsChatWindow->styleList->setSelected( mPrfsChatWindow->styleList->firstItem(), true );
+-				mPrfsChatWindow->styleList->sort();
+-			}
+-			else
+-				slotUpdatePreview();
+-
+-			styleChanged = true;
+-			return true;
+-		}
+-		else
+-		{
+-			KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("Error saving file. Check access permissions to \"%1\".").arg( filePath ), i18n("Could Not Save") );
+-		}
++		// Get the first item in the stye List.
++		QString stylePath = (*d->styleItemMap.begin());
++		d->currentStyle = ChatWindowStyleManager::self()->getStyleFromPool(stylePath);
++		emitChanged();
+ 	}
+ 	else
+ 	{
+-		KMessageBox::queuedMessageBox( this, KMessageBox::Error, i18n("A style named \"%1\" already exists. Please rename the style.").arg( styleName ), i18n("Could Not Save") );
++		KMessageBox::queuedMessageBox(this, KMessageBox::Information, i18n("It's the deleted style name", "An error occured while trying to delete %1 style.").arg(styleName));
+ 	}
+-
+-	//The style has not been saved for a reason or another
+-	return false;
+ }
+ 
+-void AppearanceConfig::slotGetStyles()
++void AppearanceConfig::slotGetChatStyles()
+ {
+ 	// we need this because KNewStuffGeneric's install function isn't clever enough
+-	KopeteStyleNewStuff * kns = new KopeteStyleNewStuff( "kopete/chatstyle", this );
+-	KNS::Engine * engine = new KNS::Engine( kns, "kopete/chatstyle", this );
+-	KNS::DownloadDialog * d = new KNS::DownloadDialog( engine, this );
+-	d->setType( "kopete/chatstyle" );
++	KopeteStyleNewStuff *kopeteNewStuff = new KopeteStyleNewStuff( "kopete/chatstyle", this );
++	KNS::Engine *engine = new KNS::Engine( kopeteNewStuff, "kopete/chatstyle", this );
++	KNS::DownloadDialog *downloadDialog = new KNS::DownloadDialog( engine, this );
++	downloadDialog->setType( "kopete/chatstyle" );
+ 	// you have to do this by hand when providing your own Engine
+-	KNS::ProviderLoader * p = new KNS::ProviderLoader( this );
+-	QObject::connect( p, SIGNAL( providersLoaded(Provider::List*) ), d, SLOT( slotProviders (Provider::List *) ) );
+-	p->load( "kopete/chatstyle", "http://download.kde.org/khotnewstuff/kopetestyles-providers.xml" );
+-	d->exec();
++	KNS::ProviderLoader *provider = new KNS::ProviderLoader( this );
++	QObject::connect( provider, SIGNAL( providersLoaded(Provider::List*) ), downloadDialog, SLOT( slotProviders (Provider::List *) ) );
++	provider->load( "kopete/chatstyle", "http://download.kde.org/khotnewstuff/kopetestyles12-providers.xml" );
++	downloadDialog->exec();
+ }
+ 
+ // Reimplement Kopete::Contact and its abstract method
++// This is for style preview.
+ class FakeContact : public Kopete::Contact
+ {
+ public:
+-	FakeContact ( const QString &id, Kopete::MetaContact *mc ) : Kopete::Contact( 0, id, mc ) {}
++	FakeContact (Kopete::Account *account, const QString &id, Kopete::MetaContact *mc ) : Kopete::Contact( account, id, mc ) {}
+ 	virtual Kopete::ChatSession *manager(Kopete::Contact::CanCreateFlags /*c*/) { return 0L; }
+ 	virtual void slotUserInfo() {};
+ };
+ 
+-static QString sampleConversationXML()
++// This is for style preview.
++class FakeProtocol : public Kopete::Protocol
+ {
+-	//Kopete::MetaContact jackMC;
+-	FakeContact myself( i18n( "Myself" ), 0 );
+-	FakeContact jack( i18n( "Jack" ), /*&jackMC*/ 0 );
++public:
++FakeProtocol( KInstance *instance, QObject *parent, const char *name ) : Kopete::Protocol(instance, parent, name){}
++Kopete::Account* createNewAccount( const QString &/*accountId*/ ){return 0L;}
++AddContactPage* createAddContactWidget( QWidget */*parent*/, Kopete::Account */*account*/){return 0L;}
++KopeteEditAccountWidget* createEditAccountWidget( Kopete::Account */*account*/, QWidget */*parent */){return 0L;}
++};
+ 
+-	Kopete::Message msgIn  ( &jack,   &myself, i18n( "Hello, this is an incoming message :-)" ), Kopete::Message::Inbound );
+-	Kopete::Message msgOut ( &myself, &jack,   i18n( "Ok, this is an outgoing message" ), Kopete::Message::Outbound );
+-	Kopete::Message msgCol ( &jack,   &myself, i18n( "Here is an incoming colored message" ), Kopete::Message::Inbound );
++// This is for style preview.
++class FakeAccount : public Kopete::Account
++{
++public:
++FakeAccount(Kopete::Protocol *parent, const QString &accountID, const char *name) : Kopete::Account(parent, accountID, name){}
++~FakeAccount()
++{}
++bool createContact( const QString &/*contactId*/, Kopete::MetaContact */*parentContact*/ ){return true;}
++void connect( const Kopete::OnlineStatus& /*initialStatus*/){}
++void disconnect(){}
++void setOnlineStatus( const Kopete::OnlineStatus& /*status*/ , const QString &/*reason*/){}
++};
++
++void AppearanceConfig::createPreviewChatSession()
++{
++	d->previewProtocol = new FakeProtocol( new KInstance(QCString("kopete-preview-chatwindowstyle")), 0L, "kopete-preview-chatwindowstyle");
++	d->previewAccount = new FakeAccount(d->previewProtocol, QString("previewaccount"), 0);
++
++	// Create fake meta/contacts
++	d->myselfMetaContact = new Kopete::MetaContact();
++	d->myself = new FakeContact(d->previewAccount, i18n("This is the myself preview contact id", "myself at preview"), d->myselfMetaContact);
++	d->myself->setNickName(i18n("This is the myself preview contact nickname", "Myself"));
++	d->jackMetaContact = new Kopete::MetaContact();
++	d->jack = new FakeContact(d->previewAccount, i18n("This is the other preview contact id", "jack at preview"), d->jackMetaContact);
++	d->jack->setNickName(i18n("This is the other preview contact nickname", "Jack"));
++	d->myselfMetaContact->setDisplayName(i18n("Myself"));
++	d->myselfMetaContact->setDisplayNameSource(Kopete::MetaContact::SourceCustom);
++	d->jackMetaContact->setDisplayName(i18n("Jack"));
++	d->jackMetaContact->setDisplayNameSource(Kopete::MetaContact::SourceCustom);
++
++	Kopete::ContactPtrList contactList;
++	contactList.append(d->jack);
++	// Create fakeChatSession
++	d->previewChatSession = Kopete::ChatSessionManager::self()->create(d->myself, contactList, 0);
++	d->previewChatSession->setDisplayName("Preview Session");
++}
++
++void AppearanceConfig::createPreviewMessages()
++{
++	Kopete::Message msgIn( d->jack,d->myself, i18n( "Hello, this is an incoming message :-)" ), Kopete::Message::Inbound );
++	Kopete::Message msgIn2( d->jack, d->myself, i18n( "Hello, this is an incoming consecutive message." ), Kopete::Message::Inbound );
++
++	Kopete::Message msgOut( d->myself, d->jack, i18n( "Ok, this is an outgoing message" ), Kopete::Message::Outbound );
++	Kopete::Message msgOut2( d->myself, d->jack, i18n( "Ok, a outgoing consecutive message." ), Kopete::Message::Outbound );
++
++	Kopete::Message msgCol( d->jack, d->myself, i18n( "Here is an incoming colored message" ), Kopete::Message::Inbound );
+ 	msgCol.setFg( QColor( "DodgerBlue" ) );
+ 	msgCol.setBg( QColor( "LightSteelBlue" ) );
+-	Kopete::Message msgInt ( &jack,   &myself, i18n( "This is an internal message" ), Kopete::Message::Internal );
+-	Kopete::Message msgAct ( &jack,   &myself, i18n( "performed an action" ), Kopete::Message::Inbound,
++	Kopete::Message msgInt( d->jack, d->myself, i18n( "This is an internal message" ), Kopete::Message::Internal );
++	Kopete::Message msgAct( d->jack, d->myself, i18n( "performed an action" ), Kopete::Message::Inbound,
+ 				  Kopete::Message::PlainText, QString::null, Kopete::Message::TypeAction );
+-	Kopete::Message msgHigh( &jack,   &myself, i18n( "This is a highlighted message" ), Kopete::Message::Inbound );
++	Kopete::Message msgHigh( d->jack, d->myself, i18n( "This is a highlighted message" ), Kopete::Message::Inbound );
+ 	msgHigh.setImportance( Kopete::Message::Highlight );
+-	Kopete::Message msgBye ( &myself, &jack,   i18n( "Bye" ), Kopete::Message::Outbound );
++	// This is a UTF-8 string btw.
++	Kopete::Message msgRightToLeft(d->myself, d->jack, i18n("This special UTF-8 string is to test if the style support Right-to-Left language display.", "הודעות טקסט"), Kopete::Message::Outbound);
++	Kopete::Message msgBye ( d->myself, d->jack,   i18n( "Bye" ), Kopete::Message::Outbound );
+ 
+-	return QString::fromLatin1( "<document>" ) + msgIn.asXML().toString() + msgOut.asXML().toString()
+-	       + msgCol.asXML().toString() + msgInt.asXML().toString() + msgAct.asXML().toString()
+-	       + msgHigh.asXML().toString() + msgBye.asXML().toString() + QString::fromLatin1( "</document>" );
++	// Add the messages to ChatMessagePart
++	d->preview->appendMessage(msgIn);
++	d->preview->appendMessage(msgIn2);
++	d->preview->appendMessage(msgOut);
++	d->preview->appendMessage(msgOut2);
++	d->preview->appendMessage(msgCol);
++	d->preview->appendMessage(msgInt);
++	d->preview->appendMessage(msgAct);
++	d->preview->appendMessage(msgHigh);
++	d->preview->appendMessage(msgRightToLeft);
++	d->preview->appendMessage(msgBye);
+ }
+ 
+-void AppearanceConfig::slotUpdatePreview()
++void AppearanceConfig::slotUpdateChatPreview()
+ {
+-	if(loading)
++	if(d->loading || !d->currentStyle)
+ 		return;
+ 
+-	QListBoxItem *style = mPrfsChatWindow->styleList->selectedItem();
+-	if( style && style->text() != currentStyle )
+-	{
+-		//FIXME: should be using a ChatMessagePart
+-		preview->begin();
+-		preview->write( QString::fromLatin1(
+-			"<html><head><style>"
+-			"body{ font-family:%1;color:%2; }"
+-			"td{ font-family:%3;color:%4; }"
+-			".highlight{ color:%5;background-color:%6 }"
+-			"</style></head>"
+-			"<body bgcolor=\"%7\" vlink=\"%8\" link=\"%9\">"
+-		).arg( mPrfsColors->fontFace->font().family() ).arg( mPrfsColors->textColor->color().name() )
+-			.arg( mPrfsColors->fontFace->font().family() ).arg( mPrfsColors->textColor->color().name() )
+-			.arg( mPrfsColors->foregroundColor->color().name() ).arg( mPrfsColors->backgroundColor->color().name() )
+-			.arg( mPrfsColors->bgColor->color().name() ).arg( mPrfsColors->linkColor->color().name() )
+-			.arg( mPrfsColors->linkColor->color().name() ) );
++	// Update the preview
++	d->preview->setStyle(d->currentStyle);
+ 
+-		QString stylePath = itemMap[ style ];
+-		d->xsltParser->setXSLT( fileContents(stylePath) );
+-		preview->write( d->xsltParser->transform( sampleConversationXML() ) );
+-		preview->write( QString::fromLatin1( "</body></html>" ) );
+-		preview->end();
+-
+-		emitChanged();
+-	}
++	emitChanged();
+ }
+ 
+-QString AppearanceConfig::fileContents( const QString &path )
+-{
+- 	QString contents;
+-	QFile file( path );
+-	if ( file.open( IO_ReadOnly ) )
+-	{
+-		QTextStream stream( &file );
+-		contents = stream.read();
+-		file.close();
+-	}
+-
+-	return contents;
+-}
+-
+ void AppearanceConfig::emitChanged()
+ {
+ 	emit changed( true );
+ }
+ 
+-void AppearanceConfig::installNewTheme()
++void AppearanceConfig::installEmoticonTheme()
+ {
+ 	KURL themeURL = KURLRequesterDlg::getURL(QString::null, this,
+ 			i18n("Drag or Type Emoticon Theme URL"));
+@@ -1011,9 +821,9 @@
+ 	updateEmoticonlist();
+ }
+ 
+-void AppearanceConfig::removeSelectedTheme()
++void AppearanceConfig::removeSelectedEmoticonTheme()
+ {
+-	QListBoxItem *selected = mPrfsEmoticons->icon_theme_list->selectedItem();
++	QListBoxItem *selected = d->mPrfsEmoticons->icon_theme_list->selectedItem();
+ 	if(selected==0)
+ 		return;
+ 
+@@ -1035,7 +845,7 @@
+ 	updateEmoticonlist();
+ }
+ 
+-void AppearanceConfig::slotGetThemes()
++void AppearanceConfig::slotGetEmoticonThemes()
+ {
+ 	KConfig* config = KGlobal::config();
+ 	config->setGroup( "KNewStuff" );
+@@ -1044,8 +854,13 @@
+ 	config->writeEntry( "StandardResource", "emoticons" );
+ 	config->writeEntry( "Uncompress", "application/x-gzip" );
+ 	config->sync();
+-	
++
++#if ( KDE_IS_VERSION(3,3,90) )
+ 	KNS::DownloadDialog::open( "emoticons", i18n( "Get New Emoticons") );
++#else
++	KNS::DownloadDialog::open( i18n( "Get New Emoticons" ) );
++#endif
++
+ 	updateEmoticonlist();
+ }
+ 
+--- kopete/kopete/config/appearance/appearanceconfig_chatwindow.ui	(revision 568672)
++++ kopete/kopete/config/appearance/appearanceconfig_chatwindow.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>553</width>
+-            <height>356</height>
++            <width>462</width>
++            <height>454</height>
+         </rect>
+     </property>
+     <property name="sizePolicy">
+@@ -42,11 +42,11 @@
+             <property name="title">
+                 <string>Styles</string>
+             </property>
+-            <vbox>
++            <grid>
+                 <property name="name">
+                     <cstring>unnamed</cstring>
+                 </property>
+-                <widget class="QSplitter">
++                <widget class="QSplitter" row="0" column="0" rowspan="1" colspan="2">
+                     <property name="name">
+                         <cstring>splitter1</cstring>
+                     </property>
+@@ -94,7 +94,7 @@
+                         </property>
+                     </widget>
+                 </widget>
+-                <widget class="QLayoutWidget">
++                <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2">
+                     <property name="name">
+                         <cstring>layout10</cstring>
+                     </property>
+@@ -118,38 +118,14 @@
+                         </widget>
+                         <widget class="KPushButton">
+                             <property name="name">
+-                                <cstring>addButton</cstring>
++                                <cstring>installButton</cstring>
+                             </property>
+                             <property name="text">
+-                                <string>&amp;Add...</string>
++                                <string>&amp;Install...</string>
+                             </property>
+                         </widget>
+                         <widget class="KPushButton">
+                             <property name="name">
+-                                <cstring>importButton</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>&amp;Import...</string>
+-                            </property>
+-                        </widget>
+-                        <widget class="KPushButton">
+-                            <property name="name">
+-                                <cstring>copyButton</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>Cop&amp;y...</string>
+-                            </property>
+-                        </widget>
+-                        <widget class="KPushButton">
+-                            <property name="name">
+-                                <cstring>editButton</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>&amp;Edit...</string>
+-                            </property>
+-                        </widget>
+-                        <widget class="KPushButton">
+-                            <property name="name">
+                                 <cstring>deleteButton</cstring>
+                             </property>
+                             <property name="text">
+@@ -158,143 +134,56 @@
+                         </widget>
+                     </hbox>
+                 </widget>
+-            </vbox>
++                <widget class="QLabel" row="1" column="0">
++                    <property name="name">
++                        <cstring>textLabel1</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Style Variant:</string>
++                    </property>
++                </widget>
++                <widget class="QComboBox" row="1" column="1">
++                    <property name="name">
++                        <cstring>variantList</cstring>
++                    </property>
++                    <property name="sizePolicy">
++                        <sizepolicy>
++                            <hsizetype>7</hsizetype>
++                            <vsizetype>1</vsizetype>
++                            <horstretch>0</horstretch>
++                            <verstretch>0</verstretch>
++                        </sizepolicy>
++                    </property>
++                </widget>
++            </grid>
+         </widget>
+         <widget class="QButtonGroup">
+             <property name="name">
+-                <cstring>mTransparencyGroupBox</cstring>
++                <cstring>buttonGroup2</cstring>
+             </property>
+             <property name="title">
+-                <string>Chat Window Translucency</string>
++                <string>Display</string>
+             </property>
+             <grid>
+                 <property name="name">
+                     <cstring>unnamed</cstring>
+                 </property>
+-                <widget class="QSlider" row="3" column="1">
++                <widget class="QCheckBox" row="1" column="0">
+                     <property name="name">
+-                        <cstring>mTransparencyValue</cstring>
++                        <cstring>groupConsecutiveMessages</cstring>
+                     </property>
+-                    <property name="maxValue">
+-                        <number>100</number>
+-                    </property>
+-                    <property name="lineStep">
+-                        <number>1</number>
+-                    </property>
+-                    <property name="pageStep">
+-                        <number>5</number>
+-                    </property>
+-                    <property name="value">
+-                        <number>50</number>
+-                    </property>
+-                    <property name="tracking">
+-                        <bool>true</bool>
+-                    </property>
+-                    <property name="orientation">
+-                        <enum>Horizontal</enum>
+-                    </property>
+-                    <property name="tickmarks">
+-                        <enum>NoMarks</enum>
+-                    </property>
+-                    <property name="tickInterval">
+-                        <number>10</number>
+-                    </property>
+-                </widget>
+-                <widget class="QLayoutWidget" row="4" column="1">
+-                    <property name="name">
+-                        <cstring>layout1</cstring>
+-                    </property>
+-                    <hbox>
+-                        <property name="name">
+-                            <cstring>unnamed</cstring>
+-                        </property>
+-                        <property name="margin">
+-                            <number>0</number>
+-                        </property>
+-                        <widget class="QLabel">
+-                            <property name="name">
+-                                <cstring>txt0percent</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>0%</string>
+-                            </property>
+-                            <property name="alignment">
+-                                <set>AlignVCenter|AlignLeft</set>
+-                            </property>
+-                        </widget>
+-                        <widget class="QLabel">
+-                            <property name="name">
+-                                <cstring>txt50percent</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>50%</string>
+-                            </property>
+-                            <property name="alignment">
+-                                <set>AlignCenter</set>
+-                            </property>
+-                        </widget>
+-                        <widget class="QLabel">
+-                            <property name="name">
+-                                <cstring>txt100percent</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string>100%</string>
+-                            </property>
+-                            <property name="alignment">
+-                                <set>AlignVCenter|AlignRight</set>
+-                            </property>
+-                        </widget>
+-                    </hbox>
+-                </widget>
+-                <widget class="QLabel" row="3" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel2_3</cstring>
+-                    </property>
+                     <property name="text">
+-                        <string>&amp;Opacity:</string>
++                        <string>Group consecuti&amp;ve messages</string>
+                     </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>mTransparencyValue</cstring>
+-                    </property>
+                 </widget>
+-                <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+-                    <property name="name">
+-                        <cstring>mTransparencyEnabled</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Enable translucenc&amp;y</string>
+-                    </property>
+-                </widget>
+-                <widget class="KColorCombo" row="2" column="1">
+-                    <property name="name">
+-                        <cstring>mTransparencyTintColor</cstring>
+-                    </property>
+-                </widget>
+-                <widget class="QLabel" row="2" column="0">
+-                    <property name="name">
+-                        <cstring>textLabel1_4</cstring>
+-                    </property>
+-                    <property name="text">
+-                        <string>Ti&amp;nt color:</string>
+-                    </property>
+-                    <property name="buddy" stdset="0">
+-                        <cstring>mTransparencyTintColor</cstring>
+-                    </property>
+-                </widget>
+             </grid>
+         </widget>
+     </vbox>
+ </widget>
+ <tabstops>
+     <tabstop>styleList</tabstop>
+-    <tabstop>addButton</tabstop>
+-    <tabstop>importButton</tabstop>
+-    <tabstop>copyButton</tabstop>
+-    <tabstop>editButton</tabstop>
++    <tabstop>installButton</tabstop>
+     <tabstop>deleteButton</tabstop>
+-    <tabstop>mTransparencyEnabled</tabstop>
+-    <tabstop>mTransparencyTintColor</tabstop>
+-    <tabstop>mTransparencyValue</tabstop>
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
+@@ -302,9 +191,5 @@
+     <includehint>kpushbutton.h</includehint>
+     <includehint>kpushbutton.h</includehint>
+     <includehint>kpushbutton.h</includehint>
+-    <includehint>kpushbutton.h</includehint>
+-    <includehint>kpushbutton.h</includehint>
+-    <includehint>kpushbutton.h</includehint>
+-    <includehint>kcolorcombo.h</includehint>
+ </includehints>
+ </UI>
+--- kopete/kopete/config/appearance/Makefile.am	(revision 568672)
++++ kopete/kopete/config/appearance/Makefile.am	(revision 586398)
+@@ -1,6 +1,6 @@
+ METASOURCES = AUTO
+ AM_CPPFLAGS = $(KOPETE_INCLUDES) -I$(top_srcdir)/kopete/libkopete/private \
+-	$(KOPETE_COMPAT_INCLUDES) $(all_includes)
++	-I$(top_srcdir)/kopete/kopete/chatwindow $(KOPETE_COMPAT_INCLUDES) $(all_includes)
+ 
+ kde_module_LTLIBRARIES = kcm_kopete_appearanceconfig.la
+ 
+@@ -10,7 +10,8 @@
+ 
+ kcm_kopete_appearanceconfig_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) \
+ 	$(all_libraries)
+-kcm_kopete_appearanceconfig_la_LIBADD = ../../../libkopete/libkopete.la \
++kcm_kopete_appearanceconfig_la_LIBADD = ../../../libkopete/libkopete.la  \
++	../../../kopete/chatwindow/libkopetechatwindow.la \
+ 	-lktexteditor $(LIB_KOPETECOMPAT) $(LIB_KUTILS) $(LIB_KNEWSTUFF)
+ 
+ service_DATA = kopete_appearanceconfig.desktop
+--- kopete/kopete/config/appearance/appearanceconfig.h	(revision 568672)
++++ kopete/kopete/config/appearance/appearanceconfig.h	(revision 586398)
+@@ -2,8 +2,10 @@
+     appearanceconfig.h  -  Kopete Look Feel Config
+ 
+     Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan at kde.org>
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
+ 
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
++
+     *************************************************************************
+     *                                                                       *
+     * This program is free software; you can redistribute it and/or modify  *
+@@ -21,32 +23,9 @@
+ #include <qptrlist.h>
+ #include <qmap.h>
+ 
+-class QFrame;
+-class QTabWidget;
+-class QCheckBox;
+-class KListBox;
+-class KTextEdit;
+-class KHTMLPart;
+-class StyleEditDialog;
+-class QListBoxItem;
+-
+-class AppearanceConfig_Emoticons;
+-class AppearanceConfig_ChatWindow;
+-class AppearanceConfig_Colors;
+-class AppearanceConfig_ContactList;
+-
+-class KopeteAppearanceConfigPrivate;
+-
+-namespace KTextEditor
+-{
+-	class View;
+-	class Document;
+-}
+-
+-typedef QMap<QString,QString> KopeteChatStyleMap;
+-
+ /**
+  * @author Duncan Mac-Vicar P. <duncan at kde.org>
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
+  */
+ class AppearanceConfig : public KCModule
+ {
+@@ -63,54 +42,29 @@
+ 
+ private slots:
+ 	void slotSelectedEmoticonsThemeChanged();
+-	void slotTransparencyChanged(bool);
+-	void slotUpdatePreview();
++	void slotUpdateChatPreview();
+ 	void slotHighlightChanged();
+ 	void slotChangeFont();
+-	void slotAddStyle();
+-	void slotEditStyle();
+-	void slotDeleteStyle();
+-	void slotImportStyle();
+-	void slotCopyStyle();
+-	void slotStyleModified(const QString &);
+-	void slotStyleSelected();
++	void slotInstallChatStyle();
++	void slotDeleteChatStyle();
++	void slotChatStyleSelected();
++	void slotChatStyleVariantSelected(const QString &variantName);
+ 	void slotEditTooltips();
+ 	void emitChanged();
+-	void installNewTheme();
+-	void removeSelectedTheme();
+-	void slotGetThemes();
+-	void slotGetStyles();
++	void installEmoticonTheme();
++	void removeSelectedEmoticonTheme();
++	void slotGetEmoticonThemes();
++	void slotGetChatStyles();
++	void slotLoadChatStyles();
+ 	void updateEmoticonsButton(bool);
+ private:
+-	void updateHighlight();
+-	QString fileContents(const QString &path);
+-	bool addStyle(const QString &styleName, const QString &xslString);
+ 	void updateEmoticonlist();
+-	void loadStyles();
+-
++	void createPreviewChatSession();
++	void createPreviewMessages();
++	
+ private:
+-	QTabWidget* mAppearanceTabCtl;
+-
+-	// Widgets for Chat TAB
+-	KHTMLPart *preview;
+-	KTextEditor::Document* editDocument;
+-
+-	// All other TABs have their own ui-file
+-	AppearanceConfig_Emoticons *mPrfsEmoticons;
+-	AppearanceConfig_ChatWindow *mPrfsChatWindow;
+-	AppearanceConfig_Colors *mPrfsColors;
+-	AppearanceConfig_ContactList *mPrfsContactList;
+-
+-	// Vars used in ChatWindow TAB
+-	StyleEditDialog *styleEditor;
+-	QListBoxItem *editedItem;
+-	QMap<QListBoxItem*,QString> itemMap;
+-	QString currentStyle;
+-	bool loading;
+-	bool styleChanged;
+-	bool m_allowDownloadTheme;
+-
+-	KopeteAppearanceConfigPrivate *d;
++	class Private;
++	Private *d;
+ };
+ #endif
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/config/behavior/kopete_behaviorconfig.desktop	(revision 568672)
++++ kopete/kopete/config/behavior/kopete_behaviorconfig.desktop	(revision 586398)
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Icon=package_settings
++Icon=configure
+ Type=Service
+ ServiceTypes=KCModule
+ 
+--- kopete/kopete/config/behavior/behaviorconfig_events.ui	(revision 568672)
++++ kopete/kopete/config/behavior/behaviorconfig_events.ui	(revision 586398)
+@@ -8,8 +8,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>421</width>
+-            <height>378</height>
++            <width>427</width>
++            <height>386</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -35,7 +35,7 @@
+                         <cstring>mTrayflashNotifyChk</cstring>
+                     </property>
+                     <property name="text">
+-                        <string>&amp;Flash system tray</string>
++                        <string>Flash s&amp;ystem tray</string>
+                     </property>
+                     <property name="toolTip" stdset="0">
+                         <string>Flash the system tray icon on an incoming message</string>
+@@ -93,7 +93,7 @@
+                         <cstring>mBalloonNotifyChk</cstring>
+                     </property>
+                     <property name="text">
+-                        <string>Show &amp;bubble</string>
++                        <string>Sho&amp;w bubble</string>
+                     </property>
+                     <property name="toolTip" stdset="0">
+                         <string>Show a bubble on an incoming message</string>
+@@ -146,6 +146,90 @@
+                         </widget>
+                     </hbox>
+                 </widget>
++                <widget class="QLayoutWidget">
++                    <property name="name">
++                        <cstring>layout7</cstring>
++                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer7</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Fixed</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>16</width>
++                                    <height>16</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="QCheckBox">
++                            <property name="name">
++                                <cstring>mCloseBalloonChk</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="text">
++                                <string>Close &amp;bubble automatically after</string>
++                            </property>
++                            <property name="checked">
++                                <bool>false</bool>
++                            </property>
++                            <property name="toolTip" stdset="0">
++                                <string>Automatically close bubble after fixed amount of time</string>
++                            </property>
++                            <property name="whatsThis" stdset="0">
++                                <string>Bubbles will automatically be closed after a fixed amount of time. A closed one will be replaced by a new one if another message is waiting.</string>
++                            </property>
++                        </widget>
++                        <widget class="QSpinBox">
++                            <property name="name">
++                                <cstring>mBalloonCloseDelay</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="suffix">
++                                <string> Sec</string>
++                            </property>
++                            <property name="maxValue">
++                                <number>120</number>
++                            </property>
++                            <property name="minValue">
++                                <number>1</number>
++                            </property>
++                            <property name="value">
++                                <number>30</number>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer6</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>70</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </hbox>
++                </widget>
+                 <widget class="QCheckBox">
+                     <property name="name">
+                         <cstring>mQueueOnlyHighlightedMessagesInGroupChatsChk</cstring>
+@@ -168,10 +252,10 @@
+                         <string>Exclude messages in chats on current des&amp;ktop</string>
+                     </property>
+                     <property name="toolTip" stdset="0">
+-                        <string>Do not notify messages in chat windows on current desktop</string>
++                        <string>Do not display notification for messages in chat windows on current desktop</string>
+                     </property>
+                     <property name="whatsThis" stdset="0">
+-                        <string>Notify only unread messages in chat windows that are not on the current desktop.</string>
++                        <string>This option allows you to turn off the notification of events for chat windows that are on the current desktop. If this option is turned on, then only chat windows on different desktops than the current one will notify you that an event has occured. Otherwise, all chat windows will notify you that an event has occured.</string>
+                     </property>
+                 </widget>
+             </vbox>
+@@ -220,7 +304,7 @@
+                         <cstring>mTrayflashNotifySetCurrentDesktopToChatViewChk</cstring>
+                     </property>
+                     <property name="text">
+-                        <string>&amp;Switch to desktop containing chat on opening message</string>
++                        <string>Switch &amp;to desktop containing chat on opening message</string>
+                     </property>
+                     <property name="toolTip" stdset="0">
+                         <string>Switch to the desktop which contains the chat window for the sender when opening his/her message</string>
+@@ -277,6 +361,18 @@
+         <receiver>mBalloonNotifyIgnoreClosesChatViewChk</receiver>
+         <slot>setEnabled(bool)</slot>
+     </connection>
++    <connection>
++        <sender>mBalloonNotifyChk</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mCloseBalloonChk</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
++    <connection>
++        <sender>mBalloonNotifyChk</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mBalloonCloseDelay</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
+ </connections>
+ <tabstops>
+     <tabstop>mTrayflashNotifyChk</tabstop>
+--- kopete/kopete/config/behavior/behaviorconfig.cpp	(revision 568672)
++++ kopete/kopete/config/behavior/behaviorconfig.cpp	(revision 586398)
+@@ -19,11 +19,13 @@
+ #include "behaviorconfig_chat.h"
+ 
+ #include <qcheckbox.h>
++#include <qradiobutton.h>
+ #include <qlayout.h>
+ #include <qlabel.h>
+ #include <qhbuttongroup.h>
+ #include <qspinbox.h>
+ #include <qcombobox.h>
++#include <qradiobutton.h>
+ 
+ #include <kdebug.h>
+ #include <kplugininfo.h>
+@@ -32,11 +34,13 @@
+ #include <kgenericfactory.h>
+ #include <ktrader.h>
+ #include <kconfig.h>
++#include <klineedit.h>
+ 
+ #include "kopeteprefs.h"
+ #include "kopeteaway.h"
+ #include "kopeteawayconfigbase.h"
+ #include "kopetepluginmanager.h"
++#include "kopeteaway.h"
+ 
+ #include <qtabwidget.h>
+ 
+@@ -79,6 +83,8 @@
+ 		this, SLOT(slotSettingsChanged(bool)));
+ 	connect(mPrfsGeneral->mUseQueueChk, SIGNAL(toggled(bool)),
+ 		this, SLOT(slotSettingsChanged(bool)));
++	connect(mPrfsGeneral->mUseStackChk, SIGNAL(toggled(bool)),
++		this, SLOT(slotSettingsChanged(bool)));
+ 	connect(mPrfsGeneral->mQueueUnreadMessagesChk, SIGNAL(toggled(bool)),
+ 		this, SLOT(slotSettingsChanged(bool)));
+ 	connect(mPrfsGeneral->mAutoConnect, SIGNAL(toggled(bool)),
+@@ -96,6 +102,10 @@
+ 		this, SLOT(slotSettingsChanged(bool)));
+ 	connect(mPrfsEvents->mBalloonNotifyIgnoreClosesChatViewChk, SIGNAL(toggled(bool)),
+ 		this, SLOT(slotSettingsChanged(bool)));
++	connect(mPrfsEvents->mCloseBalloonChk, SIGNAL(toggled(bool)),
++		this, SLOT(slotSettingsChanged(bool)));
++	connect(mPrfsEvents->mBalloonCloseDelay, SIGNAL(valueChanged(int)),
++		this, SLOT(slotValueChanged(int)));
+ 	connect(mPrfsEvents->mTrayflashNotifyChk, SIGNAL(toggled(bool)),
+ 		this, SLOT(slotSettingsChanged(bool)));
+ 	connect(mPrfsEvents->mTrayflashNotifyLeftClickOpensMessageChk, SIGNAL(toggled(bool)),
+@@ -139,6 +149,12 @@
+ 		this, SLOT(slotSettingsChanged(bool)));
+ 	connect( mAwayConfigUI->mUseAutoAway, SIGNAL(toggled(bool)),
+ 		this, SLOT(slotSettingsChanged(bool)));
++	connect( mAwayConfigUI->mDisplayLastAwayMessage, SIGNAL(toggled(bool)),
++		this, SLOT(slotSettingsChanged(bool)));
++	connect( mAwayConfigUI->mDisplayCustomAwayMessage, SIGNAL(toggled(bool)),
++		this, SLOT(slotSettingsChanged(bool)));
++	connect( mAwayConfigUI->mAutoAwayMessageEdit, SIGNAL(textChanged(const QString&)),
++		this, SLOT(slotTextChanged(const QString&)));
+ }
+ 
+ void BehaviorConfig::save()
+@@ -152,6 +168,7 @@
+ 	p->setShowTray(mPrfsGeneral->mShowTrayChk->isChecked());
+ 	p->setStartDocked(mPrfsGeneral->mStartDockedChk->isChecked());
+ 	p->setUseQueue(mPrfsGeneral->mUseQueueChk->isChecked());
++	p->setUseStack(mPrfsGeneral->mUseStackChk->isChecked());
+ 	p->setQueueUnreadMessages(mPrfsGeneral->mQueueUnreadMessagesChk->isChecked());
+ 	p->setAutoConnect(mPrfsGeneral->mAutoConnect->isChecked());
+ 	p->setContactListMouseNavigation(mPrfsGeneral->mMouseNavigation->isChecked());
+@@ -161,6 +178,8 @@
+ 	p->setQueueOnlyMessagesOnAnotherDesktop(mPrfsEvents->mQueueOnlyMessagesOnAnotherDesktopChk->isChecked());
+ 	p->setBalloonNotify(mPrfsEvents->mBalloonNotifyChk->isChecked());
+ 	p->setBalloonNotifyIgnoreClosesChatView(mPrfsEvents->mBalloonNotifyIgnoreClosesChatViewChk->isChecked());
++	p->setBalloonClose(mPrfsEvents->mCloseBalloonChk->isChecked());
++	p->setBalloonDelay(mPrfsEvents->mBalloonCloseDelay->value());
+ 	p->setTrayflashNotify(mPrfsEvents->mTrayflashNotifyChk->isChecked());
+ 	p->setTrayflashNotifyLeftClickOpensMessage(mPrfsEvents->mTrayflashNotifyLeftClickOpensMessageChk->isChecked());
+ 	p->setTrayflashNotifySetCurrentDesktopToChatView(mPrfsEvents->mTrayflashNotifySetCurrentDesktopToChatViewChk->isChecked());
+@@ -176,7 +195,14 @@
+ 	config->writeEntry("Timeout", mAwayConfigUI->mAutoAwayTimeout->value() * 60);
+ 	config->writeEntry("GoAvailable", mAwayConfigUI->mGoAvailable->isChecked());
+ 	config->writeEntry("UseAutoAway", mAwayConfigUI->mUseAutoAway->isChecked() );
++	config->writeEntry("UseAutoAwayMessage", mAwayConfigUI->mDisplayCustomAwayMessage->isChecked() );
+ 	config->sync();
++	
++	// Save the auto away message, if defined
++	if( mAwayConfigUI->mDisplayCustomAwayMessage->isChecked() )
++	{
++		awayInstance->setAutoAwayMessage( mAwayConfigUI->mAutoAwayMessageEdit->text() );
++	}
+ 
+ 	// "Chat" TAB ===============================================================
+ 	p->setShowEvents(mPrfsChat->cb_ShowEventsChk->isChecked());
+@@ -198,11 +224,13 @@
+ //	kdDebug(14000) << k_funcinfo << "called" << endl;
+ 	KopetePrefs *p = KopetePrefs::prefs();
+ 	KConfig *config = KGlobal::config();
++	awayInstance = Kopete::Away::getInstance();
+ 
+ 	// "General" TAB ============================================================
+ 	mPrfsGeneral->mShowTrayChk->setChecked( p->showTray() );
+ 	mPrfsGeneral->mStartDockedChk->setChecked( p->startDocked() );
+ 	mPrfsGeneral->mUseQueueChk->setChecked( p->useQueue() );
++	mPrfsGeneral->mUseStackChk->setChecked( p->useStack() );
+ 	mPrfsGeneral->mQueueUnreadMessagesChk->setChecked ( p->queueUnreadMessages() );
+ 	mPrfsGeneral->mAutoConnect->setChecked( p->autoConnect() );
+ 	mPrfsGeneral->mMouseNavigation->setChecked( p->contactListMouseNavigation() );
+@@ -212,6 +240,8 @@
+ 	mPrfsEvents->mQueueOnlyMessagesOnAnotherDesktopChk->setChecked ( p->queueOnlyMessagesOnAnotherDesktop() );
+ 	mPrfsEvents->mBalloonNotifyChk->setChecked ( p->balloonNotify() );
+ 	mPrfsEvents->mBalloonNotifyIgnoreClosesChatViewChk->setChecked ( p->balloonNotifyIgnoreClosesChatView() );
++	mPrfsEvents->mCloseBalloonChk->setChecked( p->balloonClose() );
++	mPrfsEvents->mBalloonCloseDelay->setValue( p->balloonCloseDelay() );
+ 	mPrfsEvents->mTrayflashNotifyChk->setChecked ( p->trayflashNotify() );
+ 	mPrfsEvents->mTrayflashNotifyLeftClickOpensMessageChk->setChecked ( p->trayflashNotifyLeftClickOpensMessage() );
+ 	mPrfsEvents->mTrayflashNotifySetCurrentDesktopToChatViewChk->setChecked ( p->trayflashNotifySetCurrentDesktopToChatView() );
+@@ -226,7 +256,11 @@
+ 	mAwayConfigUI->mGoAvailable->setChecked(config->readBoolEntry("GoAvailable", true));
+ 	mAwayConfigUI->mUseAutoAway->setChecked(config->readBoolEntry("UseAutoAway", true));
+ 	mAwayConfigUI->rememberedMessages->setValue( p->rememberedMessages() );
++	mAwayConfigUI->mAutoAwayMessageEdit->setText( awayInstance->autoAwayMessage() );
+ 
++	// Always display the last away message by default
++	mAwayConfigUI->mDisplayCustomAwayMessage->setChecked(config->readBoolEntry("UseAutoAwayMessage", false));
++
+ 	// "Chat" TAB ===============================================================
+ 	mPrfsChat->cb_ShowEventsChk->setChecked(p->showEvents());
+ 	mPrfsChat->highlightEnabled->setChecked(p->highlightEnabled());
+@@ -235,7 +269,7 @@
+ 
+ 	mPrfsChat->mChatViewBufferSize->setValue(p->chatViewBufferSize());
+ 	mPrfsChat->truncateContactNameEnabled->setChecked(p->truncateContactNames());
+-	mPrfsChat->mMaxContactNameLength->setValue(p->maxContactNameLength());
++	mPrfsChat->mMaxContactNameLength->setValue(p->maxConactNameLength());
+ 
+ 
+ 	mPrfsChat->viewPlugin->clear();
+@@ -266,5 +300,10 @@
+ 	emit changed( true );
+ }
+ 
++void BehaviorConfig::slotTextChanged(const QString&)
++{
++	emit changed( true );
++}
++
+ #include "behaviorconfig.moc"
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/config/behavior/kopeteawayconfigbase.ui	(revision 568672)
++++ kopete/kopete/config/behavior/kopeteawayconfigbase.ui	(revision 586398)
+@@ -97,11 +97,11 @@
+                 <string>&lt;p&gt;If you check the &lt;i&gt;Use auto away&lt;/i&gt; checkbox, Kopete will automaticaly set you globaly away when the KDE screen saver start, or after the selected minutes of user inactivity (i.e no mouse move, or key pressed)&lt;/p&gt;
+ &lt;p&gt;Kopete will set you available again when you come back if you checked &lt;i&gt;Become available when detecting activity again&lt;/i&gt;&lt;/p&gt;</string>
+             </property>
+-            <grid>
++            <vbox>
+                 <property name="name">
+                     <cstring>unnamed</cstring>
+                 </property>
+-                <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="4">
++                <widget class="QCheckBox">
+                     <property name="name">
+                         <cstring>mUseAutoAway</cstring>
+                     </property>
+@@ -109,71 +109,171 @@
+                         <string>&amp;Use auto away</string>
+                     </property>
+                 </widget>
+-                <widget class="QLabel" row="1" column="0">
++                <widget class="QLayoutWidget">
+                     <property name="name">
+-                        <cstring>TextLabel2</cstring>
++                        <cstring>layout3</cstring>
+                     </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>TextLabel2</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="text">
++                                <string>Become away after</string>
++                            </property>
++                        </widget>
++                        <widget class="QSpinBox">
++                            <property name="name">
++                                <cstring>mAutoAwayTimeout</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="maxValue">
++                                <number>999</number>
++                            </property>
++                            <property name="minValue">
++                                <number>1</number>
++                            </property>
++                        </widget>
++                        <widget class="QLabel">
++                            <property name="name">
++                                <cstring>TextLabel3</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="text">
++                                <string>minutes of user inactivity</string>
++                            </property>
++                        </widget>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer7</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Expanding</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>81</width>
++                                    <height>20</height>
++                                </size>
++                            </property>
++                        </spacer>
++                    </hbox>
++                </widget>
++                <widget class="QCheckBox">
++                    <property name="name">
++                        <cstring>mGoAvailable</cstring>
++                    </property>
+                     <property name="enabled">
+                         <bool>false</bool>
+                     </property>
+                     <property name="text">
+-                        <string>Become away after</string>
++                        <string>Become available when detecting activity again</string>
+                     </property>
+                 </widget>
+-                <widget class="QSpinBox" row="1" column="1">
++            </vbox>
++        </widget>
++        <widget class="QButtonGroup">
++            <property name="name">
++                <cstring>autoAwayMessageGroup</cstring>
++            </property>
++            <property name="enabled">
++                <bool>false</bool>
++            </property>
++            <property name="title">
++                <string>Auto Away Message</string>
++            </property>
++            <vbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QRadioButton">
+                     <property name="name">
+-                        <cstring>mAutoAwayTimeout</cstring>
++                        <cstring>mDisplayLastAwayMessage</cstring>
+                     </property>
+                     <property name="enabled">
+                         <bool>false</bool>
+                     </property>
+-                    <property name="maxValue">
+-                        <number>999</number>
++                    <property name="text">
++                        <string>Display the last away message used</string>
+                     </property>
+-                    <property name="minValue">
+-                        <number>1</number>
++                    <property name="checked">
++                        <bool>true</bool>
+                     </property>
+                 </widget>
+-                <widget class="QLabel" row="1" column="2">
++                <widget class="QRadioButton">
+                     <property name="name">
+-                        <cstring>TextLabel3</cstring>
++                        <cstring>mDisplayCustomAwayMessage</cstring>
+                     </property>
+                     <property name="enabled">
+                         <bool>false</bool>
+                     </property>
+                     <property name="text">
+-                        <string>minutes of user inactivity</string>
++                        <string>Display the following away message:</string>
+                     </property>
+                 </widget>
+-                <spacer row="1" column="3">
++                <widget class="QLayoutWidget">
+                     <property name="name">
+-                        <cstring>spacer7</cstring>
++                        <cstring>layout3</cstring>
+                     </property>
+-                    <property name="orientation">
+-                        <enum>Horizontal</enum>
+-                    </property>
+-                    <property name="sizeType">
+-                        <enum>Expanding</enum>
+-                    </property>
+-                    <property name="sizeHint">
+-                        <size>
+-                            <width>81</width>
+-                            <height>20</height>
+-                        </size>
+-                    </property>
+-                </spacer>
+-                <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="4">
+-                    <property name="name">
+-                        <cstring>mGoAvailable</cstring>
+-                    </property>
+-                    <property name="enabled">
+-                        <bool>false</bool>
+-                    </property>
+-                    <property name="text">
+-                        <string>Become available when detecting activity again</string>
+-                    </property>
++                    <hbox>
++                        <property name="name">
++                            <cstring>unnamed</cstring>
++                        </property>
++                        <spacer>
++                            <property name="name">
++                                <cstring>spacer5_2_2</cstring>
++                            </property>
++                            <property name="orientation">
++                                <enum>Horizontal</enum>
++                            </property>
++                            <property name="sizeType">
++                                <enum>Fixed</enum>
++                            </property>
++                            <property name="sizeHint">
++                                <size>
++                                    <width>16</width>
++                                    <height>16</height>
++                                </size>
++                            </property>
++                        </spacer>
++                        <widget class="KLineEdit">
++                            <property name="name">
++                                <cstring>mAutoAwayMessageEdit</cstring>
++                            </property>
++                            <property name="enabled">
++                                <bool>false</bool>
++                            </property>
++                            <property name="sizePolicy">
++                                <sizepolicy>
++                                    <hsizetype>3</hsizetype>
++                                    <vsizetype>0</vsizetype>
++                                    <horstretch>0</horstretch>
++                                    <verstretch>0</verstretch>
++                                </sizepolicy>
++                            </property>
++                            <property name="minimumSize">
++                                <size>
++                                    <width>300</width>
++                                    <height>0</height>
++                                </size>
++                            </property>
++                        </widget>
++                    </hbox>
+                 </widget>
+-            </grid>
++            </vbox>
+         </widget>
+         <spacer>
+             <property name="name">
+@@ -188,7 +288,7 @@
+             <property name="sizeHint">
+                 <size>
+                     <width>20</width>
+-                    <height>70</height>
++                    <height>30</height>
+                 </size>
+             </property>
+         </spacer>
+@@ -219,6 +319,30 @@
+         <receiver>mGoAvailable</receiver>
+         <slot>setEnabled(bool)</slot>
+     </connection>
++    <connection>
++        <sender>mUseAutoAway</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mDisplayLastAwayMessage</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
++    <connection>
++        <sender>mUseAutoAway</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mDisplayCustomAwayMessage</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
++    <connection>
++        <sender>mDisplayCustomAwayMessage</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mAutoAwayMessageEdit</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
++    <connection>
++        <sender>mUseAutoAway</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>autoAwayMessageGroup</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
+ </connections>
+ <tabstops>
+     <tabstop>mUseAutoAway</tabstop>
+@@ -226,4 +350,7 @@
+     <tabstop>mGoAvailable</tabstop>
+ </tabstops>
+ <layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>klineedit.h</includehint>
++</includehints>
+ </UI>
+--- kopete/kopete/config/behavior/behaviorconfig.h	(revision 568672)
++++ kopete/kopete/config/behavior/behaviorconfig.h	(revision 586398)
+@@ -18,6 +18,11 @@
+ 
+ #include "kcmodule.h"
+ 
++namespace Kopete
++{
++class Away;
++}
++
+ class QFrame;
+ class QTabWidget;
+ 
+@@ -41,6 +46,7 @@
+ 		void slotSettingsChanged(bool);
+ 		void slotValueChanged(int);
+ 		void slotUpdatePluginLabel(int);
++		void slotTextChanged(const QString&);
+ 
+ 	private:
+ 		QTabWidget* mBehaviorTabCtl;
+@@ -49,6 +55,7 @@
+ 		BehaviorConfig_Chat *mPrfsChat;
+ 		KopeteAwayConfigBaseUI *mAwayConfigUI;
+ 		QValueList<KPluginInfo*> viewPlugins;
++		Kopete::Away* awayInstance;
+ };
+ #endif
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/config/behavior/behaviorconfig_general.ui	(revision 568672)
++++ kopete/kopete/config/behavior/behaviorconfig_general.ui	(revision 586398)
+@@ -9,7 +9,7 @@
+             <x>0</x>
+             <y>0</y>
+             <width>348</width>
+-            <height>268</height>
++            <height>302</height>
+         </rect>
+     </property>
+     <property name="caption">
+@@ -63,77 +63,91 @@
+                 </widget>
+             </vbox>
+         </widget>
+-        <widget class="QGroupBox">
++        <widget class="QButtonGroup">
+             <property name="name">
+-                <cstring>groupBox1</cstring>
++                <cstring>buttonGroup1</cstring>
+             </property>
+             <property name="title">
+-                <string>Miscellaneous</string>
++                <string>Message Handling</string>
+             </property>
+             <vbox>
+                 <property name="name">
+                     <cstring>unnamed</cstring>
+                 </property>
+-                <widget class="QCheckBox">
++                <widget class="QRadioButton">
+                     <property name="name">
++                        <cstring>mInstantMessageOpeningChk</cstring>
++                    </property>
++                    <property name="text">
++                        <string>Open messages instantl&amp;y</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Instantly open incoming messages</string>
++                    </property>
++                    <property name="whatsThis" stdset="0">
++                        <string>If there is no existing chat window a new window will be opened when a new message comes in. If there is already a chat window opened for the sender of the message it will be displayed there instantly.</string>
++                    </property>
++                </widget>
++                <widget class="QRadioButton">
++                    <property name="name">
+                         <cstring>mUseQueueChk</cstring>
+                     </property>
+                     <property name="text">
+                         <string>Use message &amp;queue</string>
+                     </property>
+                     <property name="toolTip" stdset="0">
+-                        <string>Use a message queue instead of instantly opening a chat window on incoming messages</string>
++                        <string>Use a message queue to store incoming messages</string>
+                     </property>
+                     <property name="whatsThis" stdset="0">
+-                        <string>Use a message for new incoming messages. New messages are messages that cannot be displayed in an already open chat window. Only queued messages trigger notification via bubble and flashing tray icon.</string>
++                        <string>Store new incoming messages in a message queue. New messages are messages that cannot be displayed in an already open chat window. Only queued or stacked messages trigger notification via bubble, a flashing tray icon, or both..</string>
+                     </property>
+                 </widget>
+-                <widget class="QLayoutWidget">
++                <widget class="QRadioButton">
+                     <property name="name">
+-                        <cstring>layout7</cstring>
++                        <cstring>mUseStackChk</cstring>
+                     </property>
+-                    <hbox>
+-                        <property name="name">
+-                            <cstring>unnamed</cstring>
+-                        </property>
+-                        <spacer>
+-                            <property name="name">
+-                                <cstring>spacer11</cstring>
+-                            </property>
+-                            <property name="orientation">
+-                                <enum>Horizontal</enum>
+-                            </property>
+-                            <property name="sizeType">
+-                                <enum>Fixed</enum>
+-                            </property>
+-                            <property name="sizeHint">
+-                                <size>
+-                                    <width>16</width>
+-                                    <height>16</height>
+-                                </size>
+-                            </property>
+-                        </spacer>
+-                        <widget class="QCheckBox">
+-                            <property name="name">
+-                                <cstring>mQueueUnreadMessagesChk</cstring>
+-                            </property>
+-                            <property name="enabled">
+-                                <bool>false</bool>
+-                            </property>
+-                            <property name="text">
+-                                <string>Queue &amp;unread messages</string>
+-                            </property>
+-                            <property name="toolTip" stdset="0">
+-                                <string>Also add unread messages to queue</string>
+-                            </property>
+-                            <property name="whatsThis" stdset="0">
+-                                <string>Unread messages are messages that will be displayed in an already opened but inactive chat window. Only incoming queued messages trigger notification via bubble and flashing tray icon. With this option disabled only new incoming messages are queued, i.e. messages that cannot be displayed in an already open chat window.</string>
+-                            </property>
+-                        </widget>
+-                    </hbox>
++                    <property name="text">
++                        <string>Use message stac&amp;k</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Use a message stack to store incoming messages</string>
++                    </property>
++                    <property name="whatsThis" stdset="0">
++                        <string>Store new incoming messages in a message stack. New messages are messages that cannot be displayed in an already open chat window. Only queued or stacked messages trigger notification via bubble and flashing tray.</string>
++                    </property>
+                 </widget>
+                 <widget class="QCheckBox">
+                     <property name="name">
++                        <cstring>mQueueUnreadMessagesChk</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>false</bool>
++                    </property>
++                    <property name="text">
++                        <string>Queue/stack &amp;unread messages</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Also add unread messages to queue/stack</string>
++                    </property>
++                    <property name="whatsThis" stdset="0">
++                        <string>Unread messages are messages that will be displayed in an already opened but inactive chat window. Only incoming queued messages trigger notification via the bubble, the flashing tray icon, or both. With this option disabled only new incoming messages are queued, i.e. messages that cannot be displayed in an already open chat window.</string>
++                    </property>
++                </widget>
++            </vbox>
++        </widget>
++        <widget class="QGroupBox">
++            <property name="name">
++                <cstring>groupBox2</cstring>
++            </property>
++            <property name="title">
++                <string>Miscellaneous</string>
++            </property>
++            <vbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="QCheckBox">
++                    <property name="name">
+                         <cstring>mAutoConnect</cstring>
+                     </property>
+                     <property name="text">
+@@ -194,6 +208,12 @@
+         <receiver>mQueueUnreadMessagesChk</receiver>
+         <slot>setEnabled(bool)</slot>
+     </connection>
++    <connection>
++        <sender>mUseStackChk</sender>
++        <signal>toggled(bool)</signal>
++        <receiver>mQueueUnreadMessagesChk</receiver>
++        <slot>setEnabled(bool)</slot>
++    </connection>
+ </connections>
+ <tabstops>
+     <tabstop>mShowTrayChk</tabstop>
+--- kopete/kopete/config/avdevice/avdeviceconfig.h	(revision 568672)
++++ kopete/kopete/config/avdevice/avdeviceconfig.h	(revision 586398)
+@@ -1,7 +1,7 @@
+ /*
+     avdeviceconfig.h  -  Kopete Video Device Configuration Panel
+ 
+-    Copyright (c) 2005 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
++    Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
+ 
+     Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -35,7 +35,7 @@
+ class AVDeviceConfig_AudioDevice;
+ 
+ /**
+- at author Cláudio da Silveira Pinheiro
++ at author Cl�dio da Silveira Pinheiro
+ */
+ class AVDeviceConfig : public KCModule
+ {
+@@ -61,6 +61,7 @@
+ 	void slotImageAutoBrightnessContrastChanged(bool);
+ 	void slotImageAutoColorCorrectionChanged(bool);
+ 	void slotImageAsMirrorChanged(bool);
++	void slotDeviceDisableMMapChanged(bool);
+ 	void slotDeviceWorkaroundBrokenDriverChanged(bool);
+ 	void slotUpdateImage();
+ private:
+@@ -69,7 +70,7 @@
+ 	AVDeviceConfig_AudioDevice  *mPrfsAudioDevice;
+ 	Kopete::AV::VideoDevicePool *mVideoDevicePool ;
+ 	QImage qimage;
+-	QPixmap qpixmap, m_video_image;
++	QPixmap qpixmap;
+ 	QTimer qtimer;
+ 	void setVideoInputParameters();
+ #ifdef HAVE_GL
+--- kopete/kopete/config/avdevice/avdeviceconfig_videoconfig.ui	(revision 568672)
++++ kopete/kopete/config/avdevice/avdeviceconfig_videoconfig.ui	(revision 586398)
+@@ -442,123 +442,149 @@
+                 <attribute name="title">
+                     <string>Optio&amp;ns</string>
+                 </attribute>
+-                <vbox>
++                <grid>
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="QButtonGroup">
++                    <widget class="QLayoutWidget" row="0" column="0">
+                         <property name="name">
+-                            <cstring>ImageOptions</cstring>
++                            <cstring>layout8</cstring>
+                         </property>
+-                        <property name="sizePolicy">
+-                            <sizepolicy>
+-                                <hsizetype>5</hsizetype>
+-                                <vsizetype>3</vsizetype>
+-                                <horstretch>0</horstretch>
+-                                <verstretch>0</verstretch>
+-                            </sizepolicy>
+-                        </property>
+-                        <property name="title">
+-                            <string>Image options</string>
+-                        </property>
+                         <vbox>
+                             <property name="name">
+                                 <cstring>unnamed</cstring>
+                             </property>
+-                            <widget class="QCheckBox">
++                            <widget class="QButtonGroup">
+                                 <property name="name">
+-                                    <cstring>mImageAutoBrightnessContrast</cstring>
++                                    <cstring>ImageOptions</cstring>
+                                 </property>
+                                 <property name="sizePolicy">
+                                     <sizepolicy>
+-                                        <hsizetype>3</hsizetype>
+-                                        <vsizetype>1</vsizetype>
++                                        <hsizetype>5</hsizetype>
++                                        <vsizetype>3</vsizetype>
+                                         <horstretch>0</horstretch>
+                                         <verstretch>0</verstretch>
+                                     </sizepolicy>
+                                 </property>
+-                                <property name="text">
+-                                    <string>Au&amp;tomatic brightness/contrast adjustment</string>
++                                <property name="title">
++                                    <string>Image options</string>
+                                 </property>
++                                <vbox>
++                                    <property name="name">
++                                        <cstring>unnamed</cstring>
++                                    </property>
++                                    <widget class="QCheckBox">
++                                        <property name="name">
++                                            <cstring>mImageAutoBrightnessContrast</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>3</hsizetype>
++                                                <vsizetype>1</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="text">
++                                            <string>Au&amp;tomatic brightness/contrast adjustment</string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QCheckBox">
++                                        <property name="name">
++                                            <cstring>mImageAutoColorCorrection</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>3</hsizetype>
++                                                <vsizetype>1</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="text">
++                                            <string>Automatic color correction</string>
++                                        </property>
++                                        <property name="accel">
++                                            <string></string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QCheckBox">
++                                        <property name="name">
++                                            <cstring>mImageAsMirror</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>3</hsizetype>
++                                                <vsizetype>1</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="text">
++                                            <string>See preview mirrored</string>
++                                        </property>
++                                        <property name="accel">
++                                            <string></string>
++                                        </property>
++                                    </widget>
++                                </vbox>
+                             </widget>
+-                            <widget class="QCheckBox">
++                            <widget class="QButtonGroup">
+                                 <property name="name">
+-                                    <cstring>mImageAutoColorCorrection</cstring>
++                                    <cstring>deviceOptions</cstring>
+                                 </property>
+                                 <property name="sizePolicy">
+                                     <sizepolicy>
+-                                        <hsizetype>3</hsizetype>
++                                        <hsizetype>5</hsizetype>
+                                         <vsizetype>1</vsizetype>
+                                         <horstretch>0</horstretch>
+                                         <verstretch>0</verstretch>
+                                     </sizepolicy>
+                                 </property>
+-                                <property name="text">
+-                                    <string>Automatic color correction</string>
++                                <property name="title">
++                                    <string>Device options</string>
+                                 </property>
+-                                <property name="accel">
+-                                    <string></string>
+-                                </property>
++                                <grid>
++                                    <property name="name">
++                                        <cstring>unnamed</cstring>
++                                    </property>
++                                    <widget class="QCheckBox" row="1" column="0">
++                                        <property name="name">
++                                            <cstring>mDeviceWorkaroundBrokenDriver</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>3</hsizetype>
++                                                <vsizetype>1</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="text">
++                                            <string>&amp;Workaround broken driver</string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QCheckBox" row="0" column="0">
++                                        <property name="name">
++                                            <cstring>mDeviceDisableMMap</cstring>
++                                        </property>
++                                        <property name="sizePolicy">
++                                            <sizepolicy>
++                                                <hsizetype>3</hsizetype>
++                                                <vsizetype>1</vsizetype>
++                                                <horstretch>0</horstretch>
++                                                <verstretch>0</verstretch>
++                                            </sizepolicy>
++                                        </property>
++                                        <property name="text">
++                                            <string>Disable memor&amp;y mapping</string>
++                                        </property>
++                                    </widget>
++                                </grid>
+                             </widget>
+-                            <widget class="QCheckBox">
+-                                <property name="name">
+-                                    <cstring>mImageAsMirror</cstring>
+-                                </property>
+-                                <property name="sizePolicy">
+-                                    <sizepolicy>
+-                                        <hsizetype>3</hsizetype>
+-                                        <vsizetype>1</vsizetype>
+-                                        <horstretch>0</horstretch>
+-                                        <verstretch>0</verstretch>
+-                                    </sizepolicy>
+-                                </property>
+-                                <property name="text">
+-                                    <string>See preview mirrored</string>
+-                                </property>
+-                                <property name="accel">
+-                                    <string></string>
+-                                </property>
+-                            </widget>
+                         </vbox>
+                     </widget>
+-                    <widget class="QButtonGroup">
+-                        <property name="name">
+-                            <cstring>deviceOptions</cstring>
+-                        </property>
+-                        <property name="sizePolicy">
+-                            <sizepolicy>
+-                                <hsizetype>5</hsizetype>
+-                                <vsizetype>1</vsizetype>
+-                                <horstretch>0</horstretch>
+-                                <verstretch>0</verstretch>
+-                            </sizepolicy>
+-                        </property>
+-                        <property name="title">
+-                            <string>Device options</string>
+-                        </property>
+-                        <vbox>
+-                            <property name="name">
+-                                <cstring>unnamed</cstring>
+-                            </property>
+-                            <widget class="QCheckBox">
+-                                <property name="name">
+-                                    <cstring>mDeviceWorkaroundBrokenDriver</cstring>
+-                                </property>
+-                                <property name="sizePolicy">
+-                                    <sizepolicy>
+-                                        <hsizetype>3</hsizetype>
+-                                        <vsizetype>1</vsizetype>
+-                                        <horstretch>0</horstretch>
+-                                        <verstretch>0</verstretch>
+-                                    </sizepolicy>
+-                                </property>
+-                                <property name="text">
+-                                    <string>&amp;Workaround broken driver</string>
+-                                </property>
+-                            </widget>
+-                        </vbox>
+-                    </widget>
+-                </vbox>
++                </grid>
+             </widget>
+         </widget>
+         <widget class="QLayoutWidget" row="0" column="0">
+--- kopete/kopete/config/avdevice/kopete_avdeviceconfig.desktop	(revision 568672)
++++ kopete/kopete/config/avdevice/kopete_avdeviceconfig.desktop	(revision 586398)
+@@ -25,9 +25,11 @@
+ Name[es]=Dispositivos
+ Name[et]=Seadmed
+ Name[eu]=Dispositiboak
++Name[fi]=Laitteet
+ Name[fr]=Périphériques
+ Name[ga]=Gléasanna
+ Name[gl]=Dispositivos
++Name[he]=התקנים
+ Name[hu]=Eszközök
+ Name[id]=Divais
+ Name[is]=Tæki
+@@ -73,6 +75,7 @@
+ Comment[es]=Aquí­ puede configurar los dispositivos de sonido y audio de Kopete
+ Comment[et]=Siin saab muuta Kopete video- ja heliseadmete seadistusi
+ Comment[eu]=Hemen Kopete-ren bideo eta audio ezarpenak ezar ditzakezu
++Comment[fi]=Täältä voit muuttaa Kopeten video- ja äänilaitteiden asetuksia
+ Comment[fr]=Vous pouvez modifier ici la configuration des périphériques audio et vidéo de Kopete
+ Comment[gl]=Aquí podes modificar as opcións dos dispositivos de video e audio de Kopete
+ Comment[hu]=Itt lehet módosítani a Kopete video- és hangbeállításait
+--- kopete/kopete/config/avdevice/avdeviceconfig.cpp	(revision 568672)
++++ kopete/kopete/config/avdevice/avdeviceconfig.cpp	(revision 586398)
+@@ -1,7 +1,7 @@
+ /*
+     avdeviceconfig.cpp  -  Kopete Video Device Configuration Panel
+ 
+-    Copyright (c) 2005 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
++    Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro   <taupter at gmail.com>
+ 
+     Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -63,6 +63,7 @@
+ 	connect(mPrfsVideoDevice->mImageAutoBrightnessContrast,  SIGNAL(toggled(bool)),     this, SLOT(slotImageAutoBrightnessContrastChanged(bool)));
+ 	connect(mPrfsVideoDevice->mImageAutoColorCorrection,     SIGNAL(toggled(bool)),     this, SLOT(slotImageAutoColorCorrectionChanged(bool)));
+ 	connect(mPrfsVideoDevice->mImageAsMirror,                SIGNAL(toggled(bool)),     this, SLOT(slotImageAsMirrorChanged(bool)));
++	connect(mPrfsVideoDevice->mDeviceDisableMMap,            SIGNAL(toggled(bool)),     this, SLOT(slotDeviceDisableMMapChanged(bool)));
+ 	connect(mPrfsVideoDevice->mDeviceWorkaroundBrokenDriver, SIGNAL(toggled(bool)),     this, SLOT(slotDeviceWorkaroundBrokenDriverChanged(bool)));
+ 
+ 	// why is this here?
+@@ -74,6 +75,7 @@
+ 
+ 	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
+ 	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
++	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
+ 	setVideoInputParameters();
+ 
+ 	mVideoDevicePool->startCapturing();
+@@ -123,15 +125,19 @@
+ 
+ void AVDeviceConfig::setVideoInputParameters()
+ {
+-	mPrfsVideoDevice->mBrightnessSlider->setValue((int)(mVideoDevicePool->getBrightness()*65535));
+-	mPrfsVideoDevice->mContrastSlider->setValue((int)(mVideoDevicePool->getContrast()*65535));
+-	mPrfsVideoDevice->mSaturationSlider->setValue((int)(mVideoDevicePool->getSaturation()*65535));
+-	mPrfsVideoDevice->mWhitenessSlider->setValue((int)(mVideoDevicePool->getWhiteness()*65535));
+-	mPrfsVideoDevice->mHueSlider->setValue((int)(mVideoDevicePool->getHue()*65535));
+-	mPrfsVideoDevice->mImageAutoBrightnessContrast->setChecked(mVideoDevicePool->getAutoBrightnessContrast());
+-	mPrfsVideoDevice->mImageAutoColorCorrection->setChecked(mVideoDevicePool->getAutoColorCorrection());
+-	mPrfsVideoDevice->mImageAsMirror->setChecked(mVideoDevicePool->getImageAsMirror());
+-	mPrfsVideoDevice->mDeviceWorkaroundBrokenDriver->setChecked(mVideoDevicePool->getWorkaroundBrokenDriver());
++	if(mVideoDevicePool->size())
++	{
++		mPrfsVideoDevice->mBrightnessSlider->setValue((int)(mVideoDevicePool->getBrightness()*65535));
++		mPrfsVideoDevice->mContrastSlider->setValue((int)(mVideoDevicePool->getContrast()*65535));
++		mPrfsVideoDevice->mSaturationSlider->setValue((int)(mVideoDevicePool->getSaturation()*65535));
++		mPrfsVideoDevice->mWhitenessSlider->setValue((int)(mVideoDevicePool->getWhiteness()*65535));
++		mPrfsVideoDevice->mHueSlider->setValue((int)(mVideoDevicePool->getHue()*65535));
++		mPrfsVideoDevice->mImageAutoBrightnessContrast->setChecked(mVideoDevicePool->getAutoBrightnessContrast());
++		mPrfsVideoDevice->mImageAutoColorCorrection->setChecked(mVideoDevicePool->getAutoColorCorrection());
++		mPrfsVideoDevice->mImageAsMirror->setChecked(mVideoDevicePool->getImageAsMirror());
++		mPrfsVideoDevice->mDeviceDisableMMap->setChecked(mVideoDevicePool->getDisableMMap());
++		mPrfsVideoDevice->mDeviceWorkaroundBrokenDriver->setChecked(mVideoDevicePool->getWorkaroundBrokenDriver());
++	}
+ }
+ 
+ void AVDeviceConfig::slotDeviceKComboBoxChanged(int){
+@@ -157,6 +163,7 @@
+ 	if((newinput < mVideoDevicePool->inputs()) && ( newinput !=mVideoDevicePool->currentInput()))
+ 	{
+ 		mVideoDevicePool->selectInput(mPrfsVideoDevice->mInputKComboBox->currentItem());
++		mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
+ 		setVideoInputParameters();
+ 		emit changed( true );
+ 	}
+@@ -223,6 +230,12 @@
+ 	emit changed( true );
+ }
+ 
++void AVDeviceConfig::slotDeviceDisableMMapChanged(bool){
++	kdDebug() << "kopete:config (avdevice): slotDeviceDisableMMapChanged(" << mPrfsVideoDevice->mDeviceDisableMMap->isChecked() << ") called. " << endl;
++	mVideoDevicePool->setDisableMMap(mPrfsVideoDevice->mDeviceDisableMMap->isChecked());
++	emit changed( true );
++}
++
+ void AVDeviceConfig::slotUpdateImage()
+ {
+ 	mVideoDevicePool->getFrame();
+--- kopete/kopete/config/identity/kopeteidentityconfig.cpp	(revision 568672)
++++ kopete/kopete/config/identity/kopeteidentityconfig.cpp	(revision 586398)
+@@ -26,6 +26,7 @@
+ #include <qradiobutton.h>
+ #include <qcombobox.h>
+ #include <qapplication.h>
++#include <qbuffer.h>
+ 
+ // KDE includes
+ #include <kcombobox.h>
+@@ -41,6 +42,7 @@
+ #include <kurlrequester.h>
+ #include <kinputdialog.h>
+ #include <kpixmapregionselectordialog.h>
++#include <kmdcodec.h>
+ 
+ // KDE KIO includes
+ #include <kio/netaccess.h>
+@@ -121,7 +123,8 @@
+ 	d->m_view->buttonNewIdentity->setIconSet(SmallIconSet("new"));
+ 	d->m_view->buttonCopyIdentity->setIconSet(SmallIconSet("editcopy"));
+ 	d->m_view->buttonRenameIdentity->setIconSet(SmallIconSet("edit"));
+-	d->m_view->buttonRemoveIdentity->setIconSet(SmallIconSet("editdelete"));
++	d->m_view->buttonRemoveIdentity->setIconSet(SmallIconSet("delete_user"));
++	d->m_view->buttonClearPhoto->setIconSet(  SmallIconSet( QApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) );
+ 
+ 	load(); // Load Configuration
+ 
+@@ -133,6 +136,7 @@
+ 	connect(d->m_view->buttonRenameIdentity, SIGNAL(clicked()), this, SLOT(slotRenameIdentity()));
+ 	connect(d->m_view->buttonRemoveIdentity, SIGNAL(clicked()), this, SLOT(slotRemoveIdentity()));
+ 	connect(d->m_view->comboPhotoURL, SIGNAL(urlSelected(const QString& )), this, SLOT(slotChangePhoto(const QString& )));
++	connect(d->m_view->buttonClearPhoto, SIGNAL(clicked()), this, SLOT(slotClearPhoto()));
+ 
+ 	// Settings signal/slots
+ 	connect(d->m_view->radioNicknameContact, SIGNAL(toggled(bool )), this, SLOT(slotEnableAndDisableWidgets()));
+@@ -197,6 +201,8 @@
+ 		d->myself->setPhotoSourceContact(selectedPhotoSourceContact());
+ 		if(!d->m_view->comboPhotoURL->url().isEmpty())
+ 			d->myself->setPhoto(d->m_view->comboPhotoURL->url());
++		else
++			d->myself->setPhoto( KURL() );
+ 		d->myself->setPhotoSyncedWithKABC(d->m_view->checkSyncPhotoKABC->isChecked());
+ 	}
+ 	
+@@ -204,6 +210,9 @@
+ 	KopeteIdentityConfigPreferences::self()->setSelectedIdentity(d->selectedIdentity);
+ 	GlobalIdentitiesManager::self()->saveXML();
+ 
++	// (Re)made slot connections to apply Global Identity in protocols
++	Kopete::ContactList::self()->loadGlobalIdentity();
++
+ 	load();
+ }
+ 
+@@ -248,6 +257,8 @@
+ 	d->currentIdentity->setPhotoSourceContact(selectedPhotoSourceContact());
+ 	if(!d->m_view->comboPhotoURL->url().isEmpty())
+ 		d->currentIdentity->setPhoto(d->m_view->comboPhotoURL->url());
++	else
++		d->currentIdentity->setPhoto( KURL() );
+ 	d->currentIdentity->setPhotoSyncedWithKABC(d->m_view->checkSyncPhotoKABC->isChecked());
+ }
+ 
+@@ -373,6 +384,8 @@
+ 
+ 	if(!photo.isNull())
+ 		d->m_view->labelPhoto->setPixmap(QPixmap(photo.smoothScale(64, 92, QImage::ScaleMin)));
++	else
++		d->m_view->labelPhoto->setPixmap(QPixmap());
+ 
+ 	emit changed(true);
+ }
+@@ -445,6 +458,10 @@
+ 	if(renamedName.isEmpty() || !ok)
+ 		return;
+ 
++
++	if(renamedName.isEmpty())
++		return;
++
+ 	if(!GlobalIdentitiesManager::self()->isIdentityPresent(renamedName))
+ 	{
+ 		GlobalIdentitiesManager::self()->renameIdentity(d->selectedIdentity, renamedName);
+@@ -500,22 +517,55 @@
+ 
+ void KopeteIdentityConfig::slotChangePhoto(const QString &photoUrl)
+ {
+-	QString saveLocation = locateLocal("appdata", "globalidentitiespictures/"+d->selectedIdentity.replace(" ", "-")+".png");
+-
++	QString saveLocation;
++	
+ 	QImage photo(photoUrl);
+ 	// use KABC photo size 100x140
+-	photo = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap(photo), 100, 140, this );
++	photo = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap(photo), 96, 96, this );
+ 
+ 	if(!photo.isNull())
+ 	{
+-		if(photo.width() != 100 || photo.height() != 140)
++		if(photo.width() > 96 || photo.height() > 96)
+ 		{
+-			 if (photo.height() > photo.width())
+-				photo = photo.scaleHeight(140);
+-			else
+-				photo = photo.scaleWidth(100);
++			// Scale and crop the picture.
++			photo = photo.smoothScale( 96, 96, QImage::ScaleMin );
++			// crop image if not square
++			if(photo.width() < photo.height()) 
++				photo = photo.copy((photo.width()-photo.height())/2, 0, 96, 96);
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, 96, 96);
++
+ 		}
++		else if (photo.width() < 32 || photo.height() < 32)
++		{
++			// Scale and crop the picture.
++			photo = photo.smoothScale( 32, 32, QImage::ScaleMin );
++			// crop image if not square
++			if(photo.width() < photo.height())
++				photo = photo.copy((photo.width()-photo.height())/2, 0, 32, 32);
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, 32, 32);
++	
++		}
++		else if (photo.width() != photo.height())
++		{
++			if(photo.width() < photo.height())
++				photo = photo.copy((photo.width()-photo.height())/2, 0, photo.height(), photo.height());
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, photo.height(), photo.height());
++		}
+ 
++		// Use MD5 hash to save the filename, so no problems will occur with the filename because of non-ASCII characters.
++		// Bug 124175: My personnal picture doesn't appear cause of l10n
++		QByteArray tempArray;
++		QBuffer tempBuffer(tempArray);
++		tempBuffer.open( IO_WriteOnly );
++		photo.save(&tempBuffer, "PNG");
++		KMD5 context(tempArray);
++		// Save the image to a file.
++		saveLocation = context.hexDigest() + ".png";
++		saveLocation = locateLocal( "appdata", QString::fromUtf8("globalidentitiespictures/%1").arg( saveLocation ) );
++
+ 		if(!photo.save(saveLocation, "PNG"))
+ 		{
+ 			KMessageBox::sorry(this, 
+@@ -533,6 +583,12 @@
+ 	}
+ }
+ 
++void KopeteIdentityConfig::slotClearPhoto()
++{
++	d->m_view->comboPhotoURL->setURL( QString::null );
++	slotEnableAndDisableWidgets();
++}
++
+ void KopeteIdentityConfig::slotSettingsChanged()
+ {
+ 	emit changed(true);
+--- kopete/kopete/config/identity/kopeteidentityconfig.h	(revision 568672)
++++ kopete/kopete/config/identity/kopeteidentityconfig.h	(revision 586398)
+@@ -66,6 +66,7 @@
+ 
+ 	void slotChangeAddressee();
+ 	void slotChangePhoto(const QString &photoUrl);
++	void slotClearPhoto();
+ 
+ 	void slotSettingsChanged();
+ 
+--- kopete/kopete/config/identity/kopete_identityconfig.desktop	(revision 568672)
++++ kopete/kopete/config/identity/kopete_identityconfig.desktop	(revision 586398)
+@@ -24,9 +24,11 @@
+ Name[es]=Identidad
+ Name[et]=Identiteet
+ Name[eu]=Identitatea
++Name[fi]=Identiteetti
+ Name[fr]=Identité
+ Name[ga]=Aitheantas
+ Name[gl]=Indentidade
++Name[he]=חשבון
+ Name[hu]=Azonosító
+ Name[is]=Auðkenni
+ Name[it]=Identità
+@@ -63,9 +65,11 @@
+ Comment[es]=Aqui puede gestionar su identidad global
+ Comment[et]=Siin saad hallata oma globaalset identiteeti
+ Comment[eu]=Hemen zure identitate globala kudea dezakezu
++Comment[fi]=Täältä voit hallita globaalia identiteettiäsi
+ Comment[fr]=Vous pouvez gérer ici votre identité principale
+ Comment[ga]=Tig Leat d'Aitheantas a Láimhseáil Anseo
+ Comment[gl]=Aquí podes xestionar a súa identidade global
++Comment[he]=כאן באפשרותך לנהל את כל חשבונותיך
+ Comment[hu]=Itt lehet kezelni a globális azonosítókat
+ Comment[is]=Hér geturðu haldið utan um víðværa auðkennið þitt
+ Comment[it]=Qui puoi gestire la tua identità globale
+--- kopete/kopete/config/identity/kopeteidentityconfigbase.ui	(revision 568672)
++++ kopete/kopete/config/identity/kopeteidentityconfigbase.ui	(revision 586398)
+@@ -9,8 +9,8 @@
+         <rect>
+             <x>0</x>
+             <y>0</y>
+-            <width>618</width>
+-            <height>395</height>
++            <width>633</width>
++            <height>447</height>
+         </rect>
+     </property>
+     <vbox>
+@@ -217,7 +217,7 @@
+                     <cstring>tab</cstring>
+                 </property>
+                 <attribute name="title">
+-                    <string>Pho&amp;to</string>
++                    <string>P&amp;hoto</string>
+                 </attribute>
+                 <vbox>
+                     <property name="name">
+@@ -242,42 +242,40 @@
+                             </property>
+                             <widget class="QLayoutWidget">
+                                 <property name="name">
+-                                    <cstring>layout10</cstring>
++                                    <cstring>layout7</cstring>
+                                 </property>
+-                                <vbox>
++                                <grid>
+                                     <property name="name">
+                                         <cstring>unnamed</cstring>
+                                     </property>
+-                                    <widget class="QRadioButton">
++                                    <widget class="KURLComboRequester" row="1" column="0">
+                                         <property name="name">
+-                                            <cstring>radioPhotoCustom</cstring>
+-                                        </property>
+-                                        <property name="text">
+-                                            <string>Cus&amp;tom:</string>
+-                                        </property>
+-                                    </widget>
+-                                    <widget class="KURLComboRequester">
+-                                        <property name="name">
+                                             <cstring>comboPhotoURL</cstring>
+                                         </property>
+                                     </widget>
+-                                    <widget class="QRadioButton">
++                                    <widget class="KPushButton" row="1" column="1">
+                                         <property name="name">
+-                                            <cstring>radioPhotoKABC</cstring>
++                                            <cstring>buttonClearPhoto</cstring>
+                                         </property>
++                                        <property name="maximumSize">
++                                            <size>
++                                                <width>32</width>
++                                                <height>3232</height>
++                                            </size>
++                                        </property>
+                                         <property name="text">
+-                                            <string>Use a&amp;ddress book photo (needs address book link)</string>
++                                            <string></string>
+                                         </property>
+                                     </widget>
+-                                    <widget class="QRadioButton">
++                                    <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="2">
+                                         <property name="name">
+-                                            <cstring>radioPhotoContact</cstring>
++                                            <cstring>checkSyncPhotoKABC</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>U&amp;se photo from contact for global photo:</string>
++                                            <string>S&amp;ync address book photo with global photo</string>
+                                         </property>
+                                     </widget>
+-                                    <widget class="QComboBox">
++                                    <widget class="QComboBox" row="4" column="0" rowspan="1" colspan="2">
+                                         <property name="name">
+                                             <cstring>comboPhotoContact</cstring>
+                                         </property>
+@@ -290,15 +288,31 @@
+                                             </sizepolicy>
+                                         </property>
+                                     </widget>
+-                                    <widget class="QCheckBox">
++                                    <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+                                         <property name="name">
+-                                            <cstring>checkSyncPhotoKABC</cstring>
++                                            <cstring>radioPhotoCustom</cstring>
+                                         </property>
+                                         <property name="text">
+-                                            <string>S&amp;ync address book photo with global photo</string>
++                                            <string>Cus&amp;tom:</string>
+                                         </property>
+                                     </widget>
+-                                </vbox>
++                                    <widget class="QRadioButton" row="3" column="0" rowspan="1" colspan="2">
++                                        <property name="name">
++                                            <cstring>radioPhotoContact</cstring>
++                                        </property>
++                                        <property name="text">
++                                            <string>U&amp;se photo from contact for global photo:</string>
++                                        </property>
++                                    </widget>
++                                    <widget class="QRadioButton" row="2" column="0" rowspan="1" colspan="2">
++                                        <property name="name">
++                                            <cstring>radioPhotoKABC</cstring>
++                                        </property>
++                                        <property name="text">
++                                            <string>Use a&amp;ddress book photo (needs address book link)</string>
++                                        </property>
++                                    </widget>
++                                </grid>
+                             </widget>
+                             <widget class="QLayoutWidget">
+                                 <property name="name">
+@@ -521,6 +535,7 @@
+     <includehint>kurlrequester.h</includehint>
+     <includehint>kcombobox.h</includehint>
+     <includehint>kpushbutton.h</includehint>
++    <includehint>kpushbutton.h</includehint>
+     <includehint>klineedit.h</includehint>
+ </includehints>
+ </UI>
+--- kopete/kopete/chatwindow/kopetechatwindowstyle.cpp	(revision 0)
++++ kopete/kopete/chatwindow/kopetechatwindowstyle.cpp	(revision 586398)
+@@ -0,0 +1,287 @@
++ /*
++    kopetechatwindowstyle.cpp - A Chat Window Style.
++
++    Copyright (c) 2005      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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 "kopetechatwindowstyle.h"
++
++// Qt includes
++#include <qfile.h>
++#include <qdir.h>
++#include <qstringlist.h>
++#include <qtextstream.h>
++
++// KDE includes
++#include <kdebug.h>
++
++
++class ChatWindowStyle::Private
++{
++public:
++	QString stylePath;
++	StyleVariants variantsList;
++	QString baseHref;
++	QString currentVariantPath;
++
++	QString headerHtml;
++	QString footerHtml;
++	QString incomingHtml;
++	QString nextIncomingHtml;
++	QString outgoingHtml;
++	QString nextOutgoingHtml;
++	QString statusHtml;
++	QString actionIncomingHtml;
++	QString actionOutgoingHtml;
++};
++
++ChatWindowStyle::ChatWindowStyle(const QString &stylePath, int styleBuildMode)
++	: d(new Private)
++{
++	init(stylePath, styleBuildMode);
++}
++
++ChatWindowStyle::ChatWindowStyle(const QString &stylePath, const QString &variantPath, int styleBuildMode)
++	: d(new Private)
++{
++	d->currentVariantPath = variantPath;
++	init(stylePath, styleBuildMode);
++}
++
++void ChatWindowStyle::init(const QString &stylePath, int styleBuildMode)
++{
++	d->stylePath = stylePath;
++	d->baseHref = stylePath + QString::fromUtf8("/Contents/Resources/");
++	readStyleFiles();
++	if(styleBuildMode & StyleBuildNormal)
++	{
++		listVariants();
++	}
++}
++
++ChatWindowStyle::~ChatWindowStyle()
++{
++	kdDebug(14000) << k_funcinfo << endl;
++	delete d;
++}
++
++ChatWindowStyle::StyleVariants ChatWindowStyle::getVariants()
++{
++	// If the variantList is empty, list available variants.
++	if( d->variantsList.isEmpty() )
++	{
++		listVariants();
++	}
++	return d->variantsList;
++}
++
++QString ChatWindowStyle::getStylePath() const
++{
++	return d->stylePath;
++}
++
++QString ChatWindowStyle::getStyleBaseHref() const
++{
++	return d->baseHref;
++}
++
++QString ChatWindowStyle::getHeaderHtml() const
++{
++	return d->headerHtml;
++}
++
++QString ChatWindowStyle::getFooterHtml() const
++{
++	return d->footerHtml;
++}
++
++QString ChatWindowStyle::getIncomingHtml() const
++{
++	return d->incomingHtml;
++}
++
++QString ChatWindowStyle::getNextIncomingHtml() const
++{
++	return d->nextIncomingHtml;
++}
++
++QString ChatWindowStyle::getOutgoingHtml() const
++{
++	return d->outgoingHtml;
++}
++
++QString ChatWindowStyle::getNextOutgoingHtml() const
++{
++	return d->nextOutgoingHtml;
++}
++
++QString ChatWindowStyle::getStatusHtml() const
++{
++	return d->statusHtml;
++}
++
++QString ChatWindowStyle::getActionIncomingHtml() const
++{
++	return d->actionIncomingHtml;	
++}
++
++QString ChatWindowStyle::getActionOutgoingHtml() const
++{
++	return d->actionOutgoingHtml;
++}
++
++bool ChatWindowStyle::hasActionTemplate() const
++{
++	return ( !d->actionIncomingHtml.isEmpty() && !d->actionOutgoingHtml.isEmpty() );
++}
++
++void ChatWindowStyle::listVariants()
++{
++	QString variantDirPath = d->baseHref + QString::fromUtf8("Variants/");
++	QDir variantDir(variantDirPath);
++
++	QStringList variantList = variantDir.entryList("*.css");
++	QStringList::ConstIterator it, itEnd = variantList.constEnd();
++	for(it = variantList.constBegin(); it != itEnd; ++it)
++	{
++		QString variantName = *it, variantPath;
++		// Retrieve only the file name.
++		variantName = variantName.left(variantName.findRev("."));
++		// variantPath is relative to baseHref.
++		variantPath = QString("Variants/%1").arg(*it);
++		d->variantsList.insert(variantName, variantPath);
++	}
++}
++
++void ChatWindowStyle::readStyleFiles()
++{
++	QString headerFile = d->baseHref + QString("Header.html");
++	QString footerFile = d->baseHref + QString("Footer.html");
++	QString incomingFile = d->baseHref + QString("Incoming/Content.html");
++	QString nextIncomingFile = d->baseHref + QString("Incoming/NextContent.html");
++	QString outgoingFile = d->baseHref + QString("Outgoing/Content.html");
++	QString nextOutgoingFile = d->baseHref + QString("Outgoing/NextContent.html");
++	QString statusFile = d->baseHref + QString("Status.html");
++	QString actionIncomingFile = d->baseHref + QString("Incoming/Action.html");
++	QString actionOutgoingFile = d->baseHref + QString("Outgoing/Action.html");
++
++	QFile fileAccess;
++	// First load header file.
++	if( QFile::exists(headerFile) )
++	{
++		fileAccess.setName(headerFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->headerHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "Header HTML: " << d->headerHtml << endl;
++		fileAccess.close();
++	}
++	// Load Footer file
++	if( QFile::exists(footerFile) )
++	{
++		fileAccess.setName(footerFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->footerHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "Footer HTML: " << d->footerHtml << endl;
++		fileAccess.close();
++	}
++	// Load incoming file
++	if( QFile::exists(incomingFile) )
++	{
++		fileAccess.setName(incomingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->incomingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "Incoming HTML: " << d->incomingHtml << endl;
++		fileAccess.close();
++	}
++	// Load next Incoming file
++	if( QFile::exists(nextIncomingFile) )
++	{
++		fileAccess.setName(nextIncomingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->nextIncomingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "NextIncoming HTML: " << d->nextIncomingHtml << endl;
++		fileAccess.close();
++	}
++	// Load outgoing file
++	if( QFile::exists(outgoingFile) )
++	{
++		fileAccess.setName(outgoingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->outgoingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "Outgoing HTML: " << d->outgoingHtml << endl;
++		fileAccess.close();
++	}
++	// Load next outgoing file
++	if( QFile::exists(nextOutgoingFile) )
++	{
++		fileAccess.setName(nextOutgoingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->nextOutgoingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "NextOutgoing HTML: " << d->nextOutgoingHtml << endl;
++		fileAccess.close();
++	}
++	// Load status file
++	if( QFile::exists(statusFile) )
++	{
++		fileAccess.setName(statusFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->statusHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "Status HTML: " << d->statusHtml << endl;
++		fileAccess.close();
++	}
++	
++	// Load Action Incoming file
++	if( QFile::exists(actionIncomingFile) )
++	{
++		fileAccess.setName(actionIncomingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->actionIncomingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "ActionIncoming HTML: " << d->actionIncomingHtml << endl;
++		fileAccess.close();
++	}
++	// Load Action Outgoing file
++	if( QFile::exists(actionOutgoingFile) )
++	{
++		fileAccess.setName(actionOutgoingFile);
++		fileAccess.open(IO_ReadOnly);
++		QTextStream headerStream(&fileAccess);
++		headerStream.setEncoding(QTextStream::UnicodeUTF8);
++		d->actionOutgoingHtml = headerStream.read();
++		kdDebug(14000) << k_funcinfo << "ActionOutgoing HTML: " << d->actionOutgoingHtml << endl;
++		fileAccess.close();
++	}
++}
++
++void ChatWindowStyle::reload()
++{
++	d->variantsList.clear();
++	readStyleFiles();
++	listVariants();
++}
+--- kopete/kopete/chatwindow/kopetechatwindowstylemanager.h	(revision 0)
++++ kopete/kopete/chatwindow/kopetechatwindowstylemanager.h	(revision 586398)
+@@ -0,0 +1,147 @@
++ /*
++    kopetechatwindowstylemanager.h - Manager all chat window styles
++
++    Copyright (c) 2005      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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 KOPETECHATWINDOWSTYLEMANAGER_H
++#define KOPETECHATWINDOWSTYLEMANAGER_H
++
++#include <qobject.h>
++#include <qmap.h>
++#include <kfileitem.h>
++#include <kopete_export.h>
++
++class ChatWindowStyle;
++/**
++ * Sigleton class that handle Chat Window styles. 
++ * It use style absolute path to avoid unexpected behavior that could happen when using style name.
++ *
++ * It can install, delete styles. The styles are managed in a pool, they are only retrieved on demand.
++ *
++ * Use getStyleFromPool to retrieve a ChatWindowStyle instance. Do not delete the returned instance, it
++ * is handled by this class.
++ *
++ * When called the first time, it list all the available styles in $KDEDATADIR/kopete/styles and
++ * KDirWatch (via KDirLister) watch for new styles. 
++ *
++ * If you want to keep a trace of avaiable styles, connect to loadStylesFinished() signal. 
++ * It is called when KDirLister finish a job(ex: on new directory).
++ *
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
++class KOPETE_EXPORT ChatWindowStyleManager : public QObject
++{
++	Q_OBJECT
++public:
++	/**
++	 * StyleList typedef (a QMap)
++	 * key = Name of the style (currently the directory name)
++	 * value = Path to the style
++	 */
++	typedef QMap<QString, QString> StyleList;
++
++	/**
++	 * The StyleInstallStatus enum. It gives better return value for installStyle().
++	 * - StyleInstallOk : The install went fine.
++	 * - StyleNotValid : The archive didn't contain a valid Chat Window style.
++	 * - StyleNoDirectoryValid : It didn't find a suitable directory to install the theme.
++	 * - StyleCannotOpen : The archive couldn't be openned.
++	 * - StyleUnknow : Unknow error.
++	 */
++	enum StyleInstallStatus { StyleInstallOk = 0, StyleNotValid, StyleNoDirectoryValid, StyleCannotOpen, StyleUnknow };
++
++	/**
++	 * Destructor.
++	 */
++	~ChatWindowStyleManager();
++
++	/**
++	 * Singleton access to this class.
++	 * @return the single instance of this class.
++	 */
++	static ChatWindowStyleManager *self();
++
++	/**
++	 * List all availables styles.
++	 * Init KDirLister and thus KDirWatch that watch for new styles.
++	 */
++	void loadStyles();
++
++	/**
++	 * Get all available styles.
++	 */
++	StyleList getAvailableStyles();
++
++public slots:
++	/**
++	 * Install a new style into user style directory
++	 * Note that you must pass a path to a archive.
++	 *
++	 * @param styleBundlePath Path to the container file to install.
++	 * @return A status code from StyleInstallStatus enum.
++	 */
++	int installStyle(const QString &styleBundlePath);
++
++	/**
++	 * Remove a style from user style directory
++	 *
++	 * @param stylePath the path of the style to remove.
++	 * @return true if the deletion went without problems.
++	 */
++	bool removeStyle(const QString &stylePath);
++	
++	/**
++	 * Get a instance of a ChatWindowStyle from the pool.
++	 * If they are no instance for the specified style, it gets created.
++	 * DO NOT DELETE the resulting pointer, it is handled by this class.
++	 *
++	 * @param stylePath Path for the specified style. Name can be ambigous.
++	 * @return the instance of ChatWindow for the specified style. DO NOT DELETE IT.
++	 */
++	ChatWindowStyle *getStyleFromPool(const QString &stylePath);
++
++signals:
++	/**
++	 * This signal is emitted when all styles finished to list.
++	 * Used to inform and/or update GUI.
++	 */
++	void loadStylesFinished();
++
++private slots:
++	/**
++	 * KDirLister found new files.
++	 * @param dirList new files found.
++	 */
++	void slotNewStyles(const KFileItemList &dirList);
++	/**
++	 * KDirLister finished a job.
++	 * Emit loadStylesFinished() if they are no directory left in the stack.
++	 */
++	void slotDirectoryFinished();
++
++private:
++	/**
++	 * Private constructor(it's a singleton class)
++	 * Call loadStyles() to list all avaiable styles.
++	 */
++	ChatWindowStyleManager(QObject *parent = 0, const char *name = 0);
++
++	static ChatWindowStyleManager *s_self;
++
++	class Private;
++	Private *d;
++};
++
++#endif
+--- kopete/kopete/chatwindow/kopetechatwindow.rc	(revision 568672)
++++ kopete/kopete/chatwindow/kopetechatwindow.rc	(revision 586398)
+@@ -1,5 +1,5 @@
+ <!DOCTYPE kpartgui>
+-<kpartgui version="30" name="kopetechatwindow">
++<kpartgui version="33" name="kopetechatwindow">
+ 	<MenuBar>
+ 		<Menu noMerge="1" name="file">
+ 			<text>&amp;Chat</text>
+--- kopete/kopete/chatwindow/krichtexteditpart.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/krichtexteditpart.cpp	(revision 586398)
+@@ -74,7 +74,9 @@
+ 
+ void KopeteRichTextEditPart::slotSetRichTextEnabled( bool enable )
+ {
+-	if( enable )
++	m_richTextEnabled = enable && m_richTextAvailable;
++
++	if( m_richTextEnabled )
+ 	{
+ 		editor->setTextFormat( Qt::RichText );
+ 	}
+@@ -83,16 +85,16 @@
+ 		editor->setTextFormat( Qt::PlainText );
+ 	}
+ 
+-	m_richTextEnabled = enable;
+ 	emit toggleToolbar( buttonsEnabled() );
+ 
+ 	// Spellchecking disabled when using rich text because the
+ 	// text we were getting from widget was coloured HTML!
+-	editor->setCheckSpellingEnabled( !richTextEnabled() );
+-	checkSpelling->setEnabled( !richTextEnabled() );
++	editor->setCheckSpellingEnabled( !m_richTextEnabled );
++	checkSpelling->setEnabled( !m_richTextEnabled );
+ 
+ 	//Enable / disable buttons
+ 	updateActions();
++	enableRichText->setChecked( m_richTextEnabled );
+ }
+ 
+ void KopeteRichTextEditPart::checkToolbarEnabled()
+@@ -473,12 +475,12 @@
+ void KopeteRichTextEditPart::setBold( bool b )
+ {
+ 	mFont.setBold(b);
+-	if( m_capabilities & Kopete::Protocol::RichBFormatting || m_capabilities & Kopete::Protocol::BaseBFormatting ) 
++	if( m_capabilities & Kopete::Protocol::RichBFormatting || m_capabilities & Kopete::Protocol::BaseBFormatting )
+ 	{
+ 		if( m_richTextEnabled )
+ 			editor->setBold(b);
+-		else 
+-			editor->setFont(mFont);  
++		else
++			editor->setFont(mFont);
+ 	}
+ 	writeConfig();
+ }
+@@ -486,12 +488,12 @@
+ void KopeteRichTextEditPart::setItalic( bool b )
+ {
+ 	mFont.setItalic( b );
+-	if( m_capabilities & Kopete::Protocol::RichIFormatting ||  m_capabilities & Kopete::Protocol::BaseIFormatting ) 
++	if( m_capabilities & Kopete::Protocol::RichIFormatting ||  m_capabilities & Kopete::Protocol::BaseIFormatting )
+ 	{
+ 		if(m_richTextEnabled)
+ 			editor->setItalic(b);
+-		else 
+-			editor->setFont(mFont);  
++		else
++			editor->setFont(mFont);
+ 	}
+ 	writeConfig();
+ }
+@@ -503,8 +505,8 @@
+ 	{
+ 		if(m_richTextEnabled)
+ 			editor->setUnderline(b);
+-		else 
+-			editor->setFont(mFont);  
++		else
++			editor->setFont(mFont);
+ 	}
+ 	writeConfig();
+ }
+--- kopete/kopete/chatwindow/kopetechatwindowstyle.h	(revision 0)
++++ kopete/kopete/chatwindow/kopetechatwindowstyle.h	(revision 586398)
+@@ -0,0 +1,129 @@
++ /*
++    kopetechatwindowstyle.h - A Chat Window Style.
++
++    Copyright (c) 2005      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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 KOPETECHATWINDOWSTYLE_H
++#define KOPETECHATWINDOWSTYLE_H
++
++#include <qstring.h>
++#include <qmap.h>
++
++
++/**
++ * This class represent a single chat window style.
++ *
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
++class ChatWindowStyle
++{
++public:
++	/**
++	 * StyleVariants is a typedef to a QMap
++	 * key = Variant Name
++	 * value = Path to variant CSS file.
++	 * Path is relative to Ressources directory.
++	 */
++	typedef QMap<QString,QString> StyleVariants;
++
++	/**
++	 * This enum specifies the mode of the constructor
++	 * - StyleBuildFast : Build the style the fatest possible
++	 * - StyleBuildNormal : List all variants of this style. Require a async dir list.
++	 */
++	enum StyleBuildMode { StyleBuildFast, StyleBuildNormal};
++
++	/**
++	 * @brief Build a single chat window style.
++	 * 
++	 */
++	ChatWindowStyle(const QString &stylePath, int styleBuildMode = StyleBuildNormal);
++	ChatWindowStyle(const QString &stylePath, const QString &variantPath, int styleBuildMode = StyleBuildFast);
++	~ChatWindowStyle();
++
++	/**
++	 * Get the list of all variants for this theme.
++	 * If the variant aren't listed, it call the lister
++	 * before returning the list of the Variants.
++	 * If the variant are listed, it just return the cached
++	 * variant list.
++	 * @return the StyleVariants QMap.
++	 */
++	StyleVariants getVariants();
++
++	/**
++	 * Get the style path.
++	 * The style path points to the directory where the style is located.
++	 * ex: ~/.kde/share/apps/kopete/styles/StyleName/
++	 *
++	 * @return the style path based.
++	 */
++	QString getStylePath() const;
++
++	/**
++	 * Get the style ressource directory.
++	 * Ressources directory is the base where all CSS, HTML and images are located.
++	 *
++	 * Adium(and now Kopete too) style directories are disposed like this:
++	 * StyleName/
++	 *          Contents/
++	 *            Resources/
++	 *
++	 * @return the path to the the ressource directory.
++	 */
++	QString getStyleBaseHref() const;
++
++	QString getHeaderHtml() const;
++	QString getFooterHtml() const;
++	QString getIncomingHtml() const;
++	QString getNextIncomingHtml() const;
++	QString getOutgoingHtml() const;
++	QString getNextOutgoingHtml() const;
++	QString getStatusHtml() const;
++
++	QString getActionIncomingHtml() const;
++	QString getActionOutgoingHtml() const;
++
++	/**
++	 * Check if the style has the support for Kopete Action template (Kopete extension)
++	 * @return true if the style has Action template.
++	 */
++	bool hasActionTemplate() const;
++
++	/**
++	 * Reload style from disk.
++	 */
++	void reload();
++private:
++	/**
++	 * Read style HTML files from disk
++	 */
++	void readStyleFiles();
++
++	/**
++	 * Init this class
++	 */
++	void init(const QString &stylePath, int styleBuildMode);
++
++	/**
++	 * List available variants for the current style.
++	 */
++	void listVariants();
++
++private:
++	class Private;
++	Private *d;
++};
++
++#endif
+--- kopete/kopete/chatwindow/krichtexteditpart.h	(revision 568672)
++++ kopete/kopete/chatwindow/krichtexteditpart.h	(revision 586398)
+@@ -79,6 +79,7 @@
+ 
+ 		void checkToolbarEnabled();
+ 		void reloadConfig();
++		void slotSetRichTextEnabled( bool enable );
+ 
+ 	signals:
+ 		void toggleToolbar( bool enabled );
+@@ -101,8 +102,6 @@
+ 		void updateCharFmt();
+ 		void updateAligment();
+ 
+-		void slotSetRichTextEnabled( bool enable );
+-
+ 	private:
+ 		void readConfig();
+ 		void writeConfig();
+--- kopete/kopete/chatwindow/chatview.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/chatview.cpp	(revision 586398)
+@@ -192,11 +192,6 @@
+ 	return this;
+ }
+ 
+-KParts::Part *ChatView::part() const
+-{
+-	return editPart();
+-}
+-
+ bool ChatView::canSend()
+ {
+ 	return editPart()->canSend();
+@@ -536,8 +531,16 @@
+ 	for( ; it.current(); ++it )
+ 	{
+ 		Kopete::Contact *c = static_cast<Kopete::Contact*>( it.currentKey() );
+-		QString nick = c->property( Kopete::Global::Properties::self()->nickName() ).value().toString();
+-		typingList.append( c->metaContact() ? c->metaContact()->displayName() : ( nick.isEmpty() ? c->contactId() : nick ) );
++		QString nick;
++		if( c->metaContact() && c->metaContact() != Kopete::ContactList::self()->myself() )
++		{
++			nick = c->metaContact()->displayName();
++		}
++		else
++		{
++			nick = c->nickName();
++		}
++		typingList.append( nick );
+ 	}
+ 
+ 	// Update the status area
+@@ -594,11 +597,38 @@
+ 	}
+ }
+ 
++void ChatView::slotDisplayNameChanged( const QString &oldValue, const QString &newValue )
++{
++	if( KopetePrefs::prefs()->showEvents() )
++	{
++		if( oldValue != newValue )
++			sendInternalMessage( i18n( "%1 is now known as %2" ). arg( oldValue, newValue ) );
++	}
++}
++
+ void ChatView::slotContactAdded(const Kopete::Contact *contact, bool suppress)
+ {
+-	QString contactName = contact->property(Kopete::Global::Properties::self()->nickName()).value().toString();
+-	connect( contact, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ),
++	QString contactName;
++	// Myself metacontact is not a reliable source.
++	if( contact->metaContact() && contact->metaContact() != Kopete::ContactList::self()->myself() )
++	{
++		contactName = contact->metaContact()->displayName();
++	}
++	else
++	{
++		contactName = contact->nickName();
++	}
++
++	if( contact->metaContact() && contact->metaContact() != Kopete::ContactList::self()->myself() )
++	{
++		connect( contact->metaContact(), SIGNAL( displayNameChanged(const QString&, const QString&) ),
++			this, SLOT( slotDisplayNameChanged(const QString &, const QString &) ) );
++	}
++	else
++	{
++		connect( contact, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ),
+ 		this, SLOT( slotPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ) ) ;
++	}
+ 
+ 	if( !suppress && m_manager->members().count() > 1 )
+ 		sendInternalMessage(  i18n("%1 has joined the chat.").arg(contactName) );
+@@ -624,13 +654,29 @@
+ 	{
+ 		m_remoteTypingMap.remove( const_cast<Kopete::Contact *>( contact ) );
+ 
+-		QString contactName = contact->property(Kopete::Global::Properties::self()->nickName()).value().toString();
++		QString contactName;
++		if( contact->metaContact() && contact->metaContact() != Kopete::ContactList::self()->myself() )
++		{
++			contactName = contact->metaContact()->displayName();
++		}
++		else
++		{
++			contactName = contact->nickName();
++		}
+ 
+ 		// When the last person leaves, don't disconnect the signals, since we're in a one-to-one chat
+ 		if ( m_manager->members().count() > 0 )
+ 		{
+-			disconnect(contact,SIGNAL(propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & )),
++			if( contact->metaContact() )
++			{
++				disconnect( contact->metaContact(), SIGNAL( displayNameChanged(const QString&, const QString&) ),
++				this, SLOT( slotDisplayNameChanged(const QString&, const QString&) ) );
++			}
++			else
++			{
++				disconnect(contact,SIGNAL(propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & )),
+ 				this, SLOT( slotPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ) ) ;
++			}
+ 		}
+ 
+ 		if ( !suppressNotification )
+@@ -682,6 +728,7 @@
+ 	remoteTyping( message.from(), false );
+ 
+ 	messagePart()->appendMessage(message);
++
+ 	if( !d->isActive )
+ 	{
+ 		switch ( message.importance() )
+@@ -702,8 +749,14 @@
+ 
+ 	if( message.direction() == Kopete::Message::Inbound )
+ 	{
+-		unreadMessageFrom = message.from()->metaContact() ?
+-			 message.from()->metaContact()->displayName() : message.from()->contactId();
++		if( message.from()->metaContact() && message.from()->metaContact() != Kopete::ContactList::self()->myself() )
++		{
++			unreadMessageFrom = message.from()->metaContact()->displayName();
++		}
++		else
++		{
++			unreadMessageFrom = message.from()->nickName();
++		}
+ 		QTimer::singleShot( 1000, this, SLOT( slotMarkMessageRead() ) );
+ 	}
+ 	else
+@@ -736,16 +789,16 @@
+ 		else if ( !contact->account() || !contact->account()->suppressStatusNotification() )
+ 		{
+ 			// Don't send notifications when we just connected ourselves, i.e. when suppressions are still active
+-			if ( contact->metaContact() )
++			if ( contact->metaContact() && contact->metaContact() != Kopete::ContactList::self()->myself() )
+ 			{
+ 				sendInternalMessage( i18n( "%2 is now %1." )
+ 					.arg( newStatus.description(), contact->metaContact()->displayName() ) );
+ 			}
+ 			else
+ 			{
+-				QString nick=contact->property(Kopete::Global::Properties::self()->nickName().key()).value().toString();
++				QString nick=contact->nickName();
+ 				sendInternalMessage( i18n( "%2 is now %1." )
+-					.arg( newStatus.description(), nick.isEmpty() ? contact->contactId() : nick  ) );
++					.arg( newStatus.description(), nick ) );
+ 			}
+ 		}
+ 	}
+@@ -785,9 +838,54 @@
+ 	writeDockConfig ( config, QString::fromLatin1( "ChatViewDock" ) );
+ 	config->setGroup( QString::fromLatin1( "ChatViewDock" ) );
+ 	config->writeEntry( QString::fromLatin1( "membersDockPosition" ), membersDockPosition );
++	saveChatSettings();
+ 	config->sync();
+ }
+ 
++void ChatView::saveChatSettings()
++{
++	Kopete::ContactPtrList contacts = msgManager()->members();
++
++	if ( contacts.count() == 0 )
++		return;
++
++	Kopete::MetaContact* mc = contacts.first()->metaContact();
++	
++	if ( contacts.count() > 1 )
++		return; //can't save with more than one person in chatview
++
++	if ( !mc )
++		return;
++
++	KConfig* config = KGlobal::config();
++	
++	QString contactListGroup = QString::fromLatin1("chatwindow_") +
++	                           mc->metaContactId();
++
++	config->setGroup( contactListGroup );
++	config->writeEntry( "EnableRichText", editPart()->richTextEnabled() );
++	config->writeEntry( "EnableAutoSpellCheck", editPart()->autoSpellCheckEnabled() );
++	config->sync();
++}
++
++void ChatView::loadChatSettings()
++{
++	Kopete::ContactPtrList contacts = msgManager()->members();
++	if ( contacts.count() > 1 )
++		return; //can't load with more than one other person in the chat
++
++	//read settings for metacontact
++	QString contactListGroup = QString::fromLatin1("chatwindow_") +
++	                           contacts.first()->metaContact()->metaContactId();
++	KConfig* config = KGlobal::config();
++	config->setGroup( contactListGroup );
++	bool enableRichText = config->readBoolEntry( "EnableRichText", true );
++	editPart()->slotSetRichTextEnabled( enableRichText );
++	emit rtfEnabled( this, editPart()->richTextEnabled() );
++	bool enableAutoSpell = config->readBoolEntry( "EnableAutoSpellCheck", false );
++	emit autoSpellCheckEnabled( this, enableAutoSpell );
++}
++
+ void ChatView::readOptions()
+ {
+ 	KConfig *config = KGlobal::config();
+--- kopete/kopete/chatwindow/chatmessagepart.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/chatmessagepart.cpp	(revision 586398)
+@@ -4,6 +4,7 @@
+     Copyright (c) 2002-2005 by Olivier Goffart       <ogoffart @ kde.org>
+     Copyright (c) 2002-2003 by Martijn Klingens      <klingens at kde.org>
+     Copyright (c) 2004      by Richard Smith         <kde at metafoo.co.uk>
++    Copyright (c) 2005-2006 by Michaël Larouche      <michael.larouche at kdemail.net>
+ 
+     Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
+ 
+@@ -19,17 +20,32 @@
+ 
+ #include "chatmessagepart.h"
+ 
++// STYLE_TIMETEST is for time staticstic gathering.
++//#define STYLE_TIMETEST
++
++#include <ctime>
++
++// Qt includes
+ #include <qclipboard.h>
+ #include <qtooltip.h>
+ #include <qrect.h>
+ #include <qcursor.h>
++#include <qptrlist.h>
++#include <qregexp.h>
++#include <qvaluelist.h>
++#include <qtimer.h>
++#include <qstylesheet.h>
+ 
++// KHTML::DOM includes
+ #include <dom/dom_doc.h>
+ #include <dom/dom_text.h>
+ #include <dom/dom_element.h>
+ #include <dom/html_base.h>
+ #include <dom/html_document.h>
+ #include <dom/html_inline.h>
++
++
++// KDE includes
+ #include <kapplication.h>
+ #include <kdebug.h>
+ #include <kdeversion.h>
+@@ -39,25 +55,32 @@
+ #include <kmessagebox.h>
+ #include <kmultipledrag.h>
+ #include <kpopupmenu.h>
+-#include <krootpixmap.h>
+ #include <krun.h>
+ #include <kstringhandler.h>
+ #include <ktempfile.h>
+ #include <kurldrag.h>
+ #include <kio/netaccess.h>
++#include <kstandarddirs.h>
++#include <kiconloader.h>
+ 
++// Kopete includes
+ #include "chatmemberslistwidget.h"
++#include "kopetecontact.h"
++#include "kopetecontactlist.h"
+ #include "kopetechatwindow.h"
+ #include "kopetechatsession.h"
+ #include "kopetemetacontact.h"
+ #include "kopetepluginmanager.h"
+ #include "kopeteprefs.h"
+ #include "kopeteprotocol.h"
+-#include "kopetexsl.h"
+ #include "kopeteaccount.h"
+ #include "kopeteglobal.h"
+ #include "kopeteemoticons.h"
++#include "kopeteview.h"
++#include "kopetepicture.h"
+ 
++#include "kopetechatwindowstyle.h"
++#include "kopetechatwindowstylemanager.h"
+ 
+ #if !(KDE_IS_VERSION(3,3,90))
+ //From  kdelibs/khtml/misc/htmltags.h
+@@ -87,21 +110,48 @@
+ #define ID_UL 99
+ #endif
+ 
++class ToolTip;
+ 
+ class ChatMessagePart::Private
+ {
+ public:
+-	Kopete::XSLT *xsltParser;
+-	bool transparencyEnabled;
++	Private() 
++	 : tt(0L), manager(0L), scrollPressed(false),
++	   copyAction(0L), saveAction(0L), printAction(0L),
++	   closeAction(0L),copyURLAction(0L), currentChatStyle(0L), latestContact(0L),
++	   latestDirection(Kopete::Message::Inbound), latestType(Kopete::Message::TypeNormal)
++	{}
++	
++	~Private()
++	{
++		// Don't delete manager and latestContact, because they could be still used.
++		// Don't delete currentChatStyle, it is handled by ChatWindowStyleManager.
++	}
++
+ 	bool bgOverride;
+ 	bool fgOverride;
+ 	bool rtfOverride;
+-	/**
+-	 * we want to render several messages in one pass if several message are apended at the same time.
+-	 */
+-	QTimer refreshtimer;
+-	bool transformAllMessages;
++
+ 	ToolTip *tt;
++
++	Kopete::ChatSession *manager;
++	bool scrollPressed;
++
++	DOM::HTMLElement activeElement;
++
++	KAction *copyAction;
++	KAction *saveAction;
++	KAction *printAction;
++	KAction *closeAction;
++	KAction *copyURLAction;
++
++	ChatWindowStyle *currentChatStyle;
++	Kopete::Contact *latestContact;
++	Kopete::Message::MessageDirection latestDirection;
++	Kopete::Message::MessageType latestType;
++	// Yep I know it will take memory, but I don't have choice
++	// to enable on-the-fly style changing.
++	QValueList<Kopete::Message> allMessages;
+ };
+ 
+ class ChatMessagePart::ToolTip : public QToolTip
+@@ -119,6 +169,9 @@
+ 		DOM::Node node = m_chat->nodeUnderMouse();
+ 		Kopete::Contact *contact = m_chat->contactFromNode( node );
+ 		QString toolTipText;
++		
++		if(node.isNull())
++			return;
+ 
+ 		// this tooltip is attached to the viewport widget, so translate the node's rect
+ 		// into its coordinates.
+@@ -156,33 +209,23 @@
+ 	ChatMessagePart *m_chat;
+ };
+ 
+-
+-
+-ChatMessagePart::ChatMessagePart( Kopete::ChatSession *mgr, QWidget *parent, const char *name )
+-	: KHTMLPart( parent, name ), m_manager( mgr ), d( new Private )
++ChatMessagePart::ChatMessagePart( Kopete::ChatSession *mgr, QWidget *parent, const char *name)
++	: KHTMLPart( parent, name ), d( new Private )
+ {
+-	d->xsltParser = new Kopete::XSLT( KopetePrefs::prefs()->styleContents() );
+-	d->transformAllMessages = ( d->xsltParser->flags() & Kopete::XSLT::TransformAllMessages );
++	d->manager = mgr;
+ 
+-	backgroundFile = 0;
+-	root = 0;
+-	messageId = 0;
+-	bgChanged = false;
+-	scrollPressed = false;
++	KopetePrefs *kopetePrefs = KopetePrefs::prefs();
++	d->currentChatStyle = ChatWindowStyleManager::self()->getStyleFromPool( kopetePrefs->stylePath() );
+ 
+ 	//Security settings, we don't need this stuff
+-	setJScriptEnabled( false ) ;
++	setJScriptEnabled( true ) ;
+ 	setJavaEnabled( false );
+ 	setPluginsEnabled( false );
+ 	setMetaRefreshEnabled( false );
+ 	setOnlyLocalReferences( true );
+ 
+-	begin();
+-	write( QString::fromLatin1( "<html><head>\n"
+-		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=") +
+-		encoding() + QString::fromLatin1("\">\n<style>") + styleHTML() +
+-		QString::fromLatin1("</style></head><body></body></html>") );
+-	end();
++	// Write the template to KHTMLPart
++	writeTemplate();
+ 
+ 	view()->setFocusPolicy( QWidget::NoFocus );
+ 
+@@ -191,13 +234,17 @@
+ 	// It is not possible to drag and drop on our widget
+ 	view()->setAcceptDrops(false);
+ 
+-	// some signals and slots connections
+-	connect( KopetePrefs::prefs(), SIGNAL(transparencyChanged()),
+-	         this, SLOT( slotTransparencyChanged() ) );
+ 	connect( KopetePrefs::prefs(), SIGNAL(messageAppearanceChanged()),
+ 	         this, SLOT( slotAppearanceChanged() ) );
+ 	connect( KopetePrefs::prefs(), SIGNAL(windowAppearanceChanged()),
+ 	         this, SLOT( slotRefreshView() ) );
++	connect( KopetePrefs::prefs(), SIGNAL(styleChanged(const QString &)),
++			 this, SLOT( setStyle(const QString &) ) );
++	connect( KopetePrefs::prefs(), SIGNAL(styleVariantChanged(const QString &)),
++			 this, SLOT( setStyleVariant(const QString &) ) );
++	// Refresh the style if the display name change.
++	connect( d->manager, SIGNAL(displayNameChanged()), this, SLOT(slotUpdateHeaderDisplayName()) );
++	connect( d->manager, SIGNAL(photoChanged()), this, SLOT(slotUpdateHeaderPhoto()) );
+ 
+ 	connect ( browserExtension(), SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
+ 	          this, SLOT( slotOpenURLRequest( const KURL &, const KParts::URLArgs & ) ) );
+@@ -207,32 +254,21 @@
+ 	connect( view(), SIGNAL(contentsMoving(int,int)),
+ 	         this, SLOT(slotScrollingTo(int,int)) );
+ 
+-	connect( &d->refreshtimer , SIGNAL(timeout()) , this, SLOT(slotRefreshNodes()));
+-
+ 	//initActions
+-	copyAction = KStdAction::copy( this, SLOT(copy()), actionCollection() );
+-	saveAction = KStdAction::saveAs( this, SLOT(save()), actionCollection() );
+-	printAction = KStdAction::print( this, SLOT(print()),actionCollection() );
+-	closeAction = KStdAction::close( this, SLOT(slotCloseView()),actionCollection() );
+-	copyURLAction = new KAction( i18n( "Copy Link Address" ), QString::fromLatin1( "editcopy" ), 0, this, SLOT( slotCopyURL() ), actionCollection() );
++	d->copyAction = KStdAction::copy( this, SLOT(copy()), actionCollection() );
++	d->saveAction = KStdAction::saveAs( this, SLOT(save()), actionCollection() );
++	d->printAction = KStdAction::print( this, SLOT(print()),actionCollection() );
++	d->closeAction = KStdAction::close( this, SLOT(slotCloseView()),actionCollection() );
++	d->copyURLAction = new KAction( i18n( "Copy Link Address" ), QString::fromLatin1( "editcopy" ), 0, this, SLOT( slotCopyURL() ), actionCollection() );
+ 
+ 	// read formatting override flags
+ 	readOverrides();
++}
+ 
+-	slotTransparencyChanged();
+-	}
+-
+ ChatMessagePart::~ChatMessagePart()
+ {
+-	if( backgroundFile )
+-	{
+-		backgroundFile->close();
+-		backgroundFile->unlink();
+-		delete backgroundFile;
+-	}
+-
++	kdDebug(14000) << k_funcinfo << endl;
+ 	delete d->tt;
+-	delete d->xsltParser;
+ 	delete d;
+ }
+ 
+@@ -240,14 +276,14 @@
+ {
+ 	int scrolledTo = y + view()->visibleHeight();
+ 	if ( scrolledTo >= ( view()->contentsHeight() - 10 ) )
+-		scrollPressed = false;
++		d->scrollPressed = false;
+ 	else
+-		scrollPressed = true;
++		d->scrollPressed = true;
+ }
+ 
+ void ChatMessagePart::save()
+ {
+-	KFileDialog dlg( QString::null, QString::fromLatin1( "text/html text/xml text/plain" ), view(), "fileSaveDialog", false );
++	KFileDialog dlg( QString::null, QString::fromLatin1( "text/html text/plain" ), view(), "fileSaveDialog", false );
+ 	dlg.setCaption( i18n( "Save Conversation" ) );
+ 	dlg.setOperationMode( KFileDialog::Saving );
+ 
+@@ -260,21 +296,20 @@
+ 	QFile* file = tempFile.file();
+ 
+ 	QTextStream stream ( file );
+-	if ( dlg.currentFilter() == QString::fromLatin1( "text/xml" ) )
++	stream.setEncoding(QTextStream::UnicodeUTF8);
++
++	if ( dlg.currentFilter() == QString::fromLatin1( "text/plain" ) )
+ 	{
+-		stream << QString::fromLatin1( "<document>" );
+-		stream << messageMap.join("\n");
+-		stream << QString::fromLatin1( "</document>\n" );
+-	}
+-	else if ( dlg.currentFilter() == QString::fromLatin1( "text/plain" ) )
+-	{
+-		for( QStringList::Iterator it = messageMap.begin(); it != messageMap.end(); ++it)
++		QValueList<Kopete::Message>::ConstIterator it, itEnd = d->allMessages.constEnd();
++		for(it = d->allMessages.constBegin(); it != itEnd; ++it)
+ 		{
+-			QDomDocument doc;
+-			doc.setContent(*it);
+-			stream << "[" << doc.elementsByTagName("message").item(0).toElement().attribute("formattedTimestamp");
+-			stream << "] " << doc.elementsByTagName("contact").item(0).toElement().attribute("contactId") ;
+-			stream << ": " << doc.elementsByTagName("body").item(0).toElement().text() << "\n";
++			Kopete::Message tempMessage = *it;
++			stream << "[" << KGlobal::locale()->formatDateTime(tempMessage.timestamp()) << "] ";
++			if( tempMessage.from() && tempMessage.from()->metaContact() )
++			{
++				stream << formatName(tempMessage.from()->metaContact()->displayName());
++			}
++			stream << ": " << tempMessage.plainBody() << "\n";
+ 		}
+ 	}
+ 	else
+@@ -307,7 +342,7 @@
+ 	kdDebug(14000) << k_funcinfo << "url=" << url.url() << endl;
+ 	if ( url.protocol() == QString::fromLatin1("kopetemessage") )
+ 	{
+-		Kopete::Contact *contact = m_manager->account()->contacts()[ url.host() ];
++		Kopete::Contact *contact = d->manager->account()->contacts()[ url.host() ];
+ 		if ( contact )
+ 			contact->execute();
+ 	}
+@@ -326,134 +361,206 @@
+ 	d->rtfOverride = KopetePrefs::prefs()->rtfOverride();
+ }
+ 
+-void ChatMessagePart::setStylesheet( const QString &style )
++void ChatMessagePart::setStyle( const QString &stylePath )
+ {
+-	d->xsltParser->setXSLT( style );
+-	d->transformAllMessages = ( d->xsltParser->flags() & Kopete::XSLT::TransformAllMessages );
+-	slotRefreshNodes();
++	// Create a new ChatWindowStyle
++	d->currentChatStyle = ChatWindowStyleManager::self()->getStyleFromPool(stylePath);
++
++	// Do the actual style switch
++	// Wait for the event loop before switching the style
++	QTimer::singleShot( 0, this, SLOT(changeStyle()) );
+ }
+ 
++void ChatMessagePart::setStyle( ChatWindowStyle *style )
++{
++	// Change the current style
++	d->currentChatStyle = style;
++
++	// Do the actual style switch
++	// Wait for the event loop before switching the style
++	QTimer::singleShot( 0, this, SLOT(changeStyle()) );
++}
++
++void ChatMessagePart::setStyleVariant( const QString &variantPath )
++{
++	DOM::HTMLElement variantNode = document().getElementById( QString::fromUtf8("mainStyle") );
++	if( !variantNode.isNull() )
++		variantNode.setInnerText( QString("@import url(\"%1\");").arg(variantPath) );
++}
++
+ void ChatMessagePart::slotAppearanceChanged()
+ {
+ 	readOverrides();
+ 
+-	d->xsltParser->setXSLT( KopetePrefs::prefs()->styleContents() );
+-	slotRefreshNodes();
++	changeStyle();
+ }
+ 
+-void ChatMessagePart::appendMessage( Kopete::Message &message )
++void ChatMessagePart::appendMessage( Kopete::Message &message, bool restoring )
+ {
+-	//parse emoticons and URL now.
+-	message.setBody( message.parsedBody() , Kopete::Message::ParsedHTML );
+-
+ 	message.setBgOverride( d->bgOverride );
+ 	message.setFgOverride( d->fgOverride );
+ 	message.setRtfOverride( d->rtfOverride );
++	
++	// parse emoticons and URL now.
++	// Do not reparse emoticons on restoring, because it cause very intensive CPU usage on long chats.
++	if( !restoring )
++		message.setBody( message.parsedBody() , Kopete::Message::ParsedHTML );
+ 
+-	messageMap.append(  message.asXML().toString() );
++#ifdef STYLE_TIMETEST
++	QTime beforeMessage = QTime::currentTime();
++#endif
+ 
++	QString formattedMessageHtml;
++	bool isConsecutiveMessage = false;
+ 	uint bufferLen = (uint)KopetePrefs::prefs()->chatViewBufferSize();
+ 
+-	// transform all messages every time. needed for Adium style.
+-	if(d->transformAllMessages)
++	// Find the "Chat" div element.
++	// If the "Chat" div element is not found, do nothing. It's the central part of Adium format.
++	DOM::HTMLElement chatNode = htmlDocument().getElementById( "Chat" );
++
++	if( chatNode.isNull() )
+ 	{
+-		while ( bufferLen>0 && messageMap.count() >= bufferLen )
+-			messageMap.pop_front();
++		kdDebug(14000) << k_funcinfo << "WARNING: Chat Node was null !" << endl;
++		return;
++	}
+ 
+-		d->refreshtimer.start(50,true); //let 50ms delay in the case several message are appended in the same time.
++	// Check if it's a consecutive Message
++	// Consecutive messages are only for normal messages, status messages do not have a <div id="insert" />
++	// We check if the from() is the latestContact, because consecutive incoming/outgoing message can come from differents peopole(in groupchat and IRC)
++	// Group only if the user want it.
++	if( KopetePrefs::prefs()->groupConsecutiveMessages() )
++	{
++		isConsecutiveMessage = (message.direction() == d->latestDirection && d->latestContact && d->latestContact == message.from() && message.type() == d->latestType);
+ 	}
++
++	// Don't test it in the switch to don't break consecutive messages.
++	if(message.type() == Kopete::Message::TypeAction)
++	{
++		// Check if chat style support Action template (Kopete extension)
++		if( d->currentChatStyle->hasActionTemplate() )
++		{
++			switch(message.direction())
++			{
++				case Kopete::Message::Inbound:
++					formattedMessageHtml = d->currentChatStyle->getActionIncomingHtml();
++					break;
++				case Kopete::Message::Outbound:
++					formattedMessageHtml = d->currentChatStyle->getActionOutgoingHtml();
++					break;
++				default:
++					break;
++			}
++		}
++		// Use status template if no Action template.
++		else
++		{
++			formattedMessageHtml = d->currentChatStyle->getStatusHtml();
++		}
++	}
+ 	else
+ 	{
+-		QDomDocument domMessage = message.asXML();
+-		domMessage.documentElement().setAttribute( QString::fromLatin1( "id" ), QString::number( messageId ) );
+-		QString resultHTML = addNickLinks( d->xsltParser->transform( domMessage.toString() ) );
++		switch(message.direction())
++		{
++			case Kopete::Message::Inbound:
++			{
++				if(isConsecutiveMessage)
++				{
++					formattedMessageHtml = d->currentChatStyle->getNextIncomingHtml();
++				}
++				else
++				{
++					formattedMessageHtml = d->currentChatStyle->getIncomingHtml();
++				}
++				break;
++			}
++			case Kopete::Message::Outbound:
++			{
++				if(isConsecutiveMessage)
++				{
++					formattedMessageHtml = d->currentChatStyle->getNextOutgoingHtml();
++				}
++				else
++				{
++					formattedMessageHtml = d->currentChatStyle->getOutgoingHtml();
++				}
++				break;
++			}
++			case Kopete::Message::Internal:
++			{
++				formattedMessageHtml = d->currentChatStyle->getStatusHtml();
++				break;
++			}
++		}
++	}
+ 
+-		QString direction = ( message.plainBody().isRightToLeft() ? QString::fromLatin1("rtl") : QString::fromLatin1("ltr") );
+-		DOM::HTMLElement newNode = document().createElement( QString::fromLatin1("span") );
+-		newNode.setAttribute( QString::fromLatin1("dir"), direction );
+-		newNode.setInnerHTML( resultHTML );
++	formattedMessageHtml = formatStyleKeywords( formattedMessageHtml, message );
+ 
+-		htmlDocument().body().appendChild( newNode );
++	// newMessageNode is common to both code path
++	// FIXME: Find a better than to create a dummy span.
++	DOM::HTMLElement newMessageNode = document().createElement( QString::fromUtf8("span") );
++	newMessageNode.setInnerHTML( formattedMessageHtml );
+ 
+-		while ( bufferLen>0 && messageMap.count() >= bufferLen )
+-		{
+-			htmlDocument().body().removeChild( htmlDocument().body().firstChild() );
+-			messageMap.pop_front();
+-		}
++	// Find the insert Node
++	DOM::HTMLElement insertNode = document().getElementById( QString::fromUtf8("insert") );
+ 
+-		if ( !scrollPressed )
+-			QTimer::singleShot( 1, this, SLOT( slotScrollView() ) );
++	if( isConsecutiveMessage && !insertNode.isNull() )
++	{
++		// Replace the insert block, because it's a consecutive message.
++		insertNode.parentNode().replaceChild(newMessageNode, insertNode);
+ 	}
+-}
++	else
++	{
++		// Remove the insert block, because it's a new message.
++		if( !insertNode.isNull() )
++			insertNode.parentNode().removeChild(insertNode);
++		// Append to the chat.
++		chatNode.appendChild(newMessageNode);
++	}
+ 
+-const QString ChatMessagePart::addNickLinks( const QString &html ) const
+-{
+-	QString retVal = html;
++	// Keep the direction to see on next message
++	// if it's a consecutive message
++	// Keep also the from() contact.
++	d->latestDirection = message.direction();
++	d->latestType = message.type();
++	d->latestContact = const_cast<Kopete::Contact*>(message.from());
+ 
+-	Kopete::ContactPtrList members = m_manager->members();
+-	for ( QPtrListIterator<Kopete::Contact> it( members ); it.current(); ++it )
++	// Add the message to the list for futher restoring if needed
++	if(!restoring)
++		d->allMessages.append(message);
++
++	while ( bufferLen>0 && d->allMessages.count() >= bufferLen )
+ 	{
+-		QString nick = (*it)->property( Kopete::Global::Properties::self()->nickName().key() ).value().toString();
+-		//FIXME: this is really slow in channels with lots of contacts
+-		QString parsed_nick = Kopete::Emoticons::parseEmoticons( nick );
+-
+-		if ( nick != parsed_nick )
++		d->allMessages.pop_front();
++			
++		// FIXME: Find a way to make work Chat View Buffer efficiently with consecutives messages.
++		// Before it was calling changeStyle() but it's damn too slow.
++		if( !KopetePrefs::prefs()->groupConsecutiveMessages() )
+ 		{
+-			retVal.replace( QRegExp( QString::fromLatin1("([\\s&;>])%1([\\s&;<:])")
+-					.arg( QRegExp::escape( parsed_nick ) )  ), QString::fromLatin1("\\1%1\\2").arg( nick ) );
++			chatNode.removeChild( chatNode.firstChild() );
+ 		}
+-		if ( nick.length() > 0 && ( retVal.find( nick ) > -1 ) )
+-		{
+-			retVal.replace(
+-				QRegExp( QString::fromLatin1("([\\s&;>])(%1)([\\s&;<:])")
+-					.arg( QRegExp::escape( nick ) )  ),
+-			QString::fromLatin1("\\1<a href=\"kopetemessage://%1/?protocolId=%2&accountId=%3\" class=\"KopeteDisplayName\">\\2</a>\\3")
+-				.arg( (*it)->contactId(), m_manager->protocol()->pluginId(), m_manager->account()->accountId() )
+-			);
+-		}
+ 	}
+-	QString nick = m_manager->myself()->property( Kopete::Global::Properties::self()->nickName().key() ).value().toString();
+-	retVal.replace( QRegExp( QString::fromLatin1("([\\s&;>])%1([\\s&;<:])")
+-			.arg( QRegExp::escape( Kopete::Emoticons::parseEmoticons( nick ) ) )  ), QString::fromLatin1("\\1%1\\2").arg( nick ) );
+ 
+-	return retVal;
+-}
++	if ( !d->scrollPressed )
++		QTimer::singleShot( 1, this, SLOT( slotScrollView() ) );
+ 
+-void ChatMessagePart::slotRefreshNodes()
+-{
+-	d->refreshtimer.stop();
+-	DOM::HTMLBodyElement bodyElement = htmlDocument().body();
+-
+-	QString xmlString = QString::fromLatin1( "<document>" );
+-	xmlString += messageMap.join("\n");
+-	xmlString += QString::fromLatin1( "</document>" );
+-
+-	d->xsltParser->transformAsync( xmlString, this, SLOT( slotTransformComplete( const QVariant & ) ) );
++#ifdef STYLE_TIMETEST
++	kdDebug(14000) << "Message time: " << beforeMessage.msecsTo( QTime::currentTime()) << endl;
++#endif
+ }
+ 
+ void ChatMessagePart::slotRefreshView()
+ {
+-	DOM::Element htmlElement = document().documentElement();
+-	DOM::Element headElement = htmlElement.getElementsByTagName( QString::fromLatin1( "head" ) ).item(0);
+-	DOM::HTMLElement styleElement = headElement.getElementsByTagName( QString::fromLatin1( "style" ) ).item(0);
+-	if ( !styleElement.isNull() )
+-		styleElement.setInnerText( styleHTML() );
++	DOM::HTMLElement kopeteNode = document().getElementById( QString::fromUtf8("KopeteStyle") );
++	if( !kopeteNode.isNull() )
++		kopeteNode.setInnerText( styleHTML() );
+ 
+ 	DOM::HTMLBodyElement bodyElement = htmlDocument().body();
+ 	bodyElement.setBgColor( KopetePrefs::prefs()->bgColor().name() );
+ }
+ 
+-void ChatMessagePart::slotTransformComplete( const QVariant &result )
+-{
+-	htmlDocument().body().setInnerHTML( addNickLinks( result.toString() ) );
+-
+-	if ( !scrollPressed )
+-		QTimer::singleShot( 1, this, SLOT( slotScrollView() ) );
+-}
+-
+ void ChatMessagePart::keepScrolledDown()
+ {
+-	if ( !scrollPressed )
++	if ( !d->scrollPressed )
+ 		QTimer::singleShot( 1, this, SLOT( slotScrollView() ) );
+ }
+ 
+@@ -462,12 +569,13 @@
+ 	KopetePrefs *p = KopetePrefs::prefs();
+ 
+ 	QString style = QString::fromLatin1(
+-		"body{margin:4px;background-color:%1;font-family:%2;font-size:%3pt;color:%4;background-repeat:no-repeat;background-attachment:fixed}"
++		"body{background-color:%1;font-family:%2;font-size:%3pt;color:%4}"
+ 		"td{font-family:%5;font-size:%6pt;color:%7}"
+ 		"a{color:%8}a.visited{color:%9}"
+ 		"a.KopeteDisplayName{text-decoration:none;color:inherit;}"
+ 		"a.KopeteDisplayName:hover{text-decoration:underline;color:inherit}"
+-		".KopeteLink{cursor:pointer;}.KopeteLink:hover{text-decoration:underline}" )
++		".KopeteLink{cursor:pointer;}.KopeteLink:hover{text-decoration:underline}"
++		".KopeteMessageBody > p:first-child{margin:0;padding:0;display:inline;}" /* some html messages are encapsuled into a <p> */ )
+ 		.arg( p->bgColor().name() )
+ 		.arg( p->fontFace().family() )
+ 		.arg( p->fontFace().pointSize() )
+@@ -478,26 +586,18 @@
+ 		.arg( p->linkColor().name() )
+ 		.arg( p->linkColor().name() );
+ 
+-	//JASON, VA TE FAIRE FOUTRE AVEC TON *default* HIGHLIGHT!
+-	// that broke my highlight plugin
+-	// if the user has not Spetialy specified that it you theses 'putaint de' default color, WE DON'T USE THEM
+-	if ( p->highlightEnabled() )
+-	{
+-		style += QString::fromLatin1( ".highlight{color:%1;background-color:%2}" )
+-			.arg( p->highlightForeground().name() )
+-			.arg( p->highlightBackground().name() );
+-	}
+-
+ 	return style;
+ }
+ 
+ void ChatMessagePart::clear()
+ {
+-	DOM::HTMLElement body = htmlDocument().body();
+-	while ( body.hasChildNodes() )
+-		body.removeChild( body.childNodes().item( body.childNodes().length() - 1 ) );
++	// writeTemplate actually reset the HTML chat session from the beginning.
++	writeTemplate();
+ 
+-	messageMap.clear();
++	// Reset consecutive messages
++	d->latestContact = 0;
++	// Remove all stored messages.
++	d->allMessages.clear();
+ }
+ 
+ Kopete::Contact *ChatMessagePart::contactFromNode( const DOM::Node &n ) const
+@@ -517,14 +617,14 @@
+ 	if ( element.hasAttribute( "contactid" ) )
+ 	{
+ 		QString contactId = element.getAttribute( "contactid" ).string();
+-		for ( QPtrListIterator<Kopete::Contact> it ( m_manager->members() ); it.current(); ++it )
++		for ( QPtrListIterator<Kopete::Contact> it ( d->manager->members() ); it.current(); ++it )
+ 			if ( (*it)->contactId() == contactId )
+ 				return *it;
+ 	}
+ 	else
+ 	{
+ 		QString nick = element.innerText().string().stripWhiteSpace();
+-		for ( QPtrListIterator<Kopete::Contact> it ( m_manager->members() ); it.current(); ++it )
++		for ( QPtrListIterator<Kopete::Contact> it ( d->manager->members() ); it.current(); ++it )
+ 			if ( (*it)->property( Kopete::Global::Properties::self()->nickName().key() ).value().toString() == nick )
+ 				return *it;
+ 	}
+@@ -540,39 +640,39 @@
+ 		activeNode = activeNode.parentNode();
+ 
+ 	// make sure it's valid
+-	activeElement = activeNode;
+-	if ( activeElement.isNull() )
++	d->activeElement = activeNode;
++	if ( d->activeElement.isNull() )
+ 		return;
+ 
+ 	KPopupMenu *chatWindowPopup = 0L;
+ 
+-	if ( Kopete::Contact *contact = contactFromNode( activeElement ) )
++	if ( Kopete::Contact *contact = contactFromNode( d->activeElement ) )
+ 	{
+-		chatWindowPopup = contact->popupMenu( m_manager );
++		chatWindowPopup = contact->popupMenu( d->manager );
+ 		connect( chatWindowPopup, SIGNAL( aboutToHide() ), chatWindowPopup , SLOT( deleteLater() ) );
+ 	}
+ 	else
+ 	{
+ 		chatWindowPopup = new KPopupMenu();
+ 
+-		if ( activeElement.className() == "KopeteDisplayName" )
++		if ( d->activeElement.className() == "KopeteDisplayName" )
+ 		{
+ 			chatWindowPopup->insertItem( i18n( "User Has Left" ), 1 );
+ 			chatWindowPopup->setItemEnabled( 1, false );
+ 			chatWindowPopup->insertSeparator();
+ 		}
+-		else if ( activeElement.tagName().lower() == QString::fromLatin1( "a" ) )
++		else if ( d->activeElement.tagName().lower() == QString::fromLatin1( "a" ) )
+ 		{
+-			copyURLAction->plug( chatWindowPopup );
++			d->copyURLAction->plug( chatWindowPopup );
+ 			chatWindowPopup->insertSeparator();
+ 		}
+ 
+-		copyAction->setEnabled( hasSelection() );
+-		copyAction->plug( chatWindowPopup );
+-		saveAction->plug( chatWindowPopup );
+-		printAction->plug( chatWindowPopup );
++		d->copyAction->setEnabled( hasSelection() );
++		d->copyAction->plug( chatWindowPopup );
++		d->saveAction->plug( chatWindowPopup );
++		d->printAction->plug( chatWindowPopup );
+ 		chatWindowPopup->insertSeparator();
+-		closeAction->plug( chatWindowPopup );
++		d->closeAction->plug( chatWindowPopup );
+ 
+ 		connect( chatWindowPopup, SIGNAL( aboutToHide() ), chatWindowPopup, SLOT( deleteLater() ) );
+ 		chatWindowPopup->popup( point );
+@@ -627,7 +727,7 @@
+ 
+ void ChatMessagePart::slotCopyURL()
+ {
+-	DOM::HTMLAnchorElement a = activeElement;
++	DOM::HTMLAnchorElement a = d->activeElement;
+ 	if ( !a.isNull() )
+ 	{
+ 		QApplication::clipboard()->setText( a.href().string(), QClipboard::Clipboard );
+@@ -651,127 +751,127 @@
+ 	* This also copies the text as type text/html
+ 	* RangeImpl::toHTML  was not implemented before KDE 3.4
+ 	*/
+-
+ 	QString text;
+ 	QString htmltext;
+-
++	
+ #if KDE_IS_VERSION(3,3,90)
+-	htmltext = selectedTextAsHTML();
+-	text = selectedText();
+-	//selectedText is now sufficent
+-//	text=Kopete::Message::unescape( htmltext ).stripWhiteSpace();
+-	// Message::unsescape will replace image by his title attribute
+-	// stripWhiteSpace is for removing the newline added by the <!DOCTYPE> and other xml things of RangeImpl::toHTML
++        htmltext = selectedTextAsHTML();
++        text = selectedText();
++        //selectedText is now sufficent
++//      text=Kopete::Message::unescape( htmltext ).stripWhiteSpace();
++        // Message::unsescape will replace image by his title attribute
++        // stripWhiteSpace is for removing the newline added by the <!DOCTYPE> and other xml things of RangeImpl::toHTML
+ #else
+ 
+-	DOM::Node startNode, endNode;
+-	long startOffset, endOffset;
+-	selection( startNode, startOffset, endNode, endOffset );
++        DOM::Node startNode, endNode;
++        long startOffset, endOffset;
++        selection( startNode, startOffset, endNode, endOffset );
+ 
+-	//BEGIN: copied from KHTMLPart::selectedText
++        //BEGIN: copied from KHTMLPart::selectedText
+ 
+-	bool hasNewLine = true;
+-	DOM::Node n = startNode;
+-	while(!n.isNull())
+-	{
+-		if(n.nodeType() == DOM::Node::TEXT_NODE /*&& n.handle()->renderer()*/)
+-		{
+-			QString str = n.nodeValue().string();
+-			hasNewLine = false;
+-			if(n == startNode && n == endNode)
+-				text = str.mid(startOffset, endOffset - startOffset);
+-			else if(n == startNode)
+-				text = str.mid(startOffset);
+-			else if(n == endNode)
+-				text += str.left(endOffset);
+-			else
+-				text += str;
+-		}
+-		else
+-		{ // This is our simple HTML -> ASCII transformation:
+-			unsigned short id = n.elementId();
+-			switch(id)
+-			{
+-			case ID_IMG: //here is the main difference with KHTMLView::selectedText
+-			{
+-				DOM::HTMLElement e = n;
+-				if( !e.isNull() && e.hasAttribute( "title" ) )
+-					text+=e.getAttribute( "title" ).string();
+-				break;
+-			}
+-			case ID_BR:
+-				text += "\n";
+-				hasNewLine = true;
+-				break;
+-			case ID_TD:  case ID_TH:  case ID_HR:
+-			case ID_OL:  case ID_UL:  case ID_LI:
+-			case ID_DD:  case ID_DL:  case ID_DT:
+-			case ID_PRE: case ID_BLOCKQUOTE: case ID_DIV:
+-				if (!hasNewLine)
+-					text += "\n";
+-				hasNewLine = true;
+-				break;
+-			case ID_P:   case ID_TR:
+-			case ID_H1:  case ID_H2:  case ID_H3:
+-			case ID_H4:  case ID_H5:  case ID_H6:
+-				if (!hasNewLine)
+-					text += "\n";
+-				text += "\n";
+-				hasNewLine = true;
+-				break;
+-			}
+-		}
+-		if(n == endNode)
+-			break;
+-		DOM::Node next = n.firstChild();
+-		if(next.isNull())
+-			next = n.nextSibling();
+-		while( next.isNull() && !n.parentNode().isNull() )
+-		{
+-			n = n.parentNode();
+-			next = n.nextSibling();
+-			unsigned short id = n.elementId();
+-			switch(id)
+-			{
+-			case ID_TD:  case ID_TH:  case ID_HR:
+-			case ID_OL:  case ID_UL:  case ID_LI:
+-			case ID_DD:  case ID_DL:  case ID_DT:
+-			case ID_PRE: case ID_BLOCKQUOTE:  case ID_DIV:
+-				if (!hasNewLine)
+-					text += "\n";
+-				hasNewLine = true;
+-				break;
+-			case ID_P:   case ID_TR:
+-			case ID_H1:  case ID_H2:  case ID_H3:
+-			case ID_H4:  case ID_H5:  case ID_H6:
+-				if (!hasNewLine)
+-					text += "\n";
+-				text += "\n";
+-				hasNewLine = true;
+-				break;
+-			}
+-		}
+-		n = next;
+-	}
++        bool hasNewLine = true;
++        DOM::Node n = startNode;
++        while(!n.isNull())
++        {
++                if(n.nodeType() == DOM::Node::TEXT_NODE /*&& n.handle()->renderer()*/)
++                {
++                        QString str = n.nodeValue().string();
++                        hasNewLine = false;
++                        if(n == startNode && n == endNode)
++                                text = str.mid(startOffset, endOffset - startOffset);
++                        else if(n == startNode)
++                                text = str.mid(startOffset);
++                        else if(n == endNode)
++                                text += str.left(endOffset);
++                        else
++                                text += str;
++                }
++                else
++                { // This is our simple HTML -> ASCII transformation:
++                        unsigned short id = n.elementId();
++                        switch(id)
++                        {
++                        case ID_IMG: //here is the main difference with KHTMLView::selectedText
++                        {
++                                DOM::HTMLElement e = n;
++                                if( !e.isNull() && e.hasAttribute( "title" ) )
++                                        text+=e.getAttribute( "title" ).string();
++                                break;
++                        }
++                        case ID_BR:
++                                text += "\n";
++                                hasNewLine = true;
++                                break;
++                        case ID_TD:  case ID_TH:  case ID_HR:
++                        case ID_OL:  case ID_UL:  case ID_LI:
++                        case ID_DD:  case ID_DL:  case ID_DT:
++                        case ID_PRE: case ID_BLOCKQUOTE: case ID_DIV:
++                                if (!hasNewLine)
++                                        text += "\n";
++                                hasNewLine = true;
++                                break;
++                        case ID_P:   case ID_TR:
++                        case ID_H1:  case ID_H2:  case ID_H3:
++                        case ID_H4:  case ID_H5:  case ID_H6:
++                                if (!hasNewLine)
++                                        text += "\n";
++                                text += "\n";
++                                hasNewLine = true;
++                                break;
++                        }
++                }
++                if(n == endNode)
++                        break;
++                DOM::Node next = n.firstChild();
++                if(next.isNull())
++                        next = n.nextSibling();
++                while( next.isNull() && !n.parentNode().isNull() )
++                {
++                        n = n.parentNode();
++                        next = n.nextSibling();
++                        unsigned short id = n.elementId();
++                        switch(id)
++                        {
++                        case ID_TD:  case ID_TH:  case ID_HR:
++                        case ID_OL:  case ID_UL:  case ID_LI:
++                        case ID_DD:  case ID_DL:  case ID_DT:
++                        case ID_PRE: case ID_BLOCKQUOTE:  case ID_DIV:
++                                if (!hasNewLine)
++                                        text += "\n";
++                                hasNewLine = true;
++                                break;
++                        case ID_P:   case ID_TR:
++                        case ID_H1:  case ID_H2:  case ID_H3:
++                        case ID_H4:  case ID_H5:  case ID_H6:
++                                if (!hasNewLine)
++                                        text += "\n";
++                                text += "\n";
++                                hasNewLine = true;
++                                break;
++                        }
++                }
++                n = next;
++        }
+ 
+-	if(text.isEmpty())
+-		return;
++        if(text.isEmpty())
++                return;
+ 
+-	int start = 0;
+-	int end = text.length();
++        int start = 0;
++        int end = text.length();
+ 
+-	// Strip leading LFs
+-	while ((start < end) && (text[start] == '\n'))
+-		start++;
++        // Strip leading LFs
++        while ((start < end) && (text[start] == '\n'))
++                start++;
+ 
+-	// Strip excessive trailing LFs
+-	while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
+-		end--;
++        // Strip excessive trailing LFs
++        while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
++                end--;
+ 
+-	text=text.mid(start, end-start);
++        text=text.mid(start, end-start);
+ 
+-	//END: copied from KHTMLPart::selectedText
++        //END: copied from KHTMLPart::selectedText
+ #endif
++
+ 	if(text.isEmpty()) return;
+ 
+ 	disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
+@@ -805,91 +905,402 @@
+ 	view()->print();
+ }
+ 
+-void ChatMessagePart::slotTransparencyChanged()
++void ChatMessagePart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * event) //virtual
+ {
+-	d->transparencyEnabled = KopetePrefs::prefs()->transparencyEnabled();
++	KHTMLPart::khtmlDrawContentsEvent(event);
++	//copy(true /*selection only*/); not needed anymore.
++}
++void ChatMessagePart::slotCloseView( bool force )
++{
++	d->manager->view()->closeView( force );
++}
+ 
+-//	kdDebug(14000) << k_funcinfo << "transparencyEnabled=" << transparencyEnabled << ", bgOverride=" << bgOverride << "." << endl;
++void ChatMessagePart::emitTooltipEvent(  const QString &textUnderMouse, QString &toolTip )
++{
++	emit tooltipEvent(  textUnderMouse, toolTip );
++}
+ 
+-	if ( d->transparencyEnabled )
++// Style formatting for messages(incoming, outgoing, status)
++QString ChatMessagePart::formatStyleKeywords( const QString &sourceHTML, const Kopete::Message &_message )
++{
++	Kopete::Message message=_message; //we will eventually need to modify it before showing it.
++	QString resultHTML = sourceHTML;
++	QString nick, contactId, service, protocolIcon, nickLink;
++	
++	if( message.from() )
+ 	{
+-		if ( !root )
++		// Use metacontact display name if the metacontact exists and if its not the myself metacontact.
++		if( message.from()->metaContact() && message.from()->metaContact() != Kopete::ContactList::self()->myself() )
+ 		{
+-//			kdDebug(14000) << k_funcinfo << "enabling transparency" << endl;
+-			root = new KRootPixmap( view() );
+-			connect(root, SIGNAL( backgroundUpdated( const QPixmap & ) ), this, SLOT( slotUpdateBackground( const QPixmap & ) ) );
+-			root->setCustomPainting( true );
+-			root->setFadeEffect( KopetePrefs::prefs()->transparencyValue() * 0.01, KopetePrefs::prefs()->transparencyColor() );
+-			root->start();
++			nick = message.from()->metaContact()->displayName();
+ 		}
++		// Use contact nickname for no metacontact or myself.
+ 		else
+ 		{
+-			root->setFadeEffect( KopetePrefs::prefs()->transparencyValue() * 0.01, KopetePrefs::prefs()->transparencyColor() );
+-			root->repaint( true );
++			nick = message.from()->nickName();
+ 		}
++		nick = formatName(nick);
++		contactId = message.from()->contactId();
++		// protocol() returns NULL here in the style preview in appearance config.
++		// this isn't the right place to work around it, since contacts should never have
++		// no protocol, but it works for now.
++		//
++		// Use default if protocol() and protocol()->displayName() is NULL.
++		// For preview and unit tests.
++		QString iconName = QString::fromUtf8("kopete");
++		service = QString::fromUtf8("Kopete");
++		if(message.from()->protocol() && !message.from()->protocol()->displayName().isNull())
++		{
++			service =  message.from()->protocol()->displayName();
++			iconName = message.from()->protocol()->pluginIcon();
++		}
++
++		protocolIcon = KGlobal::iconLoader()->iconPath( iconName, KIcon::Small );
++		
++		nickLink=QString::fromLatin1("<a href=\"kopetemessage://%1/?protocolId=%2&amp;accountId=%3\" class=\"KopeteDisplayName\">")
++				.arg( QStyleSheet::escape(message.from()->contactId()).replace('"',"&quot;"),
++					  QStyleSheet::escape(message.from()->protocol()->pluginId()).replace('"',"&quot;"), 
++					  QStyleSheet::escape(message.from()->account()->accountId() ).replace('"',"&quot;"));
+ 	}
+ 	else
+ 	{
+-		if ( root )
++		nickLink="<a>";
++	}
++	
++	
++	// Replace sender (contact nick)
++	resultHTML = resultHTML.replace( QString::fromUtf8("%sender%"), nickLink+nick+"</a>" );
++	// Replace time, by default display only time and display seconds(that was true means).
++	resultHTML = resultHTML.replace( QString::fromUtf8("%time%"), KGlobal::locale()->formatTime(message.timestamp().time(), true) );
++	// Replace %screenName% (contact ID)
++	resultHTML = resultHTML.replace( QString::fromUtf8("%senderScreenName%"), nickLink+QStyleSheet::escape(contactId)+"</a>" );
++	// Replace service name (protocol name)
++	resultHTML = resultHTML.replace( QString::fromUtf8("%service%"), QStyleSheet::escape(service) );
++	// Replace protocolIcon (sender statusIcon)
++	resultHTML = resultHTML.replace( QString::fromUtf8("%senderStatusIcon%"), QStyleSheet::escape(protocolIcon).replace('"',"&quot;") );
++	
++	// Look for %time{X}%
++	QRegExp timeRegExp("%time\\{([^}]*)\\}%");
++	int pos=0;
++	while( (pos=timeRegExp.search(resultHTML , pos) ) != -1 )
++	{
++		QString timeKeyword = formatTime( timeRegExp.cap(1), message.timestamp() );
++		resultHTML = resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword );
++	}
++
++	// Look for %textbackgroundcolor{X}% 
++	// TODO: use the X value.
++	// Replace with user-selected highlight color if to be highlighted or
++	// with "inherit" otherwise to keep CSS clean
++	QString bgColor = QString::fromUtf8("inherit");
++	if( message.importance() == Kopete::Message::Highlight && KopetePrefs::prefs()->highlightEnabled() )
++	{
++		bgColor = KopetePrefs::prefs()->highlightBackground().name();
++	}
++
++	QRegExp textBackgroundRegExp("%textbackgroundcolor\\{([^}]*)\\}%");
++	int textPos=0;
++	while( (textPos=textBackgroundRegExp.search(resultHTML, textPos) ) != -1 )
++	{
++		resultHTML = resultHTML.replace( textPos , textBackgroundRegExp.cap(0).length() , bgColor );
++	}
++
++	// Replace userIconPath
++	if( message.from() )
++	{
++		QString photoPath;
++#if 0
++		photoPath = message.from()->property(Kopete::Global::Properties::self()->photo().key()).value().toString();
++		// If the photo path is empty, set the default buddy icon for the theme
++		if( photoPath.isEmpty() )
+ 		{
+-//			kdDebug(14000) << k_funcinfo << "disabling transparency" << endl;
+-			delete root;
+-			root = 0;
+-			if( backgroundFile )
+-			{
+-				backgroundFile->close();
+-				backgroundFile->unlink();
+-				delete backgroundFile;
+-				backgroundFile = 0;
+-			}
+-			executeScript( QString::fromLatin1("document.body.background = \"\";") );
++			if(message.direction() == Kopete::Message::Inbound)
++				photoPath = QString::fromUtf8("Incoming/buddy_icon.png");
++			else if(message.direction() == Kopete::Message::Outbound)
++				photoPath = QString::fromUtf8("Outgoing/buddy_icon.png");
+ 		}
++#endif
++		if( !message.from()->metaContact()->picture().isNull() )
++		{
++			photoPath = QString("data:image/png;base64,%1").arg( message.from()->metaContact()->picture().base64() );
++		}
++		else
++		{
++			if(message.direction() == Kopete::Message::Inbound)
++				photoPath = QString::fromUtf8("Incoming/buddy_icon.png");
++			else if(message.direction() == Kopete::Message::Outbound)
++				photoPath = QString::fromUtf8("Outgoing/buddy_icon.png");
++		}
++		resultHTML = resultHTML.replace(QString::fromUtf8("%userIconPath%"), photoPath);
+ 	}
++
++	// Replace messages.
++	// Build the action message if the currentChatStyle do not have Action template.
++	if( message.type() == Kopete::Message::TypeAction && !d->currentChatStyle->hasActionTemplate() )
++	{
++		kdDebug(14000) << k_funcinfo << "Map Action message to Status template. " << endl;
++
++		QString boldNick = QString::fromUtf8("%1<b>%2</b></a> ").arg(nickLink,nick);
++		QString newBody = boldNick + message.parsedBody();
++		message.setBody(newBody, Kopete::Message::ParsedHTML );
++	}
++
++	// Set message direction("rtl"(Right-To-Left) or "ltr"(Left-to-right))
++	resultHTML = resultHTML.replace( QString::fromUtf8("%messageDirection%"), message.plainBody().isRightToLeft() ? "rtl" : "ltr" );
++
++	// These colors are used for coloring nicknames. I tried to use
++	// colors both visible on light and dark background.
++	static const char* const nameColors[] =
++	{
++		"red", "blue" , "gray", "magenta", "violet", /*"olive"*/ "#808000", "yellowgreen",
++		"darkred", "darkgreen", "darksalmon", "darkcyan", /*"darkyellow"*/   "#B07D2B",
++		"mediumpurple", "peru", "olivedrab", /*"royalred"*/ "#B01712", "darkorange", "slateblue",
++		"slategray", "goldenrod", "orangered", "tomato", /*"dogderblue"*/ "#1E90FF", "steelblue",
++		"deeppink", "saddlebrown", "coral", "royalblue"
++	};
++
++	static const int nameColorsLen = sizeof(nameColors) / sizeof(nameColors[0]) - 1;
++	// hash contactId to deterministically pick a color for the contact
++	int hash = 0;
++	for( uint f = 0; f < contactId.length(); ++f )
++		hash += contactId[f].unicode() * f;
++	QColor color = QColor( nameColors[ hash % nameColorsLen ] ).name();
++	kdDebug(14000) << k_funcinfo << hash << " has color " << nameColors[ hash % nameColorsLen ] << endl;
++	QRegExp senderColorRegExp("%senderColor(?:\\{([^}]*)\\})?%");
++	textPos=0;
++	while( (textPos=senderColorRegExp.search(resultHTML, textPos) ) != -1 )
++	{
++		int light=100;
++		bool doLight=false;
++		if(senderColorRegExp.numCaptures()>=1)
++		{
++			light=senderColorRegExp.cap(1).toUInt(&doLight);
++		}
++		resultHTML = resultHTML.replace( textPos , senderColorRegExp.cap(0).length() , doLight ? color.light(light).name() : color.name() );
++	}
++
++	// Replace message at the end, maybe someone could put a Adium keyword in his message :P
++	resultHTML = resultHTML.replace( QString::fromUtf8("%message%"), formatMessageBody(message) );
++
++	// TODO: %status
++//	resultHTML = addNickLinks( resultHTML );
++	return resultHTML;
+ }
+ 
+-void ChatMessagePart::slotUpdateBackground( const QPixmap &pixmap )
++// Style formatting for header and footer.
++QString ChatMessagePart::formatStyleKeywords( const QString &sourceHTML )
+ {
+-	if( backgroundFile )
++	QString resultHTML = sourceHTML;
++
++	Kopete::Contact *remoteContact = d->manager->members().getFirst();
++
++	// Verify that all contacts are not null before doing anything
++	if( remoteContact && d->manager->myself() )
+ 	{
+-		backgroundFile->close();
+-		backgroundFile->unlink();
+-		delete backgroundFile;
++		QString sourceName, destinationName;
++		// Use contact nickname for ourselfs, Myself metacontact display name isn't a reliable source.
++		sourceName = d->manager->myself()->nickName();
++		if( remoteContact->metaContact() )
++			destinationName = remoteContact->metaContact()->displayName();
++		else
++			destinationName = remoteContact->nickName();
++
++		// Replace %chatName%, create a internal span to update it by DOM when asked.
++		resultHTML = resultHTML.replace( QString::fromUtf8("%chatName%"), QString("<span id=\"KopeteHeaderChatNameInternal\">%1</span>").arg( formatName(d->manager->displayName()) ) );
++		// Replace %sourceName%
++		resultHTML = resultHTML.replace( QString::fromUtf8("%sourceName%"), formatName(sourceName) );
++		// Replace %destinationName%
++		resultHTML = resultHTML.replace( QString::fromUtf8("%destinationName%"), formatName(destinationName) );
++		// For %timeOpened%, display the date and time (also the seconds).
++		resultHTML = resultHTML.replace( QString::fromUtf8("%timeOpened%"), KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), true, true ) );
++
++		// Look for %timeOpened{X}%
++		QRegExp timeRegExp("%timeOpened\\{([^}]*)\\}%");
++		int pos=0;
++		while( (pos=timeRegExp.search(resultHTML, pos) ) != -1 )
++		{
++			QString timeKeyword = formatTime( timeRegExp.cap(1), QDateTime::currentDateTime() );
++			resultHTML = resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword );
++		}
++		// Get contact image paths
++#if 0
++		QString photoIncomingPath, photoOutgoingPath;
++		photoIncomingPath = remoteContact->property( Kopete::Global::Properties::self()->photo().key()).value().toString();
++		photoOutgoingPath = d->manager->myself()->property(Kopete::Global::Properties::self()->photo().key()).value().toString();
++
++		if( photoIncomingPath.isEmpty() )
++			photoIncomingPath = QString::fromUtf8("Incoming/buddy_icon.png");
++		if( photoOutgoingPath.isEmpty() )
++			photoOutgoingPath = QString::fromUtf8("Outgoing/buddy_icon.png");
++
++		resultHTML = resultHTML.replace( QString::fromUtf8("%incomingIconPath%"), photoIncomingPath);
++		resultHTML = resultHTML.replace( QString::fromUtf8("%outgoingIconPath%"), photoOutgoingPath);
++#endif
++		QString photoIncoming, photoOutgoing;
++		if( remoteContact->metaContact() && !remoteContact->metaContact()->picture().isNull() )
++		{
++			photoIncoming = QString("data:image/png;base64,%1").arg( remoteContact->metaContact()->picture().base64() );
++		}
++		else
++		{
++			photoIncoming = QString::fromUtf8("Incoming/buddy_icon.png");
++		}
++		
++		if( d->manager->myself()->metaContact() && !d->manager->myself()->metaContact()->picture().isNull() )
++		{
++			photoOutgoing =  QString("data:image/png;base64,%1").arg( d->manager->myself()->metaContact()->picture().base64() );
++		}
++		else
++		{
++			photoOutgoing = QString::fromUtf8("Outgoing/buddy_icon.png");
++		}
++
++
++		resultHTML = resultHTML.replace( QString::fromUtf8("%incomingIconPath%"), photoIncoming);
++		resultHTML = resultHTML.replace( QString::fromUtf8("%outgoingIconPath%"), photoOutgoing );
+ 	}
+ 
+-	backgroundFile = new KTempFile( QString::null, QString::fromLatin1( ".bmp" ) );
+-	pixmap.save( backgroundFile->name(), "BMP" );
++	return resultHTML;
++}
+ 
+-	bgChanged = true;
++QString ChatMessagePart::formatTime(const QString &timeFormat, const QDateTime &dateTime)
++{
++	char buffer[256];
+ 
+-	//This doesn't work well using the DOM, so just use some JS
+-	if ( bgChanged && backgroundFile && !backgroundFile->name().isNull() )
++	time_t timeT;
++	struct tm *loctime;
++	// Get current time
++	timeT = dateTime.toTime_t();
++	// Convert it to local time representation.
++	loctime = localtime (&timeT);
++	strftime (buffer, 256, timeFormat.ascii(), loctime);
++
++	return QString(buffer);
++}
++
++QString ChatMessagePart::formatName(const QString &sourceName)
++{
++	QString formattedName = sourceName;
++	// Escape the name.
++	formattedName = Kopete::Message::escape(formattedName);
++
++	// Squeeze the nickname if the user want it
++	if( KopetePrefs::prefs()->truncateContactNames() )
+ 	{
+-		setJScriptEnabled( true ) ;
+-		executeScript( QString::fromLatin1( "document.body.background = \"%1\";" ).arg( backgroundFile->name() ) );
+-		setJScriptEnabled( false ) ;
++		formattedName = KStringHandler::csqueeze( sourceName, KopetePrefs::prefs()->maxConactNameLength() );
+ 	}
+ 
+-	bgChanged = false;
++	return formattedName;
++}
+ 
+-	if ( !scrollPressed )
+-		QTimer::singleShot( 1, this, SLOT( slotScrollView() ) );
++QString ChatMessagePart::formatMessageBody(const Kopete::Message &message)
++{
++	QString formattedBody("<span ");
++	
++	formattedBody += message.getHtmlStyleAttribute();
++
++	// Affect the parsed body.
++	formattedBody += QString::fromUtf8("class=\"KopeteMessageBody\">%1</span>").arg(message.parsedBody());
++	
++	return formattedBody;
+ }
+ 
+-void ChatMessagePart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * event) //virtual
++void ChatMessagePart::slotUpdateHeaderDisplayName()
+ {
+-	KHTMLPart::khtmlDrawContentsEvent(event);
+-	//copy(true /*selection only*/); not needed anymore.
++	kdDebug(14000) << k_funcinfo << endl;
++	DOM::HTMLElement kopeteChatNameNode = document().getElementById( QString::fromUtf8("KopeteHeaderChatNameInternal") );
++	if( !kopeteChatNameNode.isNull() )
++		kopeteChatNameNode.setInnerText( formatName(d->manager->displayName()) );
+ }
+-void ChatMessagePart::slotCloseView( bool force )
++
++void ChatMessagePart::slotUpdateHeaderPhoto()
+ {
+-	m_manager->view()->closeView( force );
++	// Do the actual style switch
++	// Wait for the event loop before switching the style
++	QTimer::singleShot( 0, this, SLOT(changeStyle()) );
+ }
+ 
+-void ChatMessagePart::emitTooltipEvent(  const QString &textUnderMouse, QString &toolTip )
++void ChatMessagePart::changeStyle()
+ {
+-	emit tooltipEvent(  textUnderMouse, toolTip );
++#ifdef STYLE_TIMETEST
++	QTime beforeChange = QTime::currentTime();
++#endif
++	// Make latestContact null to reset consecutives messages.
++	d->latestContact = 0;
++
++	// Rewrite the header and footer.
++	writeTemplate();
++	
++	// Readd all current messages.
++	QValueList<Kopete::Message>::ConstIterator it, itEnd = d->allMessages.constEnd();
++	for(it = d->allMessages.constBegin(); it != itEnd; ++it)
++	{
++		Kopete::Message tempMessage = *it;
++		appendMessage(tempMessage, true); // true means that we are restoring.
++	}
++	kdDebug(14000) << k_funcinfo << "Finish changing style." << endl;
++#ifdef STYLE_TIMETEST
++	kdDebug(14000) << "Change time: " << beforeChange.msecsTo( QTime::currentTime()) << endl;
++#endif
+ }
+ 
++void ChatMessagePart::writeTemplate()
++{
++	kdDebug(14000) << k_funcinfo << endl;
++
++#ifdef STYLE_TIMETEST
++	QTime beforeHeader = QTime::currentTime();
++#endif
++	// Clear all the page, and begin a new page.
++	begin();
++
++	// NOTE: About styles
++	// Order of style tag in the template is important.
++	// mainStyle take over all other style definition (which is what we want).
++	//
++	// KopeteStyle: Kopete appearance configuration into a style. It loaded first because
++	// we don't want Kopete settings to override CSS Chat Window Style.
++	// baseStyle: Import the main.css from the Chat Window Style
++	// mainStyle: Currrent variant CSS url.
++
++	// FIXME: Maybe this string should be load from a file, then parsed for args.
++	QString xhtmlBase;
++	xhtmlBase += QString("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
++		"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
++		"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
++		"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
++    	"<head>\n"
++        "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\n\" />\n"
++        "<base href=\"%1\">\n"
++		"<style id=\"KopeteStyle\" type=\"text/css\" media=\"screen,print\">\n"
++		"	%5\n"
++		"</style>\n"
++		"<style id=\"baseStyle\" type=\"text/css\" media=\"screen,print\">\n"
++		"	@import url(\"main.css\");\n"
++		"	*{ word-wrap:break-word; }\n"
++		"</style>\n"
++		"<style id=\"mainStyle\" type=\"text/css\" media=\"screen,print\">\n"
++		"	@import url(\"%4\");\n"
++        "</style>\n"
++		"</head>\n"
++		"<body>\n"
++		"%2\n"
++		"<div id=\"Chat\">\n</div>\n"
++		"%3\n"
++		"</body>"
++		"</html>"
++		).arg( d->currentChatStyle->getStyleBaseHref() )
++		.arg( formatStyleKeywords(d->currentChatStyle->getHeaderHtml()) )
++		.arg( formatStyleKeywords(d->currentChatStyle->getFooterHtml()) )
++		.arg( KopetePrefs::prefs()->styleVariant() )
++		.arg( styleHTML() );
++	write(xhtmlBase);
++	end();
++#ifdef STYLE_TIMETEST
++	kdDebug(14000) << "Header time: " << beforeHeader.msecsTo( QTime::currentTime()) << endl;
++#endif
++}
++
+ #include "chatmessagepart.moc"
+ 
+ // vim: set noet ts=4 sts=4 sw=4:
+--- kopete/kopete/chatwindow/kopetechatwindow.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/kopetechatwindow.cpp	(revision 586398)
+@@ -1,7 +1,7 @@
+ /*
+     kopetechatwindow.cpp - Chat Window
+ 
+-    Copyright (c) 2002-2005 by Olivier Goffart       <ogoffart@ kde.org>
++    Copyright (c) 2002-2006 by Olivier Goffart       <ogoffart@ kde.org>
+     Copyright (c) 2003-2004 by Richard Smith         <kde at metafoo.co.uk>
+     Copyright (C) 2002      by James Grant
+     Copyright (c) 2002      by Stefan Gehn           <metz AT gehn.net>
+@@ -311,10 +311,8 @@
+ 
+ 	createStandardStatusBarAction();
+ 
+-	chatSend = new KAction( i18n( "&Send Message" ), QString::fromLatin1( "mail_send" ), 0,
++	chatSend = new KAction( i18n( "&Send Message" ), QString::fromLatin1( "mail_send" ), QKeySequence(Key_Return) ,
+ 		this, SLOT( slotSendMessage() ), coll, "chat_send" );
+-	//Default to 'Return' for sending messages
+-	chatSend->setShortcut( QKeySequence(Key_Return) );
+ 	chatSend->setEnabled( false );
+ 
+  	KStdAction::save ( this, SLOT(slotChatSave()), coll );
+@@ -381,7 +379,7 @@
+ 	toggleAutoSpellCheck = new KToggleAction( i18n( "Automatic Spell Checking" ), QString::null, 0,
+ 		this, SLOT( toggleAutoSpellChecking() ), coll, "enable_auto_spell_check" );
+ 	toggleAutoSpellCheck->setChecked( true );
+-	
++
+ 	actionSmileyMenu = new KopeteEmoticonAction( coll, "format_smiley" );
+ 	actionSmileyMenu->setDelayed( false );
+ 	connect(actionSmileyMenu, SIGNAL(activated(const QString &)), this, SLOT(slotSmileyActivated(const QString &)));
+@@ -702,8 +700,12 @@
+ 	connect( newView, SIGNAL(rtfEnabled( ChatView*, bool ) ), this, SLOT( slotRTFEnabled( ChatView*, bool ) ) );
+ 	connect( newView, SIGNAL(updateStatusIcon( ChatView* ) ), this, SLOT(slotUpdateCaptionIcons( ChatView* ) ) );
+ 	connect( newView, SIGNAL(updateChatState( ChatView*, int ) ), this, SLOT( updateChatState( ChatView*, int ) ) );
++
+ 	updateSpellCheckAction();
+ 	checkDetachEnable();
++	newView->loadChatSettings();
++	connect( newView, SIGNAL(autoSpellCheckEnabled( ChatView*, bool ) ),
++	         this, SLOT( slotAutoSpellCheckEnabled( ChatView*, bool ) ) );
+ }
+ 
+ void KopeteChatWindow::checkDetachEnable()
+@@ -839,10 +841,11 @@
+ 	{
+ 		disconnect( m_activeView, SIGNAL( canSendChanged(bool) ), this, SLOT( slotUpdateSendEnabled() ) );
+ 		guiFactory()->removeClient(m_activeView->msgManager());
++		m_activeView->saveChatSettings();
+ 	}
+ 
+ 	guiFactory()->addClient(view->msgManager());
+-	createGUI( view->part() );
++	createGUI( view->editPart() );
+ 
+ 	if( m_activeView )
+ 		m_activeView->setActive( false );
+@@ -889,6 +892,7 @@
+ 	updateSpellCheckAction();
+ 	slotUpdateSendEnabled();
+ 	m_activeView->editPart()->reloadConfig();
++	m_activeView->loadChatSettings();
+ }
+ 
+ void KopeteChatWindow::slotUpdateCaptionIcons( ChatView *view )
+@@ -903,7 +907,7 @@
+ 		if(!c || c->onlineStatus() < contact->onlineStatus())
+ 			c=contact;
+ 	}
+-	
++
+ 	if ( view == m_activeView )
+  	{
+ 		QPixmap icon16 = c ? view->msgManager()->contactOnlineStatus( c ).iconFor( c , 16) :
+@@ -1095,6 +1099,16 @@
+ 	updateSpellCheckAction();
+ }
+ 
++void KopeteChatWindow::slotAutoSpellCheckEnabled( ChatView* view, bool isEnabled )
++{
++	if ( view != m_activeView )
++		return;
++
++	toggleAutoSpellCheck->setEnabled( isEnabled );
++	toggleAutoSpellCheck->setChecked( isEnabled );
++	m_activeView->editPart()->toggleAutoSpellCheck( isEnabled );
++}
++
+ bool KopeteChatWindow::queryClose()
+ {
+ 	bool canClose = true;
+@@ -1135,7 +1149,7 @@
+ 		Kopete::PluginManager::self()->shutdown();
+ 		return true;
+ 	}
+-	else 
++	else
+ 		return false;
+ }
+ 
+@@ -1150,7 +1164,7 @@
+ 		// Save settings if auto-save is enabled, and settings have changed
+ 		if ( settingsDirty() && autoSaveSettings() )
+ 			saveAutoSaveSettings();
+-	
++
+ 		if ( queryClose() ) {
+ 			e->accept();
+ 		}
+@@ -1175,8 +1189,8 @@
+ 			++it;
+ 		}
+ 
+-		if( m_activeView->part() )
+-			dlg.insert( m_activeView->part()->actionCollection(), m_activeView->part()->name() );
++		if( m_activeView->editPart() )
++			dlg.insert( m_activeView->editPart()->actionCollection(), m_activeView->editPart()->name() );
+ 	}
+ 
+ 	dlg.configure();
+@@ -1189,10 +1203,7 @@
+ 	if (dlg->exec())
+ 	{
+ 		if( m_activeView )
+-		{
+-			createGUI( m_activeView->part() );
+-			//guiFactory()->addClient(m_activeView->msgManager());
+-		}
++			createGUI( m_activeView->editPart() );
+ 		else
+ 			createGUI( 0L );
+ 		applyMainWindowSettings(KGlobal::config(), QString::fromLatin1( "KopeteChatWindow" ));
+--- kopete/kopete/chatwindow/chatview.h	(revision 568672)
++++ kopete/kopete/chatwindow/chatview.h	(revision 586398)
+@@ -82,6 +82,16 @@
+ 	void setActive( bool value );
+ 
+ 	/**
++	 * save the chat settings (rich text, auto spelling)
++	 */
++	void saveChatSettings();
++
++	/**
++	 * read the chat settings (rich text, auto spelling)
++	 */
++	void loadChatSettings();
++
++	/**
+ 	 * Clears the chat buffer
+ 	 *
+ 	 * Reimplemented from KopeteView
+@@ -94,14 +104,13 @@
+ 	void setCaption( const QString &text, bool modified );
+ 
+ 	/**
+-	 * Changes the pointer to the chat widnow. Used to re-parent the view
++	 * Changes the pointer to the chat window. Used to re-parent the view
+ 	 * @param parent The new chat window
+ 	 */
+ 	void setMainWindow( KopeteChatWindow* parent );
+ 
+ 	/**
+ 	 * Returns the message currently in the edit area
+-	 * Reimplemented from KopeteView
+ 	 * @return The Kopete::Message object for the message
+ 	 *
+ 	 * Reimplemented from KopeteView
+@@ -168,10 +177,10 @@
+ 
+ 	bool canSend();
+ 
+-	/** Reimplimented from KopeteView **/
++	/** Reimplemented from KopeteView **/
+ 	virtual void registerContextMenuHandler( QObject *target, const char* slot );
+ 
+-	/** Reimplimented from KopeteView **/
++	/** Reimplemented from KopeteView **/
+ 	virtual void registerTooltipHandler( QObject *target, const char* slot );
+ 
+ public slots:
+@@ -254,8 +263,6 @@
+ 
+ 	virtual bool closeView( bool force = false );
+ 
+-	KParts::Part *part() const;
+-
+ signals:
+ 	/**
+ 	 * Emitted when a message is sent
+@@ -302,8 +309,13 @@
+ 	 */
+ 	void rtfEnabled( ChatView*, bool );
+ 
++	void autoSpellCheckEnabled( ChatView*, bool );
++
+ private slots:
+ 	void slotRemoteTypingTimeout();
++	/**
++	 * Show that a contact changed his nickname when a metacontact is not avaiable.
++	 */
+ 	void slotPropertyChanged( Kopete::Contact *contact, const QString &key, const QVariant &oldValue, const QVariant &newValue  );
+ 
+ 	/**
+@@ -342,6 +354,11 @@
+ 
+ 	void slotToggleRtfToolbar( bool enabled );
+ 
++	/**
++	 * Show that a (meta)contact change his display name.
++	 */
++	void slotDisplayNameChanged(const QString &oldValue, const QString &newValue);
++
+ protected:
+ 	virtual void dragEnterEvent ( QDragEnterEvent * );
+ 	virtual void dropEvent ( QDropEvent * );
+--- kopete/kopete/chatwindow/chatmessagepart.h	(revision 568672)
++++ kopete/kopete/chatwindow/chatmessagepart.h	(revision 586398)
+@@ -2,8 +2,9 @@
+     chatmessagepart.h - Chat Message KPart
+ 
+     Copyright (c) 2004      by Richard Smith         <kde at metafoo.co.uk>
++    Copyright (c) 2005      by Michaël Larouche      <michael.larouche at kdemail.net>
+ 
+-    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -19,20 +20,19 @@
+ #define CHATMESSAGEPART_H
+ 
+ #include <khtml_part.h>
+-
+ #include <dom/html_element.h>
+ 
+-#include <qptrdict.h>
+ #include <qvaluelist.h>
+-#include <qpair.h>
+ 
+-#include "kopeteview.h"
++namespace Kopete
++{ 
++	class Message; 
++	class ChatSession; 
++	class Contact; 
++}
++class KPopupMenu;
++class ChatWindowStyle;
+ 
+-class KTempFile;
+-class KRootPixmap;
+-namespace DOM { class Node; }
+-namespace Kopete { class ChatSession; }
+-
+ /**
+  * @author Richard Smith
+  */
+@@ -40,7 +40,10 @@
+ {
+ 	Q_OBJECT
+ public:
+-	ChatMessagePart( Kopete::ChatSession *manager, QWidget *parent, const char *name = 0 );
++	/**
++	 * Create a new ChatMessage Part.
++	 */
++	ChatMessagePart( Kopete::ChatSession *manager, QWidget *parent, const char *name = 0);
+ 	~ChatMessagePart();
+ 
+ 	/**
+@@ -48,8 +51,6 @@
+ 	 */
+ 	void clear();
+ 
+-	void setStylesheet( const QString &style  );
+-
+ 	/**
+ 	 * Immediately scroll the chat to the bottom, as long as it has not been intentionally scrolled away from the bottom
+ 	 * use 
+@@ -90,9 +91,38 @@
+ 	/**
+ 	 * Appends a message to the messave view
+ 	 * @param message The message to be appended
++	 * @param restoring This flag is used to not re-append message when changing style. By default false.
+ 	 */
+-	void appendMessage( Kopete::Message &message );
++	void appendMessage( Kopete::Message &message, bool restoring = false);
+ 
++	/**
++	 * Change the current style.
++	 * This method override is used when preferences change.
++	 * This method create a new ChatWindowStyle object.
++	 *
++	 * Need to rebuild all the XHTML content.
++	 *
++	 * @param stylePath absolute path to the style.
++	 */
++	void setStyle( const QString &stylePath );
++	
++	/**
++	 * Change the current style
++	 * This method override is used on preview and unit tests.
++	 * Use a already existing ChatWindowStyle object.
++	 *
++	 * Need to rebuild all the XHTML content.
++	 *
++	 * @param chatWindowStyle ChatWindowStyle object.
++	 */
++	void setStyle( ChatWindowStyle *style );
++	
++	/**
++	 * Change the current variant for the current style
++	 * @param variantPath relative path to the style variant.
++	 */
++	void setStyleVariant( const QString &variantPath );
++
+ signals:
+ 	/**
+ 	 * Emits before the context menu is about to show
+@@ -109,61 +139,38 @@
+ 	void slotScrollView();
+ 	void slotAppearanceChanged();
+ 
+-	/**
+-	 * Called when KopetePrefs are saved
+-	 */
+-	void slotTransparencyChanged();
+-
+-	/**
+-	 * Sets the background of the widget
+-	 * @param pm The new background image
+-	 */
+-	void slotUpdateBackground( const QPixmap &pm );
+-
+ 	void slotScrollingTo( int x, int y );
+ 
+-	void slotRefreshNodes();
+-
+ 	void slotRefreshView();
+ 
+-	void slotTransformComplete( const QVariant &result );
+-
+ 	void slotRightClick( const QString &, const QPoint &point );
+ 
+ 	void slotCopyURL();
+ 
+ 	void slotCloseView( bool force = false );
+ 
++	/**
++	 * Do the actual style change.
++	 */
++	void changeStyle();
++	
++	/**
++	 * Update the display in the header template if any.
++	 */
++	void slotUpdateHeaderDisplayName();
++	/**
++	 * Upda the photo in the header.
++	 */
++	void slotUpdateHeaderPhoto();
++
+ protected:
+ 	virtual void khtmlDrawContentsEvent( khtml::DrawContentsEvent * );
+ 	
+ private:
+-	Kopete::ChatSession *m_manager;
+-
+-	unsigned long messageId;
+-	QStringList messageMap;
+-
+-	bool scrollPressed;
+-	bool bgChanged;
+-
+-	DOM::HTMLElement activeElement;
+-
+-	// FIXME: share
+-	KTempFile *backgroundFile;
+-	KRootPixmap *root;
+-
+-	KAction *copyAction;
+-	KAction *saveAction;
+-	KAction *printAction;
+-	KAction *closeAction;
+-	KAction *copyURLAction;
+-
+ 	void readOverrides();
+ 
+ 	const QString styleHTML() const;
+ 
+-	const QString addNickLinks( const QString &html ) const;
+-
+ 	Kopete::Contact *contactFromNode( const DOM::Node &n ) const;
+ 
+ 	/**
+@@ -176,6 +183,58 @@
+ 	 */
+ 	QString textUnderMouse();
+ 
++	/**
++	 * Format(replace) style keywords for messages (incoming, outgoing, internal)
++	 * Use formatStyleKeywords(const QString &sourceHTML) for header and footer.
++	 *
++	 * @param sourceHTML the source html which contains the keywords
++	 * @param message the current Message.
++	 * 
++	 * @return the resulting HTML with replaced keywords.
++	 */
++	QString formatStyleKeywords( const QString &sourceHTML, const Kopete::Message &message );
++	/**
++	 * Format(replace) style keywords for header and footers.
++	 * For messages, use formatStyleKeywords(const QString &sourceHTML, Kopete::Message &message)  instead.
++	 *
++	 * @param sourceHTML HTML source needed to be replaced.
++	 *
++	 * @return the resulting HTML with replaced keywords.
++	 */
++	QString formatStyleKeywords( const QString &sourceHTML );
++
++	/**
++	 * Helper function to parse time in correct format.
++	 * Use glibc strftime function.
++	 *
++	 * @param timeFormat the time format to parse.
++	 * @param dateTime the QDateTime which contains the datetime to format.
++	 * @return the formatted time string.
++	 */
++	QString formatTime(const QString &timeFormat, const QDateTime &dateTime);
++
++	/**
++	 * Format a nickname/displayname according to preferences.
++	 *
++	 * @param sourceName Source name to format.
++	 * @return the formatted name.
++	 */
++	QString formatName( const QString &sourceName );
++
++	/**
++	 * Format a message body according to the style included
++	 * in the message.
++	 *
++	 * @param message Kopete::Message to format.
++	 * @return a span tag with a style attribute.
++	 */
++	QString formatMessageBody( const Kopete::Message &message );
++
++	/**
++	 * Write the template file to KHTMLPart
++	 */
++	void writeTemplate();
++
+ 	class ToolTip;
+ 	friend class ToolTip;
+ 
+--- kopete/kopete/chatwindow/chattexteditpart.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/chattexteditpart.cpp	(revision 586398)
+@@ -280,13 +280,13 @@
+ 		m_lastMatch = QString::null;
+ 	}
+ 
++	slotStoppedTypingTimer();
+ 	Kopete::Message sentMessage = contents();
+ 	emit messageSent( sentMessage );
+ 	historyList.prepend( edit()->text() );
+ 	historyPos = -1;
+ 	clear();
+ 	emit canSendChanged( false );
+-	slotStoppedTypingTimer();
+ }
+ 
+ bool ChatTextEditPart::isTyping()
+@@ -342,7 +342,10 @@
+ 	historyPos++;
+ 	
+ 	QString newText = historyList[historyPos];
+-	edit()->setText( historyList[historyPos] );
++	TextFormat format=edit()->textFormat();
++	edit()->setTextFormat(AutoText); //workaround bug 115690
++	edit()->setText( newText );
++	edit()->setTextFormat(format);
+ 	edit()->moveCursor( QTextEdit::MoveEnd, false );
+ }
+ 
+@@ -363,7 +366,15 @@
+ 	historyPos--;
+ 	
+ 	QString newText = ( historyPos >= 0 ? historyList[historyPos] : QString::null );
++	
++	
++	TextFormat format=edit()->textFormat();
++	edit()->setTextFormat(AutoText); //workaround bug 115690
+ 	edit()->setText( newText );
++	edit()->setTextFormat(format);
++	
++	
++	
+ 	edit()->moveCursor( QTextEdit::MoveEnd, false );
+ }
+ 
+@@ -374,7 +385,7 @@
+ 
+ void ChatTextEditPart::setContents( const Kopete::Message &message )
+ {
+-	edit()->setText( message.plainBody() );
++	edit()->setText( richTextEnabled() ? message.escapedBody() : message.plainBody() );
+ 
+ 	setFont( message.font() );
+ 	setFgColor( message.fg() );
+@@ -402,6 +413,7 @@
+ void ChatTextEditPart::slotStoppedTypingTimer()
+ {
+ 	m_typingRepeatTimer->stop();
++	m_typingStopTimer->stop();
+ 	emit typing( false );
+ }
+ 
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Incoming/NextContent.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Incoming/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++Incoming:
++<div>%message%</div>
++<div id="insert">
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Incoming/Content.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Incoming/Content.html	(revision 586398)
+@@ -0,0 +1,9 @@
++Incoming:
++<div>%userIconPath%</div>
++<div>%senderScreenName%</div>
++<div>%sender%</div>
++<div>%service%</div>
++<div>%message%</div>
++<div>%time%</div>
++<div>%time{%H:%M}%</div>
++<div id="insert">
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Status.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Status.html	(revision 586398)
+@@ -0,0 +1,3 @@
++<div>%message%</div>
++<div>%time%</div>
++<div>%time{%H:%M}%</div>
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Variants/Variant1.css	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Variants/Variant1.css	(revision 586398)
+@@ -0,0 +1 @@
++ 
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Variants/Variant2.css	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Variants/Variant2.css	(revision 586398)
+@@ -0,0 +1 @@
++ 
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Header.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Header.html	(revision 586398)
+@@ -0,0 +1,7 @@
++<div>%chatName%</div>
++<div>%sourceName%</div>
++<div>%destinationName%</div>
++<div>%incomingIconPath%</div>
++<div>%outgoingIconPath%</div>
++<div>%timeOpened%</div>
++<div>%timeOpened{%H:%M}%</div>
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Outgoing/NextContent.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Outgoing/NextContent.html	(revision 586398)
+@@ -0,0 +1,3 @@
++Outgoing:
++<div>%message%</div>
++<div id="insert">
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Outgoing/Content.html	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/Outgoing/Content.html	(revision 586398)
+@@ -0,0 +1,9 @@
++Outgoing:
++<div>%userIconPath%</div>
++<div>%senderScreenName%</div>
++<div>%sender%</div>
++<div>%service%</div>
++<div>%message%</div>
++<div>%time%</div>
++<div>%time{%H:%M}%</div>
++<div id="insert">
+\ No newline at end of file
+--- kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/main.css	(revision 0)
++++ kopete/kopete/chatwindow/tests/TestStyle/Contents/Resources/main.css	(revision 586398)
+@@ -0,0 +1 @@
++ 
+--- kopete/kopete/chatwindow/tests/chatwindowstylerendering_test.cpp	(revision 0)
++++ kopete/kopete/chatwindow/tests/chatwindowstylerendering_test.cpp	(revision 586398)
+@@ -0,0 +1,329 @@
++/*
++    Adium(and Kopete) ChatWindowStyle format rendering test suite
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at 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 "chatwindowstylerendering_test.h"
++
++#include <stdlib.h>
++
++// Qt includes
++#include <qdir.h>
++#include <qfile.h>
++#include <qdatetime.h>
++#include <qtextstream.h>
++
++// KDE includes
++#include <kapplication.h>
++#include <kunittest/module.h>
++#include <kinstance.h>
++#include <kdebug.h>
++#include <kglobal.h>
++#include <klocale.h>
++
++#include <kopetechatwindowstyle.h>
++
++// Libkopete includes
++#include <kopeteprotocol.h>
++#include <kopetemetacontact.h>
++#include <kopeteaccount.h>
++#include <kopetecontact.h>
++#include <kopetechatsession.h>
++#include <kopetechatsessionmanager.h>
++
++using namespace Kopete;
++
++KUNITTEST_MODULE( kunittest_chatwindowstylerendering_test, "KopeteChatWindowTestSuite");
++KUNITTEST_MODULE_REGISTER_TESTER( ChatWindowStyleRendering_Test );
++
++// Reimplement Kopete::Contact and its abstract method
++class FakeContact : public Kopete::Contact
++{
++public:
++	FakeContact (Kopete::Account *account, const QString &id, Kopete::MetaContact *mc ) : Kopete::Contact( account, id, mc ) {}
++	virtual Kopete::ChatSession *manager(Kopete::Contact::CanCreateFlags /*c*/) { return 0L; }
++	virtual void slotUserInfo() {};
++};
++
++class FakeProtocol : public Kopete::Protocol
++{
++public:
++FakeProtocol( KInstance *instance, QObject *parent, const char *name ) : Kopete::Protocol(instance, parent, name)
++{
++	
++}
++
++Account* createNewAccount( const QString &/*accountId*/ )
++{
++	return 0L;
++}
++
++AddContactPage* createAddContactWidget( QWidget */*parent*/, Kopete::Account */*account*/)
++{
++	return 0L;
++}
++
++KopeteEditAccountWidget* createEditAccountWidget( Kopete::Account */*account*/, QWidget */*parent */)
++{
++	return 0L;
++}
++
++};
++
++class FakeAccount : public Kopete::Account
++{
++public:
++FakeAccount(Kopete::Protocol *parent, const QString &accountID, const char *name) : Kopete::Account(parent, accountID, name)
++{
++
++}
++
++~FakeAccount()
++{
++
++}
++
++bool createContact( const QString &/*contactId*/, Kopete::MetaContact */*parentContact*/ )
++{
++	return true;
++}
++
++void connect( const Kopete::OnlineStatus& /*initialStatus*/)
++{
++	// do nothing
++}
++
++void disconnect()
++{
++	// do nothing
++}
++
++void setOnlineStatus( const Kopete::OnlineStatus& /*status*/ , const QString &/*reason*/)
++{
++	// do nothing
++}
++};
++
++class ChatWindowStyleRendering_Test::Private
++{
++public:
++	Private()
++	{
++		protocol = new FakeProtocol( new KInstance(QCString("test-kopete-message")), 0L, "test-kopete-message");
++		account = new FakeAccount(protocol, QString("testaccount"), 0);
++
++		// Create fake meta/contacts
++		myselfMetaContact = new Kopete::MetaContact();
++		myself = new FakeContact(account, "bob at localhost", myselfMetaContact);
++		myself->setNickName("Bob");
++		otherMetaContact = new Kopete::MetaContact();
++		other = new FakeContact(account, "audrey at localhost", otherMetaContact);
++		other->setNickName("Audrey");
++		myselfMetaContact->setDisplayName("Bob");
++		myselfMetaContact->setDisplayNameSource(Kopete::MetaContact::SourceCustom);
++		otherMetaContact->setDisplayName("Audrey");
++		otherMetaContact->setDisplayNameSource(Kopete::MetaContact::SourceCustom);
++
++		Kopete::ContactPtrList contactList;
++		contactList.append(other);
++		// Create fakeChatSession
++		fakeChatSession = Kopete::ChatSessionManager::self()->create(myself, contactList, 0);
++		fakeChatSession->setDisplayName("Test Session");
++
++		// Create testStyle
++		testStyle = new ChatWindowStyle(QString(SRCDIR)+QString("/TestStyle"));
++	}
++	~Private()
++	{
++		delete myselfMetaContact;
++		delete otherMetaContact;
++		delete myself;
++		delete other;
++		delete fakeChatSession;
++	}
++	FakeProtocol *protocol;
++	FakeAccount *account;
++	Kopete::MetaContact *myselfMetaContact;
++	Kopete::MetaContact *otherMetaContact;
++	FakeContact *myself;
++	FakeContact *other;
++	Kopete::ChatSession *fakeChatSession;
++	ChatWindowStyle *testStyle;
++
++	QString resultHTML;
++};
++
++
++
++ChatWindowStyleRendering_Test::ChatWindowStyleRendering_Test()
++{
++	d = new Private;
++}
++
++ChatWindowStyleRendering_Test::~ChatWindowStyleRendering_Test()
++{
++	delete d;
++}
++
++void ChatWindowStyleRendering_Test::allTests()
++{
++	// change user data dir to avoid messing with user's .kde dir
++	setenv( "KDEHOME", QFile::encodeName( QDir::homeDirPath() + "/.kopete-unittest" ), true );
++
++	KApplication::disableAutoDcopRegistration();
++	//KCmdLineArgs::init(argc,argv,"testkopetemessage", 0, 0, 0, 0);
++	KApplication app;
++
++	chatPart = new ChatMessagePart(d->fakeChatSession, 0, 0);
++
++	testHeaderRendering();
++	testMessageRendering();
++	testStatusRendering();
++	//testFullRendering();
++}
++
++void ChatWindowStyleRendering_Test::testHeaderRendering()
++{
++	QString expectedHtml = QString(
++"<div>Test Session</div>\n"
++"<div>Bob</div>\n"
++"<div>Audrey</div>\n"
++"<div>Incoming/buddy_icon.png</div>\n"
++"<div>Outgoing/buddy_icon.png</div>\n"
++"<div>%1</div>\n"
++"<div>%2</div>"
++	).arg(KGlobal::locale()->formatDateTime( QDateTime::currentDateTime()))
++	.arg(QDateTime::currentDateTime().toString("hh:mm"));
++
++	QString headerHtml = d->testStyle->getHeaderHtml();
++	QString resultHtml;
++
++	resultHtml = chatPart->formatStyleKeywords(headerHtml);
++
++	kdDebug(14000) << "Result HTML: " << resultHtml << endl;
++
++	CHECK(resultHtml, expectedHtml);
++}
++
++void ChatWindowStyleRendering_Test::testMessageRendering()
++{
++	QString expectedIncomingHtml = QString(
++"Incoming:\n"
++"<div>Incoming/buddy_icon.png</div>\n"
++"<div>audrey at localhost</div>\n"
++"<div>Audrey</div>\n"
++"<div>Kopete</div>\n"
++"<div>Test</div>\n"
++"<div>%1</div>\n"
++"<div>%2</div>\n"
++"<div id=\"insert\">"
++	).arg(KGlobal::locale()->formatDateTime( QDateTime::currentDateTime()))
++	.arg(QDateTime::currentDateTime().toString("hh:mm"));
++
++	QString expectedOutgoingHtml = QString(
++"Outgoing:\n"
++"<div>Outgoing/buddy_icon.png</div>\n"
++"<div>bob at localhost</div>\n"
++"<div>Bob</div>\n"
++"<div>Kopete</div>\n"
++"<div>Hello there</div>\n"
++"<div>%1</div>\n"
++"<div>%2</div>\n"
++"<div id=\"insert\">"
++	).arg(KGlobal::locale()->formatDateTime( QDateTime::currentDateTime()))
++	.arg(QDateTime::currentDateTime().toString("hh:mm"));
++
++
++	QString tempHtml;
++	QString resultHtml;
++	
++	Kopete::Message msgIn(d->other, d->myself, QString::fromUtf8("Test"), Kopete::Message::Inbound );
++	Kopete::Message msgOut(d->myself, d->other, QString::fromUtf8("Hello there"), Kopete::Message::Outbound);
++
++	tempHtml = d->testStyle->getIncomingHtml();
++	resultHtml = chatPart->formatStyleKeywords(tempHtml, msgIn);
++
++	kdDebug(14000) << "Message incoming HTML: " << resultHtml << endl;
++
++	CHECK(resultHtml, expectedIncomingHtml);
++
++	tempHtml = d->testStyle->getOutgoingHtml();
++	resultHtml = chatPart->formatStyleKeywords(tempHtml, msgOut);
++
++	kdDebug(14000) << "Message outgoing HTML: " << resultHtml << endl;
++
++	CHECK(resultHtml, expectedOutgoingHtml);
++}
++
++void ChatWindowStyleRendering_Test::testStatusRendering()
++{
++	QString expectedStatusHtml = QString(
++"<div>A contact went offline.</div>\n"
++"<div>%1</div>\n"
++"<div>%2</div>"
++	).arg(KGlobal::locale()->formatDateTime( QDateTime::currentDateTime()))
++	.arg(QDateTime::currentDateTime().toString("hh:mm"));
++
++	QString statusHtml = d->testStyle->getStatusHtml();
++	QString resultHtml;
++	
++	Kopete::Message msgStatus(0,0, QString::fromUtf8("A contact went offline."), Kopete::Message::Internal);
++	resultHtml = chatPart->formatStyleKeywords(statusHtml, msgStatus);
++
++	CHECK(resultHtml, expectedStatusHtml);
++}
++
++void ChatWindowStyleRendering_Test::testFullRendering()
++{
++	QString expectedFullHtml;
++	QString resultHtml;
++
++	Kopete::Message msgIn1(d->myself, d->other, QString("Hello there !"), Kopete::Message::Inbound);
++	Kopete::Message msgIn2(d->myself, d->other, QString("How are you doing ?"), Kopete::Message::Inbound);
++	Kopete::Message msgOut1(d->other, d->myself, QString("Fine and you ?"), Kopete::Message::Outbound);
++	Kopete::Message msgStatus1(d->myself,d->other, QString("You are now marked as away."), Kopete::Message::Internal);
++	Kopete::Message msgStatus2(d->myself,d->other, QString("You are now marked as online."), Kopete::Message::Internal);
++	Kopete::Message msgIn3(d->myself, d->other, QString("Well, doing some tests."), Kopete::Message::Internal);
++	Kopete::Message msgOut2(d->other, d->myself, QString("All your bases are belong to us."), Kopete::Message::Outbound);
++	Kopete::Message msgOut3(d->other, d->myself, QString("You are on the way to destruction"), Kopete::Message::Outbound);
++
++	// Change style on the fly in ChatMessagePart so this test would run
++	chatPart->setStyle(d->testStyle);
++	
++	// Simulate a consersation
++	chatPart->appendMessage(msgIn1);
++	chatPart->appendMessage(msgIn2);
++	chatPart->appendMessage(msgOut1);
++	chatPart->appendMessage(msgStatus1);
++	chatPart->appendMessage(msgStatus2);
++	chatPart->appendMessage(msgIn3);
++	chatPart->appendMessage(msgOut2);
++	chatPart->appendMessage(msgOut3);
++
++	resultHtml = chatPart->htmlDocument().toHTML();
++
++	// Read the expected(sample) HTML from file.
++	QFile sampleHtml(QString(SRCDIR)+"sample.html");
++	if(sampleHtml.open(IO_ReadOnly))
++	{
++		QTextStream stream(&sampleHtml);
++		stream.setEncoding(QTextStream::UnicodeUTF8);
++		expectedFullHtml = stream.read();
++		sampleHtml.close();
++	}
++
++	CHECK(resultHtml, expectedFullHtml);
++}
+--- kopete/kopete/chatwindow/tests/chatwindowstyle_test.cpp	(revision 0)
++++ kopete/kopete/chatwindow/tests/chatwindowstyle_test.cpp	(revision 586398)
+@@ -0,0 +1,132 @@
++/*
++    ChatWindowStyle test suite
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at 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 <kunittest/module.h>
++#include "chatwindowstyle_test.h"
++
++#include <stdlib.h>
++
++#include <qdir.h>
++#include <qfile.h>
++
++#include <kopetechatwindowstyle.h>
++
++KUNITTEST_MODULE( kunittest_chatwindowstyle_test, "KopeteChatWindowTestSuite");
++KUNITTEST_MODULE_REGISTER_TESTER( ChatWindowStyle_Test );
++
++void ChatWindowStyle_Test::allTests()
++{
++	testStyle = new ChatWindowStyle(QString(SRCDIR)+QString("/TestStyle"));
++
++	// change user data dir to avoid messing with user's .kde dir
++	setenv( "KDEHOME", QFile::encodeName( QDir::homeDirPath() + "/.kopete-unittest" ), true );
++
++	testPaths();
++	testHtml();
++	testVariants();
++	testAction();
++}
++
++void ChatWindowStyle_Test::testPaths()
++{
++	QString expectedStylePath = SRCDIR + QString::fromUtf8("/TestStyle");
++	QString expectedBaseHref = expectedStylePath + QString::fromUtf8("/Contents/Resources/");
++
++	CHECK(testStyle->getStylePath(), expectedStylePath);
++	CHECK(testStyle->getStyleBaseHref(), expectedBaseHref);
++}
++
++void ChatWindowStyle_Test::testHtml()
++{
++	QString exceptedHeader = QString::fromUtf8(
++"<div>%chatName%</div>\n"
++"<div>%sourceName%</div>\n"
++"<div>%destinationName%</div>\n"
++"<div>%incomingIconPath%</div>\n"
++"<div>%outgoingIconPath%</div>\n"
++"<div>%timeOpened%</div>\n"
++"<div>%timeOpened{%H:%M}%</div>");
++	// Footer is empty on purpose, this is to test if the file doesn't exist.
++	QString exceptedFooter;
++	QString exceptedIncoming = QString::fromUtf8(
++"Incoming:\n"
++"<div>%userIconPath%</div>\n"
++"<div>%senderScreenName%</div>\n"
++"<div>%sender%</div>\n"
++"<div>%service%</div>\n"
++"<div>%message%</div>\n"
++"<div>%time%</div>\n"
++"<div>%time{%H:%M}%</div>\n"
++"<div id=\"insert\">");
++	QString exceptedNextIncoming = QString::fromUtf8(
++"Incoming:\n"
++"<div>%message%</div>\n"
++"<div id=\"insert\">"
++);
++	QString exceptedOutgoing = QString::fromUtf8(
++"Outgoing:\n"
++"<div>%userIconPath%</div>\n"
++"<div>%senderScreenName%</div>\n"
++"<div>%sender%</div>\n"
++"<div>%service%</div>\n"
++"<div>%message%</div>\n"
++"<div>%time%</div>\n"
++"<div>%time{%H:%M}%</div>\n"
++"<div id=\"insert\">");
++	QString exceptedNextOutgoing = QString::fromUtf8(
++"Outgoing:\n"
++"<div>%message%</div>\n"
++"<div id=\"insert\">"
++);
++	QString exceptedStatus = QString::fromUtf8(
++"<div>%message%</div>\n"
++"<div>%time%</div>\n"
++"<div>%time{%H:%M}%</div>");
++
++	CHECK(testStyle->getHeaderHtml(), exceptedHeader);
++	CHECK(testStyle->getFooterHtml(), exceptedFooter);
++	CHECK(testStyle->getIncomingHtml(), exceptedIncoming);
++	CHECK(testStyle->getNextIncomingHtml(), exceptedNextIncoming);
++	CHECK(testStyle->getOutgoingHtml(), exceptedOutgoing);
++	CHECK(testStyle->getNextOutgoingHtml(), exceptedNextOutgoing);
++	CHECK(testStyle->getStatusHtml(), exceptedStatus);
++}
++
++void ChatWindowStyle_Test::testAction()
++{
++	CHECK(testStyle->hasActionTemplate(), false);
++}
++
++void ChatWindowStyle_Test::testVariants()
++{
++	QString expectedNameResult("Variant1;Variant2");
++	QString expectedPathResult("Variants/Variant1.css;Variants/Variant2.css");
++	QStringList variantNameList;
++	QStringList variantPathList;
++	ChatWindowStyle::StyleVariants variantList;
++	ChatWindowStyle::StyleVariants::ConstIterator it;
++	variantList = testStyle->getVariants();
++
++	for(it = variantList.constBegin(); it != variantList.constEnd(); ++it)
++	{
++		variantNameList.append(it.key());
++		variantPathList.append(it.data());
++	}	
++	
++	CHECK(variantNameList.join(";"), expectedNameResult);
++	CHECK(variantPathList.join(";"), expectedPathResult);
++}
+--- kopete/kopete/chatwindow/tests/Makefile.am	(revision 0)
++++ kopete/kopete/chatwindow/tests/Makefile.am	(revision 586398)
+@@ -0,0 +1,23 @@
++AM_CPPFLAGS = -DKDE_NO_COMPAT -DQT_NO_ASCII_CAST -DQT_NO_COMPAT \
++	$(KOPETE_INCLUDES) -I$(top_srcdir)/kopete/kopete/chatwindow -I$(top_srcdir)/kopete/libkopete $(all_includes) -DSRCDIR=\"$(top_srcdir)/kopete/kopete/chatwindow/tests\"
++METASOURCES = AUTO
++check_PROGRAMS = kopetetabwidgettest
++check_LTLIBRARIES = kunittest_chatwindowstyle_test.la kunittest_chatwindowstylerendering_test.la
++
++kunittest_chatwindowstyle_test_la_SOURCES = chatwindowstyle_test.cpp
++kunittest_chatwindowstyle_test_la_LIBADD = -lkunittest ../libkopetechatwindow.la
++kunittest_chatwindowstyle_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
++
++kunittest_chatwindowstylerendering_test_la_SOURCES = chatwindowstylerendering_test.cpp
++kunittest_chatwindowstylerendering_test_la_LIBADD = -lkunittest $(top_srcdir)/kopete/libkopete/libkopete.la ../libkopetechatwindow.la
++kunittest_chatwindowstylerendering_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
++
++kopetetabwidgettest_SOURCES = kopetetabwidgettest.cpp
++kopetetabwidgettest_LDADD = ../libkopetechatwindow.la
++kopetetabwidgettest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
++
++
++check-local: 
++	kunittestmodrunner
++guicheck:
++	kunittestmod $(PWD) 
+--- kopete/kopete/chatwindow/tests/chatwindowstylerendering_test.h	(revision 0)
++++ kopete/kopete/chatwindow/tests/chatwindowstylerendering_test.h	(revision 586398)
+@@ -0,0 +1,45 @@
++/*
++    Adium(and Kopete) ChatWindowStyle format rendering test suite
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at 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 CHATWINDOWSTYLERENDERING_TEST_H
++#define CHATWINDOWSTYLERENDERING_TEST_H
++
++#include <kunittest/tester.h>
++
++// HACK: Needed to access private methods of ChatMessagePart.
++#define private public
++#include <chatmessagepart.h>
++#undef private
++
++class ChatWindowStyleRendering_Test : public KUnitTest::Tester
++{
++public:
++	ChatWindowStyleRendering_Test();
++	~ChatWindowStyleRendering_Test();
++
++	void allTests();
++public slots:
++	void testHeaderRendering();
++	void testMessageRendering();
++	void testStatusRendering();
++	void testFullRendering();
++private:
++	class Private;
++	Private *d;
++
++	ChatMessagePart *chatPart;
++};
++#endif
+--- kopete/kopete/chatwindow/tests/chatwindowstyle_test.h	(revision 0)
++++ kopete/kopete/chatwindow/tests/chatwindowstyle_test.h	(revision 586398)
+@@ -0,0 +1,39 @@
++/*
++    ChatWindowStyle test suite
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at 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 CHATWINDOWSTYLE_TEST_H
++#define CHATWINDOWSTYLE_TEST_H
++
++#include <kunittest/tester.h>
++
++class ChatWindowStyle;
++
++class ChatWindowStyle_Test : public KUnitTest::Tester
++{
++public:
++	void allTests();
++
++public slots:
++	void testPaths();
++	void testHtml();
++	void testVariants();
++	void testAction();
++	
++private:
++	ChatWindowStyle *testStyle;
++};
++
++#endif
+--- kopete/kopete/chatwindow/kopetechatwindow.h	(revision 568672)
++++ kopete/kopete/chatwindow/kopetechatwindow.h	(revision 586398)
+@@ -94,8 +94,8 @@
+ 	void updateMembersActions();
+ 	void setStatus( const QString & );
+ 
+-	/** 
+-	 * Reimplemented from KMainWindow - asks each ChatView in the window if it is ok to close the window 
++	/**
++	 * Reimplemented from KMainWindow - asks each ChatView in the window if it is ok to close the window
+ 	 * @return true if no ChatView objects to closing.
+ 	 */
+ 	virtual bool queryClose();
+@@ -105,7 +105,7 @@
+ 	QPtrList<ChatView> chatViewList;
+ 
+ private:
+-	// All KopeteChatWindows are created by the findWindow function
++	// All KopeteChatWindows are created by the window function
+ 	KopeteChatWindow( QWidget *parent = 0, const char* name = "KopeteChatWindow" );
+ 
+ 	/**
+@@ -211,6 +211,7 @@
+ 
+ 	void toggleAutoSpellChecking();
+ 	void slotRTFEnabled( ChatView*, bool );
++	void slotAutoSpellCheckEnabled( ChatView*, bool );
+ 
+ 	void slotSetCaption( bool );
+ 	void slotUpdateCaptionIcons( ChatView * );
+--- kopete/kopete/chatwindow/Makefile.am	(revision 568672)
++++ kopete/kopete/chatwindow/Makefile.am	(revision 586398)
+@@ -1,22 +1,27 @@
+ kde_module_LTLIBRARIES = libkrichtexteditpart.la kopete_chatwindow.la kopete_emailwindow.la
++noinst_LTLIBRARIES = libkopetechatwindow.la
+ METASOURCES = AUTO
+ 
+ AM_CPPFLAGS = $(KOPETE_INCLUDES) $(KOPETE_COMPAT_INCLUDES) -I$(top_srcdir)/kopete/libkopete/private    -I$(top_srcdir)/kopete/kopete $(all_includes)
+ 
+-kopete_chatwindow_la_SOURCES = chatmessagepart.cpp emoticonselector.cpp kopeteemoticonaction.cpp \
+-	chattexteditpart.cpp krichtexteditpart.cpp chatview.cpp kopetechatwindow.cpp chatmemberslistwidget.cpp
++kopete_chatwindow_la_SOURCES = chatview.cpp kopetechatwindow.cpp chatmemberslistwidget.cpp
+ kopete_chatwindow_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries)
+-kopete_chatwindow_la_LIBADD = ../../libkopete/libkopete.la $(LIB_KOPETECOMPAT) $(LIB_KDEUI)
++kopete_chatwindow_la_LIBADD = ../../libkopete/libkopete.la ./libkopetechatwindow.la $(LIB_KOPETECOMPAT) $(LIB_KDEUI)
+ 
+-kopete_emailwindow_la_SOURCES = chatmessagepart.cpp emoticonselector.cpp kopeteemoticonaction.cpp \
+-	chattexteditpart.cpp krichtexteditpart.cpp kopeteemailwindow.cpp
++kopete_emailwindow_la_SOURCES = kopeteemailwindow.cpp
+ kopete_emailwindow_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries)
+-kopete_emailwindow_la_LIBADD = ../../libkopete/libkopete.la $(LIB_KOPETECOMPAT) $(LIB_KDEUI)
++kopete_emailwindow_la_LIBADD = ../../libkopete/libkopete.la ./libkopetechatwindow.la $(LIB_KOPETECOMPAT) $(LIB_KDEUI)
+ 
+ libkrichtexteditpart_la_SOURCES = krichtexteditpart.cpp
+ libkrichtexteditpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(KDE_RPATH)
+ libkrichtexteditpart_la_LIBADD = ../../libkopete/libkopete.la $(LIB_KPARTS) $(LIB_KSPELL) $(LIB_KDEPRINT)
+ 
++libkopetechatwindow_la_SOURCES = chatmessagepart.cpp emoticonselector.cpp kopeteemoticonaction.cpp \
++	chattexteditpart.cpp krichtexteditpart.cpp kopetechatwindowstylemanager.cpp \
++	kopetechatwindowstyle.cpp 
++libkopetechatwindow_la_LDFLAGS = $(all_libraries) -no-undefined
++libkopetechatwindow_la_LIBADD = ../../libkopete/libkopete.la $(LIB_KOPETECOMPAT) $(LIB_KDEUI)
++
+ partdir = $(kde_datadir)/kopeterichtexteditpart
+ part_DATA = kopeterichtexteditpartfull.rc
+ 
+--- kopete/kopete/chatwindow/chatmemberslistwidget.cpp	(revision 568672)
++++ kopete/kopete/chatwindow/chatmemberslistwidget.cpp	(revision 586398)
+@@ -169,7 +169,6 @@
+ 
+ ChatMembersListWidget::~ChatMembersListWidget()
+ {
+-	delete m_toolTip;
+ }
+ 
+ void ChatMembersListWidget::slotContextMenu( KListView*, QListViewItem *item, const QPoint &point )
+--- kopete/kopete/chatwindow/kopetechatwindowstylemanager.cpp	(revision 0)
++++ kopete/kopete/chatwindow/kopetechatwindowstylemanager.cpp	(revision 586398)
+@@ -0,0 +1,384 @@
++ /*
++    kopetechatwindowstylemanager.cpp - Manager all chat window styles
++
++    Copyright (c) 2005      by Michaël Larouche     <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers <kopete-devel at 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 "kopetechatwindowstylemanager.h"
++
++// Qt includes
++#include <qvaluestack.h>
++
++// KDE includes
++#include <kstandarddirs.h>
++#include <kdirlister.h>
++#include <kdebug.h>
++#include <kurl.h>
++#include <kglobal.h>
++#include <karchive.h>
++#include <kzip.h>
++#include <ktar.h>
++#include <kmimetype.h>
++#include <kio/netaccess.h>
++#include <kstaticdeleter.h>
++#include <kconfig.h>
++#include <kglobal.h>
++
++#include "kopetechatwindowstyle.h"
++
++class ChatWindowStyleManager::Private
++{
++public:
++	Private()
++	 : styleDirLister(0)
++	{}
++
++	~Private()
++	{
++		if(styleDirLister)
++		{
++			styleDirLister->deleteLater();
++		}
++
++		QMap<QString, ChatWindowStyle*>::Iterator styleIt, styleItEnd = stylePool.end();
++		for(styleIt = stylePool.begin(); styleIt != styleItEnd; ++styleIt)
++		{
++			delete styleIt.data();
++		}
++	}
++
++	KDirLister *styleDirLister;
++	StyleList availableStyles;
++	
++	// key = style path, value = ChatWindowStyle instance
++	QMap<QString, ChatWindowStyle*> stylePool;
++
++	QValueStack<KURL> styleDirs;
++};
++
++static KStaticDeleter<ChatWindowStyleManager> ChatWindowStyleManagerstaticDeleter;
++
++ChatWindowStyleManager *ChatWindowStyleManager::s_self = 0;
++
++ChatWindowStyleManager *ChatWindowStyleManager::self()
++{
++	if( !s_self )
++	{
++		ChatWindowStyleManagerstaticDeleter.setObject( s_self, new ChatWindowStyleManager() );
++	}
++	
++	return s_self;
++}
++
++ChatWindowStyleManager::ChatWindowStyleManager(QObject *parent, const char *name)
++	: QObject(parent, name), d(new Private())
++{
++	kdDebug(14000) << k_funcinfo << endl;
++	loadStyles();
++}
++
++ChatWindowStyleManager::~ChatWindowStyleManager()
++{	
++	kdDebug(14000) << k_funcinfo << endl;
++	delete d;
++}
++
++void ChatWindowStyleManager::loadStyles()
++{
++	QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QString::fromUtf8( "styles" ) );
++	QStringList::const_iterator it;
++	for(it = chatStyles.constBegin(); it != chatStyles.constEnd(); ++it)
++	{
++		kdDebug(14000) << k_funcinfo << *it << endl;
++		d->styleDirs.push( KURL(*it) );
++	}
++	
++	d->styleDirLister = new KDirLister(this);
++	d->styleDirLister->setDirOnlyMode(true);
++
++	connect(d->styleDirLister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(slotNewStyles(const KFileItemList &)));
++	connect(d->styleDirLister, SIGNAL(completed()), this, SLOT(slotDirectoryFinished()));
++
++	if( !d->styleDirs.isEmpty() )
++		d->styleDirLister->openURL(d->styleDirs.pop(), true);
++}
++
++ChatWindowStyleManager::StyleList ChatWindowStyleManager::getAvailableStyles()
++{
++	return d->availableStyles;
++}
++
++int ChatWindowStyleManager::installStyle(const QString &styleBundlePath)
++{
++	QString localStyleDir( locateLocal( "appdata", QString::fromUtf8("styles/") ) );
++	
++	KArchiveEntry *currentEntry = 0L;
++	KArchiveDirectory* currentDir = 0L;
++	KArchive *archive = 0L;
++
++	if( localStyleDir.isEmpty() )
++	{
++		return StyleNoDirectoryValid;
++	}
++
++	// Find mimetype for current bundle. ZIP and KTar need separate constructor
++	QString currentBundleMimeType = KMimeType::findByPath(styleBundlePath, 0, false)->name();
++	if(currentBundleMimeType == "application/x-zip")
++	{
++		archive = new KZip(styleBundlePath);
++	}
++	else if( currentBundleMimeType == "application/x-tgz" || currentBundleMimeType == "application/x-tbz" || currentBundleMimeType == "application/x-gzip" || currentBundleMimeType == "application/x-bzip2" )
++	{
++		archive = new KTar(styleBundlePath);
++	}
++	else
++	{
++		return StyleCannotOpen;
++	}
++
++	if ( !archive->open(IO_ReadOnly) )
++	{
++		delete archive;
++
++		return StyleCannotOpen;
++	}
++
++	const KArchiveDirectory* rootDir = archive->directory();
++
++	// Ok where we go to check if the archive is valid.
++	// Each time we found a correspondance to a theme bundle, we add a point to validResult.
++	// A valid style bundle must have:
++	// -a Contents, Contents/Resources, Co/Res/Incoming, Co/Res/Outgoing dirs
++	// main.css, Footer.html, Header.html, Status.html files in Contents/Ressources.
++	// So for a style bundle to be valid, it must have a result greather than 8, because we test for 8 required entry.
++	int validResult = 0;
++	QStringList entries = rootDir->entries();
++	// Will be reused later.
++	QStringList::Iterator entriesIt, entriesItEnd = entries.end();
++	for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
++	{
++		currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
++// 		kdDebug() << k_funcinfo << "Current entry name: " << currentEntry->name() << endl;
++		if (currentEntry->isDirectory())
++		{
++			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
++			if (currentDir)
++			{
++				if( currentDir->entry(QString::fromUtf8("Contents")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Incoming found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Outgoing found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/main.css")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/main.css found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Footer.html")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Footer.html found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Status.html")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Status.html found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Header.html")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Header.html found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming/Content.html")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Incoming/Content.html found" << endl;
++					validResult += 1;
++				}
++				if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing/Content.html")) )
++				{
++// 					kdDebug() << k_funcinfo << "Contents/Resources/Outgoing/Content.html found" << endl;
++					validResult += 1;
++				}
++			}
++		}
++	}
++// 	kdDebug() << k_funcinfo << "Valid result: " << QString::number(validResult) << endl;
++	// The archive is a valid style bundle.
++	if(validResult >= 8)
++	{
++		bool installOk = false;
++		for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
++		{
++			currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
++			if(currentEntry && currentEntry->isDirectory())
++			{
++				// Ignore this MacOS X "garbage" directory in zip.
++				if(currentEntry->name() == QString::fromUtf8("__MACOSX"))
++				{
++					continue;
++				}
++				else
++				{
++					currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
++					if(currentDir)
++					{
++						currentDir->copyTo(localStyleDir + currentDir->name());
++						installOk = true;
++					}
++				}
++			}
++		}
++
++		archive->close();
++		delete archive;
++
++		if(installOk)
++			return StyleInstallOk;
++		else
++			return StyleUnknow;
++	}
++	else
++	{
++		archive->close();
++		delete archive;
++
++		return StyleNotValid;
++	}
++
++	if(archive)
++	{
++		archive->close();
++		delete archive;
++	}
++
++	return StyleUnknow;
++}
++
++bool ChatWindowStyleManager::removeStyle(const QString &stylePath)
++{
++	// Find for the current style in avaiableStyles map.
++	StyleList::Iterator foundStyle = d->availableStyles.find(stylePath);
++	// QMap iterator return end() if it found no item.
++	if(foundStyle != d->availableStyles.end())
++	{
++		d->availableStyles.remove(foundStyle);
++		
++		// Remove and delete style from pool if needed.
++		if( d->stylePool.contains(stylePath) )
++		{
++			ChatWindowStyle *deletedStyle = d->stylePool[stylePath];
++			d->stylePool.remove(stylePath);
++			delete deletedStyle;
++		}
++	
++		// Do the actual deletion of the directory style.
++		return KIO::NetAccess::del( KURL(stylePath), 0 );
++	}
++	else
++	{
++		return false;
++	}
++}
++
++ChatWindowStyle *ChatWindowStyleManager::getStyleFromPool(const QString &stylePath)
++{
++	if( d->stylePool.contains(stylePath) )
++	{
++		// NOTE: This is a hidden config switch for style developers
++		// Check in the config if the cache is disabled.
++		// if the cache is disabled, reload the style everytime it's getted.
++		KConfig *config = KGlobal::config();
++		config->setGroup("KopeteStyleDebug");
++		bool disableCache = config->readBoolEntry("disableStyleCache", false);
++		if(disableCache)
++		{
++			d->stylePool[stylePath]->reload();
++		}
++
++		return d->stylePool[stylePath];
++	}
++	else
++	{
++		// Build a chat window style and list its variants, then add it to the pool.
++		ChatWindowStyle *style = new ChatWindowStyle(stylePath, ChatWindowStyle::StyleBuildNormal);
++		d->stylePool.insert(stylePath, style);
++
++		return style;
++	}
++	
++	return 0;
++}
++
++void ChatWindowStyleManager::slotNewStyles(const KFileItemList &dirList)
++{
++	KFileItem *item;
++	QPtrListIterator<KFileItem> it( dirList );
++	while( (item = it.current()) != 0 ) 
++	{
++		// Ignore data dir(from deprecated XSLT themes)
++		if( !item->url().fileName().contains(QString::fromUtf8("data")) )
++		{
++			kdDebug(14000) << k_funcinfo << "Listing: " << item->url().fileName() << endl;
++			// If the style path is already in the pool, that's mean the style was updated on disk
++			// Reload the style
++			if( d->stylePool.contains(item->url().path()) )
++			{
++				kdDebug(14000) << k_funcinfo << "Updating style: " << item->url().path() << endl;
++
++				d->stylePool[item->url().path()]->reload();
++
++				// Add to avaialble if required.
++				if( !d->availableStyles.contains(item->url().fileName()) )
++					d->availableStyles.insert(item->url().fileName(), item->url().path());
++			}
++			else
++			{
++				// TODO: Use name from Info.plist
++				d->availableStyles.insert(item->url().fileName(), item->url().path());
++			}
++		}
++		++it;
++	}
++}
++
++void ChatWindowStyleManager::slotDirectoryFinished()
++{
++	// Start another scanning if the directories stack is not empty
++	if( !d->styleDirs.isEmpty() )
++	{
++		kdDebug(14000) << k_funcinfo << "Starting another directory." << endl;
++		d->styleDirLister->openURL(d->styleDirs.pop(), true);
++	}
++	else
++	{
++		emit loadStylesFinished();
++	}
++}
++
++#include "kopetechatwindowstylemanager.moc"
+--- kopete/kopete/Makefile.am	(revision 568672)
++++ kopete/kopete/Makefile.am	(revision 586398)
+@@ -22,12 +22,13 @@
+ KDE_ICON = AUTO
+ METASOURCES = AUTO
+ 
+-SUBDIRS = addaccountwizard addcontactwizard contactlist config . chatwindow kconf_update
++SUBDIRS = addaccountwizard addcontactwizard contactlist chatwindow config . kconf_update
+ 
+ bin_PROGRAMS = kopete
+ kopete_SOURCES = main.cpp 	kopeteapplication.cpp kopeteiface.cpp \
+-	kopeteiface.skel 	systemtray.cpp 	kopeteballoon.cpp kopetewindow.cpp \
+-		kopeteaccountstatusbaricon.cpp 	kimifaceimpl.cpp kimiface.skel kopeteeditglobalidentitywidget.cpp
++		kopeteiface.skel 	systemtray.cpp 	kopeteballoon.cpp kopetewindow.cpp \
++			kopeteaccountstatusbaricon.cpp 	kimifaceimpl.cpp kimiface.skel kopeteeditglobalidentitywidget.cpp \
++	groupkabcselectorwidget.ui
+ 
+ kimiface_DIR = $(kde_includes)
+ 
+--- kopete/kopete/systemtray.h	(revision 568672)
++++ kopete/kopete/systemtray.h	(revision 586398)
+@@ -5,7 +5,7 @@
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+     Copyright (c) 2003      by Olivier Goffart        <ogoffart @ kde.org>
+ 
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+     *************************************************************************
+     *                                                                       *
+@@ -75,11 +75,13 @@
+ 	void slotEventDone(Kopete::MessageEvent *);
+ 	void slotConfigChanged();
+ 	void slotReevaluateAccountStates();
++	void slotRemoveBalloon();
+ 	void addBalloon();
+ 
+ private:
+ 	KopeteSystemTray( QWidget* parent, const char* name );
+ 	QString squashMessage( const Kopete::Message& msgText );
++	void removeBalloonEvent(Kopete::MessageEvent *);
+ 
+ 	QTimer *mBlinkTimer;
+ 	QPixmap mKopeteIcon;
+@@ -92,6 +94,7 @@
+ 	static KopeteSystemTray* s_systemTray;
+ 
+ 	QPtrList<Kopete::MessageEvent> mEventList;
++	QPtrList<Kopete::MessageEvent> mBalloonEventList;
+ 	KopeteBalloon *m_balloon;
+ };
+ 
+--- kopete/kopete/kopeteeditglobalidentitywidget.cpp	(revision 568672)
++++ kopete/kopete/kopeteeditglobalidentitywidget.cpp	(revision 586398)
+@@ -176,17 +176,39 @@
+ 
+ 	QString saveLocation(locateLocal("appdata", "global-photo.png"));
+ 	QImage photo(photoURL.path());
+-	photo = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap(photo), 100, 140, this );
++	photo = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap(photo), 96, 96, this );
+ 
+ 	if(!photo.isNull())
+ 	{
+-		if(photo.width() != 100 || photo.height() != 140)
++		if(photo.width() > 96 || photo.height() > 96)
+ 		{
+-			 if (photo.height() > photo.width())
+-				photo = photo.scaleHeight(140);
+-			else
+-				photo = photo.scaleWidth(100);
++			// Scale and crop the picture.
++			photo = photo.smoothScale( 96, 96, QImage::ScaleMin );
++			// crop image if not square
++			if(photo.width() < photo.height()) 
++				photo = photo.copy((photo.width()-photo.height())/2, 0, 96, 96);
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, 96, 96);
++
+ 		}
++		else if (photo.width() < 32 || photo.height() < 32)
++		{
++			// Scale and crop the picture.
++			photo = photo.smoothScale( 32, 32, QImage::ScaleMin );
++			// crop image if not square
++			if(photo.width() < photo.height())
++				photo = photo.copy((photo.width()-photo.height())/2, 0, 32, 32);
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, 32, 32);
++	
++		}
++		else if (photo.width() != photo.height())
++		{
++			if(photo.width() < photo.height())
++				photo = photo.copy((photo.width()-photo.height())/2, 0, photo.height(), photo.height());
++			else if (photo.width() > photo.height())
++				photo = photo.copy(0, (photo.height()-photo.width())/2, photo.height(), photo.height());
++		}
+ 
+ 		if(!photo.save(saveLocation, "PNG"))
+ 		{
+--- kopete/configure.in.in	(revision 568672)
++++ kopete/configure.in.in	(revision 586398)
+@@ -16,6 +16,35 @@
+ 
+ KOPETE_INCLUDES='-I$(top_srcdir)/kopete/libkopete -I$(top_builddir)/kopete/libkopete -I$(top_srcdir)/kopete/libkopete/avdevice -I$(top_srcdir)/kopete/libkopete/ui -I$(top_builddir)/kopete/libkopete/ui'
+ 
++AC_MSG_CHECKING([for kdelibs newer than 3.3.x])
++AC_LANG_SAVE
++AC_LANG_CPLUSPLUS
++kcompat_save_CXXFLAGS="$CXXFLAGS"
++kcompat_safe_LIBS="$LIBS"
++LIBS="$LIBS $X_EXTRA_LIBS"
++CXXFLAGS="$CXXFLAGS $all_includes"
++
++AC_TRY_COMPILE([
++#include <kdeversion.h>
++#if !( KDE_IS_VERSION( 3, 3, 90 ) )
++#error Kopete compatibility with KDE 3.3 needs to be enabled
++#endif
++],
++[
++],
++	AC_MSG_RESULT(yes)
++,
++	KOPETE_COMPAT_INCLUDES='-I$(top_srcdir)/kopete/libkopete/compat'
++	KOPETE_INCLUDES=$KOPETE_INCLUDES' $(KOPETE_COMPAT_INCLUDES)'
++	LIB_KOPETECOMPAT='$(top_builddir)/kopete/libkopete/libkopete.la'
++	AC_MSG_RESULT(no)
++)
++CXXFLAGS="$kcompat_save_CXXFLAGS"
++LIBS="$kcompat_safe_LIBS"
++AC_LANG_RESTORE
++AM_CONDITIONAL(compile_LIBKOPETE_COMPAT, test -n "$LIB_KOPETECOMPAT")
++
++
+ AC_ARG_ENABLE(smpppd,
+ [AC_HELP_STRING([--enable-smpppd], [enable support for the SuSE Meta PPP Daemon (smpppd) (default is NO)])],
+ [
+--- kopete/README	(revision 568672)
++++ kopete/README	(revision 586398)
+@@ -5,7 +5,7 @@
+ 
+ Kopete is an Instant Messaging client designed to be modular and plugin based.
+ 
+-It requires the KDE Desktop, version 3.2 or higher.
++It requires the KDE Desktop, version 3.3 or higher.
+ 
+ Kopete ships with a lot of protocol plugins, supporting nine different messaging
+ systems.  All plugins have seen numerous enhancements and bugfixes since the
+--- kopete/kopete.kdevelop	(revision 568672)
++++ kopete/kopete.kdevelop	(revision 586398)
+@@ -19,7 +19,7 @@
+       <part>kdevsnippet</part>
+       <part>kdevdebugger</part>
+       <part>kdevdistpart</part>
+-      <part>kdevvalgrind</part>
++      <part>kdevquickopen</part>
+     </ignoreparts>
+     <secondaryLanguages/>
+     <versioncontrol>kdevsubversion</versioncontrol>
+@@ -125,14 +125,14 @@
+         <envvar value="1" name="WANT_AUTOMAKE_1_6" />
+       </envvars>
+       <abortonerror>true</abortonerror>
+-      <numberofjobs>2</numberofjobs>
++      <numberofjobs>1</numberofjobs>
+       <dontact>false</dontact>
+-      <makebin>unsermake --compile-jobs=30</makebin>
++      <makebin>make</makebin>
+       <prio>0</prio>
+     </make>
+     <general>
+       <useconfiguration>default</useconfiguration>
+-      <activetarget>protocols/groupwise/kopete_groupwise.la</activetarget>
++      <activetarget>libkopete/avdevice/libkopete_videodevice.la</activetarget>
+     </general>
+     <run>
+       <mainprogram>kopete/kopete</mainprogram>
+@@ -145,9 +145,9 @@
+     </run>
+     <configurations>
+       <default>
+-        <configargs>--enable-debug=full --enable-libsuffix=64</configargs>
+-        <builddir>/space/kde/builds/opt_3_5/kdenetwork/kopete</builddir>
+-        <topsourcedir>/space/kde/sources/3_5/kdenetwork/kopete</topsourcedir>
++        <configargs>--enable-debug=full</configargs>
++        <builddir/>
++        <topsourcedir/>
+         <cppflags/>
+         <ldflags/>
+         <ccompiler>kdevgccoptions</ccompiler>
+@@ -215,11 +215,12 @@
+       <inlineGet>true</inlineGet>
+       <inlineSet>true</inlineSet>
+     </creategettersetter>
+-    <qt>
+-      <used>false</used>
+-      <version>3</version>
+-      <root>/home/qt/3.3</root>
+-    </qt>
++    <designerintegration>
++      <qtdesigner>
++        <implementation class="dlgChatJoin" path="protocols/jabber/ui/dlgchatjoin.ui" implementationpath="protocols/jabber/ui/dlgchatjoin.h" />
++        <implementation class="dlgChatRoomsList" path="protocols/jabber/ui/dlgchatroomslist.ui" implementationpath="protocols/jabber/ui/dlgchatroomslist.h" />
++      </qtdesigner>
++    </designerintegration>
+   </kdevcppsupport>
+   <kdevcvsservice>
+     <recursivewhenupdate>true</recursivewhenupdate>
+--- kopete/icons/Makefile.am	(revision 568672)
++++ kopete/icons/Makefile.am	(revision 586398)
+@@ -1,2 +1 @@
+-kopeteicondir = $(kde_datadir)/kopete/icons
+-kopeteicon_ICON = AUTO
++KDE_ICON=AUTO
+--- kopete/libkopete/kopetexsl.cpp	(revision 568672)
++++ kopete/libkopete/kopetexsl.cpp	(revision 586398)
+@@ -1,442 +0,0 @@
+-/*
+-    kopetexsl.cpp - Kopete XSL Routines
+-
+-    Copyright (c) 2003      by Jason Keirstead       <jason at keirstead.org>
+-    Copyright (c) 2003      by Martijn Klingens      <klingens at kde.org>
+-
+-    Kopete    (c) 2002-2003 by the Kopete developers <kopete-devel at kde.org>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#include "kopetexsl.h"
+-
+-#include <libxml/globals.h>
+-#include <libxml/parser.h>
+-
+-// Don't try to sort the libxslt includes alphabetically!
+-// transform.h _HAS_ to be after xsltInternals.h and xsltconfig.h _HAS_ to be
+-// the first libxslt include or it will break the compilation on some
+-// libxslt versions
+-#include <libxslt/xsltconfig.h>
+-#include <libxslt/xsltInternals.h>
+-#include <libxslt/transform.h>
+-
+-// stdlib.h is required to build on Solaris
+-#include <stdlib.h>
+-
+-#include <qregexp.h>
+-#include <qsignal.h>
+-#include <qstylesheet.h>
+-#include <qthread.h>
+-#include <qevent.h>
+-#include <qmutex.h>
+-
+-#include <kapplication.h>
+-#include <kdebug.h>
+-#include <klocale.h>
+-#include <kstandarddirs.h>
+-
+-#include "kopeteprefs.h" //to get style path 
+-
+-
+-/**
+- * @author Jason Keirstead <jason at keirstead.org>
+- *
+- * The thread class that actually performs the XSL processing.
+- * Using a thread allows async operation.
+- */
+-class KopeteXSLThread : public QObject, public QThread
+-{
+-public:
+-	/**
+-	 * Thread constructor
+-	 *
+-	 * @param xmlString The XML to be transformed
+-	 * @param xslString The XSL stylesheet we will use to transform
+-	 * @param target Target object to connect to for async operation
+-	 * @param slotCompleted Slot to fire on completion in asnc operation
+-	 */
+-	KopeteXSLThread( const QString &xmlString, xsltStylesheetPtr xslDoc, QObject *target = 0L, const char *slotCompleted = 0L );
+-
+-	/**
+-	 * Reimplemented from QThread. Does the processing.
+-	 */
+-	virtual void run();
+-
+-	/**
+-	 * A user event is used to get back to the UI thread to emit the completed signal
+-	 */
+-	bool event( QEvent *event );
+-
+-	static QString xsltTransform( const QString &xmlString, xsltStylesheetPtr xslDoc );
+-
+-	/**
+-	 * Returns the result string
+-	 */
+-	const QString &result()
+-	{ return m_resultString; };
+-
+-private:
+-	QString m_xml;
+-	xsltStylesheetPtr m_xsl;
+-	QString m_resultString;
+-	QObject *m_target;
+-	const char *m_slotCompleted;
+-	QMutex dataMutex;
+-};
+-
+-KopeteXSLThread::KopeteXSLThread( const QString &xmlString, xsltStylesheetPtr xslDoc, QObject *target, const char *slotCompleted )
+-{
+-	m_xml = xmlString;
+-	m_xsl = xslDoc;
+-
+-	m_target = target;
+-	m_slotCompleted = slotCompleted;
+-}
+-
+-void KopeteXSLThread::run()
+-{
+-	dataMutex.lock();
+-	m_resultString = xsltTransform( m_xml, m_xsl );
+-	dataMutex.unlock();
+-	// get back to the main thread
+-	qApp->postEvent( this, new QEvent( QEvent::User ) );
+-}
+-
+-bool KopeteXSLThread::event( QEvent *event )
+-{
+-	if ( event->type() == QEvent::User )
+-	{
+-		dataMutex.lock();
+-		if( m_target && m_slotCompleted )
+-		{
+-			QSignal completeSignal( m_target );
+-			completeSignal.connect( m_target, m_slotCompleted );
+-			completeSignal.setValue( m_resultString );
+-			completeSignal.activate();
+-		}
+-		dataMutex.unlock();
+-		delete this;
+-		return true;
+-	}
+-	return QObject::event( event );
+-}
+-
+-QString KopeteXSLThread::xsltTransform( const QString &xmlString, xsltStylesheetPtr styleSheet )
+-{
+-	// Convert QString into a C string
+-	QCString xmlCString = xmlString.utf8();
+-
+-	QString resultString;
+-	QString errorMsg;
+-
+-	xmlDocPtr xmlDoc = xmlParseMemory( xmlCString, xmlCString.length() );
+-	if ( xmlDoc )
+-	{
+-		if ( styleSheet )
+-		{
+-			KopetePrefs *p = KopetePrefs::prefs();
+-
+-			static QCString appPath( QString::fromLatin1("\"%1\"").arg(p->styleDataPath()).utf8() );
+-
+-			static const char* params[3] = {
+-				"appdata",
+-				appPath,
+-				NULL
+-			};
+-
+-			xmlDocPtr resultDoc = xsltApplyStylesheet( styleSheet, xmlDoc, params );
+-			if ( resultDoc )
+-			{
+-				// Save the result into the QString
+-				xmlChar *mem;
+-				int size;
+-				xmlDocDumpMemory( resultDoc, &mem, &size );
+-				resultString = QString::fromUtf8( QCString( ( char * )( mem ), size + 1 ) );
+-				xmlFree( mem );
+-				xmlFreeDoc( resultDoc );
+-			}
+-			else
+-			{
+-				errorMsg = i18n( "Message is null." );
+-			}
+-		}
+-		else
+-		{
+-			errorMsg = i18n( "The selected chat style is invalid." );
+-		}
+-
+-		xmlFreeDoc( xmlDoc );
+-	}
+-	else
+-	{
+-		errorMsg = i18n( "Message could not be parsed. This is likely due to an encoding problem. Please ensure you have selected the correct encoding for this contact." );
+-	}
+-
+-	if ( resultString.isEmpty() )
+-	{
+-		resultString = i18n( "<div><b>Kopete encountered the following error while parsing a message:</b><br />%1</div>" ).arg( errorMsg );
+-	}
+-
+-	#ifdef RAWXSL
+-		kdDebug(14000) << k_funcinfo << resultString << endl;
+-	#endif
+-	return resultString;
+-}
+-
+-class KopeteXSLTPrivate
+-{
+-public:
+-	xmlDocPtr xslDoc;
+-	xsltStylesheetPtr styleSheet;
+-	unsigned int flags;
+-};
+-
+-Kopete::XSLT::XSLT( const QString &document, QObject *parent )
+-: QObject( parent )
+-{
+-	d = new KopeteXSLTPrivate;
+-	d->flags = 0;
+-	d->xslDoc = 0;
+-	d->styleSheet = 0;
+-
+-	// Init Stuff
+-	xmlLoadExtDtdDefaultValue = 0;
+-	xmlSubstituteEntitiesDefault( 1 );
+-
+-	setXSLT( document );
+-}
+-
+-Kopete::XSLT::~XSLT()
+-{
+-	xsltFreeStylesheet( d->styleSheet );
+-
+-	delete d;
+-}
+-
+-void Kopete::XSLT::setXSLT( const QString &_document )
+-{
+-	// Search for '<kopete-i18n>' elements and feed them through i18n().
+-	// After that replace the %VAR% variables with their proper XSLT counterpart.
+-	//
+-	// FIXME: Preprocessing the document using the QString API is fast and simple,
+-	//        but also error-sensitive.
+-	//        In fact, there are a couple of known issues with this algorithm that
+-	//        depend on the strings in the current styles. If these strings change
+-	//        they may break the parsing here.
+-	//
+-	//        The reason I'm doing it like this is because of issues with QDOM and
+-	//        namespaces in earlier Qt versions. When we drop Qt 3.1.x support we
+-	//        should probably convert this to more accurate DOM code. - Martijn
+-	//
+-	//	Actually, since we need to parse into a libxml2 document anyway, this whole
+-	//	nonsense could be replaced with some simple XPath expressions - JK
+-	//
+-	QRegExp elementMatch( QString::fromLatin1( "<kopete-i18n>(.*)</kopete-i18n>" ) );
+-	elementMatch.setMinimal( true );
+-	QString document = _document;
+-	int pos;
+-	while ( ( pos = elementMatch.search( document ) ) != -1 )
+-	{
+-		QString orig = elementMatch.cap( 1 );
+-		//kdDebug( 14010 ) << k_funcinfo << "Original text: " << orig << endl;
+-
+-		// Split on % and go over all parts
+-		// WARNING: If you change the translator comment, also change it in the
+-		//          styles/extracti18n Perl script, because the strings have to be
+-		//          identical!
+-		QStringList parts = QStringList::split( '%', i18n(
+-			"Translators: The %FOO% placeholders are variables that are substituted "
+-			"in the code, please leave them untranslated", orig.utf8() ), true );
+-
+-		// The first part is always text, as our variables are written like %FOO%
+-		QStringList::Iterator it = parts.begin();
+-		QString trans = *it;
+-		bool prependPercent = true;
+-		it = parts.remove( it );
+-		for ( it = parts.begin(); it != parts.end(); ++it )
+-		{
+-			prependPercent = false;
+-
+-			if ( *it == QString::fromLatin1( "TIME" ) )
+-			{
+-				trans += QString::fromLatin1( "<xsl:value-of select=\"@time\"/>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "TIMESTAMP" ) )
+-			{
+-				trans += QString::fromLatin1( "<xsl:value-of select=\"@timestamp\"/>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "FORMATTEDTIMESTAMP" ) )
+-			{
+-				trans += QString::fromLatin1( "<xsl:value-of select=\"@formattedTimestamp\"/>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "FROM_CONTACT_DISPLAYNAME" ) )
+-			{
+-				trans += QString::fromLatin1( "<span><xsl:attribute name=\"title\">"
+-					"<xsl:choose>"
+-						"<xsl:when test='from/contact/@contactId=from/contact/contactDisplayName/@text'>"
+-							"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/metaContactDisplayName/@text\"/>"
+-						"</xsl:when>"
+-						"<xsl:otherwise>"
+-							"<xsl:value-of disable-output-escaping=\"yes\"	select=\"from/contact/metaContactDisplayName/@text\"/>&#160;"
+-							"(<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>)"
+-						"</xsl:otherwise>"
+-					"</xsl:choose></xsl:attribute>"
+-					"<xsl:attribute name=\"dir\">"
+-					"<xsl:value-of select=\"from/contact/contactDisplayName/@dir\"/>"
+-					"</xsl:attribute>"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/contactDisplayName/@text\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "TO_CONTACT_DISPLAYNAME" ) )
+-			{
+-				trans += QString::fromLatin1( "<span><xsl:attribute name=\"title\">"
+-					"<xsl:choose>"
+-						"<xsl:when test='to/contact/@contactId=from/contact/contactDisplayName/@text'>"
+-							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/metaContactDisplayName/@text\"/>"
+-						"</xsl:when>"
+-						"<xsl:otherwise>"
+-							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/metaContactDisplayName/@text\"/>&#160;"
+-							"(<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>)"
+-						"</xsl:otherwise>"
+-					"</xsl:choose></xsl:attribute>"
+-					"<xsl:attribute name=\"dir\">"
+-					"<xsl:value-of select=\"to/contact/contactDisplayName/@dir\"/>"
+-					"</xsl:attribute>"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/contactDisplayName/@text\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "FROM_METACONTACT_DISPLAYNAME" ) )
+-			{
+-				trans += QString::fromLatin1( "<span>"
+-				"<xsl:attribute name=\"dir\">"
+-				"<xsl:value-of select=\"from/contact/metaContactDisplayName/@dir\"/>"
+-				"</xsl:attribute>"
+-				"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/metaContactDisplayName/@text\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "TO_METACONTACT_DISPLAYNAME" ) )
+-			{
+-				trans += QString::fromLatin1( "<span>"
+-				"<xsl:attribute name=\"dir\">"
+-					"<xsl:value-of select=\"to/contact/metaContactDisplayName/@dir\"/>"
+-					"</xsl:attribute>"
+-				"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/metaContactDisplayName/@text\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "FROM_CONTACT_ID" ) )
+-			{
+-				trans += QString::fromLatin1( "<span><xsl:attribute name=\"title\">"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/contactDisplayName/@text\"/></xsl:attribute>"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "TO_CONTACT_ID" ) )
+-			{
+-				trans += QString::fromLatin1( "<span><xsl:attribute name=\"title\">"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/contactDisplayName/@text\"/></xsl:attribute>"
+-					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/></span>" );
+-			}
+-			else if ( *it == QString::fromLatin1( "BODY" ) )
+-			{
+-				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"body\"/>" );
+-			}
+-			else
+-			{
+-				if ( prependPercent )
+-					trans += '%';
+-				trans += *it;
+-				prependPercent = true;
+-			}
+-		}
+-		//kdDebug( 14010 ) << k_funcinfo << "Translated text: " << trans << endl;
+-		// Add "<kopete-i18n>" and "</kopete-i18n>" to length, hence the '+ 27'
+-		document.replace( uint( pos ), orig.length() + 27, trans );
+-	}
+-
+-	#ifdef RAWXSL
+-		kdDebug(14000) << k_funcinfo << document.utf8() << endl;
+-	#endif
+-
+-	//Freeing the stylesheet also frees the doc pointer;
+-	xsltFreeStylesheet( d->styleSheet );
+-	d->styleSheet = 0;
+-	d->xslDoc = 0;
+-	d->flags = 0;
+-
+-	QCString rawDocument = document.utf8();
+-	d->xslDoc = xmlParseMemory( rawDocument, rawDocument.length() );
+-
+-	if( d->xslDoc )
+-	{
+-		d->styleSheet = xsltParseStylesheetDoc( d->xslDoc );
+-		if( d->styleSheet  )
+-		{
+-			// Check for flags
+-			QStringList flags;
+-			for( xmlNodePtr child = d->xslDoc->children; child != d->xslDoc->last; child = child->next )
+-			{
+-				if( child->type == XML_PI_NODE )
+-				{
+-					//We have a flag. Enable it;
+-					QCString flagData( (const char*)child->content );
+-
+-					if( flagData.contains( "Flag:" ) )
+-					{
+-						flags += flagData.mid(5);
+-					}
+-				}
+-			}
+-
+-			if( !flags.isEmpty() )
+-				setProperty("flags", flags.join( QString::fromLatin1("|") ) );
+-		}
+-		else
+-		{
+-			kdWarning(14000) << "Invalid stylesheet provided" << endl;
+-
+-			//We don't have a stylesheet, so free the doc pointer
+-			xmlFreeDoc( d->xslDoc );
+-			d->styleSheet = 0;
+-			d->xslDoc = 0;
+-		}
+-	}
+-	else
+-	{
+-		kdWarning(14000) << "Invalid stylesheet provided" << endl;
+-		d->xslDoc = 0;
+-	}
+-}
+-
+-QString Kopete::XSLT::transform( const QString &xmlString )
+-{
+-	return KopeteXSLThread::xsltTransform( xmlString, d->styleSheet );
+-}
+-
+-void Kopete::XSLT::transformAsync( const QString &xmlString, QObject *target, const char *slotCompleted )
+-{
+-	( new KopeteXSLThread( xmlString, d->styleSheet, target, slotCompleted ) )->start();
+-}
+-
+-bool Kopete::XSLT::isValid() const
+-{
+-	return d->styleSheet != NULL;
+-}
+-
+-void Kopete::XSLT::setFlags( unsigned int flags )
+-{
+-	d->flags = flags;
+-}
+-
+-unsigned int Kopete::XSLT::flags() const
+-{
+-	return d->flags;
+-}
+-
+-#include "kopetexsl.moc"
+-
+-// vim: set noet ts=4 sts=4 sw=4:
+-
+--- kopete/libkopete/kopetexsl.h	(revision 568672)
++++ kopete/libkopete/kopetexsl.h	(revision 586398)
+@@ -1,117 +0,0 @@
+-/*
+-    kopetexslt.h - Kopete XSLT Routines
+-
+-    Copyright (c) 2003      by Jason Keirstead       <jason at keirstead.org>
+-    Copyright (c) 2003      by Martijn Klingens      <klingens at kde.org>
+-
+-    Kopete    (c) 2002-2003 by the Kopete developers <kopete-devel at kde.org>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#ifndef _KOPETE_XSLT_H
+-#define _KOPETE_XSLT_H
+-
+-#include <qobject.h>
+-#include "kopete_export.h"
+-
+-class KopeteXSLTPrivate;
+-
+-namespace Kopete
+-{
+-
+-/**
+- * @author Jason Keirstead <jason at keirstead.org>
+- *
+- * This class provides an easy to use interface to basic
+- * libxslt transformations.
+- */
+-class KOPETE_EXPORT XSLT : public QObject
+-{
+-	Q_OBJECT
+-
+-	Q_PROPERTY( Flags flags READ flags WRITE setFlags )
+-	Q_PROPERTY( bool isValid READ isValid )
+-
+-	Q_SETS( Flags )
+-
+-public:
+-	/**
+-	 * Special flags to be used during the transformation process. Passed
+-	 * into the engine as processing instructions.
+-	 */
+-	enum Flags
+-	{
+- 		TransformAllMessages = 1
+-	};
+-
+-	/**
+-	 * Constructor.
+-	 *
+-	 * Constructs a new Kopete XSLT parser using the provided XSLT document
+-	 */
+-	XSLT( const QString &xsltDocument, QObject *parent = 0L );
+-
+-	virtual ~XSLT();
+-
+-	/**
+-	 * Set the XSLT document
+-	 *
+-	 * @return an ORed set of @ref Flags, or 0 if none
+-	 */
+-	void setXSLT( const QString &document );
+-
+-	/**
+-	 * Transforms the XML string using the XSLT document, synchronously
+-	 *
+-	 * @param xmlString The source XML
+-	 * @return The result of the transformation
+-	 */
+-	QString transform( const QString &xmlString );
+-
+-	/**
+-	 * Transforms the XML string using the XSLT document, asynchronously
+-	 *
+-	 * @param xmlString The source XML
+-	 * @param target The QObject that contains the slot to be executed when processing is complete
+-	 * @param slotCompleted A slot that accepts a QVariant & paramater, that is the result
+-	 * of the transformation
+-	 */
+-	void transformAsync( const QString &xmlString, QObject *target, const char *slotCompleted );
+-
+-	/**
+-	 * Check whether the XSLT document is valid
+-	 *
+-	 * @return Whether the document represents a valid XSLT stylesheet
+-	 */
+-	bool isValid() const;
+-
+-	/**
+-	 * @return An ORed list of Flags that the current stylesheet provides via processing instructions
+-	 */
+-	unsigned int flags() const;
+-
+-	/**
+-	 * Sets flags to be used for the transformation.
+-	 *
+-	 * @param flags An ORed list of flags
+-	 */
+-	void setFlags( unsigned int flags );
+-
+-private:
+-	KopeteXSLTPrivate *d;
+-};
+-
+-}
+-
+-#endif
+-
+-// vim: set noet ts=4 sts=4 sw=4:
+-
+--- kopete/libkopete/kopetechatsession.h	(revision 568672)
++++ kopete/libkopete/kopetechatsession.h	(revision 586398)
+@@ -6,7 +6,7 @@
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+     Copyright (c) 2002-2004 by Olivier Goffart        <ogoffart @ kde.org>
+     Copyright (c) 2003      by Jason Keirstead        <jason at keirstead.org>
+-    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
+ 
+     Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -250,6 +250,12 @@
+ 	 */
+ 	void eventNotification( const QString& notificationText);
+ 
++	/**
++	 * @brief A contact within the chat session changed his photo.
++	 * Used to update the contacts photo in chat window.
++	 */
++	void photoChanged();
++
+ public slots:
+ 	/**
+ 	 * @brief Got a typing notification from a user
+--- kopete/libkopete/kopetecontactlist.h	(revision 568672)
++++ kopete/libkopete/kopetecontactlist.h	(revision 586398)
+@@ -173,6 +173,11 @@
+ 	 */
+ 	 void setSelectedItems(QPtrList<MetaContact> metaContacts , QPtrList<Group> groups);
+ 
++	/**
++	  * Apply the global identity.
++	  */
++	void loadGlobalIdentity();
++
+ signals:
+ 	/**
+ 	 * A meta contact was added to the contact list. Interested classes
+@@ -270,11 +275,6 @@
+ 	void slotKABCChanged();
+ 	
+ 	/**
+-	  * Apply the global identity.
+-	  */
+-	void loadGlobalIdentity();
+-
+-	/**
+ 	 * Called when the myself displayName changed.
+ 	 */
+ 	void slotDisplayNameChanged();
+--- kopete/libkopete/avdevice/videodevicepool.cpp	(revision 568672)
++++ kopete/libkopete/avdevice/videodevicepool.cpp	(revision 586398)
+@@ -808,7 +808,7 @@
+ 			const QString modelindex = QString::fromLocal8Bit ( "Model %1 Device %2")  .arg ((*vditerator).m_name ) .arg ((*vditerator).m_modelindex);
+ 			if(modelindex == currentdevice)
+ 			{
+-				m_current_device = vditerator - m_videodevice.begin();
++				m_current_device = std::distance (m_videodevice.begin(), vditerator);
+ //				kdDebug() << k_funcinfo << "This place will be used to set " << modelindex << " as the current device ( " << std::distance(m_videodevice.begin(), vditerator ) << " )." << endl;
+ 			}
+ 			const QString name                = config->readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Name")  .arg ((*vditerator).m_name ) .arg ((*vditerator).m_modelindex)), (*vditerator).m_model);
+--- kopete/libkopete/avdevice/videodevice.cpp	(revision 568672)
++++ kopete/libkopete/avdevice/videodevice.cpp	(revision 586398)
+@@ -601,6 +601,8 @@
+ 				{
+ 					struct video_window V4L_videowindow;
+ 
++kdDebug() << "------------- width: " << V4L_videowindow.width << " Height: " << V4L_videowindow.height << " Clipcount: " << V4L_videowindow.clipcount << " -----------------" << endl;
++
+ 				if (xioctl (VIDIOCGWIN, &V4L_videowindow)== -1)
+ 				{
+ 					perror ("ioctl VIDIOCGWIN");
+--- kopete/libkopete/avdevice/Makefile.am	(revision 568672)
++++ kopete/libkopete/avdevice/Makefile.am	(revision 586398)
+@@ -8,7 +8,7 @@
+ libkopete_videodevice_la_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+ 
+ noinst_HEADERS = videodevice.h videoinput.h kxv.h qvideo.h qvideostream.h \
+-		videodevicepool.h videodevicemodelpool.h
++	videodevicepool.h videodevicemodelpool.h
+ libkopete_videodevice_la_SOURCES = videodevice.cpp videoinput.cpp \
+ 		videodevicepool.cpp videodevicemodelpool.cpp
+ libkvideoio_la_LDFLAGS = -no-undefined $(all_libraries) -version-info 1:0:0
+--- kopete/libkopete/webcamwidget.h	(revision 0)
++++ kopete/libkopete/webcamwidget.h	(revision 586398)
+@@ -0,0 +1,66 @@
++/*
++    webcamwidget.h - A simple widget for displaying webcam frames
++
++    Copyright (c) 2006 by Gustavo Pichorim Boiko   <gustavo.boiko at kdemail.net>
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at 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 WEBCAMWIDGET_H 
++#define WEBCAMWIDGET_H 
++
++#include <qwidget.h>
++#include <qpixmap.h>
++#include <qstring.h>
++
++#include "kopete_export.h"
++
++namespace Kopete
++{
++/**
++ * A simple widget to display webcam frames.
++ */
++class KOPETE_EXPORT WebcamWidget : public QWidget
++{
++Q_OBJECT
++public:
++	/**
++	* @brief WebcamWidget constructor.
++	* @param parent The parent widget of this widget
++	* @param name The name for this QObject
++	*/
++	WebcamWidget( QWidget* parent = 0, const char* name = 0 );
++	~WebcamWidget();
++
++	/**
++	 * @brief Updates the frame being displayed in the widget
++	 * @param pixmap The frame to be displayed
++	 */
++	void updatePixmap(const QPixmap& pixmap);
++
++	/**
++	 * @brief Clear the widget
++	 */
++	void clear();
++
++	/**
++	 * @brief Set a text to be displayed in the widget
++	 * @param text The text to be displayed
++	 */
++	void setText(const QString& text);
++protected slots:
++	void paintEvent( QPaintEvent* event );
++	QPixmap mPixmap;
++	QString mText;
++};
++
++} // end namespace Kopete
++#endif
+--- kopete/libkopete/kopeteutils.cpp	(revision 568672)
++++ kopete/libkopete/kopeteutils.cpp	(revision 586398)
+@@ -36,12 +36,12 @@
+ #include "kopeteuiglobal.h"
+ 
+ static const QString notifyConnectionLost_DefaultMessage = i18n("You have been disconnected.");
+-static const QString notifyConnectionLost_DefaultCaption = i18n("Connection Lost");
+-static const QString notifyConnectionLost_DefaultExplanation = i18n("Kopete lost the channel used to talk to the instant messaging system.\nThis can be because your Internet connection went down, the service is experiencing problems, or the service disconnected you because you tried to connect using the same account from another location. Try connecting again later.");
++static const QString notifyConnectionLost_DefaultCaption = i18n("Connection Lost.");
++static const QString notifyConnectionLost_DefaultExplanation = i18n("Kopete lost the channel used to talk to the instant messaging system.\nThis can be because either your internet access went down, the service is experiencing problems, or the service disconnected you because you tried to connect with the same account from another location. Try connecting again later.");
+ 
+ static const QString notifyCannotConnect_DefaultMessage = i18n("Can't connect with the instant messaging server or peers.");
+ static const QString notifyCannotConnect_DefaultCaption = i18n("Can't connect.");
+-static const QString notifyCannotConnect_DefaultExplanation = i18n("This means Kopete can't reach the instant messaging server or peers.\nThis can be either your Internet access is down or the server is experiencing problems. Try connecting again later.");
++static const QString notifyCannotConnect_DefaultExplanation = i18n("This means Kopete can't reach the instant messaging server or peers.\nThis can be because either your internet access is down or the server is experiencing problems. Try connecting again later.");
+ 
+ namespace Kopete
+ {
+--- kopete/libkopete/kopeteaway.cpp	(revision 568672)
++++ kopete/libkopete/kopeteaway.cpp	(revision 586398)
+@@ -60,6 +60,8 @@
+ struct KopeteAwayPrivate
+ {
+ 	QString awayMessage;
++	QString autoAwayMessage;
++	bool useAutoAwayMessage;
+ 	bool globalAway;
+ 	QStringList awayMessageList;
+ 	QTime idleTime;
+@@ -94,6 +96,8 @@
+ 
+ 	// Set up the away messages
+ 	d->awayMessage = QString::null;
++	d->autoAwayMessage = QString::null;
++	d->useAutoAwayMessage = false;
+ 	d->globalAway = false;
+ 	d->autoaway = false;
+ 	d->useAutoAway = true;
+@@ -145,6 +149,7 @@
+ 	/* Load the saved away messages */
+ 	config->setGroup("Away Messages");
+ 
++	// Away Messages
+ 	if(config->hasKey("Messages"))
+ 	{
+ 		d->awayMessageList = config->readListEntry("Messages");
+@@ -169,6 +174,19 @@
+ 		save();
+ 	}
+ 
++	// Auto away message
++	if(config->hasKey("AutoAwayMessage"))
++	{
++		d->autoAwayMessage = config->readEntry("AutoAwayMessage");
++	}
++	else
++	{
++		d->autoAwayMessage = i18n( "I am gone right now, but I will be back later" );
++		
++		// Save the default auto away message to disk
++		save();
++	}
++	
+ 	// init the timer
+ 	d->timer = new QTimer(this, "AwayTimer");
+ 	connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimerTimeout()));
+@@ -180,6 +198,8 @@
+ 
+ Kopete::Away::~Away()
+ {
++	if(this == instance)
++		instance = 0L;	
+ 	delete d;
+ }
+ 
+@@ -188,6 +208,11 @@
+ 	return getInstance()->d->awayMessage;
+ }
+ 
++QString Kopete::Away::autoAwayMessage()
++{
++	return getInstance()->d->autoAwayMessage;
++}
++
+ void Kopete::Away::setGlobalAwayMessage(const QString &message)
+ {
+ 	if( !message.isEmpty() )
+@@ -198,6 +223,19 @@
+ 	}
+ }
+ 
++void Kopete::Away::setAutoAwayMessage(const QString &message)
++{
++	if( !message.isEmpty() )
++	{
++		kdDebug(14010) << k_funcinfo <<
++			"Setting auto away message: " << message << endl;
++		d->autoAwayMessage = message;
++		
++		// Save the new auto away message to disk
++		save();
++	}
++}
++
+ Kopete::Away *Kopete::Away::getInstance()
+ {
+ 	if (!instance)
+@@ -221,6 +259,7 @@
+ 	/* Set the away message settings in the Away Messages config group */
+ 	config->setGroup("Away Messages");
+ 	config->writeEntry("Messages", d->awayMessageList);
++	config->writeEntry("AutoAwayMessage",  d->autoAwayMessage);
+ 	config->sync();
+ 
+ 	emit( messagesChanged() );
+@@ -233,6 +272,7 @@
+ 	d->awayTimeout=config->readNumEntry("Timeout", 600);
+ 	d->goAvailable=config->readBoolEntry("GoAvailable", true);
+ 	d->useAutoAway=config->readBoolEntry("UseAutoAway", true);
++	d->useAutoAwayMessage=config->readBoolEntry("UseAutoAwayMessage", false);
+ }
+ 
+ QStringList Kopete::Away::getMessages()
+@@ -286,9 +326,18 @@
+ 	// isn't blanked/locked, because activity while blanked is impossible and
+ 	// activity while locked never matters (if there is any, it's probably just
+ 	// the cleaner wiping the keyboard :).
+-
++	
++	
++	/* we should be able to respond to KDesktop queries to avoid a deadlock, so we allow the event loop to be called */
++	static bool rentrency_protection=false;
++	if(rentrency_protection)
++		return;
++	rentrency_protection=true;
+ 	DCOPRef screenSaver("kdesktop", "KScreensaverIface");
+-	DCOPReply isBlanked = screenSaver.call("isBlanked");
++	DCOPReply isBlanked = screenSaver.callExt("isBlanked" ,  DCOPRef::UseEventLoop, 10);
++	rentrency_protection=false;
++	if(!instance) //this may have been deleted in the event loop
++		return;
+ 	if (!(isBlanked.isValid() && isBlanked.type == "bool" && ((bool)isBlanked)))
+ 	{
+ 		// DCOP failed, or returned something odd, or the screensaver is
+@@ -421,8 +470,7 @@
+ 				if(i->isConnected() && i->isAway())
+ 				{
+ 					i->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( i->protocol() ,
+-										Kopete::OnlineStatusManager::Online ) ,
+-					getInstance()->d->awayMessage);	
++										Kopete::OnlineStatusManager::Online ) );
+ 				}
+ 
+ 				// remove() makes the next entry in the list the current one,
+@@ -454,9 +502,21 @@
+ 		if(i->myself()->onlineStatus().status() == Kopete::OnlineStatus::Online)
+ 		{
+ 			d->autoAwayAccounts.append(i);
++			
++			if(d->useAutoAwayMessage)
++			{
++			// Display a specific away message
+ 			i->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( i->protocol() ,
+-													Kopete::OnlineStatusManager::Idle ) ,
++				Kopete::OnlineStatusManager::Idle ) ,
++								getInstance()->d->autoAwayMessage);
++			}
++			else
++			{
++			// Display the last away message used
++			i->setOnlineStatus( Kopete::OnlineStatusManager::self()->onlineStatus( i->protocol() ,
++				Kopete::OnlineStatusManager::Idle ) ,
+ 								getInstance()->d->awayMessage);
++			}
+ 		}
+ 	}
+ }
+--- kopete/libkopete/kopetepicture.h	(revision 0)
++++ kopete/libkopete/kopetepicture.h	(revision 586398)
+@@ -0,0 +1,149 @@
++/*
++    kopetepicture.h - Kopete Picture
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++#ifndef KOPETEPICTURE_H
++#define KOPETEPICTURE_H
++
++#include <kdemacros.h>
++#include <ksharedptr.h>
++#include "kopete_export.h"
++
++#include <qimage.h>
++
++namespace KABC
++{
++	class Picture;
++}
++
++namespace Kopete
++{
++/**
++ * @brief Represent a picture in Kopete context
++ *
++ * It kept a cache of a QImage object, a base64 string and
++ * a path to a image file. It ensure that all source are synced.
++ * Interally, the image is stored in PNG format when possible.
++ * It can happen that the image path do not return a PNG file.
++ *
++ * You can only use an QImage and a image path to create/update
++ * the picture.
++ * If the picture doesn't exist as a file, it generate a local
++ * copy into ~/.kde/share/apps/kopete/metacontactpicturecache
++ *
++ * This class is implicitly shared, so don't use it as a pointer.
++ *
++ * How to use this class:
++ * @code
++ * Kopete::Picture picture;
++ * picture.setPicture(QImage());
++ * picture.setPicture(QString("/tmp/image.png"));
++ * 
++ * QString base64 = picture.base64();
++ * QString path = picture.path();
++ * QImage image = picture.image();
++ * @endcode
++ *
++ * @author Michaël Larouche <michael.larouche at kdemail.net>
++ */
++class KOPETE_EXPORT Picture	
++{
++public:
++	/**
++	 * Create a empty Kopete::Picture
++	 */
++	Picture();
++	/**
++	 * Create a picture from a local path.
++	 */
++	Picture(const QString &path);
++	/**
++	 * Create a picture from a QImage.
++	 */
++	Picture(const QImage &image);
++	/**
++	 * Create a picture from a KABC::Picture.
++	 */
++	Picture(const KABC::Picture &picture);
++	/**
++	 * Copy a picture. It doesn't create a full copy, it just make a reference.
++	 */
++	Picture(const Picture &other);
++	/**
++	 * Delete the Kopete::Picture
++	 */
++	~Picture();
++	/**
++	 * Assignment operator.
++	 * Like the copy constructor, it just make a reference.
++	 */
++	Picture &operator=(const Picture &other);
++
++	/**
++	 * Return the current picture as QImage.
++	 * QImage can used to draw the image on a context.
++	 * 
++	 * @return the QImage cache of current picture.
++	 */
++	QImage image();
++	/**
++	 * Return the current picture as a base64 string.
++	 * The base64 is used to include the picture into a XML/XHTML context.
++	 */
++	QString base64();
++	/**
++	 * Return the local path of the current picture.
++	 */
++	QString path();
++
++	/**
++	 * Check if the picture is null.
++ 	 */
++	bool isNull();
++	/**
++	 * Reset the picture.
++	 */
++	void clear();
++
++	/**
++	 * Set the picture content.
++	 * @param image the picture as a QImage.
++	 */
++	void setPicture(const QImage &image);
++	/**
++	 * Set the picture content.
++	 * @param path the path to the picture.
++	 */
++	void setPicture(const QString &path);
++	/**
++	 * Set the picture content.
++	 * @param picture a KABC Picture.
++	 */
++	void setPicture(const KABC::Picture &picture);
++	
++private:
++	/**
++	 * Kopete::Picture is implicitly shared.
++	 * Detach the instance when modifying data.
++	 */
++	void detach();
++
++	class Private;
++	KSharedPtr<Private> d;
++};
++
++}//END namespace Kopete
++
++#endif
+--- kopete/libkopete/kopetechatsession.cpp	(revision 568672)
++++ kopete/libkopete/kopetechatsession.cpp	(revision 586398)
+@@ -6,7 +6,7 @@
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+     Copyright (c) 2002-2004 by Olivier Goffart        <ogoffart @ kde.org>
+     Copyright (c) 2003      by Jason Keirstead        <jason at keirstead.org>
+-    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
+ 
+     Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -82,6 +82,9 @@
+ 	connect( user, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ), this,
+ 		SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
+ 
++	if( user->metaContact() )
++		connect( user->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
++
+ 	slotUpdateDisplayName();
+ }
+ 
+@@ -321,7 +324,10 @@
+ 			this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
+ 
+ 			if ( old->metaContact() )
++			{
+ 				disconnect( old->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
++				disconnect( old->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
++			}
+ 			else
+ 				disconnect( old, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
+ 			emit contactAdded( c, suppress );
+@@ -337,7 +343,10 @@
+ 			this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
+ ;
+ 		if ( c->metaContact() )
++		{
+ 			connect( c->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
++			connect( c->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
++		}
+ 		else
+ 			connect( c, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
+ 		connect( c, SIGNAL( contactDestroyed( Kopete::Contact * ) ), this, SLOT( slotContactDestroyed( Kopete::Contact * ) ) );
+@@ -366,7 +375,10 @@
+ 			this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &) ) );
+ 
+ 		if ( c->metaContact() )
++		{
+ 			disconnect( c->metaContact(), SIGNAL( displayNameChanged( const QString &, const QString & ) ), this, SLOT( slotUpdateDisplayName() ) );
++			disconnect( c->metaContact(), SIGNAL( photoChanged() ), this, SIGNAL( photoChanged() ) );
++		}
+ 		else
+ 			disconnect( c, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ), this, SLOT( slotUpdateDisplayName() ) );
+ 		disconnect( c, SIGNAL( contactDestroyed( Kopete::Contact * ) ), this, SLOT( slotContactDestroyed( Kopete::Contact * ) ) );
+@@ -457,7 +469,10 @@
+ 
+ void Kopete::ChatSession::slotContactDestroyed( Kopete::Contact *contact )
+ {
+-	if ( !contact || !d->mContactList.contains( contact ) )
++	if(contact == myself())
++		deleteLater();
++		
++	if( !contact || !d->mContactList.contains( contact ) )
+ 		return;
+ 
+ 	//This is a workaround to prevent crash if the contact get deleted.
+--- kopete/libkopete/kopetemessage.cpp	(revision 568672)
++++ kopete/libkopete/kopetemessage.cpp	(revision 586398)
+@@ -2,7 +2,7 @@
+     kopetemessage.cpp  -  Base class for Kopete messages
+ 
+     Copyright (c) 2002-2003 by Martijn Klingens       <klingens at kde.org>
+-    Copyright (c) 2002-2005 by Olivier Goffart        <ogoffart @ kde.org>
++    Copyright (c) 2002-2006 by Olivier Goffart        <ogoffart @ kde.org>
+ 
+     Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -29,6 +29,7 @@
+ #include <kiconloader.h>
+ #include <kstringhandler.h>
+ #include <kmdcodec.h>
++#include <qguardedptr.h>
+ 
+ #include "kopetemessage.h"
+ #include "kopetemetacontact.h"
+@@ -49,7 +50,7 @@
+ 	         const QString &body, const QString &subject, MessageDirection direction, MessageFormat f,
+ 	         const QString &requestedPlugin, MessageType type );
+ 
+-	const Contact *from;
++	QGuardedPtr<const Contact> from;
+ 	ContactPtrList to;
+ 	ChatSession *manager;
+ 
+@@ -68,15 +69,8 @@
+ 	QColor bgColor;
+ 	QString body;
+ 	QString subject;
+-	
+-	//the cache is used to keep the base64 if images
+-	//Note: in QT4 this should be probably a QHash
+-	static QMap <QString , QString> imageCache;
+-
+ };
+ 
+-QMap <QString , QString> Message::Private::imageCache;
+-
+ Message::Private::Private( const QDateTime &timeStamp, const Contact *from,
+              const ContactPtrList &to, const QString &body, const QString &subject,
+ 				 MessageDirection direction, MessageFormat f, const QString &requestedPlugin, MessageType type )
+@@ -84,6 +78,8 @@
+ 	, requestedPlugin(requestedPlugin), importance( (to.count() <= 1) ? Normal : Low ), bgOverride(false), fgOverride(false)
+ 	, rtfOverride(false), timeStamp(timeStamp), body(body), subject(subject)
+ {
++	
++	//TODO: move that in ChatTextEditPart::contents
+ 	if( format == RichText )
+ 	{
+ 		//This is coming from the RichTextEditor component.
+@@ -100,6 +96,8 @@
+ 		if ( this->body.endsWith( QString::fromLatin1("<br/>") ) )
+ 			this->body.truncate( this->body.length() - 5 );
+ 		this->body.remove(  QString::fromLatin1("\n") );
++		this->body.replace( QRegExp( QString::fromLatin1( "\\s\\s" ) ), QString::fromLatin1( "&nbsp; " ) );
++
+ 	}
+ }
+ 
+@@ -212,6 +210,7 @@
+ 	detach();
+ 
+ 	QString theBody = body;
++	//TODO: move that in ChatTextEditPart::contents
+ 	if( f == RichText )
+ 	{
+ 		//This is coming from the RichTextEditor component.
+@@ -227,9 +226,14 @@
+ 		//Remove trailing </br>
+ 		if ( theBody.endsWith( QString::fromLatin1("<br/>") ) )
+ 			theBody.truncate( theBody.length() - 5 );
+-
++	
+ 		theBody.remove( QString::fromLatin1("\n") );
++		theBody.replace( QRegExp( QString::fromLatin1( "\\s\\s" ) ), QString::fromLatin1( "&nbsp; " ) );
+ 	}
++	/*	else if( f == ParsedHTML )
++	{
++	kdWarning( 14000 ) << k_funcinfo << "using ParsedHTML which is internal !   message: " << body << kdBacktrace() << endl;
++	}*/
+ 
+ 	d->body=theBody;
+ 	d->format = f;
+@@ -259,6 +263,7 @@
+ 	data.replace( QString::fromLatin1( "&quot;" ), QString::fromLatin1( "\"" ) );
+ 	data.replace( QString::fromLatin1( "&nbsp;" ), QString::fromLatin1( " " ) );
+ 	data.replace( QString::fromLatin1( "&amp;" ), QString::fromLatin1( "&" ) );
++	data.replace( QString::fromLatin1( "&#160;" ), QString::fromLatin1( " " ) );  //this one is used in jabber:  note, we should escape all &#xx;
+ 
+ 	return data;
+ }
+@@ -293,11 +298,17 @@
+ QString Message::escapedBody() const
+ {
+ 	QString escapedBody=d->body;
++//	kdDebug(14000) << k_funcinfo << escapedBody << " " << d->rtfOverride << endl;
+ 
+ 	if( d->format & PlainText )
+ 	{
+ 		escapedBody=escape( escapedBody );
+ 	}
++	else if( d->format & RichText && d->rtfOverride)
++	{
++		//remove the rich text
++		escapedBody = escape (unescape( escapedBody ) );
++	}
+ 
+ 	return escapedBody;
+ }
+@@ -312,7 +323,7 @@
+ 	}
+ 	else
+ 	{
+-		return Kopete::Emoticons::parseEmoticons(parseLinks(escapedBody(), d->format));
++		return Kopete::Emoticons::parseEmoticons(parseLinks(escapedBody(), RichText));
+ 	}
+ }
+ 
+@@ -467,210 +478,23 @@
+ 	d->manager=kmm;
+ }
+ 
+-
+-QDomElement Message::contactNode( QDomDocument doc, const Contact *contact )
++QString Message::getHtmlStyleAttribute() const
+ {
+-	KopetePrefs *p = KopetePrefs::prefs();
+-
+-	// These colors are used for coloring nicknames. I tried to use
+-	// colors both visible on light and dark background.
+-	static const char* const nameColors[] =
+-	{
+-		"red", "blue" , "gray", "magenta", "violet", "olive", "yellowgreen",
+-		"darkred", "darkgreen", "darksalmon", "darkcyan", "darkyellow",
+-		"mediumpurple", "peru", "olivedrab", "royalred", "darkorange", "slateblue",
+-		"slategray", "goldenrod", "orangered", "tomato", "dogderblue", "steelblue",
+-		"deeppink", "saddlebrown", "coral", "royalblue"
+-	};
+-
+-	static const int nameColorsLen = sizeof(nameColors) / sizeof(nameColors[0]) - 1;
++	QString styleAttribute;
+ 	
+-	QString contactName = contact->property(Global::Properties::self()->nickName()).value().toString();
+-	if( p->truncateContactNames() )
+-	{
+-		contactName = KStringHandler::csqueeze( contactName, p->maxContactNameLength() );
+-	}
++	styleAttribute = QString::fromUtf8("style=\"");
+ 
+-	if(contactName.isEmpty())
+-		contactName = contact->metaContact() ? contact->metaContact()->displayName() : contact->contactId();
+-
+-	QString metacontactName = contact->metaContact() ? contact->metaContact()->displayName() : contactName;
+-	QDomElement contactNode = doc.createElement( QString::fromLatin1("contact") );
+-	contactNode.setAttribute( QString::fromLatin1("contactId"), contact->contactId() );
+-
+-	QDomElement contactNameNode = doc.createElement( QString::fromLatin1("contactDisplayName") );
+-	contactNameNode.setAttribute( QString::fromLatin1("dir"), contactName.isRightToLeft() ?
+-	                              QString::fromLatin1("rtl") : QString::fromLatin1("ltr") );
+-	contactNameNode.setAttribute( QString::fromLatin1("text"), QStyleSheet::escape( contactName ) );
+-	contactNode.appendChild( contactNameNode );
+-
+-
+-	QDomElement metacontactNameNode = doc.createElement( QString::fromLatin1("metaContactDisplayName") );
+-	metacontactNameNode.setAttribute( QString::fromLatin1("dir"), metacontactName.isRightToLeft() ?
+-	                                  QString::fromLatin1("rtl") : QString::fromLatin1("ltr") );
+-	metacontactNameNode.setAttribute( QString::fromLatin1("text"), QStyleSheet::escape( metacontactName ) );
+-
+-	
+-	if( contact->metaContact() && !contact->metaContact()->metaContactId().isEmpty())
++	// Affect foreground(color) and background color to message.
++	if( !d->fgOverride && d->fgColor.isValid() )
+ 	{
+-		if(d->imageCache.contains(contact->metaContact()->metaContactId()))
+-		{
+-			contactNode.setAttribute( QString::fromLatin1("userPhoto"), d->imageCache[contact->metaContact()->metaContactId()]);
+-		}
+-		else
+-		{
+-			QImage photo = contact->metaContact()->photo();
+-			if( !photo.isNull() )
+-			{
+-				QByteArray ba;
+-				QBuffer buffer( ba );
+-				buffer.open( IO_WriteOnly );
+-				photo.save ( &buffer, "PNG" );
+-				QString photo64=KCodecs::base64Encode(ba);
+-			
+-				if(d->imageCache.count() > 14)
+-				{
+-					d->imageCache.clear();
+-				}
+-				d->imageCache.insert(contact->metaContact()->metaContactId(), photo64);
+-				
+-				contactNode.setAttribute( QString::fromLatin1("userPhoto"), photo64 );
+-			}
+-		}
++		styleAttribute += QString::fromUtf8("color: %1; ").arg(d->fgColor.name());
+ 	}
+-
+-	contactNode.appendChild( metacontactNameNode );
+-
+-	// protocol() returns NULL here in the style preview in appearance config.
+-	// this isn't the right place to work around it, since contacts should never have
+-	// no protocol, but it works for now.
+-	QString iconName = QString::fromLatin1("kopete");
+-	if ( Protocol *protocol = contact->protocol() )
+-		iconName = protocol->pluginIcon();
+-
+-	QString iconPath = KGlobal::iconLoader()->iconPath( iconName, KIcon::Small );
+-	contactNode.setAttribute( QString::fromLatin1("protocolIcon"), iconPath );
+-
+-	// hash contactId to deterministically pick a color for the contact
+-	int hash = 0;
+-	const QString &contactId = contact->contactId();
+-	for( uint f = 0; f < contactId.length(); ++f )
+-		hash += contactId[f].unicode() * f;
+-
+-	QString color = QColor( nameColors[ hash % nameColorsLen ] ).name();
+-	contactNode.setAttribute( QString::fromLatin1("color"), color );
+-
+-	return contactNode;
+-}
+-
+-
+-const QDomDocument Message::asXML()
+-{
+-	QDomDocument doc;
+-	QDomElement messageNode = doc.createElement( QString::fromLatin1("message") );
+-	messageNode.setAttribute( QString::fromLatin1("time"),
+-		KGlobal::locale()->formatTime(d->timeStamp.time(), true) );
+-	messageNode.setAttribute( QString::fromLatin1("timestamp"),
+-		KGlobal::locale()->formatDateTime(d->timeStamp) );
+-	if( d->timeStamp.date() == QDate::currentDate() )
++	if( !d->bgOverride && d->bgColor.isValid() )
+ 	{
+-		messageNode.setAttribute( QString::fromLatin1("formattedTimestamp"),
+-			KGlobal::locale()->formatTime(d->timeStamp.time(), true) );
++		styleAttribute += QString::fromUtf8("background-color: %1; ").arg(d->bgColor.name());
+ 	}
+-	else
+-	{
+-		messageNode.setAttribute( QString::fromLatin1("formattedTimestamp"),
+-			KGlobal::locale()->formatDateTime(d->timeStamp) );
+-	}
+-	messageNode.setAttribute( QString::fromLatin1("subject"), QStyleSheet::escape( d->subject ) );
+-
+-	/**
+-	 * @deprecated backwards-compatibility direction attribute for old XSLT
+-	 * It used to be the case that Action was in the MessageDirection enum.
+-	 * Clearly this is broken - Action is not a direction, and it was impossible
+-	 * to tell whether actions were incoming or outgoing. Anyway, some XSLT view
+-	 * styles were written back when this was the case. They expected numeric
+-	 * 'directions'. So we fake some for them.
+-	 */
+-	{
+-		int oldDirection = 0;
+-		if( type() == TypeAction )
+-			oldDirection = 3;
+-		else if( direction() == Inbound )
+-			oldDirection = 0;
+-		else if( direction() == Outbound )
+-			oldDirection = 1;
+-		else if( direction() == Internal )
+-			oldDirection = 2;
+-		messageNode.setAttribute( QString::fromLatin1("direction"), oldDirection );
+-	}
+-
+-	const char *route;
+-	switch( d->direction )
+-	{
+-		case Inbound:
+-			route = "inbound";
+-			break;
+-		case Outbound:
+-			route = "outbound";
+-			break;
+-		case Internal:
+-			route = "internal";
+-			break;
+-		default:
+-			kdWarning(14000) << k_funcinfo << "unknown message direction " << d->direction << endl;
+-			route = "unknown";
+-			break;
+-	}
+-	messageNode.setAttribute( QString::fromLatin1("route"), QString::fromLatin1(route) );
+-
+-	const char *type;
+-	switch( d->type )
+-	{
+-		case TypeNormal:
+-			type = "normal";
+-			break;
+-		case TypeAction:
+-			type = "action";
+-			break;
+-		default:
+-			kdWarning(14000) << k_funcinfo << "unknown message type " << d->type << endl;
+-			type = "unknown";
+-			break;
+-	}
+-	messageNode.setAttribute( QString::fromLatin1("type"), QString::fromLatin1(type) );
+-
+-	messageNode.setAttribute( QString::fromLatin1("importance"), d->importance );
+-
+-
+-	//build the <from> and <to>  node
+-	if( const Contact *mainContact = (d->direction == Inbound ? d->from : d->to.getFirst()) )
+-		messageNode.setAttribute( QString::fromLatin1("mainContactId"), mainContact->contactId() );
+-
+-	doc.appendChild( messageNode );
+-
+-	if( const Contact *c = d->from )
+-	{
+-		kdDebug() << "KopeteMessage::asXML ** from " << c->contactId() << endl;
+-		QDomElement fromNode = doc.createElement( QString::fromLatin1("from") );
+-		fromNode.appendChild( contactNode( doc, c ) );
+-		messageNode.appendChild( fromNode );
+-	}
+-
+-	if( const Contact *c = d->to.getFirst() )
+-	{
+-		QDomElement toNode = doc.createElement( QString::fromLatin1("to") );
+-		toNode.appendChild( contactNode( doc, c ) );
+-		messageNode.appendChild( toNode );
+-	}
+-
+-	QDomElement bodyNode = doc.createElement( QString::fromLatin1("body") );
+-
+-	if( !d->fgOverride && d->fgColor.isValid() )
+-		bodyNode.setAttribute( QString::fromLatin1("color"), d->fgColor.name() );
+-	if( !d->bgOverride && d->bgColor.isValid() )
+-		bodyNode.setAttribute( QString::fromLatin1("bgcolor"), d->bgColor.name() );
+-
++	
++	// Affect font parameters.
+ 	if( !d->rtfOverride && d->font!=QFont() )
+ 	{
+ 		QString fontstr;
+@@ -685,17 +509,12 @@
+ 		if(d->font.bold())
+ 			fontstr+=QString::fromLatin1("font-weight: bold;");
+ 
+-		bodyNode.setAttribute( QString::fromLatin1("font"), fontstr );
++		styleAttribute += fontstr;
+ 	}
+ 
+-	bodyNode.setAttribute( QString::fromLatin1("dir"),
+-		plainBody().isRightToLeft() ? QString::fromLatin1("rtl") : QString::fromLatin1("ltr") );
+-	QDomCDATASection bodyText = doc.createCDATASection( parsedBody() );
+-	bodyNode.appendChild( bodyText );
++	styleAttribute += QString::fromUtf8("\"");
+ 
+-	messageNode.appendChild( bodyNode );
+-
+-	return doc;
++	return styleAttribute;
+ }
+ 
+ // KDE4: Move that to a utils class/namespace
+@@ -776,9 +595,3 @@
+ 
+ 	return result;
+ }
+-
+-void Kopete::Message::clearImageCache()  //[static]
+-{
+-	Private::imageCache.clear();
+-}
+-
+--- kopete/libkopete/kopetecontactlist.cpp	(revision 568672)
++++ kopete/libkopete/kopetecontactlist.cpp	(revision 586398)
+@@ -40,6 +40,7 @@
+ #include "kopeteaccount.h"
+ #include "kopeteaccountmanager.h"
+ #include "kopetegroup.h"
++#include "kopetepicture.h"
+ 
+ 
+ namespace  Kopete
+@@ -302,6 +303,10 @@
+  	// Apply the global identity
+ 	if(Kopete::Config::enableGlobalIdentity())
+  	{
++		// Disconnect to make sure it will not cause duplicate calls.
++		disconnect(myself(), SIGNAL(displayNameChanged(const QString&, const QString&)), this, SLOT(slotDisplayNameChanged()));
++		disconnect(myself(), SIGNAL(photoChanged()), this, SLOT(slotPhotoChanged()));
++
+ 		connect(myself(), SIGNAL(displayNameChanged(const QString&, const QString&)), this, SLOT(slotDisplayNameChanged()));
+ 		connect(myself(), SIGNAL(photoChanged()), this, SLOT(slotPhotoChanged()));
+ 
+@@ -317,43 +322,47 @@
+ 		slotDisplayNameChanged();
+ 		slotPhotoChanged();
+  	}
++	else
++	{
++		disconnect(myself(), SIGNAL(displayNameChanged(const QString&, const QString&)), this, SLOT(slotDisplayNameChanged()));
++		disconnect(myself(), SIGNAL(photoChanged()), this, SLOT(slotPhotoChanged()));
++	}
+ }
+ 
+ void ContactList::slotDisplayNameChanged()
+ {
++	static bool mutex=false;
++	if(mutex)
++	{
++		kdDebug (14010) << k_funcinfo << " mutex blocked" << endl ;
++		return;
++	}
++	mutex=true;
++
+ 	kdDebug( 14010 ) << k_funcinfo << myself()->displayName() << endl;
+ 
+ 	emit globalIdentityChanged(Kopete::Global::Properties::self()->nickName().key(), myself()->displayName());
++	mutex=false;
+ }
+ 
+ void ContactList::slotPhotoChanged()
+ {
+-	QString photoURL;
+-	
+-	MetaContact::PropertySource photoSource = myself()->photoSource();
+-	
+-	// Save the image to ~./kde/share/apps/kopete/global-photo.png if the source is not custom.
+-	if(photoSource != MetaContact::SourceCustom)
++	static bool mutex=false;
++	if(mutex)
+ 	{
+-		QImage globalPhoto = myself()->photo();
+-
+-		photoURL = "global-photo.png";
+-		photoURL = locateLocal("appdata", photoURL);
+-
+-		if(!globalPhoto.save(photoURL, "PNG"))
+-		{
+-				kdDebug( 14010 ) << k_funcinfo << "Error while saving the global photo to file." << endl;
+-				return;
+-		}
++		kdDebug (14010) << k_funcinfo << " mutex blocked" << endl ;
++		return;
+ 	}
+-	else
+-	{
+-		photoURL = myself()->customPhoto().path();
+-	}
++	mutex=true;
++	kdDebug( 14010 ) << k_funcinfo << myself()->picture().path() << endl;
+ 
+-	kdDebug( 14010 ) << k_funcinfo << photoURL << endl;
+-
+-	emit globalIdentityChanged(Kopete::Global::Properties::self()->photo().key(), photoURL);
++	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 
++	*/
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+--- kopete/libkopete/kopeteaccountmanager.cpp	(revision 568672)
++++ kopete/libkopete/kopeteaccountmanager.cpp	(revision 586398)
+@@ -31,9 +31,12 @@
+ #include "kopeteaway.h"
+ #include "kopeteprotocol.h"
+ #include "kopetecontact.h"
++#include "kopetecontactlist.h"
+ #include "kopetepluginmanager.h"
+ #include "kopeteonlinestatus.h"
+ #include "kopeteonlinestatusmanager.h"
++#include "kopetemetacontact.h"
++#include "kopetegroup.h"
+ 
+ namespace Kopete {
+ 
+@@ -48,7 +51,7 @@
+ 			{
+ 				uint priority1 = static_cast<Account*>(a)->priority();
+ 				uint priority2 = static_cast<Account*>(b)->priority();
+-	
++
+ 				if( a==b ) //two account are equal only if they are equal :-)
+ 					return 0;  // remember than an account can be only once on the list, but two account may have the same priority when loading
+ 				else if( priority1 > priority2 )
+@@ -114,7 +117,7 @@
+ 			if ( it.current()->isConnected() )
+ 				it.current()->setAway( false, awayReason );
+ 		}
+-		else 
++		else
+ 			if(!it.current()->excludeConnect())
+ 				it.current()->connect();
+ 	}
+@@ -153,7 +156,7 @@
+ {
+ 	OnlineStatusManager::Categories katgor=(OnlineStatusManager::Categories)category;
+ 	bool anyConnected = isAnyAccountConnected();
+-	
++
+ 	for ( QPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
+ 	{
+ 		Account *account = it.current();
+@@ -219,7 +222,7 @@
+ {
+ 	if( !account || d->accounts.contains( account ) )
+ 		return account;
+-		
++
+ 	if( account->accountId().isEmpty() )
+ 	{
+ 		account->deleteLater();
+@@ -236,9 +239,9 @@
+ 		}
+ 	}
+ 
+-	d->accounts.append( account );	
++	d->accounts.append( account );
+ 	d->accounts.sort();
+-	
++
+ 	// Connect to the account's status changed signal
+ 	connect(account->myself(), SIGNAL(onlineStatusChanged(Kopete::Contact *,
+ 			const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)),
+@@ -295,6 +298,27 @@
+ 
+ 	KConfigGroup *configgroup = account->configGroup();
+ 
++	// Clean up the contact list
++	QDictIterator<Kopete::Contact> it( account->contacts() );
++	for ( ; it.current(); ++it )
++	{
++		Contact* c = it.current();
++		MetaContact* mc = c->metaContact();
++		if ( mc == ContactList::self()->myself() )
++			continue;
++		mc->removeContact( c );
++		c->deleteLater();
++		if ( mc->contacts().count() == 0 ) //we can delete the metacontact
++		{
++			//get the first group and it's members
++			Group* group = mc->groups().first();
++			QPtrList<MetaContact> groupMembers = group->members();
++			ContactList::self()->removeMetaContact( mc );
++			if ( groupMembers.count() == 1 && groupMembers.findRef( mc ) != -1 )
++				ContactList::self()->removeGroup( group );
++		}
++	}
++
+ 	// Clean up the account list
+ 	d->accounts.remove( account );
+ 
+@@ -319,11 +343,11 @@
+ {
+ 	//kdDebug( 14010 ) << k_funcinfo << endl;
+ 	d->accounts.sort();
+-	
++
+ 	for ( QPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
+ 	{
+ 		KConfigBase *config = it.current()->configGroup();
+-	
++
+ 		config->writeEntry( "Protocol", it.current()->protocol()->pluginId() );
+ 		config->writeEntry( "AccountId", it.current()->accountId() );
+ 	}
+@@ -386,7 +410,7 @@
+ 
+ 		kdDebug( 14010 ) << k_funcinfo <<
+ 			"Creating account for '" << accountId << "'" << endl;
+-		
++
+ 		Account *account = 0L;
+ 		account = registerAccount( protocol->createNewAccount( accountId ) );
+ 		if ( !account )
+--- kopete/libkopete/kopeteglobal.cpp	(revision 568672)
++++ kopete/libkopete/kopeteglobal.cpp	(revision 586398)
+@@ -27,6 +27,8 @@
+ #include <kprogress.h>
+ #include <kstandarddirs.h>
+ #include <ktar.h>
++#include <kzip.h>
++#include <kmimetype.h>
+ 
+ 
+ namespace Kopete
+@@ -220,7 +222,7 @@
+ 	KArchiveEntry *currentEntry = 0L;
+ 	KArchiveDirectory* currentDir = 0L;
+ 	KProgressDialog *progressDlg = 0L;
+-	KTar *archive = 0L;
++	KArchive *archive = 0L;
+ 
+ 	QString localThemesDir(locateLocal("emoticons", QString::null) );
+ 
+@@ -238,8 +240,20 @@
+ 	progressDlg->show();
+ 	kapp->processEvents();
+ 
+-	archive = new KTar(archiveName);
+-	if ( !archive->open(IO_ReadOnly) )
++	QString currentBundleMimeType = KMimeType::findByPath(archiveName, 0, false)->name();
++	if( currentBundleMimeType == QString::fromLatin1("application/x-zip") )
++		archive = new KZip(archiveName);
++	else if( currentBundleMimeType == QString::fromLatin1("application/x-tgz") || 
++				currentBundleMimeType == QString::fromLatin1("application/x-tbz") ||
++				currentBundleMimeType == QString::fromLatin1("application/x-gzip") ||
++				currentBundleMimeType == QString::fromLatin1("application/x-bzip2") )
++		archive = new KTar(archiveName);
++	else if(archiveName.endsWith(QString::fromLatin1("jisp")) || archiveName.endsWith(QString::fromLatin1("zip")) )
++		archive = new KZip(archiveName);
++	else
++		archive = new KTar(archiveName);
++
++	if ( !archive || !archive->open(IO_ReadOnly) )
+ 	{
+ 		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
+ 			KMessageBox::Error,
+@@ -259,7 +273,8 @@
+ 		if (currentEntry->isDirectory())
+ 		{
+ 			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
+-			if (currentDir && (currentDir->entry(QString::fromLatin1("emoticons.xml")) != NULL))
++			if (currentDir && ( currentDir->entry(QString::fromLatin1("emoticons.xml")) != NULL ||
++						 		currentDir->entry(QString::fromLatin1("icondef.xml")) != NULL ) )
+ 				foundThemes.append(currentDir->name());
+ 		}
+ 	}
+@@ -312,8 +327,7 @@
+ 
+ 	// check if all steps were done, if there are skipped ones then we didn't
+ 	// succeed copying all dirs from the tarball
+-	if (progressDlg->progressBar()->totalSteps() !=
+-		progressDlg->progressBar()->progress())
++	if (progressDlg->progressBar()->totalSteps() > progressDlg->progressBar()->progress())
+ 	{
+ 		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
+ 			KMessageBox::Error,
+--- kopete/libkopete/kopetemetacontact.cpp	(revision 568672)
++++ kopete/libkopete/kopetemetacontact.cpp	(revision 586398)
+@@ -41,6 +41,7 @@
+ #include "kopeteglobal.h"
+ #include "kopeteprefs.h"
+ #include "kopeteuiglobal.h"
++#include "kopetepicture.h"
+ 
+ namespace Kopete {
+ 
+@@ -56,10 +57,13 @@
+ { public:
+ 	Private() :
+ 		photoSource(MetaContact::SourceCustom), displayNameSource(MetaContact::SourceCustom),
+-		displayNameSourceContact(0L),  photoSourceContact(0L), temporary(false), onlineStatus(Kopete::OnlineStatus::Offline),
+-		photoSyncedWithKABC(false)
++		displayNameSourceContact(0L),  photoSourceContact(0L), temporary(false),
++		onlineStatus(Kopete::OnlineStatus::Offline), photoSyncedWithKABC(false)
+ 	{}
+ 
++	~Private()
++	{}
++
+ 	QPtrList<Contact> contacts;
+ 
+ 	// property sources	
+@@ -89,7 +93,7 @@
+ 	QString photoSourcePID, photoSourceAID, photoSourceCID;
+ 
+ 	// The photo cache. Reduce disk access and CPU usage.
+-	QImage customPhotoCache, contactPhotoCache;
++	Picture customPicture, contactPicture, kabcPicture;
+ };
+ 
+ MetaContact::MetaContact()
+@@ -107,6 +111,8 @@
+ 	connect( this, SIGNAL( contactAdded( Kopete::Contact * ) ), SIGNAL( persistentDataChanged() ) );
+ 	connect( this, SIGNAL( contactRemoved( Kopete::Contact * ) ), SIGNAL( persistentDataChanged() ) );
+ 
++	// Update the KABC picture when the KDE Address book change.
++	connect(KABCPersistence::self()->addressBook(), SIGNAL(addressBookChanged(AddressBook *)), this, SLOT(slotUpdateAddressBookPicture()));
+ 
+ 	// make sure MetaContact is at least in one group
+ 	addToGroup( Group::topLevel() );
+@@ -319,7 +325,6 @@
+ 	d->photoSource = source;	
+ 	if ( source != oldSource )
+ 	{
+-		Message::clearImageCache();
+ 		emit photoChanged();
+ 	}
+ }
+@@ -672,39 +677,36 @@
+ void MetaContact::setPhoto( const KURL &url )
+ {
+ 	d->photoUrl = url;
+-	// Create the cache for the photo.
+-	d->customPhotoCache = photoFromCustom();
++	d->customPicture.setPicture(url.path());
+ 
+ 	if ( photoSource() == SourceCustom )
+ 	{
+-		Message::clearImageCache();
+ 		emit photoChanged();
+ 	}
+ }
+ 
+ QImage MetaContact::photo() const
+ {
++	return picture().image();
++}
++
++Picture &MetaContact::picture() const
++{
+ 	if ( photoSource() == SourceKABC )
+ 	{
+-		// kabc source, try to get from addressbook
+-		// if the metacontact has a kabc association
+-		if ( ! metaContactId().isEmpty() )
+-			return photoFromKABC(metaContactId());
++		return d->kabcPicture;
+ 	}
+ 	else if ( photoSource() == SourceContact )
+ 	{
+-		return d->contactPhotoCache;
++		return d->contactPicture;
+ 	}
+ 
+-	return d->customPhotoCache;
++	return d->customPicture;
+ }
+ 
+ QImage MetaContact::photoFromCustom() const
+ {
+-	if ( d->photoUrl.isEmpty() || !d->photoUrl.isValid() )
+-		return QImage();
+-
+-	return QImage(d->photoUrl.path());
++	return d->customPicture.image();
+ }
+ 
+ QImage photoFromContact( Kopete::Contact *contact) /*const*/
+@@ -784,11 +786,23 @@
+ 	
+ 	// Create a cache for the contact photo.
+ 	if(d->photoSourceContact != 0L)
+-		d->contactPhotoCache = photoFromContact(d->photoSourceContact);
++	{
++		QVariant photoProp;
++		if ( contact->hasProperty( Kopete::Global::Properties::self()->photo().key() ) )
++			photoProp = contact->property( Kopete::Global::Properties::self()->photo().key() ).value();
+ 
++		if(photoProp.canCast( QVariant::Image ))
++			d->contactPicture.setPicture(photoProp.toImage());
++		else if(photoProp.canCast( QVariant::Pixmap ))
++			d->contactPicture.setPicture(photoProp.toPixmap().convertToImage());
++		else if(!photoProp.asString().isEmpty())
++		{
++			d->contactPicture.setPicture(photoProp.toString());
++		}
++	}
++
+ 	if ( photoSource() == SourceContact )
+ 	{
+-		Message::clearImageCache();
+ 		emit photoChanged();
+ 	}
+ }
+@@ -831,11 +845,7 @@
+ 				if(d->photoSyncedWithKABC)
+ 					setPhotoSyncedWithKABC(true);
+ 					
+-				// Update the contact photo cache.
+-				d->contactPhotoCache = photoFromContact(subcontact);
+-
+-				Message::clearImageCache();
+-				emit photoChanged();
++				setPhotoSourceContact(subcontact);
+ 			}
+ 		}
+ 	}
+@@ -1024,7 +1034,11 @@
+ 
+ 	QString strContactId = element.attribute( QString::fromUtf8("contactId") );
+ 	if( !strContactId.isEmpty() )
++	{
+ 		d->metaContactId = strContactId;
++		// Set the KABC Picture
++		slotUpdateAddressBookPicture();
++	}
+ 
+ 	QDomElement contactElement = element.firstChild().toElement();
+ 	while( !contactElement.isNull() )
+@@ -1267,6 +1281,28 @@
+ 	setPhotoSourceContact( findContact( d->photoSourcePID, d->photoSourceAID, d->photoSourceCID) );
+ }
+ 
++void MetaContact::slotUpdateAddressBookPicture()
++{
++	KABC::AddressBook* ab = KABCPersistence::self()->addressBook();
++	QString id = metaContactId();
++	if ( !id.isEmpty() && !id.contains(':') )
++	{
++		KABC::Addressee theAddressee = ab->findByUid(id);
++		if ( theAddressee.isEmpty() )
++		{
++			kdDebug( 14010 ) << k_funcinfo << "no KABC::Addressee found for ( " << id << " ) " << " in current address book" << endl;
++		}
++		else
++		{
++			KABC::Picture pic = theAddressee.photo();
++			if ( pic.data().isNull() && pic.url().isEmpty() )
++				pic = theAddressee.logo();
++
++			d->kabcPicture.setPicture(pic);
++		}
++	}
++}
++
+ bool MetaContact::isTemporary() const
+ {
+ 	return d->temporary;
+@@ -1345,8 +1381,8 @@
+ 			}
+ 			case SourceCustom:
+ 			{
+-				if( !d->photoUrl.isEmpty() )
+-					newValue = d->photoUrl.url();
++				if( !d->customPicture.isNull() )
++					newValue = d->customPicture.path();
+ 				break;
+ 			}
+ 			// Don't sync the photo with KABC if the source is KABC !
+--- kopete/libkopete/kopetepicture.cpp	(revision 0)
++++ kopete/libkopete/kopetepicture.cpp	(revision 586398)
+@@ -0,0 +1,197 @@
++/*
++    kopetepicture.cpp - Kopete Picture
++
++    Copyright (c) 2005      by Michaël Larouche       <michael.larouche at kdemail.net>
++
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++#include "kopetepicture.h"
++
++#include <qbuffer.h>
++
++#include <kabc/picture.h>
++
++#include <kmdcodec.h>
++#include <kstandarddirs.h>
++#include <kdebug.h>
++
++namespace Kopete
++{
++
++class Picture::Private : public KShared
++{
++public:
++	Private()
++	{}
++
++	QString pictureBase64;
++	QImage pictureImage;
++	QString picturePath;
++};
++
++Picture::Picture()
++ : d(new Private)
++{
++}
++
++Picture::Picture(const QString &path)
++ : d(new Private)
++{
++	setPicture(path);
++}
++
++Picture::Picture(const QImage &image)
++ : d(new Private)
++{
++	setPicture(image);
++}
++
++Picture::Picture(const KABC::Picture &picture)
++ : d(new Private)
++{
++	setPicture(picture);
++}
++
++Picture::Picture(const Picture &other)
++ : d(other.d)
++{}
++
++Picture::~Picture()
++{}
++
++Picture &Picture::operator=(const Picture &other)
++{
++	d = other.d;
++	return *this;
++}
++
++QImage Picture::image()
++{
++	// Do the conversion if only needed.
++	// If the image is null, the path is not empty then.
++	if( d->pictureImage.isNull() )
++	{
++		d->pictureImage = QImage(d->picturePath);
++	}
++
++	return d->pictureImage;
++}
++
++QString Picture::base64()
++{
++	if( d->pictureBase64.isEmpty() )
++	{
++		// Generate base64 cache for the picture.
++		QByteArray tempArray;
++		QBuffer tempBuffer( tempArray );
++		tempBuffer.open( IO_WriteOnly );
++		// Make sure it create a image cache.
++		if( image().save( &tempBuffer, "PNG" ) )
++		{
++			d->pictureBase64 = KCodecs::base64Encode(tempArray);
++		}
++	}
++
++	return d->pictureBase64;
++}
++
++QString Picture::path()
++{
++	if( d->picturePath.isEmpty() )
++	{
++		// For a image source, finding a filename is tricky.
++		// I decided to use MD5 Hash as the filename.
++		QString localPhotoPath;
++		
++		// Generate MD5 Hash for the image.
++		QByteArray tempArray;
++		QBuffer tempBuffer(tempArray);
++		tempBuffer.open( IO_WriteOnly );
++		image().save(&tempBuffer, "PNG");
++		KMD5 context(tempArray);
++		// Save the image to a file.
++		localPhotoPath = context.hexDigest() + ".png";
++		localPhotoPath = locateLocal( "appdata", QString::fromUtf8("metacontactpicturecache/%1").arg( localPhotoPath) );
++		if( image().save(localPhotoPath, "PNG") )
++		{
++			d->picturePath = localPhotoPath;
++		}
++	}
++
++	return d->picturePath;
++}
++
++bool Picture::isNull()
++{
++	if( d->pictureBase64.isEmpty() && d->picturePath.isEmpty() && d->pictureImage.isNull() )
++	{
++		return true;
++	}
++	else
++	{
++		return false;
++	}
++}
++
++void Picture::clear()
++{
++	detach();
++	d->pictureBase64 = QString::null;
++	d->picturePath = QString::null;
++	d->pictureImage = QImage();
++}
++
++void Picture::setPicture(const QImage &image)
++{
++	detach();
++
++	d->pictureImage = image;
++
++	// Clear the path and base64, it will call the update of then when "getted"
++	d->picturePath= QString::null;
++	d->pictureBase64 = QString::null;
++}
++
++void Picture::setPicture(const QString &path)
++{
++	detach();
++	d->picturePath = path;
++	
++	// Clear the image and base64, it will call the update of then when "getted"
++	d->pictureImage = QImage();
++	d->pictureBase64 = QString::null;
++}
++
++void Picture::setPicture(const KABC::Picture &picture)
++{
++	// No need to call detach() here because setPicture will do it.
++	if ( picture.isIntern())
++	{
++		setPicture( picture.data() );
++	}
++	else
++	{
++		setPicture( picture.url() );
++	}
++}
++
++void Picture::detach()
++{
++	// there is no detach in KSharedPtr.
++	if( d.count() == 1 )
++		return;
++
++	// Warning: this only works as long as the private object doesn't contain pointers to allocated objects.
++	d = new Private(*d);
++}
++
++} // END namespace Kopete
+--- kopete/libkopete/kopetecommandhandler.cpp	(revision 568672)
++++ kopete/libkopete/kopetecommandhandler.cpp	(revision 586398)
+@@ -202,7 +202,7 @@
+ 	}
+ 	else
+ 		return false;
+-
++	
+ 	CommandList mCommands = commands( manager->protocol() );
+ 	Kopete::Command *c = mCommands[ command ];
+ 	if(c)
+--- kopete/libkopete/private/kopeteprefs.cpp	(revision 568672)
++++ kopete/libkopete/private/kopeteprefs.cpp	(revision 586398)
+@@ -1,692 +0,0 @@
+-/*
+-    kopeteprefs.cpp - Kopete Preferences Container-Class
+-
+-    Copyright (c) 2002      by Stefan Gehn            <metz AT gehn.net>
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#include "kopeteprefs.h"
+-
+-#include <qfile.h>
+-#include <qfont.h>
+-#include <qmetaobject.h>
+-
+-#include <kapplication.h>
+-#include <kglobalsettings.h>
+-#include <kconfig.h>
+-#include <kdebug.h>
+-#include <kstandarddirs.h>
+-
+-#define KOPETE_DEFAULT_CHATSTYLE  "Kopete"
+-
+-KopetePrefs *KopetePrefs::s_prefs = 0L;
+-
+-KopetePrefs *KopetePrefs::prefs()
+-{
+-	if( !s_prefs )
+-		s_prefs = new KopetePrefs;
+-	return s_prefs;
+-}
+-
+-KopetePrefs::KopetePrefs() : QObject( kapp, "KopetePrefs" )
+-{
+-	config = KGlobal::config();
+-	load();
+-}
+-
+-void KopetePrefs::load()
+-{
+-//	kdDebug( 14010 ) << k_funcinfo << endl;
+-	config->setGroup("Appearance");
+-
+-	mIconTheme = config->readEntry("EmoticonTheme", defaultTheme());
+-	mUseEmoticons = config->readBoolEntry("Use Emoticons", true);
+-	mEmoticonsRequireSpaces = config->readBoolEntry("EmoticonsRequireSpaces" , true );
+-	mShowOffline = config->readBoolEntry("ShowOfflineUsers", true);
+-	mShowEmptyGroups = config->readBoolEntry("ShowEmptyGroups", true);
+-	mGreyIdle = config->readBoolEntry("GreyIdleMetaContacts", true);
+-	mSortByGroup = config->readBoolEntry("SortByGroup" , true);
+-	mTreeView = config->readBoolEntry("TreeView", true);
+-	mStartDocked = config->readBoolEntry("StartDocked", false);
+-	mUseQueue = config->readBoolEntry("Use Queue", true);
+-	mRaiseMsgWindow = config->readBoolEntry("Raise Msg Window", false);
+-	mShowEvents = config->readBoolEntry("Show Events in Chat Window", true);
+-	mSpellCheck = config->readBoolEntry("SpellCheck", true);
+-	mQueueUnreadMessages = config->readBoolEntry("Queue Unread Messages", false);
+-	mQueueOnlyHighlightedMessagesInGroupChats = config->readBoolEntry("Queue Only Highlighted Messages In Group Chats", false);
+-	mQueueOnlyMessagesOnAnotherDesktop = config->readBoolEntry("Queue Only Messages On Another Desktop", false);
+-	mBalloonNotify = config->readBoolEntry("Balloon Notification", true);
+-	mBalloonNotifyIgnoreClosesChatView = config->readBoolEntry("Balloon Notification Ignore Closes Chat View", false);
+-	mTrayflashNotify = config->readBoolEntry("Trayflash Notification", true);
+-	mTrayflashNotifyLeftClickOpensMessage = config->readBoolEntry("Trayflash Notification Left Click Opens Message", true);
+-	mTrayflashNotifySetCurrentDesktopToChatView = config->readBoolEntry("Trayflash Notification Set Current Desktop To Chat View", false);
+-	mSoundIfAway = config->readBoolEntry("Sound Notification If Away", true);
+-	mChatWindowPolicy = config->readNumEntry("Chatwindow Policy", 0);
+-	mTransparencyEnabled = config->readBoolEntry("ChatView Transparency Enabled", false);
+-	mTransparencyValue = config->readNumEntry("ChatView Transparency Value", 50);
+-	mRichText = config->readBoolEntry("RichText editor", false);
+-	mChatWShowSend = config->readBoolEntry("Show Chatwindow Send Button", true);
+-	mRememberedMessages = config->readNumEntry("Remembered Messages", 5);
+-	mTruncateContactNames = config->readBoolEntry("TruncateContactNames", false);
+-	mMaxContactNameLength = config->readNumEntry("MaxContactNameLength", 20);
+-
+-	mTransparencyColor = config->readColorEntry("ChatView Transparency Tint Color", &Qt::white);
+-	mChatViewBufferSize = config->readNumEntry("ChatView BufferSize", 250);
+-
+-	QColor tmpColor = KGlobalSettings::highlightColor();
+-	mHighlightBackground = config->readColorEntry("Highlight Background Color", &tmpColor);
+-	tmpColor = KGlobalSettings::highlightedTextColor();
+-	mHighlightForeground = config->readColorEntry("Highlight Foreground Color", &tmpColor);
+-	mHighlightEnabled = config->readBoolEntry("Highlighting Enabled", true);
+-	mBgOverride = config->readBoolEntry("ChatView Override Background", false);
+-	mFgOverride = config->readBoolEntry("ChatView Override Foreground", false);
+-	mRtfOverride = config->readBoolEntry("ChatView Override RTF", false);
+-	mInterfacePreference = config->readEntry("View Plugin", QString::fromLatin1("kopete_chatwindow") );
+-	tmpColor = KGlobalSettings::textColor();
+-	mTextColor = config->readColorEntry("Text Color", &tmpColor );
+-	tmpColor = KGlobalSettings::baseColor();
+-	mBgColor = config->readColorEntry("Bg Color", &tmpColor );
+-	tmpColor = KGlobalSettings::linkColor();
+-	mLinkColor = config->readColorEntry("Link Color", &tmpColor );
+-	mFontFace = config->readFontEntry("Font Face");
+-	tmpColor = darkGray;
+-	mIdleContactColor = config->readColorEntry("Idle Contact Color", &tmpColor);
+-
+-	mShowTray = config->readBoolEntry("Show Systemtray", true);
+-
+-	/*
+-	The stylesheet config value is now just the basename of the xsl file ie: Messenger, Kopete.
+-	To avoid having duplicated fallback code, I used the extract method refactoring and left all in
+-	_setStyleSheet.
+-	*/
+-	_setStyleSheet(config->readEntry("Stylesheet", QString::fromLatin1(KOPETE_DEFAULT_CHATSTYLE)));
+-
+-	mToolTipContents = config->readListEntry("ToolTipContents");
+-	if(mToolTipContents.empty())
+-	{
+-		mToolTipContents
+-			<< QString::fromLatin1("FormattedName")
+-			<< QString::fromLatin1("userInfo")
+-			<< QString::fromLatin1("server")
+-			<< QString::fromLatin1("channels")
+-			<< QString::fromLatin1("FormattedIdleTime")
+-			<< QString::fromLatin1("channelMembers")
+-			<< QString::fromLatin1("channelTopic")
+-			<< QString::fromLatin1("emailAddress")
+-			<< QString::fromLatin1("homePage")
+-			<< QString::fromLatin1("onlineSince")
+-			<< QString::fromLatin1("lastOnline")
+-			<< QString::fromLatin1("awayMessage");
+-	}
+-
+-	config->setGroup("ContactList");
+-	int n = metaObject()->findProperty( "contactListDisplayMode" );
+-	QString value = config->readEntry("DisplayMode",QString::fromLatin1("Default"));
+-	mContactListDisplayMode = (ContactDisplayMode)metaObject()->property( n )->keyToValue( value.latin1() );
+-	n = metaObject()->findProperty( "contactListIconMode" );
+-	value = config->readEntry("IconMode",
+-                                  QString::fromLatin1("IconDefault"));
+-	mContactListIconMode = (IconDisplayMode) metaObject()->property( n )->keyToValue( value.latin1() );
+-	mContactListIndentContacts = config->readBoolEntry("IndentContacts", false);
+-	mContactListHideVerticalScrollBar = config->readBoolEntry("HideVerticalScrollBar", false );
+-	mContactListUseCustomFonts = config->readBoolEntry("UseCustomFonts", false);
+-	QFont font = KGlobalSettings::generalFont();
+-	mContactListNormalFont = config->readFontEntry("NormalFont", &font);
+-	if ( font.pixelSize() != -1 )
+-		font.setPixelSize( (font.pixelSize() * 3) / 4 );
+-	else
+-		font.setPointSizeFloat( font.pointSizeFloat() * 0.75 );
+-	mContactListSmallFont = config->readFontEntry("SmallFont", &font);
+-	mContactListGroupNameColor = config->readColorEntry("GroupNameColor", &darkRed);
+-	mContactListAnimation = config->readBoolEntry("AnimateChanges", true);
+-	mContactListFading = config->readBoolEntry("FadeItems", true);
+-	mContactListFolding = config->readBoolEntry("FoldItems", true);
+-	mContactListMouseNavigation = config->readBoolEntry("MouseNavigation", false );
+-	mContactListAutoHide = config->readBoolEntry("AutoHide", false);
+-	mContactListAutoHideVScroll = config->readBoolEntry("AutoHideVScroll", true );
+-	mContactListAutoHideTimeout = config->readUnsignedNumEntry("AutoHideTimeout", 30);
+-
+-	// Load the reconnection setting
+-	config->setGroup("General");
+-	mReconnectOnDisconnect = config->readBoolEntry("ReconnectOnDisconnect", true);
+-	mAutoConnect = config->readBoolEntry("AutoConnect", false);
+-
+-	// Nothing has changed yet
+-	mWindowAppearanceChanged = false;
+-	mTransparencyChanged = false;
+-	mContactListAppearanceChanged = false;
+-	mMessageAppearanceChanged = false;
+-}
+-
+-void KopetePrefs::save()
+-{
+-//	kdDebug(14010) << "KopetePrefs::save()" << endl;
+-	config->setGroup("Appearance");
+-
+-	config->writeEntry("EmoticonTheme", mIconTheme);
+-	config->writeEntry("Use Emoticons", mUseEmoticons);
+-	config->writeEntry("EmoticonsRequireSpaces", mEmoticonsRequireSpaces);
+-	config->writeEntry("ShowOfflineUsers", mShowOffline);
+-	config->writeEntry("ShowEmptyGroups", mShowEmptyGroups);
+-	config->writeEntry("GreyIdleMetaContacts", mGreyIdle);
+-	config->writeEntry("TreeView", mTreeView);
+-	config->writeEntry("SortByGroup", mSortByGroup);
+-	config->writeEntry("StartDocked", mStartDocked);
+-	config->writeEntry("Use Queue", mUseQueue);
+-	config->writeEntry("Raise Msg Window", mRaiseMsgWindow);
+-	config->writeEntry("Show Events in Chat Window", mShowEvents);
+-	config->writeEntry("SpellCheck", mSpellCheck);
+-	config->writeEntry("Queue Unread Messages", mQueueUnreadMessages);
+-	config->writeEntry("Queue Only Highlighted Messages In Group Chats", mQueueOnlyHighlightedMessagesInGroupChats);
+-	config->writeEntry("Queue Only Messages On Another Desktop", mQueueOnlyMessagesOnAnotherDesktop);
+-	config->writeEntry("Balloon Notification", mBalloonNotify);
+-	config->writeEntry("Balloon Notification Ignore Closes Chat View", mBalloonNotifyIgnoreClosesChatView);
+-	config->writeEntry("Trayflash Notification", mTrayflashNotify);
+-	config->writeEntry("Trayflash Notification Left Click Opens Message", mTrayflashNotifyLeftClickOpensMessage);
+-	config->writeEntry("Trayflash Notification Set Current Desktop To Chat View", mTrayflashNotifySetCurrentDesktopToChatView);
+-	config->writeEntry("Sound Notification If Away", mSoundIfAway);
+-	config->writeEntry("Chatwindow Policy", mChatWindowPolicy);
+-	config->writeEntry("ChatView Transparency Enabled", mTransparencyEnabled);
+-	config->writeEntry("ChatView Transparency Value", mTransparencyValue);
+-	config->writeEntry("ChatView Transparency Tint Color", mTransparencyColor);
+-	config->writeEntry("ChatView Override Background", mBgOverride);
+-	config->writeEntry("ChatView Override Foreground", mFgOverride);
+-	config->writeEntry("ChatView Override RTF", mRtfOverride);
+-	config->writeEntry("ChatView BufferSize", mChatViewBufferSize);
+-	config->writeEntry("Highlight Background Color", mHighlightBackground);
+-	config->writeEntry("Highlight Foreground Color", mHighlightForeground);
+-	config->writeEntry("Highlighting Enabled", mHighlightEnabled );
+-	config->writeEntry("Font Face", mFontFace);
+-	config->writeEntry("Text Color",mTextColor);
+-	config->writeEntry("Remembered Messages",mRememberedMessages);
+-	config->writeEntry("Bg Color", mBgColor);
+-	config->writeEntry("Link Color", mLinkColor);
+-	config->writeEntry("Idle Contact Color", mIdleContactColor);
+-	config->writeEntry("RichText editor", mRichText);
+-	config->writeEntry("Show Chatwindow Send Button", mChatWShowSend);
+-	config->writeEntry("TruncateContactNames", mTruncateContactNames);
+-	config->writeEntry("MaxContactNameLength", mMaxContactNameLength);
+-
+-	config->writeEntry("View Plugin", mInterfacePreference);
+-
+-	config->writeEntry("Show Systemtray", mShowTray);
+-	config->writeEntry("Stylesheet", mStyleSheet);
+-
+-	config->writeEntry("ToolTipContents", mToolTipContents);
+-
+-	config->setGroup("ContactList");
+-	int n = metaObject()->findProperty( "contactListDisplayMode" );
+-	config->writeEntry("DisplayMode", metaObject()->property( n )->valueToKey( mContactListDisplayMode ));
+-	n = metaObject()->findProperty( "contactListIconMode" );
+-	config->writeEntry("IconMode", metaObject()->property( n )->valueToKey( mContactListIconMode ));
+-	config->writeEntry("IndentContacts", mContactListIndentContacts);
+-	config->writeEntry("HideVerticalScrollBar", mContactListHideVerticalScrollBar );
+-	config->writeEntry("UseCustomFonts", mContactListUseCustomFonts);
+-	config->writeEntry("NormalFont", mContactListNormalFont);
+-	config->writeEntry("SmallFont", mContactListSmallFont);
+-	config->writeEntry("GroupNameColor", mContactListGroupNameColor);
+-	config->writeEntry("AnimateChanges", mContactListAnimation);
+-	config->writeEntry("FadeItems", mContactListFading);
+-	config->writeEntry("FoldItems", mContactListFolding);
+-	config->writeEntry("MouseNavigation", mContactListMouseNavigation );
+-	config->writeEntry("AutoHide", mContactListAutoHide);
+-	config->writeEntry("AutoHideVScroll", mContactListAutoHideVScroll );
+-	config->writeEntry("AutoHideTimeout", mContactListAutoHideTimeout);
+-
+-	//Save the reconnection setting
+-	config->setGroup("General");
+-	config->writeEntry("ReconnectOnDisconnect", mReconnectOnDisconnect);
+-	config->writeEntry("AutoConnect", mAutoConnect);
+-
+-	config->sync();
+-	emit saved();
+-
+-	if(mTransparencyChanged)
+-		emit transparencyChanged();
+-
+-	if(mWindowAppearanceChanged)
+-		emit windowAppearanceChanged();
+-
+-	if(mContactListAppearanceChanged)
+-		emit contactListAppearanceChanged();
+-
+-	if(mMessageAppearanceChanged)
+-		emit messageAppearanceChanged();
+-
+-	// Clear all *Changed flags. This will cause breakage if someone makes some
+-	// changes but doesn't save them in a slot connected to a *Changed signal.
+-	mWindowAppearanceChanged = false;
+-	mTransparencyChanged = false;
+-	mContactListAppearanceChanged = false;
+-	mMessageAppearanceChanged = false;
+-}
+-
+-void KopetePrefs::setIconTheme(const QString &value)
+-{
+-	if( mIconTheme != value )
+-	{
+-		mMessageAppearanceChanged = true;
+-		mContactListAppearanceChanged = true;
+-	}
+-	mIconTheme = value;
+-}
+-
+-void KopetePrefs::setUseEmoticons(bool value)
+-{
+-	if( mUseEmoticons != value )
+-	{
+-		 mMessageAppearanceChanged = true;
+-		 mContactListAppearanceChanged = true;
+-	}
+-	mUseEmoticons = value;
+-}
+-
+-void KopetePrefs::setShowOffline(bool value)
+-{
+-	if( value != mShowOffline ) mContactListAppearanceChanged = true;
+-	mShowOffline = value;
+-}
+-
+-void KopetePrefs::setShowEmptyGroups(bool value)
+-{
+-	if( value != mShowEmptyGroups ) mContactListAppearanceChanged = true;
+-	mShowEmptyGroups = value;
+-}
+-
+-void KopetePrefs::setTreeView(bool value)
+-{
+-	if( value != mTreeView ) mContactListAppearanceChanged = true;
+-	mTreeView = value;
+-}
+-
+-void KopetePrefs::setSortByGroup(bool value)
+-{
+-	if( value != mSortByGroup ) mContactListAppearanceChanged = true;
+-	mSortByGroup = value;
+-}
+-
+-void KopetePrefs::setGreyIdleMetaContacts(bool value)
+-{
+-	if( value != mGreyIdle ) mContactListAppearanceChanged = true;
+-	mGreyIdle = value;
+-}
+-
+-void KopetePrefs::setStartDocked(bool value)
+-{
+-	mStartDocked = value;
+-}
+-
+-void KopetePrefs::setUseQueue(bool value)
+-{
+-	mUseQueue = value;
+-}
+-
+-
+-void KopetePrefs::setRaiseMsgWindow(bool value)
+-{
+-	mRaiseMsgWindow = value;
+-}
+-
+-void KopetePrefs::setRememberedMessages(int value)
+-{
+-	mRememberedMessages = value;
+-}
+-
+-void KopetePrefs::setShowEvents(bool value)
+-{
+-	mShowEvents = value;
+-}
+-
+-void KopetePrefs::setTrayflashNotify(bool value)
+-{
+-	mTrayflashNotify = value;
+-}
+-
+-void KopetePrefs::setSpellCheck(bool value)
+-{
+-	mSpellCheck = value;
+-}
+-
+-void KopetePrefs::setQueueUnreadMessages(bool value)
+-{
+-	mQueueUnreadMessages = value;
+-}
+-
+-void KopetePrefs::setQueueOnlyHighlightedMessagesInGroupChats(bool value)
+-{
+-	mQueueOnlyHighlightedMessagesInGroupChats = value;
+-}
+-
+-void KopetePrefs::setQueueOnlyMessagesOnAnotherDesktop(bool value)
+-{
+-	mQueueOnlyMessagesOnAnotherDesktop = value;
+-}
+-
+-void KopetePrefs::setTrayflashNotifyLeftClickOpensMessage(bool value)
+-{
+-	mTrayflashNotifyLeftClickOpensMessage = value;
+-}
+-
+-void KopetePrefs::setTrayflashNotifySetCurrentDesktopToChatView(bool value)
+-{
+-	mTrayflashNotifySetCurrentDesktopToChatView = value;
+-}
+-
+-void KopetePrefs::setBalloonNotify(bool value)
+-{
+-	mBalloonNotify = value;
+-}
+-
+-void KopetePrefs::setBalloonNotifyIgnoreClosesChatView(bool value)
+-{
+-	mBalloonNotifyIgnoreClosesChatView = value;
+-}
+-
+-void KopetePrefs::setSoundIfAway(bool value)
+-{
+-	mSoundIfAway = value;
+-}
+-
+-void KopetePrefs::setStyleSheet(const QString &value)
+-{
+-	if( mStyleSheet != value ) mMessageAppearanceChanged = true;
+-	_setStyleSheet(value);
+-}
+-
+-void KopetePrefs::_setStyleSheet(const QString &value)
+-{
+-	QString styleFileName  = locate( "appdata", QString::fromLatin1("styles/") + value + QString::fromLatin1(".xsl"));
+-
+-	/* In case the user had selected a style not available now */
+-	if ( !QFile::exists(styleFileName) || value.isEmpty() )
+-	{
+-		/* Try to fallback to default style */
+-		mStyleSheet = QString::fromLatin1(KOPETE_DEFAULT_CHATSTYLE);
+-		// FIXME: Duncan: we could check here if Kopete XSL exists too and show a msgbox about a broken install in case it is not found
+-	}
+-	else
+-	{
+-		mStyleSheet = value;
+-	}
+-	
+-	styleFileName = locate( "appdata", QString::fromLatin1("styles/") + mStyleSheet + QString::fromLatin1(".xsl"));
+-
+-	/* We must find the path of style data to replace $appdata by correct value in xsl that Kopete XSLT doesn't processing well (and impossible to fix without changing lots of things).  */
+-	mStyleDataPath = styleFileName;
+-	mStyleDataPath.replace(mStyleSheet + QString::fromLatin1(".xsl"),QString::fromLatin1("data/"));
+-
+-	mStyleContents = fileContents(styleFileName);
+-
+-}
+-
+-void KopetePrefs::setFontFace( const QFont &value )
+-{
+-	if( value != mFontFace ) mWindowAppearanceChanged = true;
+-	mFontFace = value;
+-}
+-
+-void KopetePrefs::setTextColor( const QColor &value )
+-{
+-	if( value != mTextColor ) mWindowAppearanceChanged = true;
+-	mTextColor = value;
+-}
+-
+-void KopetePrefs::setBgColor( const QColor &value )
+-{
+-	if( value != mBgColor ) mWindowAppearanceChanged = true;
+-	mBgColor = value;
+-}
+-
+-void KopetePrefs::setLinkColor( const QColor &value )
+-{
+-	if( value != mLinkColor ) mWindowAppearanceChanged = true;
+-	mLinkColor = value;
+-}
+-
+-void KopetePrefs::setChatWindowPolicy(int value)
+-{
+-	mChatWindowPolicy = value;
+-}
+-
+-void KopetePrefs::setTruncateContactNames( bool value )
+-{
+-	mTruncateContactNames = value;
+-}
+-
+-void KopetePrefs::setMaxContactNameLength( int value )
+-{
+-	mMaxContactNameLength = value;
+-}
+-
+-void KopetePrefs::setInterfacePreference(const QString &value)
+-{
+-	mInterfacePreference = value;
+-}
+-
+-void KopetePrefs::setTransparencyEnabled(bool value)
+-{
+-	if( value != mTransparencyEnabled ) mTransparencyChanged = true;
+-	mTransparencyEnabled = value;
+-}
+-
+-void KopetePrefs::setTransparencyColor(const QColor &value)
+-{
+-	if( value != mTransparencyColor ) mTransparencyChanged = true;
+-	mTransparencyColor = value;
+-}
+-
+-void KopetePrefs::setChatViewBufferSize( int value )
+-{
+-	mChatViewBufferSize = value;
+-}
+-
+-void KopetePrefs::setHighlightBackground(const QColor &value)
+-{
+-	if( value != mHighlightBackground ) mWindowAppearanceChanged = true;
+-	mHighlightBackground = value;
+-}
+-
+-void KopetePrefs::setHighlightForeground(const QColor &value)
+-{
+-	if( value != mHighlightForeground ) mWindowAppearanceChanged = true;
+-	mHighlightForeground = value;
+-}
+-
+-void KopetePrefs::setHighlightEnabled(bool value)
+-{
+-	if( value != mHighlightEnabled ) mWindowAppearanceChanged = true;
+-	mHighlightEnabled = value;
+-}
+-
+-void KopetePrefs::setTransparencyValue(int value)
+-{
+-	if( value != mTransparencyValue ) mTransparencyChanged = true;
+-	mTransparencyValue = value;
+-}
+-
+-void KopetePrefs::setBgOverride(bool value)
+-{
+-	if( value != mBgOverride ) mMessageAppearanceChanged = true;
+-	mBgOverride = value;
+-}
+-
+-void KopetePrefs::setFgOverride(bool value)
+-{
+-	if( value != mFgOverride ) mMessageAppearanceChanged = true;
+-	mFgOverride = value;
+-}
+-
+-void KopetePrefs::setRtfOverride(bool value)
+-{
+-	if( value != mRtfOverride ) mMessageAppearanceChanged = true;
+-	mRtfOverride = value;
+-}
+-
+-void KopetePrefs::setShowTray(bool value)
+-{
+-	mShowTray = value;
+-}
+-
+-
+-QString KopetePrefs::fileContents(const QString &path)
+-{
+- 	QString contents;
+-	QFile file( path );
+-	if ( file.open( IO_ReadOnly ) )
+-	{
+-		QTextStream stream( &file );
+-		contents = stream.read();
+-		file.close();
+-	}
+-	return contents;
+-}
+-
+-void KopetePrefs::setIdleContactColor(const QColor &value)
+-{
+-	if( value != mIdleContactColor ) mContactListAppearanceChanged = true;
+-	mIdleContactColor = value;
+-}
+-
+-void KopetePrefs::setRichText(bool value)
+-{
+-	mRichText=value;
+-}
+-
+-void KopetePrefs::setToolTipContents(const QStringList &value)
+-{
+-	mToolTipContents=value;
+-}
+-
+-void KopetePrefs::setContactListIndentContacts( bool v )
+-{
+-	if( v != mContactListIndentContacts ) mContactListAppearanceChanged = true;
+-	mContactListIndentContacts = v;
+-}
+-
+-void KopetePrefs::setContactListHideVerticalScrollBar( bool v )
+-{
+-	if( v != mContactListHideVerticalScrollBar ) mContactListAppearanceChanged = true;
+-	mContactListHideVerticalScrollBar = v;
+-}
+-
+-void KopetePrefs::setContactListDisplayMode( ContactDisplayMode v )
+-{
+-	if( v != mContactListDisplayMode ) mContactListAppearanceChanged = true;
+-	mContactListDisplayMode = v;
+-}
+-
+-void KopetePrefs::setContactListIconMode( IconDisplayMode v )
+-{
+-	if( v != mContactListIconMode ) mContactListAppearanceChanged = true;
+-	mContactListIconMode = v;
+-}
+-
+-void KopetePrefs::setContactListUseCustomFonts( bool v )
+-{
+-	if( v != mContactListUseCustomFonts ) mContactListAppearanceChanged = true;
+-	mContactListUseCustomFonts = v;
+-}
+-
+-void KopetePrefs::setContactListCustomNormalFont( const QFont & v )
+-{
+-	if( v != mContactListNormalFont ) mContactListAppearanceChanged = true;
+-	mContactListNormalFont = v;
+-}
+-
+-void KopetePrefs::setContactListCustomSmallFont( const QFont & v )
+-{
+-	if( v != mContactListSmallFont ) mContactListAppearanceChanged = true;
+-	mContactListSmallFont = v;
+-}
+-
+-QFont KopetePrefs::contactListSmallFont() const
+-{
+-	if ( mContactListUseCustomFonts )
+-		return contactListCustomSmallFont();
+-	QFont smallFont = KGlobalSettings::generalFont();
+-	if ( smallFont.pixelSize() != -1 )
+-		smallFont.setPixelSize( (smallFont.pixelSize() * 3) / 4 );
+-	else
+-		smallFont.setPointSizeFloat( smallFont.pointSizeFloat() * 0.75 );
+-	return smallFont;
+-}
+-
+-void KopetePrefs::setContactListGroupNameColor( const QColor & v )
+-{
+-	if( v != mContactListGroupNameColor ) mContactListAppearanceChanged = true;
+-	mContactListGroupNameColor = v;
+-}
+-
+-void KopetePrefs::setContactListAnimation( bool n )
+-{
+-	if( n != mContactListAnimation ) mContactListAppearanceChanged = true;
+-	mContactListAnimation = n;
+-}
+-
+-void KopetePrefs::setContactListFading( bool n )
+-{
+-	if( n != mContactListFading ) mContactListAppearanceChanged = true;
+-	mContactListFading = n;
+-}
+-
+-void KopetePrefs::setContactListFolding( bool n )
+-{
+-	if( n != mContactListFolding ) mContactListAppearanceChanged = true;
+-	mContactListFolding = n;
+-}
+-
+-void KopetePrefs::setContactListMouseNavigation( bool n )
+-{
+-	if( n != mContactListMouseNavigation ) mContactListAppearanceChanged = true;
+-	mContactListMouseNavigation = n;
+-}
+-
+-void KopetePrefs::setContactListAutoHide( bool n )
+-{
+-	if( n != mContactListAutoHide ) mContactListAppearanceChanged = true;
+-	mContactListAutoHide = n;
+-}
+-
+-void KopetePrefs::setContactListAutoHideVScroll( bool n )
+-{
+-	if( n != mContactListAutoHideVScroll ) mContactListAppearanceChanged = true;
+-	mContactListAutoHideVScroll = n;
+-}
+-
+-void KopetePrefs::setContactListAutoHideTimeout( unsigned int n )
+-{
+-	if( n != mContactListAutoHideTimeout ) mContactListAppearanceChanged = true;
+-	mContactListAutoHideTimeout = n;
+-}
+-
+-void KopetePrefs::setReconnectOnDisconnect( bool newSetting )
+-{
+-	mReconnectOnDisconnect = newSetting;
+-}
+-
+-void KopetePrefs::setAutoConnect(bool b)
+-{
+-	mAutoConnect=b;
+-}
+-
+-void KopetePrefs::setEmoticonsRequireSpaces( bool b )
+-{
+-	if( mEmoticonsRequireSpaces != b )
+-	{
+-		 mMessageAppearanceChanged = true;
+-		 mContactListAppearanceChanged = true;
+-	}
+-	mEmoticonsRequireSpaces=b;
+-}
+-
+-#include "kopeteprefs.moc"
+-// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/libkopete/private/kopeteprefs.h	(revision 568672)
++++ kopete/libkopete/private/kopeteprefs.h	(revision 586398)
+@@ -1,309 +0,0 @@
+-/*
+-    kopeteprefs.cpp - Kopete Preferences Container-Class
+-
+-    Copyright (c) 2002      by Stefan Gehn            <metz AT gehn.net>
+-    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel at kde.org>
+-
+-    *************************************************************************
+-    *                                                                       *
+-    * This library is free software; you can redistribute it and/or         *
+-    * modify it under the terms of the GNU Lesser General Public            *
+-    * License as published by the Free Software Foundation; either          *
+-    * version 2 of the License, or (at your option) any later version.      *
+-    *                                                                       *
+-    *************************************************************************
+-*/
+-
+-#ifndef __KOPETEPREFS_H__
+-#define __KOPETEPREFS_H__
+-
+-#include <qobject.h>
+-#include <kdeversion.h>
+-#include <qcolor.h>
+-#include <qfont.h>
+-
+-#include "kopete_export.h"
+-
+-class KConfig;
+-
+-class KOPETE_EXPORT KopetePrefs : public QObject
+-{
+-	Q_OBJECT
+-	// here so we can use Qt to translate enums<-->strings
+-	Q_PROPERTY( ContactDisplayMode contactListDisplayMode READ contactListDisplayMode WRITE setContactListDisplayMode )
+-	Q_PROPERTY( IconDisplayMode contactListIconMode READ contactListIconMode WRITE setContactListIconMode )
+-        Q_ENUMS( ContactDisplayMode IconDisplayMode )
+-
+-public:
+-	/**
+-	 * The prefs container-class is a singleton object. Use this method to retrieve
+-	 * the instance.
+-	 */
+-	static KopetePrefs *prefs();
+-
+-	/**
+-	 * Reads all pref-variables from KConfig
+-	 * usually you don't need this as KopetePrefs loads settings
+-	 * when an instance is created
+-	 */
+-	void load();
+-
+-	/**
+-	 * Stores all pref-variables into KConfig
+-	 */
+-	void save();
+-
+-	QString iconTheme() const { return mIconTheme; }
+-	bool useEmoticons() const { return mUseEmoticons; }
+-	bool showOffline() const { return mShowOffline; }
+-	bool showEmptyGroups() const { return mShowEmptyGroups; }
+-	bool treeView() const { return mTreeView; }
+-	bool sortByGroup() const { return mSortByGroup; }
+-	bool greyIdleMetaContacts() const { return mGreyIdle; }
+-	bool startDocked() const { return mStartDocked; }
+-	bool useQueue() const { return mUseQueue; }
+-	bool raiseMsgWindow() const{ return mRaiseMsgWindow; }
+-	bool showEvents() const{ return mShowEvents; }
+-	bool trayflashNotify() const { return mTrayflashNotify; }
+-	bool spellCheck() const { return mSpellCheck; }
+-	bool queueUnreadMessages() const { return mQueueUnreadMessages; }
+-	bool queueOnlyHighlightedMessagesInGroupChats() const { return mQueueOnlyHighlightedMessagesInGroupChats; }
+-	bool queueOnlyMessagesOnAnotherDesktop() const { return mQueueOnlyMessagesOnAnotherDesktop; }
+-	bool trayflashNotifyLeftClickOpensMessage() const { return mTrayflashNotifyLeftClickOpensMessage; }
+-	bool trayflashNotifySetCurrentDesktopToChatView() const { return mTrayflashNotifySetCurrentDesktopToChatView; }
+-	bool balloonNotify() const { return mBalloonNotify; }
+-	bool balloonNotifyIgnoreClosesChatView() const { return mBalloonNotifyIgnoreClosesChatView; }
+-	bool soundIfAway() const { return mSoundIfAway; }
+-	bool transparencyEnabled() const { return mTransparencyEnabled; }
+-	int transparencyValue() const { return mTransparencyValue; }
+-	QColor transparencyColor() const { return mTransparencyColor; }
+-	int chatViewBufferSize() const { return mChatViewBufferSize; }
+-	int rememberedMessages() const { return mRememberedMessages; }
+-	const QColor &highlightBackground() const { return mHighlightBackground; }
+-	const QColor &highlightForeground() const { return mHighlightForeground; }
+-	const QColor &textColor() const { return mTextColor; }
+-	const QColor &bgColor() const { return mBgColor; }
+-	const QColor &linkColor() const { return mLinkColor; }
+-	const QFont &fontFace() const { return mFontFace; }
+-	const QColor &idleContactColor() const { return mIdleContactColor; }
+-	bool highlightEnabled() const { return mHighlightEnabled; }
+-	bool bgOverride() const { return mBgOverride; }
+-	bool fgOverride() const { return mFgOverride; }
+-	bool rtfOverride() const { return mRtfOverride; }
+-
+-	QString interfacePreference() const { return mInterfacePreference; }
+-	bool showTray() const { return mShowTray; }
+-	bool richText() const { return mRichText; }
+-	bool chatWShowSend() const { return mChatWShowSend; }
+-	bool autoConnect() const { return mAutoConnect; }
+-
+-	int chatWindowPolicy() const { return mChatWindowPolicy; }
+-	QString styleSheet() const { return mStyleSheet; }
+-	QString styleDataPath() const { return mStyleDataPath; }
+-	QString styleContents() const { return mStyleContents; }
+-	QString defaultTheme() const { return QString::fromLatin1("Default"); }
+-
+-	QStringList toolTipContents() const { return mToolTipContents; }
+-
+-	///
+-	enum ContactDisplayMode { Classic, RightAligned, Detailed, Yagami, Default = Classic };
+-	///
+-	enum IconDisplayMode { IconPic, PhotoPic, IconDefault = IconPic };
+-	bool contactListIndentContacts() const { return mContactListIndentContacts; }
+-	bool contactListHideVerticalScrollBar() const { return mContactListHideVerticalScrollBar; }
+-	ContactDisplayMode contactListDisplayMode() const { return mContactListDisplayMode; }
+-	IconDisplayMode contactListIconMode() const { return mContactListIconMode; }
+-	bool contactListUseCustomFonts() const { return mContactListUseCustomFonts; }
+-	QFont contactListCustomNormalFont() const { return mContactListNormalFont; }
+-	QFont contactListCustomSmallFont() const { return mContactListSmallFont; }
+-	QFont contactListSmallFont() const;
+-	QColor contactListGroupNameColor() const { return mContactListGroupNameColor; }
+-	bool contactListAnimation() const { return mContactListAnimation; }
+-	bool contactListFading() const { return mContactListFading; }
+-	bool contactListFolding() const { return mContactListFolding; }
+-	bool contactListMouseNavigation() const { return mContactListMouseNavigation; }
+-	bool contactListAutoHide() const { return mContactListAutoHide; }
+-	bool contactListAutoHideVScroll() const { return mContactListAutoHideVScroll; }
+-	unsigned int contactListAutoHideTimeout() const { return mContactListAutoHideTimeout; }
+-
+-	bool reconnectOnDisconnect() const { return mReconnectOnDisconnect; }
+-
+-	bool truncateContactNames() const { return mTruncateContactNames; }
+-	int maxContactNameLength() const { return mMaxContactNameLength; }
+-	bool emoticonsRequireSpaces() const { return mEmoticonsRequireSpaces; }
+-
+-	void setIconTheme(const QString &value);
+-	void setUseEmoticons(bool value);
+-	void setShowOffline(bool value);
+-	void setShowEmptyGroups(bool value);
+-	void setTreeView(bool);
+-	void setSortByGroup(bool);
+-	void setGreyIdleMetaContacts(bool);
+-	void setStartDocked(bool);
+-	void setUseQueue(bool);
+-	void setRaiseMsgWindow(bool);
+-	void setShowEvents(bool);
+-	void setTrayflashNotify(bool);
+-	void setSpellCheck(bool);
+-	void setQueueUnreadMessages(bool);
+-	void setQueueOnlyHighlightedMessagesInGroupChats(bool);
+-	void setQueueOnlyMessagesOnAnotherDesktop(bool);
+-	void setTrayflashNotifyLeftClickOpensMessage(bool);
+-	void setTrayflashNotifySetCurrentDesktopToChatView(bool);
+-	void setBalloonNotify(bool);
+-	void setBalloonNotifyIgnoreClosesChatView(bool);
+-	void setSoundIfAway(bool);
+-	void setBeepNotify(bool);
+-	void setChatWindowPolicy(int);
+-	void setStyleSheet (const QString &);
+-	void setTransparencyEnabled(bool);
+-	void setTransparencyColor(const QColor &);
+-	void setChatViewBufferSize(int);
+-	void setHighlightBackground(const QColor &);
+-	void setHighlightForeground(const QColor &);
+-	void setHighlightEnabled(bool);
+-	void setTransparencyValue(int);
+-	void setBgOverride(bool);
+-	void setFgOverride(bool);
+-	void setRtfOverride(bool);
+-	void setInterfacePreference(const QString &viewPlugin);
+-	void setTextColor(const QColor &);
+-	void setBgColor(const QColor &);
+-	void setLinkColor(const QColor &);
+-	void setFontFace(const QFont &);
+-	void setIdleContactColor(const QColor &);
+-	void setShowTray(bool);
+-	void setRichText(bool);
+-	void setRememberedMessages(int);
+-	void setToolTipContents(const QStringList &);
+-	void setContactListIndentContacts( bool v );
+-	void setContactListHideVerticalScrollBar( bool v );
+-	void setContactListDisplayMode( ContactDisplayMode v );
+-	void setContactListIconMode( IconDisplayMode v );
+-	void setContactListUseCustomFonts( bool v );
+-	void setContactListCustomNormalFont( const QFont & v );
+-	void setContactListCustomSmallFont( const QFont & v );
+-	void setContactListGroupNameColor( const QColor & v );
+-	void setContactListAnimation( bool );
+-	void setContactListFading( bool );
+-	void setContactListFolding( bool );
+-	void setContactListMouseNavigation( bool );
+-	void setContactListAutoHide( bool );
+-	void setContactListAutoHideVScroll( bool );
+-	void setContactListAutoHideTimeout( unsigned int );
+-	void setReconnectOnDisconnect( bool newSetting );
+-	void setTruncateContactNames( bool );
+-	void setMaxContactNameLength( int );
+-	void setAutoConnect( bool );
+-	void setEmoticonsRequireSpaces( bool );
+-
+-signals:
+-	/**
+-	 * Emitted when config gets saved by save()
+-	 */
+-	void saved();
+-	/**
+-	 * Emitted when config gets saved by save() and a certain
+-	 * setting has changed.
+-	 * Naming scheme is the same as with the config vars.
+-	 */
+-	void windowAppearanceChanged();
+-	void messageAppearanceChanged();
+-	void contactListAppearanceChanged();
+-	void transparencyChanged();
+-
+-private:
+-	/**
+-	 * Private constructor: we are a singleton
+-	 */
+-	KopetePrefs();
+-
+-	/**
+-	 * Our instance
+-	 */
+-	static KopetePrefs *s_prefs;
+-
+-	KConfig *config;
+-
+-	QString mIconTheme;
+-	bool mUseEmoticons;
+-	bool mShowOffline;
+-	bool mShowEmptyGroups;
+-	bool mGreyIdle;
+-	bool mTreeView;
+-	bool mSortByGroup;
+-	bool mStartDocked;
+-	bool mUseQueue;
+-	bool mRaiseMsgWindow;
+-	bool mShowEvents;
+-	bool mTrayflashNotify;
+-	bool mSpellCheck;
+-	bool mQueueUnreadMessages;
+-	bool mQueueOnlyHighlightedMessagesInGroupChats;
+-	bool mQueueOnlyMessagesOnAnotherDesktop;
+-	bool mTrayflashNotifyLeftClickOpensMessage;
+-	bool mTrayflashNotifySetCurrentDesktopToChatView;
+-	bool mBalloonNotify;
+-	bool mBalloonNotifyIgnoreClosesChatView;
+-	bool mSoundIfAway;
+-	bool mTransparencyEnabled;
+-	int mTransparencyValue;
+-	int mRememberedMessages;
+-	QString mInterfacePreference;
+-	QColor mTransparencyColor;
+-	int mChatViewBufferSize;
+-	QColor mHighlightBackground;
+-	QColor mHighlightForeground;
+-	QColor mTextColor;
+-	QColor mBgColor;
+-	QColor mLinkColor;
+-	QFont mFontFace;
+-	QColor mIdleContactColor;
+-	bool mHighlightEnabled;
+-	bool mBgOverride;
+-	bool mFgOverride;
+-	bool mRtfOverride;
+-	bool mShowTray;
+-	bool mTransparencyChanged;
+-	bool mWindowAppearanceChanged;
+-	bool mMessageAppearanceChanged;
+-	bool mContactListAppearanceChanged;
+-	bool mChatWShowSend;
+-	bool mAutoConnect;
+-
+-	int mChatWindowPolicy;
+-
+-	bool mTruncateContactNames;
+-	int mMaxContactNameLength;
+-
+-	bool mRichText;
+-	QString mStyleSheet;
+-	QString mStyleDataPath;
+-	QString mStyleContents;
+-
+-	QStringList mToolTipContents;
+-
+-	bool mContactListIndentContacts;
+-	bool mContactListHideVerticalScrollBar;
+-	ContactDisplayMode mContactListDisplayMode;
+-	IconDisplayMode mContactListIconMode;
+-	bool mContactListUseCustomFonts;
+-	QFont mContactListNormalFont;
+-	QFont mContactListSmallFont;
+-	QColor mContactListGroupNameColor;
+-	bool mContactListAnimation;
+-	bool mContactListFading;
+-	bool mContactListFolding;
+-	bool mContactListMouseNavigation;
+-	bool mContactListAutoHide;
+-	bool mContactListAutoHideVScroll;
+-	unsigned int mContactListAutoHideTimeout;
+-
+-	bool mReconnectOnDisconnect;
+-	bool mEmoticonsRequireSpaces;
+-
+-	QString fileContents(const QString &path);
+-	void _setStyleSheet (const QString &);
+-};
+-#endif
+-// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/libkopete/private/Makefile.am	(revision 568672)
++++ kopete/libkopete/private/Makefile.am	(revision 586398)
+@@ -6,7 +6,7 @@
+ noinst_LTLIBRARIES = libkopeteprivate.la
+ 
+ libkopeteprivate_la_SOURCES = kopeteemoticons.cpp \
+-	kopeteprefs.cpp kopetecommand.cpp kopeteviewmanager.cpp kopeteutils_private.cpp
++	kopetecommand.cpp kopeteviewmanager.cpp kopeteutils_private.cpp
+ libkopeteprivate_la_LDFLAGS = $(all_libraries)
+ libkopeteprivate_la_LIBADD = $(LIB_KDEUI)
+ # vim: set noet:
+--- kopete/libkopete/private/kopeteemoticons.cpp	(revision 568672)
++++ kopete/libkopete/private/kopeteemoticons.cpp	(revision 586398)
+@@ -2,7 +2,7 @@
+     kopeteemoticons.cpp - Kopete Preferences Container-Class
+ 
+     Copyright (c) 2002      by Stefan Gehn            <metz AT gehn.net>
+-    Copyright (c) 2002-2005 by Olivier Goffart        <ogoffart @ kde.org>
++    Copyright (c) 2002-2006 by Olivier Goffart        <ogoffart @ kde.org>
+     Copyright (c) 2005      by Engin AYDOGAN          <engin at bzzzt.biz>
+ 
+    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+@@ -48,6 +48,8 @@
+ struct Emoticons::Emoticon
+ {
+ 	Emoticon(){}
++	/* sort by longest to shortest matchText */
++	bool operator< (const Emoticon &e){ return matchText.length() > e.matchText.length(); }
+ 	QString matchText;
+ 	QString matchTextEscaped;
+ 	QString	picPath;
+@@ -176,13 +178,11 @@
+ 			continue;
+ 		}
+ 
+-		if ( mode & StrictParse )
+-			//<br /> marks beginning of line
+-			if ( !p.isSpace() && message.mid(pos - 6, 6) != QString::fromLatin1("<br />"))
+-			{
+-				p = c; 
+-				continue; 
+-			} /* strict requires space before the emoticon */
++		if ( (mode & StrictParse)  &&  !p.isSpace() && p != '>')
++		{  // '>' may mark the end of an html tag
++			p = c; 
++			continue; 
++		} /* strict requires space before the emoticon */
+ 		if ( d->emoticonMap.contains( c ) )
+ 		{
+ 			emoticonList = d->emoticonMap[ c ];
+@@ -199,8 +199,7 @@
+ 					/* check if the character after this match is space or end of string*/
+ 						n = message[ pos + needle.length() ];
+ 						//<br/> marks the end of a line
+-						if( message.mid( pos + needle.length(), 3) != QString::fromLatin1("<br") && 
+-								!n.isSpace() &&  !n.isNull() && n!= '&') 
++						if( n != '<' && !n.isSpace() &&  !n.isNull() && n!= '&') 
+ 							break;
+ 					}
+ 					/* Perfect match */
+@@ -366,10 +365,19 @@
+ 	d->emoticonAndPicList.clear();
+ 	d->emoticonMap.clear();
+ 
+-	QDomDocument emoticonMap( QString::fromLatin1( "messaging-emoticon-map" ) );
++	QString filename= KGlobal::dirs()->findResource( "emoticons",  d->theme + QString::fromLatin1( "/emoticons.xml" ) );
++	if(!filename.isEmpty())
++		return initEmoticon_emoticonsxml( filename );
++	filename= KGlobal::dirs()->findResource( "emoticons",  d->theme + QString::fromLatin1( "/icondef.xml" ) );
++	if(!filename.isEmpty())
++		return initEmoticon_JEP0038( filename );
++	kdWarning(14010) << k_funcinfo << "emotiucon XML theme description not found" <<endl;
++}
+ 
+-    QString filename= KGlobal::dirs()->findResource( "emoticons",  d->theme + QString::fromLatin1( "/emoticons.xml" ) );
+-
++void Emoticons::initEmoticon_emoticonsxml( const QString & filename)
++{
++	QDomDocument emoticonMap( QString::fromLatin1( "messaging-emoticon-map" ) );	
++	
+ 	QFile mapFile( filename );
+ 	mapFile.open( IO_ReadOnly );
+ 	emoticonMap.setContent( &mapFile );
+@@ -418,9 +426,96 @@
+ 		node = node.nextSibling();
+ 	}
+ 	mapFile.close();
++	sortEmoticons();
+ }
+ 
+ 
++void Emoticons::initEmoticon_JEP0038( const QString & filename)
++{
++	QDomDocument emoticonMap( QString::fromLatin1( "icondef" ) );	
++	
++	QFile mapFile( filename );
++	mapFile.open( IO_ReadOnly );
++	emoticonMap.setContent( &mapFile );
++
++	QDomElement list = emoticonMap.documentElement();
++	QDomNode node = list.firstChild();
++	while( !node.isNull() )
++	{
++		QDomElement element = node.toElement();
++		if( !element.isNull() )
++		{
++			if( element.tagName() == QString::fromLatin1( "icon" ) )
++			{
++				QStringList items;
++				QString emoticon_file;
++
++				QDomNode emoticonNode = node.firstChild();
++				while( !emoticonNode.isNull() )
++				{
++					QDomElement emoticonElement = emoticonNode.toElement();
++					if( !emoticonElement.isNull() )
++					{
++						if( emoticonElement.tagName() == QString::fromLatin1( "text" ) )
++						{
++							//TODO xml:lang
++							items << emoticonElement.text();
++						}
++						else if( emoticonElement.tagName() == QString::fromLatin1( "object" ) && emoticon_file.isEmpty() )
++						{
++							QString mime= emoticonElement.attribute(
++									QString::fromLatin1( "mime" ), QString::fromLatin1("image/*") );
++							if(mime.startsWith(QString::fromLatin1("image/")) && !mime.endsWith(QString::fromLatin1("/svg+xml")))
++							{
++								emoticon_file = emoticonElement.text();
++							}
++							else
++							{
++								kdDebug(14010) << k_funcinfo <<	"Warning: Unsupported format '" << mime << endl;
++							}
++						}
++						/*else
++						{
++							kdDebug(14010) << k_funcinfo <<
++									"Warning: Unknown element '" << element.tagName() <<
++									"' in emoticon data" << endl;
++						}*/
++					}
++					emoticonNode = emoticonNode.nextSibling();
++				}
++				if( !items.isEmpty() && !emoticon_file.isEmpty() )
++					addIfPossible ( emoticon_file, items );
++			}
++			else
++			{
++				kdDebug(14010) << k_funcinfo << "Warning: Unknown element '" <<
++						element.tagName() << "' in map file" << endl;
++			}
++		}
++		node = node.nextSibling();
++	}
++	mapFile.close();
++	sortEmoticons();
++}
++
++
++void Emoticons::sortEmoticons()
++{
++	/* sort strings in order of longest to shortest to provide convenient input for
++		greedy matching in the tokenizer */
++	QValueList<QChar> keys = d->emoticonMap.keys();
++	for ( QValueList<QChar>::const_iterator it = keys.begin(); it != keys.end(); ++it )
++	{
++		QChar key = (*it);
++		QValueList<Emoticon> keyValues = d->emoticonMap[key];
++ 		qHeapSort(keyValues.begin(), keyValues.end());
++ 		d->emoticonMap[key] = keyValues;
++	}
++}
++
++
++
++
+ QMap<QString, QString> Emoticons::emoticonAndPicList()
+ {
+ 	return d->emoticonAndPicList;
+--- kopete/libkopete/private/kopeteemoticons.h	(revision 568672)
++++ kopete/libkopete/private/kopeteemoticons.h	(revision 586398)
+@@ -144,7 +144,26 @@
+ 	 * an animation/pixmap has been found for it
+ 	 **/
+ 	void addIfPossible( const QString& filenameNoExt, const QStringList &emoticons );
++	
++	/**
++	 * uses the kopete's emoticons.xml  for the theme
++	 * @see initEmoticons
++	 */
++	void initEmoticon_emoticonsxml( const QString & filename);
++	
++	/**
++	 * uses the JEP-0038 xml description for the theme
++	 * @see initEmoticons
++	 */
++	void initEmoticon_JEP0038( const QString & filename);
++	
++	/**
++	 * sorts emoticons for convenient parsing, which yields greedy matching on
++	 * matchText
++	 */
++	void sortEmoticons();
+ 
++
+ 	struct Emoticon;
+ 	struct EmoticonNode;
+ 	class Private;
+--- kopete/libkopete/private/kopeteviewmanager.cpp	(revision 568672)
++++ kopete/libkopete/private/kopeteviewmanager.cpp	(revision 586398)
+@@ -48,7 +48,7 @@
+ 	EventList eventList;
+ 	KopeteView *activeView;
+ 
+-	bool useQueue;
++	bool useQueueOrStack;
+ 	bool raiseWindow;
+ 	bool queueUnreadMessages;
+ 	bool queueOnlyHighlightedMessagesInGroupChats;
+@@ -98,7 +98,7 @@
+ 
+ void KopeteViewManager::slotPrefsChanged()
+ {
+-	d->useQueue = KopetePrefs::prefs()->useQueue();
++	d->useQueueOrStack = KopetePrefs::prefs()->useQueue() || KopetePrefs::prefs()->useStack();
+ 	d->raiseWindow = KopetePrefs::prefs()->raiseMsgWindow();
+ 	d->queueUnreadMessages = KopetePrefs::prefs()->queueUnreadMessages();
+ 	d->queueOnlyHighlightedMessagesInGroupChats = KopetePrefs::prefs()->queueOnlyHighlightedMessagesInGroupChats();
+@@ -167,7 +167,7 @@
+ 		manager->view(true,msg.requestedPlugin())->appendMessage( msg );
+ 		d->foreignMessage=false; //the view is created, reset the flag
+ 
+-		bool appendMessageEvent = d->useQueue;
++		bool appendMessageEvent = d->useQueueOrStack;
+ 
+ 		QWidget *w;
+ 		if( d->queueUnreadMessages && ( w = dynamic_cast<QWidget*>(view( manager )) ) )
+@@ -201,7 +201,8 @@
+ 			readMessages( manager, outgoingMessage );
+ 		}
+ 
+-		if ( !outgoingMessage && ( !manager->account()->isAway() || KopetePrefs::prefs()->soundIfAway() ) )
++		if ( !outgoingMessage && ( !manager->account()->isAway() || KopetePrefs::prefs()->soundIfAway() )
++				&& msg.direction() != Kopete::Message::Internal )
+ 		{
+ 			QWidget *w=dynamic_cast<QWidget*>(manager->view(false));
+ 			KConfig *config = KGlobal::config();
+@@ -344,7 +345,10 @@
+ 
+ 	if( d->managerMap.contains( manager ) )
+ 	{
+-		d->managerMap[ manager ]->closeView( true );
++		KopeteView *v=d->managerMap[ manager ];
++		v->closeView( true );
++		delete v;   //closeView call deleteLater,  but in this case this is not enough, because some signal are called that case crash
++		d->managerMap.remove( manager );
+ 	}
+ }
+ 
+--- kopete/libkopete/kopeteonlinestatus.cpp	(revision 568672)
++++ kopete/libkopete/kopeteonlinestatus.cpp	(revision 586398)
+@@ -147,7 +147,14 @@
+ 
+ bool OnlineStatus::operator==( const OnlineStatus &other ) const
+ {
+-	return d->internalStatus == other.d->internalStatus && d->protocol == other.d->protocol;
++	if ( d->internalStatus == other.d->internalStatus && d->protocol == other.d->protocol &&
++	     d->weight == other.d->weight && d->overlayIcons == other.d->overlayIcons &&
++	     d->description == other.d->description )
++	{
++		return true;
++	}
++
++	return false;
+ }
+ 
+ bool OnlineStatus::operator!=( const OnlineStatus &other ) const
+@@ -230,6 +237,8 @@
+ 	// figure out what icon we should use for this contact
+  	QString iconName = contact->icon();
+ 	if ( iconName.isNull() )
++		iconName = contact->account()->customIcon();
++	if ( iconName.isNull() )
+ 		iconName = d->protocolIcon();
+ 
+ 
+@@ -243,8 +252,11 @@
+ 
+ QString OnlineStatus::mimeSourceFor( const Account *account, int size ) const
+ {
+-	//FIXME: support Kopete::Account having knowledge of a custom icon
+-	return mimeSource( d->protocolIcon(), size, account->color(), false );
++	QString iconName = account->customIcon();
++	if ( iconName.isNull() )
++		iconName = d->protocolIcon();
++
++	return mimeSource( iconName, size, account->color(), false );
+ }
+ 
+ QPixmap OnlineStatus::iconFor( const QString &mimeSource ) const
+--- kopete/libkopete/kopetemessage.h	(revision 568672)
++++ kopete/libkopete/kopetemessage.h	(revision 586398)
+@@ -335,11 +335,6 @@
+ 	 void setManager(ChatSession *);
+ 
+ 	/**
+-	 * get a XML version of this message
+-	 */
+-	const QDomDocument asXML();
+-
+-	/**
+ 	 * Enables the use of a background for a message
+ 	 * @param enable A flag to indicate if the background should be enabled or disabled.
+ 	 */
+@@ -357,6 +352,11 @@
+ 	 */
+ 	void setRtfOverride( bool enable );
+ 
++	/**
++	 * Return HTML style attribute for this message.
++	 * @return A string formatted like this: "style=attr"
++	 */
++	QString getHtmlStyleAttribute() const;
+ 
+ public:  /* static helpers */
+ 
+@@ -387,14 +387,6 @@
+ 	static QString decodeString( const QCString &message,
+  		const QTextCodec *providedCodec = 0L, bool *success = 0L );
+ 
+-	
+-	/**
+-	 * @internal
+-	 * this function will clear the cache of metacontact photo.
+-	 * it is called when the photo of a contact change.
+-	 */
+-	static void clearImageCache();
+-
+ private:
+ 	/**
+ 	 * Message is implicitly shared.
+@@ -406,8 +398,6 @@
+ 	KSharedPtr<Private> d;
+ 
+ 	static QString parseLinks( const QString &message, MessageFormat format );
+-
+-	QDomElement contactNode( QDomDocument doc, const Contact *contact );
+ };
+ 
+ }
+--- kopete/libkopete/kopetecontact.cpp	(revision 568672)
++++ kopete/libkopete/kopetecontact.cpp	(revision 586398)
+@@ -44,6 +44,7 @@
+ #include "kopetemetacontact.h"
+ #include "kopeteprefs.h"
+ #include "metacontactselectorwidget.h"
++#include "kopeteemoticons.h"
+ 
+ //For the moving to another metacontact dialog
+ #include <qlabel.h>
+@@ -92,19 +93,26 @@
+ 	d->idleTime = 0;
+ 	d->icon = icon;
+ 
++	// If can happend that a MetaContact may be used without a account
++	// (ex: for unit tests or chat window style preview)
+ 	if ( account )
++	{
+ 		account->registerContact( this );
++		connect( account, SIGNAL( isConnectedChanged() ), SLOT( slotAccountIsConnectedChanged() ) );
++	}
+ 
+ 	// Need to check this because myself() may have no parent
+-	if( parent )
++	// Maybe too the metaContact doesn't have a valid protocol() 
++	// (ex: for unit tests or chat window style preview)
++	if( parent && protocol() )
+ 	{
+ 		connect( parent, SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
+ 			protocol(), SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
+ 
+ 		parent->addContact( this );
+ 	}
+-	if( account )
+-		connect( account, SIGNAL( isConnectedChanged() ), SLOT( slotAccountIsConnectedChanged() ) );
++
++	
+ }
+ 
+ Contact::~Contact()
+@@ -201,7 +209,7 @@
+ 
+ 	if( metaContact() && metaContact()->isTemporary() && contactId() != account()->myself()->contactId() )
+ 	{
+-		KAction *actionAddContact = new KAction( i18n( "&Add to Your Contact List" ), QString::fromLatin1( "bookmark_add" ),
++		KAction *actionAddContact = new KAction( i18n( "&Add to Your Contact List" ), QString::fromLatin1( "add_user" ),
+ 		                                         0, this, SLOT( slotAddContact() ), menu, "actionAddContact" );
+ 		actionAddContact->plug( menu );
+ 		menu->insertSeparator();
+@@ -266,7 +274,8 @@
+ 	w->setSpacing( KDialog::spacingHint() );
+ 	Kopete::UI::MetaContactSelectorWidget *selector = new Kopete::UI::MetaContactSelectorWidget(w);
+ 	selector->setLabelMessage(i18n( "Select the meta contact to which you want to move this contact:" ));
+-
++	// exclude this metacontact as a target metacontact for the move
++	selector->excludeMetaContact( metaContact() );
+ 	QCheckBox *chkCreateNew = new QCheckBox( i18n( "Create a new metacontact for this contact" ), w );
+ 	QWhatsThis::add( chkCreateNew , i18n( "If you select this option, a new metacontact will be created in the top-level group "
+ 		"with the name of this contact and the contact will be moved to it." ) );
+@@ -449,7 +458,7 @@
+ {
+ 	if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
+ 		i18n( "Are you sure you want to remove the contact  '%1' from your contact list?" ).
+-		arg( d->contactId ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"), QString::fromLatin1("editdelete") ),
++		arg( d->contactId ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"), QString::fromLatin1("delete_user") ),
+ 		QString::fromLatin1("askRemoveContact"), KMessageBox::Notify | KMessageBox::Dangerous )
+ 		== KMessageBox::Continue )
+ 	{
+@@ -656,7 +665,7 @@
+ 			"<nobr><b>%4</b> (%3)</nobr><br><img src=\"%2\">&nbsp;%1" ).
+ 				arg( Kopete::Message::escape( onlineStatus().description() ), iconName,
+ 					Kopete::Message::escape( contactId() ),
+-					Kopete::Message::escape( nick ) );
++					Kopete::Emoticons::parseEmoticons( Kopete::Message::escape( nick ) ) );
+ 	}
+ 
+ 	// --------------------------------------------------------------------------
+@@ -698,7 +707,7 @@
+ 			if(!awaymsg.isEmpty())
+ 			{
+ 				tip += i18n("<br><b>Away Message:</b>&nbsp;FORMATTED AWAY MESSAGE",
+-							"<br><b>Away&nbsp;Message:</b>&nbsp;%1").arg ( Kopete::Message::escape(awaymsg) );
++							"<br><b>Away&nbsp;Message:</b>&nbsp;%1").arg ( Kopete::Emoticons::parseEmoticons( Kopete::Message::escape(awaymsg) ) );
+ 			}
+ 		}
+ 		else
+--- kopete/libkopete/kopeteaccount.cpp	(revision 568672)
++++ kopete/libkopete/kopeteaccount.cpp	(revision 586398)
+@@ -78,6 +78,9 @@
+ 	Kopete::BlackLister *blackList;
+ 	KConfigGroup *configGroup;
+ 	uint connectionTry;
++	QString customIcon;
++	Kopete::OnlineStatus restoreStatus;
++	QString restoreMessage;
+ };
+ 
+ Account::Account( Protocol *parent, const QString &accountId, const char *name )
+@@ -87,8 +90,12 @@
+ 
+ 	d->excludeconnect = d->configGroup->readBoolEntry( "ExcludeConnect", false );
+ 	d->color = d->configGroup->readColorEntry( "Color", &d->color );
++	d->customIcon = d->configGroup->readEntry( "Icon", QString() );
+ 	d->priority = d->configGroup->readNumEntry( "Priority", 0 );
+ 
++	d->restoreStatus = Kopete::OnlineStatus::Online;
++	d->restoreMessage = "";
++
+ 	QObject::connect( &d->suppressStatusTimer, SIGNAL( timeout() ),
+ 		this, SLOT( slotStopSuppression() ) );
+ }
+@@ -109,17 +116,26 @@
+ 	delete d;
+ }
+ 
++void Account::reconnect()
++{
++	kdDebug( 14010 ) << k_funcinfo << "account " << d->id << " restoreStatus " << d->restoreStatus.status() << " restoreMessage " << d->restoreMessage << endl;
++	setOnlineStatus( d->restoreStatus, d->restoreMessage );
++}
++
+ void Account::disconnected( DisconnectReason reason )
+ {
++	kdDebug( 14010 ) << k_funcinfo << reason << endl;
+ 	//reconnect if needed
+-	if ( ( KopetePrefs::prefs()->reconnectOnDisconnect() == true && reason > Manual ) ||
+-	     reason == BadPassword )
++	if(reason == BadPassword )
+ 	{
+-		if(reason != BadPassword) 
+-			d->connectionTry++;
++		QTimer::singleShot(0, this, SLOT(reconnect()));
++	}
++	else if ( KopetePrefs::prefs()->reconnectOnDisconnect() == true && reason > Manual )
++	{
++		d->connectionTry++;
+ 		//use a timer to allow the plugins to clean up after return
+ 		if(d->connectionTry < 3)
+-			QTimer::singleShot( 0, this, SLOT(connect()));
++			QTimer::singleShot(10000, this, SLOT(reconnect())); // wait 10 seconds before reconnect
+ 	}
+ 	if(reason== OtherClient)
+ 	{
+@@ -166,9 +182,11 @@
+ 
+ QPixmap Account::accountIcon(const int size) const
+ {
++	QString icon= d->customIcon.isEmpty() ? d->protocol->pluginIcon() : d->customIcon;
++	
+ 	// FIXME: this code is duplicated with OnlineStatus, can we merge it somehow?
+ 	QPixmap base = KGlobal::instance()->iconLoader()->loadIcon(
+-		d->protocol->pluginIcon(), KIcon::Small, size );
++		icon, KIcon::Small, size );
+ 
+ 	if ( d->color.isValid() )
+ 	{
+@@ -381,6 +399,8 @@
+ 	{
+ 		QObject::disconnect( d->myself, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
+ 			this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
++		QObject::disconnect( d->myself, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ),
++			this, SLOT( slotContactPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ) );
+ 	}
+ 
+ 	d->myself = myself;
+@@ -389,6 +409,8 @@
+ 	
+ 	QObject::connect( d->myself, SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
+ 		this, SLOT( slotOnlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ) );
++	QObject::connect( d->myself, SIGNAL( propertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ),
++		this, SLOT( slotContactPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & ) ) );
+ 
+ 	if ( isConnected() != wasConnected )
+ 		emit isConnectedChanged();
+@@ -413,6 +435,13 @@
+ 		//the timer is also used to reset the d->connectionTry
+ 	}
+ 
++	if ( !isOffline )
++	{
++		d->restoreStatus = newStatus;
++		d->restoreMessage = myself()->property( Kopete::Global::Properties::self()->awayMessage() ).value().toString();
++//		kdDebug( 14010 ) << k_funcinfo << "account " << d->id << " restoreStatus " << d->restoreStatus.status() << " restoreMessage " << d->restoreMessage << endl;
++	}
++
+ /*	kdDebug(14010) << k_funcinfo << "account " << d->id << " changed status. was "
+ 	               << Kopete::OnlineStatus::statusTypeToString(oldStatus.status()) << ", is "
+ 	               << Kopete::OnlineStatus::statusTypeToString(newStatus.status()) << endl;*/
+@@ -430,6 +459,16 @@
+ 			it.current()->setOnlineStatus( status );
+ }
+ 
++void Account::slotContactPropertyChanged( Contact * /* contact */,
++	const QString &key, const QVariant &old, const QVariant &newVal )
++{
++	if ( key == QString::fromLatin1("awayMessage") && old != newVal && isConnected() )
++	{
++		d->restoreMessage = newVal.toString();
++//		kdDebug( 14010 ) << k_funcinfo << "account " << d->id << " restoreMessage " << d->restoreMessage << endl;
++	}
++}
++
+ void Account::slotStopSuppression()
+ {
+ 	d->suppressStatusNotification = false;
+@@ -514,11 +553,29 @@
+ 	setOnlineStatus( OnlineStatusManager::self()->onlineStatus(protocol() , away ? OnlineStatusManager::Away : OnlineStatusManager::Online)  , reason );
+ }
+ 
++void Account::setCustomIcon( const QString & i)
++{
++	d->customIcon = i;
++	if(!i.isEmpty())
++		d->configGroup->writeEntry( "Icon", i );
++	else
++		d->configGroup->deleteEntry( "Icon" );
++	emit colorChanged( color() );
++}
++
++QString Account::customIcon()  const
++{
++	return d->customIcon;
++}
++
+ void Account::virtual_hook( uint /*id*/, void* /*data*/)
+ {
+ }
+ 
+ 
+-} //END namespace Kopete
+ 
++}
++
++ //END namespace Kopete
++
+ #include "kopeteaccount.moc"
+--- kopete/libkopete/kabcpersistence.cpp	(revision 568672)
++++ kopete/libkopete/kabcpersistence.cpp	(revision 586398)
+@@ -395,7 +395,7 @@
+ 										contactAdded = true;
+ 									else
+ 										KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
+-											i18n( "<qt>It was not possible to add the contact. Please see the debug messages for details.</qt>" ),
++											i18n( "<qt>It was not possible to add the contact.</qt>" ),
+ 											i18n( "Could Not Add Contact") ) ;
+ 								}
+ 							}
+--- kopete/libkopete/knotification.h	(revision 568672)
++++ kopete/libkopete/knotification.h	(revision 586398)
+@@ -147,6 +147,7 @@
+ 	 */
+ 	static void raiseWidget(QWidget *w);
+ 
++	bool m_linkClicked;
+ 
+ private slots:
+ 	void notifyByMessagebox();
+--- kopete/libkopete/kopetepassword.cpp	(revision 568672)
++++ kopete/libkopete/kopetepassword.cpp	(revision 586398)
+@@ -184,12 +184,12 @@
+ 	{
+ 		QString result = grabPassword();
+ 		if ( mSource == Kopete::Password::FromUser || result.isNull() )
+-			doPasswordDialog( result );
++			doPasswordDialog();
+ 		else
+ 			finished( result );
+ 	}
+ 
+-	void doPasswordDialog( const QString &password )
++	void doPasswordDialog()
+ 	{
+ 		kdDebug( 14010 ) << k_funcinfo << endl;
+ 
+--- kopete/libkopete/kopetemetacontact.h	(revision 568672)
++++ kopete/libkopete/kopetemetacontact.h	(revision 586398)
+@@ -41,6 +41,7 @@
+ 
+ class Plugin;
+ class Group;
++class Picture;
+ 
+ /**
+  * @author Will Stephenson <will at stevello.free-online.co.uk>
+@@ -187,6 +188,15 @@
+ 	QImage photo() const;
+ 
+ 	/**
++	 * Return the correct Kopete::Picture object depending of the metacontact photo source.
++	 *
++	 * This photo is obtained from the source set with @ref setPhotoSource
++	 *
++	 * KDE4 TODO: Rename this to photo() and use the new object.
++	 */
++	Picture &picture() const;
++
++	/**
+ 	 * @brief Set the custom displayName.
+ 	 *
+ 	 * This display name is used when name source is Custom
+@@ -207,10 +217,10 @@
+ 	QString customDisplayName() const;
+ 
+ 	/**
+-	 * @brief Returns the custom display name
++	 * @brief Returns the custom display photo
+ 	 *
+-	 * @see displayName()
+-	 * @see displayNameSource()
++	 * @see photo()
++	 * @see photoSource()
+ 	 */
+ 	KURL customPhoto() const;
+ 
+@@ -441,7 +451,7 @@
+ 	 * @brief Set if this is a temporary contact. (see @ref isTemporary)
+ 	 *
+ 	 * @param b if the contact is or not temporary
+-	 * @param group if the contact was temporary and b is true, then the contact will be moved to this group.
++	 * @param group if the contact was temporary and b is false, then the contact will be moved to this group.
+ 	 *  if group is null, it will be moved to top-level
+ 	 */
+ 	void setTemporary( bool b = true, Kopete::Group *group = 0L );
+@@ -571,6 +581,11 @@
+ 	 */
+ 	void slotAllPluginsLoaded();
+ 
++	/**
++	 * Update the KABC Picture when the addressbook is changed.
++	 */
++	void slotUpdateAddressBookPicture();
++
+ protected:
+ 	//QImage photoFromContact( Kopete::Contact *c) const;
+ 	//QImage photoFromKABC( const QString &id ) const;
+--- kopete/libkopete/tests/kopetemessage_test.h	(revision 568672)
++++ kopete/libkopete/tests/kopetemessage_test.h	(revision 586398)
+@@ -2,6 +2,7 @@
+     Tests for Kopete::Message
+ 
+     Copyright (c) 2005      by Duncan Mac-Vicar       <duncan at kde.org>
++    Copyright (c) 2005      by Tommi Rantala  <tommi.rantala at cs.helsinki.fi>
+ 
+     Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -27,7 +28,7 @@
+ class Kopete::Protocol;
+ class Kopete::Account;
+ class Kopete::MetaContact;
+-class	Kopete::Contact;
++class Kopete::Contact;
+ 
+ // change to SlotTester when it works
+ class KopeteMessage_Test : public KUnitTest::Tester
+@@ -35,9 +36,9 @@
+ public:
+ 	KopeteMessage_Test();
+ 	void allTests();
++
+ public slots:
+-	void testFormats();
+-	void testValidXML();
++	void testPrimitives();
+ 	void testLinkParser();
+ 
+ private:
+--- kopete/libkopete/tests/mock/Makefile.am	(revision 568672)
++++ kopete/libkopete/tests/mock/Makefile.am	(revision 586398)
+@@ -7,7 +7,7 @@
+ libkopete_mock_la_SOURCES = kopetemessage_mock.cpp kopeteaccount_mock.cpp kopetecontact_mock.cpp kopetemetacontact_mock.cpp kopeteprotocol_mock.cpp
+ 
+ libkopete_mock_la_LDFLAGS = $(all_libraries) -lkabc
+-libkopete_mock_la_LIBADD = ../../libkopete.la ../../private/libkopeteprivate.la $(LIB_KHTML) $(LIBXML_LIBS) $(LIBXSLT_LIBS)
++libkopete_mock_la_LIBADD = ../../libkopete.la ../../private/libkopeteprivate.la $(LIB_KHTML)
+ 
+ noinst_HEADERS = kopetemessage_mock.h kopetecontact_mock.h kopetemetacontact_mock.h kopeteaccount_mock.h kopeteprotocol_mock.h
+ 
+--- kopete/libkopete/tests/README	(revision 568672)
++++ kopete/libkopete/tests/README	(revision 586398)
+@@ -1,4 +1,3 @@
+-
+ LibKopete Unit Tests
+ ====================
+ 
+@@ -8,30 +7,41 @@
+ Link Test
+ Property Test
+ 
+-run make check to build and test.
+-Or make guicheck
+-
+ Test Programs:
+ --------------
+ Password Test Program
+ Wallet Test Program
+ 
++
++HOWTO Run
++=========
++
++You can use the console or the GUI version:
++
++ $ make guicheck
++ $ make check
++
++The 'silent' switch in make is useful to reduce output:
++ 
++ $ make check -s
++
++
+ Tricks
+ ======
+ 
+ Accessing private data?, you should not. We will kill you.
+ If it is really required, do something like:
+ 
+-#define private public
+-#include "kopetemessage.h"
+-#undef private
++ #define private public
++ #include "kopetemessage.h"
++ #undef private
+ 
+ Add a new test quickly:
+ 
+-[duncan at tarro tests]$ ./create_test.rb Kopete::ContactList
+-Creating test for class Kopete::ContactList
+-kopetecontactlist_test.h and kopetecontactlist_test.cpp writen.
+-Please add the following to Makefile.am:
+-kunittest_kopetecontactlist_test_la_SOURCES = kopetecontactlist_test.cpp
+-kunittest_kopetecontactlist_test_la_LIBADD = -lkunittest ../mock/libkopete_mock.la
+-kunittest_kopetecontactlist_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
++ $ ./create_test.rb Kopete::ContactList
++ Creating test for class Kopete::ContactList
++ kopetecontactlist_test.h and kopetecontactlist_test.cpp writen.
++ Please add the following to Makefile.am:
++ kunittest_kopetecontactlist_test_la_SOURCES = kopetecontactlist_test.cpp
++ kunittest_kopetecontactlist_test_la_LIBADD = -lkunittest ../mock/libkopete_mock.la
++ kunittest_kopetecontactlist_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+--- kopete/libkopete/tests/Makefile.am	(revision 568672)
++++ kopete/libkopete/tests/Makefile.am	(revision 586398)
+@@ -6,7 +6,7 @@
+ check_LTLIBRARIES = kunittest_kopetemessage_test.la kunittest_kopetepropertiestest.la kunittest_kopetecontactlist_test.la 
+ noinst_LTLIBRARIES = kunittest_kopeteemoticontest.la
+ 
+-check_PROGRAMS = kopetewallettest_program kopetepasswordtest_program kopeteerrornotifiertest_program
++check_PROGRAMS = kopetewallettest_program kopetepasswordtest_program
+ 
+ kunittest_kopetepropertiestest_la_SOURCES = kopetepropertiestest.cpp ../kopeteproperties.cpp
+ kunittest_kopetepropertiestest_la_LIBADD = -lkunittest ../libkopete.la
+@@ -28,10 +28,6 @@
+ kopetepasswordtest_program_LDFLAGS = -no-undefined $(all_libraries) $(KDE_RPATH)
+ kopetepasswordtest_program_LDADD = ../libkopete.la
+ 
+-kopeteerrornotifiertest_program_SOURCES = kopeteerrornotifiertest_program.cpp
+-kopeteerrornotifiertest_program_LDFLAGS = -no-undefined $(all_libraries) $(KDE_RPATH)
+-kopeteerrornotifiertest_program_LDADD = ../libkopete.la
+-
+ kunittest_kopetecontactlist_test_la_SOURCES = kopetecontactlist_test.cpp
+ kunittest_kopetecontactlist_test_la_LIBADD = -lkunittest mock/libkopete_mock.la
+ kunittest_kopetecontactlist_test_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+--- kopete/libkopete/tests/kopetemessage_test.cpp	(revision 568672)
++++ kopete/libkopete/tests/kopetemessage_test.cpp	(revision 586398)
+@@ -1,8 +1,9 @@
+ /*
+     Tests for Kopete::Message
+ 
+-    Copyright (c) 2005 by Duncan Mac-Vicar Prett  <duncan at kde.org>
+-		Copyright (c) 2004 by Richard Smith <kde at metafoo.co.uk>
++    Copyright (c) 2005   by Tommi Rantala  <tommi.rantala at cs.helsinki.fi>
++    Copyright (c) 2005   by Duncan Mac-Vicar Prett  <duncan at kde.org>
++    Copyright (c) 2004   by Richard Smith <kde at metafoo.co.uk>
+ 
+     Kopete (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
+ 
+@@ -48,18 +49,9 @@
+ 
+ KopeteMessage_Test::KopeteMessage_Test()
+ {
+-	setup();
+-}
+-
+-void KopeteMessage_Test::allTests()
+-{
+ 	// change user data dir to avoid messing with user's .kde dir
+ 	setenv( "KDEHOME", QFile::encodeName( QDir::homeDirPath() + "/.kopete-unittest" ), true );
+ 
+-	KApplication::disableAutoDcopRegistration();
+-	//KCmdLineArgs::init(argc,argv,"testkopetemessage", 0, 0, 0, 0);
+-	KApplication app;
+-	
+ 	// create fake objects needed to build a reasonable testeable message
+ 	m_protocol = new Kopete::Test::Mock::Protocol( new KInstance(QCString("test-kopete-message")), 0L, "test-kopete-message");
+ 	m_account = new Kopete::Test::Mock::Account(m_protocol, "testaccount");
+@@ -68,62 +60,183 @@
+ 	m_contactFrom = new Kopete::Test::Mock::Contact(m_account, QString::fromLatin1("test-myself"), m_metaContactMyself, QString::null);
+ 	m_contactTo = new Kopete::Test::Mock::Contact(m_account, QString::fromLatin1("test-dest"), m_metaContactOther, QString::null);
+ 	m_message = new Kopete::Message( m_contactFrom, m_contactTo, QString::null, Kopete::Message::Outbound, Kopete::Message::PlainText);
+-	
+-	testLinkParser();
+-	testValidXML();
+ }
+ 
+-void KopeteMessage_Test::testFormats()
++void KopeteMessage_Test::allTests()
+ {
+-	
++	KApplication::disableAutoDcopRegistration();
++	//KCmdLineArgs::init(argc,argv,"testkopetemessage", 0, 0, 0, 0);
++
++	// At least Kopete::Message::asXML() seems to require that a QApplication
++	// is created. Running the console version doesn't create it, but the GUI
++	// version does.
++
++	if (!kapp)
++		new KApplication();
++
++	testPrimitives();
++	testLinkParser();
+ }
+ 
+-void KopeteMessage_Test::testValidXML()
++void KopeteMessage_Test::testPrimitives()
+ {
+-	if ( KStandardDirs::findExe( QString::fromLatin1("xmllint") ).isEmpty() )
++	/**********************************************
++	 * from(), to()
++	 *********************************************/
++
+ 	{
+-		SKIP("Sorry, this test requires xmllint installed.");
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Inbound, Kopete::Message::PlainText);
++		Q_ASSERT(msg.from());
++		Q_ASSERT(!msg.to().isEmpty());
+ 	}
+ 
+-	Kopete::Test::Mock::Contact* contactFrom = new Kopete::Test::Mock::Contact( 0L /*account*/, QString::fromLatin1("test-friend"), 0L /* metaContact */);
+-	Kopete::Test::Mock::Contact* contactTo = new Kopete::Test::Mock::Contact( 0L /*account*/, QString::fromLatin1("test-myself"), 0L /* metaContact */);
+-	
+-	Kopete::Message message( contactFrom, contactTo, QString::fromLatin1("Hello my friend, I am Testing you"), Kopete::Message::Inbound, Kopete::Message::PlainText);
+-	
+-	kdDebug(14010) << k_funcinfo << endl;
+-	QString xml = message.asXML().toString();
+-	QFile xmlFile("message.xml");
+-	if ( xmlFile.open( IO_WriteOnly ) )
++	/**********************************************
++	 * Direction
++	 *********************************************/
++
+ 	{
+-		kdDebug(14010) << k_funcinfo << "Writing xml" << endl;
+-		QTextStream outXML(&xmlFile);
+-		outXML << QString::fromLatin1("<?xml version=\"1.0\"?>\n");
+-		outXML << xml;	
+-		xmlFile.close();
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Inbound, Kopete::Message::PlainText);
++		CHECK(Kopete::Message::Inbound, msg.direction());
+ 	}
+-	else
+ 	{
+-		kdDebug(14010) << k_funcinfo << "Cannot open file" << endl;
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Outbound, Kopete::Message::RichText);
++		CHECK(Kopete::Message::Outbound, msg.direction());
+ 	}
++	{
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Internal, Kopete::Message::RichText);
++		CHECK(Kopete::Message::Internal, msg.direction());
++	}
+ 
+-	QString schemaPath = QString::fromLatin1( SRCDIR ) + QString::fromLatin1("/kopetemessage.xsd");
+-	kdDebug() << k_funcinfo << schemaPath << endl;
+-	KProcess p;
+-	p << "xmllint" << "--noout" << "--schema" << schemaPath << QString::fromLatin1("message.xml"); 
+-	p.start(KProcess::Block);
+-	if (p.normalExit())
++	/**********************************************
++	 * Message Format
++	 *********************************************/
++
+ 	{
+-		//kdDebug() << k_funcinfo << p.exitStatus();
+-		// Exit code 0 NO ERROR on validating.
+-		CHECK( p.exitStatus(), 0 );
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Inbound, Kopete::Message::PlainText);
++		CHECK(Kopete::Message::PlainText, msg.format());
+ 	}
+-	delete contactTo;
+-	delete contactFrom;
++	{
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foobar", Kopete::Message::Inbound, Kopete::Message::RichText);
++		CHECK(Kopete::Message::RichText, msg.format());
++	}
++	{
++		QString m = "foobar";
++		Kopete::Message msg( m_contactFrom, m_contactTo, m, Kopete::Message::Inbound, Kopete::Message::RichText);
++
++		msg.setBody(m, Kopete::Message::PlainText);
++		CHECK(Kopete::Message::PlainText, msg.format());
++
++		msg.setBody(m, Kopete::Message::RichText);
++		CHECK(Kopete::Message::RichText, msg.format());
++
++		msg.setBody(m, Kopete::Message::ParsedHTML);
++		CHECK(Kopete::Message::ParsedHTML, msg.format());
++
++		msg.setBody(m, Kopete::Message::Crypted);
++		CHECK(Kopete::Message::Crypted, msg.format());
++	}
++
++
++	/**********************************************
++	 * setBody()
++	 *********************************************/
++
++	{
++		QString m = "foobar";
++		Kopete::Message msg( m_contactFrom, m_contactTo, m, Kopete::Message::Inbound, Kopete::Message::RichText);
++
++		msg.setBody("NEW", Kopete::Message::PlainText);
++		CHECK(QString("NEW"), msg.plainBody());
++
++		msg.setBody("NEW_NEW", Kopete::Message::RichText);
++		CHECK(QString("NEW_NEW"), msg.plainBody());
++	}
++	{
++		QString m = "foobar";
++		Kopete::Message msg( m_contactFrom, m_contactTo, m, Kopete::Message::Inbound, Kopete::Message::PlainText);
++
++		msg.setBody("NEW", Kopete::Message::PlainText);
++		CHECK(QString("NEW"), msg.plainBody());
++
++		msg.setBody("NEW_NEW", Kopete::Message::RichText);
++		CHECK(QString("NEW_NEW"), msg.plainBody());
++	}
++	{
++		QString m = "<html><head></head><body foo=\"bar\">   <b>HELLO WORLD</b>   </body></html>";
++		Kopete::Message msg( m_contactFrom, m_contactTo, m, Kopete::Message::Inbound, Kopete::Message::PlainText);
++		CHECK(m, msg.plainBody());
++
++		msg.setBody("<simple> SIMPLE", Kopete::Message::PlainText);
++		CHECK(QString("<simple> SIMPLE"), msg.plainBody());
++		CHECK(QString("&lt;simple&gt; SIMPLE"), msg.escapedBody());
++
++		msg.setBody(m, Kopete::Message::RichText);
++
++		// FIXME: Should setBody() also strip extra white space?
++		//CHECK(msg.plainBody(),   QString("HELLO WORLD"));
++		//CHECK(msg.escapedBody(), QString("<b>HELLO WORLD</b>"));
++
++		CHECK(msg.plainBody().stripWhiteSpace(),   QString("HELLO WORLD"));
++		CHECK(msg.escapedBody().stripWhiteSpace(), QString("<b>HELLO WORLD</b>"));
++	}
++	{
++		Kopete::Message msg( m_contactFrom, m_contactTo, "foo", Kopete::Message::Inbound, Kopete::Message::PlainText);
++
++		msg.setBody("<p>foo", Kopete::Message::RichText);
++		CHECK(msg.escapedBody(), QString("foo"));
++
++		msg.setBody("<p>foo</p>", Kopete::Message::RichText);
++		CHECK(msg.escapedBody(), QString("foo"));
++
++		msg.setBody("\n<p>foo</p>\n<br/>", Kopete::Message::RichText);
++		CHECK(msg.escapedBody(), QString("foo<br/>"));
++	}
++
++	/**********************************************
++	 * Copy constructor
++	 *********************************************/
++
++	{
++		Kopete::Message msg1(m_contactFrom, m_contactTo, "foo", Kopete::Message::Inbound, Kopete::Message::RichText);
++		Kopete::Message msg2(msg1);
++
++		CHECK(msg1.plainBody(), msg2.plainBody());
++		CHECK(msg1.escapedBody(), msg2.escapedBody());
++
++		msg1.setBody("NEW", Kopete::Message::PlainText);
++		CHECK(msg1.plainBody(), QString("NEW"));
++		CHECK(msg2.plainBody(), QString("foo"));
++	}
++
++	/**********************************************
++	 * operator=
++	 *********************************************/
++
++	{
++		Kopete::Message msg1(m_contactFrom, m_contactTo, "foo", Kopete::Message::Inbound, Kopete::Message::RichText);
++		{
++			Kopete::Message msg2;
++
++			CHECK(msg2.plainBody(), QString::null);
++
++			msg2 = msg1;
++
++			CHECK(msg1.plainBody(), msg2.plainBody());
++			CHECK(msg1.escapedBody(), msg2.escapedBody());
++
++			msg1.setBody("NEW", Kopete::Message::PlainText);
++			CHECK(msg1.plainBody(), QString("NEW"));
++			CHECK(msg2.plainBody(), QString("foo"));
++		}
++		CHECK(msg1.plainBody(), QString("NEW"));
++
++		msg1 = msg1;
++		CHECK(msg1.plainBody(), QString("NEW"));
++	}
+ }
+ 
+ void KopeteMessage_Test::setup()
+ {
+-	
+ }
+ 
+ void KopeteMessage_Test::testLinkParser()
+@@ -181,12 +294,12 @@
+ 			// otherwise use CHECK
+ 			if ( fileName.section("-", 0, 0) == QString::fromLatin1("broken") )
+ 			{
+-				kdDebug() << "checking known-broken testcase: " << fileName << endl;
++				//kdDebug() << "checking known-broken testcase: " << fileName << endl;
+ 				XFAIL(result, expectedData);
+ 			}
+ 			else
+ 			{
+-				kdDebug() << "checking known-working testcase: " << fileName << endl;
++				//kdDebug() << "checking known-working testcase: " << fileName << endl;
+ 				CHECK(result, expectedData);
+ 			}
+ 		}
+@@ -196,5 +309,6 @@
+ 			continue;
+ 		}
+ 	}
+-	
+ }
++
++// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/libkopete/kopeteprefs.h	(revision 0)
++++ kopete/libkopete/kopeteprefs.h	(revision 586398)
+@@ -0,0 +1,327 @@
++/*
++    kopeteprefs.cpp - Kopete Preferences Container-Class
++
++    Copyright (c) 2002      by Stefan Gehn            <metz AT gehn.net>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#ifndef __KOPETEPREFS_H__
++#define __KOPETEPREFS_H__
++
++#include <qobject.h>
++#include <kdeversion.h>
++#include <qcolor.h>
++#include <qfont.h>
++
++#include "kopete_export.h"
++
++class KConfig;
++
++class KOPETE_EXPORT KopetePrefs : public QObject
++{
++	Q_OBJECT
++	// here so we can use Qt to translate enums<-->strings
++	Q_PROPERTY( ContactDisplayMode contactListDisplayMode READ contactListDisplayMode WRITE setContactListDisplayMode )
++	Q_PROPERTY( IconDisplayMode contactListIconMode READ contactListIconMode WRITE setContactListIconMode )
++        Q_ENUMS( ContactDisplayMode IconDisplayMode )
++
++public:
++	/**
++	 * The prefs container-class is a singleton object. Use this method to retrieve
++	 * the instance.
++	 */
++	static KopetePrefs *prefs();
++
++	/**
++	 * Reads all pref-variables from KConfig
++	 * usually you don't need this as KopetePrefs loads settings
++	 * when an instance is created
++	 */
++	void load();
++
++	/**
++	 * Stores all pref-variables into KConfig
++	 */
++	void save();
++
++	QString iconTheme() const { return mIconTheme; }
++	bool useEmoticons() const { return mUseEmoticons; }
++	bool showOffline() const { return mShowOffline; }
++	bool showEmptyGroups() const { return mShowEmptyGroups; }
++	bool treeView() const { return mTreeView; }
++	bool sortByGroup() const { return mSortByGroup; }
++	bool greyIdleMetaContacts() const { return mGreyIdle; }
++	bool startDocked() const { return mStartDocked; }
++	bool useQueue() const { return mUseQueue; }
++	bool useStack() const { return mUseStack; }
++	bool raiseMsgWindow() const{ return mRaiseMsgWindow; }
++	bool showEvents() const{ return mShowEvents; }
++	bool trayflashNotify() const { return mTrayflashNotify; }
++	bool spellCheck() const { return mSpellCheck; }
++	bool queueUnreadMessages() const { return mQueueUnreadMessages; }
++	bool queueOnlyHighlightedMessagesInGroupChats() const { return mQueueOnlyHighlightedMessagesInGroupChats; }
++	bool queueOnlyMessagesOnAnotherDesktop() const { return mQueueOnlyMessagesOnAnotherDesktop; }
++	bool trayflashNotifyLeftClickOpensMessage() const { return mTrayflashNotifyLeftClickOpensMessage; }
++	bool trayflashNotifySetCurrentDesktopToChatView() const { return mTrayflashNotifySetCurrentDesktopToChatView; }
++	bool balloonNotify() const { return mBalloonNotify; }
++	bool balloonNotifyIgnoreClosesChatView() const { return mBalloonNotifyIgnoreClosesChatView; }
++	bool balloonClose() const { return mBalloonClose; }
++	int balloonCloseDelay() const { return mBalloonCloseDelay; }
++	bool soundIfAway() const { return mSoundIfAway; }
++	int chatViewBufferSize() const { return mChatViewBufferSize; }
++	int rememberedMessages() const { return mRememberedMessages; }
++	const QColor &highlightBackground() const { return mHighlightBackground; }
++	const QColor &highlightForeground() const { return mHighlightForeground; }
++	const QColor &textColor() const { return mTextColor; }
++	const QColor &bgColor() const { return mBgColor; }
++	const QColor &linkColor() const { return mLinkColor; }
++	const QFont &fontFace() const { return mFontFace; }
++	const QColor &idleContactColor() const { return mIdleContactColor; }
++	bool highlightEnabled() const { return mHighlightEnabled; }
++	bool bgOverride() const { return mBgOverride; }
++	bool fgOverride() const { return mFgOverride; }
++	bool rtfOverride() const { return mRtfOverride; }
++
++	QString interfacePreference() const { return mInterfacePreference; }
++	bool showTray() const { return mShowTray; }
++	bool richText() const { return mRichText; }
++	bool chatWShowSend() const { return mChatWShowSend; }
++	bool autoConnect() const { return mAutoConnect; }
++
++	int chatWindowPolicy() const { return mChatWindowPolicy; }
++
++	//Styles
++	QString defaultTheme() const { return QString::fromLatin1("Default"); }
++	//for Adium (xhtml+css)
++	QString stylePath() const { return mStylePath; }
++	QString styleVariant() const { return mStyleVariant; }
++
++	QStringList toolTipContents() const { return mToolTipContents; }
++
++	///
++	enum ContactDisplayMode { Classic, RightAligned, Detailed, Yagami, Default = Classic };
++	///
++	enum IconDisplayMode { IconPic, PhotoPic, IconDefault = IconPic };
++	bool contactListIndentContacts() const { return mContactListIndentContacts; }
++	bool contactListHideVerticalScrollBar() const { return mContactListHideVerticalScrollBar; }
++	ContactDisplayMode contactListDisplayMode() const { return mContactListDisplayMode; }
++	IconDisplayMode contactListIconMode() const { return mContactListIconMode; }
++	bool contactListUseCustomFonts() const { return mContactListUseCustomFonts; }
++	QFont contactListCustomNormalFont() const { return mContactListNormalFont; }
++	QFont contactListCustomSmallFont() const { return mContactListSmallFont; }
++	QFont contactListSmallFont() const;
++	QColor contactListGroupNameColor() const { return mContactListGroupNameColor; }
++	bool contactListAnimation() const { return mContactListAnimation; }
++	bool contactListFading() const { return mContactListFading; }
++	bool contactListFolding() const { return mContactListFolding; }
++	bool contactListMouseNavigation() const { return mContactListMouseNavigation; }
++	bool contactListAutoHide() const { return mContactListAutoHide; }
++	bool contactListAutoHideVScroll() const { return mContactListAutoHideVScroll; }
++	unsigned int contactListAutoHideTimeout() const { return mContactListAutoHideTimeout; }
++
++	bool reconnectOnDisconnect() const { return mReconnectOnDisconnect; }
++
++	bool truncateContactNames() const { return mTruncateContactNames; }
++	int maxConactNameLength() const { return mMaxContactNameLength; }
++	bool emoticonsRequireSpaces() const { return mEmoticonsRequireSpaces; }
++	bool groupConsecutiveMessages() const { return mGroupConsecutiveMessages; }
++
++	void setIconTheme(const QString &value);
++	void setUseEmoticons(bool value);
++	void setShowOffline(bool value);
++	void setShowEmptyGroups(bool value);
++	void setTreeView(bool);
++	void setSortByGroup(bool);
++	void setGreyIdleMetaContacts(bool);
++	void setStartDocked(bool);
++	void setUseQueue(bool);
++	void setUseStack(bool);
++	void setRaiseMsgWindow(bool);
++	void setShowEvents(bool);
++	void setTrayflashNotify(bool);
++	void setSpellCheck(bool);
++	void setQueueUnreadMessages(bool);
++	void setQueueOnlyHighlightedMessagesInGroupChats(bool);
++	void setQueueOnlyMessagesOnAnotherDesktop(bool);
++	void setTrayflashNotifyLeftClickOpensMessage(bool);
++	void setTrayflashNotifySetCurrentDesktopToChatView(bool);
++	void setBalloonNotify(bool);
++	void setBalloonNotifyIgnoreClosesChatView(bool);
++	void setSoundIfAway(bool);
++	void setBeepNotify(bool);
++	void setChatWindowPolicy(int);
++	void setStylePath(const QString &);
++	void setStyleVariant(const QString &);
++	void setChatViewBufferSize(int);
++	void setHighlightBackground(const QColor &);
++	void setHighlightForeground(const QColor &);
++	void setHighlightEnabled(bool);
++	void setBgOverride(bool);
++	void setFgOverride(bool);
++	void setRtfOverride(bool);
++	void setInterfacePreference(const QString &viewPlugin);
++	void setTextColor(const QColor &);
++	void setBgColor(const QColor &);
++	void setLinkColor(const QColor &);
++	void setFontFace(const QFont &);
++	void setIdleContactColor(const QColor &);
++	void setShowTray(bool);
++	void setRichText(bool);
++	void setRememberedMessages(int);
++	void setToolTipContents(const QStringList &);
++	void setContactListIndentContacts( bool v );
++	void setContactListHideVerticalScrollBar( bool v );
++	void setContactListDisplayMode( ContactDisplayMode v );
++	void setContactListIconMode( IconDisplayMode v );
++	void setContactListUseCustomFonts( bool v );
++	void setContactListCustomNormalFont( const QFont & v );
++	void setContactListCustomSmallFont( const QFont & v );
++	void setContactListGroupNameColor( const QColor & v );
++	void setContactListAnimation( bool );
++	void setContactListFading( bool );
++	void setContactListFolding( bool );
++	void setContactListMouseNavigation( bool );
++	void setContactListAutoHide( bool );
++	void setContactListAutoHideVScroll( bool );
++	void setContactListAutoHideTimeout( unsigned int );
++	void setReconnectOnDisconnect( bool newSetting );
++	void setTruncateContactNames( bool );
++	void setMaxContactNameLength( int );
++	void setAutoConnect( bool );
++	void setEmoticonsRequireSpaces( bool );
++	void setBalloonClose( bool );
++	void setBalloonDelay( int );
++	void setGroupConsecutiveMessages( bool );
++
++signals:
++	/**
++	 * Emitted when config gets saved by save()
++	 */
++	void saved();
++	/**
++	 * Emitted when config gets saved by save() and a certain
++	 * setting has changed.
++	 * Naming scheme is the same as with the config vars.
++	 */
++	void windowAppearanceChanged();
++	void messageAppearanceChanged();
++	void contactListAppearanceChanged();
++	/**
++	 * Emitted when chat Window Style changed.
++	 * @param stylePath New stylePath
++	 */
++	void styleChanged(const QString &stylePath);
++	/**
++	 * Emitted when ChatWindowStyle variant changed.
++	 * @param variantPath New variant Path.
++	 */
++	void styleVariantChanged(const QString &variantPath);
++
++private:
++	/**
++	 * Private constructor: we are a singleton
++	 */
++	KopetePrefs();
++
++	/**
++	 * Our instance
++	 */
++	static KopetePrefs *s_prefs;
++
++	KConfig *config;
++
++	QString mIconTheme;
++	bool mUseEmoticons;
++	bool mShowOffline;
++	bool mShowEmptyGroups;
++	bool mGreyIdle;
++	bool mTreeView;
++	bool mSortByGroup;
++	bool mStartDocked;
++	bool mUseQueue;
++	bool mUseStack;
++	bool mRaiseMsgWindow;
++	bool mShowEvents;
++	bool mTrayflashNotify;
++	bool mSpellCheck;
++	bool mQueueUnreadMessages;
++	bool mQueueOnlyHighlightedMessagesInGroupChats;
++	bool mQueueOnlyMessagesOnAnotherDesktop;
++	bool mTrayflashNotifyLeftClickOpensMessage;
++	bool mTrayflashNotifySetCurrentDesktopToChatView;
++	bool mBalloonNotify;
++	bool mBalloonNotifyIgnoreClosesChatView;
++	bool mBalloonClose;
++	int mBalloonCloseDelay;
++	bool mSoundIfAway;
++	int mRememberedMessages;
++	QString mInterfacePreference;
++	int mChatViewBufferSize;
++	QColor mHighlightBackground;
++	QColor mHighlightForeground;
++	QColor mTextColor;
++	QColor mBgColor;
++	QColor mLinkColor;
++	QFont mFontFace;
++	QColor mIdleContactColor;
++	bool mHighlightEnabled;
++	bool mBgOverride;
++	bool mFgOverride;
++	bool mRtfOverride;
++	bool mShowTray;
++	bool mWindowAppearanceChanged;
++	bool mMessageAppearanceChanged;
++	bool mContactListAppearanceChanged;
++	bool mChatWShowSend;
++	bool mAutoConnect;
++
++	int mChatWindowPolicy;
++
++	bool mTruncateContactNames;
++	int mMaxContactNameLength;
++
++	bool mRichText;
++
++	// xhtml+css
++	//for Adium (xhtml+css)
++	QString mStylePath;
++	QString mStyleVariant;
++	bool mStylePathChanged;
++	bool mStyleVariantChanged;
++
++	QStringList mToolTipContents;
++
++	bool mContactListIndentContacts;
++	bool mContactListHideVerticalScrollBar;
++	ContactDisplayMode mContactListDisplayMode;
++	IconDisplayMode mContactListIconMode;
++	bool mContactListUseCustomFonts;
++	QFont mContactListNormalFont;
++	QFont mContactListSmallFont;
++	QColor mContactListGroupNameColor;
++	bool mContactListAnimation;
++	bool mContactListFading;
++	bool mContactListFolding;
++	bool mContactListMouseNavigation;
++	bool mContactListAutoHide;
++	bool mContactListAutoHideVScroll;
++	unsigned int mContactListAutoHideTimeout;
++
++	bool mReconnectOnDisconnect;
++	bool mEmoticonsRequireSpaces;
++	bool mGroupConsecutiveMessages;
++
++	QString fileContents(const QString &path);
++	void _setStylePath (const QString &);
++};
++#endif
++// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/libkopete/knotification.cpp	(revision 568672)
++++ kopete/libkopete/knotification.cpp	(revision 586398)
+@@ -18,6 +18,7 @@
+ 
+ #include "knotification.h"
+ 
++#include <kdebug.h>
+ #include <kapplication.h>
+ #include <knotifyclient.h>
+ #include <kmessagebox.h>
+@@ -65,11 +66,11 @@
+ KNotification::KNotification(QObject *parent) :
+ 		QObject(parent) , d(new Private)
+ {
++	m_linkClicked = false;
+ }
+ 
+ KNotification::~KNotification() 
+ {
+-	emit closed();
+ 	delete d;
+ }
+ 
+@@ -228,17 +229,23 @@
+ 
+ void KNotification::slotPopupLinkClicked(const QString &adr)
+ {
++	m_linkClicked = true;
+ 	unsigned int action=adr.toUInt();
+ 	if(action==0)
+ 		return;
+ 
+ 	activate(action);
++
++	// since we've hidden the message (KNotification::notifyByPassivePopup(const QPixmap &pix ))
++	// we must now schedule overselves for deletion
++	close();
+ }
+ 
+ void KNotification::activate(unsigned int action)
+ {
+ 	if(action==0)
+ 		emit activated();
++
+ 	emit activated(action);
+ 	deleteLater();
+ }
+@@ -246,6 +253,14 @@
+ 
+ void KNotification::close()
+ {
++	// if the user hasn't clicked the link, and if we got here, it means the dialog closed
++	// and we were ignored
++	if (!m_linkClicked)
++	{
++		emit ignored();
++	}
++
++	emit closed();
+ 	deleteLater();
+ }
+ 
+--- kopete/libkopete/compat/kpixmapregionselectordialog.cpp	(revision 0)
++++ kopete/libkopete/compat/kpixmapregionselectordialog.cpp	(revision 586398)
+@@ -0,0 +1,127 @@
++/* This file is part of the KDE libraries
++    Copyright (C) 2004 Antonio Larrosa <larrosa at kde.org
++
++    This library is free software; you can redistribute it and/or
++    modify it under the terms of the GNU Library General Public
++    License as published by the Free Software Foundation; either
++    version 2 of the License, or (at your option) any later version.
++
++    This library is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++    Library General Public License for more details.
++
++    You should have received a copy of the GNU Library General Public License
++    along with this library; see the file COPYING.LIB.  If not, write to
++    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++    Boston, MA 02110-1301, USA.
++*/
++
++#include "kpixmapregionselectordialog.h"
++#include <kdialogbase.h>
++#include <qdialog.h>
++#include <qdesktopwidget.h>
++#include <klocale.h>
++#include <kdialog.h>
++
++KPixmapRegionSelectorDialog::KPixmapRegionSelectorDialog(QWidget *parent,
++     const char *name, bool modal ) : KDialogBase(parent, name, modal, i18n("Select Region of Image"), Help|Ok|Cancel, Ok, true )
++{
++  QVBox *vbox=new QVBox(this);
++  new QLabel(i18n("Please click and drag on the image to select the region of interest:"), vbox);
++  m_pixmapSelectorWidget= new KPixmapRegionSelectorWidget(vbox);
++
++  vbox->setSpacing( KDialog::spacingHint() );
++
++  setMainWidget(vbox);
++}
++
++KPixmapRegionSelectorDialog::~KPixmapRegionSelectorDialog()
++{
++}
++
++QRect KPixmapRegionSelectorDialog::getSelectedRegion(const QPixmap &pixmap, QWidget *parent )
++{
++  KPixmapRegionSelectorDialog dialog(parent);
++
++  dialog.pixmapRegionSelectorWidget()->setPixmap(pixmap);
++
++  QDesktopWidget desktopWidget;
++  QRect screen=desktopWidget.availableGeometry();
++  dialog.pixmapRegionSelectorWidget()->setMaximumWidgetSize(
++        (int)(screen.width()*4.0/5), (int)(screen.height()*4.0/5));
++
++  int result = dialog.exec();
++
++  QRect rect;
++
++  if ( result == QDialog::Accepted )
++    rect = dialog.pixmapRegionSelectorWidget()->unzoomedSelectedRegion();
++
++  return rect;
++}
++
++QRect KPixmapRegionSelectorDialog::getSelectedRegion(const QPixmap &pixmap, int aspectRatioWidth, int aspectRatioHeight, QWidget *parent )
++{
++  KPixmapRegionSelectorDialog dialog(parent);
++
++  dialog.pixmapRegionSelectorWidget()->setPixmap(pixmap);
++  dialog.pixmapRegionSelectorWidget()->setSelectionAspectRatio(aspectRatioWidth,aspectRatioHeight);
++
++  QDesktopWidget desktopWidget;
++  QRect screen=desktopWidget.availableGeometry();
++  dialog.pixmapRegionSelectorWidget()->setMaximumWidgetSize(
++        (int)(screen.width()*4.0/5), (int)(screen.height()*4.0/5));
++
++  int result = dialog.exec();
++
++  QRect rect;
++
++  if ( result == QDialog::Accepted )
++    rect = dialog.pixmapRegionSelectorWidget()->unzoomedSelectedRegion();
++
++  return rect;
++}
++
++QImage KPixmapRegionSelectorDialog::getSelectedImage(const QPixmap &pixmap, QWidget *parent )
++{
++  KPixmapRegionSelectorDialog dialog(parent);
++
++  dialog.pixmapRegionSelectorWidget()->setPixmap(pixmap);
++
++  QDesktopWidget desktopWidget;
++  QRect screen=desktopWidget.availableGeometry();
++  dialog.pixmapRegionSelectorWidget()->setMaximumWidgetSize(
++        (int)(screen.width()*4.0/5), (int)(screen.height()*4.0/5));
++  int result = dialog.exec();
++
++  QImage image;
++
++  if ( result == QDialog::Accepted )
++    image = dialog.pixmapRegionSelectorWidget()->selectedImage();
++
++  return image;
++}
++
++QImage KPixmapRegionSelectorDialog::getSelectedImage(const QPixmap &pixmap, int aspectRatioWidth, int aspectRatioHeight, QWidget *parent )
++{
++  KPixmapRegionSelectorDialog dialog(parent);
++
++  dialog.pixmapRegionSelectorWidget()->setPixmap(pixmap);
++  dialog.pixmapRegionSelectorWidget()->setSelectionAspectRatio(aspectRatioWidth,aspectRatioHeight);
++
++  QDesktopWidget desktopWidget;
++  QRect screen=desktopWidget.availableGeometry();
++  dialog.pixmapRegionSelectorWidget()->setMaximumWidgetSize(
++        (int)(screen.width()*4.0/5), (int)(screen.height()*4.0/5));
++
++  int result = dialog.exec();
++
++  QImage image;
++
++  if ( result == QDialog::Accepted )
++    image = dialog.pixmapRegionSelectorWidget()->selectedImage();
++
++  return image;
++}
++
+--- kopete/libkopete/compat/kpixmapregionselectorwidget.cpp	(revision 0)
++++ kopete/libkopete/compat/kpixmapregionselectorwidget.cpp	(revision 586398)
+@@ -0,0 +1,450 @@
++/* This file is part of the KDE libraries
++    Copyright (C) 2004 Antonio Larrosa <larrosa at kde.org
++
++    This library is free software; you can redistribute it and/or
++    modify it under the terms of the GNU Library General Public
++    License as published by the Free Software Foundation; either
++    version 2 of the License, or (at your option) any later version.
++
++    This library is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++    Library General Public License for more details.
++
++    You should have received a copy of the GNU Library General Public License
++    along with this library; see the file COPYING.LIB.  If not, write to
++    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++    Boston, MA 02110-1301, USA.
++*/
++
++/* NOTE: There are two copies of this .h and the .cpp file, with subtle differences.
++ * One copy is in kdelibs/kdeui, and the other copy is in kdepim/libkdepim
++ * This is because kdepim has to remain backwards compatible.  Any changes
++ * to either file should be made to the other.
++ */
++
++#include "kpixmapregionselectorwidget.h"
++#include <qpainter.h>
++#include <qcolor.h>
++#include <qimage.h>
++#include <qlayout.h>
++#include <kimageeffect.h>
++#include <kdebug.h>
++#include <klocale.h>
++#include <kpopupmenu.h>
++#include <kaction.h>
++#include <stdlib.h>
++#include <qcursor.h>
++#include <qapplication.h>
++
++KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( QWidget *parent, 
++      const char *name) : QWidget( parent, name)
++{
++   QHBoxLayout * hboxLayout=new QHBoxLayout( this );
++   
++   hboxLayout->addStretch();
++   QVBoxLayout * vboxLayout=new QVBoxLayout( hboxLayout );
++
++   vboxLayout->addStretch();
++   m_label = new QLabel(this, "pixmapHolder");
++   m_label->setBackgroundMode( Qt::NoBackground );
++   m_label->installEventFilter( this );
++
++   vboxLayout->addWidget(m_label);
++   vboxLayout->addStretch();
++
++   hboxLayout->addStretch();
++
++   m_forcedAspectRatio=0;
++
++   m_zoomFactor=1.0;
++}
++
++KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget()
++{
++}
++
++void KPixmapRegionSelectorWidget::setPixmap( const QPixmap &pixmap )
++{
++   Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps.
++   m_originalPixmap = pixmap;
++   m_unzoomedPixmap = pixmap;
++   m_label->setPixmap( pixmap );
++   resetSelection();
++}
++
++void KPixmapRegionSelectorWidget::resetSelection()
++{
++   m_selectedRegion = m_originalPixmap.rect();
++   updatePixmap();
++}
++
++QRect KPixmapRegionSelectorWidget::selectedRegion() const
++{
++     return m_selectedRegion;
++}
++
++void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect)
++{
++   if (!rect.isValid()) resetSelection();
++   else 
++   {
++      m_selectedRegion=rect;
++      updatePixmap();
++
++      QRect r=unzoomedSelectedRegion();
++   }
++}
++
++void KPixmapRegionSelectorWidget::updatePixmap()
++{
++   Q_ASSERT(!m_originalPixmap.isNull()); if(m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; }
++   if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() );
++   if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() );
++
++   QPainter painter;
++   if (m_linedPixmap.isNull())
++   {
++     m_linedPixmap = m_originalPixmap;
++
++     painter.begin(&m_linedPixmap);
++     painter.setRasterOp( Qt::XorROP );
++     painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(), 
++                  QBrush( QColor(255,255,255), Qt::BDiagPattern) );
++     painter.end();
++
++     QImage image=m_linedPixmap.convertToImage();
++     image=KImageEffect::fade(image, (float)0.4, QColor(0,0,0));
++     m_linedPixmap.convertFromImage(image);
++   } 
++
++   QPixmap pixmap = m_linedPixmap;
++
++   painter.begin(&pixmap);
++   painter.drawPixmap( m_selectedRegion.topLeft(), 
++        m_originalPixmap, m_selectedRegion );
++
++   painter.setPen( QColor(255,255,255) );
++   painter.setRasterOp( Qt::XorROP );
++
++   painter.drawRect( m_selectedRegion );
++
++   painter.end();
++
++   m_label->setPixmap(pixmap);
++}
++
++
++KPopupMenu *KPixmapRegionSelectorWidget::createPopupMenu()
++{
++   KPopupMenu *popup=new KPopupMenu(this, "PixmapRegionSelectorPopup");
++   popup->insertTitle(i18n("Image Operations"));
++   
++   KAction *action = new KAction(i18n("&Rotate Clockwise"), "rotate_cw",
++                                0, this, SLOT(rotateClockwise()),
++                                popup, "rotateclockwise");
++   action->plug(popup);
++
++   action = new KAction(i18n("Rotate &Counterclockwise"), "rotate_ccw",
++                                0, this, SLOT(rotateCounterclockwise()),
++                                popup, "rotatecounterclockwise");
++   action->plug(popup);
++ 
++/*
++   I wonder if it would be appropiate to have here an "Open with..." option to
++   edit the image (antlarr)
++*/
++   return popup;
++}
++
++void KPixmapRegionSelectorWidget::rotate(KImageEffect::RotateDirection direction)
++{
++   int w=m_originalPixmap.width();
++   int h=m_originalPixmap.height();
++   QImage img=m_unzoomedPixmap.convertToImage();
++   img= KImageEffect::rotate(img, direction);
++   m_unzoomedPixmap.convertFromImage(img);
++
++   img=m_originalPixmap.convertToImage();
++   img= KImageEffect::rotate(img, direction);
++   m_originalPixmap.convertFromImage(img);
++
++   m_linedPixmap=QPixmap();
++
++   if (m_forcedAspectRatio>0 && m_forcedAspectRatio!=1) 
++      resetSelection();
++   else
++   {
++      switch (direction)
++      {
++         case ( KImageEffect::Rotate90 ):
++            {
++              int x=h-m_selectedRegion.y()-m_selectedRegion.height();
++              int y=m_selectedRegion.x();
++              m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
++              updatePixmap();
++            } break;
++         case ( KImageEffect::Rotate270 ):
++            {
++              int x=m_selectedRegion.y();
++              int y=w-m_selectedRegion.x()-m_selectedRegion.width();
++              m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
++              updatePixmap();
++            } break;
++         default: resetSelection();
++      }
++   }
++}
++
++void KPixmapRegionSelectorWidget::rotateClockwise()
++{
++   rotate(KImageEffect::Rotate90);
++}
++
++void KPixmapRegionSelectorWidget::rotateCounterclockwise()
++{
++   rotate(KImageEffect::Rotate270);
++}
++
++bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev)
++{
++   if ( ev->type() == QEvent::MouseButtonPress )
++   {
++      QMouseEvent *mev= (QMouseEvent *)(ev);
++      //kdDebug() << QString("click at  %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
++
++      if ( mev->button() == RightButton )
++      {
++         KPopupMenu *popup = createPopupMenu( );
++         popup->exec( mev->globalPos() );
++         delete popup;
++         return TRUE;
++      };
++
++      QCursor cursor;
++
++      if ( m_selectedRegion.contains( mev->pos() ) 
++          && m_selectedRegion!=m_originalPixmap.rect() )
++      {
++         m_state=Moving;
++         cursor.setShape( Qt::SizeAllCursor );
++      }
++      else
++      {
++         m_state=Resizing;
++         cursor.setShape( Qt::CrossCursor );
++      }
++      QApplication::setOverrideCursor(cursor);
++
++      m_tempFirstClick=mev->pos();
++      
++
++      return TRUE;
++   }
++
++   if ( ev->type() == QEvent::MouseMove )
++   {
++      QMouseEvent *mev= (QMouseEvent *)(ev);
++
++      //kdDebug() << QString("move to  %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
++      
++      if ( m_state == Resizing )
++      {
++         setSelectedRegion ( 
++              calcSelectionRectangle( m_tempFirstClick, mev->pos() ) );
++      }
++      else if (m_state == Moving )
++      {
++         int mevx = mev->x();
++         int mevy = mev->y();
++         bool mouseOutside=false;
++         if ( mevx < 0 ) 
++         {
++           m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
++           mouseOutside=true;
++         }
++         else if ( mevx > m_originalPixmap.width() )
++         {
++           m_selectedRegion.moveBy(m_originalPixmap.width()-m_selectedRegion.width()-m_selectedRegion.x(),0);
++           mouseOutside=true;
++         }
++         if ( mevy < 0 ) 
++         {
++           m_selectedRegion.moveBy(0,-m_selectedRegion.y());
++           mouseOutside=true;
++         }
++         else if ( mevy > m_originalPixmap.height() )
++         {
++           m_selectedRegion.moveBy(0,m_originalPixmap.height()-m_selectedRegion.height()-m_selectedRegion.y());
++           mouseOutside=true;
++         }
++         if (mouseOutside) { updatePixmap(); return TRUE; };
++
++         m_selectedRegion.moveBy( mev->x()-m_tempFirstClick.x(),
++                                  mev->y()-m_tempFirstClick.y() );
++
++         // Check that the region has not fallen outside the image
++         if (m_selectedRegion.x() < 0)
++            m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
++         else if (m_selectedRegion.right() > m_originalPixmap.width())
++            m_selectedRegion.moveBy(-(m_selectedRegion.right()-m_originalPixmap.width()),0); 
++
++         if (m_selectedRegion.y() < 0) 
++            m_selectedRegion.moveBy(0,-m_selectedRegion.y());
++         else if (m_selectedRegion.bottom() > m_originalPixmap.height()) 
++            m_selectedRegion.moveBy(0,-(m_selectedRegion.bottom()-m_originalPixmap.height()));
++
++         m_tempFirstClick=mev->pos();
++         updatePixmap();
++      } 
++      return TRUE;
++   }
++
++   if ( ev->type() == QEvent::MouseButtonRelease )
++   {
++      QMouseEvent *mev= (QMouseEvent *)(ev);
++
++      if ( m_state == Resizing && mev->pos() == m_tempFirstClick)
++         resetSelection();
++
++      m_state=None;
++      QApplication::restoreOverrideCursor(); 
++
++      return TRUE;
++   }
++
++   QWidget::eventFilter(obj, ev);
++   return FALSE;
++}
++
++QRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const QPoint & startPoint, const QPoint & _endPoint )
++{
++   QPoint endPoint = _endPoint;
++   if ( endPoint.x() < 0 ) endPoint.setX(0);
++   else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width());
++   if ( endPoint.y() < 0 ) endPoint.setY(0);
++   else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height());
++   int w=abs(startPoint.x()-endPoint.x());
++   int h=abs(startPoint.y()-endPoint.y());
++
++   if (m_forcedAspectRatio>0)
++   {
++      double aspectRatio=w/double(h);
++
++      if (aspectRatio>m_forcedAspectRatio) 
++         h=(int)(w/m_forcedAspectRatio);
++      else
++         w=(int)(h*m_forcedAspectRatio);
++   }
++
++   int x,y;
++   if ( startPoint.x() < endPoint.x() )
++     x=startPoint.x();
++   else
++     x=startPoint.x()-w;
++   if ( startPoint.y() < endPoint.y() )
++     y=startPoint.y();
++   else
++     y=startPoint.y()-h;
++
++   if (x<0)
++   {
++      w+=x;
++      x=0;
++      h=(int)(w/m_forcedAspectRatio);
++
++      if ( startPoint.y() > endPoint.y() )
++        y=startPoint.y()-h;
++   }
++   else if (x+w>m_originalPixmap.width())
++   {
++      w=m_originalPixmap.width()-x;
++      h=(int)(w/m_forcedAspectRatio);
++
++      if ( startPoint.y() > endPoint.y() )
++        y=startPoint.y()-h;
++   }
++   if (y<0)
++   {
++      h+=y;
++      y=0;
++      w=(int)(h*m_forcedAspectRatio);
++
++      if ( startPoint.x() > endPoint.x() )
++        x=startPoint.x()-w;
++   }
++   else if (y+h>m_originalPixmap.height())
++   {
++      h=m_originalPixmap.height()-y;
++      w=(int)(h*m_forcedAspectRatio);
++
++      if ( startPoint.x() > endPoint.x() )
++        x=startPoint.x()-w;
++   }
++
++   return QRect(x,y,w,h);
++}
++
++QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const
++{
++  return QRect((int)(m_selectedRegion.x()/m_zoomFactor),
++               (int)(m_selectedRegion.y()/m_zoomFactor),
++               (int)(m_selectedRegion.width()/m_zoomFactor),
++               (int)(m_selectedRegion.height()/m_zoomFactor));
++}
++
++QImage KPixmapRegionSelectorWidget::selectedImage() const
++{
++   QImage origImage=m_unzoomedPixmap.convertToImage();
++   return origImage.copy(unzoomedSelectedRegion());
++}
++
++void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height)
++{
++   m_forcedAspectRatio=width/double(height);
++}
++
++void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio()
++{
++   m_forcedAspectRatio=0;
++}
++
++void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height)
++{
++   m_maxWidth=width;
++   m_maxHeight=height;
++
++   m_originalPixmap=m_unzoomedPixmap;
++   if (m_selectedRegion == m_originalPixmap.rect()) m_selectedRegion=QRect();
++
++//   kdDebug() << QString(" original Pixmap :") << m_originalPixmap.rect() << endl;
++//   kdDebug() << QString(" unzoomed Pixmap : %1 x %2 ").arg(m_unzoomedPixmap.width()).arg(m_unzoomedPixmap.height()) << endl;
++
++   if ( !m_originalPixmap.isNull() &&
++       ( m_originalPixmap.width() > m_maxWidth || 
++         m_originalPixmap.height() > m_maxHeight ) )
++   {
++         /* We have to resize the pixmap to get it complete on the screen */
++         QImage image=m_originalPixmap.convertToImage();
++         m_originalPixmap.convertFromImage( image.smoothScale( width, height, QImage::ScaleMin ) );
++         double oldZoomFactor = m_zoomFactor;
++         m_zoomFactor=m_originalPixmap.width()/(double)m_unzoomedPixmap.width();
++
++         if (m_selectedRegion.isValid())
++         {
++            m_selectedRegion=
++                  QRect((int)(m_selectedRegion.x()*m_zoomFactor/oldZoomFactor),
++                        (int)(m_selectedRegion.y()*m_zoomFactor/oldZoomFactor),
++                        (int)(m_selectedRegion.width()*m_zoomFactor/oldZoomFactor),
++                        (int)(m_selectedRegion.height()*m_zoomFactor/oldZoomFactor) );
++         }
++   }
++   
++   if (!m_selectedRegion.isValid()) m_selectedRegion = m_originalPixmap.rect();
++
++   m_linedPixmap=QPixmap();
++   updatePixmap();
++   resize(m_label->width(), m_label->height());
++}
++
++#include "kpixmapregionselectorwidget.moc"
+--- kopete/libkopete/compat/kpixmapregionselectordialog.h	(revision 0)
++++ kopete/libkopete/compat/kpixmapregionselectordialog.h	(revision 586398)
+@@ -0,0 +1,107 @@
++/* This file is part of the KDE libraries
++    Copyright (C) 2004 Antonio Larrosa <larrosa at kde.org
++
++    This library is free software; you can redistribute it and/or
++    modify it under the terms of the GNU Library General Public
++    License as published by the Free Software Foundation; either
++    version 2 of the License, or (at your option) any later version.
++
++    This library is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++    Library General Public License for more details.
++
++    You should have received a copy of the GNU Library General Public License
++    along with this library; see the file COPYING.LIB.  If not, write to
++    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++    Boston, MA 02110-1301, USA.
++*/
++
++#ifndef __KPIXMAPREGIONSELECTORDIALOG_H__
++#define __KPIXMAPREGIONSELECTORDIALOG_H__
++
++#include <qimage.h>
++
++#include <kdialogbase.h>
++#include <kpixmapregionselectorwidget.h>
++
++/**
++ * A dialog that uses a KPixmapRegionSelectorWidget to allow the user
++ * to select a region of an image. If you want to use special features
++ * like forcing the selected area to have a fixed aspect ratio, you can use
++ * @see pixmapRegionSelectorWidget() to get the pointer to the 
++ * KPixmapRegionSelectorWidget object and set the desired options there.
++ * 
++ * There are some convenience methods that allow to easily show a dialog
++ * for the user to select a region of an image, and just care about the selected
++ * image.
++ *
++ * @author Antonio Larrosa <larrosa at kde.org>
++ * @since 3.4
++ */ 
++class KOPETE_EXPORT KPixmapRegionSelectorDialog : public KDialogBase
++{
++public:
++   /**
++    * The constructor of an empty KPixmapRegionSelectorDialog, you have to call
++    * later the setPixmap method of the KPixmapRegionSelectorWidget widget of
++    * the new object.
++    */
++   KPixmapRegionSelectorDialog(QWidget *parent=0L, const char *name=0L,
++                      bool modal = false );
++   /**
++    * The destructor of the dialog
++    */
++   ~KPixmapRegionSelectorDialog();
++
++   /**
++    * @returns the KPixmapRegionSelectorWidget widget so that additional
++    * parameters can be set by using it.
++    */
++   KPixmapRegionSelectorWidget *pixmapRegionSelectorWidget() const 
++      { return m_pixmapSelectorWidget; };
++   
++   /**
++    * Creates a modal dialog, lets the user to select a region of the @p pixmap
++    * and returns when the dialog is closed.
++    *
++    * @returns the selected rectangle, or an invalid rectangle if the user 
++    * pressed the Cancel button.
++    */
++   static QRect getSelectedRegion(const QPixmap &pixmap, QWidget *parent = 0L );
++
++   /**
++    * Creates a modal dialog, lets the user to select a region of the @p pixmap
++    * with the same aspect ratio than @p aspectRatioWidth x @p aspectRatioHeight
++    * and returns when the dialog is closed.
++    *
++    * @returns the selected rectangle, or an invalid rectangle if the user 
++    * pressed the Cancel button.
++    */
++   static QRect getSelectedRegion(const QPixmap &pixmap, int aspectRatioWidth, int aspectRatioHeight, QWidget *parent = 0L );
++
++   /**
++    * Creates a modal dialog, lets the user to select a region of the @p pixmap
++    * and returns when the dialog is closed.
++    *
++    * @returns the selected image, or an invalid image if the user 
++    * pressed the Cancel button.
++    */
++   static QImage getSelectedImage(const QPixmap &pixmap, QWidget *parent = 0L );
++
++   /**
++    * Creates a modal dialog, lets the user to select a region of the @p pixmap
++    * with the same aspect ratio than @p aspectRatioWidth x @p aspectRatioHeight
++    * and returns when the dialog is closed.
++    *
++    * @returns the selected image, or an invalid image if the user 
++    * pressed the Cancel button.
++    */
++   static QImage getSelectedImage(const QPixmap &pixmap, int aspectRatioWidth, int aspectRatioHeight, QWidget *parent = 0L );
++
++protected:
++   KPixmapRegionSelectorWidget *m_pixmapSelectorWidget;
++};
++
++
++#endif
+--- kopete/libkopete/compat/kpixmapregionselectorwidget.h	(revision 0)
++++ kopete/libkopete/compat/kpixmapregionselectorwidget.h	(revision 586398)
+@@ -0,0 +1,170 @@
++/* This file is part of the KDE libraries
++    Copyright (C) 2004 Antonio Larrosa <larrosa at kde.org
++
++    This library is free software; you can redistribute it and/or
++    modify it under the terms of the GNU Library General Public
++    License as published by the Free Software Foundation; either
++    version 2 of the License, or (at your option) any later version.
++
++    This library is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++    Library General Public License for more details.
++
++    You should have received a copy of the GNU Library General Public License
++    along with this library; see the file COPYING.LIB.  If not, write to
++    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++    Boston, MA 02110-1301, USA.
++*/
++
++#ifndef __KPIXMAPREGIONSELECTORWIDGET_H__
++#define __KPIXMAPREGIONSELECTORWIDGET_H__
++#include <qvbox.h>
++#include <qpixmap.h>
++#include <qrect.h>
++#include <qlabel.h>
++#include <kimageeffect.h>
++
++class KPopupMenu;
++
++#include "kopete_export.h"
++
++/**
++ * KPixmapRegionSelectorWidget is a widget that shows a picture and provides the
++ * user with a friendly way to select a rectangular subregion of the pixmap.
++ *
++ * NOTE: There are two copies of this .h and the .cpp file, with subtle differences.
++ * One copy is in kdelibs/kdeui, and the other copy is in kdepim/libkdepim
++ * This is because kdepim has to remain backwards compatible.  Any changes
++ * to either file should be made to the other.
++ *
++ * @author Antonio Larrosa <larrosa at kde.org>
++ * @since 3.4
++ */
++class KOPETE_EXPORT KPixmapRegionSelectorWidget : public QWidget
++{
++   Q_OBJECT
++public:
++   /**
++    * Constructor for a KPixmapRegionSelectorWidget.
++    */
++   KPixmapRegionSelectorWidget( QWidget *parent = 0L, const char *name=0L);
++
++   /**
++    * Destructor for a KPixmapRegionSelectorWidget
++    */
++   ~KPixmapRegionSelectorWidget();
++
++   /**
++    * Sets the pixmap which will be shown for the user to select a region from.
++    * @param pixmap The pixmap.  Must be non-null.
++    * 
++    */
++   void setPixmap( const QPixmap &pixmap );
++
++   /**
++    * @return the original whole pixmap that we're using in this widget as the
++    * pixmap the user is selecting a region from.
++    */
++   QPixmap pixmap() const { return m_unzoomedPixmap; };
++
++   /**
++    * Sets the selected region to be @p rect (in zoomed pixmap coordinates)
++    */
++   void setSelectedRegion(const QRect &rect);
++
++   /**
++    * Returns the selected region ( in zoomed pixmap coordinates )
++    */
++   QRect selectedRegion() const;
++
++   /**
++    * Returns the selected region ( in unzoomed, original pixmap coordinates )
++    */
++   QRect unzoomedSelectedRegion() const;
++
++   /**
++    * Resets the selection to use the whole image
++    */
++   void resetSelection();
++
++   /**
++    * @returns a QImage object with just the region the user selected from the
++    * image
++    */
++   QImage selectedImage() const;
++
++   /**
++    * Sets the aspect ration that the selected subimage should have. The way to
++    * select it, is specifying an example valid @p width and @p height.
++    * @see setFreeSelectionAspectRatio()
++    */
++   void setSelectionAspectRatio(int width, int height);
++
++   /**
++    * Allows the user to do a selection which has any aspect ratio. This is
++    * the default.
++    * @see setSelectionAspectRatio()
++    */
++   void setFreeSelectionAspectRatio();
++ 
++   /**
++    * Sets the maximum size for the widget. If the image is larger than this
++    * (either horizontally or vertically), it's scaled to adjust to the maximum
++    * size (preserving the aspect ratio)
++    */
++   void setMaximumWidgetSize( int width, int height );
++
++   /**
++    * Rotates the image as specified by the @p direction parameter, also tries
++    * to rotate the selected region so that it doesn't change, as long as the
++    * forced aspect ratio setting is respected, in other case, the selected region
++    * is resetted.
++    */
++   void rotate(KImageEffect::RotateDirection direction);
++
++public slots:
++   /**
++    * Rotates the current image 90º clockwise
++    */
++   void rotateClockwise();
++   /**
++    * Rotates the current image 90º counterclockwise
++    */
++   void rotateCounterclockwise();
++
++protected:
++   /**
++    * Creates a KPopupMenu with the menu that appears when clicking with the right button on the label
++    */
++   virtual KPopupMenu *createPopupMenu();
++
++private:
++   bool eventFilter(QObject *obj, QEvent *ev);
++
++   /**
++    * Recalculates the pixmap that is shown based on the current selected area,
++    * the original image, etc. 
++    */
++   void updatePixmap();
++
++   QRect calcSelectionRectangle( const QPoint &startPoint, const QPoint & endPoint );
++
++   enum CursorState { None=0, Resizing, Moving };
++   CursorState m_state;
++
++   QPixmap m_unzoomedPixmap;
++   QPixmap m_originalPixmap;
++   QPixmap m_linedPixmap;
++   QRect   m_selectedRegion;
++   QLabel *m_label;
++
++   QPoint m_tempFirstClick;
++   double m_forcedAspectRatio;
++
++   int m_maxWidth, m_maxHeight;
++   double m_zoomFactor;
++};
++
++#endif
++
+--- kopete/libkopete/compat/Makefile.am	(revision 0)
++++ kopete/libkopete/compat/Makefile.am	(revision 586398)
+@@ -0,0 +1,8 @@
++METASOURCES = AUTO
++AM_CPPFLAGS = $(KOPETE_INCLUDES) $(all_includes)
++noinst_LTLIBRARIES = libkopetecompat.la
++
++libkopetecompat_la_SOURCES = kpixmapregionselectordialog.cpp kpixmapregionselectorwidget.cpp
++libkopetecompat_la_LDFLAGS = -no-undefined $(all_libraries)
++libkopetecompat_la_LIBADD  = $(LIB_KDEUI) $(LIB_KDECORE)
++
+--- kopete/libkopete/kopeteversion.h	(revision 568672)
++++ kopete/libkopete/kopeteversion.h	(revision 586398)
+@@ -14,10 +14,10 @@
+ #ifndef _KOPETE_VERSION_H_
+ #define _KOPETE_VERSION_H_
+ 
+-#define KOPETE_VERSION_STRING "0.11.3"
++#define KOPETE_VERSION_STRING "0.12.2"
+ #define KOPETE_VERSION_MAJOR 0
+-#define KOPETE_VERSION_MINOR 11
+-#define KOPETE_VERSION_RELEASE 3
++#define KOPETE_VERSION_MINOR 12
++#define KOPETE_VERSION_RELEASE 2
+ #define KOPETE_MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c))
+ 
+ #define KOPETE_VERSION \
+--- kopete/libkopete/webcamwidget.cpp	(revision 0)
++++ kopete/libkopete/webcamwidget.cpp	(revision 586398)
+@@ -0,0 +1,107 @@
++/*
++    webcamwidget.h - A simple widget for displaying webcam frames
++
++    Copyright (c) 2006 by Gustavo Pichorim Boiko   <gustavo.boiko at kdemail.net>
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at 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 "webcamwidget.h"
++
++#include <qcolor.h>
++#include <qpainter.h>
++
++#include <kdebug.h>
++namespace Kopete
++{
++
++WebcamWidget::WebcamWidget( QWidget* parent, const char* name )
++: QWidget( parent, name )
++{
++	clear();
++}
++
++WebcamWidget::~WebcamWidget()
++{
++	// don't do anything either
++}
++
++void WebcamWidget::updatePixmap(const QPixmap& pixmap)
++{
++	mPixmap = pixmap;
++	mText = "";
++
++	QPaintEvent *ev = new QPaintEvent( rect(), true );
++	paintEvent( ev );
++	delete ev;
++}
++
++void WebcamWidget::clear()
++{
++	mText = "";
++	if (!mPixmap.isNull())
++		mPixmap.resize(0,0);
++	
++	QPaintEvent *ev = new QPaintEvent( rect(), true );
++	paintEvent( ev );
++	delete ev;
++}
++
++void WebcamWidget::setText(const QString& text)
++{
++	mText = text;
++
++	// for now redraw everything
++	QPaintEvent *ev = new QPaintEvent( rect(), true );
++        paintEvent( ev );
++        delete ev;
++}
++
++void WebcamWidget::paintEvent( QPaintEvent* event )
++{
++	QMemArray<QRect> rects = event->region().rects();
++
++	if (!mPixmap.isNull())
++	{
++		for (unsigned int i = 0; i < rects.count(); ++i)
++		{
++			bitBlt(this, rects[i].topLeft(), &mPixmap, rects[i], Qt::CopyROP, true);
++		}
++	}
++	else
++	{
++		for (unsigned int i = 0; i < rects.count(); ++i)
++		{
++			QColor bgColor = paletteBackgroundColor();
++			QPainter p(this);
++			p.fillRect(rects[i], bgColor);
++		}
++	}
++
++	// TODO: draw the text
++	QPainter p(this);
++	QRect r = p.boundingRect(rect(), Qt::AlignCenter | Qt::WordBreak, mText );
++	if ( !mText.isEmpty() && event->rect().intersects(r))
++	{
++		p.setPen(Qt::black);
++		QRect rec = rect();
++		rec.moveTopLeft(QPoint(1,1));
++		p.drawText(rec, Qt::AlignCenter | Qt::WordBreak, mText, -1); 
++
++		rec.moveTopLeft(QPoint(-1,-1));
++		p.setPen(Qt::white);
++		p.drawText(rec, Qt::AlignCenter | Qt::WordBreak, mText, -1); 
++	}
++}
++
++} // end namespace Kopete
++
++#include "webcamwidget.moc"
+--- kopete/libkopete/kopeteplugin.cpp	(revision 568672)
++++ kopete/libkopete/kopeteplugin.cpp	(revision 586398)
+@@ -52,12 +52,12 @@
+ 
+ QString Plugin::displayName() const
+ {
+-	return pluginInfo()->name();
++	return pluginInfo() ? pluginInfo()->name() : QString::null;
+ }
+ 
+ QString Plugin::pluginIcon() const
+ {
+-	return pluginInfo()->icon();
++	return pluginInfo() ? pluginInfo()->icon() : QString::null;
+ }
+ 
+ 
+--- kopete/libkopete/kopeteaccount.h	(revision 568672)
++++ kopete/libkopete/kopeteaccount.h	(revision 586398)
+@@ -177,6 +177,25 @@
+ 	 * @return the icon for this account, colored if needed
+ 	 */
+ 	QPixmap accountIcon( const int size = 0 ) const;
++	
++	/**
++	 * \brief change the account icon.
++	 * by default the icon of an account is the protocol one, but it may be overide it.
++	 * Set QString::null to go back to the default  (the protocol icon)
++	 * 
++	 * this call will emit colorChanged()
++	 */
++	void setCustomIcon( const QString& );
++	
++	/**
++	 * \brief return the icon base
++	 * This is the custom account icon set with setIcon.   if this icon is null, then the protocol icon is used
++	 * don't use this funciton to get the icon that need to be displayed, use accountIcon
++	 */
++	QString customIcon() const;
++	
++			
++			
+ 
+ 	/**
+ 	 * \brief Retrieve the 'myself' contact.
+@@ -289,8 +308,10 @@
+ 	/**
+ 	 * Return the @ref KConfigGroup used to write and read special properties
+ 	 *
+-	 * "Protocol", "AccountId" , "Color", "AutoConnect", "Priority", "Enabled" are reserved keyword
++	 * "Protocol", "AccountId" , "Color", "AutoConnect", "Priority", "Enabled" , "Icon" are reserved keyword
+ 	 * already in use in that group.
++	 * 
++	 * for compatibility, try to not use key that start with a uppercase
+ 	 */
+ 	KConfigGroup *configGroup() const;
+ 
+@@ -392,6 +413,9 @@
+ signals:
+ 	/**
+ 	 * The color of the account has been changed
++	 * 
++	 * also emited when the icon change
++	 * @todo  probably rename to accountIconChanged
+ 	 */
+ 	void colorChanged( const QColor & );
+ 
+@@ -479,6 +503,11 @@
+ 
+ private slots:
+ 	/**
++	 * Restore online status and status message on reconnect.
++	 */
++	virtual void reconnect(); 
++
++	/**
+ 	 * Track the deletion of a Contact and clean up
+ 	 */
+ 	void contactDestroyed( Kopete::Contact * );
+@@ -489,6 +518,11 @@
+ 	void slotOnlineStatusChanged( Kopete::Contact *contact, const Kopete::OnlineStatus &newStatus, const Kopete::OnlineStatus &oldStatus );
+ 
+ 	/**
++	 * The @ref myself() contact's property changed.
++	 */
++	void slotContactPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & );
++
++	/**
+ 	 * Stop the suppression of status notification (connected to a timer)
+ 	 */
+ 	void slotStopSuppression();
+--- kopete/libkopete/kopeteaway.h	(revision 568672)
++++ kopete/libkopete/kopeteaway.h	(revision 586398)
+@@ -75,6 +75,12 @@
+ 	static QString message();
+ 
+ 	/**
++	 * @brief Gets the current global auto away message
++	 * @return The global auto away message
++	 */
++	static QString autoAwayMessage();
++
++	/**
+ 	 * This method sets the global away message,
+ 	 * it does not set you away, just sets the message.
+ 	 * @brief Sets the global away message
+@@ -83,6 +89,14 @@
+ 	void setGlobalAwayMessage(const QString &message);
+ 
+ 	/**
++	 * This method sets the global auto away message,
++	 * it does not set you away, just sets the message.
++	 * @brief Sets the global auto away message
++	 * @param message The message you want to set
++	 */
++	void setAutoAwayMessage(const QString &message);
++
++	/**
+ 	 * @brief Sets global away for all protocols
+ 	 */
+ 	static void setGlobalAway(bool status);
+--- kopete/libkopete/kopeteprefs.cpp	(revision 0)
++++ kopete/libkopete/kopeteprefs.cpp	(revision 586398)
+@@ -0,0 +1,696 @@
++/*
++    kopeteprefs.cpp - Kopete Preferences Container-Class
++
++    Copyright (c) 2002      by Stefan Gehn            <metz AT gehn.net>
++    Kopete    (c) 2002-2005 by the Kopete developers  <kopete-devel at kde.org>
++
++    *************************************************************************
++    *                                                                       *
++    * This library is free software; you can redistribute it and/or         *
++    * modify it under the terms of the GNU Lesser General Public            *
++    * License as published by the Free Software Foundation; either          *
++    * version 2 of the License, or (at your option) any later version.      *
++    *                                                                       *
++    *************************************************************************
++*/
++
++#include "kopeteprefs.h"
++
++#include <qfile.h>
++#include <qfont.h>
++#include <qmetaobject.h>
++
++#include <kapplication.h>
++#include <kglobalsettings.h>
++#include <kconfig.h>
++#include <kdebug.h>
++#include <kstandarddirs.h>
++
++#define KOPETE_DEFAULT_CHATSTYLE  "Kopete"
++
++KopetePrefs *KopetePrefs::s_prefs = 0L;
++
++KopetePrefs *KopetePrefs::prefs()
++{
++	if( !s_prefs )
++		s_prefs = new KopetePrefs;
++	return s_prefs;
++}
++
++KopetePrefs::KopetePrefs() : QObject( kapp, "KopetePrefs" )
++{
++	config = KGlobal::config();
++	load();
++}
++
++void KopetePrefs::load()
++{
++//	kdDebug( 14010 ) << k_funcinfo << endl;
++	config->setGroup("Appearance");
++
++	mIconTheme = config->readEntry("EmoticonTheme", defaultTheme());
++	mUseEmoticons = config->readBoolEntry("Use Emoticons", true);
++	mEmoticonsRequireSpaces = config->readBoolEntry("EmoticonsRequireSpaces" , true );
++	mShowOffline = config->readBoolEntry("ShowOfflineUsers", true);
++	mShowEmptyGroups = config->readBoolEntry("ShowEmptyGroups", true);
++	mGreyIdle = config->readBoolEntry("GreyIdleMetaContacts", true);
++	mSortByGroup = config->readBoolEntry("SortByGroup" , true);
++	mTreeView = config->readBoolEntry("TreeView", true);
++	mStartDocked = config->readBoolEntry("StartDocked", false);
++	mUseQueue = config->readBoolEntry("Use Queue", true);
++	mUseStack = config->readBoolEntry("Use Stack", false);
++	mRaiseMsgWindow = config->readBoolEntry("Raise Msg Window", false);
++	mShowEvents = config->readBoolEntry("Show Events in Chat Window", true);
++	mSpellCheck = config->readBoolEntry("SpellCheck", true);
++	mQueueUnreadMessages = config->readBoolEntry("Queue Unread Messages", false);
++	mQueueOnlyHighlightedMessagesInGroupChats = config->readBoolEntry("Queue Only Highlighted Messages In Group Chats", false);
++	mQueueOnlyMessagesOnAnotherDesktop = config->readBoolEntry("Queue Only Messages On Another Desktop", false);
++	mBalloonNotify = config->readBoolEntry("Balloon Notification", true);
++	mBalloonNotifyIgnoreClosesChatView = config->readBoolEntry("Balloon Notification Ignore Closes Chat View", false);
++	mBalloonCloseDelay = config->readNumEntry("Balloon Autoclose Delay", 30);
++	mBalloonClose = config->readBoolEntry("Balloon Autoclose", false);
++	mTrayflashNotify = config->readBoolEntry("Trayflash Notification", true);
++	mTrayflashNotifyLeftClickOpensMessage = config->readBoolEntry("Trayflash Notification Left Click Opens Message", true);
++	mTrayflashNotifySetCurrentDesktopToChatView = config->readBoolEntry("Trayflash Notification Set Current Desktop To Chat View", false);
++	mSoundIfAway = config->readBoolEntry("Sound Notification If Away", true);
++	mChatWindowPolicy = config->readNumEntry("Chatwindow Policy", 0);
++	mRichText = config->readBoolEntry("RichText editor", false);
++	mChatWShowSend = config->readBoolEntry("Show Chatwindow Send Button", true);
++	mRememberedMessages = config->readNumEntry("Remembered Messages", 5);
++	mTruncateContactNames = config->readBoolEntry("TruncateContactNames", false);
++	mMaxContactNameLength = config->readNumEntry("MaxContactNameLength", 20);
++
++	mChatViewBufferSize = config->readNumEntry("ChatView BufferSize", 250);
++
++	QColor tmpColor = KGlobalSettings::highlightColor();
++	mHighlightBackground = config->readColorEntry("Highlight Background Color", &tmpColor);
++	tmpColor = KGlobalSettings::highlightedTextColor();
++	mHighlightForeground = config->readColorEntry("Highlight Foreground Color", &tmpColor);
++	mHighlightEnabled = config->readBoolEntry("Highlighting Enabled", true);
++	mBgOverride = config->readBoolEntry("ChatView Override Background", false);
++	mFgOverride = config->readBoolEntry("ChatView Override Foreground", false);
++	mRtfOverride = config->readBoolEntry("ChatView Override RTF", false);
++	mInterfacePreference = config->readEntry("View Plugin", QString::fromLatin1("kopete_chatwindow") );
++	tmpColor = KGlobalSettings::textColor();
++	mTextColor = config->readColorEntry("Text Color", &tmpColor );
++	tmpColor = KGlobalSettings::baseColor();
++	mBgColor = config->readColorEntry("Bg Color", &tmpColor );
++	tmpColor = KGlobalSettings::linkColor();
++	mLinkColor = config->readColorEntry("Link Color", &tmpColor );
++	mFontFace = config->readFontEntry("Font Face");
++	tmpColor = darkGray;
++	mIdleContactColor = config->readColorEntry("Idle Contact Color", &tmpColor);
++
++	mShowTray = config->readBoolEntry("Show Systemtray", true);
++
++	_setStylePath(config->readEntry("StylePath"));
++	mStyleVariant = config->readEntry("StyleVariant");
++	// Read Chat Window Style display
++	mGroupConsecutiveMessages = config->readBoolEntry("GroupConsecutiveMessages", true);
++
++	mToolTipContents = config->readListEntry("ToolTipContents");
++	if(mToolTipContents.empty())
++	{
++		mToolTipContents
++			<< QString::fromLatin1("FormattedName")
++			<< QString::fromLatin1("userInfo")
++			<< QString::fromLatin1("server")
++			<< QString::fromLatin1("channels")
++			<< QString::fromLatin1("FormattedIdleTime")
++			<< QString::fromLatin1("channelMembers")
++			<< QString::fromLatin1("channelTopic")
++			<< QString::fromLatin1("emailAddress")
++			<< QString::fromLatin1("homePage")
++			<< QString::fromLatin1("onlineSince")
++			<< QString::fromLatin1("lastOnline")
++			<< QString::fromLatin1("awayMessage");
++	}
++
++	config->setGroup("ContactList");
++	int n = metaObject()->findProperty( "contactListDisplayMode" );
++	QString value = config->readEntry("DisplayMode",QString::fromLatin1("Default"));
++	mContactListDisplayMode = (ContactDisplayMode)metaObject()->property( n )->keyToValue( value.latin1() );
++	n = metaObject()->findProperty( "contactListIconMode" );
++	value = config->readEntry("IconMode",
++                                  QString::fromLatin1("IconDefault"));
++	mContactListIconMode = (IconDisplayMode) metaObject()->property( n )->keyToValue( value.latin1() );
++	mContactListIndentContacts = config->readBoolEntry("IndentContacts", false);
++	mContactListHideVerticalScrollBar = config->readBoolEntry("HideVerticalScrollBar", false );
++	mContactListUseCustomFonts = config->readBoolEntry("UseCustomFonts", false);
++	QFont font = KGlobalSettings::generalFont();
++	mContactListNormalFont = config->readFontEntry("NormalFont", &font);
++	if ( font.pixelSize() != -1 )
++		font.setPixelSize( (font.pixelSize() * 3) / 4 );
++	else
++		font.setPointSizeFloat( font.pointSizeFloat() * 0.75 );
++	mContactListSmallFont = config->readFontEntry("SmallFont", &font);
++	mContactListGroupNameColor = config->readColorEntry("GroupNameColor", &darkRed);
++	mContactListAnimation = config->readBoolEntry("AnimateChanges", true);
++	mContactListFading = config->readBoolEntry("FadeItems", true);
++	mContactListFolding = config->readBoolEntry("FoldItems", true);
++	mContactListMouseNavigation = config->readBoolEntry("MouseNavigation", false );
++	mContactListAutoHide = config->readBoolEntry("AutoHide", false);
++	mContactListAutoHideVScroll = config->readBoolEntry("AutoHideVScroll", true );
++	mContactListAutoHideTimeout = config->readUnsignedNumEntry("AutoHideTimeout", 30);
++
++	// Load the reconnection setting
++	config->setGroup("General");
++	mReconnectOnDisconnect = config->readBoolEntry("ReconnectOnDisconnect", true);
++	mAutoConnect = config->readBoolEntry("AutoConnect", false);
++
++	// Nothing has changed yet
++	mWindowAppearanceChanged = false;
++	mContactListAppearanceChanged = false;
++	mMessageAppearanceChanged = false;
++	mStylePathChanged = false;
++	mStyleVariantChanged = false;
++}
++
++void KopetePrefs::save()
++{
++//	kdDebug(14010) << "KopetePrefs::save()" << endl;
++	config->setGroup("Appearance");
++
++	config->writeEntry("EmoticonTheme", mIconTheme);
++	config->writeEntry("Use Emoticons", mUseEmoticons);
++	config->writeEntry("EmoticonsRequireSpaces", mEmoticonsRequireSpaces);
++	config->writeEntry("ShowOfflineUsers", mShowOffline);
++	config->writeEntry("ShowEmptyGroups", mShowEmptyGroups);
++	config->writeEntry("GreyIdleMetaContacts", mGreyIdle);
++	config->writeEntry("TreeView", mTreeView);
++	config->writeEntry("SortByGroup", mSortByGroup);
++	config->writeEntry("StartDocked", mStartDocked);
++	config->writeEntry("Use Queue", mUseQueue);
++	config->writeEntry("Use Stack", mUseStack);
++	config->writeEntry("Raise Msg Window", mRaiseMsgWindow);
++	config->writeEntry("Show Events in Chat Window", mShowEvents);
++	config->writeEntry("SpellCheck", mSpellCheck);
++	config->writeEntry("Queue Unread Messages", mQueueUnreadMessages);
++	config->writeEntry("Queue Only Highlighted Messages In Group Chats", mQueueOnlyHighlightedMessagesInGroupChats);
++	config->writeEntry("Queue Only Messages On Another Desktop", mQueueOnlyMessagesOnAnotherDesktop);
++	config->writeEntry("Balloon Notification", mBalloonNotify);
++	config->writeEntry("Balloon Notification Ignore Closes Chat View", mBalloonNotifyIgnoreClosesChatView);
++	config->writeEntry("Balloon Autoclose Delay", mBalloonCloseDelay);
++	config->writeEntry("Balloon Autoclose", mBalloonClose);
++	config->writeEntry("Trayflash Notification", mTrayflashNotify);
++	config->writeEntry("Trayflash Notification Left Click Opens Message", mTrayflashNotifyLeftClickOpensMessage);
++	config->writeEntry("Trayflash Notification Set Current Desktop To Chat View", mTrayflashNotifySetCurrentDesktopToChatView);
++	config->writeEntry("Sound Notification If Away", mSoundIfAway);
++	config->writeEntry("Chatwindow Policy", mChatWindowPolicy);
++	config->writeEntry("ChatView Override Background", mBgOverride);
++	config->writeEntry("ChatView Override Foreground", mFgOverride);
++	config->writeEntry("ChatView Override RTF", mRtfOverride);
++	config->writeEntry("ChatView BufferSize", mChatViewBufferSize);
++	config->writeEntry("Highlight Background Color", mHighlightBackground);
++	config->writeEntry("Highlight Foreground Color", mHighlightForeground);
++	config->writeEntry("Highlighting Enabled", mHighlightEnabled );
++	config->writeEntry("Font Face", mFontFace);
++	config->writeEntry("Text Color",mTextColor);
++	config->writeEntry("Remembered Messages",mRememberedMessages);
++	config->writeEntry("Bg Color", mBgColor);
++	config->writeEntry("Link Color", mLinkColor);
++	config->writeEntry("Idle Contact Color", mIdleContactColor);
++	config->writeEntry("RichText editor", mRichText);
++	config->writeEntry("Show Chatwindow Send Button", mChatWShowSend);
++	config->writeEntry("TruncateContactNames", mTruncateContactNames);
++	config->writeEntry("MaxContactNameLength", mMaxContactNameLength);
++
++	config->writeEntry("View Plugin", mInterfacePreference);
++
++	config->writeEntry("Show Systemtray", mShowTray);
++
++	//Style
++	//for xhtml+css
++	config->writeEntry("StylePath", mStylePath);
++	config->writeEntry("StyleVariant", mStyleVariant);
++	// Chat Window Display
++	config->writeEntry("GroupConsecutiveMessages", mGroupConsecutiveMessages);
++
++	config->writeEntry("ToolTipContents", mToolTipContents);
++
++	config->setGroup("ContactList");
++	int n = metaObject()->findProperty( "contactListDisplayMode" );
++	config->writeEntry("DisplayMode", metaObject()->property( n )->valueToKey( mContactListDisplayMode ));
++	n = metaObject()->findProperty( "contactListIconMode" );
++	config->writeEntry("IconMode", metaObject()->property( n )->valueToKey( mContactListIconMode ));
++	config->writeEntry("IndentContacts", mContactListIndentContacts);
++	config->writeEntry("HideVerticalScrollBar", mContactListHideVerticalScrollBar );
++	config->writeEntry("UseCustomFonts", mContactListUseCustomFonts);
++	config->writeEntry("NormalFont", mContactListNormalFont);
++	config->writeEntry("SmallFont", mContactListSmallFont);
++	config->writeEntry("GroupNameColor", mContactListGroupNameColor);
++	config->writeEntry("AnimateChanges", mContactListAnimation);
++	config->writeEntry("FadeItems", mContactListFading);
++	config->writeEntry("FoldItems", mContactListFolding);
++	config->writeEntry("MouseNavigation", mContactListMouseNavigation );
++	config->writeEntry("AutoHide", mContactListAutoHide);
++	config->writeEntry("AutoHideVScroll", mContactListAutoHideVScroll );
++	config->writeEntry("AutoHideTimeout", mContactListAutoHideTimeout);
++
++	//Save the reconnection setting
++	config->setGroup("General");
++	config->writeEntry("ReconnectOnDisconnect", mReconnectOnDisconnect);
++	config->writeEntry("AutoConnect", mAutoConnect);
++
++	config->sync();
++	emit saved();
++
++	if(mWindowAppearanceChanged)
++		emit windowAppearanceChanged();
++
++	if(mContactListAppearanceChanged)
++		emit contactListAppearanceChanged();
++
++	if(mMessageAppearanceChanged)
++		emit messageAppearanceChanged();
++
++	if(mStylePathChanged)
++		emit styleChanged(mStylePath);
++
++	if(mStyleVariantChanged)
++		emit styleVariantChanged(mStyleVariant);
++
++	// Clear all *Changed flags. This will cause breakage if someone makes some
++	// changes but doesn't save them in a slot connected to a *Changed signal.
++	mWindowAppearanceChanged = false;
++	mContactListAppearanceChanged = false;
++	mMessageAppearanceChanged = false;
++	mStylePathChanged = false;
++	mStyleVariantChanged = false;
++}
++
++void KopetePrefs::setIconTheme(const QString &value)
++{
++	if( mIconTheme != value )
++	{
++		mMessageAppearanceChanged = true;
++		mContactListAppearanceChanged = true;
++	}
++	mIconTheme = value;
++}
++
++void KopetePrefs::setUseEmoticons(bool value)
++{
++	if( mUseEmoticons != value )
++	{
++		 mMessageAppearanceChanged = true;
++		 mContactListAppearanceChanged = true;
++	}
++	mUseEmoticons = value;
++}
++
++void KopetePrefs::setShowOffline(bool value)
++{
++	if( value != mShowOffline ) mContactListAppearanceChanged = true;
++	mShowOffline = value;
++}
++
++void KopetePrefs::setShowEmptyGroups(bool value)
++{
++	if( value != mShowEmptyGroups ) mContactListAppearanceChanged = true;
++	mShowEmptyGroups = value;
++}
++
++void KopetePrefs::setTreeView(bool value)
++{
++	if( value != mTreeView ) mContactListAppearanceChanged = true;
++	mTreeView = value;
++}
++
++void KopetePrefs::setSortByGroup(bool value)
++{
++	if( value != mSortByGroup ) mContactListAppearanceChanged = true;
++	mSortByGroup = value;
++}
++
++void KopetePrefs::setGreyIdleMetaContacts(bool value)
++{
++	if( value != mGreyIdle ) mContactListAppearanceChanged = true;
++	mGreyIdle = value;
++}
++
++void KopetePrefs::setStartDocked(bool value)
++{
++	mStartDocked = value;
++}
++
++void KopetePrefs::setUseQueue(bool value)
++{
++	mUseQueue = value;
++}
++
++void KopetePrefs::setUseStack(bool value)
++{
++	mUseStack = value;
++}
++
++
++void KopetePrefs::setRaiseMsgWindow(bool value)
++{
++	mRaiseMsgWindow = value;
++}
++
++void KopetePrefs::setRememberedMessages(int value)
++{
++	mRememberedMessages = value;
++}
++
++void KopetePrefs::setShowEvents(bool value)
++{
++	mShowEvents = value;
++}
++
++void KopetePrefs::setTrayflashNotify(bool value)
++{
++	mTrayflashNotify = value;
++}
++
++void KopetePrefs::setSpellCheck(bool value)
++{
++	mSpellCheck = value;
++}
++
++void KopetePrefs::setQueueUnreadMessages(bool value)
++{
++	mQueueUnreadMessages = value;
++}
++
++void KopetePrefs::setQueueOnlyHighlightedMessagesInGroupChats(bool value)
++{
++	mQueueOnlyHighlightedMessagesInGroupChats = value;
++}
++
++void KopetePrefs::setQueueOnlyMessagesOnAnotherDesktop(bool value)
++{
++	mQueueOnlyMessagesOnAnotherDesktop = value;
++}
++
++void KopetePrefs::setTrayflashNotifyLeftClickOpensMessage(bool value)
++{
++	mTrayflashNotifyLeftClickOpensMessage = value;
++}
++
++void KopetePrefs::setTrayflashNotifySetCurrentDesktopToChatView(bool value)
++{
++	mTrayflashNotifySetCurrentDesktopToChatView = value;
++}
++
++void KopetePrefs::setBalloonNotify(bool value)
++{
++	mBalloonNotify = value;
++}
++
++void KopetePrefs::setBalloonNotifyIgnoreClosesChatView(bool value)
++{
++	mBalloonNotifyIgnoreClosesChatView = value;
++}
++
++void KopetePrefs::setBalloonClose( bool value ) 
++{
++	mBalloonClose = value;
++}
++
++void KopetePrefs::setBalloonDelay( int value )
++{
++	mBalloonCloseDelay = value;
++}
++
++void KopetePrefs::setSoundIfAway(bool value)
++{
++	mSoundIfAway = value;
++}
++
++void KopetePrefs::setStylePath(const QString &stylePath)
++{
++	if(mStylePath != stylePath) mStylePathChanged = true;
++	_setStylePath(stylePath);
++}
++
++void KopetePrefs::_setStylePath(const QString &stylePath)
++{
++	mStylePath = stylePath;
++	
++	// Fallback to default style if the directory doesn't exist
++	// or the value is empty.
++	if( !QFile::exists(stylePath) || stylePath.isEmpty() )
++	{
++		QString fallback;
++		fallback = QString(QString::fromLatin1("styles/%1/")).arg(QString::fromLatin1(KOPETE_DEFAULT_CHATSTYLE));
++		mStylePath = locate("appdata", fallback);
++	}
++}
++
++void KopetePrefs::setStyleVariant(const QString &variantPath)
++{
++	if(mStyleVariant != variantPath) mStyleVariantChanged = true;
++	mStyleVariant = variantPath;
++}
++
++void KopetePrefs::setFontFace( const QFont &value )
++{
++	if( value != mFontFace ) mWindowAppearanceChanged = true;
++	mFontFace = value;
++}
++
++void KopetePrefs::setTextColor( const QColor &value )
++{
++	if( value != mTextColor ) mWindowAppearanceChanged = true;
++	mTextColor = value;
++}
++
++void KopetePrefs::setBgColor( const QColor &value )
++{
++	if( value != mBgColor ) mWindowAppearanceChanged = true;
++	mBgColor = value;
++}
++
++void KopetePrefs::setLinkColor( const QColor &value )
++{
++	if( value != mLinkColor ) mWindowAppearanceChanged = true;
++	mLinkColor = value;
++}
++
++void KopetePrefs::setChatWindowPolicy(int value)
++{
++	mChatWindowPolicy = value;
++}
++
++void KopetePrefs::setTruncateContactNames( bool value )
++{
++	mTruncateContactNames = value;
++}
++
++void KopetePrefs::setMaxContactNameLength( int value )
++{
++	mMaxContactNameLength = value;
++}
++
++void KopetePrefs::setInterfacePreference(const QString &value)
++{
++	mInterfacePreference = value;
++}
++
++void KopetePrefs::setChatViewBufferSize( int value )
++{
++	mChatViewBufferSize = value;
++}
++
++void KopetePrefs::setHighlightBackground(const QColor &value)
++{
++	if( value != mHighlightBackground ) mWindowAppearanceChanged = true;
++	mHighlightBackground = value;
++}
++
++void KopetePrefs::setHighlightForeground(const QColor &value)
++{
++	if( value != mHighlightForeground ) mWindowAppearanceChanged = true;
++	mHighlightForeground = value;
++}
++
++void KopetePrefs::setHighlightEnabled(bool value)
++{
++	if( value != mHighlightEnabled ) mWindowAppearanceChanged = true;
++	mHighlightEnabled = value;
++}
++
++void KopetePrefs::setBgOverride(bool value)
++{
++	if( value != mBgOverride ) mMessageAppearanceChanged = true;
++	mBgOverride = value;
++}
++
++void KopetePrefs::setFgOverride(bool value)
++{
++	if( value != mFgOverride ) mMessageAppearanceChanged = true;
++	mFgOverride = value;
++}
++
++void KopetePrefs::setRtfOverride(bool value)
++{
++	if( value != mRtfOverride ) mMessageAppearanceChanged = true;
++	mRtfOverride = value;
++}
++
++void KopetePrefs::setShowTray(bool value)
++{
++	mShowTray = value;
++}
++
++
++QString KopetePrefs::fileContents(const QString &path)
++{
++ 	QString contents;
++	QFile file( path );
++	if ( file.open( IO_ReadOnly ) )
++	{
++		QTextStream stream( &file );
++		contents = stream.read();
++		file.close();
++	}
++	return contents;
++}
++
++void KopetePrefs::setIdleContactColor(const QColor &value)
++{
++	if( value != mIdleContactColor ) mContactListAppearanceChanged = true;
++	mIdleContactColor = value;
++}
++
++void KopetePrefs::setRichText(bool value)
++{
++	mRichText=value;
++}
++
++void KopetePrefs::setToolTipContents(const QStringList &value)
++{
++	mToolTipContents=value;
++}
++
++void KopetePrefs::setContactListIndentContacts( bool v )
++{
++	if( v != mContactListIndentContacts ) mContactListAppearanceChanged = true;
++	mContactListIndentContacts = v;
++}
++
++void KopetePrefs::setContactListHideVerticalScrollBar( bool v )
++{
++	if( v != mContactListHideVerticalScrollBar ) mContactListAppearanceChanged = true;
++	mContactListHideVerticalScrollBar = v;
++}
++
++void KopetePrefs::setContactListDisplayMode( ContactDisplayMode v )
++{
++	if( v != mContactListDisplayMode ) mContactListAppearanceChanged = true;
++	mContactListDisplayMode = v;
++}
++
++void KopetePrefs::setContactListIconMode( IconDisplayMode v )
++{
++	if( v != mContactListIconMode ) mContactListAppearanceChanged = true;
++	mContactListIconMode = v;
++}
++
++void KopetePrefs::setContactListUseCustomFonts( bool v )
++{
++	if( v != mContactListUseCustomFonts ) mContactListAppearanceChanged = true;
++	mContactListUseCustomFonts = v;
++}
++
++void KopetePrefs::setContactListCustomNormalFont( const QFont & v )
++{
++	if( v != mContactListNormalFont ) mContactListAppearanceChanged = true;
++	mContactListNormalFont = v;
++}
++
++void KopetePrefs::setContactListCustomSmallFont( const QFont & v )
++{
++	if( v != mContactListSmallFont ) mContactListAppearanceChanged = true;
++	mContactListSmallFont = v;
++}
++
++QFont KopetePrefs::contactListSmallFont() const
++{
++	if ( mContactListUseCustomFonts )
++		return contactListCustomSmallFont();
++	QFont smallFont = KGlobalSettings::generalFont();
++	if ( smallFont.pixelSize() != -1 )
++		smallFont.setPixelSize( (smallFont.pixelSize() * 3) / 4 );
++	else
++		smallFont.setPointSizeFloat( smallFont.pointSizeFloat() * 0.75 );
++	return smallFont;
++}
++
++void KopetePrefs::setContactListGroupNameColor( const QColor & v )
++{
++	if( v != mContactListGroupNameColor ) mContactListAppearanceChanged = true;
++	mContactListGroupNameColor = v;
++}
++
++void KopetePrefs::setContactListAnimation( bool n )
++{
++	if( n != mContactListAnimation ) mContactListAppearanceChanged = true;
++	mContactListAnimation = n;
++}
++
++void KopetePrefs::setContactListFading( bool n )
++{
++	if( n != mContactListFading ) mContactListAppearanceChanged = true;
++	mContactListFading = n;
++}
++
++void KopetePrefs::setContactListFolding( bool n )
++{
++	if( n != mContactListFolding ) mContactListAppearanceChanged = true;
++	mContactListFolding = n;
++}
++
++void KopetePrefs::setContactListMouseNavigation( bool n )
++{
++	if( n != mContactListMouseNavigation ) mContactListAppearanceChanged = true;
++	mContactListMouseNavigation = n;
++}
++
++void KopetePrefs::setContactListAutoHide( bool n )
++{
++	if( n != mContactListAutoHide ) mContactListAppearanceChanged = true;
++	mContactListAutoHide = n;
++}
++
++void KopetePrefs::setContactListAutoHideVScroll( bool n )
++{
++	if( n != mContactListAutoHideVScroll ) mContactListAppearanceChanged = true;
++	mContactListAutoHideVScroll = n;
++}
++
++void KopetePrefs::setContactListAutoHideTimeout( unsigned int n )
++{
++	if( n != mContactListAutoHideTimeout ) mContactListAppearanceChanged = true;
++	mContactListAutoHideTimeout = n;
++}
++
++void KopetePrefs::setReconnectOnDisconnect( bool newSetting )
++{
++	mReconnectOnDisconnect = newSetting;
++}
++
++void KopetePrefs::setAutoConnect(bool b)
++{
++	mAutoConnect=b;
++}
++
++void KopetePrefs::setEmoticonsRequireSpaces( bool b )
++{
++	if( mEmoticonsRequireSpaces != b )
++	{
++		 mMessageAppearanceChanged = true;
++		 mContactListAppearanceChanged = true;
++	}
++	mEmoticonsRequireSpaces=b;
++}
++
++void KopetePrefs::setGroupConsecutiveMessages( bool value )
++{
++	mGroupConsecutiveMessages = value;
++}
++#include "kopeteprefs.moc"
++// vim: set noet ts=4 sts=4 sw=4:
+--- kopete/libkopete/Makefile.am	(revision 568672)
++++ kopete/libkopete/Makefile.am	(revision 586398)
+@@ -1,3 +1,9 @@
++if compile_LIBKOPETE_COMPAT
++COMPAT_DIR = compat
++COMPAT_LIBS = compat/libkopetecompat.la
++endif
++
++
+ include ../../admin/Doxyfile.am
+ DOXYGEN_REFERENCES = kio kdecore kdeui
+ DOXYGEN_EXCLUDE = compat
+@@ -3,10 +9,9 @@
+ DOXYGEN_SET_PROJECT_NAME = libkopete
+ 
+-SUBDIRS = private ui . avdevice
++SUBDIRS = $(COMPAT_DIR) private ui . avdevice
+ 
+ METASOURCES = AUTO
+ 
+ AM_CPPFLAGS = -DKDE_NO_COMPAT -DQT_NO_COMPAT -DQT_NO_CAST_ASCII -DQT_NO_ASCII_CAST \
+-	$(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) \
+ 	$(KOPETE_INCLUDES) -I$(top_srcdir)/kopete/libkopete/private \
+ 	-I$(top_srcdir)/kopete/libkopete/ui $(all_includes)
+@@ -22,14 +27,15 @@
+ 	kopetecontactlistelement.cpp kopetecommandhandler.cpp kopeteaway.cpp \
+ 	kopeteawayaction.cpp kautoconfig.cpp kopetewalletmanager.cpp kopetecontactproperty.cpp \
+ 	kopetepassword.cpp kopeteglobal.cpp kopeteuiglobal.cpp kopetepasswordedaccount.cpp \
+-	kopetemimetypehandler.cpp kopetetask.cpp kopetemimesourcefactory.cpp kopetexsl.cpp \
++	kopetemimetypehandler.cpp kopetetask.cpp kopetemimesourcefactory.cpp \
+ 	kopeteeventpresentation.cpp kopetenotifyevent.cpp kopetenotifydataobject.cpp kopeteblacklister.cpp \
+ 	kopetemessageevent.cpp kopetemessagehandler.cpp kopetemessagehandlerchain.cpp \
+ 	kopetesimplemessagehandler.cpp kopeteproperties.cpp kabcpersistence.cpp connectionmanager.skel \
+-	clientiface.stub managedconnectionaccount.cpp networkstatuscommon.h kopeteconfig.kcfgc kopeteutils.cpp
++	clientiface.stub managedconnectionaccount.cpp networkstatuscommon.h kopeteconfig.kcfgc kopeteutils.cpp \
++	kopeteprefs.cpp kopetepicture.cpp webcamwidget.cpp
+ 
+ libkopete_la_LDFLAGS = -no-undefined -version-info 1:0:0 $(all_libraries)
+-libkopete_la_LIBADD = -lkabc ui/libkopeteui.la $(LIB_KIO) $(LIB_XSS) $(LIBXML_LIBS) $(LIBXSLT_LIBS)
++libkopete_la_LIBADD = -lkabc ui/libkopeteui.la $(COMPAT_LIBS) $(LIB_KIO) $(LIB_XSS) $(LIB_XRENDER)
+ 
+ kde_kcfg_DATA = kopete.kcfg
+ 
+@@ -39,8 +45,8 @@
+ #libkopetewidgets_la_LIBADD = $(LIB_KIO) libkopete.la ui/libkopeteui.la
+ #libkopetewidgets_la_SOURCES = ui/kopetewidgets.cpp
+ 
+-#kopetewidgets.cpp: $(srcdir)/kopete.widgets
+-#	$(MAKEKDEWIDGETS) -o kopetewidgets.cpp $(srcdir)/kopete.widgets
++kopetewidgets.cpp: $(srcdir)/kopete.widgets
++	$(MAKEKDEWIDGETS) -o kopetewidgets.cpp $(srcdir)/kopete.widgets
+ 
+ rcdir = $(kde_datadir)/kopete
+ rc_DATA = kopetecommandui.rc
+@@ -56,8 +62,8 @@
+ 	kopetechatsession.h kopetechatsessionmanager.h kopetemetacontact.h kopetemimetypehandler.h \
+ 	kopeteonlinestatus.h kopeteonlinestatusmanager.h kopetepasswordedaccount.h \
+ 	kopetepassword.h kopeteplugin.h kopeteprotocol.h kopetesimplemessagehandler.h kopetetask.h \
+-	kopetetransfermanager.h kopeteuiglobal.h kopetexsl.h kabcpersistence.h managedconnectionaccount.h \
+-	kopetenotifydataobject.h kopeteversion.h
++	kopetetransfermanager.h kopeteuiglobal.h kabcpersistence.h managedconnectionaccount.h \
++	kopetenotifydataobject.h kopeteversion.h kopeteprefs.h kopetepicture.h webcamwidget.h
+ 
+ # vim: set noet:
+ 
+--- kopete/libkopete/ui/addcontactpage.h	(revision 568672)
++++ kopete/libkopete/ui/addcontactpage.h	(revision 586398)
+@@ -25,6 +25,9 @@
+ 
+ /**
+  * @author Duncan Mac-Vicar P. <duncan at kde.org>
++ * @todo   i want to be able to have a assync apply. 
++ *     (in the case of jabber, i need to translate the legacy id to a JID)
++ *     this could also be usefull in the case of MLSN to check if no error  (and also jabber)
+  */
+ class KOPETE_EXPORT AddContactPage : public QWidget
+ {
+--- kopete/libkopete/ui/addressbooklinkwidget_base.ui	(revision 0)
++++ kopete/libkopete/ui/addressbooklinkwidget_base.ui	(revision 586398)
+@@ -0,0 +1,78 @@
++<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
++<class>AddressBookLinkWidgetBase</class>
++<widget class="QWidget">
++    <property name="name">
++        <cstring>AddressBookLinkWidgetBase</cstring>
++    </property>
++    <property name="geometry">
++        <rect>
++            <x>0</x>
++            <y>0</y>
++            <width>350</width>
++            <height>31</height>
++        </rect>
++    </property>
++    <vbox>
++        <property name="name">
++            <cstring>unnamed</cstring>
++        </property>
++        <property name="margin">
++            <number>0</number>
++        </property>
++        <widget class="QLayoutWidget">
++            <property name="name">
++                <cstring>layout9</cstring>
++            </property>
++            <hbox>
++                <property name="name">
++                    <cstring>unnamed</cstring>
++                </property>
++                <widget class="KLineEdit">
++                    <property name="name">
++                        <cstring>edtAddressee</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="readOnly">
++                        <bool>true</bool>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>The KDE Address Book entry associated with this Kopete Contact</string>
++                    </property>
++                </widget>
++                <widget class="KPushButton">
++                    <property name="name">
++                        <cstring>btnClear</cstring>
++                    </property>
++                    <property name="text">
++                        <string></string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Clear</string>
++                    </property>
++                </widget>
++                <widget class="QPushButton">
++                    <property name="name">
++                        <cstring>btnSelectAddressee</cstring>
++                    </property>
++                    <property name="enabled">
++                        <bool>true</bool>
++                    </property>
++                    <property name="text">
++                        <string>C&amp;hange...</string>
++                    </property>
++                    <property name="toolTip" stdset="0">
++                        <string>Select an address book entry</string>
++                    </property>
++                </widget>
++            </hbox>
++        </widget>
++    </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++<includehints>
++    <includehint>klineedit.h</includehint>
++    <includehint>kpushbutton.h</includehint>
++</includehints>
++</UI>
+--- kopete/libkopete/ui/metacontactselectorwidget.cpp	(revision 568672)
++++ kopete/libkopete/ui/metacontactselectorwidget.cpp	(revision 586398)
+@@ -24,6 +24,7 @@
+ #include <qpixmap.h>
+ #include <qpainter.h>
+ #include <qlayout.h>
++#include <qvaluelist.h>
+ 
+ #include <kapplication.h>
+ #include <kconfig.h>
+@@ -55,7 +56,6 @@
+ class MetaContactSelectorWidgetLVI::Private
+ {
+ public:
+-	
+ 	Kopete::MetaContact *metaContact;
+ 	ImageComponent *metaContactPhoto;
+ 	ImageComponent *metaContactIcon;
+@@ -177,6 +177,7 @@
+ {
+ public:
+ 	MetaContactSelectorWidget_Base *widget;
++	QValueList<Kopete::MetaContact *> excludedMetaContacts;
+ };
+ 
+ 
+@@ -241,12 +242,21 @@
+ 	}
+ }
+ 
++void MetaContactSelectorWidget::excludeMetaContact( Kopete::MetaContact *mc )
++{
++	if( d->excludedMetaContacts.findIndex(mc) == -1 )
++	{
++		d->excludedMetaContacts.append(mc);
++	}
++	slotLoadMetaContacts();
++}
++
+ bool MetaContactSelectorWidget::metaContactSelected()
+ {
+ 	return d->widget->metaContactListView->selectedItem() ? true : false;
+ }
+ 
+-/**  Read in contacts from addressbook, and select the contact that is for our nick. */
++/**  Read in metacontacts from contactlist */
+ void MetaContactSelectorWidget::slotLoadMetaContacts()
+ {
+ 	d->widget->metaContactListView->clear();
+@@ -254,7 +264,7 @@
+ 	QPtrList<Kopete::MetaContact> metaContacts = Kopete::ContactList::self()->metaContacts();
+ 	for( Kopete::MetaContact *mc = metaContacts.first(); mc ; mc = metaContacts.next() )
+ 	{
+-		if( !mc->isTemporary() && mc != metaContact() )
++		if( !mc->isTemporary() && (d->excludedMetaContacts.findIndex(mc) == -1) )
+ 		{
+ 			new MetaContactSelectorWidgetLVI(mc, d->widget->metaContactListView);
+ 		}
+--- kopete/libkopete/ui/kopete.widgets	(revision 568672)
++++ kopete/libkopete/ui/kopete.widgets	(revision 586398)
+@@ -6,12 +6,19 @@
+ [Kopete::UI::ListView::ListView]
+ ToolTip=List View (Kopete)
+ WhatsThis=A component capable list view widget.
+-IncludeFile=kopete/ui/kopetelistview.h
++IncludeFile=kopetelistview.h
+ Group=Views (Kopete)
+ 
+ [Kopete::UI::ListView::SearchLine]
+ ToolTip=List View Search Line (Kopete)
+ WhatsThis=Search line able to use Kopete custom list View.
+-IncludeFile=kopete/ui/kopetelistviewsearchline.h
++IncludeFile=kopetelistviewsearchline.h
+ ConstructorArgs=(parent, 0, name)
+ Group=Input (Kopete)
++
++[Kopete::UI::AddressBookLinkWidget]
++ToolTip=Address Book Link Widget (Kopete)
++WhatsThis=KABC::Addressee display/selector
++IncludeFile=addressbooklinkwidget.h
++ConstructorArgs=(parent, name)
++Group=Input (Kopete)
+--- kopete/libkopete/ui/kopetewidgets.cpp	(revision 568672)
++++ kopete/libkopete/ui/kopetewidgets.cpp	(revision 586398)
+@@ -6,8 +6,9 @@
+ #include <qwidgetplugin.h>
+ 
+ #include <kinstance.h>
+-#include "kopetelistview.h"
+-#include "kopetelistviewsearchline.h"
++#include <addressbooklinkwidget.h>
++#include <kopetelistview.h>
++#include <kopetelistviewsearchline.h>
+ #ifndef EMBED_IMAGES
+ #include <kstandarddirs.h>
+ #endif
+@@ -70,13 +71,25 @@
+ {
+         WidgetInfo widget;
+ 
++	widget.group = QString::fromLatin1("Input (Kopete)");
++#ifdef EMBED_IMAGES
++	widget.iconSet = QPixmap(kopete__ui__addressbooklinkwidget_xpm);
++#else
++	widget.iconSet = QString::fromLatin1("kopete__ui__addressbooklinkwidget.png");
++#endif
++	widget.includeFile = QString::fromLatin1("addressbooklinkwidget.h");
++	widget.toolTip = QString::fromLatin1("Address Book Link Widget (Kopete)");
++	widget.whatsThis = QString::fromLatin1("KABC::Addressee display/selector");
++	widget.isContainer = false;
++	m_widgets.insert(QString::fromLatin1("Kopete::UI::AddressBookLinkWidget"), widget);
++
+ 	widget.group = QString::fromLatin1("Views (Kopete)");
+ #ifdef EMBED_IMAGES
+ 	widget.iconSet = QPixmap(kopete__ui__listview__listview_xpm);
+ #else
+ 	widget.iconSet = QString::fromLatin1("kopete__ui__listview__listview.png");
+ #endif
+-	widget.includeFile = QString::fromLatin1("kopete/ui/kopetelistview.h");
++	widget.includeFile = QString::fromLatin1("kopetelistview.h");
+ 	widget.toolTip = QString::fromLatin1("List View (Kopete)");
+ 	widget.whatsThis = QString::fromLatin1("A component capable list view widget.");
+ 	widget.isContainer = false;
+@@ -88,7 +101,7 @@
+ #else
+ 	widget.iconSet = QString::fromLatin1("kopete__ui__listview__searchline.png");
+ #endif
+-	widget.includeFile = QString::fromLatin1("kopete/ui/kopetelistviewsearchline.h");
++	widget.includeFile = QString::fromLatin1("kopetelistviewsearchline.h");
+ 	widget.toolTip = QString::fromLatin1("List View Search Line (Kopete)");
+ 	widget.whatsThis = QString::fromLatin1("Search line able to use Kopete custom list View.");
+ 	widget.isContainer = false;
+@@ -103,6 +116,9 @@
+ QWidget *KopeteWidgets::create(const QString &key, QWidget *parent, const char *name)
+ {
+ 
++         if (key == QString::fromLatin1("Kopete::UI::AddressBookLinkWidget"))
++                return new Kopete::UI::AddressBookLinkWidget(parent, name);
++
+          if (key == QString::fromLatin1("Kopete::UI::ListView::ListView"))
+                 return new Kopete::UI::ListView::ListView(parent, name);
+ 
+--- kopete/libkopete/ui/kopeteawaydialogbase.ui	(revision 568672)
++++ kopete/libkopete/ui/kopeteawaydialogbase.ui	(revision 586398)
+@@ -24,7 +24,7 @@
+                 <cstring>TextLabel1</cstring>
+             </property>
+             <property name="text">
+-                <string>Please specify an away message, or choose a predefined one from the dropdown.</string>
++                <string>Please specify an away message, or choose a predefined one.</string>
+             </property>
+             <property name="alignment">
+                 <set>WordBreak|AlignVCenter|AlignLeft</set>
+--- kopete/libkopete/ui/addressbooklinkwidget.h	(revision 0)
++++ kopete/libkopete/ui/addressbooklinkwidget.h	(revision 586398)
+@@ -0,0 +1,81 @@
++/*
++    AddressBookLinkWidget
++
++    A compact widget for showing and changing which address book item a
++    particular Kopete::MetaContact is related to.
++
++    Comprises a label showing the contact's name, a Clear button, and a Change
++    button that usually invokes the AddressBookSelectorWidget.
++
++    Copyright (c) 2006 by Will Stephenson <wstephenson at kde.org>
++
++    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel at 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 ADDRESSBOOKLINKWIDGET_H
++#define ADDRESSBOOKLINKWIDGET_H
++
++#include <kabc/addressee.h>
++
++#include "addressbooklinkwidget_base.h"
++
++namespace Kopete {
++class MetaContact;
++
++namespace UI {
++
++/** 
++ * A compact widget for showing and changing which address book item a
++ * particular Kopete::MetaContact is related to.
++ *
++ * Comprises a label showing the contact's name, a Clear button, and a Change
++ * button that usually invokes the AddressBookSelectorWidget.
++ */
++class AddressBookLinkWidget : public AddressBookLinkWidgetBase
++{
++Q_OBJECT
++public:
++	AddressBookLinkWidget( QWidget * parent, const char * name );
++	~AddressBookLinkWidget() {}
++	/**
++	 * Set the currently selected addressee
++	 */
++	void setAddressee( const KABC::Addressee& addr );
++	/**
++	 * Set the current metacontact so that the selector dialog may be preselected
++	 */
++	void setMetaContact( const Kopete::MetaContact * );
++	/**
++	 * Return the selected addressbook UID.
++	 */
++	QString uid() const;
++signals:
++	/**
++	 * Emitted when the selected addressee changed.  addr is the KABC::Addressee that was selected. If addr.isEmpty() is empty, the clear button was clicked.
++	 */
++	void addresseeChanged( const KABC::Addressee& addr );
++	
++	/**
++	 * Provided so you can perform your own actions instead of opening the AddressBookSelectorWidget.
++	 * To do so, QObject::disconnect() btnSelectAddressee and connect your own slot to this signal
++	 */
++	void selectAddresseeClicked();
++protected slots:
++	void slotClearAddressee();
++	void slotSelectAddressee();
++private:
++	const Kopete::MetaContact * mMetaContact;
++	QString mSelectedUid;
++};
++} // end namespace UI
++} // end namespace Kopete
++#endif
+--- kopete/libkopete/ui/kopeteview.h	(revision 568672)
++++ kopete/libkopete/ui/kopeteview.h	(revision 586398)
+@@ -43,6 +43,7 @@
+ 		 * constructor
+ 		 */
+ 		KopeteView( Kopete::ChatSession *manager, Kopete::ViewPlugin *parent );
++		virtual ~KopeteView();
+ 
+ 		/**
+ 		 * @brief Returns the message currently in the edit area
+--- kopete/libkopete/ui/contactaddednotifydialog.h	(revision 568672)
++++ kopete/libkopete/ui/contactaddednotifydialog.h	(revision 586398)
+@@ -20,6 +20,10 @@
+ #include <kdialogbase.h>
+ #include "kopete_export.h"
+ 
++namespace KABC {
++	class Addressee;
++}
++
+ namespace Kopete {
+ 
+ class Group;
+@@ -155,8 +159,7 @@
+ 
+ 
+ private slots:
+-	void slotClearAddresseeClicked();
+-	void slotSelectAddresseeClicked();
++	void slotAddresseeSelected( const KABC::Addressee &);
+ 	void slotInfoClicked();
+ 	void slotFinished();
+ 
+--- kopete/libkopete/ui/kopetestdaction.cpp	(revision 568672)
++++ kopete/libkopete/ui/kopetestdaction.cpp	(revision 586398)
+@@ -85,7 +85,7 @@
+ 
+ KAction * KopeteStdAction::sendFile( const QObject *recvr, const char *slot, QObject *parent, const char *name )
+ {
+-	return new KAction( i18n( "Send &File..." ), QString::fromLatin1( "launch" ), 0, recvr, slot, parent, name );
++	return new KAction( i18n( "Send &File..." ), QString::fromLatin1( "attach" ), 0, recvr, slot, parent, name );
+ }
+ 
+ KAction * KopeteStdAction::viewHistory( const QObject *recvr, const char *slot, QObject *parent, const char *name )
+@@ -105,7 +105,7 @@
+ 
+ KAction * KopeteStdAction::deleteContact( const QObject *recvr, const char *slot, QObject *parent, const char *name )
+ {
+-	return new KAction( i18n( "&Delete Contact" ), QString::fromLatin1( "editdelete" ), Qt::Key_Delete, recvr, slot, parent, name );
++	return new KAction( i18n( "&Delete Contact" ), QString::fromLatin1( "delete_user" ), Qt::Key_Delete, recvr, slot, parent, name );
+ }
+ 
+ KAction * KopeteStdAction::changeAlias( const QObject *recvr, const char *slot, QObject *parent, const char *name )
+--- kopete/libkopete/ui/kopetelistviewitem.h	(revision 568672)
++++ kopete/libkopete/ui/kopetelistviewitem.h	(revision 586398)
+@@ -313,6 +313,7 @@
+ {
+ public:
+ 	ContactComponent( ComponentBase *parent, Kopete::Contact *contact, int iconSize);
++	~ContactComponent();
+ 	void updatePixmap();
+ 	Kopete::Contact *contact();
+ 	std::pair<QString,QRect> toolTip( const QPoint &relativePos );
+--- kopete/libkopete/ui/contactaddednotifywidget.ui	(revision 568672)
++++ kopete/libkopete/ui/contactaddednotifywidget.ui	(revision 586398)
+@@ -183,7 +183,7 @@
+                 </widget>
+                 <widget class="QLayoutWidget">
+                     <property name="name">
+-                        <cstring>layout14</cstring>
++                        <cstring>layout11</cstring>
+                     </property>
+                     <hbox>
+                         <property name="name">
+@@ -191,60 +191,26 @@
+                         </property>
+                         <spacer>
+                             <property name="name">
+-                                <cstring>spacer17</cstring>
++                                <cstring>spacer11</cstring>
+                             </property>
+                             <property name="orientation">
+                                 <enum>Horizontal</enum>
+                             </property>
+                             <property name="sizeType">
+-                                <enum>Fixed</enum>
++                                <enum>Expanding</enum>
+                             </property>
+                             <property name="sizeHint">
+                                 <size>
+-                                    <width>31</width>
+-                                    <height>21</height>
++                                    <width>51</width>
++                                    <height>20</height>
+                                 </size>
+                             </property>
+                         </spacer>
+-                        <widget class="KLineEdit">
++                        <widget class="Kopete::UI::AddressBookLinkWidget">
+                             <property name="name">
+-                                <cstring>edtAddressee</cstring>
++                                <cstring>widAddresseeLink</cstring>
+                             </property>
+-                            <property name="text">
+-                                <string></string>
+-                            </property>
+-                            <property name="readOnly">
+-                                <bool>true</bool>
+-                            </property>
+-                            <property name="toolTip" stdset="0">
+-                                <string>The KDE Address Book entry associated with this Kopete Contact</string>
+-                            </property>
+                         </widget>
+-                        <widget class="KPushButton">
+-                            <property name="name">
+-                                <cstring>btnClear</cstring>
+-                            </property>
+-                            <property name="text">
+-                                <string></string>
+-                            </property>
+-                            <property name="toolTip" stdset="0">
+-                                <string>Clear</string>
+-                            </property>
+-                        </widget>
+-                        <widget class="QPushButton">
+-                            <property name="name">
+-                                <cstring>btnSelectAddressee</cstring>
+-                            </property>
+-                            <property name="enabled">
+-                                <bool>true</bool>
+-                            </property>
+-                            <property name="text">
+-                                <string>Change...</string>
+-                            </property>
+-                            <property name="toolTip" stdset="0">
+-                                <string>Select an address book entry</string>
+-                            </property>
+-                        </widget>
+                     </hbox>
+                 </widget>
+             </vbox>
+@@ -268,8 +234,6 @@
+         </spacer>
+     </vbox>
+ </widget>
+-<customwidgets>
+-</customwidgets>
+ <connections>
+     <connection>
+         <sender>m_addCb</sender>
+@@ -278,6 +242,12 @@
+         <slot>setEnabled(bool)</slot>
+     </connection>
+ </connections>
++<customwidgets>
++    <customwidget>
++           <class>Kopete::UI::AddressBookLinkWidget</class>
++	   <header>addressbooklinkwidget.h</header>
++    </customwidget>
++</customwidgets>
+ <layoutdefaults spacing="6" margin="11"/>
+ <includehints>
+     <includehint>kpushbutton.h</includehint>
+--- kopete/libkopete/ui/metacontactselectorwidget.h	(revision 568672)
++++ kopete/libkopete/ui/metacontactselectorwidget.h	(revision 586398)
+@@ -32,8 +32,9 @@
+ 
+ /**
+  * @author Duncan Mac-Vicar Prett <duncan at kde.org>
++ * This class provides a widget which allows easy selection
++ * of available Kopete metacontacts.
+  */
+-
+ class KOPETE_EXPORT MetaContactSelectorWidget : public QWidget
+ {
+ 	Q_OBJECT
+@@ -52,6 +53,11 @@
+ 	 */
+ 	void selectMetaContact( Kopete::MetaContact *mc );
+ 	/**
++	 * excludes a metacontact from being shown in the list
++	* if the metacontact is already excluded, do nothing
++	 */
++	void excludeMetaContact( Kopete::MetaContact *mc );
++	/**
+ 	 * @return true if there is a contact selected
+ 	 */
+ 	bool metaContactSelected();
+--- kopete/libkopete/ui/addressbooklinkwidget.cpp	(revision 0)
++++ kopete/libkopete/ui/addressbooklinkwidget.cpp	(revision 586398)
+@@ -0,0 +1,99 @@
++/*
++    AddressBookLinkWidget
++
++    A compact widget for showing and changing which address book item a
++    particular Kopete::MetaContact is related to.
++
++    Comprises a label showing the contact's name, a Clear button, and a Change
++    button that usually invokes the AddressBookSelectorWidget.
++
++    Copyright (c) 2006 by Will Stephenson <wstephenson at kde.org>
++
++    Kopete    (c) 2002-2006 by the Kopete developers  <kopete-devel at 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 <qapplication.h>
++#include <klineedit.h>
++#include <klocale.h>
++#include <kpushbutton.h>
++
++#include <kiconloader.h>
++
++#include <kopetemetacontact.h>
++
++#include "addressbooklinkwidget.h"
++#include "addressbookselectordialog.h"
++#include "addressbookselectorwidget.h"
++
++namespace Kopete {
++namespace UI {
++
++
++AddressBookLinkWidget::AddressBookLinkWidget( QWidget * parent, const char * name ) : AddressBookLinkWidgetBase( parent, name ), mMetaContact( 0 )
++{
++	btnClear->setIconSet( SmallIconSet( QApplication::reverseLayout() ? QString::fromLatin1( "locationbar_erase" ) : QString::fromLatin1( "clear_left") ) );
++	connect( btnClear, SIGNAL( clicked() ), this, SLOT( slotClearAddressee() ) );
++	connect( btnSelectAddressee, SIGNAL( clicked() ), SLOT( slotSelectAddressee() ) );
++}
++
++void AddressBookLinkWidget::setAddressee( const KABC::Addressee& addr )
++{
++	edtAddressee->setText( addr.realName() );
++	btnClear->setEnabled( !addr.isEmpty() );
++}
++
++void AddressBookLinkWidget::setMetaContact( const Kopete::MetaContact * mc )
++{
++	mMetaContact = mc;
++}
++
++QString AddressBookLinkWidget::uid() const
++{
++	return mSelectedUid;
++}
++
++void AddressBookLinkWidget::slotClearAddressee()
++{
++	edtAddressee->clear();
++	btnClear->setEnabled( false );
++	KABC::Addressee mrEmpty;
++	mSelectedUid = QString::null;
++	emit addresseeChanged( mrEmpty );
++}
++
++void AddressBookLinkWidget::slotSelectAddressee()
++{
++	QString message;
++	if ( mMetaContact )
++		message = i18n("Choose the corresponding entry for '%1'" ).arg( mMetaContact->displayName() );
++ 	else
++		message = i18n("Choose the corresponding entry in the address book" );
++
++	Kopete::UI::AddressBookSelectorDialog dialog( i18n("Addressbook Association"), message, ( mMetaContact ? mMetaContact->metaContactId() : QString::null ), this );
++	int result = dialog.exec();
++
++	KABC::Addressee addr;
++	if ( result == QDialog::Accepted )
++	{
++		addr = dialog.addressBookSelectorWidget()->addressee();
++
++		edtAddressee->setText( addr.realName() );
++		btnClear->setEnabled( !addr.isEmpty() );
++		mSelectedUid = ( addr.isEmpty() ? QString::null : addr.uid() );
++		emit addresseeChanged( addr );
++	}
++}
++
++} // end namespace UI
++} // end namespace Kopete
++
++#include "addressbooklinkwidget.moc"
+--- kopete/libkopete/ui/kopeteview.cpp	(revision 568672)
++++ kopete/libkopete/ui/kopeteview.cpp	(revision 586398)
+@@ -47,3 +47,6 @@
+ 	return m_plugin;
+ }
+ 
++KopeteView::~ KopeteView( )
++{
++}
+--- kopete/libkopete/ui/contactaddednotifydialog.cpp	(revision 568672)
++++ kopete/libkopete/ui/contactaddednotifydialog.cpp	(revision 586398)
+@@ -37,6 +37,7 @@
+ #include "kopeteprotocol.h"
+ #include "kopetecontactlist.h"
+ #include "kopetemetacontact.h"
++#include "addressbooklinkwidget.h"
+ #include "addressbookselectordialog.h"
+ 
+ 
+@@ -69,7 +70,7 @@
+ 	
+ 	d->account=account;
+ 	d->contactId=contactId;
+-	d->widget->m_label->setText(i18n("<qt><img src=\"kopete-account-icon:%1\" /> The contact <b>%2</b> has added you in his contactlist. (Account %3)</qt>")
++	d->widget->m_label->setText(i18n("<qt><img src=\"kopete-account-icon:%1\" /> The contact <b>%2</b> has added you to his/her contactlist. (Account %3)</qt>")
+ 			.arg( KURL::encode_string( account->protocol()->pluginId() ) + QString::fromLatin1(":")
+ 			                  + KURL::encode_string( account->accountId() ) ,
+ 				  contactNick.isEmpty() ? contactId : contactNick + QString::fromLatin1(" < ") + contactId + QString::fromLatin1(" >")  ,
+@@ -77,9 +78,15 @@
+ 	if( hide & InfoButton)
+ 		d->widget->m_infoButton->hide() ;
+ 	if( hide & AuthorizeCheckBox )
++	{
+ 		d->widget->m_authorizeCb->hide();
++		d->widget->m_authorizeCb->setChecked(false);
++	}
+ 	if( hide & AddCheckBox )
++	{
+ 		d->widget->m_addCb->hide();
++		d->widget->m_addCb->setChecked(false);
++	}
+ 	if( hide & AddGroupBox )
+ 		d->widget->m_contactInfoBox->hide();
+ 
+@@ -95,10 +102,7 @@
+ 	}
+ 	d->widget->m_groupList->setCurrentText(QString::null); //default to top-level
+ 
+-	d->widget->btnClear->setIconSet( SmallIconSet( QApplication::reverseLayout() ?
+-			 QString::fromLatin1 ( "locationbar_erase" ) : QString::fromLatin1 ("clear_left") ) );
+-	connect( d->widget->btnClear, SIGNAL( clicked() ), this, SLOT( slotClearAddresseeClicked() ) );
+-	connect( d->widget->btnSelectAddressee, SIGNAL( clicked() ), this, SLOT( slotSelectAddresseeClicked() ) );
++	connect( d->widget->widAddresseeLink, SIGNAL( addresseeChanged( const KABC::Addressee& ) ), this, SLOT( slotAddresseeSelected( const KABC::Addressee& ) ) );
+ 	connect( d->widget->m_infoButton, SIGNAL( clicked() ), this, SLOT( slotInfoClicked() ) );
+ 
+ 	connect( this, SIGNAL(okClicked()) , this , SLOT(slotFinished()));
+@@ -149,29 +153,14 @@
+ 	return metacontact;
+ }
+ 
+-
+-
+-
+-
+-void ContactAddedNotifyDialog::slotSelectAddresseeClicked()
++void ContactAddedNotifyDialog::slotAddresseeSelected( const KABC::Addressee & addr )
+ {
+-	KABC::Addressee a = Kopete::UI::AddressBookSelectorDialog::getAddressee( i18n("Addressbook association"), i18n("Choose the person who '%1' is.").arg(d->contactId ), d->addressbookId , this);
+-	
+-	if ( !a.isEmpty() )
++	if ( !addr.isEmpty() )
+ 	{
+-		d->widget->edtAddressee->setText( a.realName() );
+-		// set/update the MC's addressee uin field
+-		d->addressbookId = a.uid();
++		d->addressbookId = addr.uid();
+ 	}
+ }
+ 
+-
+-void ContactAddedNotifyDialog::slotClearAddresseeClicked()
+-{
+-	d->widget->edtAddressee->setText( QString::null );
+-	d->addressbookId=QString::null;
+-}
+-
+ void ContactAddedNotifyDialog::slotInfoClicked()
+ {
+ 	emit infoClicked(d->contactId);
+--- kopete/libkopete/ui/Makefile.am	(revision 568672)
++++ kopete/libkopete/ui/Makefile.am	(revision 586398)
+@@ -5,23 +5,25 @@
+ noinst_LTLIBRARIES = libkopeteui.la
+ 
+ libkopeteui_la_SOURCES = kopetecontactaction.cpp addcontactpage.cpp \
+-		editaccountwidget.cpp kopetepassworddialog.ui kopetestdaction.cpp 	kopeteawaydialogbase.ui \
+-	kopetefileconfirmdialog.cpp 	fileconfirmbase.ui userinfodialog.cpp kopeteview.cpp \
+-	kopetepasswordwidgetbase.ui 	kopetepasswordwidget.cpp accountselector.cpp kopeteviewplugin.cpp \
+-	addresseeitem.cpp addressbookselectorwidget_base.ui addressbookselectordialog.cpp \
+-		addressbookselectorwidget.cpp metacontactselectorwidget_base.ui 	metacontactselectorwidget.cpp \
+-	kopetelistview.cpp kopetelistviewitem.cpp kopetelistviewsearchline.cpp \
+-	contactaddednotifywidget.ui contactaddednotifydialog.cpp
++			editaccountwidget.cpp kopetepassworddialog.ui kopetestdaction.cpp 	kopeteawaydialogbase.ui \
++		kopetefileconfirmdialog.cpp 	fileconfirmbase.ui userinfodialog.cpp kopeteview.cpp \
++		kopetepasswordwidgetbase.ui 	kopetepasswordwidget.cpp accountselector.cpp kopeteviewplugin.cpp \
++		addresseeitem.cpp addressbookselectorwidget_base.ui addressbookselectordialog.cpp \
++			addressbookselectorwidget.cpp metacontactselectorwidget_base.ui 	metacontactselectorwidget.cpp \
++		kopetelistview.cpp kopetelistviewitem.cpp kopetelistviewsearchline.cpp \
++		contactaddednotifywidget.ui contactaddednotifydialog.cpp addressbooklinkwidget_base.ui \
++	addressbooklinkwidget.cpp
+ 
+ libkopeteui_la_LDFLAGS = $(all_libraries) -lkabc
+-libkopeteui_la_LIBADD = ../private/libkopeteprivate.la $(LIB_KHTML) $(LIBXML_LIBS) $(LIBXSLT_LIBS)
++libkopeteui_la_LIBADD = ../private/libkopeteprivate.la $(LIB_KHTML)
+ 
+ kopeteincludedir = $(includedir)/kopete/ui
+-kopeteinclude_HEADERS = accountselector.h fileconfirmbase.h kopetefileconfirmdialog.h \
+-	kopetepasswordwidget.h kopeteview.h addcontactpage.h kopeteawaydialogbase.h  \
+-	kopetepasswordwidgetbase.h kopeteviewplugin.h \
+-	editaccountwidget.h kopetecontactaction.h kopetepassworddialog.h kopetestdaction.h \
+-	userinfodialog.h addressbookselectordialog.h addressbookselectorwidget.h kopetelistview.h kopetelistviewitem.h kopetelistviewsearchline.h
++kopeteinclude_HEADERS = accountselector.h fileconfirmbase.h \
++	kopetefileconfirmdialog.h 	kopetepasswordwidget.h kopeteview.h addcontactpage.h \
++	kopeteawaydialogbase.h 	kopetepasswordwidgetbase.h kopeteviewplugin.h 	editaccountwidget.h \
++	kopetecontactaction.h kopetepassworddialog.h kopetestdaction.h 	userinfodialog.h \
++	addressbookselectordialog.h addressbookselectorwidget.h kopetelistview.h kopetelistviewitem.h \
++	kopetelistviewsearchline.h addressbooklinkwidget.h
+ 
+ noinst_HEADERS = addresseeitem.h contactaddednotifywidget.h
+ 
+--- kopete/libkopete/ui/kopetelistviewitem.cpp	(revision 568672)
++++ kopete/libkopete/ui/kopetelistviewitem.cpp	(revision 586398)
+@@ -820,6 +820,11 @@
+ 	updatePixmap();
+ }
+ 
++ContactComponent::~ContactComponent()
++{
++	delete d;
++}
++
+ void ContactComponent::updatePixmap()
+ {
+ 	setPixmap( contact()->onlineStatus().iconFor( contact(), d->iconSize ) );
+--- knewsticker/knewstickerstub/knewstickerstub.desktop	(revision 568672)
++++ knewsticker/knewstickerstub/knewstickerstub.desktop	(revision 586398)
+@@ -15,6 +15,7 @@
+ Name[fi]=KNewsTickerin asetusten käyttöliittymä
+ Name[fr]=Interface pour la configuration du téléscripteur
+ Name[gl]=Interface de Configuración de KNewsTicker
++Name[he]=ממשק לקביעת התצורה של KNewsTicker
+ Name[hu]=Grafikus felületű beállítóprogram a KNewsTickerhez
+ Name[is]=Stillingatól KNewsTicker
+ Name[it]=Interfaccia per la configurazione di KNewsTicker
+--- knewsticker/knewsticker.desktop	(revision 568672)
++++ knewsticker/knewsticker.desktop	(revision 586398)
+@@ -62,8 +62,10 @@
+ Comment[es]=Teletipo de noticias RDF
+ Comment[et]=RDF uudiste jälgija
+ Comment[eu]=RDF berri-markatzailea
++Comment[fi]=Skrollaava RDF-uutisnäyttäjä
+ Comment[fr]=Défilement de nouvelles RDF
+ Comment[gl]=Un visor de novas RDF deslizante
++Comment[he]=צג חדשות
+ Comment[hu]=Hírbejelentő RSS hírforrásokhoz
+ Comment[is]=Skrunandi RDF fréttastrimill
+ Comment[it]=Un ticker notizie RDF a scorrimento
+--- kget/kget_plug_in/kget_linkview.cpp	(revision 568672)
++++ kget/kget_plug_in/kget_linkview.cpp	(revision 586398)
+@@ -40,7 +40,7 @@
+     setPlainCaption( i18n( "KGet" ) );
+ 
+     KAction* actionDownload = new KAction( i18n("Download Selected Files"),
+-                                           "khtml_kget", CTRL+Key_D,
++                                           "kget", CTRL+Key_D,
+                                            this, SLOT( slotStartLeech() ),
+                                            actionCollection(), "startDownload" );
+ 
+--- kget/kget_plug_in/kget_plug_in.cpp	(revision 568672)
++++ kget/kget_plug_in/kget_plug_in.cpp	(revision 586398)
+@@ -47,7 +47,7 @@
+ KGet_plug_in::KGet_plug_in( QObject* parent, const char* name )
+     : Plugin( parent, name )
+ {
+-    QPixmap pix = KGlobal::iconLoader()->loadIcon("khtml_kget",
++    QPixmap pix = KGlobal::iconLoader()->loadIcon("kget",
+                                                   KIcon::MainToolbar);
+     KActionMenu *menu = new KActionMenu( i18n("Download Manager"), pix,
+                                          actionCollection(), "kget_menu" );
+--- kget/kget_download.desktop	(revision 568672)
++++ kget/kget_download.desktop	(revision 586398)
+@@ -21,9 +21,11 @@
+ Name[es]=Descarga con KGet
+ Name[et]=Laadi alla KGeti abil
+ Name[eu]=Deskargatu KGet-ekin
++Name[fi]=Hae KGet ohjelmalla
+ Name[fr]=Télécharger avec KGet
+ Name[ga]=Íosluchtaigh le KGet
+ Name[gl]=Descargar con KGet
++Name[he]=הורד בעזרת KGet
+ Name[hu]=Letöltés a KGettel
+ Name[is]=Sækja með KGet
+ Name[it]=Scarica con KGet
+--- kget/eventsrc	(revision 568672)
++++ kget/eventsrc	(revision 586398)
+@@ -13,8 +13,10 @@
+ Name[es]=TransferenciaAñadida
+ Name[et]=Ãœlekanne lisatud
+ Name[eu]=DeskargaGehituta
++Name[fi]=SiirtoLisätty
+ Name[fr]=Transfert ajouté
+ Name[gl]=TransferenciaEngadida
++Name[he]=העברה הוספה
+ Name[hu]=ÁtvittHozzáadva
+ Name[is]=Færslu bætt við
+ Name[it]=Aggiunto trasferimento
+@@ -46,8 +48,10 @@
+ Comment[es]=Se ha añadido una nueva descarga
+ Comment[et]=Lisati uus allalaadimine
+ Comment[eu]=Deskarga berri bat gehitu da
++Comment[fi]=Uusi tiedoston haku lisätty
+ Comment[fr]=Un nouveau téléchargement a été ajouté
+ Comment[gl]=Engadiuse unha nova descarga
++Comment[he]=הורדה חדשה הוספה
+ Comment[hu]=Új letöltés lett megadva
+ Comment[is]=Nýju niðurhali hefur verið bætt við
+ Comment[it]=È stato aggiunto un nuovo scaricamento
+@@ -87,8 +91,10 @@
+ Name[es]=DescargaComenzada
+ Name[et]=Allalaadimine alustatud
+ Name[eu]=DeskargaHasita
++Name[fi]=HakuAlkoi
+ Name[fr]=Téléchargement démarré
+ Name[gl]=DescargaComezada
++Name[he]=הורדההתחילה
+ Name[hu]=LetöltésKezdődött
+ Name[is]=Niðurhal sett í gang
+ Name[it]=Scaricamento avviato
+@@ -124,8 +130,10 @@
+ Comment[es]=Una descarga comenzó
+ Comment[et]=Allalaadimine alustatud
+ Comment[eu]=Deskarga hasi da
++Comment[fi]=Tiedoston hakeminen alkoi
+ Comment[fr]=Téléchargement démarré
+ Comment[gl]=Comezou a descarga
++Comment[he]=ההורדה התחילה
+ Comment[hu]=Letöltés kezdődött
+ Comment[is]=Byrjað á niðurhali
+ Comment[it]=Scaricamento avviato
+@@ -165,8 +173,10 @@
+ Name[es]=DescargaAcabada
+ Name[et]=Allalaadimine lõpetatud
+ Name[eu]=DeskargaAmaituta
++Name[fi]=HakuValmistui
+ Name[fr]=Téléchargement terminé
+ Name[gl]=DescargaRematada
++Name[he]=הורדההסתיימה
+ Name[hu]=LetöltésBefejezve
+ Name[is]=Niðurhali lokið
+ Name[it]=Scaricamento completato
+@@ -202,8 +212,10 @@
+ Comment[es]=Una descarga acabó
+ Comment[et]=Allalaadimine lõpetatud
+ Comment[eu]=Deskarga amaitu da
++Comment[fi]=Tiedoston haku valmistui
+ Comment[fr]=Téléchargement terminé
+ Comment[gl]=Rematou a descarga
++Comment[he]=ההורדה הסתיימה
+ Comment[hu]=Egy letöltés befejeződött
+ Comment[is]=Niðurhali lokið
+ Comment[it]=Scaricamento completato
+@@ -241,6 +253,7 @@
+ Name[es]=AñadirDescargasAcabadas
+ Name[et]=Kõik allalaadimised lõpetatud
+ Name[eu]=GehituDeskargakAmaituta
++Name[fi]=LisääHautValmistui
+ Name[fr]=Téléchargements ajoutés terminés
+ Name[hu]=FelvettLetöltésBefejeződött
+ Name[is]=Lokið að bæta við niðurhölum
+@@ -274,8 +287,10 @@
+ Comment[es]=Todas las descargas acabaron
+ Comment[et]=Kõik allalaadimised lõpetatud
+ Comment[eu]=Deskarga guztiak amaituta
++Comment[fi]=Kaikki tiedostojen haut ovat valmistuneet
+ Comment[fr]=Tous les téléchargements sont terminés
+ Comment[gl]=Tódalas descargar están rematadas
++Comment[he]=כל ההורדות הסתיימו
+ Comment[hu]=Minden letöltés befejeződött
+ Comment[is]=Öllum niðurhölum lokið
+ Comment[it]=Tutti gli scaricamenti completati
+--- filesharing/advanced/kcm_sambaconf/kcminterface.ui	(revision 568672)
++++ filesharing/advanced/kcm_sambaconf/kcminterface.ui	(revision 586398)
+@@ -7700,7 +7700,7 @@
+                                         <cstring>groupBox9</cstring>
+                                     </property>
+                                     <property name="title">
+-                                        <string>UMTP</string>
++                                        <string>UTMP</string>
+                                     </property>
+                                     <grid>
+                                         <property name="name">
+--- filesharing/advanced/kcm_sambaconf/kcmsambaconf.desktop	(revision 568672)
++++ filesharing/advanced/kcm_sambaconf/kcmsambaconf.desktop	(revision 586398)
+@@ -27,8 +27,10 @@
+ Comment[es]=Un modulo para configurar recursos compartidos de Microsoft Windows
+ Comment[et]=Microsoft Windowsi jagatud ressursside seadistusmoodul
+ Comment[eu]=Microsoft Windows-en partekatzeak konfiguratzeko modulu bat
++Comment[fi]=Moduli Microsoft Windows jakojen asetuksiin
+ Comment[fr]=Un module permettant de configurer les partages Microsoft Windows
+ Comment[gl]=Un módulo para configurar comparticións con Microsoft Windows
++Comment[he]=מודול להגדרת שיתופים עם חלונות של מיקרוסופט
+ Comment[hu]=Beállítómodul Microsoft Windows-os megosztásokhoz
+ Comment[is]=Eining til að stilla sameignir fyrir Microsoft Windows
+ Comment[it]=Un modulo per configurare le condivisioni per Microsoft Windows
+@@ -43,7 +45,7 @@
+ Comment[pt]=Um módulo para configurar partilhas para o Microsoft Windows
+ Comment[pt_BR]=Um módulo para configurar compartilhamentos com o Microsoft Windows
+ Comment[ru]=Модуль настройки общих ресурсов для Microsoft Windows
+-Comment[sk]=Modul na konfiguráciu zdielania pre Microsoft Windows
++Comment[sk]=Modul na konfiguráciu zdieľania pre Microsoft Windows
+ Comment[sl]=Modul za nastavitev souporabe map za Microsoft Windows
+ Comment[sr]=Модул који подешава дељења за Microsoft Windows
+ Comment[sr at Latn]=Modul koji podešava deljenja za Microsoft Windows
+@@ -60,6 +62,7 @@
+ Keywords[de]=KcmSambaConf,kcmsambaconf,samba,windows,freigabe
+ Keywords[et]=KcmSambaConf,kcmsambaconf,samba,windows,jagatud ressursid
+ Keywords[eu]=KcmSambaConf,kcmsambaconf,samba,windows,partekatze
++Keywords[fi]=KcmSambaConf,kcmsambaconf,samba,windows,jako
+ Keywords[fr]=KcmSambaConf,kcmsambaconf,samba,windows,partage
+ Keywords[gl]=KcmSambaConf,kcmsambaconf,samba,widows,compartir
+ Keywords[he]=KcmSambaConf,kcmsambaconf,samba,windows,share, סמבה, חלונות, שיתוף, שיתופי חלונות
+--- filesharing/advanced/propsdlgplugin/fileshare_propsdlgplugin.desktop	(revision 568672)
++++ filesharing/advanced/propsdlgplugin/fileshare_propsdlgplugin.desktop	(revision 586398)
+@@ -17,6 +17,7 @@
+ Name[fi]=Konquerorin tiedostojakojen ominaisuussivu
+ Name[fr]=Page des propriétés d'un dossier de partage de Konqueror
+ Name[gl]=Páxina coas Propiedades do Directorio de Ficheiros Compartidos de Konqueror
++Name[he]=דף מאפייני ספרית קבצים משותפת של Konqueror
+ Name[hu]=Fájlmegosztási lap a Konqueror könyvtártulajdonságainál
+ Name[is]=Skráastjóraeiginleikar Konqueror
+ Name[it]=Pagina delle proprietà di Konqueror per la condivisione
+--- filesharing/simple/fileshare.cpp	(revision 568672)
++++ filesharing/simple/fileshare.cpp	(revision 586398)
+@@ -87,7 +87,8 @@
+ 
+   if ( nfsExec.isEmpty() && sambaExec.isEmpty())
+   {
+-      m_ccgui->setEnabled( false );
++      m_ccgui->shareGrp->setDisabled(true);
++      m_ccgui->sharedFoldersGroupBox->setDisabled(true);
+   }
+   else
+   {   
+--- filesharing/simple/fileshare.desktop	(revision 568672)
++++ filesharing/simple/fileshare.desktop	(revision 586398)
+@@ -79,7 +79,7 @@
+ Comment[hu]=A fájlmegosztás ki-be kapcsolása
+ Comment[is]=Virkja eða slökkva á skráardeilingu um net
+ Comment[it]=Abilita o disabilita la condivisione dei file
+-Comment[ja]=ファイル共有を有効ないし無効にします
++Comment[ja]=ファイル共有を有効または無効にします
+ Comment[km]=អនុញ្ញាត ឬ មិន​អនុញ្ញាត​ការ​ចែក​រំ​លែក​ឯកសារ
+ Comment[lt]=Įjungti ar išjungti bylų dalinimąsi
+ Comment[mk]=Овозможува или оневозможува делење на датотеки
+--- filesharing/simple/controlcenter.ui	(revision 568672)
++++ filesharing/simple/controlcenter.ui	(revision 586398)
+@@ -288,7 +288,7 @@
+         </widget>
+         <widget class="QGroupBox">
+             <property name="name">
+-                <cstring>groupBox1</cstring>
++                <cstring>sharedFoldersGroupBox</cstring>
+             </property>
+             <property name="title">
+                 <string>Shared Folders</string>
+--- COPYING-DOCS	(revision 0)
++++ COPYING-DOCS	(revision 586398)
+@@ -0,0 +1,397 @@
++		GNU Free Documentation License
++		  Version 1.2, November 2002
++
++
++ Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
++     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++
++0. PREAMBLE
++
++The purpose of this License is to make a manual, textbook, or other
++functional and useful document "free" in the sense of freedom: to
++assure everyone the effective freedom to copy and redistribute it,
++with or without modifying it, either commercially or noncommercially.
++Secondarily, this License preserves for the author and publisher a way
++to get credit for their work, while not being considered responsible
++for modifications made by others.
++
++This License is a kind of "copyleft", which means that derivative
++works of the document must themselves be free in the same sense.  It
++complements the GNU General Public License, which is a copyleft
++license designed for free software.
++
++We have designed this License in order to use it for manuals for free
++software, because free software needs free documentation: a free
++program should come with manuals providing the same freedoms that the
++software does.  But this License is not limited to software manuals;
++it can be used for any textual work, regardless of subject matter or
++whether it is published as a printed book.  We recommend this License
++principally for works whose purpose is instruction or reference.
++
++
++1. APPLICABILITY AND DEFINITIONS
++
++This License applies to any manual or other work, in any medium, that
++contains a notice placed by the copyright holder saying it can be
++distributed under the terms of this License.  Such a notice grants a
++world-wide, royalty-free license, unlimited in duration, to use that
++work under the conditions stated herein.  The "Document", below,
++refers to any such manual or work.  Any member of the public is a
++licensee, and is addressed as "you".  You accept the license if you
++copy, modify or distribute the work in a way requiring permission
++under copyright law.
++
++A "Modified Version" of the Document means any work containing the
++Document or a portion of it, either copied verbatim, or with
++modifications and/or translated into another language.
++
++A "Secondary Section" is a named appendix or a front-matter section of
++the Document that deals exclusively with the relationship of the
++publishers or authors of the Document to the Document's overall subject
++(or to related matters) and contains nothing that could fall directly
++within that overall subject.  (Thus, if the Document is in part a
++textbook of mathematics, a Secondary Section may not explain any
++mathematics.)  The relationship could be a matter of historical
++connection with the subject or with related matters, or of legal,
++commercial, philosophical, ethical or political position regarding
++them.
++
++The "Invariant Sections" are certain Secondary Sections whose titles
++are designated, as being those of Invariant Sections, in the notice
++that says that the Document is released under this License.  If a
++section does not fit the above definition of Secondary then it is not
++allowed to be designated as Invariant.  The Document may contain zero
++Invariant Sections.  If the Document does not identify any Invariant
++Sections then there are none.
++
++The "Cover Texts" are certain short passages of text that are listed,
++as Front-Cover Texts or Back-Cover Texts, in the notice that says that
++the Document is released under this License.  A Front-Cover Text may
++be at most 5 words, and a Back-Cover Text may be at most 25 words.
++
++A "Transparent" copy of the Document means a machine-readable copy,
++represented in a format whose specification is available to the
++general public, that is suitable for revising the document
++straightforwardly with generic text editors or (for images composed of
++pixels) generic paint programs or (for drawings) some widely available
++drawing editor, and that is suitable for input to text formatters or
++for automatic translation to a variety of formats suitable for input
++to text formatters.  A copy made in an otherwise Transparent file
++format whose markup, or absence of markup, has been arranged to thwart
++or discourage subsequent modification by readers is not Transparent.
++An image format is not Transparent if used for any substantial amount
++of text.  A copy that is not "Transparent" is called "Opaque".
++
++Examples of suitable formats for Transparent copies include plain
++ASCII without markup, Texinfo input format, LaTeX input format, SGML
++or XML using a publicly available DTD, and standard-conforming simple
++HTML, PostScript or PDF designed for human modification.  Examples of
++transparent image formats include PNG, XCF and JPG.  Opaque formats
++include proprietary formats that can be read and edited only by
++proprietary word processors, SGML or XML for which the DTD and/or
++processing tools are not generally available, and the
++machine-generated HTML, PostScript or PDF produced by some word
++processors for output purposes only.
++
++The "Title Page" means, for a printed book, the title page itself,
++plus such following pages as are needed to hold, legibly, the material
++this License requires to appear in the title page.  For works in
++formats which do not have any title page as such, "Title Page" means
++the text near the most prominent appearance of the work's title,
++preceding the beginning of the body of the text.
++
++A section "Entitled XYZ" means a named subunit of the Document whose
++title either is precisely XYZ or contains XYZ in parentheses following
++text that translates XYZ in another language.  (Here XYZ stands for a
++specific section name mentioned below, such as "Acknowledgements",
++"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
++of such a section when you modify the Document means that it remains a
++section "Entitled XYZ" according to this definition.
++
++The Document may include Warranty Disclaimers next to the notice which
++states that this License applies to the Document.  These Warranty
++Disclaimers are considered to be included by reference in this
++License, but only as regards disclaiming warranties: any other
++implication that these Warranty Disclaimers may have is void and has
++no effect on the meaning of this License.
++
++
++2. VERBATIM COPYING
++
++You may copy and distribute the Document in any medium, either
++commercially or noncommercially, provided that this License, the
++copyright notices, and the license notice saying this License applies
++to the Document are reproduced in all copies, and that you add no other
++conditions whatsoever to those of this License.  You may not use
++technical measures to obstruct or control the reading or further
++copying of the copies you make or distribute.  However, you may accept
++compensation in exchange for copies.  If you distribute a large enough
++number of copies you must also follow the conditions in section 3.
++
++You may also lend copies, under the same conditions stated above, and
++you may publicly display copies.
++
++
++3. COPYING IN QUANTITY
++
++If you publish printed copies (or copies in media that commonly have
++printed covers) of the Document, numbering more than 100, and the
++Document's license notice requires Cover Texts, you must enclose the
++copies in covers that carry, clearly and legibly, all these Cover
++Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
++the back cover.  Both covers must also clearly and legibly identify
++you as the publisher of these copies.  The front cover must present
++the full title with all words of the title equally prominent and
++visible.  You may add other material on the covers in addition.
++Copying with changes limited to the covers, as long as they preserve
++the title of the Document and satisfy these conditions, can be treated
++as verbatim copying in other respects.
++
++If the required texts for either cover are too voluminous to fit
++legibly, you should put the first ones listed (as many as fit
++reasonably) on the actual cover, and continue the rest onto adjacent
++pages.
++
++If you publish or distribute Opaque copies of the Document numbering
++more than 100, you must either include a machine-readable Transparent
++copy along with each Opaque copy, or state in or with each Opaque copy
++a computer-network location from which the general network-using
++public has access to download using public-standard network protocols
++a complete Transparent copy of the Document, free of added material.
++If you use the latter option, you must take reasonably prudent steps,
++when you begin distribution of Opaque copies in quantity, to ensure
++that this Transparent copy will remain thus accessible at the stated
++location until at least one year after the last time you distribute an
++Opaque copy (directly or through your agents or retailers) of that
++edition to the public.
++
++It is requested, but not required, that you contact the authors of the
++Document well before redistributing any large number of copies, to give
++them a chance to provide you with an updated version of the Document.
++
++
++4. MODIFICATIONS
++
++You may copy and distribute a Modified Version of the Document under
++the conditions of sections 2 and 3 above, provided that you release
++the Modified Version under precisely this License, with the Modified
++Version filling the role of the Document, thus licensing distribution
++and modification of the Modified Version to whoever possesses a copy
++of it.  In addition, you must do these things in the Modified Version:
++
++A. Use in the Title Page (and on the covers, if any) a title distinct
++   from that of the Document, and from those of previous versions
++   (which should, if there were any, be listed in the History section
++   of the Document).  You may use the same title as a previous version
++   if the original publisher of that version gives permission.
++B. List on the Title Page, as authors, one or more persons or entities
++   responsible for authorship of the modifications in the Modified
++   Version, together with at least five of the principal authors of the
++   Document (all of its principal authors, if it has fewer than five),
++   unless they release you from this requirement.
++C. State on the Title page the name of the publisher of the
++   Modified Version, as the publisher.
++D. Preserve all the copyright notices of the Document.
++E. Add an appropriate copyright notice for your modifications
++   adjacent to the other copyright notices.
++F. Include, immediately after the copyright notices, a license notice
++   giving the public permission to use the Modified Version under the
++   terms of this License, in the form shown in the Addendum below.
++G. Preserve in that license notice the full lists of Invariant Sections
++   and required Cover Texts given in the Document's license notice.
++H. Include an unaltered copy of this License.
++I. Preserve the section Entitled "History", Preserve its Title, and add
++   to it an item stating at least the title, year, new authors, and
++   publisher of the Modified Version as given on the Title Page.  If
++   there is no section Entitled "History" in the Document, create one
++   stating the title, year, authors, and publisher of the Document as
++   given on its Title Page, then add an item describing the Modified
++   Version as stated in the previous sentence.
++J. Preserve the network location, if any, given in the Document for
++   public access to a Transparent copy of the Document, and likewise
++   the network locations given in the Document for previous versions
++   it was based on.  These may be placed in the "History" section.
++   You may omit a network location for a work that was published at
++   least four years before the Document itself, or if the original
++   publisher of the version it refers to gives permission.
++K. For any section Entitled "Acknowledgements" or "Dedications",
++   Preserve the Title of the section, and preserve in the section all
++   the substance and tone of each of the contributor acknowledgements
++   and/or dedications given therein.
++L. Preserve all the Invariant Sections of the Document,
++   unaltered in their text and in their titles.  Section numbers
++   or the equivalent are not considered part of the section titles.
++M. Delete any section Entitled "Endorsements".  Such a section
++   may not be included in the Modified Version.
++N. Do not retitle any existing section to be Entitled "Endorsements"
++   or to conflict in title with any Invariant Section.
++O. Preserve any Warranty Disclaimers.
++
++If the Modified Version includes new front-matter sections or
++appendices that qualify as Secondary Sections and contain no material
++copied from the Document, you may at your option designate some or all
++of these sections as invariant.  To do this, add their titles to the
++list of Invariant Sections in the Modified Version's license notice.
++These titles must be distinct from any other section titles.
++
++You may add a section Entitled "Endorsements", provided it contains
++nothing but endorsements of your Modified Version by various
++parties--for example, statements of peer review or that the text has
++been approved by an organization as the authoritative definition of a
++standard.
++
++You may add a passage of up to five words as a Front-Cover Text, and a
++passage of up to 25 words as a Back-Cover Text, to the end of the list
++of Cover Texts in the Modified Version.  Only one passage of
++Front-Cover Text and one of Back-Cover Text may be added by (or
++through arrangements made by) any one entity.  If the Document already
++includes a cover text for the same cover, previously added by you or
++by arrangement made by the same entity you are acting on behalf of,
++you may not add another; but you may replace the old one, on explicit
++permission from the previous publisher that added the old one.
++
++The author(s) and publisher(s) of the Document do not by this License
++give permission to use their names for publicity for or to assert or
++imply endorsement of any Modified Version.
++
++
++5. COMBINING DOCUMENTS
++
++You may combine the Document with other documents released under this
++License, under the terms defined in section 4 above for modified
++versions, provided that you include in the combination all of the
++Invariant Sections of all of the original documents, unmodified, and
++list them all as Invariant Sections of your combined work in its
++license notice, and that you preserve all their Warranty Disclaimers.
++
++The combined work need only contain one copy of this License, and
++multiple identical Invariant Sections may be replaced with a single
++copy.  If there are multiple Invariant Sections with the same name but
++different contents, make the title of each such section unique by
++adding at the end of it, in parentheses, the name of the original
++author or publisher of that section if known, or else a unique number.
++Make the same adjustment to the section titles in the list of
++Invariant Sections in the license notice of the combined work.
++
++In the combination, you must combine any sections Entitled "History"
++in the various original documents, forming one section Entitled
++"History"; likewise combine any sections Entitled "Acknowledgements",
++and any sections Entitled "Dedications".  You must delete all sections
++Entitled "Endorsements".
++
++
++6. COLLECTIONS OF DOCUMENTS
++
++You may make a collection consisting of the Document and other documents
++released under this License, and replace the individual copies of this
++License in the various documents with a single copy that is included in
++the collection, provided that you follow the rules of this License for
++verbatim copying of each of the documents in all other respects.
++
++You may extract a single document from such a collection, and distribute
++it individually under this License, provided you insert a copy of this
++License into the extracted document, and follow this License in all
++other respects regarding verbatim copying of that document.
++
++
++7. AGGREGATION WITH INDEPENDENT WORKS
++
++A compilation of the Document or its derivatives with other separate
++and independent documents or works, in or on a volume of a storage or
++distribution medium, is called an "aggregate" if the copyright
++resulting from the compilation is not used to limit the legal rights
++of the compilation's users beyond what the individual works permit.
++When the Document is included in an aggregate, this License does not
++apply to the other works in the aggregate which are not themselves
++derivative works of the Document.
++
++If the Cover Text requirement of section 3 is applicable to these
++copies of the Document, then if the Document is less than one half of
++the entire aggregate, the Document's Cover Texts may be placed on
++covers that bracket the Document within the aggregate, or the
++electronic equivalent of covers if the Document is in electronic form.
++Otherwise they must appear on printed covers that bracket the whole
++aggregate.
++
++
++8. TRANSLATION
++
++Translation is considered a kind of modification, so you may
++distribute translations of the Document under the terms of section 4.
++Replacing Invariant Sections with translations requires special
++permission from their copyright holders, but you may include
++translations of some or all Invariant Sections in addition to the
++original versions of these Invariant Sections.  You may include a
++translation of this License, and all the license notices in the
++Document, and any Warranty Disclaimers, provided that you also include
++the original English version of this License and the original versions
++of those notices and disclaimers.  In case of a disagreement between
++the translation and the original version of this License or a notice
++or disclaimer, the original version will prevail.
++
++If a section in the Document is Entitled "Acknowledgements",
++"Dedications", or "History", the requirement (section 4) to Preserve
++its Title (section 1) will typically require changing the actual
++title.
++
++
++9. TERMINATION
++
++You may not copy, modify, sublicense, or distribute the Document except
++as expressly provided for under this License.  Any other attempt to
++copy, modify, sublicense or distribute the Document is void, and will
++automatically terminate your rights under this License.  However,
++parties who have received copies, or rights, from you under this
++License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++
++10. FUTURE REVISIONS OF THIS LICENSE
++
++The Free Software Foundation may publish new, revised versions
++of the GNU Free Documentation License from time to time.  Such new
++versions will be similar in spirit to the present version, but may
++differ in detail to address new problems or concerns.  See
++http://www.gnu.org/copyleft/.
++
++Each version of the License is given a distinguishing version number.
++If the Document specifies that a particular numbered version of this
++License "or any later version" applies to it, you have the option of
++following the terms and conditions either of that specified version or
++of any later version that has been published (not as a draft) by the
++Free Software Foundation.  If the Document does not specify a version
++number of this License, you may choose any version ever published (not
++as a draft) by the Free Software Foundation.
++
++
++ADDENDUM: How to use this License for your documents
++
++To use this License in a document you have written, include a copy of
++the License in the document and put the following copyright and
++license notices just after the title page:
++
++    Copyright (c)  YEAR  YOUR NAME.
++    Permission is granted to copy, distribute and/or modify this document
++    under the terms of the GNU Free Documentation License, Version 1.2
++    or any later version published by the Free Software Foundation;
++    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
++    A copy of the license is included in the section entitled "GNU
++    Free Documentation License".
++
++If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
++replace the "with...Texts." line with this:
++
++    with the Invariant Sections being LIST THEIR TITLES, with the
++    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
++
++If you have Invariant Sections without Cover Texts, or some other
++combination of the three, merge those two alternatives to suit the
++situation.
++
++If your document contains nontrivial examples of program code, we
++recommend releasing these examples in parallel under your choice of
++free software license, such as the GNU General Public License,
++to permit their use in free software.
+--- wifi/interface_wireless_wirelessextensions.cpp	(revision 568672)
++++ wifi/interface_wireless_wirelessextensions.cpp	(revision 586398)
+@@ -533,14 +533,17 @@
+ 
+     *iwlist << iwlist_bin << interface_name << "scanning";
+ 
+-    connect ( iwlist, SIGNAL ( readReady ( KProcIO * ) ), this, SLOT ( parseScanData ( KProcIO * ) ) );
++//    connect ( iwlist, SIGNAL ( readReady ( KProcIO * ) ), this, SLOT ( parseScanData ( KProcIO * ) ) );
+ 	    
+    if ( !iwlist->start ( KProcess::Block ) )
+         KMessageBox::sorry ( 0, i18n ( "Unable to perform the scan. Please make sure the executable \"iwlist\" is in your $PATH." ),
+ 				i18n ( "Scanning not possible" ) );
+ 
+-    // while (iwlist->isRunning()) sleep ( 1 );
++    // this should never happen. But there was a report about Block not being as blocking as it should, so let's be safe about it
++    while (iwlist->isRunning()) sleep ( 1 );
+ 
++    parseScanData ( iwlist );
++   
+     for (int i = 0; i<4; i++ ) networks->adjustColumn(i);
+ 
+     return networks;
+@@ -598,17 +601,23 @@
+         }
+       if ( !ignoreRemainingBits && data.contains ( "Encryption key:" ) )
+         {
+-          if ( data.contains ( "on" ) )
++          if ( data.contains ( "off" ) )
++            networks->setText ( cellcount - 1, 3, QString ( "off" ) );
++          else
+             networks->setText ( cellcount - 1, 3, QString ( "on" ) );
+-          else
+-            networks->setText ( cellcount - 1, 3, QString ( "off" ) );
+         }
+       if ( !ignoreRemainingBits && data.contains ( "Quality:" ) )
+         {
+           QString quality = data.mid ( data.find ( ":" ) + 1, data.find ( "/" ) - data.find ( ":" ) - 1 );
+           networks->setText ( cellcount - 1, 2, quality );
+         }
+-
++      
++      if ( !ignoreRemainingBits && data.contains ( "Quality=" ) )
++        {
++          QString quality = data.mid ( data.find ( "=" ) + 1, data.find ( "/" ) - data.find ( "=" ) - 1 );
++          networks->setText ( cellcount - 1, 2, quality );
++        }
++      
+       if ( !ignoreRemainingBits && data.contains ( "wpa_ie" ) )
+ 	{
+ 	  networks->setText ( cellcount - 1, 3, QString ( "WPA" ) );
+--- wifi/kwifimanager.desktop	(revision 568672)
++++ wifi/kwifimanager.desktop	(revision 586398)
+@@ -84,6 +84,7 @@
+ GenericName[fi]=Langattoman lähiverkon hallinta
+ GenericName[fr]=Gestionnaire de réseau sans fil
+ GenericName[ga]=Bainisteoir Ghréasáin gan sreang
++GenericName[he]=מנהל LAN אלחוטי
+ GenericName[hi]= बेतार लैन मैनेजर
+ GenericName[hr]=Upravitelj bežičnog LAN-a
+ GenericName[hu]=WiFi-kezelő
+--- doc/kopete/chatstyle.docbook	(revision 0)
++++ doc/kopete/chatstyle.docbook	(revision 586398)
+@@ -0,0 +1,363 @@
++<!-- Copyright (c) 2005 by Michaël Larouche <michael.larouche at kdemail.net> -->
++<!-- Licensed under the GNU Free Documentation License  -->
++
++<appendix id="chatwindowstyleguide">
++<title>&kopete; Chat Window Style Guide</title>
++<sect1 id="chatstyle-reference">
++<title>&kopete; Chat Window Style reference.</title>
++<para>
++Beginning with &kopete; 0.12, we are now using <ulink
++url="http://www.adiumx.com/">Adium</ulink> format for our
++Chat Window style. The theme format is based on <acronym>HTML</acronym> templates and <acronym>CSS</acronym>. They
++are easier to make and develop, only a knowledge of <acronym>HTML</acronym> and <acronym>CSS</acronym> is needed. Also, styles can have variants (defined as <acronym>CSS</acronym> file) which add more customisation value :).
++</para>
++
++<sect2 id="chatstyle-reference-guide">
++	<title>Reference guide.</title>
++<para>
++Adium format consist of a directory structure, <acronym>HTML</acronym> templates, <acronym>CSS</acronym> files and keywords that are replaced each time the template is processed. The final conversation is a <acronym>XHTML</acronym> page where messages are added with <acronym>DOM</acronym> operations. The central element is a div element named <filename>Chat</filename>. Before and after this div element goes the Header and Footer template. Messages are childs of the <filename>Chat</filename> div element.
++</para>
++
++<sect3 id="chatstyle-refrerence-directory">
++	<title>Directory Structure</title>
++<para>A style must respect this directory structure. Code in &kopete; are thinking around this directory structure. When archiving the style, archive the <filename>styleName</filename> directory. The directory structure is a structure of a <application>Mac OS X</application> bundle for those familiar with that operating system. Also you must respect the case displayed here, because a <acronym>UNIX</acronym> system is case-sensitive.</para>
++<programlisting>
++styleName\ (can have .adiumMessageStyle as suffix, because in Mac OS X it is a bundle)
++        Contents\
++                Info.plist
++                Resources\
++                        main.css
++                        Header.html
++                        Footer.html
++                        Status.html
++                        Incoming\ (and Outgoing\)
++                                Content.html
++                                NextContent.html (for consecutive messages)
++                                Context.html (for message history)
++                                NextContext.html
++                                Action.html
++                        Variants\
++                                *.css
++</programlisting>
++</sect3>
++
++<sect3 id="chatstyle-reference-divinsert">
++	<title>About &lt;div id="insert"&gt;&lt;/div&gt;</title>
++	<para>This is a special div element used internally. It is a placeholder to indicate where to insert the next message. If it's a new message, it is removed and the new message take place. But if it's a consecutive message, the div element is replaced with the content of new message. This special div element is <emphasis>required</emphasis> in Content,Context,NextContent,NextContext templates. Though it not harm to put it also in Action and Status template.
++	</para>
++</sect3>
++
++<sect3 id="chatstyle-reference-templates">
++	<title>HTML templates.</title>
++
++<variablelist><title>Template description.</title>
++
++<varlistentry><term><filename>Header.html</filename> (Required)</term>
++<listitem>
++<para>
++Use the Header template to display a nice header to the conversation. This template is insered before <filename>Chat</filename> div element. If you don't use it, just put an empty file.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>Footer.html</filename> (Required)</term>
++<listitem>
++<para>
++This is mostly the same as Header but it is for the fotter of a conversation. This template is insered after <filename>Chat</filename> div element.  If you don't use it, just put an empty file.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>Status.html</filename> (Required)</term>
++<listitem>
++<para>
++This template is used to display a internal message. Internal messages such as status change, message from Kopete(ex: Incoming File Transfert). When the style do not supply a Action template, it is used to display Action message.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>Incoming/Content.html</filename></term>
++              <term><filename>Outgoing/Content.html</filename> (Required)</term>
++<listitem>
++<para>
++The content template is the message core. Think it as a block that will hold messages.. Make sure it is ready to receive consecutive messages, don't design it to only display one message. Consecutive messages will be inserted at the div insert element.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>Incoming/NextContent.html</filename></term>
++              <term><filename>Outgoing/NextContent.html</filename> (Required)</term>
++<listitem>
++<para>
++The NextContent template is a message fragment for consecutive messages. It will be inserted into the main message block. The HTML template should contain the bare minimum to display a message.
++</para>
++</listitem>
++</varlistentry>
++
++
++<varlistentry><term><filename>Incoming/Action.html</filename></term>
++              <term><filename>Outgoing/Action.html</filename> (Optional) (&kopete; Extension)</term>
++<listitem>
++<para>
++This template is a &kopete; extension to the Adium format. It is available for Incoming and Outgoing direction. Action messages are special message to tell we are doing a action. Example: "/me is installing &kopete;" would be displayed as "DarkShock is installing &kopete;".
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>Incoming/Context.html</filename></term>
++              <term><filename>Incoming/NextContext.html</filename></term>
++              <term><filename>Outgoing/Context.html</filename></term>
++              <term><filename>Outgoing/NextContext.html</filename> (Optional)</term>
++<listitem>
++<para>
++These templates are not used in Kopete. In Adium, they are used to display history. It is mostly the same thing as Content and NextContent but with some differences to distinguist from normal messages.
++</para>
++</listitem>
++</varlistentry>
++
++</variablelist>
++
++</sect3>
++
++<sect3 id="chatstyle-reference-css">
++	<title>About CSS styles and Variants</title>
++	<para>HTML template are used to describe how the structure is made. But all the style is described in <acronym>CSS</acronym> files. <filename>main.css</filename> is the main style, where variants are just alterations of the main style. Examples of variants are differents colors, no display of user photo. Both <filename>main.css</filename> and variants and imported in final <acronym>XHTML</acronym> page.</para>
++	<sect4 id="chatstyle-reference-css-main">
++		<title>-<filename>main.css</filename></title>
++		<para>This is the main <acronym>CSS</acronym> file which is common for all variants. This file should contain all the main description of the style.</para>
++	</sect4>
++	<sect4 id="chatstyle-refrence-css-variants">
++		<title>-Variants</title>
++		<para>Variants are <acronym>CSS</acronym> files located in <filename>Variants/</filename> directory. Each variant is a single <acronym>CSS</acronym> file that include the <filename>main.css</filename> and do alteration to the main style.</para>
++	</sect4>
++</sect3>
++
++<sect3 id="chatstyle-reference-debug">
++	<title>Debugging styles</title>
++	<para>Here is two tips for testing a style while creating it.</para>
++	<sect4 id="chatstyle-reference-debug-save">
++		<title>-Save a sample conversation.</title>
++		<para>In Chat Window, you can <action>save</action> a conversation. This is a copy of the internal XHTML page displayed. Use it in <application>Konqueror</application> to test your <acronym>CSS</acronym> files.</para>
++	</sect4>
++	<sect4 id="chatstyle-reference-debug-disable-cache">
++		<title>-Disable style cache.</title>
++		<para>A little configuration switch exist to disable the style cache. When enabled, it reload the HTML templates each time the style is asked. Add the following lines to your <filename>kopeterc</filename>. Very useful when testing a style in &kopete;</para>
++		<programlisting>
++[KopeteStyleDebug]
++disableStyleCache=true
++</programlisting>
++	</sect4>
++</sect3>
++
++</sect2>
++
++<sect2 id="chatstyle-reference-keywords">
++	<title>Keywords reference</title>
++	<para>Keywords are likes holes to fill with details. On each new message, they are replaced with the correct value corresponding to their context. To fully support all features of Kopete, we added some keywords extentions to the Adium. Also some keywords are only available in certain context.</para>
++
++<variablelist><title>Keywords list for Header and Footer templates. </title>
++<para>There keywords are processed at the beginning of the chat.</para>
++<varlistentry><term><filename>%chatName%</filename></term>
++<listitem>
++<para>
++This is the name of the current chat session. For a typical session, it display the name of the contact and his status. For <acronym>IRC</acronym>, it display the topic of a channel.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%sourceName%</filename></term>
++              <term><filename>%destinationName%</filename></term>
++<listitem>
++<para>
++These are the name of the contacts for a chatsession. <filename>%sourceName%</filename> is your name. <filename>%destinationName%</filename> is the name of the contact you are chatting with. Prefer <filename>%chatName%</filename> over those, because they could be confusing for groupchat and IRC.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%incomingIconPath%</filename></term>
++              <term><filename>%outgoingIconPath%</filename></term>
++<listitem>
++<para>
++These are the image/photo/avatar of the contacts for a chatsession. Incoming represent the contact photo and Outgoing represent your own photo. If they are no photo available, it use <filename>buddy_icon.png</filename> image which is located in <filename>Incoming</filename> or <filename>Outgoing</filename> directory.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%timeOpened%</filename></term>
++              <term><filename>%timeOpened{X}%</filename></term>
++<listitem>
++<para>
++It is the time when the chat session begin. <filename>%timeOpened%</filename> use the default time format for the current locale. If you want to use a specific time format, use <filename>%timeOpened{X}%</filename> where X is a string containing the time format. The time parameters are the same as the glibc function <function>strftime</function>. Do <command>man strftime</command> to get the list of available parameters.
++</para>
++</listitem>
++</varlistentry>
++
++</variablelist>
++
++<variablelist><title>Keywords list for Content, NextContent, Context, NextContext, Action template</title>
++<para>There keywords are processed for each message.</para>
++
++<varlistentry><term><filename>%userIconPath%</filename></term>
++<listitem>
++<para>
++This is the image/photo/avatar of the contact associated with the message. If they are no photo available, it use <filename>buddy_icon.png</filename> image which is located in <filename>Incoming</filename> and <filename>Outgoing</filename> directory depending of the message direction.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%senderScreenName%</filename></term>
++<listitem>
++<para>
++This is the contact ID of the contact associated with the message. Examples: me at hotmail.com, 45566576, JohnSmith.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%sender%</filename></term>
++<listitem>
++<para>
++This is the name of the contact associated with the message. It use MetaContact display name as a source.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%service%</filename></term>
++<listitem>
++<para>
++Display the name of the service associated with the message. Examples: Jabber, Yahoo, MSN.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%textbackgroundcolor{X}%</filename></term>
++<listitem>
++<para>
++In &kopete;, this keyword is used to represent the highlight background color. Ignore parameter in the braces and only use it as <filename>%textbackgroundcolor{}</filename>.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%senderStatusIcon%</filename> (&kopete; extension)</term>
++<listitem>
++<para>
++Display the status icon of the contact associated with the message. It's a file path.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%senderColor%</filename></term>  <term><filename>%senderColor{N}%</filename>  (&kopete; extension)</term>
++<listitem>
++<para>
++Generate a color from the sender contact id. Can be used to display a different color for contact nickname.
++</para>
++<para>
++<filename>%senderColor{N}%</filename> where N is a positive number. If N is greater than 100, it represent a lighter color than the contact's color.
++If N equal 150 it is a color which is 50% brighter. If N is less than 100 then it is a darker color.  Usefull for having a background coloured differently for each contact.
++</para>
++<para>
++If you want to use theses colors in a variant, but not in the main style, you have to workaround.
++<programlisting>
++<![CDATA[
++<div style="color:%senderColor%;border:none;border-color:%senderColor{40}%;"><p class="message">...</p></div>
++]]>
++</programlisting>
++you can apply color ro the p.message element in your <filename>main.css</filename> file, and in your varient put something like
++<programlisting>
++	p.message { color:inherit; border-color:inherit; }
++</programlisting>
++
++</para>
++</listitem>
++</varlistentry>
++
++</variablelist>
++
++<variablelist><title>Keyword list common for messages and Status.html</title>
++
++<varlistentry><term><filename>%message%</filename></term>
++<listitem>
++<para>
++The message itself. This is a HTML fragment.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%time%</filename></term>
++              <term><filename>%time{X}%</filename></term>
++<listitem>
++<para>
++The time when the message was received. <filename>%time%</filename> use the default time format for the current locale. If you want to use a specific time format, use <filename>%time{X}%</filename> where X is a string containing the time format. The time parameters are the same as the glibc function <function>strftime</function>. Do <command>man strftime</command> to get the list of available parameters.
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry><term><filename>%messageDirection%</filename> (&kopete; Extension)</term>
++<listitem>
++<para>
++Represent the message direction, if the message must be displayed right-to-left or left-to-right. The values are either "rtl" or "ltr". Read <link linkend="chatstyle-guideline-direction">Message Direction guideline</link> to see how to use this keyword properly.
++</para>
++</listitem>
++</varlistentry>
++</variablelist>
++
++</sect2>
++</sect1>
++
++<sect1 id="chatstyle-guideline">
++	<title>&kopete; Chat Window Style Guideline</title>
++<para>The &kopete; Chat Window Style Guideline is a set of things that your Chat Window style must support to be compilant with Kopete.</para>
++<sect2 id="chatstyle-guideline-highlight">
++	<title>Support highlight</title>
++	<para>Your style must show hightlight. In Kopete and Adium, the <filename>%textbackgroundcolor{}%</filename> is replaced with the hightlight color. Add this style attribute: <userinput>background-color: %textbackgroundcolor{}%</userinput> to the HTML element that display the message.</para>
++</sect2>
++<sect2 id="chatstyle-guideline-consecutive">
++	<title>Consecutive message templates are required.</title>
++	<para>This guideline is for people rewriting old XSL styles to the new format. All styles must supply a template for consecutive messages. It is now a default feature.</para>
++</sect2>
++
++<sect2 id="chatstyle-guideline-encoding">
++	<title>Use <acronym>UTF-8</acronym> encoding.</title>
++	<para>The title said it all. You must save your files to <acronym>UTF-8</acronym>.</para>
++</sect2>
++
++<sect2 id="chatstyle-guideline-info">
++	<title>Supply <filename>Contents/Info.plist</filename> for interopability with Adium</title>
++	<para>The <filename>Contents/Info.plist</filename> file is not used in Kopete yet. But if you want your style to be compatible with <application>Adium</application>, you must supply that file. Here a basic example file. Strings to replace are enclosed with "$".</para>
++<programlisting>
++<![CDATA[
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
++<plist version="1.0">
++<dict>
++	<key>CFBundleDevelopmentRegion</key>
++	<string>English</string>
++	<key>CFBundleGetInfoString</key>
++	<string>$Your style full name$</string>
++	<key>CFBundleIdentifier</key>
++	<string>$Your style ID in the form: com.adiumx.smooth.operator.style$</string>
++	<key>CFBundleInfoDictionaryVersion</key>
++	<string>1.0</string>
++	<key>CFBundleName</key>
++	<string>$Your style name here$</string>
++	<key>CFBundlePackageType</key>
++	<string>AdIM</string>
++	<key>MessageViewVersion</key>
++	<integer>3</integer>
++</dict>
++</plist>
++]]>
++</programlisting>
++
++</sect2>
++
++<sect2 id="chatstyle-guideline-buddyicon">
++	<title>Supply <filename>buddy_icon.png</filename></title>
++	<para>You must place a file named <filename>buddy_icon.png</filename> in the <filename>Incoming</filename> and <filename>Outgoing</filename>. These images will be used when the contact have no photo.</para>
++</sect2>
++
++<sect2 id="chatstyle-guideline-direction">
++	<title>Support right-to-left languages with <filename>%messageDirection%</filename> keyword.</title>
++	<para><filename>%messageDirection%</filename> keyword is present for languages in the world that write right-to-left. It define the message direction, if it's "rtl"(right-to-left) or "ltr"(left-to-right). Add this style attribute to the HTML element that display the message: <userinput>direction: %messageDirection%</userinput>. Style preview in appearance config include a right-to-left to check if your style display it correctly. It should begin the string from the right.</para>
++</sect2>
++</sect1>
++</appendix>
+--- doc/kopete/index.docbook	(revision 568672)
++++ doc/kopete/index.docbook	(revision 586398)
+@@ -5,6 +5,8 @@
+   <!ENTITY Will.Stephenson.mail "<email>lists at stevello.free-online.co.uk</email>">
+   <!ENTITY Matt.Rogers "<personname><firstname>Matt</firstname><surname>Rogers</surname></personname>">
+   <!ENTITY Matt.Rogers.mail "<email>mattr at kde.org</email>">
++  <!ENTITY Michael.Larouche "<personname><firstname>Michaël</firstname><surname>Larouche</surname></personname>">
++  <!ENTITY Michael.Larouche.mail "<email>michael.larouche at kdemail.net</email>">
+   <!ENTITY package "kdenetwork">
+   <!ENTITY kappname "&kopete;">
+   <!ENTITY im "<acronym>IM</acronym>">
+@@ -12,6 +14,7 @@
+   <!ENTITY % English "INCLUDE">
+   <!ENTITY kopetewww "<ulink url='http://kopete.kde.org'>http://kopete.kde.org</ulink>">
+   <!ENTITY kopete-menus SYSTEM "menus.docbook">
++  <!ENTITY kopete-chatstyle SYSTEM "chatstyle.docbook">
+ ]>
+ <!--
+ Intro (1st draft, Will)
+@@ -62,6 +65,7 @@
+ 	Command line flags
+ Credits (1st draft, Will)
+ Appendix: Obtaining and installation (1st draft, Will)
++Appendix: Chat Window Style Guide (1st draft, Michaël)
+ -->
+ 
+ <book lang="&language;">
+@@ -72,6 +76,7 @@
+ 
+ <author>&Will.Stephenson; &Will.Stephenson.mail;</author>
+ <author>&Matt.Rogers; &Matt.Rogers.mail;</author>
++<author>&Michael.Larouche; &Michael.Larouche.mail;</author>
+ 
+ <!-- TRANS:ROLES_OF_TRANSLATORS -->
+ </authorgroup>
+@@ -577,14 +582,11 @@
+ <title>Chat Window</title>
+ <sect4 id="configuring-appearance-chat-styles">
+ <title>Styles</title>
+-<para>The style of the chat view can be altered to look like other clients, or you can invent your own style here.  Installed styles are shown in the list on the left and are previewed in the main panel.</para>
+-<para>Third party styles are available at <ulink url="http://kde-look.org">http://kde-look.org</ulink>.</para>
+-<para>To modify a style, click <guibutton>Edit...</guibutton>.  &kopete; represents chats internally as XML and uses the Extensible Stylesheet Language (<acronym>XSL</acronym>) to specify how this should be transformed into HTML for display.  You need to be familiar with <acronym>HTML</acronym> and <acronym>XSL</acronym> to edit styles.</para>
++<para>The style of the chat view can be altered to look like other clients. Installed styles are shown in the list on the left and are previewed in the main panel. See <link linkend="chatwindowstyleguide">Chat Window Style guide</link> for a document how to make your own style.</para>
++<para>Third party styles are available at <ulink url="http://kde-look.org">http://kde-look.org</ulink>. Starting with &kopete; 0.12, it support styles from Adium(a &im; program on Mac OS X). So you can download styles from Adium here: <ulink url="http://www.adiumxtras.com/">Adium Xtras</ulink> and select Message View Styles.</para>
++<para>To install a style, click<guibutton>Instal...</guibutton>. Select a archive file containing the style. To delete a style, select a style in the list and click <guibutton>Delete</guibutton>.</para>
++<para><guilabel>Group consecutive messages</guilabel> is a nice option. It group consecutive message coming from the same user. </para>
+ </sect4>
+-<sect4 id="configuring-appearance-chat-translucency">
+-<title>Chat Window</title>
+-<para>&kopete; supports translucent chat views.  You can control the degree of translucency and add a color tint here.  Changes to the translucency settings only become visible when a new chat view opens.</para>
+-</sect4>
+ </sect3>
+ <sect3 id="configuring-behavior-general-contactlist">
+ <title>Contact List</title>
+@@ -854,14 +856,16 @@
+ <itemizedlist>
+ <listitem><para>Duncan Mac-Vicar Prett (duncan at kde org): Original author, developer, and project leader</para></listitem>
+ <listitem><para>Till Gerken (till at tantalo net): Developer, Jabber maintainer</para></listitem>
+-<listitem><para>Olivier Goffart (ogoffart at tiscalinet be): Developer, MSN Plugin Maintainer</para></listitem>
+-<listitem><para>Andy Goossens (andygoossens at telenet be): Current version maintainer</para></listitem>
++<listitem><para>Olivier Goffart (ogoffart at tiscalinet be): Lead Developer, MSN Plugin Maintainer</para></listitem>
++<listitem><para>Andy Goossens (andygoossens at telenet be): Developer</para></listitem>
+ <listitem><para>Grzegorz Jaskiewicz (gregj at pointblue com pl): Developer, Gadu-gadu Plugin Maintainer</para></listitem>
+-<listitem><para>Jason Keirstead (jason at keirstead org): Developer, IRC Plugin Maintainer, Website</para></listitem>
+-<listitem><para>Martijn Klingens (klingens at kde org): Developer, MSN hacker</para></listitem>
+-<listitem><para>Matt Rogers (mattr at kde org): Developer, Yahoo Plugin Maintainer, Oscar Plugin Maintainer</para></listitem>
++<listitem><para>Jason Keirstead (jason at keirstead org): Developer</para></listitem>
++<listitem><para>Matt Rogers (mattr at kde org): Lead Developer, AIM and ICQ plugin maintainer</para></listitem>
+ <listitem><para>Richard Smith (lilachaze at hotmail com): Developer, UI maintainer</para></listitem>
+ <listitem><para>Will Stephenson (lists at stevello free-online co uk): Developer, icons, plugins, manual author</para></listitem>
++<listitem><para>Michel Hermier (michel.hermier at wanadoo fr): IRC Plugin Maintainer</para></listitem>
++<listitem><para>Andre Duffeck (andre at duffeck de): Developer: Developer, Yahoo plugin maintainer</para></listitem>
++<listitem><para>Michaël Larouche (michael.larouche at kdemail net): Developer, MSN, Chat Window.</para></listitem>
+ </itemizedlist>
+ </sect1>
+ <sect1 id="ex-team">
+@@ -879,12 +883,13 @@
+ <listitem><para>James Grant (topace at lightbox org): Developer, importer Plugin author</para></listitem>
+ <listitem><para>Zack Rusin (zack at kde org): Developer, old Gadu-gadu Plugin author</para></listitem>
+ <listitem><para>Gav Wood (gav at kde org): WinPopup Plugin author</para></listitem>
++<listitem><para>Martijn Klingens (klingens at kde org): Developer, MSN hacker</para></listitem>
+ </itemizedlist>
+ </sect1>
+ <sect1 id="documentation">
+ <title>Documentation</title>
+ <para>
+-Documentation copyright 2003,2004,2005 Will Stephenson (lists at stevello free-online co uk), copyright 2005 Matt Rogers (mattr at kde org).
++Documentation copyright 2003,2004,2005 Will Stephenson (lists at stevello free-online co uk), copyright 2005 Matt Rogers (mattr at kde org), copyright 2005,2006 Michaël Larouche (michael.larouche at kdemail net).
+ </para>
+ </sect1>
+ </chapter><!-- credits-and-licenses -->
+@@ -907,6 +912,9 @@
+ &install.compile.documentation;
+ </sect1>
+ </appendix>
++
++&kopete-chatstyle;
++
+ &documentation.index;
+ </book>
+ 
+--- configure.in.bot	(revision 568672)
++++ configure.in.bot	(revision 586398)
+@@ -33,7 +33,7 @@
+   all_tests=bad
+ fi
+ 
+-if test -z "$libidn"; then
++if test "X$have_libidn" = Xno; then
+   echo ""
+   echo "You're missing libidn or the libidn development package"
+   echo "Kopete's Jabber plugin will not be compiled."
+@@ -43,26 +43,7 @@
+   all_tests=bad
+ fi
+ 
+-if test -z "$XML_CONFIG"; then
+-  echo ""
+-  echo "You're missing libxml2, version 2.4.8 or newer, or the libxml2"
+-  echo "development package. Kopete will not be compiled."
+-  echo "If you want to use Kopete, have a look at ftp://xmlsoft.org/ or find"
+-  echo "a binary package for your system."
+-  echo ""
+-  all_tests=bad
+-fi
+ 
+-if test -z "$XSLT_CONFIG"; then
+-  echo ""
+-  echo "You're missing libxslt, version 1.0.7 or newer, or the libxslt"
+-  echo "development package. Kopete will not be compiled."
+-  echo "If you want to use Kopete, have a look at ftp://xmlsoft.org/ or find"
+-  echo "a binary package for your system."
+-  echo ""
+-  all_tests=bad
+-fi
+-
+ if test "x$with_xmms" = xcheck && test -z "$XMMS_LIBS"; then
+   echo ""
+   echo "You're missing the XMMS libraries, or the libxmms development package."
+--- kppp/Kppp.desktop	(revision 568672)
++++ kppp/Kppp.desktop	(revision 586398)
+@@ -15,6 +15,7 @@
+ GenericName[fi]=Internet-yhteyden soitto-ohjelma
+ GenericName[fr]=Connexion internet par modem
+ GenericName[gl]=Ferramenta de Conexión Telefónica a Internet
++GenericName[he]=כלי חיוג לאינטרנט
+ GenericName[hr]=Program za spajanje na Internet
+ GenericName[hu]=Internetes tárcsázó
+ GenericName[is]=Tengjast Netinu með upphringisambandi
+@@ -50,6 +51,7 @@
+ Name[eo]=Interretkonektilo
+ Name[hi]=केपीपीपी
+ Name[sv]=Kppp
++Name[zh_TW]=KPPP 撥號工具
+ MimeType=
+ DocPath=kppp/index.html
+ Exec=kppp %i %m
+--- kppp/logview/kppplogview.desktop	(revision 568672)
++++ kppp/logview/kppplogview.desktop	(revision 586398)
+@@ -5,6 +5,7 @@
+ Name[bs]=Preglednik Kppp dnevnika
+ Name[de]=KPPP-Protokoll-Betrachter
+ Name[el]=Προβολή καταγραφής KPPP
++Name[he]=KPPP תצוגת רישום
+ Name[is]=KPPP annálaskoðari
+ Name[it]=Visualizzatore log KPPP
+ Name[ja]=KPPP - ログビューア
+--- ksirc/eventsrc	(revision 568672)
++++ ksirc/eventsrc	(revision 586398)
+@@ -264,6 +264,7 @@
+ Name[fr]=Bip reçu
+ Name[ga]=Fuarthas bíp
+ Name[gl]=Recibiuse unha badalada
++Name[he]=התקבל ביפ
+ Name[hu]=Csipogás érkezett
+ Name[is]=Hljóðmerki móttekið
+ Name[it]=Ricevuto un bip
+@@ -302,6 +303,7 @@
+ Comment[eu]=Bip bat jaso da zerbitzaritik
+ Comment[fr]=Un bip a été reçu du serveur
+ Comment[gl]=Recibiuse unha badalada dende o servidor
++Comment[he]=התקבל ביפ מהשרת
+ Comment[hu]=Csipogás érkezett a kiszolgálóról
+ Comment[is]=Hljóðmerki hefur verið móttekið frá þjóninum
+ Comment[it]=È stato ricevuto un bip dal server
+--- Makefile.am.in	(revision 568672)
++++ Makefile.am.in	(revision 586398)
+@@ -1,4 +1,4 @@
+-AUTOMAKE_OPTIONS = foreign 1.5
++AUTOMAKE_OPTIONS = foreign 1.6.1
+ DISTCLEANFILES = inst-apps 
+ COMPILE_BEFORE_dcoprss= librss
+ COMPILE_BEFORE_knewsticker= librss




More information about the pkg-kde-commits mailing list