This reverts commitspull/19/head0486034738
-2d5f9c55da
andf6fd4ab6c0
. Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
@ -0,0 +1,56 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
if( NOT BUILD_KOPETE_PROTOCOL_MSN )
|
||||||
|
tde_message_fatal( "netmeeting plugin needs msn protocol.\n Add -DBUILD_KOPETE_PROTOCOL_MSN=ON to cmake flags." )
|
||||||
|
endif( )
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_BINARY_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/protocols/msn
|
||||||
|
${TDE_INCLUDE_DIR}
|
||||||
|
${TQT_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(
|
||||||
|
${TQT_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### other data ################################
|
||||||
|
|
||||||
|
install( FILES kopete_netmeeting.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
||||||
|
install( FILES kopete_netmeeting_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/tdeconfiguredialog )
|
||||||
|
install( FILES netmeetingchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_netmeeting )
|
||||||
|
|
||||||
|
|
||||||
|
##### kopete_netmeeting (module) ################
|
||||||
|
|
||||||
|
tde_add_kpart( kopete_netmeeting AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
netmeetingplugin.cpp netmeetinginvitation.cpp
|
||||||
|
netmeetingguiclient.cpp
|
||||||
|
LINK kopete_msn_shared-shared kopete-shared
|
||||||
|
DESTINATION ${PLUGIN_INSTALL_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### kcm_kopete_netmeeting (module) ############
|
||||||
|
|
||||||
|
tde_add_kpart( kcm_kopete_netmeeting AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
netmeetingprefs_ui.ui netmeetingpreferences.cpp
|
||||||
|
LINK tdeutils-shared
|
||||||
|
DESTINATION ${PLUGIN_INSTALL_DIR}
|
||||||
|
)
|
@ -0,0 +1,23 @@
|
|||||||
|
METASOURCES = AUTO
|
||||||
|
|
||||||
|
AM_CPPFLAGS = $(KOPETE_INCLUDES) -I$(top_srcdir)/kopete/protocols/msn $(all_includes)
|
||||||
|
|
||||||
|
kde_module_LTLIBRARIES = kopete_netmeeting.la kcm_kopete_netmeeting.la
|
||||||
|
|
||||||
|
kopete_netmeeting_la_SOURCES = netmeetingplugin.cpp netmeetinginvitation.cpp netmeetingguiclient.cpp
|
||||||
|
kopete_netmeeting_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
|
||||||
|
kopete_netmeeting_la_LIBADD = $(top_builddir)/kopete/libkopete/libkopete.la $(top_builddir)/kopete/protocols/msn/libkopete_msn_shared.la
|
||||||
|
|
||||||
|
service_DATA = kopete_netmeeting.desktop
|
||||||
|
servicedir = $(kde_servicesdir)
|
||||||
|
|
||||||
|
mydatadir = $(kde_datadir)/kopete_netmeeting
|
||||||
|
mydata_DATA = netmeetingchatui.rc
|
||||||
|
|
||||||
|
kcm_kopete_netmeeting_la_SOURCES = netmeetingprefs_ui.ui netmeetingpreferences.cpp
|
||||||
|
kcm_kopete_netmeeting_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
|
||||||
|
kcm_kopete_netmeeting_la_LIBADD = $(LIB_KOPETECOMPAT) $(LIB_TDEUTILS)
|
||||||
|
|
||||||
|
|
||||||
|
kcm_DATA = kopete_netmeeting_config.desktop
|
||||||
|
kcmdir = $(kde_servicesdir)/tdeconfiguredialog
|
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE kpartgui>
|
||||||
|
<kpartgui version="1" name="kopete_msn_netmeeting">
|
||||||
|
<MenuBar>
|
||||||
|
<Menu name="tools">
|
||||||
|
<text>&Tools</text>
|
||||||
|
<Action name="netmeeting" />
|
||||||
|
</Menu>
|
||||||
|
</MenuBar>
|
||||||
|
</kpartgui>
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
netmeetingguiclient.cpp
|
||||||
|
|
||||||
|
Kopete NetMeeting plugin
|
||||||
|
|
||||||
|
Copyright (c) 2003-2004 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2003-2004 by the Kopete developers <kopete-devel@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 <tqvariant.h>
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdeaction.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <kgenericfactory.h>
|
||||||
|
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
#include "msncontact.h"
|
||||||
|
|
||||||
|
#include "netmeetingguiclient.h"
|
||||||
|
#include "netmeetinginvitation.h"
|
||||||
|
|
||||||
|
class NetMeetingPlugin;
|
||||||
|
|
||||||
|
NetMeetingGUIClient::NetMeetingGUIClient( MSNChatSession *parent, const char *name )
|
||||||
|
: TQObject( parent, name ) , KXMLGUIClient(parent)
|
||||||
|
{
|
||||||
|
setInstance(KGenericFactory<NetMeetingPlugin>::instance());
|
||||||
|
m_manager=parent;
|
||||||
|
|
||||||
|
new TDEAction( i18n( "Invite to Use NetMeeting" ), 0, this, TQT_SLOT( slotStartInvitation() ), actionCollection() , "netmeeting" ) ;
|
||||||
|
|
||||||
|
setXMLFile("netmeetingchatui.rc");
|
||||||
|
}
|
||||||
|
|
||||||
|
NetMeetingGUIClient::~NetMeetingGUIClient()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetMeetingGUIClient::slotStartInvitation()
|
||||||
|
{
|
||||||
|
TQPtrList<Kopete::Contact> c=m_manager->members();
|
||||||
|
NetMeetingInvitation *i=new NetMeetingInvitation(false, static_cast<MSNContact*>(c.first()),m_manager);
|
||||||
|
m_manager->initInvitation(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "netmeetingguiclient.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
netmeetingguiclient.h
|
||||||
|
|
||||||
|
Kopete NetMeeting Plugin
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2003 by the Kopete developers <kopete-devel@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 TRANSLATORGUICLIENT_H
|
||||||
|
#define TRANSLATORGUICLIENT_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <kxmlguiclient.h>
|
||||||
|
|
||||||
|
namespace Kopete { class ChatSession; }
|
||||||
|
class MSNChatSession;
|
||||||
|
class NetMeetingPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
class NetMeetingGUIClient : public TQObject , public KXMLGUIClient
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
NetMeetingGUIClient( MSNChatSession *parent, const char *name=0L);
|
||||||
|
~NetMeetingGUIClient();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotStartInvitation();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNChatSession *m_manager;
|
||||||
|
NetMeetingPlugin *m_plugin;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-indentation-style: k&r
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
msninvitation.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netmeetinginvitation.h"
|
||||||
|
|
||||||
|
#include "kopeteuiglobal.h"
|
||||||
|
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
#include "msnswitchboardsocket.h"
|
||||||
|
#include "msncontact.h"
|
||||||
|
#include "kopetemetacontact.h"
|
||||||
|
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <tdeglobal.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <tqtimer.h>
|
||||||
|
#include <kprocess.h>
|
||||||
|
|
||||||
|
NetMeetingInvitation::NetMeetingInvitation(bool incoming, MSNContact *c, TQObject *parent)
|
||||||
|
: TQObject(parent) , MSNInvitation( incoming, NetMeetingInvitation::applicationID() , i18n("NetMeeting") )
|
||||||
|
{
|
||||||
|
m_contact=c;
|
||||||
|
oki=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NetMeetingInvitation::~NetMeetingInvitation()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TQString NetMeetingInvitation::invitationHead()
|
||||||
|
{
|
||||||
|
TQTimer::singleShot( 10*60000, this, TQT_SLOT( slotTimeout() ) ); //send TIMEOUT in 10 minute if the invitation has not been accepted/refused
|
||||||
|
return TQString( MSNInvitation::invitationHead()+
|
||||||
|
"Session-Protocol: SM1\r\n"
|
||||||
|
"Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME i don't know what is the session id
|
||||||
|
"\r\n").utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetMeetingInvitation::parseInvitation(const TQString& msg)
|
||||||
|
{
|
||||||
|
TQRegExp rx("Invitation-Command: ([A-Z]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString command=rx.cap(1);
|
||||||
|
if( msg.contains("Invitation-Command: INVITE") )
|
||||||
|
{
|
||||||
|
MSNInvitation::parseInvitation(msg); //for the cookie
|
||||||
|
|
||||||
|
unsigned int result = KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
|
||||||
|
i18n("%1 wants to start a chat with NetMeeting; do you want to accept it? " ).arg(m_contact->metaContact()->displayName()),
|
||||||
|
i18n("MSN Plugin") , i18n("Accept"),i18n("Refuse"));
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
if(result==3) // Yes == 3
|
||||||
|
{
|
||||||
|
TQCString message=TQString(
|
||||||
|
"MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: ACCEPT\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
|
||||||
|
"Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME
|
||||||
|
"Session-Protocol: SM1\r\n"
|
||||||
|
"Launch-Application: TRUE\r\n"
|
||||||
|
"Request-Data: IP-Address:\r\n"
|
||||||
|
"IP-Address: " + manager->service()->getLocalIP()+ "\r\n"
|
||||||
|
"\r\n" ).utf8();
|
||||||
|
|
||||||
|
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, message );
|
||||||
|
oki=false;
|
||||||
|
TQTimer::singleShot( 10* 60000, this, TQT_SLOT( slotTimeout() ) ); //TIMOUT afte 10 min
|
||||||
|
}
|
||||||
|
else //No
|
||||||
|
{
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, rejectMessage() );
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( msg.contains("Invitation-Command: ACCEPT") )
|
||||||
|
{
|
||||||
|
if( ! incoming() )
|
||||||
|
{
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
TQCString message=TQString(
|
||||||
|
"MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: ACCEPT\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
|
||||||
|
"Session-ID: {6672F94C-45BF-11D7-B4AE-00010A1008DF}\r\n" //FIXME: what is session id?
|
||||||
|
"Session-Protocol: SM1\r\n"
|
||||||
|
"Launch-Application: TRUE\r\n"
|
||||||
|
"Request-Data: IP-Address:\r\n"
|
||||||
|
"IP-Address: " + manager->service()->getLocalIP() + "\r\n"
|
||||||
|
"\r\n" ).utf8();
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, message );
|
||||||
|
}
|
||||||
|
rx=TQRegExp("IP-Address: ([0-9\\:\\.]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString ip_address = rx.cap(1);
|
||||||
|
startMeeting(ip_address);
|
||||||
|
kdDebug() << k_funcinfo << ip_address << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx=TQRegExp("IP-Address: ([0-9\\:\\.]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString ip_address = rx.cap(1);
|
||||||
|
|
||||||
|
startMeeting(ip_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //CANCEL
|
||||||
|
{
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetMeetingInvitation::slotTimeout()
|
||||||
|
{
|
||||||
|
if(oki)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, rejectMessage("TIMEOUT") );
|
||||||
|
}
|
||||||
|
emit done(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NetMeetingInvitation::startMeeting(const TQString & ip_address)
|
||||||
|
{
|
||||||
|
//TODO: use TDEProcess
|
||||||
|
|
||||||
|
TDEConfig *config=TDEGlobal::config();
|
||||||
|
config->setGroup("Netmeeting Plugin");
|
||||||
|
TQString app=config->readEntry("NetmeetingApplication","ekiga -c callto://%1").arg(ip_address);
|
||||||
|
|
||||||
|
kdDebug() << k_funcinfo << app << endl ;
|
||||||
|
|
||||||
|
TQStringList args=TQStringList::split(" ", app);
|
||||||
|
|
||||||
|
TDEProcess p;
|
||||||
|
for(TQStringList::Iterator it=args.begin() ; it != args.end() ; ++it)
|
||||||
|
{
|
||||||
|
p << *it;
|
||||||
|
}
|
||||||
|
p.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "netmeetinginvitation.moc"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
netmeetinginvitation.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2003 by the Kopete developers <kopete-devel@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 MSNVOICEINVITATION_H
|
||||||
|
#define MSNVOICEINVITATION_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include "msninvitation.h"
|
||||||
|
|
||||||
|
class MSNContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@author Olivier Goffart
|
||||||
|
*/
|
||||||
|
class NetMeetingInvitation : public TQObject , public MSNInvitation
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
NetMeetingInvitation(bool incoming ,MSNContact*, TQObject *parent = 0);
|
||||||
|
~NetMeetingInvitation();
|
||||||
|
|
||||||
|
static TQString applicationID() { return "44BBA842-CC51-11CF-AAFA-00AA00B6015C"; }
|
||||||
|
TQString invitationHead();
|
||||||
|
|
||||||
|
virtual void parseInvitation(const TQString& invitation);
|
||||||
|
|
||||||
|
virtual TQObject* object() { return this; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void done( MSNInvitation * );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotTimeout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNContact *m_contact;
|
||||||
|
bool oki;
|
||||||
|
void startMeeting(const TQString & ip_address);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
netmeetingplugin.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2003-2004 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netmeetingplugin.h"
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kgenericfactory.h>
|
||||||
|
#include <tdeaction.h>
|
||||||
|
#include <tdeversion.h>
|
||||||
|
#include <tdeaboutdata.h>
|
||||||
|
|
||||||
|
#include "kopetepluginmanager.h"
|
||||||
|
#include "kopetechatsessionmanager.h"
|
||||||
|
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
#include "msncontact.h"
|
||||||
|
|
||||||
|
#include "netmeetinginvitation.h"
|
||||||
|
#include "netmeetingguiclient.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const TDEAboutData aboutdata("kopete_netmeeting", I18N_NOOP("NetMeeting") , "1.0" );
|
||||||
|
K_EXPORT_COMPONENT_FACTORY( kopete_netmeeting, KGenericFactory<NetMeetingPlugin>( &aboutdata ) )
|
||||||
|
|
||||||
|
NetMeetingPlugin::NetMeetingPlugin( TQObject *parent, const char *name, const TQStringList &/*args*/ )
|
||||||
|
: Kopete::Plugin( TDEGlobal::instance(), parent, name )
|
||||||
|
{
|
||||||
|
if(MSNProtocol::protocol())
|
||||||
|
slotPluginLoaded(MSNProtocol::protocol());
|
||||||
|
else
|
||||||
|
connect(Kopete::PluginManager::self() , TQT_SIGNAL(pluginLoaded(Kopete::Plugin*) ), this, TQT_SLOT(slotPluginLoaded(Kopete::Plugin*)));
|
||||||
|
|
||||||
|
|
||||||
|
connect( Kopete::ChatSessionManager::self(), TQT_SIGNAL( chatSessionCreated( Kopete::ChatSession * )) , TQT_SLOT( slotNewKMM( Kopete::ChatSession * ) ) );
|
||||||
|
//Add GUI action to all already existing kmm (if the plugin is launched when kopete already rining)
|
||||||
|
TQValueList<Kopete::ChatSession*> sessions = Kopete::ChatSessionManager::self()->sessions();
|
||||||
|
for (TQValueListIterator<Kopete::ChatSession*> it= sessions.begin(); it!=sessions.end() ; ++it)
|
||||||
|
{
|
||||||
|
slotNewKMM(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetMeetingPlugin::~NetMeetingPlugin()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetMeetingPlugin::slotPluginLoaded(Kopete::Plugin *p)
|
||||||
|
{
|
||||||
|
if(p->pluginId()=="MSNProtocol")
|
||||||
|
{
|
||||||
|
connect( p , TQT_SIGNAL(invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* )) ,
|
||||||
|
this, TQT_SLOT( slotInvitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* )));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetMeetingPlugin::slotNewKMM(Kopete::ChatSession *KMM)
|
||||||
|
{
|
||||||
|
MSNChatSession *msnMM=dynamic_cast<MSNChatSession*>(KMM);
|
||||||
|
if(msnMM)
|
||||||
|
{
|
||||||
|
connect(this , TQT_SIGNAL( destroyed(TQObject*)) ,
|
||||||
|
new NetMeetingGUIClient(msnMM)
|
||||||
|
, TQT_SLOT(deleteLater()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NetMeetingPlugin::slotInvitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int /*cookie*/ , MSNChatSession* msnMM , MSNContact* c )
|
||||||
|
{
|
||||||
|
if(!invitation && bodyMSG.contains(NetMeetingInvitation::applicationID()))
|
||||||
|
{
|
||||||
|
invitation=new NetMeetingInvitation(true,c,msnMM);
|
||||||
|
invitation->parseInvitation(bodyMSG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "netmeetingplugin.moc"
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
netmeetingplugin.h
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NetMeetingPLUGIN_H
|
||||||
|
#define NetMeetingPLUGIN_H
|
||||||
|
|
||||||
|
#include "kopeteplugin.h"
|
||||||
|
|
||||||
|
namespace Kopete { class ChatSession; }
|
||||||
|
class MSNChatSession;
|
||||||
|
class MSNContact;
|
||||||
|
class MSNInvitation;
|
||||||
|
|
||||||
|
|
||||||
|
class NetMeetingPlugin : public Kopete::Plugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
NetMeetingPlugin( TQObject *parent, const char *name, const TQStringList &args );
|
||||||
|
~NetMeetingPlugin();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotNewKMM(Kopete::ChatSession *);
|
||||||
|
void slotPluginLoaded(Kopete::Plugin*);
|
||||||
|
void slotInvitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int cookie , MSNChatSession* msnMM , MSNContact* c );
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,81 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
Netmeetingpreferences.cpp - description
|
||||||
|
-------------------
|
||||||
|
copyright : (C) 2004 by Olivier Goffart
|
||||||
|
email : ogoffart @ kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tqlayout.h>
|
||||||
|
#include <tqcheckbox.h>
|
||||||
|
|
||||||
|
#include <kcombobox.h>
|
||||||
|
#include <klineedit.h>
|
||||||
|
#include <tdeparts/componentfactory.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <tdeglobal.h>
|
||||||
|
#include <kcombobox.h>
|
||||||
|
#include <tdelistview.h>
|
||||||
|
#include <kgenericfactory.h>
|
||||||
|
#include <kcolorbutton.h>
|
||||||
|
#include <kinputdialog.h>
|
||||||
|
#include <kurlrequester.h>
|
||||||
|
#include <kregexpeditorinterface.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
|
||||||
|
#include "netmeetingplugin.h"
|
||||||
|
#include "netmeetingprefs_ui.h"
|
||||||
|
#include "netmeetingpreferences.h"
|
||||||
|
|
||||||
|
typedef KGenericFactory<NetmeetingPreferences> NetmeetingPreferencesFactory;
|
||||||
|
K_EXPORT_COMPONENT_FACTORY( kcm_kopete_netmeeting, NetmeetingPreferencesFactory( "kcm_kopete_netmeeting" ) )
|
||||||
|
|
||||||
|
NetmeetingPreferences::NetmeetingPreferences(TQWidget *parent, const char* /*name*/, const TQStringList &args)
|
||||||
|
: TDECModule(NetmeetingPreferencesFactory::instance(), parent, args)
|
||||||
|
{
|
||||||
|
( new TQVBoxLayout( this ) )->setAutoAdd( true );
|
||||||
|
preferencesDialog = new NetmeetingPrefsUI(this);
|
||||||
|
|
||||||
|
connect(preferencesDialog->m_app , TQT_SIGNAL(textChanged(const TQString &)) , this , TQT_SLOT(slotChanged()));
|
||||||
|
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
NetmeetingPreferences::~NetmeetingPreferences()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetmeetingPreferences::load()
|
||||||
|
{
|
||||||
|
TDEConfig *config=TDEGlobal::config();
|
||||||
|
config->setGroup("Netmeeting Plugin");
|
||||||
|
preferencesDialog->m_app->setCurrentText(config->readEntry("NetmeetingApplication","ekiga -c callto://%1"));
|
||||||
|
emit TDECModule::changed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetmeetingPreferences::save()
|
||||||
|
{
|
||||||
|
TDEConfig *config=TDEGlobal::config();
|
||||||
|
config->setGroup("Netmeeting Plugin");
|
||||||
|
config->writeEntry("NetmeetingApplication",preferencesDialog->m_app->currentText());
|
||||||
|
emit TDECModule::changed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NetmeetingPreferences::slotChanged()
|
||||||
|
{
|
||||||
|
emit TDECModule::changed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "netmeetingpreferences.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
@ -0,0 +1,47 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
netmeetingpreferences.h - description
|
||||||
|
-------------------
|
||||||
|
copyright : (C) 2004 by Olivier Goffart
|
||||||
|
email : ogoffart @ kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef NetmeetingPREFERENCES_H
|
||||||
|
#define NetmeetingPREFERENCES_H
|
||||||
|
|
||||||
|
#include <tdecmodule.h>
|
||||||
|
#include <tqstring.h>
|
||||||
|
|
||||||
|
class NetmeetingPrefsUI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@author Olivier Goffart
|
||||||
|
*/
|
||||||
|
|
||||||
|
class NetmeetingPreferences : public TDECModule {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
NetmeetingPreferences(TQWidget *parent = 0, const char* name = 0, const TQStringList &args = TQStringList());
|
||||||
|
~NetmeetingPreferences();
|
||||||
|
|
||||||
|
virtual void save();
|
||||||
|
virtual void load();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetmeetingPrefsUI *preferencesDialog;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,148 @@
|
|||||||
|
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
|
||||||
|
<class>NetmeetingPrefsUI</class>
|
||||||
|
<author>Olivier Goffart</author>
|
||||||
|
<widget class="TQWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Form1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>424</width>
|
||||||
|
<height>297</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<vbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>The NetMeeting Plugin allows you to start a video or voice chat with your MSN Messenger contacts.
|
||||||
|
|
||||||
|
This is not the same as webcam chat you can find in the newer Windows Messenger®, but uses the older NetMeeting chat you can find in old versions.</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>WordBreak|AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</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="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>layout1</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Application to launch:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="KComboBox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>ekiga -c callto://%1</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>konference callto://%1</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_app</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>3</hsizetype>
|
||||||
|
<vsizetype>0</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoCompletion">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><b>%1</b> will be replaced by the ip to call</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>WordBreak|AlignVCenter</set>
|
||||||
|
</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>21</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
<widget class="KActiveLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>kActiveLabel1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>5</hsizetype>
|
||||||
|
<vsizetype>5</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>You can download Konference here: <a href="http://www.kde-apps.org/content/show.php?content=10395">http://www.kde-apps.org/content/show.php?content=10395</a></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</vbox>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
</customwidgets>
|
||||||
|
<layoutdefaults spacing="6" margin="11"/>
|
||||||
|
<includehints>
|
||||||
|
<includehint>kcombobox.h</includehint>
|
||||||
|
<includehint>klineedit.h</includehint>
|
||||||
|
<includehint>kactivelabel.h</includehint>
|
||||||
|
</includehints>
|
||||||
|
</UI>
|
@ -0,0 +1,72 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
add_subdirectory( ui )
|
||||||
|
add_subdirectory( icons )
|
||||||
|
add_subdirectory( config )
|
||||||
|
|
||||||
|
if( WITH_WEBCAM )
|
||||||
|
add_subdirectory( webcam )
|
||||||
|
add_definitions( -DMSN_WEBCAM )
|
||||||
|
set( WEBCAM_LIBRARIES mimicwrapper-static kopete_videodevice-shared ${GLIB2_LIBRARIES} )
|
||||||
|
endif( )
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/ui
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ui
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/webcam
|
||||||
|
${CMAKE_BINARY_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete/private
|
||||||
|
${TDE_INCLUDE_DIR}
|
||||||
|
${TQT_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(
|
||||||
|
${TQT_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### other data ################################
|
||||||
|
|
||||||
|
install( FILES kopete_msn.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
||||||
|
install( FILES msnchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_msn )
|
||||||
|
|
||||||
|
|
||||||
|
##### kopete_msn (module) #######################
|
||||||
|
|
||||||
|
tde_add_kpart( kopete_msn AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
dummy.cpp webcam.cpp
|
||||||
|
LINK kopete_msn_shared-shared
|
||||||
|
DESTINATION ${PLUGIN_INSTALL_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### kopete_msn_shared (shared) ################
|
||||||
|
|
||||||
|
tde_add_library( kopete_msn_shared SHARED AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
msnprotocol.cpp msnaccount.cpp msnaddcontactpage.cpp msncontact.cpp
|
||||||
|
msnsocket.cpp msnchatsession.cpp msndebugrawcmddlg.cpp
|
||||||
|
msnnotifysocket.cpp msnswitchboardsocket.cpp
|
||||||
|
msnfiletransfersocket.cpp msninvitation.cpp sha1.cpp
|
||||||
|
msnsecureloginhandler.cpp msnchallengehandler.cpp
|
||||||
|
dispatcher.cpp p2p.cpp messageformatter.cpp incomingtransfer.cpp
|
||||||
|
outgoingtransfer.cpp webcam.cpp
|
||||||
|
VERSION 0.0.0
|
||||||
|
LINK
|
||||||
|
kopetemsnui-static ${WEBCAM_LIBRARIES} kopete-shared
|
||||||
|
DESTINATION ${LIB_INSTALL_DIR}
|
||||||
|
)
|
@ -0,0 +1,106 @@
|
|||||||
|
Have fun using this all-improved plugin and feel free to contribute patches
|
||||||
|
and other improvements to our mailing list! Although we all like to boast
|
||||||
|
about our great work, we're sure there are still bugs remaining, which is
|
||||||
|
why we don't call this release 1.0, but only 0.5.
|
||||||
|
|
||||||
|
Nevertheless, we feel this new MSN plugin is an enormous step forward from
|
||||||
|
the last 0.4.1 release and we recommend anyone to try out this all-improved
|
||||||
|
plugin. Please read the release notes first before reporting bugs, but please
|
||||||
|
do report anything not listed there!
|
||||||
|
|
||||||
|
Thanks for your interest in Kopete!
|
||||||
|
|
||||||
|
October 2002, the Kopete team <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
|
||||||
|
CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.4.1
|
||||||
|
|
||||||
|
- Ported the plugin to the new MetaContact API, allowing a locally cached
|
||||||
|
copy of the contact list to be always available (even when offline) and
|
||||||
|
to combine your MSN contacts with other messaging systems in one entry
|
||||||
|
in the contact list.
|
||||||
|
|
||||||
|
- Added additional online states ('be right back', 'out to lunch', 'busy',
|
||||||
|
'invisible') and the possibility to connect directly with a particular
|
||||||
|
status (especially useful with 'invisible')
|
||||||
|
|
||||||
|
- Fix multi-user chat now the API finally supports it properly
|
||||||
|
|
||||||
|
- Fix a grave bug in Kopete 0.4.1 where Kopete would popup the 'new user'
|
||||||
|
dialog for every user in your block list, asking whether you want to
|
||||||
|
allow or block the user, often crashing Kopete completely
|
||||||
|
|
||||||
|
- Fix support for Unicode messages
|
||||||
|
|
||||||
|
- Fix the 'unhandled error 219' problem that caused Kopete to disconnect
|
||||||
|
unexpectedly for some people
|
||||||
|
|
||||||
|
- Added possibility to talk with users who aren't in the contact list
|
||||||
|
|
||||||
|
- Incoming filetransfers
|
||||||
|
|
||||||
|
- As usual, several other bugfixes
|
||||||
|
|
||||||
|
CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.4
|
||||||
|
|
||||||
|
- Added block/unblock user
|
||||||
|
|
||||||
|
- Don't show contacts from the allow list if they are not also in the
|
||||||
|
friend list (like deleted contacts). Small problem: there already was
|
||||||
|
a need to have a gui for manipulating blocked/allowed contacts, with
|
||||||
|
this change this is even a bit more urgent...
|
||||||
|
|
||||||
|
- Hopefully fix a problem with an empty reverse list on a fresh MSN account.
|
||||||
|
can't test, because by the time the recompile was done the reverse list
|
||||||
|
was no longer empty...
|
||||||
|
|
||||||
|
- Fix a problem with MSN users no longer receiving messages. Apparently
|
||||||
|
Microsoft changed the server so messages without an explicit font name are
|
||||||
|
no longer passed on.
|
||||||
|
|
||||||
|
- Fixed UTF8 handling not really being UTF8. MSN should work fine now with
|
||||||
|
all unicode characters
|
||||||
|
|
||||||
|
- Moved the plugin to use KGenericFactory as preparation for more KDE-style
|
||||||
|
plugin handling (as opposed to the current custom code)
|
||||||
|
|
||||||
|
- Fixed crash when disconnecting while an earlier connect was still running
|
||||||
|
|
||||||
|
- Made the connect code asynchronous, so connecting doesn't hang kopete
|
||||||
|
while processing
|
||||||
|
|
||||||
|
- Fixed minor memory leak in the connect code
|
||||||
|
|
||||||
|
CHANGES IN THE MSN PLUGIN SINCE KOPETE 0.3
|
||||||
|
|
||||||
|
Many things changed since 0.3. I won't mention them all, because so much of
|
||||||
|
the internal code changed that the individual commits often fix more than I
|
||||||
|
was even aware of at that time. Below are the bigger changes and fixes:
|
||||||
|
|
||||||
|
- Ported the plugin to the new KopeteMessageManager. This move unifies the
|
||||||
|
handling of various resources like chat windows, balloons, system tray
|
||||||
|
flashing, and more. In Kopete 0.3 this was the exclusive domain of the
|
||||||
|
ICQ plugin, in this release all plugins except IRC already use the shared
|
||||||
|
code.
|
||||||
|
|
||||||
|
- Rewrote almost all of the internal protocol handling, fixing an awful lot
|
||||||
|
of bugs during the process. The main goal was to make the code more
|
||||||
|
maintainable and extensible, but the gratuitous bug fixes are of course
|
||||||
|
much more useful for most people. The most important fix of all is a
|
||||||
|
grave bug that caused the plugin to read a fixed-size 1kb buffer in Kopete
|
||||||
|
0.3 without checking for additional data, often causing the plugin to
|
||||||
|
seemingly 'hang'.
|
||||||
|
|
||||||
|
- Added the ability to change the display name while connected. This can
|
||||||
|
currently only be done from the context menu. The option in the
|
||||||
|
preferences never worked, and still does not do what you'd expect it to
|
||||||
|
do. Sorry :)
|
||||||
|
|
||||||
|
- Added much more useful debug code for developers, testers and other
|
||||||
|
interested people. It is also a lot *more* debug output, so if you're
|
||||||
|
scared of console output, better not start Kopete from it...
|
||||||
|
|
||||||
|
- All those tiny bugfixes of which I don't even know whether they fix
|
||||||
|
regressions introduced during the development of version 0.4, or whether
|
||||||
|
they fix long-standing bugs.
|
||||||
|
|
@ -0,0 +1,47 @@
|
|||||||
|
if include_msn_webcam
|
||||||
|
WEBCAM = webcam
|
||||||
|
WEBCAM_LIBMINICWRAPPER = webcam/libmimicwrapper.la
|
||||||
|
endif
|
||||||
|
|
||||||
|
KDE_OPTIONS = nofinal
|
||||||
|
METASOURCES = AUTO
|
||||||
|
SUBDIRS = ui $(WEBCAM) . icons config
|
||||||
|
AM_CPPFLAGS = -Iui \
|
||||||
|
-I$(srcdir)/webcam \
|
||||||
|
-I$(srcdir)/ui \
|
||||||
|
$(KOPETE_INCLUDES) \
|
||||||
|
-I$(top_srcdir)/kopete/libkopete/private \
|
||||||
|
$(all_includes)
|
||||||
|
|
||||||
|
kde_module_LTLIBRARIES = kopete_msn.la
|
||||||
|
lib_LTLIBRARIES = libkopete_msn_shared.la
|
||||||
|
|
||||||
|
CLEANFILES = dummy.cpp
|
||||||
|
|
||||||
|
libkopete_msn_shared_la_SOURCES = msnprotocol.cpp msnaccount.cpp \
|
||||||
|
msnaddcontactpage.cpp msncontact.cpp msnsocket.cpp msnchatsession.cpp msndebugrawcmddlg.cpp \
|
||||||
|
msnnotifysocket.cpp msnswitchboardsocket.cpp msnfiletransfersocket.cpp msninvitation.cpp \
|
||||||
|
sha1.cpp msnsecureloginhandler.cpp msnchallengehandler.cpp dispatcher.cpp \
|
||||||
|
p2p.cpp messageformatter.cpp incomingtransfer.cpp outgoingtransfer.cpp \
|
||||||
|
webcam.cpp
|
||||||
|
|
||||||
|
libkopete_msn_shared_la_LIBADD = ./ui/libkopetemsnui.la ../../libkopete/libkopete.la $(WEBCAM_LIBMINICWRAPPER) ../../libkopete/avdevice/libkopete_videodevice.la $(LIB_TDEIO)
|
||||||
|
libkopete_msn_shared_la_LDFLAGS = -version-info 0:0:0 -no-undefined $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor -lkopete_videodevice -L../../libkopete/avdevice/
|
||||||
|
|
||||||
|
kopete_msn_la_SOURCES = dummy.cpp webcam.cpp
|
||||||
|
kopete_msn_la_LIBADD = libkopete_msn_shared.la
|
||||||
|
|
||||||
|
kopete_msn_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor -lkopete_videodevice -L../../libkopete/avdevice/
|
||||||
|
|
||||||
|
dummy.cpp: $(srcdir)/Makefile.am
|
||||||
|
echo '#include "kdemacros.h"' > $@
|
||||||
|
echo 'extern "C" KDE_EXPORT void *init_libkopete_msn_shared();' >> $@
|
||||||
|
echo 'extern "C" KDE_EXPORT void *init_kopete_msn() { return init_libkopete_msn_shared(); }' >> $@
|
||||||
|
|
||||||
|
service_DATA = kopete_msn.desktop
|
||||||
|
servicedir = $(kde_servicesdir)
|
||||||
|
|
||||||
|
mydatadir = $(kde_datadir)/kopete_msn
|
||||||
|
mydata_DATA = msnchatui.rc
|
||||||
|
noinst_HEADERS = p2p.h dispatcher.h messageformatter.h incomingtransfer.h \
|
||||||
|
outgoingtransfer.h webcam.h
|
@ -0,0 +1,31 @@
|
|||||||
|
If you can bear with beta-quality code, we welcome you to try out this
|
||||||
|
highly improved plugin and use it as your primary instant messaging system!
|
||||||
|
Patches are always welcome on kopete-devel@kde.org. Trivial fixes can be
|
||||||
|
committed directly to KDE CVS if you have an account, but please coordinate
|
||||||
|
larger changes with us to avoid double work.
|
||||||
|
|
||||||
|
Thanks for your interest in Kopete!
|
||||||
|
|
||||||
|
October 2002, the Kopete team <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
RELEASE NOTES FOR THE MSN PLUGIN IN KOPETE 0.5
|
||||||
|
|
||||||
|
Most of the MSN plugin has seen an enormous improvement since the previous
|
||||||
|
release, with many bugs fixed in all aspects of the plugin, most notably
|
||||||
|
the contact list handling and group chats. See the Changelog for a more
|
||||||
|
detailed description of what was changed in this release.
|
||||||
|
|
||||||
|
Some issues in MSN are still remaining though. We hope to fix them in the
|
||||||
|
next release, since we think they are not critical enough to delay this
|
||||||
|
release:
|
||||||
|
|
||||||
|
- MSN allows you to have multiple groups with the same name, because
|
||||||
|
internally a group ID is used. Kopete currently uses the name as a unique
|
||||||
|
identifier, however, and will likely get a bit confused by this. If you
|
||||||
|
do experience problems, you could join both groups using another MSN
|
||||||
|
client, like the official client, Trillian or Pidgin as a workaround.
|
||||||
|
|
||||||
|
- Kopete contacts can be at Top-Level and in no groups. MSN doesn't
|
||||||
|
support this freature. The kopete's contact list can differe from server
|
||||||
|
if you have top-level contact
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
Some things to think about as of 2003/04/15
|
||||||
|
(according to Gof)
|
||||||
|
Adding 'search for user'
|
||||||
|
Adding MSN chatroom protocol
|
||||||
|
Add MSN alerts
|
@ -0,0 +1,38 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete
|
||||||
|
${TDE_INCLUDE_DIR}
|
||||||
|
${TQT_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(
|
||||||
|
${TQT_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### other data ################################
|
||||||
|
|
||||||
|
install( FILES
|
||||||
|
kopete_msn_config.desktop
|
||||||
|
DESTINATION ${SERVICES_INSTALL_DIR}/tdeconfiguredialog )
|
||||||
|
|
||||||
|
|
||||||
|
##### kcm_kopete_msn (module) ###################
|
||||||
|
|
||||||
|
tde_add_kpart( kcm_kopete_msn AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
msnprefs.ui msnpreferences.cpp
|
||||||
|
LINK kopete-shared
|
||||||
|
DESTINATION ${PLUGIN_INSTALL_DIR}
|
||||||
|
)
|
@ -0,0 +1,12 @@
|
|||||||
|
METASOURCES = AUTO
|
||||||
|
AM_CPPFLAGS = $(KOPETE_INCLUDES) $(all_includes)
|
||||||
|
|
||||||
|
kde_module_LTLIBRARIES = kcm_kopete_msn.la
|
||||||
|
|
||||||
|
kcm_kopete_msn_la_SOURCES = msnprefs.ui msnpreferences.cpp
|
||||||
|
kcm_kopete_msn_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
|
||||||
|
kcm_kopete_msn_la_LIBADD = ../../../libkopete/libkopete.la $(LIB_TDEUTILS)
|
||||||
|
|
||||||
|
service_DATA = kopete_msn_config.desktop
|
||||||
|
servicedir = $(kde_servicesdir)/tdeconfiguredialog
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
msnpreferences.cpp - MSN Preferences Widget
|
||||||
|
|
||||||
|
Copyright (c) 2002-2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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 <kgenericfactory.h>
|
||||||
|
#include "kcautoconfigmodule.h"
|
||||||
|
#include "msnprefs.h"
|
||||||
|
|
||||||
|
class MSNPreferences;
|
||||||
|
|
||||||
|
typedef KGenericFactory<MSNPreferences> MSNProtocolConfigFactory;
|
||||||
|
K_EXPORT_COMPONENT_FACTORY( kcm_kopete_msn, MSNProtocolConfigFactory( "kcm_kopete_msn" ) )
|
||||||
|
|
||||||
|
class MSNPreferences : public KCAutoConfigModule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MSNPreferences( TQWidget *parent = 0, const char * = 0, const TQStringList &args = TQStringList() ) : KCAutoConfigModule( MSNProtocolConfigFactory::instance(), parent, args )
|
||||||
|
{
|
||||||
|
setMainWidget( new msnPrefsUI( this ) , "MSN");
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,217 @@
|
|||||||
|
<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
|
||||||
|
<class>msnPrefsUI</class>
|
||||||
|
<author>Duncan Mac-Vicar P.</author>
|
||||||
|
<widget class="TQWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>msnPrefsUI</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>522</width>
|
||||||
|
<height>347</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<vbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel3_2_2_2_3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<bold>1</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQFrame">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Frame3_3_3_2_3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>1</hsizetype>
|
||||||
|
<vsizetype>0</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>HLine</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>Sunken</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>NotifyNewChat</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Automatically open a chat window when someone starts a conversation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>AutoDownloadPicture</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Automatically download the display picture if possible</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>useCustomEmoticons</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Download and show custom emoticons (experimental)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel1_3_3_3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel3_2_2_2_2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<bold>1</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Away Messages</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQFrame">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Frame3_3_3_2_2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>1</hsizetype>
|
||||||
|
<vsizetype>0</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>HLine</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>Sunken</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>SendAwayMessages</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>7</hsizetype>
|
||||||
|
<vsizetype>0</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Send &away messages</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>layout18</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Do not send more than one away message every</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="KIntNumInput">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>AwayMessageSeconds</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>90</number>
|
||||||
|
</property>
|
||||||
|
<property name="minValue">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel4</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>seconds</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<spacer>
|
||||||
|
<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>21</width>
|
||||||
|
<height>70</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</vbox>
|
||||||
|
</widget>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>SendAwayMessages</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>AwayMessageSeconds</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>NotifyNewChat</tabstop>
|
||||||
|
<tabstop>AutoDownloadPicture</tabstop>
|
||||||
|
<tabstop>useCustomEmoticons</tabstop>
|
||||||
|
<tabstop>SendAwayMessages</tabstop>
|
||||||
|
<tabstop>AwayMessageSeconds</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<includes>
|
||||||
|
<include location="global" impldecl="in implementation">knuminput.h</include>
|
||||||
|
</includes>
|
||||||
|
<layoutdefaults spacing="6" margin="11"/>
|
||||||
|
<includehints>
|
||||||
|
<includehint>knuminput.h</includehint>
|
||||||
|
<includehint>knuminput.h</includehint>
|
||||||
|
</includehints>
|
||||||
|
</UI>
|
@ -0,0 +1,647 @@
|
|||||||
|
/*
|
||||||
|
dispatcher.cpp - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dispatcher.h"
|
||||||
|
#include "incomingtransfer.h"
|
||||||
|
#include "outgoingtransfer.h"
|
||||||
|
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
#include "webcam.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using P2P::Dispatcher;
|
||||||
|
using P2P::Message;
|
||||||
|
using P2P::TransferContext;
|
||||||
|
using P2P::IncomingTransfer;
|
||||||
|
using P2P::OutgoingTransfer;
|
||||||
|
|
||||||
|
#include "msnswitchboardsocket.h"
|
||||||
|
|
||||||
|
// Kde includes
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kmdcodec.h>
|
||||||
|
#include <kstandarddirs.h>
|
||||||
|
#include <tdetempfile.h>
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqdatastream.h>
|
||||||
|
#include <tqfile.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <tqtextcodec.h>
|
||||||
|
#include <tqtextstream.h>
|
||||||
|
|
||||||
|
// Kopete includes
|
||||||
|
#include <kopetechatsession.h> // Just for getting the contact
|
||||||
|
#include <kopeteaccount.h>
|
||||||
|
#include <kopetetransfermanager.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
Dispatcher::Dispatcher(TQObject *parent, const TQString& contact, const TQStringList &ip)
|
||||||
|
: TQObject(parent) , m_contact(contact) , m_callbackChannel(0l) , m_ip(ip)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Dispatcher::~Dispatcher()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
if(m_callbackChannel)
|
||||||
|
{
|
||||||
|
delete m_callbackChannel;
|
||||||
|
m_callbackChannel = 0l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::detach(TransferContext* transfer)
|
||||||
|
{
|
||||||
|
m_sessions.remove(transfer->m_sessionId);
|
||||||
|
transfer->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString Dispatcher::localContact()
|
||||||
|
{
|
||||||
|
return m_contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::requestDisplayIcon(const TQString& from, const TQString& msnObject)
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
|
||||||
|
TransferContext* current =
|
||||||
|
new IncomingTransfer(from, this, sessionId);
|
||||||
|
|
||||||
|
current->m_branch = P2P::Uid::createUid();
|
||||||
|
current->m_callId = P2P::Uid::createUid();
|
||||||
|
current->setType(P2P::UserDisplayIcon);
|
||||||
|
current->m_object = msnObject;
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId, current);
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "Requesting, " << msnObject << endl;
|
||||||
|
|
||||||
|
TQString context = TQString::fromUtf8(KCodecs::base64Encode(msnObject.utf8()));
|
||||||
|
// NOTE remove the \0 character automatically
|
||||||
|
// appended to a TQCString.
|
||||||
|
context.replace("=", TQString());
|
||||||
|
TQString content =
|
||||||
|
"EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}\r\n"
|
||||||
|
"SessionID: " + TQString::number(sessionId) + "\r\n"
|
||||||
|
"AppID: 1\r\n"
|
||||||
|
"Context: " + context + "\r\n"
|
||||||
|
"\r\n";
|
||||||
|
// Send the sending client an invitation message.
|
||||||
|
current->sendMessage(INVITE, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::sendFile(const TQString& path, TQ_INT64 fileSize, const TQString& to)
|
||||||
|
{
|
||||||
|
// Create a new transfer context that will handle
|
||||||
|
// the file transfer.
|
||||||
|
TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
|
||||||
|
TransferContext *current =
|
||||||
|
new OutgoingTransfer(to, this, sessionId);
|
||||||
|
current->m_branch = P2P::Uid::createUid();
|
||||||
|
current->m_callId = P2P::Uid::createUid();
|
||||||
|
current->setType(P2P::File);
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId, current);
|
||||||
|
|
||||||
|
// Set the transfer context file.
|
||||||
|
current->m_file = new TQFile(path);
|
||||||
|
// Create the file context data.
|
||||||
|
TQString context;
|
||||||
|
|
||||||
|
TQByteArray header(638);
|
||||||
|
header.fill('\0');
|
||||||
|
TQDataStream writer(header, IO_WriteOnly);
|
||||||
|
writer.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
|
||||||
|
// Write the header length to the stream.
|
||||||
|
writer << (TQ_INT32)638;
|
||||||
|
// Write client version to the stream.
|
||||||
|
writer << (TQ_INT32)3;
|
||||||
|
// Write the file size to the stream.
|
||||||
|
writer << fileSize;
|
||||||
|
// Write the file transfer flag to the stream.
|
||||||
|
// TODO support file preview. For now disable file preview.
|
||||||
|
writer << (TQ_INT32)1;
|
||||||
|
// Write the file name in utf-16 to the stream.
|
||||||
|
TQTextStream ts(header, IO_WriteOnly);
|
||||||
|
ts.setEncoding(TQTextStream::RawUnicode);
|
||||||
|
ts.device()->at(20);
|
||||||
|
ts << path.section('/', -1);
|
||||||
|
// NOTE Background Sharing base64 [540..569]
|
||||||
|
// TODO add support for background sharing.
|
||||||
|
// Write file exchange type to the stream.
|
||||||
|
// NOTE File - 0xFFFFFFFF
|
||||||
|
// NOTE Background Sharing - 0xFFFFFFFE
|
||||||
|
writer.device()->at(570);
|
||||||
|
writer << (TQ_UINT32)0xFFFFFFFF;
|
||||||
|
|
||||||
|
// Encode the file context header to base64 encoding.
|
||||||
|
context = TQString::fromUtf8(KCodecs::base64Encode(header));
|
||||||
|
|
||||||
|
// Send an INVITE message to the recipient.
|
||||||
|
TQString content = "EUF-GUID: {5D3E02AB-6190-11D3-BBBB-00C04F795683}\r\n"
|
||||||
|
"SessionID: " + TQString::number(sessionId) + "\r\n"
|
||||||
|
"AppID: 2\r\n"
|
||||||
|
"Context: " + context + "\r\n"
|
||||||
|
"\r\n";
|
||||||
|
current->sendMessage(INVITE, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::sendImage(const TQString& /*fileName*/, const TQString& /*to*/)
|
||||||
|
{
|
||||||
|
// TODO kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
// TQFile imageFile(fileName);
|
||||||
|
// if(!imageFile.open(IO_ReadOnly))
|
||||||
|
// {
|
||||||
|
// kdDebug(14140) << k_funcinfo << "Error opening image file."
|
||||||
|
// << endl;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// OutgoingTransfer *outbound =
|
||||||
|
// new OutgoingTransfer(to, this, 64);
|
||||||
|
//
|
||||||
|
// outbound->sendImage(imageFile.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
void Dispatcher::startWebcam(const TQString &/*myHandle*/, const TQString &msgHandle, bool wantToReceive)
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
|
||||||
|
Webcam::Who who= wantToReceive ? Webcam::wViewer : Webcam::wProducer;
|
||||||
|
TransferContext* current =
|
||||||
|
new Webcam(who, msgHandle, this, sessionId);
|
||||||
|
|
||||||
|
current->m_branch = P2P::Uid::createUid();
|
||||||
|
current->m_callId = P2P::Uid::createUid();
|
||||||
|
current->setType(P2P::WebcamType);
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId, current);
|
||||||
|
|
||||||
|
// {4BD96FC0-AB17-4425-A14A-439185962DC8} <- i want to show you my webcam
|
||||||
|
// {1C9AA97E-9C05-4583-A3BD-908A196F1E92} <- i want to see your webcam
|
||||||
|
TQString GUID= (who==Webcam::wProducer) ? "4BD96FC0-AB17-4425-A14A-439185962DC8" : "1C9AA97E-9C05-4583-A3BD-908A196F1E92" ;
|
||||||
|
|
||||||
|
TQString content="EUF-GUID: {"+GUID+"}\r\n"
|
||||||
|
"SessionID: "+ TQString::number(sessionId)+"\r\n"
|
||||||
|
"AppID: 4\r\n"
|
||||||
|
"Context: ewBCADgAQgBFADcAMABEAEUALTQBFADIAQwBBAC0ANAA0ADAAMAAtAEEARTQAwADMALQA4ADgARgBGADgANTQBCADkARgA0AEUAOAB9AA==\r\n\r\n";
|
||||||
|
|
||||||
|
// context is the base64 of the utf16 of {B8BE70DE-E2CA-4400-AE03-88FF85B9F4E8}
|
||||||
|
|
||||||
|
current->sendMessage( INVITE , content );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Dispatcher::slotReadMessage(const TQString &from, const TQByteArray& stream)
|
||||||
|
{
|
||||||
|
P2P::Message receivedMessage =
|
||||||
|
m_messageFormatter.readMessage(stream);
|
||||||
|
|
||||||
|
receivedMessage.source = from;
|
||||||
|
|
||||||
|
if(receivedMessage.contentType == "application/x-msnmsgrp2p")
|
||||||
|
{
|
||||||
|
if((receivedMessage.header.dataSize == 0)/* && ((receivedMessage.header.flag & 0x02) == 0x02)*/)
|
||||||
|
{
|
||||||
|
TransferContext *current = 0l;
|
||||||
|
TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
|
||||||
|
for(; it != m_sessions.end(); it++)
|
||||||
|
{
|
||||||
|
if(receivedMessage.header.ackSessionIdentifier == it.data()->m_identifier){
|
||||||
|
current = it.data();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current){
|
||||||
|
// Inform the transfer object of the acknowledge.
|
||||||
|
current->m_ackSessionIdentifier = receivedMessage.header.identifier;
|
||||||
|
current->m_ackUniqueIdentifier = receivedMessage.header.ackSessionIdentifier;
|
||||||
|
current->acknowledged();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo
|
||||||
|
<< "no transfer context with identifier, "
|
||||||
|
<< receivedMessage.header.ackSessionIdentifier
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_messageBuffer.contains(receivedMessage.header.identifier))
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo
|
||||||
|
<< TQString("retrieving buffered messsage, %1").arg(receivedMessage.header.identifier)
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
// The message was split, try to reconstruct the message
|
||||||
|
// with this received piece.
|
||||||
|
Message bufferedMessage = m_messageBuffer[receivedMessage.header.identifier];
|
||||||
|
// Remove the buffered message.
|
||||||
|
m_messageBuffer.remove(receivedMessage.header.identifier);
|
||||||
|
|
||||||
|
bufferedMessage.body.resize(bufferedMessage.body.size() + receivedMessage.header.dataSize);
|
||||||
|
for(TQ_UINT32 i=0; i < receivedMessage.header.dataSize; i++){
|
||||||
|
// Add the remaining message data to the buffered message.
|
||||||
|
bufferedMessage.body[receivedMessage.header.dataOffset + i] = receivedMessage.body[i];
|
||||||
|
}
|
||||||
|
bufferedMessage.header.dataSize += receivedMessage.header.dataSize;
|
||||||
|
bufferedMessage.header.dataOffset = 0;
|
||||||
|
|
||||||
|
receivedMessage = bufferedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch the received message.
|
||||||
|
dispatch(receivedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::dispatch(const P2P::Message& message)
|
||||||
|
|
||||||
|
{
|
||||||
|
TransferContext *messageHandler = 0l;
|
||||||
|
|
||||||
|
if(message.header.sessionId > 0)
|
||||||
|
{
|
||||||
|
if(m_sessions.contains(message.header.sessionId)){
|
||||||
|
messageHandler = m_sessions[message.header.sessionId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TQString body =
|
||||||
|
TQCString(message.body.data(), message.header.dataSize);
|
||||||
|
TQRegExp regex("SessionID: ([0-9]*)\r\n");
|
||||||
|
if(regex.search(body) > 0)
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId = regex.cap(1).toUInt();
|
||||||
|
if(m_sessions.contains(sessionId)){
|
||||||
|
// Retrieve the message handler associated with the specified session Id.
|
||||||
|
messageHandler = m_sessions[sessionId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, try to retrieve the message handler
|
||||||
|
// based on the acknowlegded unique identifier.
|
||||||
|
if(m_sessions.contains(message.header.ackUniqueIdentifier)){
|
||||||
|
messageHandler =
|
||||||
|
m_sessions[message.header.ackUniqueIdentifier];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!messageHandler)
|
||||||
|
{
|
||||||
|
// If the message handler still has not been found,
|
||||||
|
// try to retrieve the handler based on the call id.
|
||||||
|
regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString callId = regex.cap(1);
|
||||||
|
|
||||||
|
TransferContext *current = 0l;
|
||||||
|
TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
|
||||||
|
for(; it != m_sessions.end(); it++)
|
||||||
|
{
|
||||||
|
current = it.data();
|
||||||
|
if(current->m_callId == callId){
|
||||||
|
messageHandler = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(messageHandler){
|
||||||
|
// Process the received message using the
|
||||||
|
// retrieved registered handler.
|
||||||
|
messageHandler->m_ackSessionIdentifier = message.header.identifier;
|
||||||
|
messageHandler->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
|
||||||
|
messageHandler->processMessage(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// There are no objects registered, with the retrieved session Id,
|
||||||
|
// to handle the received message; default to this dispatcher.
|
||||||
|
|
||||||
|
if(message.header.totalDataSize > message.header.dataOffset + message.header.dataSize)
|
||||||
|
{
|
||||||
|
// The entire message has not been received;
|
||||||
|
// buffer the recevied portion of the original message.
|
||||||
|
kdDebug(14140) << k_funcinfo
|
||||||
|
<< TQString("Buffering messsage, %1").arg(message.header.identifier)
|
||||||
|
<< endl;
|
||||||
|
m_messageBuffer.insert(message.header.identifier, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString body =
|
||||||
|
TQCString(message.body.data(), message.header.dataSize);
|
||||||
|
kdDebug(14140) << k_funcinfo << "received, " << body << endl;
|
||||||
|
|
||||||
|
if(body.startsWith("INVITE"))
|
||||||
|
{
|
||||||
|
// Retrieve the branch, call id, and session id.
|
||||||
|
// These fields will be used later on in the p2p
|
||||||
|
// transaction.
|
||||||
|
TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString branch = regex.cap(1);
|
||||||
|
regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString callId = regex.cap(1);
|
||||||
|
regex = TQRegExp("SessionID: ([0-9]*)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString sessionId = regex.cap(1);
|
||||||
|
// Retrieve the contact that requested the session.
|
||||||
|
regex = TQRegExp("From: <msnmsgr:([^>]*)>");
|
||||||
|
regex.search(body);
|
||||||
|
TQString from = regex.cap(1);
|
||||||
|
// Retrieve the application identifier which
|
||||||
|
// is used to determine what type of session
|
||||||
|
// is being requested.
|
||||||
|
regex = TQRegExp("AppID: ([0-9]*)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQ_UINT32 applicationId = regex.cap(1).toUInt();
|
||||||
|
|
||||||
|
if(applicationId == 1 || applicationId == 11 || applicationId == 12 )
|
||||||
|
{ //the AppID is 12 since Messenger 7.5
|
||||||
|
// A contact has requested a session to download
|
||||||
|
// a display icon (User Display Icon or CustomEmotion).
|
||||||
|
|
||||||
|
regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
|
||||||
|
regex.search(body);
|
||||||
|
TQCString msnobj;
|
||||||
|
|
||||||
|
// Decode the msn object from base64 encoding.
|
||||||
|
KCodecs::base64Decode(regex.cap(1).utf8() , msnobj);
|
||||||
|
kdDebug(14140) << k_funcinfo << "Contact requested, "
|
||||||
|
<< msnobj << endl;
|
||||||
|
|
||||||
|
// Create a new transfer context that will handle
|
||||||
|
// the user display icon transfer.
|
||||||
|
TransferContext *current =
|
||||||
|
new OutgoingTransfer(from, this, sessionId.toUInt());
|
||||||
|
current->m_branch = branch;
|
||||||
|
current->m_callId = callId;
|
||||||
|
current->setType(P2P::UserDisplayIcon);
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId.toUInt(), current);
|
||||||
|
|
||||||
|
// Determine the display icon being requested.
|
||||||
|
TQString fileName = objectList.contains(msnobj)
|
||||||
|
? objectList[msnobj]
|
||||||
|
: m_pictureUrl;
|
||||||
|
TQFile *source = new TQFile(fileName);
|
||||||
|
// Try to open the source file for reading.
|
||||||
|
// If an error occurs, send an internal
|
||||||
|
// error message to the recipient.
|
||||||
|
if(!source->open(IO_ReadOnly))
|
||||||
|
{
|
||||||
|
current->error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current->m_file = source;
|
||||||
|
// Acknowledge the session request.
|
||||||
|
current->acknowledge(message);
|
||||||
|
|
||||||
|
current->m_ackSessionIdentifier = message.header.identifier;
|
||||||
|
current->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
|
||||||
|
// Send a 200 OK message to the recipient.
|
||||||
|
TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
|
||||||
|
current->sendMessage(OK, content);
|
||||||
|
}
|
||||||
|
else if(applicationId == 2)
|
||||||
|
{
|
||||||
|
// A contact has requested a session to
|
||||||
|
// send a file.
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "File transfer invitation." << endl;
|
||||||
|
|
||||||
|
// Create a new transfer context that will handle
|
||||||
|
// the file transfer.
|
||||||
|
TransferContext *transfer =
|
||||||
|
new IncomingTransfer(from, this, sessionId.toUInt());
|
||||||
|
transfer->m_branch = branch;
|
||||||
|
transfer->m_callId = callId;
|
||||||
|
transfer->setType(P2P::File);
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId.toUInt(), transfer);
|
||||||
|
|
||||||
|
regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
|
||||||
|
regex.search(body);
|
||||||
|
TQByteArray context;
|
||||||
|
|
||||||
|
// Decode the file context from base64 encoding.
|
||||||
|
KCodecs::base64Decode(regex.cap(1).utf8(), context);
|
||||||
|
TQDataStream reader(context, IO_ReadOnly);
|
||||||
|
reader.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
//Retrieve the file info from the context field.
|
||||||
|
// File Size [8..15] Int64
|
||||||
|
reader.device()->at(8);
|
||||||
|
TQ_INT64 fileSize;
|
||||||
|
reader >> fileSize;
|
||||||
|
// Flag [15..18] Int32
|
||||||
|
// 0x00 File transfer with preview data.
|
||||||
|
// 0x01 File transfer without preview data.
|
||||||
|
// 0x02 Background sharing.
|
||||||
|
TQ_INT32 flag;
|
||||||
|
reader >> flag;
|
||||||
|
kdDebug(14140) << flag << endl;
|
||||||
|
// FileName UTF16 (Unicode) [19..539]
|
||||||
|
TQByteArray bytes(520);
|
||||||
|
reader.readRawBytes(bytes.data(), bytes.size());
|
||||||
|
TQTextStream ts(bytes, IO_ReadOnly);
|
||||||
|
ts.setEncoding(TQTextStream::Unicode);
|
||||||
|
TQString fileName;
|
||||||
|
fileName = ts.readLine().utf8();
|
||||||
|
|
||||||
|
emit incomingTransfer(from, fileName, fileSize);
|
||||||
|
|
||||||
|
kdDebug(14140) <<
|
||||||
|
TQString("%1, %2 bytes.").arg(fileName, TQString::number(fileSize))
|
||||||
|
<< endl
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
// Get the contact that is sending the file.
|
||||||
|
Kopete::Contact *contact = getContactByAccountId(from);
|
||||||
|
|
||||||
|
if(contact)
|
||||||
|
{
|
||||||
|
// Acknowledge the file invitation message.
|
||||||
|
transfer->acknowledge(message);
|
||||||
|
|
||||||
|
transfer->m_ackSessionIdentifier = message.header.identifier;
|
||||||
|
transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
|
||||||
|
|
||||||
|
TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(accepted(Kopete::Transfer*, const TQString&)), transfer, TQT_SLOT(slotTransferAccepted(Kopete::Transfer*, const TQString&)));
|
||||||
|
TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(refused(const Kopete::FileTransferInfo&)), transfer, TQT_SLOT(slotTransferRefused(const Kopete::FileTransferInfo&)));
|
||||||
|
|
||||||
|
// Show the file transfer accept/decline dialog.
|
||||||
|
Kopete::TransferManager::transferManager()->askIncomingTransfer(contact, fileName, fileSize, TQString(), sessionId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdWarning(14140) << fileName << " from " << from
|
||||||
|
<< " has failed; could not retrieve contact from contact list."
|
||||||
|
<< endl;
|
||||||
|
transfer->m_ackSessionIdentifier = message.header.identifier;
|
||||||
|
transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
|
||||||
|
transfer->sendMessage(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(applicationId == 4)
|
||||||
|
{
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
regex = TQRegExp("EUF-GUID: \\{([0-9a-zA-Z\\-]*)\\}");
|
||||||
|
regex.search(body);
|
||||||
|
TQString GUID=regex.cap(1);
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "webcam " << GUID << endl;
|
||||||
|
|
||||||
|
Webcam::Who who;
|
||||||
|
if(GUID=="4BD96FC0-AB17-4425-A14A-439185962DC8")
|
||||||
|
{ //that mean "I want to send MY webcam"
|
||||||
|
who=Webcam::wViewer;
|
||||||
|
}
|
||||||
|
else if(GUID=="1C9AA97E-9C05-4583-A3BD-908A196F1E92")
|
||||||
|
{ //that mean "I want YOU to send YOUR webcam"
|
||||||
|
who=Webcam::wProducer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //unknown GUID
|
||||||
|
//current->error();
|
||||||
|
kdWarning(14140) << k_funcinfo << "Unknown GUID " << GUID << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferContext *current = new P2P::Webcam(who, from, this, sessionId.toUInt());
|
||||||
|
current->m_branch = branch;
|
||||||
|
current->m_callId = callId;
|
||||||
|
|
||||||
|
// Add the transfer to the list.
|
||||||
|
m_sessions.insert(sessionId.toUInt(), current);
|
||||||
|
// Acknowledge the session request.
|
||||||
|
current->acknowledge(message);
|
||||||
|
TQTimer::singleShot(0,current, TQT_SLOT(askIncommingInvitation()) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(message.header.sessionId == 64)
|
||||||
|
{
|
||||||
|
// A contact has sent an inkformat (handwriting) gif.
|
||||||
|
// NOTE The entire message body is UTF16 encoded.
|
||||||
|
TQString body = "";
|
||||||
|
for (TQ_UINT32 i=0; i < message.header.totalDataSize; i++){
|
||||||
|
if (message.body[i] != TQChar('\0')){
|
||||||
|
body += TQChar(message.body[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
|
||||||
|
regex.search(body);
|
||||||
|
TQString contentType = regex.cap(1);
|
||||||
|
|
||||||
|
if(contentType == "image/gif")
|
||||||
|
{
|
||||||
|
IncomingTransfer transfer(message.source, this, message.header.sessionId);
|
||||||
|
transfer.acknowledge(message);
|
||||||
|
|
||||||
|
regex = TQRegExp("base64:([0-9a-zA-Z+/=]*)");
|
||||||
|
regex.search(body);
|
||||||
|
TQString base64 = regex.cap(1);
|
||||||
|
TQByteArray image;
|
||||||
|
// Convert from base64 encoding to byte array.
|
||||||
|
KCodecs::base64Decode(base64.utf8(), image);
|
||||||
|
// Create a temporary file to store the image data.
|
||||||
|
KTempFile *ink = new KTempFile(locateLocal("tmp", "inkformatgif-" ), ".gif");
|
||||||
|
ink->setAutoDelete(true);
|
||||||
|
// Save the image data to disk.
|
||||||
|
ink->file()->writeBlock(image);
|
||||||
|
ink->file()->close();
|
||||||
|
displayIconReceived(ink, "inkformatgif");
|
||||||
|
ink = 0l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::messageAcknowledged(unsigned int correlationId, bool fullReceive)
|
||||||
|
{
|
||||||
|
if(fullReceive)
|
||||||
|
{
|
||||||
|
TransferContext *current = 0l;
|
||||||
|
TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
|
||||||
|
for(; it != m_sessions.end(); it++)
|
||||||
|
{
|
||||||
|
current = it.data();
|
||||||
|
if(current->m_transactionId == correlationId)
|
||||||
|
{
|
||||||
|
// Inform the transfer object of the acknowledge.
|
||||||
|
current->readyWrite();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::Contact* Dispatcher::getContactByAccountId(const TQString& accountId)
|
||||||
|
{
|
||||||
|
Kopete::Contact *contact = 0l;
|
||||||
|
if(parent())
|
||||||
|
{
|
||||||
|
// Retrieve the contact from the current chat session context.
|
||||||
|
Kopete::ChatSession *session = dynamic_cast<Kopete::ChatSession*>(parent()->parent());
|
||||||
|
if(session)
|
||||||
|
{
|
||||||
|
contact = session->account()->contacts()[accountId];
|
||||||
|
session->setCanBeDeleted(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dispatcher::CallbackChannel::CallbackChannel(MSNSwitchBoardSocket *switchboard)
|
||||||
|
{
|
||||||
|
m_switchboard = switchboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dispatcher::CallbackChannel::~CallbackChannel()
|
||||||
|
{}
|
||||||
|
|
||||||
|
TQ_UINT32 Dispatcher::CallbackChannel::send(const TQByteArray& stream)
|
||||||
|
{
|
||||||
|
return m_switchboard->sendCommand("MSG", "D", true, stream, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dispatcher::CallbackChannel* Dispatcher::callbackChannel()
|
||||||
|
{
|
||||||
|
if(m_callbackChannel == 0l){
|
||||||
|
MSNSwitchBoardSocket *callback = dynamic_cast<MSNSwitchBoardSocket *>(parent());
|
||||||
|
if(callback == 0l) return 0l;
|
||||||
|
m_callbackChannel = new Dispatcher::CallbackChannel(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_callbackChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dispatcher.moc"
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
dispatcher.h - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISPATCHER_H
|
||||||
|
#define DISPATCHER_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <tqstringlist.h>
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
#include "p2p.h"
|
||||||
|
#include "messageformatter.h"
|
||||||
|
#include "incomingtransfer.h"
|
||||||
|
#include "outgoingtransfer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Kopete { class Contact; }
|
||||||
|
class MSNSwitchBoardSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Kopete Developers
|
||||||
|
*/
|
||||||
|
namespace P2P{
|
||||||
|
class IncomingTransfer;
|
||||||
|
class OutgoingTransfer;
|
||||||
|
|
||||||
|
class KOPETE_EXPORT Dispatcher : public TQObject
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Dispatcher(TQObject *parent, const TQString& contact, const TQStringList &ip);
|
||||||
|
~Dispatcher();
|
||||||
|
|
||||||
|
void detach(TransferContext* transfer);
|
||||||
|
TQString localContact();
|
||||||
|
void requestDisplayIcon(const TQString& from, const TQString& msnObject);
|
||||||
|
void sendFile(const TQString& path, TQ_INT64 fileSize, const TQString& to);
|
||||||
|
void sendImage(const TQString& fileName, const TQString& to);
|
||||||
|
TQString m_pictureUrl;
|
||||||
|
TQMap<TQString, TQString> objectList;
|
||||||
|
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
void startWebcam(const TQString &myHandle, const TQString &msgHandle, bool wantToReceive);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotReadMessage(const TQString &from, const TQByteArray& stream);
|
||||||
|
void messageAcknowledged(unsigned int correlationId, bool fullReceive);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sendCommand(const TQString &cmd, const TQString &args = TQString(), bool addId = true, const TQByteArray &body = TQByteArray(), bool binary=false);
|
||||||
|
void displayIconReceived(KTempFile* file, const TQString& msnObject);
|
||||||
|
void incomingTransfer(const TQString& from, const TQString& fileName, TQ_INT64 fileSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class CallbackChannel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallbackChannel(MSNSwitchBoardSocket *switchboard);
|
||||||
|
~CallbackChannel();
|
||||||
|
|
||||||
|
TQ_UINT32 send(const TQByteArray& stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNSwitchBoardSocket *m_switchboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CallbackChannel* callbackChannel();
|
||||||
|
/**
|
||||||
|
* IP's of this compiter, the first one is the one seen by the server.
|
||||||
|
*/
|
||||||
|
TQStringList localIp() { return m_ip; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void dispatch(const P2P::Message& message);
|
||||||
|
Kopete::Contact* getContactByAccountId(const TQString& accountId);
|
||||||
|
|
||||||
|
P2P::MessageFormatter m_messageFormatter;
|
||||||
|
TQMap<TQ_UINT32, P2P::TransferContext*> m_sessions;
|
||||||
|
TQMap<TQ_UINT32, P2P::Message> m_messageBuffer;
|
||||||
|
TQString m_contact;
|
||||||
|
CallbackChannel *m_callbackChannel;
|
||||||
|
TQStringList m_ip;
|
||||||
|
|
||||||
|
friend class P2P::TransferContext;
|
||||||
|
friend class P2P::IncomingTransfer;
|
||||||
|
friend class P2P::OutgoingTransfer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "kdemacros.h"
|
||||||
|
extern "C" KDE_EXPORT void *init_libkopete_msn_shared();
|
||||||
|
extern "C" KDE_EXPORT void *init_kopete_msn() { return init_libkopete_msn_shared(); }
|
@ -0,0 +1,12 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
|
@ -0,0 +1,2 @@
|
|||||||
|
kopeteicondir = $(kde_datadir)/kopete/icons
|
||||||
|
kopeteicon_ICON = AUTO
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 661 B |
After Width: | Height: | Size: 292 B |
After Width: | Height: | Size: 449 B |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 687 B |
After Width: | Height: | Size: 497 B |
After Width: | Height: | Size: 387 B |
After Width: | Height: | Size: 688 B |
After Width: | Height: | Size: 819 B |
After Width: | Height: | Size: 943 B |
After Width: | Height: | Size: 523 B |
After Width: | Height: | Size: 943 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,384 @@
|
|||||||
|
/*
|
||||||
|
incomingtransfer.cpp - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "incomingtransfer.h"
|
||||||
|
using P2P::TransferContext;
|
||||||
|
using P2P::IncomingTransfer;
|
||||||
|
using P2P::Message;
|
||||||
|
|
||||||
|
// Kde includes
|
||||||
|
#include <kbufferedsocket.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <kserversocket.h>
|
||||||
|
#include <kstandarddirs.h>
|
||||||
|
#include <tdetempfile.h>
|
||||||
|
using namespace KNetwork;
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqfile.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
|
||||||
|
// Kopete includes
|
||||||
|
#include <kopetetransfermanager.h>
|
||||||
|
|
||||||
|
IncomingTransfer::IncomingTransfer(const TQString& from, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId)
|
||||||
|
: TransferContext(from,dispatcher,sessionId)
|
||||||
|
{
|
||||||
|
m_direction = P2P::Incoming;
|
||||||
|
m_listener = 0l;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncomingTransfer::~IncomingTransfer()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
if(m_listener)
|
||||||
|
{
|
||||||
|
delete m_listener;
|
||||||
|
m_listener = 0l;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_socket)
|
||||||
|
{
|
||||||
|
delete m_socket;
|
||||||
|
m_socket = 0l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IncomingTransfer::slotTransferAccepted(Kopete::Transfer* transfer, const TQString& /*fileName*/)
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId = transfer->info().internalId().toUInt();
|
||||||
|
if(sessionId!=m_sessionId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQObject::connect(transfer , TQT_SIGNAL(transferCanceled()), this, TQT_SLOT(abort()));
|
||||||
|
m_transfer = transfer;
|
||||||
|
|
||||||
|
TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
|
||||||
|
sendMessage(OK, content);
|
||||||
|
|
||||||
|
TQObject::disconnect(Kopete::TransferManager::transferManager(), 0l, this, 0l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotTransferRefused(const Kopete::FileTransferInfo& info)
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId = info.internalId().toUInt();
|
||||||
|
if(sessionId!=m_sessionId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
|
||||||
|
// Send the sending client a cancelation message.
|
||||||
|
sendMessage(DECLINE, content);
|
||||||
|
m_state=Finished;
|
||||||
|
|
||||||
|
TQObject::disconnect(Kopete::TransferManager::transferManager(), 0l, this, 0l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IncomingTransfer::acknowledged()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
switch(m_state)
|
||||||
|
{
|
||||||
|
case Invitation:
|
||||||
|
// NOTE UDI: base identifier acknowledge message, ignore.
|
||||||
|
// UDI: 200 OK message should follow.
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
// FT: 200 OK acknowledged message.
|
||||||
|
// If this is the first connection between the two clients, a direct connection invitation
|
||||||
|
// should follow. Otherwise, the file transfer may start right away.
|
||||||
|
if(m_transfer)
|
||||||
|
{
|
||||||
|
TQFile *destination = new TQFile(m_transfer->destinationURL().path());
|
||||||
|
if(!destination->open(IO_WriteOnly))
|
||||||
|
{
|
||||||
|
m_transfer->slotError(TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, i18n("Cannot open file for writing"));
|
||||||
|
m_transfer = 0l;
|
||||||
|
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_file = destination;
|
||||||
|
}
|
||||||
|
m_state = Negotiation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Negotiation:
|
||||||
|
// 200 OK acknowledge message.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DataTransfer:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Finished:
|
||||||
|
// UDI: Bye acknowledge message.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::processMessage(const Message& message)
|
||||||
|
{
|
||||||
|
if(m_file && (message.header.flag == 0x20 || message.header.flag == 0x01000030))
|
||||||
|
{
|
||||||
|
// UserDisplayIcon data or File data is in this message.
|
||||||
|
// Write the recieved data to the file.
|
||||||
|
kdDebug(14140) << k_funcinfo << TQString("Received, %1 bytes").arg(message.header.dataSize) << endl;
|
||||||
|
|
||||||
|
m_file->writeBlock(message.body.data(), message.header.dataSize);
|
||||||
|
if(m_transfer){
|
||||||
|
m_transfer->slotProcessed(message.header.dataOffset + message.header.dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((message.header.dataOffset + message.header.dataSize) == message.header.totalDataSize)
|
||||||
|
{
|
||||||
|
// Transfer is complete.
|
||||||
|
if(m_type == UserDisplayIcon){
|
||||||
|
m_tempFile->close();
|
||||||
|
m_dispatcher->displayIconReceived(m_tempFile, m_object);
|
||||||
|
m_tempFile = 0l;
|
||||||
|
m_file = 0l;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_file->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isComplete = true;
|
||||||
|
// Send data acknowledge message.
|
||||||
|
acknowledge(message);
|
||||||
|
|
||||||
|
if(m_type == UserDisplayIcon)
|
||||||
|
{
|
||||||
|
m_state = Finished;
|
||||||
|
// Send BYE message.
|
||||||
|
sendMessage(BYE, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(message.header.dataSize == 4 && message.applicationIdentifier == 1)
|
||||||
|
{
|
||||||
|
// Data preparation message.
|
||||||
|
//if (m_tempFile->name().isEmpty() == false) {
|
||||||
|
// TQFile::remove(m_tempFile->name());
|
||||||
|
//}
|
||||||
|
m_tempFile = new KTempFile(locateLocal("tmp", "msnpicture--"), ".png");
|
||||||
|
m_tempFile->setAutoDelete(true);
|
||||||
|
m_file = m_tempFile->file();
|
||||||
|
m_state = DataTransfer;
|
||||||
|
// Send data preparation acknowledge message.
|
||||||
|
acknowledge(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TQString body =
|
||||||
|
TQCString(message.body.data(), message.header.dataSize);
|
||||||
|
// kdDebug(14140) << k_funcinfo << "received, " << body << endl;
|
||||||
|
|
||||||
|
if(body.startsWith("INVITE"))
|
||||||
|
{
|
||||||
|
// Retrieve some MSNSLP headers used when
|
||||||
|
// replying to this INVITE message.
|
||||||
|
TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_branch = regex.cap(1);
|
||||||
|
// NOTE Call-ID never changes.
|
||||||
|
regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_callId = regex.cap(1);
|
||||||
|
regex = TQRegExp("Bridges: ([^\r\n]*)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString bridges = regex.cap(1);
|
||||||
|
// The NetID field is 0 if the Conn-Type is
|
||||||
|
// Direct-Connect or Firewall, otherwise, it is
|
||||||
|
// a randomly generated number.
|
||||||
|
regex = TQRegExp("NetID: (\\-?\\d+)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString netId = regex.cap(1);
|
||||||
|
kdDebug(14140) << "net id, " << netId << endl;
|
||||||
|
// Connection Types
|
||||||
|
// - Direct-Connect
|
||||||
|
// - Port-Restrict-NAT
|
||||||
|
// - IP-Restrict-NAT
|
||||||
|
// - Symmetric-NAT
|
||||||
|
// - Firewall
|
||||||
|
regex = TQRegExp("Conn-Type: ([^\r\n]+)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
TQString connType = regex.cap(1);
|
||||||
|
|
||||||
|
bool wouldListen = false;
|
||||||
|
if(netId.toUInt() == 0 && connType == "Direct-Connect"){
|
||||||
|
wouldListen = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(connType == "IP-Restrict-NAT"){
|
||||||
|
wouldListen = true;
|
||||||
|
}
|
||||||
|
#if 1
|
||||||
|
wouldListen = false; // TODO Direct connection support
|
||||||
|
#endif
|
||||||
|
TQString content;
|
||||||
|
|
||||||
|
if(wouldListen)
|
||||||
|
{
|
||||||
|
// Create a listening socket for direct file transfer.
|
||||||
|
m_listener = new TDEServerSocket("", "");
|
||||||
|
m_listener->setResolutionEnabled(true);
|
||||||
|
// Create the callback that will try to accept incoming connections.
|
||||||
|
TQObject::connect(m_listener, TQT_SIGNAL(readyAccept()), TQT_SLOT(slotAccept()));
|
||||||
|
TQObject::connect(m_listener, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotListenError(int)));
|
||||||
|
// Listen for incoming connections.
|
||||||
|
bool isListening = m_listener->listen(1);
|
||||||
|
kdDebug(14140) << k_funcinfo << (isListening ? "listening" : "not listening") << endl;
|
||||||
|
kdDebug(14140) << k_funcinfo
|
||||||
|
<< "local endpoint, " << m_listener->localAddress().nodeName()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
content = "Bridge: TCPv1\r\n"
|
||||||
|
"Listening: true\r\n" +
|
||||||
|
TQString("Hashed-Nonce: {%1}\r\n").arg(P2P::Uid::createUid()) +
|
||||||
|
TQString("IPv4Internal-Addrs: %1\r\n").arg(m_listener->localAddress().nodeName()) +
|
||||||
|
TQString("IPv4Internal-Port: %1\r\n").arg(m_listener->localAddress().serviceName()) +
|
||||||
|
"\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content =
|
||||||
|
"Bridge: TCPv1\r\n"
|
||||||
|
"Listening: false\r\n"
|
||||||
|
"Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
|
||||||
|
"\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = DataTransfer;
|
||||||
|
|
||||||
|
if (m_type != File)
|
||||||
|
{
|
||||||
|
// NOTE For file transfers, the connection invite *must not* be acknowledged in any way
|
||||||
|
// as this trips MSN 7.5
|
||||||
|
|
||||||
|
acknowledge(message);
|
||||||
|
// Send 200 OK message to the sending client.
|
||||||
|
sendMessage(OK, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(body.startsWith("BYE"))
|
||||||
|
{
|
||||||
|
m_state = Finished;
|
||||||
|
// Send the sending client an acknowledge message.
|
||||||
|
acknowledge(message);
|
||||||
|
|
||||||
|
if(m_file && m_transfer)
|
||||||
|
{
|
||||||
|
if(m_isComplete){
|
||||||
|
// The transfer is complete.
|
||||||
|
m_transfer->slotComplete();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The transfer has been canceled remotely.
|
||||||
|
if(m_transfer){
|
||||||
|
// Inform the user of the file transfer cancelation.
|
||||||
|
m_transfer->slotError(TDEIO::ERR_ABORTED, i18n("File transfer canceled."));
|
||||||
|
}
|
||||||
|
// Remove the partially received file.
|
||||||
|
m_file->remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispose of this transfer context.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
else if(body.startsWith("MSNSLP/1.0 200 OK"))
|
||||||
|
{
|
||||||
|
if(m_type == UserDisplayIcon){
|
||||||
|
m_state = Negotiation;
|
||||||
|
// Acknowledge the 200 OK message.
|
||||||
|
acknowledge(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotListenError(int /*errorCode*/)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << m_listener->errorString() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotAccept()
|
||||||
|
{
|
||||||
|
// Try to accept an incoming connection from the sending client.
|
||||||
|
m_socket = static_cast<TDEBufferedSocket*>(m_listener->accept());
|
||||||
|
if(!m_socket)
|
||||||
|
{
|
||||||
|
// NOTE If direct connection fails, the sending
|
||||||
|
// client wil transfer the file data through the
|
||||||
|
// existing session.
|
||||||
|
kdDebug(14140) << k_funcinfo << "Direct connection failed." << endl;
|
||||||
|
// Close the listening endpoint.
|
||||||
|
m_listener->close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "Direct connection established." << endl;
|
||||||
|
|
||||||
|
// Set the socket to non blocking,
|
||||||
|
// enable the ready read signal and disable
|
||||||
|
// ready write signal.
|
||||||
|
// NOTE readyWrite consumes too much cpu usage.
|
||||||
|
m_socket->setBlocking(false);
|
||||||
|
m_socket->enableRead(true);
|
||||||
|
m_socket->enableWrite(false);
|
||||||
|
|
||||||
|
// Create the callback that will try to read bytes from the accepted socket.
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(readyRead()), this, TQT_SLOT(slotSocketRead()));
|
||||||
|
// Create the callback that will try to handle the socket close event.
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(closed()), this, TQT_SLOT(slotSocketClosed()));
|
||||||
|
// Create the callback that will try to handle the socket error event.
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotSocketRead()
|
||||||
|
{
|
||||||
|
int available = m_socket->bytesAvailable();
|
||||||
|
kdDebug(14140) << k_funcinfo << available << ", bytes available." << endl;
|
||||||
|
if(available > 0)
|
||||||
|
{
|
||||||
|
TQByteArray buffer(available);
|
||||||
|
m_socket->readBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
if(TQString(buffer) == "foo"){
|
||||||
|
kdDebug(14140) << "Connection Check." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotSocketClosed()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncomingTransfer::slotSocketError(int errorCode)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << errorCode << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "incomingtransfer.moc"
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
incomingtransfer.h - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCOMINGTRANSFER_H
|
||||||
|
#define INCOMINGTRANSFER_H
|
||||||
|
|
||||||
|
#include "p2p.h"
|
||||||
|
#include "dispatcher.h"
|
||||||
|
|
||||||
|
namespace KNetwork{
|
||||||
|
class TDEServerSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Kopete Developers
|
||||||
|
*/
|
||||||
|
namespace P2P{
|
||||||
|
class IncomingTransfer : public P2P::TransferContext
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
IncomingTransfer(const TQString& from, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId);
|
||||||
|
virtual ~IncomingTransfer();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotListenError(int errorCode);
|
||||||
|
void slotAccept();
|
||||||
|
void slotSocketRead();
|
||||||
|
void slotSocketClosed();
|
||||||
|
void slotSocketError(int errorCode);
|
||||||
|
|
||||||
|
void slotTransferAccepted(Kopete::Transfer* transfer, const TQString& fileName);
|
||||||
|
void slotTransferRefused(const Kopete::FileTransferInfo& info);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void acknowledged();
|
||||||
|
virtual void processMessage(const Message& message);
|
||||||
|
|
||||||
|
KTempFile *m_tempFile;
|
||||||
|
KNetwork::TDEServerSocket *m_listener;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
messageformatter.cpp - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "messageformatter.h"
|
||||||
|
#include "p2p.h"
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqdatastream.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
|
||||||
|
// Kde includes
|
||||||
|
#include <kdebug.h>
|
||||||
|
|
||||||
|
using P2P::MessageFormatter;
|
||||||
|
using P2P::Message;
|
||||||
|
|
||||||
|
MessageFormatter::MessageFormatter(TQObject *parent, const char *name) : TQObject(parent, name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
MessageFormatter::~MessageFormatter()
|
||||||
|
{}
|
||||||
|
|
||||||
|
Message MessageFormatter::readMessage(const TQByteArray& stream, bool compact)
|
||||||
|
{
|
||||||
|
Message inbound;
|
||||||
|
|
||||||
|
TQ_UINT32 index = 0;
|
||||||
|
if(compact == false)
|
||||||
|
{
|
||||||
|
// Determine the end position of the message header.
|
||||||
|
while(index < stream.size())
|
||||||
|
{
|
||||||
|
if(stream[index++] == '\n'){
|
||||||
|
if(stream[index - 3] == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the message header.
|
||||||
|
TQString messageHeader = TQCString(stream.data(), index);
|
||||||
|
|
||||||
|
// Retrieve the message mime version, content type,
|
||||||
|
// and p2p destination.
|
||||||
|
TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
|
||||||
|
regex.search(messageHeader);
|
||||||
|
TQString contentType = regex.cap(1);
|
||||||
|
|
||||||
|
if(contentType != "application/x-msnmsgrp2p")
|
||||||
|
return inbound;
|
||||||
|
|
||||||
|
// kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
regex = TQRegExp("MIME-Version: (\\d.\\d)");
|
||||||
|
regex.search(messageHeader);
|
||||||
|
inbound.mimeVersion = regex.cap(1);
|
||||||
|
inbound.contentType = contentType;
|
||||||
|
regex = TQRegExp("P2P-Dest: ([^\r\n]*)");
|
||||||
|
regex.search(messageHeader);
|
||||||
|
TQString destination = regex.cap(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQDataStream reader(stream, IO_ReadOnly);
|
||||||
|
reader.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
// Seek to the start position of the message
|
||||||
|
// transport header.
|
||||||
|
reader.device()->at(index);
|
||||||
|
|
||||||
|
// Read the message transport headers from the stream.
|
||||||
|
reader >> inbound.header.sessionId;
|
||||||
|
reader >> inbound.header.identifier;
|
||||||
|
reader >> inbound.header.dataOffset;
|
||||||
|
reader >> inbound.header.totalDataSize;
|
||||||
|
reader >> inbound.header.dataSize;
|
||||||
|
reader >> inbound.header.flag;
|
||||||
|
reader >> inbound.header.ackSessionIdentifier;
|
||||||
|
reader >> inbound.header.ackUniqueIdentifier;
|
||||||
|
reader >> inbound.header.ackDataSize;
|
||||||
|
|
||||||
|
/*kdDebug(14140)
|
||||||
|
<< "session id, " << inbound.header.sessionId << endl
|
||||||
|
<< "identifier, " << inbound.header.identifier << endl
|
||||||
|
<< "data offset, " << inbound.header.dataOffset << endl
|
||||||
|
<< "total size, " << inbound.header.totalDataSize << endl
|
||||||
|
<< "data size, " << inbound.header.dataSize << endl
|
||||||
|
<< "flag, " << inbound.header.flag << endl
|
||||||
|
<< "ack session identifier, " << inbound.header.ackSessionIdentifier << endl
|
||||||
|
<< "ack unique identifier, " << inbound.header.ackUniqueIdentifier << endl
|
||||||
|
<< "ack data size, " << inbound.header.ackDataSize
|
||||||
|
<< endl;*/
|
||||||
|
|
||||||
|
// Read the message body from the stream.
|
||||||
|
if(inbound.header.dataSize > 0){
|
||||||
|
inbound.body.resize(inbound.header.dataSize);
|
||||||
|
reader.readRawBytes(inbound.body.data(), inbound.header.dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(compact == false)
|
||||||
|
{
|
||||||
|
reader.setByteOrder(TQDataStream::BigEndian);
|
||||||
|
// Read the message application identifier from the stream.
|
||||||
|
reader >> inbound.applicationIdentifier;
|
||||||
|
|
||||||
|
/* kdDebug(14140)
|
||||||
|
<< "application identifier, " << inbound.applicationIdentifier
|
||||||
|
<< endl;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return inbound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageFormatter::writeMessage(const Message& message, TQByteArray& stream, bool compact)
|
||||||
|
{
|
||||||
|
// kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
TQDataStream writer(stream, IO_WriteOnly);
|
||||||
|
writer.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
|
||||||
|
if(compact == false)
|
||||||
|
{
|
||||||
|
const TQCString messageHeader = TQString("MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: application/x-msnmsgrp2p\r\n"
|
||||||
|
"P2P-Dest: " + message.destination + "\r\n"
|
||||||
|
"\r\n").utf8();
|
||||||
|
// Set the capacity of the message buffer.
|
||||||
|
stream.resize(messageHeader.length() + 48 + message.body.size() + 4);
|
||||||
|
// Write the message header to the stream
|
||||||
|
writer.writeRawBytes(messageHeader.data(), messageHeader.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set the capacity of the message buffer.
|
||||||
|
stream.resize(4 + 48 + message.body.size());
|
||||||
|
// Write the message size to the stream.
|
||||||
|
writer << (TQ_INT32)(48+message.body.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write the transport headers to the stream.
|
||||||
|
writer << message.header.sessionId;
|
||||||
|
writer << message.header.identifier;
|
||||||
|
writer << message.header.dataOffset;
|
||||||
|
writer << message.header.totalDataSize;
|
||||||
|
writer << message.header.dataSize;
|
||||||
|
writer << message.header.flag;
|
||||||
|
writer << message.header.ackSessionIdentifier;
|
||||||
|
writer << message.header.ackUniqueIdentifier;
|
||||||
|
writer << message.header.ackDataSize;
|
||||||
|
|
||||||
|
/* kdDebug(14140)
|
||||||
|
<< "session id, " << message.header.sessionId << endl
|
||||||
|
<< "identifier, " << message.header.identifier << endl
|
||||||
|
<< "data offset, " << message.header.dataOffset << endl
|
||||||
|
<< "total size, " << message.header.totalDataSize << endl
|
||||||
|
<< "data size, " << message.header.dataSize << endl
|
||||||
|
<< "flag, " << message.header.flag << endl
|
||||||
|
<< "ack session identifier, " << message.header.ackSessionIdentifier << endl
|
||||||
|
<< "ack unique identifier, " << message.header.ackUniqueIdentifier << endl
|
||||||
|
<< "ack data size, " << message.header.ackDataSize
|
||||||
|
<< endl;
|
||||||
|
*/
|
||||||
|
if(message.body.size() > 0){
|
||||||
|
// Write the messge body to the stream.
|
||||||
|
writer.writeRawBytes(message.body.data(), message.body.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(compact == false)
|
||||||
|
{
|
||||||
|
// Seek to the message application identifier section.
|
||||||
|
writer.setByteOrder(TQDataStream::BigEndian);
|
||||||
|
// Write the message application identifier to the stream.
|
||||||
|
writer << message.applicationIdentifier;
|
||||||
|
|
||||||
|
/* kdDebug(14140)
|
||||||
|
<< "application identifier, " << message.applicationIdentifier
|
||||||
|
<< endl;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "messageformatter.moc"
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
messageformatter.h - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MESSAGEFORMATTER_H
|
||||||
|
#define MESSAGEFORMATTER_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
|
||||||
|
namespace P2P{
|
||||||
|
class Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Kopete Developers
|
||||||
|
*/
|
||||||
|
namespace P2P{
|
||||||
|
class MessageFormatter : public TQObject
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessageFormatter(TQObject *parent = 0, const char *name = 0);
|
||||||
|
~MessageFormatter();
|
||||||
|
|
||||||
|
Message readMessage(const TQByteArray& stream, bool compact=false);
|
||||||
|
void writeMessage(const Message& message, TQByteArray& stream, bool compact=false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
msnaccount.h - Manages a single MSN account
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Michaêl Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2003-2005 by The Kopete developers <kopete-devel@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 MSNACCOUNT_H
|
||||||
|
#define MSNACCOUNT_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
|
||||||
|
#include "kopetepasswordedaccount.h"
|
||||||
|
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
|
||||||
|
class TDEAction;
|
||||||
|
class TDEActionMenu;
|
||||||
|
|
||||||
|
class MSNNotifySocket;
|
||||||
|
class MSNContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSNAccount encapsulates everything that is account-based, as opposed to
|
||||||
|
* protocol based. This basically means sockets, current status, and account
|
||||||
|
* info are stored in the account, whereas the protocol is only the
|
||||||
|
* 'manager' class that creates and manages accounts.
|
||||||
|
*/
|
||||||
|
class MSNAccount : public Kopete::PasswordedAccount
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNAccount( MSNProtocol *parent, const TQString &accountID, const char *name = 0L );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return the menu for this account
|
||||||
|
*/
|
||||||
|
virtual TDEActionMenu* actionMenu();
|
||||||
|
|
||||||
|
//------ internal functions
|
||||||
|
/**
|
||||||
|
* change the publicName to this new name
|
||||||
|
*/
|
||||||
|
void setPublicName( const TQString &name );
|
||||||
|
void setPersonalMessage(MSNProtocol::PersonalMessageType type, const TQString &personalMessage );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the MSN server
|
||||||
|
*/
|
||||||
|
TQString serverName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the MSN server port
|
||||||
|
*/
|
||||||
|
uint serverPort();
|
||||||
|
|
||||||
|
MSNNotifySocket *notifySocket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if we are able to send mail, or to open hotmail inbox
|
||||||
|
*/
|
||||||
|
bool isHotmail() const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the picture url.
|
||||||
|
*/
|
||||||
|
TQString pictureUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the picture url.
|
||||||
|
*/
|
||||||
|
void setPictureUrl(const TQString &url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the <msnobj> tag of the display picture
|
||||||
|
*/
|
||||||
|
TQString pictureObject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reset the <msnobj>. This method should be called if the displayimage has changed
|
||||||
|
* If we are actualy connected, it will imediatly update the <msgobj> on the server, exepted
|
||||||
|
* if @param silent is set to true
|
||||||
|
* @param force Force the application of MSN picture
|
||||||
|
*/
|
||||||
|
void resetPictureObject(bool silent=false, bool force=false);
|
||||||
|
|
||||||
|
//BEGIN Http
|
||||||
|
|
||||||
|
bool useHttpMethod() const;
|
||||||
|
|
||||||
|
//END
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the client ID for the myself contact of this account.
|
||||||
|
* It is dynamic to see if we really have a webcam or not.
|
||||||
|
*/
|
||||||
|
TQString myselfClientId() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void connectWithPassword( const TQString &password ) ;
|
||||||
|
virtual void disconnect() ;
|
||||||
|
virtual void setOnlineStatus( const Kopete::OnlineStatus &status , const TQString &reason = TQString());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask to the account to create a new chat session
|
||||||
|
*/
|
||||||
|
void slotStartChatSession( const TQString& handle );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single slot to display error message.
|
||||||
|
*/
|
||||||
|
void slotErrorMessageReceived( int type, const TQString &msg );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool createContact( const TQString &contactId, Kopete::MetaContact *parentContact );
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// Actions related
|
||||||
|
void slotStartChat();
|
||||||
|
void slotOpenInbox();
|
||||||
|
void slotChangePublicName();
|
||||||
|
|
||||||
|
//#if !defined NDEBUG //(Stupid moc which don't see when he don't need to slot this slot)
|
||||||
|
/**
|
||||||
|
* Show simple debugging aid
|
||||||
|
*/
|
||||||
|
void slotDebugRawCommand();
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
// notifySocket related
|
||||||
|
void slotStatusChanged( const Kopete::OnlineStatus &status );
|
||||||
|
void slotNotifySocketClosed();
|
||||||
|
void slotPersonalMessageChanged(const TQString& personalMessage);
|
||||||
|
void slotContactRemoved(const TQString& handle, const TQString& list, const TQString& contactGuid, const TQString& groupGuid );
|
||||||
|
void slotContactAdded(const TQString& handle, const TQString& list, const TQString& publicName, const TQString& contactGuid, const TQString &groupGuid );
|
||||||
|
void slotContactListed( const TQString& handle, const TQString& publicName, const TQString &contactGuid, uint lists, const TQString& groups );
|
||||||
|
void slotNewContactList();
|
||||||
|
/**
|
||||||
|
* The group has successful renamed in the server
|
||||||
|
* groupName: is new new group name
|
||||||
|
*/
|
||||||
|
void slotGroupRenamed(const TQString &groupGuid, const TQString& groupName );
|
||||||
|
/**
|
||||||
|
* A new group was created on the server (or received durring an LSG command)
|
||||||
|
*/
|
||||||
|
void slotGroupAdded( const TQString& groupName, const TQString &groupGuid );
|
||||||
|
/**
|
||||||
|
* Group was removed from the server
|
||||||
|
*/
|
||||||
|
void slotGroupRemoved( const TQString &groupGuid );
|
||||||
|
/**
|
||||||
|
* Incoming RING command: connect to the Switchboard server and send
|
||||||
|
* the startChat signal
|
||||||
|
*/
|
||||||
|
void slotCreateChat( const TQString& sessionID, const TQString& address, const TQString& auth,
|
||||||
|
const TQString& handle, const TQString& publicName );
|
||||||
|
/**
|
||||||
|
* Incoming XFR command: this is an result from
|
||||||
|
* slotStartChatSession(handle)
|
||||||
|
* connect to the switchboard server and sen startChat signal
|
||||||
|
*/
|
||||||
|
void slotCreateChat( const TQString& address, const TQString& auth);
|
||||||
|
|
||||||
|
|
||||||
|
// ui related
|
||||||
|
/**
|
||||||
|
* A kopetegroup is renamed, rename group on the server
|
||||||
|
*/
|
||||||
|
void slotKopeteGroupRenamed( Kopete::Group *g );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A kopetegroup is removed, remove the group in the server
|
||||||
|
**/
|
||||||
|
void slotKopeteGroupRemoved( Kopete::Group* );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add contact ui
|
||||||
|
*/
|
||||||
|
void slotContactAddedNotifyDialogClosed( const TQString &handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the dispatch server sends us the notification server to use.
|
||||||
|
*/
|
||||||
|
void createNotificationServer( const TQString &host, uint port );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a global identity key get changed.
|
||||||
|
*/
|
||||||
|
void slotGlobalIdentityChanged( const TQString &key, const TQVariant &value );
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNNotifySocket *m_notifySocket;
|
||||||
|
TDEAction *m_openInboxAction;
|
||||||
|
TDEAction *m_startChatAction;
|
||||||
|
TDEAction *m_changeDNAction;
|
||||||
|
|
||||||
|
// status which will be using for connecting
|
||||||
|
Kopete::OnlineStatus m_connectstatus;
|
||||||
|
|
||||||
|
TQStringList m_msgHandle;
|
||||||
|
|
||||||
|
bool m_newContactList;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the contact on the server in the given groups.
|
||||||
|
* this is a helper function called bu createContact and slotStatusChanged
|
||||||
|
*/
|
||||||
|
void addContactServerside(const TQString &contactId, TQPtrList<Kopete::Group> groupList);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public: //FIXME: should be private
|
||||||
|
TQMap<TQString, Kopete::Group*> m_groupList;
|
||||||
|
|
||||||
|
void addGroup( const TQString &groupName, const TQString &contactToAdd = TQString() );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and retrive a MSNContact by its contactGuid. (Helper function)
|
||||||
|
*/
|
||||||
|
MSNContact *findContactByGuid(const TQString &contactGuid);
|
||||||
|
private:
|
||||||
|
|
||||||
|
// server data
|
||||||
|
TQStringList m_allowList;
|
||||||
|
TQStringList m_blockList;
|
||||||
|
TQStringList m_reverseList;
|
||||||
|
|
||||||
|
Kopete::MetaContact *m_addWizard_metaContact;
|
||||||
|
TQMap< TQString, TQStringList > tmp_addToNewGroup;
|
||||||
|
TQMap< TQString, TQStringList > tmp_addNewContactToGroup;
|
||||||
|
|
||||||
|
TQString m_pictureObj; //a cache of the <msnobj>
|
||||||
|
TQString m_pictureFilename; // the picture filename.
|
||||||
|
|
||||||
|
//this is the translation between old to new groups id when syncing from server.
|
||||||
|
TQMap<TQString, Kopete::Group*> m_oldGroupList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I need the password in createNotificationServer.
|
||||||
|
* but i can't ask it there with password() because a nested loop will provoque crash
|
||||||
|
* at this place. so i'm forced to keep it here.
|
||||||
|
* I would like an API to request the password WITHOUT askling it.
|
||||||
|
*/
|
||||||
|
TQString m_password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cliend ID is a bitfield that contains supported features for a MSN contact.
|
||||||
|
*/
|
||||||
|
uint m_clientId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Kopete (c) 2002-2005 by The Kopete developers <kopete-devel@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 <tqlayout.h>
|
||||||
|
#include <tqlineedit.h>
|
||||||
|
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
|
||||||
|
#include "msnadd.h"
|
||||||
|
#include "msnaddcontactpage.h"
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
#include "kopeteaccount.h"
|
||||||
|
#include "kopeteuiglobal.h"
|
||||||
|
|
||||||
|
MSNAddContactPage::MSNAddContactPage(bool connected, TQWidget *parent, const char *name )
|
||||||
|
: AddContactPage(parent,name)
|
||||||
|
{
|
||||||
|
(new TQVBoxLayout(this))->setAutoAdd(true);
|
||||||
|
/* if ( connected )
|
||||||
|
{*/
|
||||||
|
msndata = new msnAddUI(this);
|
||||||
|
/*
|
||||||
|
msndata->cmbGroup->insertStringList(owner->getGroups());
|
||||||
|
msndata->cmbGroup->setCurrentItem(0);
|
||||||
|
*/
|
||||||
|
canadd = true;
|
||||||
|
|
||||||
|
/* }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
noaddMsg1 = new TQLabel( i18n( "You need to be connected to be able to add contacts." ), this );
|
||||||
|
noaddMsg2 = new TQLabel( i18n( "Please connect to the MSN network and try again." ), this );
|
||||||
|
canadd = false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
MSNAddContactPage::~MSNAddContactPage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNAddContactPage::apply( Kopete::Account* i, Kopete::MetaContact*m )
|
||||||
|
{
|
||||||
|
if ( validateData() )
|
||||||
|
{
|
||||||
|
TQString userid = msndata->addID->text();
|
||||||
|
return i->addContact( userid , m, Kopete::Account::ChangeKABC );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MSNAddContactPage::validateData()
|
||||||
|
{
|
||||||
|
if(!canadd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TQString userid = msndata->addID->text();
|
||||||
|
|
||||||
|
if(MSNProtocol::validContactId(userid))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
|
||||||
|
i18n( "<qt>You must enter a valid email address.</qt>" ), i18n( "MSN Plugin" ) );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msnaddcontactpage.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
#ifndef MSNADDCONTACTPAGE_H
|
||||||
|
#define MSNADDCONTACTPAGE_H
|
||||||
|
|
||||||
|
#include <tqwidget.h>
|
||||||
|
#include <addcontactpage.h>
|
||||||
|
#include <tqlabel.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@author duncan
|
||||||
|
*/
|
||||||
|
class msnAddUI;
|
||||||
|
class MSNProtocol;
|
||||||
|
|
||||||
|
class MSNAddContactPage : public AddContactPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNAddContactPage(bool connected, TQWidget *parent=0, const char *name=0);
|
||||||
|
~MSNAddContactPage();
|
||||||
|
msnAddUI *msndata;
|
||||||
|
TQLabel *noaddMsg1;
|
||||||
|
TQLabel *noaddMsg2;
|
||||||
|
bool canadd;
|
||||||
|
virtual bool validateData();
|
||||||
|
virtual bool apply( Kopete::Account*, Kopete::MetaContact* );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
msnchallengehandler.h - Computes a msn challenge response hash key.
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
Kopete (c) 2003-2005 by The Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions taken from
|
||||||
|
http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "msnchallengehandler.h"
|
||||||
|
|
||||||
|
#include <tqdatastream.h>
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kmdcodec.h>
|
||||||
|
|
||||||
|
MSNChallengeHandler::MSNChallengeHandler(const TQString& productKey, const TQString& productId)
|
||||||
|
{
|
||||||
|
m_productKey = productKey;
|
||||||
|
m_productId = productId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MSNChallengeHandler::~MSNChallengeHandler()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNChallengeHandler::computeHash(const TQString& challengeString)
|
||||||
|
{
|
||||||
|
// Step One: THe MD5 Hash.
|
||||||
|
|
||||||
|
// Combine the received challenge string with the product key.
|
||||||
|
KMD5 md5((challengeString + m_productKey).utf8());
|
||||||
|
TQCString digest = md5.hexDigest();
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "md5: " << digest << endl;
|
||||||
|
|
||||||
|
TQValueVector<TQ_INT32> md5Integers(4);
|
||||||
|
for(TQ_UINT32 i=0; i < md5Integers.count(); i++)
|
||||||
|
{
|
||||||
|
md5Integers[i] = hexSwap(digest.mid(i*8, 8)).toUInt(0, 16) & 0x7FFFFFFF;
|
||||||
|
kdDebug(14140) << k_funcinfo << ("0x" + hexSwap(digest.mid(i*8, 8))) << " " << md5Integers[i] << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step Two: Create the challenge string key
|
||||||
|
|
||||||
|
TQString challengeKey = challengeString + m_productId;
|
||||||
|
// Pad to multiple of 8.
|
||||||
|
challengeKey = challengeKey.leftJustify(challengeKey.length() + (8 - challengeKey.length() % 8), '0');
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "challenge key: " << challengeKey << endl;
|
||||||
|
|
||||||
|
TQValueVector<TQ_INT32> challengeIntegers(challengeKey.length() / 4);
|
||||||
|
for(TQ_UINT32 i=0; i < challengeIntegers.count(); i++)
|
||||||
|
{
|
||||||
|
TQString sNum = challengeKey.mid(i*4, 4), sNumHex;
|
||||||
|
|
||||||
|
// Go through the number string, determining the hex equivalent of each value
|
||||||
|
// and add that to our new hex string for this number.
|
||||||
|
for(uint j=0; j < sNum.length(); j++) {
|
||||||
|
sNumHex += TQString::number((int)sNum[j].latin1(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap because of the byte ordering issue.
|
||||||
|
sNumHex = hexSwap(sNumHex);
|
||||||
|
// Assign the converted number.
|
||||||
|
challengeIntegers[i] = sNumHex.toInt(0, 16);
|
||||||
|
kdDebug(14140) << k_funcinfo << sNum << (": 0x"+sNumHex) << " " << challengeIntegers[i] << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step Three: Create the 64-bit hash key.
|
||||||
|
|
||||||
|
// Get the hash key using the specified arrays.
|
||||||
|
TQ_INT64 key = createHashKey(md5Integers, challengeIntegers);
|
||||||
|
kdDebug(14140) << k_funcinfo << "key: " << key << endl;
|
||||||
|
|
||||||
|
// Step Four: Create the final hash key.
|
||||||
|
|
||||||
|
TQString upper = TQString::number(TQString(digest.mid(0, 16)).toULongLong(0, 16)^key, 16);
|
||||||
|
if(upper.length() % 16 != 0)
|
||||||
|
upper = upper.rightJustify(upper.length() + (16 - upper.length() % 16), '0');
|
||||||
|
|
||||||
|
TQString lower = TQString::number(TQString(digest.mid(16, 16)).toULongLong(0, 16)^key, 16);
|
||||||
|
if(lower.length() % 16 != 0)
|
||||||
|
lower = lower.rightJustify(lower.length() + (16 - lower.length() % 16), '0');
|
||||||
|
|
||||||
|
return (upper + lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQ_INT64 MSNChallengeHandler::createHashKey(const TQValueVector<TQ_INT32>& md5Integers,
|
||||||
|
const TQValueVector<TQ_INT32>& challengeIntegers)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "Creating 64-bit key." << endl;
|
||||||
|
|
||||||
|
TQ_INT64 magicNumber = 0x0E79A9C1L, high = 0L, low = 0L;
|
||||||
|
|
||||||
|
for(uint i=0; i < challengeIntegers.count(); i += 2)
|
||||||
|
{
|
||||||
|
TQ_INT64 temp = ((challengeIntegers[i] * magicNumber) % 0x7FFFFFFF) + high;
|
||||||
|
temp = ((temp * md5Integers[0]) + md5Integers[1]) % 0x7FFFFFFF;
|
||||||
|
|
||||||
|
high = (challengeIntegers[i + 1] + temp) % 0x7FFFFFFF;
|
||||||
|
high = ((high * md5Integers[2]) + md5Integers[3]) % 0x7FFFFFFF;
|
||||||
|
|
||||||
|
low += high + temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
high = (high + md5Integers[1]) % 0x7FFFFFFF;
|
||||||
|
low = (low + md5Integers[3]) % 0x7FFFFFFF;
|
||||||
|
|
||||||
|
TQDataStream buffer(TQByteArray(8), IO_ReadWrite);
|
||||||
|
buffer.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
buffer << (TQ_INT32)high;
|
||||||
|
buffer << (TQ_INT32)low;
|
||||||
|
|
||||||
|
buffer.device()->reset();
|
||||||
|
buffer.setByteOrder(TQDataStream::BigEndian);
|
||||||
|
TQ_INT64 key;
|
||||||
|
buffer >> key;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNChallengeHandler::hexSwap(const TQString& in)
|
||||||
|
{
|
||||||
|
TQString sHex = in, swapped;
|
||||||
|
while(sHex.length() > 0)
|
||||||
|
{
|
||||||
|
swapped = swapped + sHex.mid(sHex.length() - 2, 2);
|
||||||
|
sHex = sHex.remove(sHex.length() - 2, 2);
|
||||||
|
}
|
||||||
|
return swapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNChallengeHandler::productId()
|
||||||
|
{
|
||||||
|
return m_productId;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msnchallengehandler.moc"
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
msnchallengehandler.h - Computes a msn challenge response hash key.
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
Kopete (c) 2003-2005 by The Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions taken from
|
||||||
|
http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MSNCHALLENGEHANDLER_H
|
||||||
|
#define MSNCHALLENGEHANDLER_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <tqvaluevector.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a simple way to compute a msn challenge response hash key.
|
||||||
|
*
|
||||||
|
* @author Gregg Edghill
|
||||||
|
*/
|
||||||
|
class MSNChallengeHandler : public TQObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNChallengeHandler(const TQString& productKey, const TQString& productId);
|
||||||
|
~MSNChallengeHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the response hash string for the specified challenge string.
|
||||||
|
*/
|
||||||
|
TQString computeHash(const TQString& challengeString);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product id used by the challenge handler.
|
||||||
|
*/
|
||||||
|
TQString productId();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a 64-bit hash key.
|
||||||
|
*/
|
||||||
|
TQ_INT64 createHashKey(const TQValueVector<TQ_INT32>& md5Integers, const TQValueVector<TQ_INT32>& challengeIntegers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the bytes in a hex string.
|
||||||
|
*/
|
||||||
|
TQString hexSwap(const TQString& in);
|
||||||
|
|
||||||
|
TQString m_productKey;
|
||||||
|
TQString m_productId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,775 @@
|
|||||||
|
/*
|
||||||
|
msnchatsession.cpp - MSN Message Manager
|
||||||
|
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart at kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 "msnchatsession.h"
|
||||||
|
|
||||||
|
#include <tqlabel.h>
|
||||||
|
#include <tqimage.h>
|
||||||
|
#include <tqtooltip.h>
|
||||||
|
#include <tqfile.h>
|
||||||
|
#include <tqiconset.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kinputdialog.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
#include <tdepopupmenu.h>
|
||||||
|
#include <tdetempfile.h>
|
||||||
|
#include <tdemainwindow.h>
|
||||||
|
#include <tdetoolbar.h>
|
||||||
|
#include <krun.h>
|
||||||
|
|
||||||
|
#include "kopetecontactaction.h"
|
||||||
|
#include "kopetemetacontact.h"
|
||||||
|
#include "kopetecontactlist.h"
|
||||||
|
#include "kopetechatsessionmanager.h"
|
||||||
|
#include "kopeteuiglobal.h"
|
||||||
|
#include "kopeteglobal.h"
|
||||||
|
#include "kopeteview.h"
|
||||||
|
|
||||||
|
#include "msncontact.h"
|
||||||
|
#include "msnfiletransfersocket.h"
|
||||||
|
#include "msnaccount.h"
|
||||||
|
#include "msnswitchboardsocket.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if !defined NDEBUG
|
||||||
|
#include "msndebugrawcmddlg.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MSNChatSession::MSNChatSession( Kopete::Protocol *protocol, const Kopete::Contact *user,
|
||||||
|
Kopete::ContactPtrList others, const char *name )
|
||||||
|
: Kopete::ChatSession( user, others, protocol, name )
|
||||||
|
{
|
||||||
|
Kopete::ChatSessionManager::self()->registerChatSession( this );
|
||||||
|
m_chatService = 0l;
|
||||||
|
m_timeoutTimer =0L;
|
||||||
|
m_newSession = true;
|
||||||
|
m_connectionTry=0;
|
||||||
|
|
||||||
|
setInstance(protocol->instance());
|
||||||
|
|
||||||
|
connect( this, TQT_SIGNAL( messageSent( Kopete::Message&,
|
||||||
|
Kopete::ChatSession* ) ),
|
||||||
|
this, TQT_SLOT( slotMessageSent( Kopete::Message&,
|
||||||
|
Kopete::ChatSession* ) ) );
|
||||||
|
|
||||||
|
connect( this, TQT_SIGNAL( invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* ) ) ,
|
||||||
|
protocol, TQT_SIGNAL( invitation(MSNInvitation*& , const TQString & , long unsigned int , MSNChatSession* , MSNContact* ) ) );
|
||||||
|
|
||||||
|
|
||||||
|
m_actionInvite = new TDEActionMenu( i18n( "&Invite" ), "kontact_contacts", actionCollection(), "msnInvite" );
|
||||||
|
connect ( m_actionInvite->popupMenu() , TQT_SIGNAL( aboutToShow() ) , this , TQT_SLOT(slotActionInviteAboutToShow() ) ) ;
|
||||||
|
|
||||||
|
#if !defined NDEBUG
|
||||||
|
new TDEAction( i18n( "Send Raw C&ommand..." ), 0, this, TQT_SLOT( slotDebugRawCommand() ), actionCollection(), "msnDebugRawCommand" ) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
m_actionNudge=new TDEAction( i18n( "Send Nudge" ), "bell", 0, this, TQT_SLOT(slotSendNudge() ), actionCollection(), "msnSendNudge" ) ;
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
// Invite to receive webcam action
|
||||||
|
m_actionWebcamReceive=new TDEAction( i18n( "View Contact's Webcam" ), "webcamreceive", 0, this, TQT_SLOT(slotWebcamReceive()), actionCollection(), "msnWebcamReceive" ) ;
|
||||||
|
|
||||||
|
//Send webcam action
|
||||||
|
m_actionWebcamSend=new TDEAction( i18n( "Send Webcam" ), "webcamsend", 0, this, TQT_SLOT(slotWebcamSend()), actionCollection(), "msnWebcamSend" ) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
new TDEAction( i18n( "Send File" ),"attach", 0, this, TQT_SLOT( slotSendFile() ), actionCollection(), "msnSendFile" );
|
||||||
|
|
||||||
|
MSNContact *c = static_cast<MSNContact*>( others.first() );
|
||||||
|
(new TDEAction( i18n( "Request Display Picture" ), "image", 0, this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnRequestDisplayPicture" ))->setEnabled(!c->object().isEmpty());
|
||||||
|
|
||||||
|
if ( !c->object().isEmpty() )
|
||||||
|
{
|
||||||
|
|
||||||
|
connect( c, TQT_SIGNAL( displayPictureChanged() ), this, TQT_SLOT( slotDisplayPictureChanged() ) );
|
||||||
|
m_image = new TQLabel( 0L, "kde toolbar widget" );
|
||||||
|
new KWidgetAction( m_image, i18n( "MSN Display Picture" ), 0, this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnDisplayPicture" );
|
||||||
|
if(c->hasProperty(Kopete::Global::Properties::self()->photo().key()) )
|
||||||
|
{
|
||||||
|
//if the view doesn't exist yet, we will be unable to get the size of the toolbar
|
||||||
|
// so when the view will exist, we will show the displaypicture.
|
||||||
|
//How to know when a our view is created? We can't.
|
||||||
|
// but chances are the next created view will be for this KMM
|
||||||
|
// And if it is not? never mind. the icon will just be sized 22x22
|
||||||
|
connect( Kopete::ChatSessionManager::self() , TQT_SIGNAL(viewActivated(KopeteView* )) , this, TQT_SLOT(slotDisplayPictureChanged()) );
|
||||||
|
//it's viewActivated and not viewCreated because the view get his mainwindow only when it is shown.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_image = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
setXMLFile("msnchatui.rc");
|
||||||
|
|
||||||
|
setMayInvite( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNChatSession::~MSNChatSession()
|
||||||
|
{
|
||||||
|
delete m_image;
|
||||||
|
//force to disconnect the switchboard
|
||||||
|
//not needed since the m_chatService has us as parent
|
||||||
|
// if(m_chatService)
|
||||||
|
// delete m_chatService;
|
||||||
|
|
||||||
|
TQMap<unsigned long int, MSNInvitation*>::Iterator it;
|
||||||
|
for( it = m_invitations.begin(); it != m_invitations.end() ; it = m_invitations.begin())
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
m_invitations.remove( it );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::createChat( const TQString &handle,
|
||||||
|
const TQString &address, const TQString &auth, const TQString &ID )
|
||||||
|
{
|
||||||
|
/* disabled because i don't want to reopen a chatwindow if we just closed it
|
||||||
|
* and the contact take much time to type his message
|
||||||
|
m_newSession= !(ID.isEmpty());
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( m_chatService )
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "Service already exists, disconnect them." << endl;
|
||||||
|
delete m_chatService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uncomment this line if you don't want to the peer know when you close the window
|
||||||
|
// setCanBeDeleted( false );
|
||||||
|
|
||||||
|
m_chatService = new MSNSwitchBoardSocket( static_cast<MSNAccount*>( myself()->account() ) , this);
|
||||||
|
m_chatService->setUseHttpMethod( static_cast<MSNAccount*>( myself()->account() )->useHttpMethod() );
|
||||||
|
m_chatService->setHandle( myself()->account()->accountId() );
|
||||||
|
m_chatService->setMsgHandle( handle );
|
||||||
|
m_chatService->connectToSwitchBoard( ID, address, auth );
|
||||||
|
|
||||||
|
connect( m_chatService, TQT_SIGNAL( userJoined(const TQString&,const TQString&,bool)),
|
||||||
|
this, TQT_SLOT( slotUserJoined(const TQString&,const TQString&,bool) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( userLeft(const TQString&,const TQString&)),
|
||||||
|
this, TQT_SLOT( slotUserLeft(const TQString&,const TQString&) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( msgReceived( Kopete::Message & ) ),
|
||||||
|
this, TQT_SLOT( slotMessageReceived( Kopete::Message & ) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( switchBoardClosed() ),
|
||||||
|
this, TQT_SLOT( slotSwitchBoardClosed() ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( receivedTypingMsg( const TQString &, bool ) ),
|
||||||
|
this, TQT_SLOT( receivedTypingMsg( const TQString &, bool ) ) );
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
if(config->readBoolEntry( "SendTypingNotification" , true) )
|
||||||
|
{
|
||||||
|
connect( this, TQT_SIGNAL( myselfTyping( bool ) ),
|
||||||
|
m_chatService, TQT_SLOT( sendTypingMsg( bool ) ) );
|
||||||
|
}
|
||||||
|
connect( m_chatService, TQT_SIGNAL( msgAcknowledgement(unsigned int, bool) ),
|
||||||
|
this, TQT_SLOT( slotAcknowledgement(unsigned int, bool) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( invitation( const TQString&, const TQString& ) ),
|
||||||
|
this, TQT_SLOT( slotInvitation( const TQString&, const TQString& ) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( nudgeReceived(const TQString&) ),
|
||||||
|
this, TQT_SLOT( slotNudgeReceived(const TQString&) ) );
|
||||||
|
connect( m_chatService, TQT_SIGNAL( errorMessage(int, const TQString& ) ), static_cast<MSNAccount *>(myself()->account()), TQT_SLOT( slotErrorMessageReceived(int, const TQString& ) ) );
|
||||||
|
|
||||||
|
if(!m_timeoutTimer)
|
||||||
|
{
|
||||||
|
m_timeoutTimer=new TQTimer(this);
|
||||||
|
connect( m_timeoutTimer , TQT_SIGNAL(timeout()), this , TQT_SLOT(slotConnectionTimeout() ) );
|
||||||
|
}
|
||||||
|
m_timeoutTimer->start(20000,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotUserJoined( const TQString &handle, const TQString &publicName, bool IRO )
|
||||||
|
{
|
||||||
|
delete m_timeoutTimer;
|
||||||
|
m_timeoutTimer=0L;
|
||||||
|
|
||||||
|
if( !account()->contacts()[ handle ] )
|
||||||
|
account()->addContact( handle, TQString(), 0L, Kopete::Account::Temporary);
|
||||||
|
|
||||||
|
MSNContact *c = static_cast<MSNContact*>( account()->contacts()[ handle ] );
|
||||||
|
|
||||||
|
c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName);
|
||||||
|
|
||||||
|
if(c->clientFlags() & MSNProtocol::MSNC4 )
|
||||||
|
{
|
||||||
|
m_actionNudge->setEnabled(true);
|
||||||
|
}
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
if(c->clientFlags() & MSNProtocol::SupportWebcam )
|
||||||
|
{
|
||||||
|
m_actionWebcamReceive->setEnabled(true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
addContact(c , IRO); // don't show notificaions when we join wesalef
|
||||||
|
if(!m_messagesQueue.empty() || !m_invitations.isEmpty())
|
||||||
|
sendMessageQueue();
|
||||||
|
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
if ( members().count()==1 && config->readNumEntry( "DownloadPicture", 1 ) >= 1 && !c->object().isEmpty() && !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
|
||||||
|
slotRequestPicture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotUserLeft( const TQString &handle, const TQString& reason )
|
||||||
|
{
|
||||||
|
MSNContact *c = static_cast<MSNContact*>( myself()->account()->contacts()[ handle ] );
|
||||||
|
if(c)
|
||||||
|
removeContact(c, reason );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::slotSwitchBoardClosed()
|
||||||
|
{
|
||||||
|
//kdDebug(14140) << "MSNChatSession::slotSwitchBoardClosed" << endl;
|
||||||
|
m_chatService->deleteLater();
|
||||||
|
m_chatService=0l;
|
||||||
|
|
||||||
|
cleanMessageQueue( i18n("Connection closed") );
|
||||||
|
|
||||||
|
if(m_invitations.isEmpty())
|
||||||
|
setCanBeDeleted( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotMessageSent(Kopete::Message &message,Kopete::ChatSession *)
|
||||||
|
{
|
||||||
|
m_newSession=false;
|
||||||
|
if(m_chatService)
|
||||||
|
{
|
||||||
|
int id = m_chatService->sendMsg(message);
|
||||||
|
if(id == -1)
|
||||||
|
{
|
||||||
|
m_messagesQueue.append(message);
|
||||||
|
kdDebug(14140) << k_funcinfo << "Message added to the queue" <<endl;
|
||||||
|
}
|
||||||
|
else if( id== -2 ) //the message has not been sent
|
||||||
|
{
|
||||||
|
//FIXME: tell the what window the message has been processed. but we havent't sent it
|
||||||
|
messageSucceeded(); //that should stop the blonking icon.
|
||||||
|
}
|
||||||
|
else if( id == -3) //the message has been sent as an immge
|
||||||
|
{
|
||||||
|
appendMessage(message);
|
||||||
|
messageSucceeded();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_messagesSent.insert( id, message );
|
||||||
|
message.setBg(TQColor()); // clear the bgColor
|
||||||
|
message.setBody(message.plainBody() , Kopete::Message::PlainText ); //clear every custom tag which are not sent
|
||||||
|
appendMessage(message); // send the own msg to chat window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // There's no switchboard available, so we must create a new one!
|
||||||
|
{
|
||||||
|
startChatSession();
|
||||||
|
m_messagesQueue.append(message);
|
||||||
|
// sendMessageQueue();
|
||||||
|
//m_msgQueued=new Kopete::Message(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotMessageReceived( Kopete::Message &msg )
|
||||||
|
{
|
||||||
|
m_newSession=false;
|
||||||
|
if( msg.plainBody().startsWith( "AutoMessage: " ) )
|
||||||
|
{
|
||||||
|
//FIXME: HardCodded color are not so good
|
||||||
|
msg.setFg( TQColor( "SlateGray3" ) );
|
||||||
|
TQFont f;
|
||||||
|
f.setItalic( true );
|
||||||
|
msg.setFont( f );
|
||||||
|
}
|
||||||
|
appendMessage( msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotActionInviteAboutToShow()
|
||||||
|
{
|
||||||
|
// We can't simply insert TDEAction in this menu bebause we don't know when to delete them.
|
||||||
|
// items inserted with insert items are automatically deleted when we call clear
|
||||||
|
|
||||||
|
m_inviteactions.setAutoDelete(true);
|
||||||
|
m_inviteactions.clear();
|
||||||
|
|
||||||
|
m_actionInvite->popupMenu()->clear();
|
||||||
|
|
||||||
|
|
||||||
|
TQDictIterator<Kopete::Contact> it( account()->contacts() );
|
||||||
|
for( ; it.current(); ++it )
|
||||||
|
{
|
||||||
|
if( !members().contains( it.current() ) && it.current()->isOnline() && it.current() != myself() )
|
||||||
|
{
|
||||||
|
TDEAction *a=new KopeteContactAction( it.current(), this,
|
||||||
|
TQT_SLOT( slotInviteContact( Kopete::Contact * ) ), m_actionInvite );
|
||||||
|
m_actionInvite->insert( a );
|
||||||
|
m_inviteactions.append( a ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TDEAction *b=new TDEAction( i18n ("Other..."), 0, this, TQT_SLOT( slotInviteOtherContact() ), m_actionInvite, "actionOther" );
|
||||||
|
m_actionInvite->insert( b );
|
||||||
|
m_inviteactions.append( b ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotCloseSession()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << m_chatService <<endl;
|
||||||
|
if(m_chatService)
|
||||||
|
m_chatService->slotCloseSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotInviteContact( Kopete::Contact *contact )
|
||||||
|
{
|
||||||
|
if(contact)
|
||||||
|
inviteContact( contact->contactId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::inviteContact(const TQString &contactId)
|
||||||
|
{
|
||||||
|
if( m_chatService )
|
||||||
|
m_chatService->slotInviteContact( contactId );
|
||||||
|
else
|
||||||
|
startChatSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotInviteOtherContact()
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
TQString handle = KInputDialog::getText(i18n( "MSN Plugin" ),
|
||||||
|
i18n( "Please enter the email address of the person you want to invite:" ),
|
||||||
|
TQString(), &ok );
|
||||||
|
if( !ok )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( handle.contains('@') != 1 || handle.contains('.') <1)
|
||||||
|
{
|
||||||
|
KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
|
||||||
|
i18n("<qt>You must enter a valid email address.</qt>"), i18n("MSN Plugin"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inviteContact(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::sendMessageQueue()
|
||||||
|
{
|
||||||
|
if(!m_chatService)
|
||||||
|
{
|
||||||
|
kdDebug(14140) <<k_funcinfo << "Service doesn't exist" <<endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// kdDebug(14140) << "MSNChatSession::sendMessageQueue: " << m_messagesQueue.count() <<endl;
|
||||||
|
for ( TQValueList<Kopete::Message>::iterator it = m_messagesQueue.begin(); it!=m_messagesQueue.end(); it = m_messagesQueue.begin() )
|
||||||
|
{
|
||||||
|
//m_chatService->sendMsg( *it) ;
|
||||||
|
slotMessageSent(*it , this);
|
||||||
|
m_messagesQueue.remove(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TQMap<unsigned long int, MSNInvitation*>::Iterator it;
|
||||||
|
for( it = m_invitations.begin(); it != m_invitations.end() ; ++it)
|
||||||
|
{
|
||||||
|
if(! (*it)->incoming() && (*it)->state()<MSNInvitation::Invited)
|
||||||
|
{
|
||||||
|
m_chatService->sendCommand( "MSG" , "N", true, (*it)->invitationHead().utf8() );
|
||||||
|
(*it)->setState(MSNInvitation::Invited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotAcknowledgement(unsigned int id, bool ack)
|
||||||
|
{
|
||||||
|
if ( !m_messagesSent.contains( id ) )
|
||||||
|
{
|
||||||
|
// This is maybe a ACK/NAK for a non-messaging message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !ack )
|
||||||
|
{
|
||||||
|
Kopete::Message m = m_messagesSent[ id ];
|
||||||
|
TQString body = i18n( "The following message has not been sent correctly:\n%1" ).arg( m.plainBody() );
|
||||||
|
Kopete::Message msg = Kopete::Message( m.to().first(), members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
|
||||||
|
appendMessage( msg );
|
||||||
|
//stop the stupid animation
|
||||||
|
messageSucceeded();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageSucceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_messagesSent.remove( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotInvitation(const TQString &handle, const TQString &msg)
|
||||||
|
{
|
||||||
|
//FIXME! a contact from another account can send a file
|
||||||
|
MSNContact *c = static_cast<MSNContact*>( myself()->account()->contacts()[ handle ] );
|
||||||
|
if(!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQRegExp rx("Invitation-Cookie: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
long unsigned int cookie=rx.cap(1).toUInt();
|
||||||
|
|
||||||
|
if(m_invitations.contains(cookie))
|
||||||
|
{
|
||||||
|
MSNInvitation *msnI=m_invitations[cookie];
|
||||||
|
msnI->parseInvitation(msg);
|
||||||
|
}
|
||||||
|
else if( msg.contains("Invitation-Command: INVITE") )
|
||||||
|
{
|
||||||
|
if( msg.contains(MSNFileTransferSocket::applicationID()) )
|
||||||
|
{
|
||||||
|
MSNFileTransferSocket *MFTS=new MSNFileTransferSocket(myself()->account()->accountId(),c,true,this);
|
||||||
|
connect(MFTS, TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
|
||||||
|
m_invitations.insert( cookie , MFTS);
|
||||||
|
MFTS->parseInvitation(msg);
|
||||||
|
setCanBeDeleted(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MSNInvitation *i=0l;
|
||||||
|
emit invitation( i , msg, cookie, this, c );
|
||||||
|
if(i)
|
||||||
|
{
|
||||||
|
m_invitations.insert( cookie , i );
|
||||||
|
//don't delete this if all invitation are not done
|
||||||
|
setCanBeDeleted(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx=TQRegExp("Application-Name: ([^\\r\\n]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString inviteName = rx.cap( 1 );
|
||||||
|
|
||||||
|
TQString body = i18n(
|
||||||
|
"%1 has sent an unimplemented invitation, the invitation was rejected.\n"
|
||||||
|
"The invitation was: %2" )
|
||||||
|
.arg( c->property( Kopete::Global::Properties::self()->nickName()).value().toString(), inviteName );
|
||||||
|
Kopete::Message tmpMsg = Kopete::Message( c , members() , body , Kopete::Message::Internal, Kopete::Message::PlainText);
|
||||||
|
appendMessage(tmpMsg);
|
||||||
|
|
||||||
|
m_chatService->sendCommand( "MSG" , "N", true, MSNInvitation::unimplemented(cookie) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::invitationDone(MSNInvitation* MFTS)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo <<endl;
|
||||||
|
m_invitations.remove(MFTS->cookie());
|
||||||
|
// MFTS->deleteLater();
|
||||||
|
delete MFTS;
|
||||||
|
if(!m_chatService && m_invitations.isEmpty())
|
||||||
|
setCanBeDeleted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::sendFile(const TQString &fileLocation, const TQString &/*fileName*/,
|
||||||
|
long unsigned int fileSize)
|
||||||
|
{
|
||||||
|
// TODO create a switchboard to send the file is one is not available.
|
||||||
|
if(m_chatService && members().getFirst())
|
||||||
|
{
|
||||||
|
m_chatService->PeerDispatcher()->sendFile(fileLocation, (TQ_INT64)fileSize, members().getFirst()->contactId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::initInvitation(MSNInvitation* invitation)
|
||||||
|
{
|
||||||
|
connect(invitation->object(), TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
|
||||||
|
m_invitations.insert( invitation->cookie() , invitation);
|
||||||
|
|
||||||
|
if(m_chatService)
|
||||||
|
{
|
||||||
|
m_chatService->sendCommand( "MSG" , "N", true, invitation->invitationHead().utf8() );
|
||||||
|
invitation->setState(MSNInvitation::Invited);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startChatSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotRequestPicture()
|
||||||
|
{
|
||||||
|
TQPtrList<Kopete::Contact> mb=members();
|
||||||
|
MSNContact *c = static_cast<MSNContact*>( mb.first() );
|
||||||
|
if(!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
|
||||||
|
{
|
||||||
|
if(m_chatService)
|
||||||
|
{
|
||||||
|
if( !c->object().isEmpty() )
|
||||||
|
m_chatService->requestDisplayPicture();
|
||||||
|
}
|
||||||
|
else if(myself()->onlineStatus().isDefinitelyOnline() && myself()->onlineStatus().status() != Kopete::OnlineStatus::Invisible )
|
||||||
|
startChatSession();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //we already have the picture, just show it.
|
||||||
|
KRun::runURL( KURL::fromPathOrURL( c->property(Kopete::Global::Properties::self()->photo()).value().toString() ), "image/png" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotDisplayPictureChanged()
|
||||||
|
{
|
||||||
|
TQPtrList<Kopete::Contact> mb=members();
|
||||||
|
MSNContact *c = static_cast<MSNContact *>( mb.first() );
|
||||||
|
if ( c && m_image )
|
||||||
|
{
|
||||||
|
if(c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
|
||||||
|
{
|
||||||
|
int sz=22;
|
||||||
|
// get the size of the toolbar were the aciton is plugged.
|
||||||
|
// if you know a better way to get the toolbar, let me know
|
||||||
|
TDEMainWindow *w= view(false) ? dynamic_cast<TDEMainWindow*>( view(false)->mainWidget()->topLevelWidget() ) : 0L;
|
||||||
|
if(w)
|
||||||
|
{
|
||||||
|
//We connected that in the constructor. we don't need to keep this slot active.
|
||||||
|
disconnect( Kopete::ChatSessionManager::self() , TQT_SIGNAL(viewActivated(KopeteView* )) , this, TQT_SLOT(slotDisplayPictureChanged()) );
|
||||||
|
|
||||||
|
TQPtrListIterator<TDEToolBar> it=w->toolBarIterator() ;
|
||||||
|
TDEAction *imgAction=actionCollection()->action("msnDisplayPicture");
|
||||||
|
if(imgAction) while(it)
|
||||||
|
{
|
||||||
|
TDEToolBar *tb=*it;
|
||||||
|
if(imgAction->isPlugged(tb))
|
||||||
|
{
|
||||||
|
sz=tb->iconSize();
|
||||||
|
//ipdate if the size of the toolbar change.
|
||||||
|
disconnect(tb, TQT_SIGNAL(modechange()), this, TQT_SLOT(slotDisplayPictureChanged()));
|
||||||
|
connect(tb, TQT_SIGNAL(modechange()), this, TQT_SLOT(slotDisplayPictureChanged()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TQString imgURL=c->property(Kopete::Global::Properties::self()->photo()).value().toString();
|
||||||
|
TQImage scaledImg = TQPixmap( imgURL ).convertToImage().smoothScale( sz, sz );
|
||||||
|
if(!scaledImg.isNull())
|
||||||
|
m_image->setPixmap( scaledImg );
|
||||||
|
else
|
||||||
|
{ //the image has maybe not been transfered correctly.. force to download again
|
||||||
|
c->removeProperty(Kopete::Global::Properties::self()->photo());
|
||||||
|
//slotDisplayPictureChanged(); //don't do that or we might end in a infinite loop
|
||||||
|
}
|
||||||
|
TQToolTip::add( m_image, "<qt><img src=\"" + imgURL + "\"></qt>" );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
if ( config->readNumEntry( "DownloadPicture", 1 ) >= 1 && !c->object().isEmpty() )
|
||||||
|
slotRequestPicture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotDebugRawCommand()
|
||||||
|
{
|
||||||
|
#if !defined NDEBUG
|
||||||
|
if ( !m_chatService )
|
||||||
|
return;
|
||||||
|
|
||||||
|
MSNDebugRawCmdDlg *dlg = new MSNDebugRawCmdDlg( 0L );
|
||||||
|
int result = dlg->exec();
|
||||||
|
if( result == TQDialog::Accepted && m_chatService )
|
||||||
|
{
|
||||||
|
m_chatService->sendCommand( dlg->command(), dlg->params(),
|
||||||
|
dlg->addId(), dlg->msg().replace("\n","\r\n").utf8() );
|
||||||
|
}
|
||||||
|
delete dlg;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::receivedTypingMsg( const TQString &contactId, bool b )
|
||||||
|
{
|
||||||
|
MSNContact *c = dynamic_cast<MSNContact *>( account()->contacts()[ contactId ] );
|
||||||
|
if(c && m_newSession && !view(false))
|
||||||
|
{
|
||||||
|
//this was originaly in MSNAccount::slotCreateChat
|
||||||
|
TDEGlobal::config()->setGroup( "MSN" );
|
||||||
|
bool notifyNewChat = TDEGlobal::config()->readBoolEntry( "NotifyNewChat", false );
|
||||||
|
if ( notifyNewChat )
|
||||||
|
{
|
||||||
|
// this internal message should open the window if they not exist
|
||||||
|
TQString body = i18n( "%1 has started a chat with you" ).arg( c->metaContact()->displayName() );
|
||||||
|
Kopete::Message tmpMsg = Kopete::Message( c, members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
|
||||||
|
appendMessage( tmpMsg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_newSession=false;
|
||||||
|
if(c)
|
||||||
|
Kopete::ChatSession::receivedTypingMsg(c,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotSendNudge()
|
||||||
|
{
|
||||||
|
if(m_chatService)
|
||||||
|
{
|
||||||
|
m_chatService->sendNudge();
|
||||||
|
Kopete::Message msg = Kopete::Message( myself(), members() , i18n ( "has sent a nudge" ), Kopete::Message::Outbound,
|
||||||
|
Kopete::Message::PlainText, TQString(), Kopete::Message::TypeAction );
|
||||||
|
appendMessage( msg );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::slotNudgeReceived(const TQString& handle)
|
||||||
|
{
|
||||||
|
Kopete::Contact *c = account()->contacts()[ handle ] ;
|
||||||
|
if(!c)
|
||||||
|
c=members().getFirst();
|
||||||
|
Kopete::Message msg = Kopete::Message(c, myself(), i18n ( "has sent you a nudge" ), Kopete::Message::Inbound,
|
||||||
|
Kopete::Message::PlainText, TQString(), Kopete::Message::TypeAction );
|
||||||
|
appendMessage( msg );
|
||||||
|
// Emit the nudge/buzz notification (configured by user).
|
||||||
|
emitNudgeNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::slotWebcamReceive()
|
||||||
|
{
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
if(m_chatService && members().getFirst())
|
||||||
|
{
|
||||||
|
m_chatService->PeerDispatcher()->startWebcam(myself()->contactId() , members().getFirst()->contactId() , true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotWebcamSend()
|
||||||
|
{
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
if(m_chatService && members().getFirst())
|
||||||
|
{
|
||||||
|
m_chatService->PeerDispatcher()->startWebcam(myself()->contactId() , members().getFirst()->contactId() , false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::slotSendFile()
|
||||||
|
{
|
||||||
|
TQPtrList<Kopete::Contact>contacts = members();
|
||||||
|
static_cast<MSNContact *>(contacts.first())->sendFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::startChatSession()
|
||||||
|
{
|
||||||
|
TQPtrList<Kopete::Contact> mb=members();
|
||||||
|
static_cast<MSNAccount*>( account() )->slotStartChatSession( mb.first()->contactId() );
|
||||||
|
|
||||||
|
if(!m_timeoutTimer)
|
||||||
|
{
|
||||||
|
m_timeoutTimer=new TQTimer(this);
|
||||||
|
connect( m_timeoutTimer , TQT_SIGNAL(timeout()), this , TQT_SLOT(slotConnectionTimeout() ) );
|
||||||
|
}
|
||||||
|
m_timeoutTimer->start(20000, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNChatSession::cleanMessageQueue( const TQString & reason )
|
||||||
|
{
|
||||||
|
delete m_timeoutTimer;
|
||||||
|
m_timeoutTimer=0L;
|
||||||
|
|
||||||
|
uint nb=m_messagesQueue.count()+m_messagesSent.count();
|
||||||
|
if(nb==0)
|
||||||
|
return;
|
||||||
|
else if(nb==1)
|
||||||
|
{
|
||||||
|
Kopete::Message m;
|
||||||
|
if(m_messagesQueue.count() == 1)
|
||||||
|
m=m_messagesQueue.first();
|
||||||
|
else
|
||||||
|
m=m_messagesSent.begin().data();
|
||||||
|
|
||||||
|
TQString body=i18n("The following message has not been sent correctly (%1): \n%2").arg(reason, m.plainBody());
|
||||||
|
Kopete::Message msg = Kopete::Message(m.to().first() , members() , body , Kopete::Message::Internal, Kopete::Message::PlainText);
|
||||||
|
appendMessage(msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Kopete::Message m;
|
||||||
|
TQString body=i18n("These messages have not been sent correctly (%1): <br /><ul>").arg(reason);
|
||||||
|
for ( TQMap<unsigned int , Kopete::Message>::iterator it = m_messagesSent.begin(); it!=m_messagesSent.end(); it = m_messagesSent.begin() )
|
||||||
|
{
|
||||||
|
m=it.data();
|
||||||
|
body+= "<li>"+m.escapedBody()+"</li>";
|
||||||
|
m_messagesSent.remove(it);
|
||||||
|
}
|
||||||
|
for ( TQValueList<Kopete::Message>::iterator it = m_messagesQueue.begin(); it!=m_messagesQueue.end(); it = m_messagesQueue.begin() )
|
||||||
|
{
|
||||||
|
m=(*it);
|
||||||
|
body+= "<li>"+m.escapedBody()+"</li>";
|
||||||
|
m_messagesQueue.remove(it);
|
||||||
|
}
|
||||||
|
body+="</ul>";
|
||||||
|
Kopete::Message msg = Kopete::Message(m.to().first() , members() , body , Kopete::Message::Internal, Kopete::Message::RichText);
|
||||||
|
appendMessage(msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
m_messagesQueue.clear();
|
||||||
|
m_messagesSent.clear();
|
||||||
|
messageSucceeded(); //stop stupid animation
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNChatSession::slotConnectionTimeout()
|
||||||
|
{
|
||||||
|
m_connectionTry++;
|
||||||
|
if(m_chatService)
|
||||||
|
{
|
||||||
|
disconnect(m_chatService , 0 , this , 0 );
|
||||||
|
m_chatService->deleteLater();
|
||||||
|
m_chatService=0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_connectionTry > 3 )
|
||||||
|
{
|
||||||
|
cleanMessageQueue( i18n("Impossible to establish the connection") );
|
||||||
|
delete m_timeoutTimer;
|
||||||
|
m_timeoutTimer=0L;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startChatSession();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "msnchatsession.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
msnchatsession.h - MSN Message Manager
|
||||||
|
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 MSNMESSAGEMANAGER_H
|
||||||
|
#define MSNMESSAGEMANAGER_H
|
||||||
|
|
||||||
|
#include "kopetechatsession.h"
|
||||||
|
|
||||||
|
class MSNSwitchBoardSocket;
|
||||||
|
class TDEActionCollection;
|
||||||
|
class MSNInvitation;
|
||||||
|
class MSNContact;
|
||||||
|
class TDEActionMenu;
|
||||||
|
class TQLabel;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Goffart
|
||||||
|
*/
|
||||||
|
class KOPETE_EXPORT MSNChatSession : public Kopete::ChatSession
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNChatSession( Kopete::Protocol *protocol, const Kopete::Contact *user, Kopete::ContactPtrList others, const char *name = 0 );
|
||||||
|
~MSNChatSession();
|
||||||
|
|
||||||
|
void createChat( const TQString &handle, const TQString &address, const TQString &auth, const TQString &ID = TQString() );
|
||||||
|
|
||||||
|
MSNSwitchBoardSocket *service() { return m_chatService; };
|
||||||
|
|
||||||
|
void sendFile( const TQString &fileLocation, const TQString &fileName,
|
||||||
|
long unsigned int fileSize );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* append an invitation in the invitation map, and send the first invitation message
|
||||||
|
*/
|
||||||
|
void initInvitation(MSNInvitation* invitation);
|
||||||
|
|
||||||
|
virtual void inviteContact(const TQString& );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotCloseSession();
|
||||||
|
void slotInviteOtherContact();
|
||||||
|
|
||||||
|
void invitationDone( MSNInvitation* );
|
||||||
|
|
||||||
|
void slotRequestPicture();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is a reimplementation of ChatSesstion slot.
|
||||||
|
* the original slot is not virtual, but that's not a problem because it's a slot.
|
||||||
|
*/
|
||||||
|
virtual void receivedTypingMsg( const TQString &, bool );
|
||||||
|
|
||||||
|
void slotConnectionTimeout();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotMessageSent( Kopete::Message &message, Kopete::ChatSession *kmm );
|
||||||
|
void slotMessageReceived( Kopete::Message &message );
|
||||||
|
|
||||||
|
void slotUserJoined( const TQString &handle, const TQString &publicName, bool IRO );
|
||||||
|
void slotUserLeft( const TQString &handle, const TQString &reason );
|
||||||
|
void slotSwitchBoardClosed();
|
||||||
|
void slotInviteContact( Kopete::Contact *contact );
|
||||||
|
void slotAcknowledgement( unsigned int id, bool ack );
|
||||||
|
void slotInvitation( const TQString &handle, const TQString &msg );
|
||||||
|
|
||||||
|
void slotActionInviteAboutToShow();
|
||||||
|
|
||||||
|
void slotDisplayPictureChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (debug)
|
||||||
|
*/
|
||||||
|
void slotDebugRawCommand();
|
||||||
|
|
||||||
|
void slotSendNudge();
|
||||||
|
void slotWebcamReceive();
|
||||||
|
void slotWebcamSend();
|
||||||
|
void slotSendFile();
|
||||||
|
|
||||||
|
void slotNudgeReceived(const TQString& handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MSNSwitchBoardSocket *m_chatService;
|
||||||
|
TQString otherString;
|
||||||
|
TDEActionMenu *m_actionInvite;
|
||||||
|
TQPtrList<TDEAction> m_inviteactions;
|
||||||
|
TDEAction *m_actionNudge;
|
||||||
|
TDEAction *m_actionWebcamReceive;
|
||||||
|
TDEAction *m_actionWebcamSend;
|
||||||
|
|
||||||
|
//Messages sent before the ending of the connection are queued
|
||||||
|
TQValueList<Kopete::Message> m_messagesQueue;
|
||||||
|
void sendMessageQueue();
|
||||||
|
void cleanMessageQueue( const TQString &reason);
|
||||||
|
void startChatSession();
|
||||||
|
|
||||||
|
TQMap<unsigned int, Kopete::Message> m_messagesSent;
|
||||||
|
|
||||||
|
TQMap<long unsigned int, MSNInvitation*> m_invitations;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* weither or not the "has opened a new chat" message need to be sent if the user is typing
|
||||||
|
*/
|
||||||
|
bool m_newSession;
|
||||||
|
|
||||||
|
TQLabel *m_image;
|
||||||
|
TQTimer *m_timeoutTimer;
|
||||||
|
uint m_connectionTry;
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/*
|
||||||
|
* This signal is relayed to the protocol and after, to plugins
|
||||||
|
*/
|
||||||
|
void invitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int cookie , MSNChatSession* msnMM , MSNContact* c );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 tw=4:
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE kpartgui>
|
||||||
|
<kpartgui version="12" name="kopete_msn_chat">
|
||||||
|
<MenuBar>
|
||||||
|
<Menu noMerge="1" name="file">
|
||||||
|
<text>&Chat</text>
|
||||||
|
<Action name="msnWebcamReceive" />
|
||||||
|
<Action name="msnWebcamSend" />
|
||||||
|
<Action name="msnSendFile" />
|
||||||
|
<Action name="msnSendNudge" />
|
||||||
|
<Action name="msnRequestDisplayPicture" />
|
||||||
|
<Action name="msnInvite" />
|
||||||
|
<!-- <Menu name="debug">
|
||||||
|
<text>&Debug</text>
|
||||||
|
<Action name="msnDebugRawCommand" />
|
||||||
|
</Menu> -->
|
||||||
|
</Menu>
|
||||||
|
</MenuBar>
|
||||||
|
|
||||||
|
|
||||||
|
<ToolBar name="statusToolBar">
|
||||||
|
<Action name="msnDisplayPicture" />
|
||||||
|
<Action name="msnWebcamReceive" />
|
||||||
|
<Action name="msnWebcamSend" />
|
||||||
|
<Action name="msnSendFile" />
|
||||||
|
<Action name="msnSendNudge" />
|
||||||
|
</ToolBar>
|
||||||
|
</kpartgui>
|
@ -0,0 +1,713 @@
|
|||||||
|
/*
|
||||||
|
msncontact.cpp - MSN Contact
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
||||||
|
Copyright (c) 2002 by Ryan Cumming <bodnar42@phalynx.dhs.org>
|
||||||
|
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart at kde.org>
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 "msncontact.h"
|
||||||
|
|
||||||
|
#include <tqcheckbox.h>
|
||||||
|
|
||||||
|
#undef KDE_NO_COMPAT
|
||||||
|
#include <tdeaction.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdefiledialog.h>
|
||||||
|
#include <klineedit.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <kstandarddirs.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
#include <krun.h>
|
||||||
|
#include <tdetempfile.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <tdeglobal.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <tdeio/job.h>
|
||||||
|
|
||||||
|
#include "kopetecontactlist.h"
|
||||||
|
#include "kopetechatsessionmanager.h"
|
||||||
|
#include "kopetemetacontact.h"
|
||||||
|
#include "kopetegroup.h"
|
||||||
|
#include "kopeteuiglobal.h"
|
||||||
|
#include "kopeteglobal.h"
|
||||||
|
|
||||||
|
#include "msninfo.h"
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
#include "msnnotifysocket.h"
|
||||||
|
#include "msnaccount.h"
|
||||||
|
|
||||||
|
MSNContact::MSNContact( Kopete::Account *account, const TQString &id, Kopete::MetaContact *parent )
|
||||||
|
: Kopete::Contact( account, id, parent )
|
||||||
|
{
|
||||||
|
m_deleted = false;
|
||||||
|
m_allowed = false;
|
||||||
|
m_blocked = false;
|
||||||
|
m_reversed = false;
|
||||||
|
m_moving = false;
|
||||||
|
|
||||||
|
m_clientFlags=0;
|
||||||
|
|
||||||
|
setFileCapable( true );
|
||||||
|
|
||||||
|
// When we are not connected, it's because we are loading the contactlist.
|
||||||
|
// so we set the initial status to offline.
|
||||||
|
// We set offline directly because modifying the status after is too slow.
|
||||||
|
// (notification, contactlist updating,....)
|
||||||
|
//
|
||||||
|
// FIXME: Hacks like these shouldn't happen in the protocols, but should be
|
||||||
|
// covered properly at the libkopete level instead - Martijn
|
||||||
|
//
|
||||||
|
// When we are connected, it can be because the user added a contact with the
|
||||||
|
// wizard, and it can be because we are creating a temporary contact.
|
||||||
|
// if it's added by the wizard, the status will be set immediately after.
|
||||||
|
// if it's a temporary contact, better to set the unknown status.
|
||||||
|
setOnlineStatus( ( parent && parent->isTemporary() ) ? MSNProtocol::protocol()->UNK : MSNProtocol::protocol()->FLN );
|
||||||
|
|
||||||
|
actionBlock = 0L;
|
||||||
|
|
||||||
|
setProperty(MSNProtocol::protocol()->propEmail, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNContact::~MSNContact()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNContact::isReachable()
|
||||||
|
{
|
||||||
|
if ( account()->isConnected() && isOnline() && account()->myself()->onlineStatus() != MSNProtocol::protocol()->HDN )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
MSNChatSession *kmm=dynamic_cast<MSNChatSession*>(manager(Kopete::Contact::CannotCreate));
|
||||||
|
if( kmm && kmm->service() ) //the chat socket is open. than mean message will be sent
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// When we are invisible we can't start a chat with others, make isReachable return false
|
||||||
|
// (This is an MSN limitation, not a problem in Kopete)
|
||||||
|
if ( !account()->isConnected() || account()->myself()->onlineStatus() == MSNProtocol::protocol()->HDN )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//if the contact is offline, it is impossible to send it a message. but it is impossible
|
||||||
|
//to be sure the contact is realy offline. For example, if the contact is not on the contactlist for
|
||||||
|
//some reason.
|
||||||
|
if( onlineStatus() == MSNProtocol::protocol()->FLN && ( isAllowed() || isBlocked() ) && !serverGroups().isEmpty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::ChatSession *MSNContact::manager( Kopete::Contact::CanCreateFlags canCreate )
|
||||||
|
{
|
||||||
|
Kopete::ContactPtrList chatmembers;
|
||||||
|
chatmembers.append(this);
|
||||||
|
|
||||||
|
Kopete::ChatSession *_manager = Kopete::ChatSessionManager::self()->findChatSession( account()->myself(), chatmembers, protocol() );
|
||||||
|
MSNChatSession *manager = dynamic_cast<MSNChatSession*>( _manager );
|
||||||
|
if(!manager && canCreate==Kopete::Contact::CanCreate)
|
||||||
|
{
|
||||||
|
manager = new MSNChatSession( protocol(), account()->myself(), chatmembers );
|
||||||
|
static_cast<MSNAccount*>( account() )->slotStartChatSession( contactId() );
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQPtrList<TDEAction> *MSNContact::customContextMenuActions()
|
||||||
|
{
|
||||||
|
TQPtrList<TDEAction> *m_actionCollection = new TQPtrList<TDEAction>;
|
||||||
|
|
||||||
|
// Block/unblock Contact
|
||||||
|
TQString label = isBlocked() ? i18n( "Unblock User" ) : i18n( "Block User" );
|
||||||
|
if( !actionBlock )
|
||||||
|
{
|
||||||
|
actionBlock = new TDEAction( label, "msn_blocked",0, this, TQT_SLOT( slotBlockUser() ),
|
||||||
|
this, "actionBlock" );
|
||||||
|
|
||||||
|
//show profile
|
||||||
|
actionShowProfile = new TDEAction( i18n("Show Profile") , 0, this, TQT_SLOT( slotShowProfile() ),
|
||||||
|
this, "actionShowProfile" );
|
||||||
|
|
||||||
|
// Send mail (only available if it is an hotmail account)
|
||||||
|
actionSendMail = new TDEAction( i18n("Send Email...") , "mail_generic",0, this, TQT_SLOT( slotSendMail() ),
|
||||||
|
this, "actionSendMail" );
|
||||||
|
|
||||||
|
// Invite to receive webcam
|
||||||
|
actionWebcamReceive = new TDEAction( i18n( "View Contact's Webcam" ), "webcamreceive", 0, this, TQT_SLOT(slotWebcamReceive() ), this, "msnWebcamReceive" ) ;
|
||||||
|
|
||||||
|
//Send webcam action
|
||||||
|
actionWebcamSend = new TDEAction( i18n( "Send Webcam" ), "webcamsend", 0, this, TQT_SLOT(slotWebcamSend() ), this, "msnWebcamSend" ) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actionBlock->setText( label );
|
||||||
|
|
||||||
|
actionSendMail->setEnabled( static_cast<MSNAccount*>(account())->isHotmail());
|
||||||
|
|
||||||
|
m_actionCollection->append( actionBlock );
|
||||||
|
m_actionCollection->append( actionShowProfile );
|
||||||
|
m_actionCollection->append( actionSendMail );
|
||||||
|
m_actionCollection->append( actionWebcamReceive );
|
||||||
|
m_actionCollection->append( actionWebcamSend );
|
||||||
|
|
||||||
|
|
||||||
|
return m_actionCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotBlockUser()
|
||||||
|
{
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
|
||||||
|
if( !notify )
|
||||||
|
{
|
||||||
|
KMessageBox::error( Kopete::UI::Global::mainWidget(),
|
||||||
|
i18n( "<qt>Please go online to block or unblock a contact.</qt>" ),
|
||||||
|
i18n( "MSN Plugin" ));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_blocked )
|
||||||
|
{
|
||||||
|
notify->removeContact( contactId(), MSNProtocol::BL, TQString(), TQString() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(m_allowed)
|
||||||
|
notify->removeContact( contactId(), MSNProtocol::AL, TQString(), TQString() );
|
||||||
|
else
|
||||||
|
notify->addContact( contactId(), MSNProtocol::BL, TQString(), TQString(), TQString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotUserInfo()
|
||||||
|
{
|
||||||
|
KDialogBase *infoDialog=new KDialogBase( 0l, "infoDialog", /*modal = */false, TQString(), KDialogBase::Close , KDialogBase::Close, false );
|
||||||
|
TQString nick=property( Kopete::Global::Properties::self()->nickName()).value().toString();
|
||||||
|
TQString personalMessage=property( MSNProtocol::protocol()->propPersonalMessage).value().toString();
|
||||||
|
MSNInfo *info=new MSNInfo ( infoDialog,"info");
|
||||||
|
info->m_id->setText( contactId() );
|
||||||
|
info->m_displayName->setText(nick);
|
||||||
|
info->m_personalMessage->setText(personalMessage);
|
||||||
|
info->m_phh->setText(m_phoneHome);
|
||||||
|
info->m_phw->setText(m_phoneWork);
|
||||||
|
info->m_phm->setText(m_phoneMobile);
|
||||||
|
info->m_reversed->setChecked(m_reversed);
|
||||||
|
|
||||||
|
connect( info->m_reversed, TQT_SIGNAL(toggled(bool)) , this, TQT_SLOT(slotUserInfoDialogReversedToggled()));
|
||||||
|
|
||||||
|
infoDialog->setMainWidget(info);
|
||||||
|
infoDialog->setCaption(nick);
|
||||||
|
infoDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotUserInfoDialogReversedToggled()
|
||||||
|
{
|
||||||
|
//workaround to make this checkboxe readonly
|
||||||
|
const TQCheckBox *cb=dynamic_cast<const TQCheckBox*>(sender());
|
||||||
|
if(cb && cb->isChecked()!=m_reversed)
|
||||||
|
const_cast<TQCheckBox*>(cb)->setChecked(m_reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::deleteContact()
|
||||||
|
{
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
|
||||||
|
if( notify )
|
||||||
|
{
|
||||||
|
if( hasProperty(MSNProtocol::protocol()->propGuid.key()) )
|
||||||
|
{
|
||||||
|
// Remove from all groups he belongs (if applicable)
|
||||||
|
for( TQMap<TQString, Kopete::Group*>::Iterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it )
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "Removing contact from group \"" << it.key() << "\"" << endl;
|
||||||
|
notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then trully remove it from server contact list,
|
||||||
|
// because only removing the contact from his groups isn't sufficent from MSNP11.
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << "Removing contact from top-level." << endl;
|
||||||
|
notify->removeContact( contactId(), MSNProtocol::FL, guid(), TQString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << "The contact is already removed from server, just delete it" << endl;
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: This case should be handled by Kopete, not by the plugins :( - Martijn
|
||||||
|
// FIXME: We should be able to delete contacts offline, and remove it from server next time we go online - Olivier
|
||||||
|
KMessageBox::error( Kopete::UI::Global::mainWidget(), i18n( "<qt>Please go online to remove a contact from your contact list.</qt>" ), i18n( "MSN Plugin" ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNContact::isBlocked() const
|
||||||
|
{
|
||||||
|
return m_blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setBlocked( bool blocked )
|
||||||
|
{
|
||||||
|
if( m_blocked != blocked )
|
||||||
|
{
|
||||||
|
m_blocked = blocked;
|
||||||
|
//update the status
|
||||||
|
setOnlineStatus(m_currentStatus);
|
||||||
|
//m_currentStatus is used here. previously it was onlineStatus() but this may cause problem when
|
||||||
|
// the account is offline because of the Kopete::Contact::OnlineStatus() account offline hack.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNContact::isAllowed() const
|
||||||
|
{
|
||||||
|
return m_allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setAllowed( bool allowed )
|
||||||
|
{
|
||||||
|
m_allowed = allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNContact::isReversed() const
|
||||||
|
{
|
||||||
|
return m_reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setReversed( bool reversed )
|
||||||
|
{
|
||||||
|
m_reversed= reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNContact::isDeleted() const
|
||||||
|
{
|
||||||
|
return m_deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setDeleted( bool deleted )
|
||||||
|
{
|
||||||
|
m_deleted= deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint MSNContact::clientFlags() const
|
||||||
|
{
|
||||||
|
return m_clientFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setClientFlags( uint flags )
|
||||||
|
{
|
||||||
|
if(m_clientFlags != flags)
|
||||||
|
{
|
||||||
|
if(hasProperty( MSNProtocol::protocol()->propClient.key() ))
|
||||||
|
{
|
||||||
|
if( flags & MSNProtocol::WebMessenger)
|
||||||
|
setProperty( MSNProtocol::protocol()->propClient , i18n("Web Messenger") );
|
||||||
|
else if( flags & MSNProtocol::WindowsMobile)
|
||||||
|
setProperty( MSNProtocol::protocol()->propClient , i18n("Windows Mobile") );
|
||||||
|
else if( flags & MSNProtocol::MSNMobileDevice)
|
||||||
|
setProperty( MSNProtocol::protocol()->propClient , i18n("MSN Mobile") );
|
||||||
|
else if( m_obj.contains("kopete") )
|
||||||
|
setProperty( MSNProtocol::protocol()->propClient , i18n("Kopete") );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
m_clientFlags=flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setInfo(const TQString &type,const TQString &data )
|
||||||
|
{
|
||||||
|
if( type == "PHH" )
|
||||||
|
{
|
||||||
|
m_phoneHome = data;
|
||||||
|
setProperty(MSNProtocol::protocol()->propPhoneHome, data);
|
||||||
|
}
|
||||||
|
else if( type == "PHW" )
|
||||||
|
{
|
||||||
|
m_phoneWork=data;
|
||||||
|
setProperty(MSNProtocol::protocol()->propPhoneWork, data);
|
||||||
|
}
|
||||||
|
else if( type == "PHM" )
|
||||||
|
{
|
||||||
|
m_phoneMobile = data;
|
||||||
|
setProperty(MSNProtocol::protocol()->propPhoneMobile, data);
|
||||||
|
}
|
||||||
|
else if( type == "MOB" )
|
||||||
|
{
|
||||||
|
if( data == "Y" )
|
||||||
|
m_phone_mob = true;
|
||||||
|
else if( data == "N" )
|
||||||
|
m_phone_mob = false;
|
||||||
|
else
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << "Unknown MOB " << data << endl;
|
||||||
|
}
|
||||||
|
else if( type == "MFN" )
|
||||||
|
{
|
||||||
|
setProperty(Kopete::Global::Properties::self()->nickName(), data );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << "Unknow info " << type << " " << data << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNContact::serialize( TQMap<TQString, TQString> &serializedData, TQMap<TQString, TQString> & /* addressBookData */ )
|
||||||
|
{
|
||||||
|
// Contact id and display name are already set for us, only add the rest
|
||||||
|
TQString groups;
|
||||||
|
bool firstEntry = true;
|
||||||
|
for( TQMap<TQString, Kopete::Group *>::ConstIterator it = m_serverGroups.begin(); it != m_serverGroups.end(); ++it )
|
||||||
|
{
|
||||||
|
if( !firstEntry )
|
||||||
|
{
|
||||||
|
groups += ",";
|
||||||
|
firstEntry = true;
|
||||||
|
}
|
||||||
|
groups += it.key();
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString lists="C";
|
||||||
|
if(m_blocked)
|
||||||
|
lists +="B";
|
||||||
|
if(m_allowed)
|
||||||
|
lists +="A";
|
||||||
|
if(m_reversed)
|
||||||
|
lists +="R";
|
||||||
|
|
||||||
|
serializedData[ "groups" ] = groups;
|
||||||
|
serializedData[ "PHH" ] = m_phoneHome;
|
||||||
|
serializedData[ "PHW" ] = m_phoneWork;
|
||||||
|
serializedData[ "PHM" ] = m_phoneMobile;
|
||||||
|
serializedData[ "lists" ] = lists;
|
||||||
|
serializedData[ "obj" ] = m_obj;
|
||||||
|
serializedData[ "contactGuid" ] = guid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TQString MSNContact::guid(){ return property(MSNProtocol::protocol()->propGuid).value().toString(); }
|
||||||
|
|
||||||
|
TQString MSNContact::phoneHome(){ return m_phoneHome ;}
|
||||||
|
TQString MSNContact::phoneWork(){ return m_phoneWork ;}
|
||||||
|
TQString MSNContact::phoneMobile(){ return m_phoneMobile ;}
|
||||||
|
|
||||||
|
|
||||||
|
const TQMap<TQString, Kopete::Group*> MSNContact::serverGroups() const
|
||||||
|
{
|
||||||
|
return m_serverGroups;
|
||||||
|
}
|
||||||
|
void MSNContact::clearServerGroups()
|
||||||
|
{
|
||||||
|
m_serverGroups.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNContact::sync( unsigned int changed )
|
||||||
|
{
|
||||||
|
if( ! (changed & Kopete::Contact::MovedBetweenGroup) )
|
||||||
|
return; //we are only interested by a change in groups
|
||||||
|
|
||||||
|
if(!metaContact() || metaContact()->isTemporary() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(m_moving)
|
||||||
|
{
|
||||||
|
//We need to make sure that syncGroups is not called twice successively
|
||||||
|
// because m_serverGroups will be only updated with the reply of the server
|
||||||
|
// and then, the same command can be sent twice.
|
||||||
|
// FIXME: if this method is called a seconds times, that mean change can be
|
||||||
|
// done in the contactlist. we should found a way to recall this
|
||||||
|
// method later. (a TQTimer?)
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << " This contact is already moving. Abort sync id: " << contactId() << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
|
||||||
|
if( !notify )
|
||||||
|
{
|
||||||
|
//We are not connected, we will doing it next connection.
|
||||||
|
//Force to reload the whole contactlist from server to suync groups when connecting
|
||||||
|
account()->configGroup()->writeEntry("serial", 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_deleted) //the contact hasn't been synced from server yet.
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned int count=m_serverGroups.count();
|
||||||
|
|
||||||
|
//Don't add the contact if it's myself.
|
||||||
|
if(count==0 && contactId() == account()->accountId())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//STEP ONE : add the contact to every kopetegroups where the MC is
|
||||||
|
TQPtrList<Kopete::Group> groupList = metaContact()->groups();
|
||||||
|
for ( Kopete::Group *group = groupList.first(); group; group = groupList.next() )
|
||||||
|
{
|
||||||
|
//For each group, ensure it is on the MSN server
|
||||||
|
if( !group->pluginData( protocol() , account()->accountId() + " id" ).isEmpty() )
|
||||||
|
{
|
||||||
|
TQString Gid=group->pluginData( protocol(), account()->accountId() + " id" );
|
||||||
|
if( !static_cast<MSNAccount*>( account() )->m_groupList.contains(Gid) )
|
||||||
|
{ // ohoh! something is corrupted on the contactlist.xml
|
||||||
|
// anyway, we never should add a contact to an unexisting group on the server.
|
||||||
|
// This shouln't be possible anymore 2004-06-10 -Olivier
|
||||||
|
|
||||||
|
//repair the problem
|
||||||
|
group->setPluginData( protocol() , account()->accountId() + " id" , TQString());
|
||||||
|
group->setPluginData( protocol() , account()->accountId() + " displayName" , TQString());
|
||||||
|
kdWarning( 14140 ) << k_funcinfo << " Group " << group->displayName() << " marked with id #" <<Gid << " does not seems to be anymore on the server" << endl;
|
||||||
|
|
||||||
|
if(!group->displayName().isEmpty() && group->type() == Kopete::Group::Normal) //not the top-level
|
||||||
|
{
|
||||||
|
//Create the group and add the contact
|
||||||
|
static_cast<MSNAccount*>( account() )->addGroup( group->displayName(),contactId() );
|
||||||
|
count++;
|
||||||
|
m_moving=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( !m_serverGroups.contains(Gid) )
|
||||||
|
{
|
||||||
|
//Add the contact to the group on the server
|
||||||
|
notify->addContact( contactId(), MSNProtocol::FL, TQString(), guid(), Gid );
|
||||||
|
count++;
|
||||||
|
m_moving=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!group->displayName().isEmpty() && group->type() == Kopete::Group::Normal) //not the top-level
|
||||||
|
{
|
||||||
|
//Create the group and add the contact
|
||||||
|
static_cast<MSNAccount*>( account() )->addGroup( group->displayName(),contactId() );
|
||||||
|
|
||||||
|
//WARNING: if contact is not correctly added (because the group was not aded corrdctly for hinstance),
|
||||||
|
// if we increment the count, the contact can be deleted from the old group, and be lost :-(
|
||||||
|
count++;
|
||||||
|
m_moving=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//STEP TWO : remove the contact from groups where the MC is not, but let it at least in one group
|
||||||
|
|
||||||
|
//contact is not in that group. on the server. we will remove them dirrectly after the loop
|
||||||
|
TQValueList<TQString> removinglist;
|
||||||
|
|
||||||
|
for( TQMap<TQString, Kopete::Group*>::Iterator it = m_serverGroups.begin();(count > 1 && it != m_serverGroups.end()); ++it )
|
||||||
|
{
|
||||||
|
if( !static_cast<MSNAccount*>( account() )->m_groupList.contains(it.key()) )
|
||||||
|
{ // ohoh! something is corrupted on the contactlist.xml
|
||||||
|
// anyway, we never should add a contact to an unexisting group on the server.
|
||||||
|
|
||||||
|
//repair the problem ... //contactRemovedFromGroup( it.key() );
|
||||||
|
// ... later (we can't remove it from the map now )
|
||||||
|
removinglist.append(it.key());
|
||||||
|
count--;
|
||||||
|
|
||||||
|
kdDebug( 14140 ) << k_funcinfo << "the group marked with id #" << it.key() << " does not seems to be anymore on the server" << endl;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::Group *group=it.data();
|
||||||
|
if(!group) //we can't trust the data of it() see in MSNProtocol::deserializeContact why
|
||||||
|
group=static_cast<MSNAccount*>( account() )->m_groupList[it.key()];
|
||||||
|
if( !metaContact()->groups().contains(group) )
|
||||||
|
{
|
||||||
|
m_moving=true;
|
||||||
|
notify->removeContact( contactId(), MSNProtocol::FL, guid(), it.key() );
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(TQValueList<TQString>::Iterator it= removinglist.begin() ; it != removinglist.end() ; ++it )
|
||||||
|
contactRemovedFromGroup(*it);
|
||||||
|
|
||||||
|
//FINAL TEST: is the contact at least in a group..
|
||||||
|
// this may happens if we just added a temporary contact to top-level
|
||||||
|
// we add the contact to the group #0 (the default one)
|
||||||
|
/*if(count==0)
|
||||||
|
{
|
||||||
|
// notify->addContact( contactId(), MSNProtocol::FL, TQString(), guid(), "0");
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::contactAddedToGroup( const TQString& groupId, Kopete::Group *group )
|
||||||
|
{
|
||||||
|
m_serverGroups.insert( groupId, group );
|
||||||
|
m_moving=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::contactRemovedFromGroup( const TQString& groupId )
|
||||||
|
{
|
||||||
|
m_serverGroups.remove( groupId );
|
||||||
|
if(m_serverGroups.isEmpty() && !m_moving)
|
||||||
|
{
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
m_moving=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNContact::rename( const TQString &newName )
|
||||||
|
{
|
||||||
|
//kdDebug( 14140 ) << k_funcinfo << "From: " << displayName() << ", to: " << newName << endl;
|
||||||
|
|
||||||
|
/* if( newName == displayName() )
|
||||||
|
return;*/
|
||||||
|
|
||||||
|
// FIXME: This should be called anymore.
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
|
||||||
|
if( notify )
|
||||||
|
{
|
||||||
|
notify->changePublicName( newName, contactId() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotShowProfile()
|
||||||
|
{
|
||||||
|
KRun::runURL( KURL( TQString::fromLatin1("http://members.msn.com/?pgmarket=it-it&mem=") + contactId()) , "text/html" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Make this a standard KMM API call
|
||||||
|
*/
|
||||||
|
void MSNContact::sendFile( const KURL &sourceURL, const TQString &altFileName, uint /*fileSize*/ )
|
||||||
|
{
|
||||||
|
TQString filePath;
|
||||||
|
|
||||||
|
//If the file location is null, then get it from a file open dialog
|
||||||
|
if( !sourceURL.isValid() )
|
||||||
|
filePath = KFileDialog::getOpenFileName( TQString() ,"*", 0l , i18n( "Kopete File Transfer" ));
|
||||||
|
else
|
||||||
|
filePath = sourceURL.path(-1);
|
||||||
|
|
||||||
|
//kdDebug(14140) << "MSNContact::sendFile: File chosen to send:" << fileName << endl;
|
||||||
|
|
||||||
|
if ( !filePath.isEmpty() )
|
||||||
|
{
|
||||||
|
TQ_UINT32 fileSize = TQFileInfo(filePath).size();
|
||||||
|
//Send the file
|
||||||
|
static_cast<MSNChatSession*>( manager(Kopete::Contact::CanCreate) )->sendFile( filePath, altFileName, fileSize );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setOnlineStatus(const Kopete::OnlineStatus& status)
|
||||||
|
{
|
||||||
|
if(isBlocked() && status.internalStatus() < 15)
|
||||||
|
{
|
||||||
|
Kopete::Contact::setOnlineStatus(
|
||||||
|
Kopete::OnlineStatus(status.status() ,
|
||||||
|
(status.weight()==0) ? 0 : (status.weight() -1) ,
|
||||||
|
protocol() ,
|
||||||
|
status.internalStatus()+15 ,
|
||||||
|
status.overlayIcons() + TQStringList("msn_blocked") ,
|
||||||
|
i18n("%1|Blocked").arg( status.description() ) ) );
|
||||||
|
}
|
||||||
|
else if(!isBlocked() && status.internalStatus() >= 15)
|
||||||
|
{ //the user is not blocked, but the status is blocked
|
||||||
|
switch(status.internalStatus()-15)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->NLN);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->BSY);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->BRB);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->AWY);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->PHN);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->LUN);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->FLN);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->HDN);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->IDL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Kopete::Contact::setOnlineStatus(MSNProtocol::protocol()->UNK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Kopete::Contact::setOnlineStatus(status);
|
||||||
|
m_currentStatus=status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotSendMail()
|
||||||
|
{
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount*>( account() )->notifySocket();
|
||||||
|
if( notify )
|
||||||
|
{
|
||||||
|
notify->sendMail( contactId() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setDisplayPicture(KTempFile *f)
|
||||||
|
{
|
||||||
|
//copy the temp file somewere else.
|
||||||
|
// in a better world, the file could be dirrectly wrote at the correct location.
|
||||||
|
// but the custom emoticon code is to deeply merged in the display picture code while it could be separated.
|
||||||
|
TQString newlocation=locateLocal( "appdata", "msnpictures/"+ contactId().lower().replace(TQRegExp("[./~]"),"-") +".png" ) ;
|
||||||
|
|
||||||
|
TDEIO::Job *j=TDEIO::file_move( KURL::fromPathOrURL( f->name() ) , KURL::fromPathOrURL( newlocation ) , -1, true /*overwrite*/ , false /*resume*/ , false /*showProgressInfo*/ );
|
||||||
|
|
||||||
|
f->setAutoDelete(false);
|
||||||
|
delete f;
|
||||||
|
|
||||||
|
//let the time to TDEIO to copy the file
|
||||||
|
connect(j, TQT_SIGNAL(result(TDEIO::Job *)) , this, TQT_SLOT(slotEmitDisplayPictureChanged() ));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::slotEmitDisplayPictureChanged()
|
||||||
|
{
|
||||||
|
TQString newlocation=locateLocal( "appdata", "msnpictures/"+ contactId().lower().replace(TQRegExp("[./~]"),"-") +".png" ) ;
|
||||||
|
setProperty( Kopete::Global::Properties::self()->photo() , newlocation );
|
||||||
|
emit displayPictureChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNContact::setObject(const TQString &obj)
|
||||||
|
{
|
||||||
|
if(m_obj==obj && (obj.isEmpty() || hasProperty(Kopete::Global::Properties::self()->photo().key())))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_obj=obj;
|
||||||
|
|
||||||
|
removeProperty( Kopete::Global::Properties::self()->photo() ) ;
|
||||||
|
emit displayPictureChanged();
|
||||||
|
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
if ( config->readNumEntry( "DownloadPicture", 2 ) >= 2 && !obj.isEmpty()
|
||||||
|
&& account()->myself()->onlineStatus().status() != Kopete::OnlineStatus::Invisible )
|
||||||
|
manager(Kopete::Contact::CanCreate); //create the manager which will download the photo automatically.
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msncontact.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
msncontact.h - MSN Contact
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
||||||
|
Copyright (c) 2002 by Ryan Cumming <bodnar42@phalynx.dhs.org>
|
||||||
|
Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart at kde.org>
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 MSNCONTACT_H
|
||||||
|
#define MSNCONTACT_H
|
||||||
|
|
||||||
|
#include "kopetecontact.h"
|
||||||
|
#include "kopeteonlinestatus.h"
|
||||||
|
|
||||||
|
#include <kurl.h>
|
||||||
|
|
||||||
|
class TQListView;
|
||||||
|
class TQListViewItem;
|
||||||
|
class TQPixmap;
|
||||||
|
class TQTimer;
|
||||||
|
|
||||||
|
class MSNChatSession;
|
||||||
|
class TDEAction;
|
||||||
|
class TDEActionCollection;
|
||||||
|
class KTempFile;
|
||||||
|
|
||||||
|
namespace Kopete { class Protocol; }
|
||||||
|
namespace Kopete { class OnlineStatus; }
|
||||||
|
|
||||||
|
class MSNContact : public Kopete::Contact
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNContact( Kopete::Account *account, const TQString &id, Kopete::MetaContact *parent );
|
||||||
|
~MSNContact();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether this contact is blocked
|
||||||
|
*/
|
||||||
|
bool isBlocked() const;
|
||||||
|
void setBlocked( bool b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether this contact is deleted
|
||||||
|
* (not on the serverside list)
|
||||||
|
*/
|
||||||
|
bool isDeleted() const;
|
||||||
|
void setDeleted( bool d );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether this contact is allowed
|
||||||
|
*/
|
||||||
|
bool isAllowed() const;
|
||||||
|
void setAllowed( bool d );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether this contact is on the reversed list
|
||||||
|
*/
|
||||||
|
bool isReversed() const;
|
||||||
|
void setReversed( bool d );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set one phone number
|
||||||
|
*/
|
||||||
|
void setInfo(const TQString &type, const TQString &data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The groups in which the user is located on the server.
|
||||||
|
*/
|
||||||
|
const TQMap<TQString, Kopete::Group *> serverGroups() const;
|
||||||
|
/**
|
||||||
|
* clear that map
|
||||||
|
*/
|
||||||
|
void clearServerGroups();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* client flags (say what version of msn messenger the contact is using)
|
||||||
|
*/
|
||||||
|
uint clientFlags() const;
|
||||||
|
void setClientFlags( uint );
|
||||||
|
|
||||||
|
virtual bool isReachable();
|
||||||
|
|
||||||
|
virtual TQPtrList<TDEAction> *customContextMenuActions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update the server group map
|
||||||
|
*/
|
||||||
|
void contactRemovedFromGroup( const TQString& groupId );
|
||||||
|
void contactAddedToGroup(const TQString& groupId, Kopete::Group *group );
|
||||||
|
|
||||||
|
virtual void serialize( TQMap<TQString, TQString> &serializedData, TQMap<TQString, TQString> &addressBookData );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename contact on server
|
||||||
|
*/
|
||||||
|
virtual void rename( const TQString &newName ) KDE_DEPRECATED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MSN Message Manager associated with this contact
|
||||||
|
*/
|
||||||
|
virtual Kopete::ChatSession *manager( Kopete::Contact::CanCreateFlags = Kopete::Contact::CannotCreate );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because blocked contact have a small auto-modified status
|
||||||
|
*/
|
||||||
|
void setOnlineStatus(const Kopete::OnlineStatus&);
|
||||||
|
|
||||||
|
TQString guid();
|
||||||
|
TQString phoneHome();
|
||||||
|
TQString phoneWork();
|
||||||
|
TQString phoneMobile();
|
||||||
|
|
||||||
|
void setObject(const TQString &obj);
|
||||||
|
TQString object() const { return m_obj; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void slotUserInfo();
|
||||||
|
virtual void deleteContact();
|
||||||
|
virtual void sendFile( const KURL &sourceURL = KURL(),
|
||||||
|
const TQString &fileName = TQString(), uint fileSize = 0L );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every time the kopete's contactlist is modified, we sync the serverlist with it
|
||||||
|
*/
|
||||||
|
virtual void sync( unsigned int cvhanged= 0xff);
|
||||||
|
|
||||||
|
|
||||||
|
void setDisplayPicture(KTempFile *f) ;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void displayPictureChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotBlockUser();
|
||||||
|
void slotShowProfile();
|
||||||
|
void slotSendMail();
|
||||||
|
void slotEmitDisplayPictureChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround to make this checkboxe readonly
|
||||||
|
*/
|
||||||
|
void slotUserInfoDialogReversedToggled();
|
||||||
|
|
||||||
|
private:
|
||||||
|
TQMap<TQString, Kopete::Group *> m_serverGroups;
|
||||||
|
|
||||||
|
bool m_blocked;
|
||||||
|
bool m_allowed;
|
||||||
|
bool m_deleted;
|
||||||
|
bool m_reversed;
|
||||||
|
bool m_moving;
|
||||||
|
bool m_phone_mob;
|
||||||
|
|
||||||
|
uint m_clientFlags;
|
||||||
|
|
||||||
|
TQString m_phoneHome;
|
||||||
|
TQString m_phoneWork;
|
||||||
|
TQString m_phoneMobile;
|
||||||
|
|
||||||
|
|
||||||
|
TDEAction *actionBlock;
|
||||||
|
TDEAction *actionShowProfile;
|
||||||
|
TDEAction *actionSendMail;
|
||||||
|
TDEAction *actionWebcamReceive;
|
||||||
|
TDEAction *actionWebcamSend;
|
||||||
|
|
||||||
|
TQString m_obj; //the MSNObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* keep the current status here. (it's normally already in Kopete::Contact::d->onlineStatus)
|
||||||
|
* This is a workaround to prevent problems with the account offline status.
|
||||||
|
*/
|
||||||
|
Kopete::OnlineStatus m_currentStatus;
|
||||||
|
|
||||||
|
//MSNProtocol::deserializeContact need to acess some contact insternals
|
||||||
|
friend class MSNProtocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
msndebugrawcmddlg.cpp - Send a raw MSN command for debugging
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions of this code are taken from KMerlin,
|
||||||
|
(c) 2001 by Olaf Lueg <olueg@olsd.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 "msndebugrawcmddlg.h"
|
||||||
|
|
||||||
|
#include "ui/msndebugrawcommand_base.h"
|
||||||
|
|
||||||
|
#include <tqcheckbox.h>
|
||||||
|
#include <tqlineedit.h>
|
||||||
|
#include <ktextedit.h>
|
||||||
|
|
||||||
|
#include <tdelocale.h>
|
||||||
|
|
||||||
|
MSNDebugRawCmdDlg::MSNDebugRawCmdDlg( TQWidget *parent )
|
||||||
|
: KDialogBase( parent, 0L, true,
|
||||||
|
i18n( "DEBUG: Send Raw Command - MSN Plugin" ), Ok | Cancel,
|
||||||
|
Ok, true )
|
||||||
|
{
|
||||||
|
setInitialSize( TQSize( 350, 200 ) );
|
||||||
|
|
||||||
|
m_main = new MSNDebugRawCommand_base( this );
|
||||||
|
setMainWidget( m_main );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNDebugRawCmdDlg::~MSNDebugRawCmdDlg()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNDebugRawCmdDlg::command()
|
||||||
|
{
|
||||||
|
return m_main->m_command->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNDebugRawCmdDlg::params()
|
||||||
|
{
|
||||||
|
return m_main->m_params->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNDebugRawCmdDlg::addNewline()
|
||||||
|
{
|
||||||
|
return m_main->m_addNewline->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNDebugRawCmdDlg::addId()
|
||||||
|
{
|
||||||
|
return m_main->m_addId->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNDebugRawCmdDlg::msg()
|
||||||
|
{
|
||||||
|
return m_main->m_msg->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msndebugrawcmddlg.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
msndebugrawcmddlg.h - Send a raw MSN command for debugging
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions of this code are taken from KMerlin,
|
||||||
|
(c) 2001 by Olaf Lueg <olueg@olsd.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 MSNDEBUGRAWCMDDLG_H
|
||||||
|
#define MSNDEBUGRAWCMDDLG_H
|
||||||
|
|
||||||
|
#include <kdialogbase.h>
|
||||||
|
|
||||||
|
class MSNDebugRawCommand_base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Martijn Klingens <klingens@kde.org>
|
||||||
|
*
|
||||||
|
* Simple debugging help
|
||||||
|
*/
|
||||||
|
class MSNDebugRawCmdDlg : public KDialogBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNDebugRawCmdDlg( TQWidget *parent );
|
||||||
|
~MSNDebugRawCmdDlg();
|
||||||
|
|
||||||
|
TQString command();
|
||||||
|
TQString params();
|
||||||
|
bool addNewline();
|
||||||
|
bool addId();
|
||||||
|
TQString msg();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNDebugRawCommand_base *m_main;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,481 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
msnfiletransfersocket.cpp - description
|
||||||
|
-------------------
|
||||||
|
begin : mer jui 31 2002
|
||||||
|
copyright : (C) 2002 by Olivier Goffart
|
||||||
|
email : ogoffart @ kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "msnfiletransfersocket.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//qt
|
||||||
|
#include <tqtimer.h>
|
||||||
|
|
||||||
|
// kde
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kserversocket.h>
|
||||||
|
#include <kbufferedsocket.h>
|
||||||
|
#include <tdefiledialog.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
|
||||||
|
#include "kopetetransfermanager.h"
|
||||||
|
#include "kopetecontact.h"
|
||||||
|
#include "kopetemetacontact.h"
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
#include "msnswitchboardsocket.h"
|
||||||
|
#include "msnnotifysocket.h"
|
||||||
|
#include "msnaccount.h"
|
||||||
|
|
||||||
|
using namespace KNetwork;
|
||||||
|
|
||||||
|
MSNFileTransferSocket::MSNFileTransferSocket(const TQString &handle, Kopete::Contact *c,bool incoming, TQObject* parent)
|
||||||
|
: MSNSocket(parent) , MSNInvitation(incoming, MSNFileTransferSocket::applicationID() , i18n("File Transfer - MSN Plugin"))
|
||||||
|
{
|
||||||
|
m_handle=handle;
|
||||||
|
m_kopeteTransfer=0l;
|
||||||
|
m_file=0L;
|
||||||
|
m_server=0L;
|
||||||
|
m_contact=c;
|
||||||
|
ready=true;
|
||||||
|
|
||||||
|
TQObject::connect( this, TQT_SIGNAL( socketClosed() ), this, TQT_SLOT( slotSocketClosed() ) );
|
||||||
|
TQObject::connect( this, TQT_SIGNAL( blockRead( const TQByteArray & ) ), this, TQT_SLOT(slotReadBlock( const TQByteArray & ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNFileTransferSocket::~MSNFileTransferSocket()
|
||||||
|
{
|
||||||
|
delete m_file;
|
||||||
|
delete m_server;
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::~MSNFileTransferSocket" <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::parseCommand(const TQString & cmd, uint id, const TQString & data)
|
||||||
|
{
|
||||||
|
if( cmd == "VER" )
|
||||||
|
{
|
||||||
|
if(data.section( ' ', 0, 0 ) != "MSNFTP")
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::parseCommand (VER): bad version: disconnect" <<endl;
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( m_incoming )
|
||||||
|
sendCommand( "USR", m_handle + " " + m_authcook, false );
|
||||||
|
else
|
||||||
|
sendCommand( "VER", "MSNFTP" , false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( cmd == "FIL" )
|
||||||
|
{
|
||||||
|
m_size=id; //data.toUInt(); //BUG: the size is take as id bye MSNSocket because it is a number
|
||||||
|
|
||||||
|
m_downsize=0;
|
||||||
|
m_file=new TQFile(m_fileName);
|
||||||
|
|
||||||
|
if( m_file->open( IO_WriteOnly ))
|
||||||
|
sendCommand( "TFR" ,NULL,false);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::parseCommand: ERROR: unable to open file - disconnect " <<endl;
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( cmd == "BYE" )
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::parseCommand : end of transfer " <<endl;
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
else if( cmd == "USR" )
|
||||||
|
{
|
||||||
|
if(data.section( ' ', 1, 1 )!= m_authcook)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::parseCommand (USR): bad auth" <<endl;
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sendCommand("FIL" , TQString::number(size()) , false);
|
||||||
|
}
|
||||||
|
else if( cmd == "TFR" )
|
||||||
|
{
|
||||||
|
m_downsize=0;
|
||||||
|
ready=true;
|
||||||
|
TQTimer::singleShot( 0, this, TQT_SLOT(slotSendFile()) );
|
||||||
|
}
|
||||||
|
else if( cmd == "CCL" )
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::parseCommand : unknown command " <<cmd <<endl;
|
||||||
|
|
||||||
|
// kdDebug(14140) << "MSNFileTransferSocket::parseCommand : done " <<cmd <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::doneConnect()
|
||||||
|
{
|
||||||
|
if(m_incoming)
|
||||||
|
sendCommand( "VER", "MSNFTP", false );
|
||||||
|
MSNSocket::doneConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::bytesReceived(const TQByteArray & head)
|
||||||
|
{
|
||||||
|
if(head[0]!='\0')
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::bytesReceived: transfer aborted" <<endl;
|
||||||
|
TQTimer::singleShot(0,this,TQT_SLOT(disconnect()));
|
||||||
|
}
|
||||||
|
unsigned int sz=(int)((unsigned char)head.data()[2])*256+(int)((unsigned char)head.data()[1]);
|
||||||
|
// kdDebug(14140) << "MSNFileTransferSocket::bytesReceived: " << sz <<endl;
|
||||||
|
readBlock(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotSocketClosed()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::slotSocketClose "<< endl;
|
||||||
|
if(m_file)
|
||||||
|
m_file->close();
|
||||||
|
delete m_file;
|
||||||
|
m_file=0L;
|
||||||
|
delete m_server;
|
||||||
|
m_server=0L;
|
||||||
|
if(m_kopeteTransfer)
|
||||||
|
{
|
||||||
|
if( (m_downsize!=m_size || m_downsize==0 ) )
|
||||||
|
m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) );
|
||||||
|
else
|
||||||
|
m_kopeteTransfer->slotComplete();
|
||||||
|
}
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotReadBlock(const TQByteArray &block)
|
||||||
|
{
|
||||||
|
m_file->writeBlock( block.data(), block.size() ); // write to file
|
||||||
|
|
||||||
|
m_downsize+=block.size();
|
||||||
|
if(m_kopeteTransfer) m_kopeteTransfer->slotProcessed(m_downsize);
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket - " << m_downsize << " of " << m_size <<" done"<<endl;
|
||||||
|
|
||||||
|
if(m_downsize==m_size)
|
||||||
|
{
|
||||||
|
//the transfer seems to be finished.
|
||||||
|
sendCommand( "BYE" ,"16777989",false);
|
||||||
|
// if we are not already disconected in 30 seconds, do it.
|
||||||
|
TQTimer::singleShot( 30000 , this, TQT_SLOT(disconnect() ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::setKopeteTransfer(Kopete::Transfer *kt)
|
||||||
|
{
|
||||||
|
m_kopeteTransfer=kt;
|
||||||
|
if(kt)
|
||||||
|
{
|
||||||
|
TQObject::connect(kt , TQT_SIGNAL(transferCanceled()), this, TQT_SLOT(abort()));
|
||||||
|
TQObject::connect(kt, TQT_SIGNAL(destroyed()) , this , TQT_SLOT(slotKopeteTransferDestroyed()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::listen(int port)
|
||||||
|
{
|
||||||
|
m_server = new TDEServerSocket();
|
||||||
|
|
||||||
|
TQObject::connect( m_server, TQT_SIGNAL(readyAccept()), this, TQT_SLOT(slotAcceptConnection()));
|
||||||
|
m_server->setAddress(TQString::number(port));
|
||||||
|
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::listen: about to listen"<<endl;
|
||||||
|
bool listenResult = m_server->listen(1);
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::listen: result: "<< listenResult <<endl;
|
||||||
|
TQTimer::singleShot( 60000, this, TQT_SLOT(slotTimer()) );
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::listen done" <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotAcceptConnection()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::slotAcceptConnection" <<endl;
|
||||||
|
if(!accept(m_server))
|
||||||
|
{
|
||||||
|
if( m_kopeteTransfer)
|
||||||
|
m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) );
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotTimer()
|
||||||
|
{
|
||||||
|
if(onlineStatus() != Disconnected)
|
||||||
|
return;
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::slotTimer: timeout "<< endl;
|
||||||
|
if( m_kopeteTransfer)
|
||||||
|
{
|
||||||
|
m_kopeteTransfer->slotError( TDEIO::ERR_CONNECTION_BROKEN , i18n( "Connection timed out" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
if(manager && manager->service())
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, rejectMessage("TIMEOUT") );
|
||||||
|
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::abort()
|
||||||
|
{
|
||||||
|
if(m_incoming)
|
||||||
|
{
|
||||||
|
sendCommand( "CCL" , NULL ,false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TQByteArray bytes(3);
|
||||||
|
bytes[0]='\1';
|
||||||
|
bytes[1]='\0';
|
||||||
|
bytes[2]='\0';
|
||||||
|
sendBytes( bytes );
|
||||||
|
m_downsize=m_size; //we don't want to send data anymore;
|
||||||
|
}
|
||||||
|
//the timer wait one second, the time to send the CCL or the binary header
|
||||||
|
//retarding the disconnection keep away from a crash. (in TDEIO::Job::emitResult when `delete this`)
|
||||||
|
TQTimer::singleShot( 1000, this, TQT_SLOT(disconnect()) );
|
||||||
|
ready=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::setFile( const TQString &fn, long unsigned int fileSize )
|
||||||
|
{
|
||||||
|
m_fileName=fn;
|
||||||
|
if(!m_incoming)
|
||||||
|
{
|
||||||
|
if(m_file)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::setFileName: WARNING m_file already exists" << endl;
|
||||||
|
delete m_file;
|
||||||
|
}
|
||||||
|
m_file = new TQFile( fn );
|
||||||
|
if(!m_file->open(IO_ReadOnly))
|
||||||
|
{
|
||||||
|
//FIXME: abort transfer here
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::setFileName: WARNING unable to open the file" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the fileSize is 0 it was not given, we are to get it from the file
|
||||||
|
if(fileSize == 0L)
|
||||||
|
m_size = m_file->size();
|
||||||
|
else
|
||||||
|
m_size = fileSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotSendFile()
|
||||||
|
{
|
||||||
|
// kdDebug(14140) <<"MSNFileTransferSocket::slotSendFile()" <<endl;
|
||||||
|
if( m_downsize >= m_size)
|
||||||
|
{
|
||||||
|
//the transfer seems to be finished.
|
||||||
|
// if we are not already disconected in 30 seconds, do it.
|
||||||
|
TQTimer::singleShot( 30000 , this, TQT_SLOT(disconnect() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ready)
|
||||||
|
{
|
||||||
|
char data[2046];
|
||||||
|
int bytesRead = m_file->readBlock( data, 2045 );
|
||||||
|
|
||||||
|
TQByteArray block(bytesRead+3);
|
||||||
|
// char i1= (char)fmod( bytesRead, 256 ) ;
|
||||||
|
// char i2= (char)floor( bytesRead / 256 ) ;
|
||||||
|
// kdDebug(14140) << "MSNFileTransferSocket::slotSendFile: " << (int)i1 <<" + 256* "<< (int)i2 <<" = " << bytesRead <<endl;
|
||||||
|
block[0]='\0';
|
||||||
|
block[1]= (char)fmod( bytesRead, 256 );
|
||||||
|
block[2]= (char)floor( bytesRead / 256 );
|
||||||
|
|
||||||
|
for ( int f = 0; f < bytesRead; f++ )
|
||||||
|
{
|
||||||
|
block[f+3] = data[f];
|
||||||
|
}
|
||||||
|
|
||||||
|
sendBytes(block);
|
||||||
|
|
||||||
|
m_downsize+=bytesRead;
|
||||||
|
if(m_kopeteTransfer)
|
||||||
|
m_kopeteTransfer->slotProcessed(m_downsize);
|
||||||
|
kdDebug(14140) << "MSNFileTransferSocket::slotSendFile: " << m_downsize << " of " << m_size <<" done"<<endl;
|
||||||
|
}
|
||||||
|
ready=false;
|
||||||
|
|
||||||
|
TQTimer::singleShot( 10, this, TQT_SLOT(slotSendFile()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotReadyWrite()
|
||||||
|
{
|
||||||
|
ready=true;
|
||||||
|
MSNSocket::slotReadyWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNFileTransferSocket::invitationHead()
|
||||||
|
{
|
||||||
|
TQTimer::singleShot( 10 * 60000, this, TQT_SLOT(slotTimer()) ); //the user has 10 mins to accept or refuse or initiate the transfer
|
||||||
|
|
||||||
|
return TQString( MSNInvitation::invitationHead()+
|
||||||
|
"Application-File: "+ m_fileName.right( m_fileName.length() - m_fileName.findRev( '/' ) - 1 ) +"\r\n"
|
||||||
|
"Application-FileSize: "+ TQString::number(size()) +"\r\n\r\n").utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::parseInvitation(const TQString& msg)
|
||||||
|
{
|
||||||
|
TQRegExp rx("Invitation-Command: ([A-Z]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString command=rx.cap(1);
|
||||||
|
if( msg.contains("Invitation-Command: INVITE") )
|
||||||
|
{
|
||||||
|
rx=TQRegExp("Application-File: ([^\\r\\n]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString filename = rx.cap(1);
|
||||||
|
rx=TQRegExp("Application-FileSize: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
unsigned long int filesize= rx.cap(1).toUInt();
|
||||||
|
|
||||||
|
MSNInvitation::parseInvitation(msg); //for the cookie
|
||||||
|
|
||||||
|
Kopete::TransferManager::transferManager()->askIncomingTransfer( m_contact , filename, filesize, TQString(), TQString::number( cookie() ) );
|
||||||
|
|
||||||
|
TQObject::connect( Kopete::TransferManager::transferManager(), TQT_SIGNAL( accepted( Kopete::Transfer *, const TQString& ) ),this, TQT_SLOT( slotFileTransferAccepted( Kopete::Transfer *, const TQString& ) ) );
|
||||||
|
TQObject::connect( Kopete::TransferManager::transferManager(), TQT_SIGNAL( refused( const Kopete::FileTransferInfo & ) ), this, TQT_SLOT( slotFileTransferRefused( const Kopete::FileTransferInfo & ) ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
else if( msg.contains("Invitation-Command: ACCEPT") )
|
||||||
|
{
|
||||||
|
if(incoming())
|
||||||
|
{
|
||||||
|
rx=TQRegExp("IP-Address: ([0-9\\.]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString ip_address = rx.cap(1);
|
||||||
|
rx=TQRegExp("AuthCookie: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString authcook = rx.cap(1);
|
||||||
|
rx=TQRegExp("Port: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString port = rx.cap(1);
|
||||||
|
|
||||||
|
setAuthCookie(authcook);
|
||||||
|
connect(ip_address, port.toUInt());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned long int auth = (rand()%(999999))+1;
|
||||||
|
setAuthCookie(TQString::number(auth));
|
||||||
|
|
||||||
|
setKopeteTransfer(Kopete::TransferManager::transferManager()->addTransfer(m_contact, fileName(), size(), m_contact->metaContact() ? m_contact->metaContact()->displayName() : m_contact->contactId() , Kopete::FileTransferInfo::Outgoing));
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
MSNNotifySocket *notify=static_cast<MSNAccount*>(manager->account())->notifySocket();
|
||||||
|
if(notify){
|
||||||
|
|
||||||
|
TQCString message=TQString(
|
||||||
|
"MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: ACCEPT\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
|
||||||
|
"IP-Address: " + notify->localIP() + "\r\n"
|
||||||
|
"Port: 6891\r\n"
|
||||||
|
"AuthCookie: "+TQString::number(auth)+"\r\n"
|
||||||
|
"Launch-Application: FALSE\r\n"
|
||||||
|
"Request-Data: IP-Address:\r\n\r\n").utf8();
|
||||||
|
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(6891);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //CANCEL
|
||||||
|
{
|
||||||
|
MSNInvitation::parseInvitation(msg);
|
||||||
|
if( m_kopeteTransfer)
|
||||||
|
m_kopeteTransfer->slotError( TDEIO::ERR_ABORTED , i18n( "The remote user aborted" ) );
|
||||||
|
emit done(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotFileTransferAccepted(Kopete::Transfer *trans, const TQString& fileName)
|
||||||
|
{
|
||||||
|
if(trans->info().internalId().toULong() != cookie())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!trans->info().contact())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setKopeteTransfer(trans);
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
setFile(fileName);
|
||||||
|
|
||||||
|
TQCString message=TQString(
|
||||||
|
"MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: ACCEPT\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
|
||||||
|
"Launch-Application: FALSE\r\n"
|
||||||
|
"Request-Data: IP-Address:\r\n" ).utf8();
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, message );
|
||||||
|
|
||||||
|
TQTimer::singleShot( 3 * 60000, this, TQT_SLOT(slotTimer()) ); //if after 3 minutes the transfer has not begin, delete this
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( m_kopeteTransfer)
|
||||||
|
m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) );
|
||||||
|
emit done(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotFileTransferRefused(const Kopete::FileTransferInfo &info)
|
||||||
|
{
|
||||||
|
if(info.internalId().toULong() != cookie())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!info.contact())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager());
|
||||||
|
|
||||||
|
if(manager && manager->service())
|
||||||
|
{
|
||||||
|
manager->service()->sendCommand( "MSG" , "N", true, rejectMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
|
emit done(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNFileTransferSocket::slotKopeteTransferDestroyed()
|
||||||
|
{
|
||||||
|
m_kopeteTransfer=0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "msnfiletransfersocket.moc"
|
||||||
|
|
@ -0,0 +1,120 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
msnfiletransfersocket.h - description
|
||||||
|
-------------------
|
||||||
|
begin : mer jui 31 2002
|
||||||
|
copyright : (C) 2002 by Olivier Goffart
|
||||||
|
email : ogoffart @ kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MSNFILETRANSFERSOCKET_H
|
||||||
|
#define MSNFILETRANSFERSOCKET_H
|
||||||
|
|
||||||
|
#include <tqwidget.h>
|
||||||
|
|
||||||
|
#include "msnsocket.h"
|
||||||
|
#include "msninvitation.h"
|
||||||
|
|
||||||
|
class TQFile;
|
||||||
|
|
||||||
|
namespace KNetwork {
|
||||||
|
class TDEServerSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kopete { class Transfer; }
|
||||||
|
namespace Kopete { class FileTransferInfo; }
|
||||||
|
namespace Kopete { class Protocol; }
|
||||||
|
namespace Kopete { class Contact; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Goffart
|
||||||
|
*/
|
||||||
|
class MSNFileTransferSocket : public MSNSocket , public MSNInvitation
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNFileTransferSocket(const TQString &myID,Kopete::Contact* c, bool incoming, TQObject* parent = 0L );
|
||||||
|
~MSNFileTransferSocket();
|
||||||
|
|
||||||
|
static TQString applicationID() { return "5D3E02AB-6190-11d3-BBBB-00C04F795683"; }
|
||||||
|
TQString invitationHead();
|
||||||
|
|
||||||
|
|
||||||
|
void setKopeteTransfer( Kopete::Transfer *kt );
|
||||||
|
Kopete::Transfer* kopeteTransfer() { return m_kopeteTransfer; }
|
||||||
|
void setFile( const TQString &fn, long unsigned int fileSize = 0L );
|
||||||
|
void setAuthCookie( const TQString &c ) { m_authcook = c; }
|
||||||
|
TQString fileName() { return m_fileName;}
|
||||||
|
long unsigned int size() { return m_size;}
|
||||||
|
void listen( int port );
|
||||||
|
|
||||||
|
virtual void parseInvitation(const TQString& invitation);
|
||||||
|
|
||||||
|
virtual TQObject* object() { return this; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void abort();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void done( MSNInvitation * );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* This reimplementation sets up the negotiating with the server and
|
||||||
|
* suppresses the change of the status to online until the handshake
|
||||||
|
* is complete.
|
||||||
|
*/
|
||||||
|
virtual void doneConnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an MSN command response line.
|
||||||
|
*/
|
||||||
|
virtual void parseCommand(const TQString & cmd, uint id, const TQString & data);
|
||||||
|
virtual void bytesReceived(const TQByteArray & data);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void slotReadyWrite();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotSocketClosed();
|
||||||
|
void slotReadBlock(const TQByteArray &);
|
||||||
|
void slotAcceptConnection();
|
||||||
|
void slotTimer();
|
||||||
|
void slotSendFile();
|
||||||
|
|
||||||
|
void slotFileTransferRefused( const Kopete::FileTransferInfo &info );
|
||||||
|
void slotFileTransferAccepted( Kopete::Transfer *trans, const TQString& fileName );
|
||||||
|
/* the Kopete::Transfer has been deleted */
|
||||||
|
void slotKopeteTransferDestroyed();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
TQString m_handle;
|
||||||
|
Kopete::Contact *m_contact;
|
||||||
|
|
||||||
|
long unsigned int m_size;
|
||||||
|
long unsigned int m_downsize;
|
||||||
|
TQString m_authcook;
|
||||||
|
TQString m_fileName;
|
||||||
|
Kopete::Transfer* m_kopeteTransfer;
|
||||||
|
TQFile *m_file ;
|
||||||
|
KNetwork::TDEServerSocket *m_server;
|
||||||
|
|
||||||
|
bool ready;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 tw=4:
|
||||||
|
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
msninvitation.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2003 by the Kopete developers <kopete-devel@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 "msninvitation.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
|
||||||
|
MSNInvitation::MSNInvitation(bool incoming, const TQString &applicationID , const TQString &applicationName)
|
||||||
|
{
|
||||||
|
m_incoming=incoming;
|
||||||
|
m_applicationId=applicationID;
|
||||||
|
m_applicationName=applicationName;
|
||||||
|
m_cookie= (rand()%(999999))+1;
|
||||||
|
m_state = Nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MSNInvitation::~MSNInvitation()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TQCString MSNInvitation::unimplemented(long unsigned int cookie)
|
||||||
|
{
|
||||||
|
return TQString( "MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: CANCEL\r\n"
|
||||||
|
"Cancel-Code: REJECT_NOT_INSTALLED\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie) + "\r\n"
|
||||||
|
"Session-ID: {120019D9-C3F5-4F94-978D-CB33534C3309}\r\n\r\n").utf8();
|
||||||
|
//FIXME: i don't know at all what Seession-ID is
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString MSNInvitation::invitationHead()
|
||||||
|
{
|
||||||
|
setState(Invited);
|
||||||
|
return TQString( "MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Application-Name: " + m_applicationName + "\r\n"
|
||||||
|
"Application-GUID: {" + m_applicationId + "}\r\n"
|
||||||
|
"Invitation-Command: INVITE\r\n"
|
||||||
|
"Invitation-Cookie: " +TQString::number(m_cookie) +"\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TQCString MSNInvitation::rejectMessage(const TQString & rejectcode)
|
||||||
|
{
|
||||||
|
return TQString( "MIME-Version: 1.0\r\n"
|
||||||
|
"Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"Invitation-Command: CANCEL\r\n"
|
||||||
|
"Invitation-Cookie: " + TQString::number(cookie()) + "\r\n"
|
||||||
|
"Cancel-Code: "+ rejectcode +"\r\n").utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNInvitation::parseInvitation(const TQString& msg)
|
||||||
|
{
|
||||||
|
TQRegExp rx("Invitation-Command: ([A-Z]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString command=rx.cap(1);
|
||||||
|
|
||||||
|
if(command=="INVITE")
|
||||||
|
{
|
||||||
|
rx=TQRegExp("Invitation-Cookie: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
m_cookie=rx.cap(1).toUInt();
|
||||||
|
}
|
||||||
|
else if(command=="CANCEL")
|
||||||
|
{
|
||||||
|
/*rx=TQRegExp("Cancel-Code: ([0-9]*)");
|
||||||
|
rx.search(msg);
|
||||||
|
TQString code=rx.cap(1).toUInt();
|
||||||
|
//TODO: parse the code*/
|
||||||
|
}
|
||||||
|
// else if(command=="ACCEPT")
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNInvitation::State MSNInvitation::state()
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNInvitation::setState(MSNInvitation::State s)
|
||||||
|
{
|
||||||
|
m_state=s;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
msninvitation.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2003 by the Kopete developers <kopete-devel@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 MSNINVITATION_H
|
||||||
|
#define MSNINVITATION_H
|
||||||
|
|
||||||
|
#include <tqstring.h>
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
class TQObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Goffart
|
||||||
|
*
|
||||||
|
* The invitation is the base class which handle an MSN invitation.
|
||||||
|
* The implemented class must to herits from TQObject too.
|
||||||
|
* You can accept the invitation by catching @ref MSNProtocol::invitation() signals
|
||||||
|
* or create one and insert it to a kmm with @ref MSNChatSession::initInvitation()
|
||||||
|
* you can add action with @ref Kopete::Plugin::customChatActions()
|
||||||
|
*/
|
||||||
|
class KOPETE_EXPORT MSNInvitation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param incoming say if it is an incoming invitation
|
||||||
|
* @param applicationID is the exadecimal id of the invitation
|
||||||
|
* @param applicationName is a i18n'ed string of the name of the application
|
||||||
|
*/
|
||||||
|
MSNInvitation(bool incoming,const TQString &applicationID , const TQString &applicationName);
|
||||||
|
virtual ~MSNInvitation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* it is a reject invitation because the invitation is not implemented
|
||||||
|
*/
|
||||||
|
static TQCString unimplemented(long unsigned int cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* you can set manualy the cookie. note that a cookie is automatically generated when a new
|
||||||
|
* invitation is created, or in @ref parseInvitation
|
||||||
|
*/
|
||||||
|
void setCookie( long unsigned int c ) { m_cookie = c; }
|
||||||
|
/**
|
||||||
|
* @return the cookie
|
||||||
|
*/
|
||||||
|
long unsigned int cookie() { return m_cookie; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if it is an incommijng invitation
|
||||||
|
*/
|
||||||
|
bool incoming() { return m_incoming; }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reimplement this. this is the invitation string used in @ref MSNChatSession::initInvitation()
|
||||||
|
* the default implementation return the common begin.
|
||||||
|
* You can also set the state to Invited (the default implementation do that)
|
||||||
|
*/
|
||||||
|
virtual TQString invitationHead();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the reject invitation string
|
||||||
|
* @param rejectcode is the code, it can be "REJECT" or "TIMEOUT"
|
||||||
|
*/
|
||||||
|
TQCString rejectMessage(const TQString & rejectcode = "REJECT");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reimplement this method. it is called when an invitation message with the invitation's cookie is received
|
||||||
|
* the default implementation parse the cookie, or the reject message
|
||||||
|
*/
|
||||||
|
virtual void parseInvitation(const TQString& invitation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the qobject (this)
|
||||||
|
*/
|
||||||
|
virtual TQObject* object()=0;
|
||||||
|
//signals:
|
||||||
|
/**
|
||||||
|
* reimplement this as a signal, and emit it when the invitation has to be destroyed.
|
||||||
|
* don't delete the invitation yourself
|
||||||
|
*/
|
||||||
|
virtual void done(MSNInvitation*)=0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This indiquate the state. it is going to be completed later
|
||||||
|
* - Nothing means than nothing has been done in the invitaiton (nothing has been sent/received)
|
||||||
|
* - Invited means than the invitaiton has been sent
|
||||||
|
*/
|
||||||
|
enum State { Nothing=0 , Invited=1 };
|
||||||
|
/**
|
||||||
|
* retrun the current state
|
||||||
|
*/
|
||||||
|
State state();
|
||||||
|
/**
|
||||||
|
* set the current State
|
||||||
|
*/
|
||||||
|
void setState(State);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_incoming;
|
||||||
|
long unsigned int m_cookie;
|
||||||
|
TQString m_applicationId;
|
||||||
|
TQString m_applicationName;
|
||||||
|
State m_state;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
msnnotifysocket.h - Notify Socket for the MSN Protocol
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
||||||
|
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2005 by Olivier Goffart <ogoffart at kde.org>
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions taken from
|
||||||
|
KMerlin (c) 2001 by Olaf Lueg <olueg@olsd.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 MSNNOTIFYSOCKET_H
|
||||||
|
#define MSNNOTIFYSOCKET_H
|
||||||
|
|
||||||
|
#include "msnsocket.h"
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
|
||||||
|
|
||||||
|
class MSNDispatchSocket;
|
||||||
|
class MSNAccount;
|
||||||
|
class KTempFile;
|
||||||
|
class MSNSecureLoginHandler;
|
||||||
|
class MSNChallengeHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olaf Lueg
|
||||||
|
* @author Olivier Goffart
|
||||||
|
*/
|
||||||
|
class MSNNotifySocket : public MSNSocket
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNNotifySocket( MSNAccount* account, const TQString &msnId, const TQString &password );
|
||||||
|
~MSNNotifySocket();
|
||||||
|
|
||||||
|
virtual void disconnect();
|
||||||
|
|
||||||
|
void setStatus( const Kopete::OnlineStatus &status );
|
||||||
|
void addContact( const TQString &handle, int list, const TQString& publicName, const TQString& contactGuid, const TQString& groupGuid );
|
||||||
|
void removeContact( const TQString &handle, int list, const TQString &contactGuid, const TQString &groupGuid );
|
||||||
|
|
||||||
|
void addGroup( const TQString& groupName );
|
||||||
|
void removeGroup( const TQString& group );
|
||||||
|
void renameGroup( const TQString& groupName, const TQString& groupGuid );
|
||||||
|
|
||||||
|
void changePublicName( const TQString& publicName , const TQString &handle=TQString() );
|
||||||
|
void changePersonalMessage( MSNProtocol::PersonalMessageType type , const TQString& personalMessage );
|
||||||
|
|
||||||
|
void changePhoneNumber( const TQString &key, const TQString &data );
|
||||||
|
|
||||||
|
void createChatSession();
|
||||||
|
|
||||||
|
void sendMail(const TQString &email);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this should return a Kopete::Account::DisconnectReason value
|
||||||
|
*/
|
||||||
|
int disconnectReason() { return m_disconnectReason; }
|
||||||
|
|
||||||
|
TQString localIP() { return m_localIP; }
|
||||||
|
|
||||||
|
bool setUseHttpMethod( bool useHttpMethod );
|
||||||
|
|
||||||
|
bool isLogged() const { return m_isLogged; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotOpenInbox();
|
||||||
|
void slotMSNAlertLink(unsigned int action);
|
||||||
|
void slotMSNAlertUnwanted();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newContactList();
|
||||||
|
void contactList(const TQString& handle, const TQString& publicName, const TQString &contactGuid, uint lists, const TQString& groups);
|
||||||
|
void contactStatus(const TQString&, const TQString&, const TQString& );
|
||||||
|
void contactAdded(const TQString& handle, const TQString& list, const TQString& publicName, const TQString& contactGuid, const TQString& groupGuid);
|
||||||
|
//void contactRemoved(const TQString&, const TQString&, uint);
|
||||||
|
void contactRemoved(const TQString& handle, const TQString& list, const TQString& contactGuid, const TQString& groupGuid);
|
||||||
|
|
||||||
|
void groupListed(const TQString&, const TQString&);
|
||||||
|
void groupAdded( const TQString&, const TQString&);
|
||||||
|
void groupRenamed( const TQString&, const TQString& );
|
||||||
|
void groupRemoved( const TQString& );
|
||||||
|
|
||||||
|
void invitedToChat(const TQString&, const TQString&, const TQString&, const TQString&, const TQString& );
|
||||||
|
void startChat( const TQString&, const TQString& );
|
||||||
|
|
||||||
|
void statusChanged( const Kopete::OnlineStatus &newStatus );
|
||||||
|
|
||||||
|
void hotmailSeted(bool) ;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the dispatch server sends us the notification server to use, this
|
||||||
|
* signal is emitted. After this the socket is automatically closed.
|
||||||
|
*/
|
||||||
|
void receivedNotificationServer( const TQString &host, uint port );
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Handle an MSN command response line.
|
||||||
|
*/
|
||||||
|
virtual void parseCommand( const TQString &cmd, uint id,
|
||||||
|
const TQString &data );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an MSN error condition.
|
||||||
|
* This reimplementation handles most of the other MSN error codes.
|
||||||
|
*/
|
||||||
|
virtual void handleError( uint code, uint id );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This reimplementation sets up the negotiating with the server and
|
||||||
|
* suppresses the change of the status to online until the handshake
|
||||||
|
* is complete.
|
||||||
|
*/
|
||||||
|
virtual void doneConnect();
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* We received a message from the server, which is sent as raw data,
|
||||||
|
* instead of cr/lf line-based text.
|
||||||
|
*/
|
||||||
|
void slotReadMessage( const TQByteArray &bytes );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a keepalive to the server to avoid idle connections to cause
|
||||||
|
* MSN closing the connection
|
||||||
|
*/
|
||||||
|
void slotSendKeepAlive();
|
||||||
|
|
||||||
|
void sslLoginFailed();
|
||||||
|
void sslLoginIncorrect();
|
||||||
|
void sslLoginSucceeded(TQString ticket);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Convert the MSN status strings to a Kopete::OnlineStatus
|
||||||
|
*/
|
||||||
|
Kopete::OnlineStatus convertOnlineStatus( const TQString &statusString );
|
||||||
|
|
||||||
|
MSNAccount *m_account;
|
||||||
|
TQString m_password;
|
||||||
|
TQStringList m_msnAlertURLs;
|
||||||
|
|
||||||
|
unsigned int mailCount;
|
||||||
|
|
||||||
|
Kopete::OnlineStatus m_newstatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an entry of the Status enum back to a string
|
||||||
|
*/
|
||||||
|
TQString statusToString( const Kopete::OnlineStatus &status ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the CurrentMedia XML element.
|
||||||
|
* @param mediaXmlElement the source XML element as text.
|
||||||
|
*/
|
||||||
|
TQString processCurrentMedia( const TQString &mediaXmlElement );
|
||||||
|
|
||||||
|
//know the last handle used
|
||||||
|
TQString m_tmpLastHandle;
|
||||||
|
TQMap <unsigned int,TQString> m_tmpHandles;
|
||||||
|
TQString m_configFile;
|
||||||
|
|
||||||
|
//for hotmail inbox opening
|
||||||
|
bool m_isHotmailAccount;
|
||||||
|
TQString m_MSPAuth;
|
||||||
|
TQString m_kv;
|
||||||
|
TQString m_sid;
|
||||||
|
TQString m_loginTime;
|
||||||
|
TQString m_localIP;
|
||||||
|
MSNSecureLoginHandler *m_secureLoginHandler;
|
||||||
|
|
||||||
|
MSNChallengeHandler *m_challengeHandler;
|
||||||
|
TQTimer *m_keepaliveTimer;
|
||||||
|
|
||||||
|
bool m_ping;
|
||||||
|
|
||||||
|
int m_disconnectReason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to set the myself() personalMessage when the acknowledge(UUX) command is received.
|
||||||
|
* The personalMessage is built into @ref changePersonalMessage
|
||||||
|
*/
|
||||||
|
TQString 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
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
msnprotocol.cpp - Kopete MSN Protocol Plugin
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
||||||
|
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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 <tqimage.h>
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kgenericfactory.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <tdeversion.h>
|
||||||
|
#include <tdeaboutdata.h>
|
||||||
|
|
||||||
|
#include "kopeteaccountmanager.h"
|
||||||
|
#include "kopeteglobal.h"
|
||||||
|
#include "kopeteonlinestatusmanager.h"
|
||||||
|
|
||||||
|
#include "msnaddcontactpage.h"
|
||||||
|
#include "msneditaccountwidget.h"
|
||||||
|
#include "msncontact.h"
|
||||||
|
#include "msnaccount.h"
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
#include "msnchatsession.h"
|
||||||
|
|
||||||
|
typedef KGenericFactory<MSNProtocol> MSNProtocolFactory;
|
||||||
|
#if KDE_IS_VERSION(3,2,90)
|
||||||
|
static const TDEAboutData aboutdata("kopete_msn", I18N_NOOP("MSN Messenger") , "1.0" );
|
||||||
|
K_EXPORT_COMPONENT_FACTORY( libkopete_msn_shared, MSNProtocolFactory( &aboutdata ) )
|
||||||
|
#else
|
||||||
|
K_EXPORT_COMPONENT_FACTORY( libkopete_msn_shared, MSNProtocolFactory( "kopete_msn" ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MSNProtocol *MSNProtocol::s_protocol = 0L;
|
||||||
|
|
||||||
|
MSNProtocol::MSNProtocol( TQObject *parent, const char *name, const TQStringList & /* args */ )
|
||||||
|
: Kopete::Protocol( MSNProtocolFactory::instance(), parent, name ),
|
||||||
|
NLN( Kopete::OnlineStatus::Online, 25, this, 1, TQString(), i18n( "Online" ) , i18n( "O&nline" ), Kopete::OnlineStatusManager::Online,Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
BSY( Kopete::OnlineStatus::Away, 20, this, 2, "msn_busy", i18n( "Busy" ) , i18n( "&Busy" ), Kopete::OnlineStatusManager::Busy, Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
BRB( Kopete::OnlineStatus::Away, 22, this, 3, "msn_brb", i18n( "Be Right Back" ), i18n( "Be &Right Back" ) , 0 , Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
AWY( Kopete::OnlineStatus::Away, 18, this, 4, "contact_away_overlay", i18n( "Away From Computer" ),i18n( "&Away" ), Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
PHN( Kopete::OnlineStatus::Away, 12, this, 5, "contact_phone_overlay", i18n( "On the Phone" ) , i18n( "On The &Phone" ) , 0 , Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
LUN( Kopete::OnlineStatus::Away, 15, this, 6, "contact_food_overlay", i18n( "Out to Lunch" ) , i18n( "Out To &Lunch" ) , 0 , Kopete::OnlineStatusManager::HasAwayMessage ),
|
||||||
|
FLN( Kopete::OnlineStatus::Offline, 0, this, 7, TQString(), i18n( "Offline" ) , i18n( "&Offline" ), Kopete::OnlineStatusManager::Offline,Kopete::OnlineStatusManager::DisabledIfOffline ),
|
||||||
|
HDN( Kopete::OnlineStatus::Invisible, 3, this, 8, "contact_invisible_overlay", i18n( "Invisible" ) , i18n( "&Invisible" ), Kopete::OnlineStatusManager::Invisible ),
|
||||||
|
IDL( Kopete::OnlineStatus::Away, 10, this, 9, "contact_away_overlay", i18n( "Idle" ) , i18n( "&Idle" ), Kopete::OnlineStatusManager::Idle , Kopete::OnlineStatusManager::HideFromMenu ),
|
||||||
|
UNK( Kopete::OnlineStatus::Unknown, 25, this, 0, "status_unknown", i18n( "Status not available" ) ),
|
||||||
|
CNT( Kopete::OnlineStatus::Connecting, 2, this, 10,"msn_connecting", i18n( "Connecting" ) ),
|
||||||
|
propEmail(Kopete::Global::Properties::self()->emailAddress()),
|
||||||
|
propPhoneHome(Kopete::Global::Properties::self()->privatePhone()),
|
||||||
|
propPhoneWork(Kopete::Global::Properties::self()->workPhone()),
|
||||||
|
propPhoneMobile(Kopete::Global::Properties::self()->privateMobilePhone()),
|
||||||
|
propClient("client", i18n("Remote Client"), 0, false),
|
||||||
|
propGuid("guid", i18n("Contact GUID"), 0, true),
|
||||||
|
propPersonalMessage(Kopete::Global::Properties::self()->awayMessage())
|
||||||
|
{
|
||||||
|
s_protocol = this;
|
||||||
|
|
||||||
|
addAddressBookField( "messaging/msn", Kopete::Plugin::MakeIndexField );
|
||||||
|
|
||||||
|
setCapabilities( Kopete::Protocol::BaseFgColor | Kopete::Protocol::BaseFont | Kopete::Protocol::BaseFormatting );
|
||||||
|
|
||||||
|
// m_status = m_unknownStatus = UNK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::Contact *MSNProtocol::deserializeContact( Kopete::MetaContact *metaContact, const TQMap<TQString, TQString> &serializedData,
|
||||||
|
const TQMap<TQString, TQString> & /* addressBookData */ )
|
||||||
|
{
|
||||||
|
TQString contactId = serializedData[ "contactId" ] ;
|
||||||
|
TQString accountId = serializedData[ "accountId" ] ;
|
||||||
|
TQString lists = serializedData[ "lists" ];
|
||||||
|
TQStringList groups = TQStringList::split( ",", serializedData[ "groups" ] );
|
||||||
|
TQString contactGuid = serializedData[ "contactGuid" ] ;
|
||||||
|
|
||||||
|
TQDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts( this );
|
||||||
|
|
||||||
|
Kopete::Account *account = accounts[ accountId ];
|
||||||
|
if( !account )
|
||||||
|
account = createNewAccount( accountId );
|
||||||
|
|
||||||
|
// Create MSN contact
|
||||||
|
MSNContact *c = new MSNContact( account, contactId, metaContact );
|
||||||
|
|
||||||
|
for( TQStringList::Iterator it = groups.begin() ; it != groups.end(); ++it )
|
||||||
|
c->contactAddedToGroup( *it, 0L /* FIXME - m_groupList[ ( *it ).toUInt() ]*/ );
|
||||||
|
|
||||||
|
c->m_obj= serializedData[ "obj" ];
|
||||||
|
c->setInfo( "PHH" , serializedData[ "PHH" ] );
|
||||||
|
c->setInfo( "PHW" , serializedData[ "PHW" ] );
|
||||||
|
c->setInfo( "PHM" , serializedData[ "PHM" ] );
|
||||||
|
c->setProperty( propGuid, contactGuid );
|
||||||
|
|
||||||
|
c->setBlocked( (bool)(lists.contains('B')) );
|
||||||
|
c->setAllowed( (bool)(lists.contains('A')) );
|
||||||
|
c->setReversed( (bool)(lists.contains('R')) );
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddContactPage *MSNProtocol::createAddContactWidget(TQWidget *parent , Kopete::Account *i)
|
||||||
|
{
|
||||||
|
return (new MSNAddContactPage(i->isConnected(),parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
KopeteEditAccountWidget *MSNProtocol::createEditAccountWidget(Kopete::Account *account, TQWidget *parent)
|
||||||
|
{
|
||||||
|
return new MSNEditAccountWidget(this,account,parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::Account *MSNProtocol::createNewAccount(const TQString &accountId)
|
||||||
|
{
|
||||||
|
return new MSNAccount(this, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: CALL THIS ONLY BEING CONNECTED
|
||||||
|
void MSNProtocol::slotSyncContactList()
|
||||||
|
{
|
||||||
|
/* if ( ! mIsConnected )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// First, delete D marked contacts
|
||||||
|
TQStringList localcontacts;
|
||||||
|
|
||||||
|
contactsFile->setGroup("Default");
|
||||||
|
|
||||||
|
contactsFile->readListEntry("Contacts",localcontacts);
|
||||||
|
TQString tmpUin;
|
||||||
|
tmpUin.sprintf("%d",uin);
|
||||||
|
tmp.append(tmpUin);
|
||||||
|
cnt=contactsFile->readNumEntry("Count",0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNProtocol* MSNProtocol::protocol()
|
||||||
|
{
|
||||||
|
return s_protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNProtocol::validContactId(const TQString& userid)
|
||||||
|
{
|
||||||
|
return ( userid.contains('@') ==1 && userid.contains('.') >=1 && userid.contains(' ') == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQImage MSNProtocol::scalePicture(const TQImage &picture)
|
||||||
|
{
|
||||||
|
TQImage img(picture);
|
||||||
|
img = img.smoothScale( 96, 96, TQ_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
#include "msnprotocol.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
msnprotocol.h - Kopete MSN Protocol Plugin
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
||||||
|
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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 __msnprotocol_h__
|
||||||
|
#define __msnprotocol_h__
|
||||||
|
|
||||||
|
#include <tqmap.h>
|
||||||
|
#include <tqstringlist.h>
|
||||||
|
|
||||||
|
#include "kopeteprotocol.h"
|
||||||
|
#include "kopeteonlinestatus.h"
|
||||||
|
#include "kopetecontactproperty.h"
|
||||||
|
|
||||||
|
#include "msnsocket.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TQImage;
|
||||||
|
|
||||||
|
class TDEAction;
|
||||||
|
class TDEActionMenu;
|
||||||
|
|
||||||
|
class MSNContact;
|
||||||
|
class MSNAccount;
|
||||||
|
class MSNNotifySocket;
|
||||||
|
class MSNSwitchBoardSocket;
|
||||||
|
class MSNChatSession;
|
||||||
|
class MSNInvitation;
|
||||||
|
namespace Kopete { class ChatSession; }
|
||||||
|
namespace Kopete { class MetaContact; }
|
||||||
|
namespace Kopete { class Contact; }
|
||||||
|
namespace Kopete { class Message; }
|
||||||
|
namespace Kopete { class Group; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author duncan
|
||||||
|
* @author Martijn Klingens <klingens@kde.org>
|
||||||
|
* @author Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
*/
|
||||||
|
class KOPETE_EXPORT MSNProtocol : public Kopete::Protocol
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNProtocol( TQObject *parent, const char *name, const TQStringList &args );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SyncMode indicates whether settings differing between client and
|
||||||
|
* server should be propagated to keep them in sync.
|
||||||
|
* SyncToServer - Ignore the server setting when sent. Instead, push
|
||||||
|
* the local setting to the server. Used when changing
|
||||||
|
* settings offline.
|
||||||
|
* SyncFromServer - Update locally stored settings with the value sent
|
||||||
|
* by the server. Used when connecting to the server if
|
||||||
|
* no offline changes are pending to force a sync.
|
||||||
|
* SyncBoth - Changes are updated both ways. This is truly a
|
||||||
|
* 'first come, first serve' scenario, which breaks if
|
||||||
|
* the 'old' value is sent by one peer before the other
|
||||||
|
* end is able to push the new value. An example of this
|
||||||
|
* is changing the MSN nickname offline - the server can
|
||||||
|
* only be updated after it has sent the old value to
|
||||||
|
* the client during connect, destroying the new setting.
|
||||||
|
* Once connected this is often the most useful setting.
|
||||||
|
* DontSync - Do not sync values at all. This is used if settings
|
||||||
|
* are overridden locally, but should not be sent to the
|
||||||
|
* server, nor should the client update server-pushed
|
||||||
|
* values. This can be useful for e.g. contact lists.
|
||||||
|
*/
|
||||||
|
enum SyncMode
|
||||||
|
{
|
||||||
|
DontSync = 0x00,
|
||||||
|
SyncToServer = 0x01,
|
||||||
|
SyncFromServer = 0x02,
|
||||||
|
SyncBoth = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The possible MSN online statuses
|
||||||
|
*/
|
||||||
|
const Kopete::OnlineStatus NLN; //online
|
||||||
|
const Kopete::OnlineStatus BSY; //busy
|
||||||
|
const Kopete::OnlineStatus BRB; //be right back
|
||||||
|
const Kopete::OnlineStatus AWY; //away
|
||||||
|
const Kopete::OnlineStatus PHN; //on the phone
|
||||||
|
const Kopete::OnlineStatus LUN; //out to lunch
|
||||||
|
const Kopete::OnlineStatus FLN; //offline
|
||||||
|
const Kopete::OnlineStatus HDN; //invisible
|
||||||
|
const Kopete::OnlineStatus IDL; //idle
|
||||||
|
const Kopete::OnlineStatus UNK; //inknown (internal)
|
||||||
|
const Kopete::OnlineStatus CNT; //connecting (internal)
|
||||||
|
|
||||||
|
const Kopete::ContactPropertyTmpl propEmail;
|
||||||
|
const Kopete::ContactPropertyTmpl propPhoneHome;
|
||||||
|
const Kopete::ContactPropertyTmpl propPhoneWork;
|
||||||
|
const Kopete::ContactPropertyTmpl propPhoneMobile;
|
||||||
|
const Kopete::ContactPropertyTmpl propClient;
|
||||||
|
const Kopete::ContactPropertyTmpl propGuid;
|
||||||
|
const Kopete::ContactPropertyTmpl propPersonalMessage; // it's the equivalent of away message.
|
||||||
|
|
||||||
|
enum List
|
||||||
|
{
|
||||||
|
FL, // forward
|
||||||
|
AL, // allow
|
||||||
|
BL, // blocked
|
||||||
|
RL, // reverse
|
||||||
|
PL // pending
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enums used to build the Kopete's MSN ClientId.
|
||||||
|
enum MSNClientInformationFields
|
||||||
|
{
|
||||||
|
WindowsMobile = 0x1,
|
||||||
|
InkFormatGIF = 0x04,
|
||||||
|
InkFormatISF = 0x08,
|
||||||
|
SupportWebcam = 0x10,
|
||||||
|
SupportMultiPacketMessaging = 0x20,
|
||||||
|
MSNMobileDevice = 0x40,
|
||||||
|
MSNDirectDevice = 0x80,
|
||||||
|
WebMessenger = 0x100,
|
||||||
|
SupportDirectIM = 0x4000,
|
||||||
|
SupportWinks = 0x8000,
|
||||||
|
MSNC1 = 0x10000000,
|
||||||
|
MSNC2 = 0x20000000,
|
||||||
|
MSNC3 = 0x30000000,
|
||||||
|
MSNC4 = 0x40000000
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PersonalMessageType
|
||||||
|
{
|
||||||
|
PersonalMessageNormal,
|
||||||
|
PersonalMessageMusic,
|
||||||
|
PersonalMessageGame,
|
||||||
|
PersonalMessageOffice
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual Kopete::Contact *deserializeContact( Kopete::MetaContact *metaContact,
|
||||||
|
const TQMap<TQString, TQString> &serializedData, const TQMap<TQString, TQString> &addressBookData );
|
||||||
|
|
||||||
|
virtual AddContactPage *createAddContactWidget( TQWidget *parent , Kopete::Account *i);
|
||||||
|
virtual KopeteEditAccountWidget *createEditAccountWidget(Kopete::Account *account, TQWidget *parent);
|
||||||
|
virtual Kopete::Account *createNewAccount(const TQString &accountId);
|
||||||
|
|
||||||
|
static MSNProtocol* protocol();
|
||||||
|
static bool validContactId(const TQString&);
|
||||||
|
TQImage scalePicture(const TQImage &picture);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotSyncContactList();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static MSNProtocol *s_protocol;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* A new msn invitation has been arrived. plugins can connect this signal to handle invitations.
|
||||||
|
* if the invitationID match to their internal id. they can create a new MSNInvitation and pass it via invitation
|
||||||
|
*
|
||||||
|
* @param invitation should be set by the plugin to the new invitaiton. plugin should check it is equal to 0L before
|
||||||
|
* @param bodyMSG is the whole invitation message
|
||||||
|
* @param cookie is the invitation cookie
|
||||||
|
* @param msnMM is the message manager
|
||||||
|
* @param c is the contact
|
||||||
|
*/
|
||||||
|
void invitation(MSNInvitation*& invitation, const TQString &bodyMSG , long unsigned int cookie , MSNChatSession* msnMM , MSNContact* c );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
msnsecureloginhandler.cpp - SSL login for MSN protocol
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 "msnsecureloginhandler.h"
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqregexp.h>
|
||||||
|
|
||||||
|
// KDE includes
|
||||||
|
#include <tdeio/job.h>
|
||||||
|
#include <kurl.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
|
||||||
|
MSNSecureLoginHandler::MSNSecureLoginHandler(const TQString &accountId, const TQString &password, const TQString &authParameters)
|
||||||
|
: m_password(password), m_accountId(accountId), m_authentification(authParameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNSecureLoginHandler::~MSNSecureLoginHandler()
|
||||||
|
{
|
||||||
|
// kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNSecureLoginHandler::login()
|
||||||
|
{
|
||||||
|
// Retrive the login server.
|
||||||
|
// Do a reload and don't show the progress.
|
||||||
|
TDEIO::Job *getLoginServer = TDEIO::get(KURL("https://nexus.passport.com/rdr/pprdr.asp"), true, false);
|
||||||
|
|
||||||
|
getLoginServer->addMetaData("cookies", "manual");
|
||||||
|
getLoginServer->addMetaData("cache", "reload");
|
||||||
|
getLoginServer->addMetaData("PropagateHttpHeader", "true");
|
||||||
|
|
||||||
|
connect(getLoginServer, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotLoginServerReceived(TDEIO::Job* )));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNSecureLoginHandler::slotLoginServerReceived(TDEIO::Job *loginJob)
|
||||||
|
{
|
||||||
|
if(!loginJob->error())
|
||||||
|
{
|
||||||
|
// Retrive the HTTP header
|
||||||
|
TQString httpHeaders = loginJob->queryMetaData("HTTP-Headers");
|
||||||
|
|
||||||
|
// Get the login URL using TQRegExp
|
||||||
|
TQRegExp rx("PassportURLs: DARealm=(.*),DALogin=(.*),DAReg=");
|
||||||
|
rx.search(httpHeaders);
|
||||||
|
|
||||||
|
// Set the loginUrl and loginServer
|
||||||
|
TQString loginUrl = rx.cap(2);
|
||||||
|
TQString loginServer = loginUrl.section('/', 0, 0);
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << loginServer << endl;
|
||||||
|
|
||||||
|
TQString authURL = "https://" + loginUrl;
|
||||||
|
|
||||||
|
TDEIO::Job *authJob = TDEIO::get(KURL(authURL), true, false);
|
||||||
|
authJob->addMetaData("cookies", "manual");
|
||||||
|
|
||||||
|
TQString authRequest = "Authorization: Passport1.4 "
|
||||||
|
"OrgVerb=GET,"
|
||||||
|
"OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,"
|
||||||
|
"sign-in=" + KURL::encode_string(m_accountId) +
|
||||||
|
",pwd=" + KURL::encode_string( m_password ).replace(',',"%2C") +
|
||||||
|
"," + m_authentification + "\r\n";
|
||||||
|
|
||||||
|
// warning, this debug contains the password
|
||||||
|
// kdDebug(14140) << k_funcinfo << "Auth request: " << authRequest << endl;
|
||||||
|
|
||||||
|
authJob->addMetaData("customHTTPHeader", authRequest);
|
||||||
|
authJob->addMetaData("SendLanguageSettings", "false");
|
||||||
|
authJob->addMetaData("PropagateHttpHeader", "true");
|
||||||
|
authJob->addMetaData("cookies", "manual");
|
||||||
|
authJob->addMetaData("cache", "reload");
|
||||||
|
|
||||||
|
connect(authJob, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotTweenerReceived(TDEIO::Job* )));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << loginJob->errorString() << endl;
|
||||||
|
|
||||||
|
emit loginFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNSecureLoginHandler::slotTweenerReceived(TDEIO::Job *authJob)
|
||||||
|
{
|
||||||
|
if(!authJob->error())
|
||||||
|
{
|
||||||
|
TQString httpHeaders = authJob->queryMetaData("HTTP-Headers");
|
||||||
|
|
||||||
|
// kdDebug(14140) << k_funcinfo << "HTTP headers: " << httpHeaders << endl;
|
||||||
|
|
||||||
|
// Check if we get "401 Unauthorized", thats means it's a bad password.
|
||||||
|
if(httpHeaders.contains(TQString::fromUtf8("401 Unauthorized")))
|
||||||
|
{
|
||||||
|
// kdDebug(14140) << k_funcinfo << "MSN Login Bad password." << endl;
|
||||||
|
emit loginBadPassword();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TQRegExp rx("from-PP='(.*)'");
|
||||||
|
rx.search(httpHeaders);
|
||||||
|
TQString ticket = rx.cap(1);
|
||||||
|
|
||||||
|
// kdDebug(14140) << k_funcinfo << "Received ticket: " << ticket << endl;
|
||||||
|
|
||||||
|
emit loginSuccesful(ticket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << authJob->errorString() << endl;
|
||||||
|
|
||||||
|
emit loginFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#include "msnsecureloginhandler.moc"
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
msnsecureloginhandler.h - SSL login for MSN protocol
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 MSNSECURELOGINHANDLER_H
|
||||||
|
#define MSNSECURELOGINHANDLER_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
|
||||||
|
namespace TDEIO
|
||||||
|
{
|
||||||
|
class Job;
|
||||||
|
class MetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class handle the login process. It connect to the .NET Password service and retrive the ticket(tweener) to login.
|
||||||
|
* Use TDEIO.
|
||||||
|
*
|
||||||
|
* @author Michaël Larouche <michael.larouche@kdemail.net>
|
||||||
|
*/
|
||||||
|
class MSNSecureLoginHandler : public TQObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNSecureLoginHandler(const TQString &accountId, const TQString &password, const TQString &authParameters);
|
||||||
|
|
||||||
|
~MSNSecureLoginHandler();
|
||||||
|
|
||||||
|
void login();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* TODO: return to const TQString &
|
||||||
|
*/
|
||||||
|
void loginSuccesful(TQString ticket);
|
||||||
|
void loginBadPassword();
|
||||||
|
void loginFailed();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotLoginServerReceived(TDEIO::Job *);
|
||||||
|
/**
|
||||||
|
* We have received our ticket to login.
|
||||||
|
*/
|
||||||
|
void slotTweenerReceived(TDEIO::Job *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Store the password.
|
||||||
|
*/
|
||||||
|
TQString m_password;
|
||||||
|
/**
|
||||||
|
* Store the accountId.
|
||||||
|
*/
|
||||||
|
TQString m_accountId;
|
||||||
|
/**
|
||||||
|
* Store the authentification parameters
|
||||||
|
*/
|
||||||
|
TQString m_authentification;
|
||||||
|
|
||||||
|
void displayMetaData(TDEIO::MetaData data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
msnsocket.h - Base class for the sockets used in MSN
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2004 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions of this code are taken from KMerlin,
|
||||||
|
(c) 2001 by Olaf Lueg <olueg@olsd.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 MSNSOCKET_H
|
||||||
|
#define MSNSOCKET_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <tqdatastream.h>
|
||||||
|
#include <tqstringlist.h>
|
||||||
|
#include <tqtimer.h>
|
||||||
|
#include <tqvaluelist.h>
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
namespace KNetwork {
|
||||||
|
class TDEBufferedSocket;
|
||||||
|
class TDEServerSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MimeMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Martijn Klingens <klingens@kde.org>
|
||||||
|
*
|
||||||
|
* MSNSocket encapsulates the common functionality shared by the Dispatch
|
||||||
|
* Server, the Notification Server and the Switchboard Server. It is
|
||||||
|
* inherited by the various specialized classes.
|
||||||
|
*/
|
||||||
|
class KOPETE_EXPORT MSNSocket : public TQObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNSocket(TQObject* parent=0l);
|
||||||
|
~MSNSocket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously read a block of data of the specified size. When the
|
||||||
|
* data is available, the blockRead() signal will be emitted with the
|
||||||
|
* data as parameter.
|
||||||
|
*
|
||||||
|
* NOTE: As the block queue takes precedence over the line-based
|
||||||
|
* command-processing this method can effectively block all
|
||||||
|
* communications when passed a wrong length!
|
||||||
|
*/
|
||||||
|
void readBlock( uint len );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnlineStatus encapsulates the 4 states a connection can be in,
|
||||||
|
* Connecting, Connected, Disconnecting, Disconnected. Connecting
|
||||||
|
* and Disconnecting are in the default implementation not used,
|
||||||
|
* because the socket connect is an atomic operation and not yet
|
||||||
|
* performed asynchronously.
|
||||||
|
* In derived classes, like the Notification Server, this state is
|
||||||
|
* actively used, because merely having a socket connection established
|
||||||
|
* by no means indicates we're actually online - the rest of the
|
||||||
|
* handshake likely has to follow first.
|
||||||
|
*/
|
||||||
|
enum OnlineStatus { Connecting, Connected, Disconnecting, Disconnected };
|
||||||
|
enum LookupStatus { Processing, Success, Failed };
|
||||||
|
enum Transport { TcpTransport, HttpTransport };
|
||||||
|
enum ErrorType { ErrorConnectionLost, ErrorConnectionError, ErrorCannotConnect, ErrorServerError, ErrorInformation};
|
||||||
|
|
||||||
|
OnlineStatus onlineStatus() { return m_onlineStatus; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return the local ip.
|
||||||
|
* Used for filetransfer
|
||||||
|
*/
|
||||||
|
TQString getLocalIP();
|
||||||
|
|
||||||
|
//BEGIN Http
|
||||||
|
|
||||||
|
virtual bool setUseHttpMethod( bool useHttp );
|
||||||
|
bool useHttpMethod() const;
|
||||||
|
|
||||||
|
//END
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void connect( const TQString &server, uint port );
|
||||||
|
virtual void disconnect();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an MSN command to the socket
|
||||||
|
*
|
||||||
|
* For debugging it's convenient to have this method public, but using
|
||||||
|
* it outside this class is deprecated for any other use!
|
||||||
|
*
|
||||||
|
* The size of the body (if any) is automatically added to the argument
|
||||||
|
* list and shouldn't be explicitly specified! This size is in bytes
|
||||||
|
* instead of characters to reflect what actually goes over the wire.
|
||||||
|
*
|
||||||
|
* if the param binary is set to true, then, the body is send as a binary message
|
||||||
|
*
|
||||||
|
* return the id
|
||||||
|
*/
|
||||||
|
int sendCommand( const TQString &cmd, const TQString &args = TQString(),
|
||||||
|
bool addId = true, const TQByteArray &body = TQByteArray() , bool binary=false );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* A block read is ready.
|
||||||
|
* After this the normal line-based reads go on again
|
||||||
|
*/
|
||||||
|
void blockRead( const TQByteArray &block );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The online status has changed
|
||||||
|
*/
|
||||||
|
void onlineStatusChanged( MSNSocket::OnlineStatus status );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection failed
|
||||||
|
*/
|
||||||
|
void connectionFailed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection was closed
|
||||||
|
*/
|
||||||
|
void socketClosed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A error has occured. Handle the display of the message.
|
||||||
|
*/
|
||||||
|
void errorMessage( int type, const TQString &msg );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Convenience method: escape spaces with '%20' for use in the protocol.
|
||||||
|
* Doesn't escape any other sequence.
|
||||||
|
*/
|
||||||
|
TQString escape( const TQString &str );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* And the other way round...
|
||||||
|
*/
|
||||||
|
TQString unescape( const TQString &str );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the online status. Emits onlineStatusChanged.
|
||||||
|
*/
|
||||||
|
void setOnlineStatus( OnlineStatus status );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called directly before the socket will actually connect.
|
||||||
|
* Override in derived classes to setup whatever is needed before connect.
|
||||||
|
*/
|
||||||
|
virtual void aboutToConnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directly after the connect, this method is called. The default
|
||||||
|
* implementation sets the OnlineStatus to Connected, be sure to override
|
||||||
|
* this if a handshake is required.
|
||||||
|
*/
|
||||||
|
virtual void doneConnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directly after the disconnect, this method is called before the actual
|
||||||
|
* cleanup takes place. The socket is close here. Cleanup internal
|
||||||
|
* variables here.
|
||||||
|
*/
|
||||||
|
virtual void doneDisconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an MSN error condition.
|
||||||
|
* The default implementation displays a generic error message and
|
||||||
|
* closes the connection. Override to allow more graceful handling and
|
||||||
|
* possibly recovery.
|
||||||
|
*/
|
||||||
|
virtual void handleError( uint code, uint id );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an MSN command response line.
|
||||||
|
* This method is pure virtual and *must* be overridden in derived
|
||||||
|
* classes.
|
||||||
|
*/
|
||||||
|
virtual void parseCommand( const TQString &cmd, uint id,
|
||||||
|
const TQString &data ) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in MSNFileTransferSocket
|
||||||
|
*/
|
||||||
|
virtual void bytesReceived( const TQByteArray & );
|
||||||
|
bool accept( KNetwork::TDEServerSocket * );
|
||||||
|
void sendBytes( const TQByteArray &data );
|
||||||
|
|
||||||
|
const TQString &server() { return m_server; }
|
||||||
|
uint port() { return m_port; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last confirmed ID by the server
|
||||||
|
*/
|
||||||
|
//uint m_lastId;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotDataReceived();
|
||||||
|
/**
|
||||||
|
* If the socket emits a connectionFailed() then this slot is called
|
||||||
|
* to handle the error.
|
||||||
|
*/
|
||||||
|
void slotSocketError( int error );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls connectDone() when connection is successfully established.
|
||||||
|
*/
|
||||||
|
void slotConnectionSuccess();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets m_lookupProgress to 'Finished' if count > 0 or 'Failed' if count = 0.
|
||||||
|
*/
|
||||||
|
void slotHostFound( );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if new lines of data are available and process the first line
|
||||||
|
*/
|
||||||
|
void slotReadLine();
|
||||||
|
|
||||||
|
void slotSocketClosed();
|
||||||
|
|
||||||
|
//BEGIN Http
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a poll request to the msn gateway when using HttpTransport.
|
||||||
|
* equivalent to sending a PNG command over TcpTransport.
|
||||||
|
*/
|
||||||
|
void slotHttpPoll();
|
||||||
|
|
||||||
|
//END
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void slotReadyWrite();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Check if we're waiting for a block of raw data. Emits blockRead()
|
||||||
|
* when the data is available.
|
||||||
|
* Returns true when still waiting and false when there is no pending
|
||||||
|
* read, or when the read is successfully handled.
|
||||||
|
*/
|
||||||
|
bool pollReadBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the message sent to the MSN server. This ID will increment
|
||||||
|
* for each subsequent message sent.
|
||||||
|
*/
|
||||||
|
uint m_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue of pending commands (should be mostly empty, but is needed to
|
||||||
|
* send more than one command to the server)
|
||||||
|
*/
|
||||||
|
TQValueList<TQByteArray> m_sendQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a single line of data.
|
||||||
|
* Will call either parseCommand or handleError depending on the type of
|
||||||
|
* data received.
|
||||||
|
*/
|
||||||
|
void parseLine( const TQString &str );
|
||||||
|
|
||||||
|
KNetwork::TDEBufferedSocket *m_socket;
|
||||||
|
OnlineStatus m_onlineStatus;
|
||||||
|
|
||||||
|
TQString m_server;
|
||||||
|
uint m_port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the requested block for block-based reads
|
||||||
|
*/
|
||||||
|
uint m_waitBlockSize;
|
||||||
|
|
||||||
|
class Buffer : public TQByteArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Buffer( unsigned size = 0 );
|
||||||
|
~Buffer();
|
||||||
|
void add( char *str, unsigned size );
|
||||||
|
TQByteArray take( unsigned size );
|
||||||
|
};
|
||||||
|
|
||||||
|
Buffer m_buffer;
|
||||||
|
|
||||||
|
//BEGIN Http
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a http request headers string using the specified, host, query, and content length.
|
||||||
|
* return: The string containing the http request headers.
|
||||||
|
*/
|
||||||
|
TQString makeHttpRequestString(const TQString& host, const TQString& query, uint contentLength);
|
||||||
|
|
||||||
|
bool m_useHttp; // Indicates whether to use the msn http gateway to connect to the msn service.
|
||||||
|
bool m_bCanPoll; // Indicates whether polling of the http server is allowed.
|
||||||
|
bool m_bIsFirstInTransaction; // Indicates whether pending message to be sent is the first in the transaction.
|
||||||
|
// If so, the gateway is used.
|
||||||
|
// Use the gateway only for initial connected state; Otherwise, use the host.
|
||||||
|
TQString m_gateway; // Msn http gateway domain name.
|
||||||
|
TQString m_gwip; // The ip address of the msn gateway.
|
||||||
|
TQString m_sessionId; // session id.
|
||||||
|
TQTimer *m_timer; // Msn http poll timer.
|
||||||
|
TQString m_type; // Indicates the type of socket being used. NS or SB
|
||||||
|
bool m_pending; // Indicates whether a http response is pending.
|
||||||
|
int m_remaining; // Indicates how many bytes of content data remain
|
||||||
|
// to be received if the content bytes are sent in
|
||||||
|
// a seperate packet(s).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to information returned from a URI request.
|
||||||
|
*/
|
||||||
|
class WebResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebResponse(const TQByteArray& bytes);
|
||||||
|
~WebResponse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the headers associated with this response from the server.
|
||||||
|
*/
|
||||||
|
MimeMessage* getHeaders();
|
||||||
|
/**
|
||||||
|
* Gets the data stream used to read the body of the response from the server.
|
||||||
|
*/
|
||||||
|
TQDataStream* getResponseStream();
|
||||||
|
/**
|
||||||
|
* Gets the status code of the response.
|
||||||
|
*/
|
||||||
|
int getStatusCode();
|
||||||
|
/**
|
||||||
|
* Gets the status description returned with the response.
|
||||||
|
*/
|
||||||
|
TQString getStatusDescription();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MimeMessage *m_headers;
|
||||||
|
TQDataStream *m_stream;
|
||||||
|
int m_statusCode;
|
||||||
|
TQString m_statusDescription;
|
||||||
|
};
|
||||||
|
|
||||||
|
//END
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
msnswitchboardsocket.h - switch board connection socket
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
|
||||||
|
Copyright (c) 2002-2006 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
|
||||||
|
|
||||||
|
Portions of this code are taken from KMerlin,
|
||||||
|
(c) 2001 by Olaf Lueg <olueg@olsd.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 MSNSWITCHBOARDSOCKET_H
|
||||||
|
#define MSNSWITCHBOARDSOCKET_H
|
||||||
|
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <tqstrlist.h>
|
||||||
|
#include <tqvaluevector.h>
|
||||||
|
|
||||||
|
#include <kstringhandler.h>
|
||||||
|
|
||||||
|
#include "msnsocket.h"
|
||||||
|
|
||||||
|
namespace Kopete { class Message; }
|
||||||
|
class MSNAccount;
|
||||||
|
class TQTimer;
|
||||||
|
|
||||||
|
class MSNP2PDisplatcher;
|
||||||
|
class KTempFile;
|
||||||
|
|
||||||
|
namespace P2P { class Dispatcher; }
|
||||||
|
|
||||||
|
#include "dispatcher.h"
|
||||||
|
|
||||||
|
class KOPETE_EXPORT MSNSwitchBoardSocket : public MSNSocket
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Contructor: id is the KopeteMessageMangager's id
|
||||||
|
*/
|
||||||
|
MSNSwitchBoardSocket( MSNAccount * account , TQObject *parent);
|
||||||
|
~MSNSwitchBoardSocket();
|
||||||
|
|
||||||
|
private:
|
||||||
|
P2P::Dispatcher *m_dispatcher;
|
||||||
|
MSNAccount *m_account;
|
||||||
|
|
||||||
|
TQString m_myHandle; // our handle
|
||||||
|
|
||||||
|
// contains the handle of the last person that msg'ed us.
|
||||||
|
// since we receive the actual message by readBlock(), we need
|
||||||
|
// to remember what the handle was of the person sending us the message.
|
||||||
|
TQString m_msgHandle;
|
||||||
|
|
||||||
|
TQString m_ID;
|
||||||
|
TQString m_auth;
|
||||||
|
TQStringList m_chatMembers;
|
||||||
|
|
||||||
|
//used for emoticons
|
||||||
|
TQValueList<const Kopete::Message> m_msgQueue;
|
||||||
|
unsigned m_recvIcons;
|
||||||
|
TQMap<TQString , TQPair<TQString , KTempFile*> > m_emoticons;
|
||||||
|
Kopete::Message &parseCustomEmoticons(Kopete::Message &msg);
|
||||||
|
TQTimer *m_emoticonTimer;
|
||||||
|
TQPtrList<KTempFile> m_typewrited;
|
||||||
|
|
||||||
|
struct InkMessage{
|
||||||
|
TQ_UINT32 chunks;
|
||||||
|
TQString data;
|
||||||
|
};
|
||||||
|
TQMap<TQString, InkMessage> m_inkMessageBuffer;
|
||||||
|
|
||||||
|
/** the number of chunk for currents messages */
|
||||||
|
unsigned int m_chunks;
|
||||||
|
|
||||||
|
/** true is we already sent the x-clientcaps message */
|
||||||
|
bool m_clientcapsSent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DispatchInkMessage(const TQString &base64String);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Handle an MSN command response line.
|
||||||
|
*/
|
||||||
|
virtual void parseCommand( const TQString &cmd, uint id,
|
||||||
|
const TQString &data );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle exceptions that might occur during a chat.
|
||||||
|
*/
|
||||||
|
virtual void handleError( uint code, uint id );
|
||||||
|
|
||||||
|
TQString parseFontAttr( TQString str, TQString attr );
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
void connectToSwitchBoard( TQString ID, TQString address, TQString auth );
|
||||||
|
void setHandle( TQString handle ) { m_myHandle = handle; }
|
||||||
|
void setMsgHandle( TQString handle ) { m_msgHandle = handle; }
|
||||||
|
|
||||||
|
const TQStringList &chatMembers() { return m_chatMembers; }
|
||||||
|
|
||||||
|
void userLeftChat( const TQString &handle , const TQString &reason );
|
||||||
|
int sendMsg( const Kopete::Message &msg );
|
||||||
|
int sendCustomEmoticon(const TQString &name, const TQString &filename);
|
||||||
|
|
||||||
|
int sendNudge();
|
||||||
|
|
||||||
|
P2P::Dispatcher* PeerDispatcher();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotCloseSession();
|
||||||
|
void slotInviteContact(const TQString &handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the server that the user is typing a message
|
||||||
|
*/
|
||||||
|
void sendTypingMsg( bool isTyping );
|
||||||
|
|
||||||
|
void requestDisplayPicture();
|
||||||
|
|
||||||
|
/** workaround Bug 113425 . see slotKeepAliveTimer() **/
|
||||||
|
TQTimer *m_keepAlive;
|
||||||
|
int m_keepAliveNb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotOnlineStatusChanged( MSNSocket::OnlineStatus status );
|
||||||
|
void slotSocketClosed( );
|
||||||
|
void slotReadMessage( const TQByteArray &bytes );
|
||||||
|
void slotEmoticonReceived( KTempFile *, const TQString& );
|
||||||
|
void slotIncomingFileTransfer(const TQString& from, const TQString& fileName, TQ_INT64 fileSize);
|
||||||
|
void cleanQueue();
|
||||||
|
|
||||||
|
/** workaround Bug 113425 . see comment inside the function **/
|
||||||
|
void slotKeepAliveTimer();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void msgReceived( Kopete::Message &msg );
|
||||||
|
void receivedTypingMsg( const TQString &contactId, bool isTyping );
|
||||||
|
void msgAcknowledgement(unsigned int, bool);
|
||||||
|
void userJoined(const TQString& handle , const TQString &publicName , bool IRO);
|
||||||
|
void userLeft(const TQString& handle , const TQString &reason);
|
||||||
|
void nudgeReceived(const TQString &handle);
|
||||||
|
|
||||||
|
void switchBoardClosed( );
|
||||||
|
void invitation(const TQString& handle, const TQString& msg);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,432 @@
|
|||||||
|
/*
|
||||||
|
outgoingtransfer.cpp - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 "outgoingtransfer.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Kde includes
|
||||||
|
#include <kbufferedsocket.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <kmdcodec.h>
|
||||||
|
using namespace KNetwork;
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqfile.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <tqtimer.h>
|
||||||
|
|
||||||
|
// Kopete includes
|
||||||
|
#include <kopetetransfermanager.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h> // For htonl
|
||||||
|
using P2P::TransferContext;
|
||||||
|
using P2P::Dispatcher;
|
||||||
|
using P2P::OutgoingTransfer;
|
||||||
|
using P2P::Message;
|
||||||
|
|
||||||
|
OutgoingTransfer::OutgoingTransfer(const TQString& to, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId)
|
||||||
|
: TransferContext(to,dispatcher,sessionId)
|
||||||
|
{
|
||||||
|
m_direction = Outgoing;
|
||||||
|
m_handshake = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutgoingTransfer::~OutgoingTransfer()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::sendImage(const TQByteArray& image)
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO TQByteArray base64 = KCodecs::base64Encode(image);
|
||||||
|
//
|
||||||
|
// TQCString 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;
|
||||||
|
// outbound.header.dataOffset = 0;
|
||||||
|
// outbound.header.totalDataSize = 4;
|
||||||
|
// outbound.header.dataSize = 4;
|
||||||
|
// outbound.header.flag = 0;
|
||||||
|
// outbound.header.ackSessionIdentifier = rand()%0x8FFFFFF0 + 4;
|
||||||
|
// outbound.header.ackUniqueIdentifier = 0;
|
||||||
|
// outbound.header.ackDataSize = 0l;
|
||||||
|
// TQByteArray bytes(4);
|
||||||
|
// bytes.fill('\0');
|
||||||
|
// outbound.body = bytes;
|
||||||
|
// outbound.applicationIdentifier = 0;
|
||||||
|
// outbound.attachApplicationId = false;
|
||||||
|
// outbound.destination = m_recipient;
|
||||||
|
//
|
||||||
|
// sendMessage(outbound, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::slotSendData()
|
||||||
|
{
|
||||||
|
TQ_INT32 bytesRead = 0;
|
||||||
|
TQByteArray buffer(1202);
|
||||||
|
if(!m_file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Read a chunk from the source file.
|
||||||
|
bytesRead = m_file->readBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
if (bytesRead < 0) {
|
||||||
|
m_file->close();
|
||||||
|
// ### error handling
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
if(bytesRead < 1202){
|
||||||
|
buffer.resize(bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << TQString("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){
|
||||||
|
// The transfer is complete.
|
||||||
|
m_transfer->slotComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::acknowledged()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
switch(m_state)
|
||||||
|
{
|
||||||
|
case Invitation:
|
||||||
|
{
|
||||||
|
if(m_type == UserDisplayIcon)
|
||||||
|
{
|
||||||
|
m_state = Negotiation;
|
||||||
|
// Send data preparation message.
|
||||||
|
sendDataPreparation();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Negotiation:
|
||||||
|
{
|
||||||
|
if(m_type == UserDisplayIcon)
|
||||||
|
{
|
||||||
|
// <<< Data preparation acknowledge message.
|
||||||
|
m_state = DataTransfer;
|
||||||
|
m_identifier++;
|
||||||
|
// Start sending data.
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DataTransfer:
|
||||||
|
// NOTE <<< Data acknowledged message.
|
||||||
|
// <<< Bye message should follow.
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
if(m_handshake == 0x01)
|
||||||
|
{
|
||||||
|
// Data handshake acknowledge message.
|
||||||
|
// Start sending data.
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
else if(m_handshake == 0x02)
|
||||||
|
{
|
||||||
|
// Data acknowledge message.
|
||||||
|
// Send the recipient a BYE message.
|
||||||
|
m_state = Finished;
|
||||||
|
sendMessage(BYE, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Finished:
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
// BYE acknowledge message.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::processMessage(const Message& message)
|
||||||
|
{
|
||||||
|
TQString body =
|
||||||
|
TQCString(message.body.data(), message.header.dataSize);
|
||||||
|
kdDebug(14140) << k_funcinfo << "received, " << body << endl;
|
||||||
|
|
||||||
|
if(body.startsWith("BYE"))
|
||||||
|
{
|
||||||
|
m_state = Finished;
|
||||||
|
// Send the recipient an acknowledge message.
|
||||||
|
acknowledge(message);
|
||||||
|
if(!m_isComplete)
|
||||||
|
{
|
||||||
|
// The peer cancelled the transfer.
|
||||||
|
if(m_transfer)
|
||||||
|
{
|
||||||
|
// Inform the user of the file transfer cancelation.
|
||||||
|
m_transfer->slotError(TDEIO::ERR_ABORTED, i18n("File transfer canceled."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Dispose of this transfer context.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
else if(body.startsWith("MSNSLP/1.0 200 OK"))
|
||||||
|
{
|
||||||
|
// Retrieve the message content type.
|
||||||
|
TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
|
||||||
|
regex.search(body);
|
||||||
|
TQString contentType = regex.cap(1);
|
||||||
|
|
||||||
|
if(contentType == "application/x-msnmsgr-sessionreqbody")
|
||||||
|
{
|
||||||
|
// Recipient has accepted the file transfer.
|
||||||
|
// Acknowledge the recipient.
|
||||||
|
acknowledge(message);
|
||||||
|
|
||||||
|
// Try to open the file for reading.
|
||||||
|
// If an error occurs, send an internal
|
||||||
|
// error message to the recipient.
|
||||||
|
if(!m_file->open(IO_ReadOnly)){
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the receiving client's contact.
|
||||||
|
Kopete::Contact *contact = m_dispatcher->getContactByAccountId(m_recipient);
|
||||||
|
if(contact == 0l)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_transfer =
|
||||||
|
Kopete::TransferManager::transferManager()->addTransfer(contact, m_file->name(), m_file->size(), m_recipient, Kopete::FileTransferInfo::Outgoing);
|
||||||
|
|
||||||
|
TQObject::connect(m_transfer , TQT_SIGNAL(transferCanceled()), this, TQT_SLOT(abort()));
|
||||||
|
|
||||||
|
m_state = Negotiation;
|
||||||
|
|
||||||
|
m_branch = P2P::Uid::createUid();
|
||||||
|
|
||||||
|
// Send the direct connection invitation message.
|
||||||
|
TQString content = "Bridges: TRUDPv1 TCPv1\r\n" +
|
||||||
|
TQString("NetID: %1\r\n").arg("-123657987") +
|
||||||
|
TQString("Conn-Type: %1\r\n").arg("Restrict-NAT") +
|
||||||
|
"UPnPNat: false\r\n"
|
||||||
|
"ICF: false\r\n" +
|
||||||
|
TQString("Hashed-Nonce: {%1}\r\n").arg(P2P::Uid::createUid()) +
|
||||||
|
"\r\n";
|
||||||
|
sendMessage(INVITE, content);
|
||||||
|
}
|
||||||
|
else if(contentType == "application/x-msnmsgr-transrespbody")
|
||||||
|
{
|
||||||
|
// Determine whether the recipient created
|
||||||
|
// a listening endpoint.
|
||||||
|
regex = TQRegExp("Listening: ([^\r\n]+)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
bool isListening = (regex.cap(1) == "true");
|
||||||
|
|
||||||
|
// Send the recipient an acknowledge message.
|
||||||
|
acknowledge(message);
|
||||||
|
|
||||||
|
m_state = DataTransfer;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
isListening = false; // TODO complete direct connection.
|
||||||
|
#endif
|
||||||
|
if(isListening)
|
||||||
|
{
|
||||||
|
// Retrieve the hashed nonce for this direct connection instance.
|
||||||
|
regex = TQRegExp("Hashed-Nonce: \\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_nonce = regex.cap(1);
|
||||||
|
// Retrieve the listening endpoints of the receiving client.
|
||||||
|
regex = TQRegExp("IPv4Internal-Addrs: ([^\r\n]+)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_peerEndpoints = TQStringList::split(" ", regex.cap(1));
|
||||||
|
m_endpointIterator = m_peerEndpoints.begin();
|
||||||
|
// Retrieve the listening port of the receiving client.
|
||||||
|
regex = TQRegExp("IPv4Internal-Port: ([^\r\n]+)\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_remotePort = regex.cap(1);
|
||||||
|
|
||||||
|
// Try to connect to the receiving client's
|
||||||
|
// listening endpoint.
|
||||||
|
connectToEndpoint(*m_endpointIterator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_handshake = 0x02;
|
||||||
|
// Otherwise, send data through the already
|
||||||
|
// existing session.
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(body.startsWith("MSNSLP/1.0 603 Decline"))
|
||||||
|
{
|
||||||
|
// File transfer has been cancelled remotely.
|
||||||
|
// Send an acknowledge message
|
||||||
|
acknowledge(message);
|
||||||
|
if(m_transfer)
|
||||||
|
{
|
||||||
|
// Inform the user of the file transfer cancelation.
|
||||||
|
m_transfer->slotError(TDEIO::ERR_ABORTED, i18n("File transfer canceled."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_file && m_file->isOpen()){
|
||||||
|
// Close the file.
|
||||||
|
m_file->close();
|
||||||
|
}
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::readyToSend()
|
||||||
|
{
|
||||||
|
if(m_isComplete){
|
||||||
|
// Ignore, do nothing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::connectToEndpoint(const TQString& hostName)
|
||||||
|
{
|
||||||
|
m_socket = new TDEBufferedSocket(hostName, m_remotePort);
|
||||||
|
m_socket->setBlocking(false);
|
||||||
|
m_socket->enableRead(true);
|
||||||
|
// Disable write signal for now. Only enable
|
||||||
|
// when we are ready to sent data.
|
||||||
|
// NOTE readyWrite consumes too much cpu usage.
|
||||||
|
m_socket->enableWrite(false);
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(readyRead()), this, TQT_SLOT(slotRead()));
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(connected(const KResolverEntry&)), this, TQT_SLOT(slotConnected()));
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
TQObject::connect(m_socket, TQT_SIGNAL(closed()), this, TQT_SLOT(slotSocketClosed()));
|
||||||
|
// Try to connect to the endpoint.
|
||||||
|
m_socket->connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::slotConnected()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
// Check if connection is ok.
|
||||||
|
TQ_UINT32 bytesWritten = m_socket->writeBlock(TQCString("foo").data(), 4);
|
||||||
|
if(bytesWritten != 4)
|
||||||
|
{
|
||||||
|
// Not all data was written, close the socket.
|
||||||
|
m_socket->closeNow();
|
||||||
|
// Schedule the data to be sent through the existing session.
|
||||||
|
TQTimer::singleShot(2000, this, TQT_SLOT(slotSendData()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data handshake message.
|
||||||
|
P2P::Message handshake;
|
||||||
|
handshake.header.sessionId = 0;
|
||||||
|
handshake.header.identifier = ++m_identifier;
|
||||||
|
handshake.header.dataOffset = 0l;
|
||||||
|
handshake.header.totalDataSize = 0l;
|
||||||
|
handshake.header.dataSize = 0;
|
||||||
|
// Set the flag to indicate that this is
|
||||||
|
// a direct connection handshake message.
|
||||||
|
handshake.header.flag = 0x100;
|
||||||
|
TQString nonce = m_nonce.remove('-');
|
||||||
|
handshake.header.ackSessionIdentifier = nonce.mid(0, 8).toUInt(0, 16);
|
||||||
|
handshake.header.ackUniqueIdentifier =
|
||||||
|
nonce.mid(8, 4).toUInt(0, 16) | (nonce.mid(12, 4).toUInt(0, 16) << 16);
|
||||||
|
const TQ_UINT32 lo = nonce.mid(16, 8).toUInt(0, 16);
|
||||||
|
const TQ_UINT32 hi = nonce.mid(24, 8).toUInt(0, 16);
|
||||||
|
handshake.header.ackDataSize =
|
||||||
|
((TQ_INT64)htonl(lo)) | (((TQ_INT64)htonl(hi)) << 32);
|
||||||
|
|
||||||
|
TQByteArray stream;
|
||||||
|
// Write the message to the memory stream.
|
||||||
|
m_messageFormatter.writeMessage(handshake, stream, true);
|
||||||
|
// Send the byte stream over the wire.
|
||||||
|
m_socket->writeBlock(stream.data(), stream.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::slotRead()
|
||||||
|
{
|
||||||
|
TQ_INT32 bytesAvailable = m_socket->bytesAvailable();
|
||||||
|
kdDebug(14140) << k_funcinfo << bytesAvailable << ", bytes available." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::slotSocketError(int)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << m_socket->TDESocketBase::errorString() << endl;
|
||||||
|
// If an error has occurred, try to connect
|
||||||
|
// to another available peer endpoint.
|
||||||
|
// If there are no more available endpoints,
|
||||||
|
// send the data through the session.
|
||||||
|
m_socket->closeNow();
|
||||||
|
|
||||||
|
// Move to the next available endpoint.
|
||||||
|
m_endpointIterator++;
|
||||||
|
if(m_endpointIterator != m_peerEndpoints.end()){
|
||||||
|
// Try to connect to the endpoint.
|
||||||
|
connectToEndpoint(*m_endpointIterator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, send the data through the session.
|
||||||
|
m_identifier -= 1;
|
||||||
|
TQTimer::singleShot(2000, this, TQT_SLOT(slotSendData()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutgoingTransfer::slotSocketClosed()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
m_socket->deleteLater();
|
||||||
|
m_socket = 0l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "outgoingtransfer.moc"
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
outgoingtransfer.h - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 OUTGOINGTRANSFER_H
|
||||||
|
#define OUTGOINGTRANSFER_H
|
||||||
|
|
||||||
|
#include "p2p.h"
|
||||||
|
#include "dispatcher.h"
|
||||||
|
#include <tqstringlist.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Kopete Developers
|
||||||
|
*/
|
||||||
|
namespace P2P{
|
||||||
|
class OutgoingTransfer : public TransferContext
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OutgoingTransfer(const TQString& to, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId);
|
||||||
|
virtual ~OutgoingTransfer();
|
||||||
|
|
||||||
|
void sendImage(const TQByteArray& image);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotConnected();
|
||||||
|
void slotRead();
|
||||||
|
void slotSendData();
|
||||||
|
void slotSocketError(int);
|
||||||
|
void slotSocketClosed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void acknowledged();
|
||||||
|
void connectToEndpoint(const TQString& hostName);
|
||||||
|
virtual void processMessage(const Message& message);
|
||||||
|
|
||||||
|
TQStringList m_peerEndpoints;
|
||||||
|
TQStringList::Iterator m_endpointIterator;
|
||||||
|
TQString m_remotePort;
|
||||||
|
TQString m_nonce;
|
||||||
|
char m_handshake;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void readyToSend();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,412 @@
|
|||||||
|
/*
|
||||||
|
p2p.cpp - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 "p2p.h"
|
||||||
|
#include "dispatcher.h"
|
||||||
|
using P2P::TransferContext;
|
||||||
|
using P2P::Message;
|
||||||
|
using P2P::MessageType;
|
||||||
|
using P2P::TransferType;
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Kde includes
|
||||||
|
#include <kbufferedsocket.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
// TQt includes
|
||||||
|
#include <tqfile.h>
|
||||||
|
|
||||||
|
// Kopete includes
|
||||||
|
#include <kopetetransfermanager.h>
|
||||||
|
|
||||||
|
TQString P2P::Uid::createUid()
|
||||||
|
{
|
||||||
|
return (TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16)
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16) + "-"
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16) + "-"
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16) + "-"
|
||||||
|
+ TQString::number(rand()%0xAAFF+0x1111, 16) + "-"
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16)
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16)
|
||||||
|
+ TQString::number((unsigned long int)rand()%0xAAFF+0x1111, 16)).upper();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferContext::TransferContext(const TQString &contact, P2P::Dispatcher *dispatcher, TQ_UINT32 sessionId)
|
||||||
|
: TQObject(dispatcher) ,
|
||||||
|
m_sessionId(sessionId) ,
|
||||||
|
m_identifier(0) ,
|
||||||
|
m_file(0) ,
|
||||||
|
m_transactionId (0),
|
||||||
|
m_ackSessionIdentifier (0) ,
|
||||||
|
m_ackUniqueIdentifier ( 0 ),
|
||||||
|
m_transfer ( 0l) ,
|
||||||
|
|
||||||
|
m_baseIdentifier(rand()%0x0FFFFFF0 + 4),
|
||||||
|
m_dispatcher (dispatcher),
|
||||||
|
m_isComplete (false) ,
|
||||||
|
m_offset(0),
|
||||||
|
m_totalDataSize(0),
|
||||||
|
m_recipient(contact),
|
||||||
|
m_sender(dispatcher->localContact()),
|
||||||
|
m_socket(0),
|
||||||
|
m_state ( Invitation)
|
||||||
|
{
|
||||||
|
m_type = File ; //uh, why??? -Olivier
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferContext::~TransferContext()
|
||||||
|
{
|
||||||
|
m_transfer = 0l;
|
||||||
|
|
||||||
|
if(m_file){
|
||||||
|
delete m_file;
|
||||||
|
m_file = 0l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// else if(m_state == Finished && m_direction == Incoming){
|
||||||
|
// m_identifier = m_baseIdentifier - 1;
|
||||||
|
// }
|
||||||
|
else if(m_state == Finished && m_direction == Outgoing){
|
||||||
|
m_identifier = m_baseIdentifier + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++m_identifier;
|
||||||
|
|
||||||
|
outbound.header.identifier = m_identifier;
|
||||||
|
outbound.header.dataOffset = 0l;
|
||||||
|
outbound.header.totalDataSize = message.header.totalDataSize;
|
||||||
|
outbound.header.dataSize = 0;
|
||||||
|
// if(m_type == UserDisplayIcon && m_state == Finished){
|
||||||
|
// if(m_direction == Outgoing){
|
||||||
|
// outbound.header.flag = 0x40;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
outbound.header.flag = 2;
|
||||||
|
|
||||||
|
outbound.header.ackSessionIdentifier = message.header.identifier;
|
||||||
|
outbound.header.ackUniqueIdentifier = message.header.ackSessionIdentifier;
|
||||||
|
outbound.header.ackDataSize = message.header.totalDataSize;
|
||||||
|
// NOTE outbound.body is null by default
|
||||||
|
outbound.applicationIdentifier = 0l;
|
||||||
|
outbound.destination = m_recipient;
|
||||||
|
|
||||||
|
TQByteArray stream;
|
||||||
|
// Write the acknowledge message to the stream.
|
||||||
|
m_messageFormatter.writeMessage(outbound, stream, (m_socket != 0l));
|
||||||
|
if(!m_socket)
|
||||||
|
{
|
||||||
|
// Send the acknowledge message.
|
||||||
|
m_dispatcher->callbackChannel()->send(stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Send acknowledge message directly.
|
||||||
|
m_socket->writeBlock(stream.data(), stream.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::error()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
sendMessage(ERROR);
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::sendData(const TQByteArray& bytes)
|
||||||
|
{
|
||||||
|
Message outbound;
|
||||||
|
outbound.header.sessionId = m_sessionId;
|
||||||
|
outbound.header.identifier = m_identifier;
|
||||||
|
outbound.header.dataOffset = m_offset;
|
||||||
|
if(m_file){
|
||||||
|
outbound.header.totalDataSize = m_file->size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
outbound.header.totalDataSize = m_totalDataSize;
|
||||||
|
|
||||||
|
outbound.header.dataSize = bytes.size();
|
||||||
|
if(m_type == UserDisplayIcon){
|
||||||
|
outbound.header.flag = 0x20;
|
||||||
|
}
|
||||||
|
else if(m_type == P2P::File){
|
||||||
|
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;
|
||||||
|
|
||||||
|
TQByteArray stream;
|
||||||
|
m_messageFormatter.writeMessage(outbound, stream, (m_socket != 0l));
|
||||||
|
if(!m_socket)
|
||||||
|
{
|
||||||
|
// Send the data message.
|
||||||
|
m_transactionId = m_dispatcher->callbackChannel()->send(stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Send data directly.
|
||||||
|
m_socket->writeBlock(stream.data(), stream.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::sendDataPreparation()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
Message outbound;
|
||||||
|
outbound.header.sessionId = m_sessionId;
|
||||||
|
outbound.header.identifier = ++m_identifier;
|
||||||
|
outbound.header.dataOffset = 0;
|
||||||
|
outbound.header.totalDataSize = 4;
|
||||||
|
outbound.header.dataSize = 4;
|
||||||
|
outbound.header.flag = 0;
|
||||||
|
outbound.header.ackSessionIdentifier = rand()%0x8FFFFFF0 + 4;
|
||||||
|
outbound.header.ackUniqueIdentifier = 0;
|
||||||
|
outbound.header.ackDataSize = 0l;
|
||||||
|
TQByteArray bytes(4);
|
||||||
|
bytes.fill('\0');
|
||||||
|
outbound.body = bytes;
|
||||||
|
outbound.applicationIdentifier = 1;
|
||||||
|
outbound.destination = m_recipient;
|
||||||
|
|
||||||
|
TQByteArray stream;
|
||||||
|
m_messageFormatter.writeMessage(outbound, stream);
|
||||||
|
// Send the receiving client the data prepartion message.
|
||||||
|
m_dispatcher->callbackChannel()->send(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::sendMessage(MessageType type, const TQString& content, TQ_INT32 flag, TQ_INT32 appId)
|
||||||
|
{
|
||||||
|
Message outbound;
|
||||||
|
if(appId != 0){
|
||||||
|
outbound.header.sessionId = m_sessionId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
outbound.header.sessionId = 0;
|
||||||
|
|
||||||
|
if(m_identifier == 0){
|
||||||
|
m_identifier = m_baseIdentifier;
|
||||||
|
}
|
||||||
|
else if(m_state == Invitation && m_direction == P2P::Outgoing && m_type == UserDisplayIcon)
|
||||||
|
{
|
||||||
|
m_identifier -= 3;
|
||||||
|
}
|
||||||
|
else if(m_state == Invitation && m_direction == P2P::Incoming && m_type == File)
|
||||||
|
{
|
||||||
|
m_identifier -= 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++m_identifier;
|
||||||
|
|
||||||
|
outbound.header.identifier = m_identifier;
|
||||||
|
outbound.header.flag = flag;
|
||||||
|
outbound.header.ackSessionIdentifier = m_ackSessionIdentifier;
|
||||||
|
outbound.header.ackUniqueIdentifier = m_ackUniqueIdentifier;
|
||||||
|
outbound.header.ackDataSize = 0l;
|
||||||
|
outbound.applicationIdentifier = appId;
|
||||||
|
outbound.destination = m_recipient;
|
||||||
|
|
||||||
|
TQString contentType, cSeq, method;
|
||||||
|
|
||||||
|
switch(m_state)
|
||||||
|
{
|
||||||
|
case DataTransfer:
|
||||||
|
contentType = "application/x-msnmsgr-transreqbody";
|
||||||
|
if(m_type == File && m_direction == Incoming)
|
||||||
|
{
|
||||||
|
contentType = "application/x-msnmsgr-transrespbody";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Finished:
|
||||||
|
contentType = "application/x-msnmsgr-sessionclosebody";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
contentType = "application/x-msnmsgr-sessionreqbody";
|
||||||
|
if(m_type == File && m_direction == Outgoing)
|
||||||
|
{
|
||||||
|
if(m_state == Negotiation){
|
||||||
|
contentType = "application/x-msnmsgr-transreqbody";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m_type == P2P::WebcamType && type==P2P::INVITE && m_state == Negotiation)
|
||||||
|
{
|
||||||
|
contentType = "application/x-msnmsgr-transreqbody";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case BYE:
|
||||||
|
method = "BYE MSNMSGR:" + m_recipient + " MSNSLP/1.0";
|
||||||
|
cSeq = "0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DECLINE:
|
||||||
|
method = "MSNSLP/1.0 603 DECLINE";
|
||||||
|
cSeq = "1";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR:
|
||||||
|
contentType = "null";
|
||||||
|
method = "MSNSLP/1.0 500 Internal Error";
|
||||||
|
cSeq = "1";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INVITE:
|
||||||
|
method = "INVITE MSNMSGR:" + m_recipient + " MSNSLP/1.0";
|
||||||
|
cSeq = "0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OK:
|
||||||
|
method = "MSNSLP/1.0 200 OK";
|
||||||
|
cSeq = "1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQCString body = TQString(method + "\r\n"
|
||||||
|
"To: <msnmsgr:" + m_recipient + ">\r\n"
|
||||||
|
"From: <msnmsgr:" + m_sender + ">\r\n"
|
||||||
|
"Via: MSNSLP/1.0/TLP ;branch={" + m_branch.upper() + "}\r\n"
|
||||||
|
"CSeq: "+ cSeq +"\r\n"
|
||||||
|
"Call-ID: {" + m_callId.upper() + "}\r\n"
|
||||||
|
"Max-Forwards: 0\r\n"
|
||||||
|
"Content-Type: " + contentType + "\r\n"
|
||||||
|
"Content-Length: "+ TQString::number(content.length() + 1) + "\r\n"
|
||||||
|
"\r\n" +
|
||||||
|
content).utf8();
|
||||||
|
|
||||||
|
// NOTE The body must have a null character at the end.
|
||||||
|
// TQCString by chance automatically adds a \0 to the
|
||||||
|
// end of the string.
|
||||||
|
|
||||||
|
outbound.header.totalDataSize = body.size();
|
||||||
|
// Send the outbound message.
|
||||||
|
sendMessage(outbound, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::sendMessage(Message& outbound, const TQByteArray& body)
|
||||||
|
{
|
||||||
|
TQ_INT64 offset = 0L, bytesLeft = outbound.header.totalDataSize;
|
||||||
|
TQ_INT16 chunkLength = 1202;
|
||||||
|
|
||||||
|
// Split the outbound message if necessary.
|
||||||
|
while(bytesLeft > 0L)
|
||||||
|
{
|
||||||
|
if(bytesLeft < chunkLength)
|
||||||
|
{
|
||||||
|
// Copy the last chunk of the multipart message.
|
||||||
|
outbound.body.duplicate(body.data() + offset, bytesLeft);
|
||||||
|
outbound.header.dataSize = bytesLeft;
|
||||||
|
outbound.header.dataOffset = offset;
|
||||||
|
bytesLeft = 0L;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Copy the next chunk of the multipart message in the sequence.
|
||||||
|
outbound.body.duplicate(body.data() + offset, chunkLength);
|
||||||
|
outbound.header.dataSize = chunkLength;
|
||||||
|
outbound.header.dataOffset = offset;
|
||||||
|
offset += chunkLength;
|
||||||
|
bytesLeft -= offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo <<
|
||||||
|
TQCString(outbound.body.data(), outbound.body.size())
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
TQByteArray stream;
|
||||||
|
// Write the outbound message to the stream.
|
||||||
|
m_messageFormatter.writeMessage(outbound, stream, (m_socket != 0l));
|
||||||
|
if(!m_socket)
|
||||||
|
{
|
||||||
|
// Send the outbound message.
|
||||||
|
m_dispatcher->callbackChannel()->send(stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Send outbound message directly.
|
||||||
|
m_socket->writeBlock(stream.data(), stream.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::setType(TransferType type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::abort()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
if(m_transfer)
|
||||||
|
{
|
||||||
|
if(m_transfer->error() == TDEIO::ERR_ABORTED)
|
||||||
|
{
|
||||||
|
switch(m_direction)
|
||||||
|
{
|
||||||
|
case P2P::Outgoing:
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P2P::Incoming:
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_state = Finished;
|
||||||
|
sendMessage(BYE, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::readyWrite()
|
||||||
|
{
|
||||||
|
if(m_direction == Outgoing && m_state == DataTransfer){
|
||||||
|
readyToSend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferContext::readyToSend()
|
||||||
|
{}
|
||||||
|
|
||||||
|
#include "p2p.moc"
|
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
p2p.h - msn p2p protocol
|
||||||
|
|
||||||
|
Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 P2P_H
|
||||||
|
#define P2P_H
|
||||||
|
|
||||||
|
// TQt includes
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include "messageformatter.h"
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace Kopete { class Transfer; }
|
||||||
|
namespace Kopete { struct FileTransferInfo; }
|
||||||
|
namespace P2P { class Dispatcher; }
|
||||||
|
namespace KNetwork { class TDEBufferedSocket; }
|
||||||
|
class TQFile;
|
||||||
|
class KTempFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@author Kopete Developers
|
||||||
|
*/
|
||||||
|
namespace System{
|
||||||
|
class Guid
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Guid(){}
|
||||||
|
static Guid newGuid();
|
||||||
|
TQString toString();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Guid(){}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace P2P{
|
||||||
|
|
||||||
|
enum TransferType { UserDisplayIcon = 1, File = 2, WebcamType=4};
|
||||||
|
enum TransferDirection { Incoming = 1, Outgoing = 8};
|
||||||
|
enum MessageType { BYE, OK, DECLINE, ERROR, INVITE };
|
||||||
|
|
||||||
|
enum CommunicationState
|
||||||
|
{
|
||||||
|
Invitation = 1,
|
||||||
|
Negotiation = 2,
|
||||||
|
DataTransfer = 8,
|
||||||
|
Finished = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransportHeader
|
||||||
|
{
|
||||||
|
TQ_UINT32 sessionId;
|
||||||
|
TQ_UINT32 identifier;
|
||||||
|
TQ_INT64 dataOffset;
|
||||||
|
TQ_INT64 totalDataSize;
|
||||||
|
TQ_UINT32 dataSize;
|
||||||
|
TQ_UINT32 flag;
|
||||||
|
TQ_UINT32 ackSessionIdentifier;
|
||||||
|
TQ_UINT32 ackUniqueIdentifier;
|
||||||
|
TQ_INT64 ackDataSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TQString mimeVersion;
|
||||||
|
TQString contentType;
|
||||||
|
TQString destination;
|
||||||
|
TQString source;
|
||||||
|
TransportHeader header;
|
||||||
|
TQByteArray body;
|
||||||
|
TQ_INT32 applicationIdentifier;
|
||||||
|
bool attachApplicationIdentifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KOPETE_EXPORT Uid
|
||||||
|
{
|
||||||
|
public: static TQString createUid();
|
||||||
|
};
|
||||||
|
|
||||||
|
class KOPETE_EXPORT TransferContext : public TQObject
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~TransferContext();
|
||||||
|
|
||||||
|
void acknowledge(const Message& message);
|
||||||
|
virtual void acknowledged() = 0;
|
||||||
|
void error();
|
||||||
|
virtual void processMessage(const P2P::Message& message) = 0;
|
||||||
|
void sendDataPreparation();
|
||||||
|
void sendMessage(MessageType type, const TQString& content=TQString(), TQ_INT32 flag=0, TQ_INT32 appId=0);
|
||||||
|
void setType(TransferType type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
TQ_UINT32 m_sessionId;
|
||||||
|
TQ_UINT32 m_identifier;
|
||||||
|
TQFile *m_file;
|
||||||
|
TQ_UINT32 m_transactionId;
|
||||||
|
TQ_UINT32 m_ackSessionIdentifier;
|
||||||
|
TQ_UINT32 m_ackUniqueIdentifier;
|
||||||
|
Kopete::Transfer *m_transfer;
|
||||||
|
TQString m_branch;
|
||||||
|
TQString m_callId;
|
||||||
|
TQString m_object;
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void abort();
|
||||||
|
void readyWrite();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TransferContext(const TQString& contact, P2P::Dispatcher *dispatcher,TQ_UINT32 sessionId);
|
||||||
|
void sendData(const TQByteArray& bytes);
|
||||||
|
void sendMessage(P2P::Message& outbound, const TQByteArray& body);
|
||||||
|
virtual void readyToSend();
|
||||||
|
|
||||||
|
TQ_UINT32 m_baseIdentifier;
|
||||||
|
TransferDirection m_direction;
|
||||||
|
P2P::Dispatcher *m_dispatcher;
|
||||||
|
bool m_isComplete;
|
||||||
|
TQ_INT64 m_offset;
|
||||||
|
TQ_INT64 m_totalDataSize;
|
||||||
|
P2P::MessageFormatter m_messageFormatter;
|
||||||
|
TQString m_recipient;
|
||||||
|
TQString m_sender;
|
||||||
|
KNetwork::TDEBufferedSocket *m_socket;
|
||||||
|
CommunicationState m_state;
|
||||||
|
TransferType m_type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* sha1.cpp - Secure Hash Algorithm 1
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com)
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||||
|
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15]^block->l[(i+2)&15]^block->l[i&15],1))
|
||||||
|
|
||||||
|
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||||
|
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||||
|
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||||
|
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||||
|
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||||
|
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||||
|
|
||||||
|
|
||||||
|
SHA1::SHA1()
|
||||||
|
{
|
||||||
|
int wordSize;
|
||||||
|
|
||||||
|
tqSysInfo(&wordSize, &bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long SHA1::blk0(TQ_UINT32 i)
|
||||||
|
{
|
||||||
|
if(bigEndian)
|
||||||
|
return block->l[i];
|
||||||
|
else
|
||||||
|
return (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) | (rol(block->l[i],8)&0x00FF00FF));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash a single 512-bit block. This is the core of the algorithm.
|
||||||
|
void SHA1::transform(TQ_UINT32 state[5], unsigned char buffer[64])
|
||||||
|
{
|
||||||
|
TQ_UINT32 a, b, c, d, e;
|
||||||
|
|
||||||
|
block = (CHAR64LONG16*)buffer;
|
||||||
|
|
||||||
|
// Copy context->state[] to working vars
|
||||||
|
a = state[0];
|
||||||
|
b = state[1];
|
||||||
|
c = state[2];
|
||||||
|
d = state[3];
|
||||||
|
e = state[4];
|
||||||
|
|
||||||
|
// 4 rounds of 20 operations each. Loop unrolled.
|
||||||
|
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||||
|
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||||
|
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||||
|
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||||
|
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||||
|
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||||
|
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||||
|
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||||
|
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||||
|
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||||
|
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||||
|
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||||
|
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||||
|
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||||
|
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||||
|
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||||
|
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||||
|
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||||
|
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||||
|
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||||
|
|
||||||
|
// Add the working vars back into context.state[]
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
state[4] += e;
|
||||||
|
|
||||||
|
// Wipe variables
|
||||||
|
a = b = c = d = e = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA1Init - Initialize new context
|
||||||
|
void SHA1::init(SHA1_CONTEXT* context)
|
||||||
|
{
|
||||||
|
// SHA1 initialization constants
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xEFCDAB89;
|
||||||
|
context->state[2] = 0x98BADCFE;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
context->state[4] = 0xC3D2E1F0;
|
||||||
|
context->count[0] = context->count[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run your data through this
|
||||||
|
void SHA1::update(SHA1_CONTEXT* context, unsigned char* data, TQ_UINT32 len)
|
||||||
|
{
|
||||||
|
TQ_UINT32 i, j;
|
||||||
|
|
||||||
|
j = (context->count[0] >> 3) & 63;
|
||||||
|
if((context->count[0] += len << 3) < (len << 3))
|
||||||
|
context->count[1]++;
|
||||||
|
|
||||||
|
context->count[1] += (len >> 29);
|
||||||
|
|
||||||
|
if((j + len) > 63) {
|
||||||
|
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||||
|
transform(context->state, context->buffer);
|
||||||
|
for ( ; i + 63 < len; i += 64) {
|
||||||
|
transform(context->state, &data[i]);
|
||||||
|
}
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
else i = 0;
|
||||||
|
memcpy(&context->buffer[j], &data[i], len - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add padding and return the message digest
|
||||||
|
void SHA1::final(unsigned char digest[20], SHA1_CONTEXT* context)
|
||||||
|
{
|
||||||
|
TQ_UINT32 i, j;
|
||||||
|
unsigned char finalcount[8];
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
||||||
|
>> ((3-(i & 3)) * 8) ) & 255); // Endian independent
|
||||||
|
}
|
||||||
|
update(context, (unsigned char *)"\200", 1);
|
||||||
|
while ((context->count[0] & 504) != 448) {
|
||||||
|
update(context, (unsigned char *)"\0", 1);
|
||||||
|
}
|
||||||
|
update(context, finalcount, 8); // Should cause a transform()
|
||||||
|
for (i = 0; i < 20; i++) {
|
||||||
|
digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wipe variables
|
||||||
|
i = j = 0;
|
||||||
|
memset(context->buffer, 0, 64);
|
||||||
|
memset(context->state, 0, 20);
|
||||||
|
memset(context->count, 0, 8);
|
||||||
|
memset(&finalcount, 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray SHA1::hash(const TQByteArray &a)
|
||||||
|
{
|
||||||
|
SHA1_CONTEXT context;
|
||||||
|
TQByteArray b(20);
|
||||||
|
|
||||||
|
SHA1 s;
|
||||||
|
s.init(&context);
|
||||||
|
s.update(&context, (unsigned char *)a.data(), (unsigned int)a.size());
|
||||||
|
s.final((unsigned char *)b.data(), &context);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray SHA1::hashString(const TQCString &cs)
|
||||||
|
{
|
||||||
|
TQByteArray a(cs.length());
|
||||||
|
memcpy(a.data(), cs.data(), a.size());
|
||||||
|
return SHA1::hash(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString SHA1::digest(const TQString &in)
|
||||||
|
{
|
||||||
|
TQByteArray a = SHA1::hashString(in.utf8());
|
||||||
|
TQString out;
|
||||||
|
for(int n = 0; n < (int)a.size(); ++n) {
|
||||||
|
TQString str;
|
||||||
|
str.sprintf("%02x", (uchar)a[n]);
|
||||||
|
out.append(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* sha1.h - Secure Hash Algorithm 1
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CS_SHA1_H
|
||||||
|
#define CS_SHA1_H
|
||||||
|
|
||||||
|
#include <tqstring.h>
|
||||||
|
|
||||||
|
class SHA1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static TQByteArray hash(const TQByteArray &);
|
||||||
|
static TQByteArray hashString(const TQCString &);
|
||||||
|
static TQString digest(const TQString &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SHA1();
|
||||||
|
|
||||||
|
struct SHA1_CONTEXT
|
||||||
|
{
|
||||||
|
TQ_UINT32 state[5];
|
||||||
|
TQ_UINT32 count[2];
|
||||||
|
unsigned char buffer[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
unsigned char c[64];
|
||||||
|
TQ_UINT32 l[16];
|
||||||
|
} CHAR64LONG16;
|
||||||
|
|
||||||
|
void transform(TQ_UINT32 state[5], unsigned char buffer[64]);
|
||||||
|
void init(SHA1_CONTEXT* context);
|
||||||
|
void update(SHA1_CONTEXT* context, unsigned char* data, TQ_UINT32 len);
|
||||||
|
void final(unsigned char digest[20], SHA1_CONTEXT* context);
|
||||||
|
|
||||||
|
unsigned long blk0(TQ_UINT32 i);
|
||||||
|
bool bigEndian;
|
||||||
|
|
||||||
|
CHAR64LONG16* block;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
transport.cpp - Peer to peer transport
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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(TQObject* parent, const char* name)
|
||||||
|
: TQObject(parent, name)
|
||||||
|
{
|
||||||
|
mFormatter = new PeerToPeer::MessageFormatter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Transport::~Transport()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//BEGIN Public Methods
|
||||||
|
|
||||||
|
TransportBridge* Transport::getBridge (const TQString& to, TQ_UINT16 port, TransportBridgeType type, const TQString& 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)
|
||||||
|
{
|
||||||
|
TQObject::connect(bridge, TQT_SIGNAL(readyRead(const TQByteArray&)), TQT_SLOT(slotOnReceive(const TQByteArray&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transport::setDefaultBridge(MSNSwitchBoardSocket* mss)
|
||||||
|
{
|
||||||
|
mDefaultBridge = mss;
|
||||||
|
TQObject::connect((MSNSwitchBoardSocket*)mDefaultBridge, TQT_SIGNAL(messageReceived(const TQString&, const TQByteArray&)), TQT_SLOT(slotOnReceive(const TQString&, const TQByteArray&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//END
|
||||||
|
|
||||||
|
//BEGIN Private Slot Methods
|
||||||
|
|
||||||
|
// void Transport::slotOnReceive(Message& message)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
|
||||||
|
void Transport::slotOnReceive(const TQString& contact, const TQByteArray& bytes)
|
||||||
|
{
|
||||||
|
kdDebug (14140) << k_funcinfo << " >> RECEIVED " << bytes.size() << " bytes." << endl;
|
||||||
|
// Message message = mFormatter->readMessage(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//END
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TransportBridge::TransportBridge(const KNetwork::KInetSocketAddress& to, MessageFormatter* formatter, TQObject* parent, const char* name)
|
||||||
|
: TQObject(parent, name)
|
||||||
|
{
|
||||||
|
mAddress = to;
|
||||||
|
mFormatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportBridge::TransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, TQObject* parent, const char* name)
|
||||||
|
: TQObject(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, TQObject* parent, const char* name)
|
||||||
|
: TransportBridge(to, formatter, parent, name)
|
||||||
|
{
|
||||||
|
mSocket = new KStreamSocket(mAddress.ipAddress().toString(), TQString::number(mAddress.port()), this);
|
||||||
|
mSocket->setBlocking(false);
|
||||||
|
TQObject::connect(mSocket, TQT_SIGNAL(connected(const KResolverEntry&)), TQT_SLOT(slotOnSocketConnect()));
|
||||||
|
TQObject::connect(mSocket, TQT_SIGNAL(gotError(int)), TQT_SLOT(slotOnError(int)));
|
||||||
|
mConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpTransportBridge::TcpTransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, TQObject* 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);
|
||||||
|
TQObject::connect(socket, TQT_SIGNAL(timeOut()), TQT_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(TQString("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;
|
||||||
|
|
||||||
|
TQObject::connect(mSocket, TQT_SIGNAL(readyRead()), TQT_SLOT(slotOnSocketReceive()));
|
||||||
|
TQObject::connect(mSocket, TQT_SIGNAL(closed()), TQT_SLOT(slotOnSocketClose()));
|
||||||
|
|
||||||
|
mVerified = true;
|
||||||
|
TQString foo = "foo\0";
|
||||||
|
mSocket->writeBlock(foo.ascii(), foo.length());
|
||||||
|
foo = TQString();
|
||||||
|
|
||||||
|
emit bridgeConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpTransportBridge::slotOnSocketReceive()
|
||||||
|
{
|
||||||
|
kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") RECEIVED " << mSocket->bytesAvailable() << " bytes." << endl;
|
||||||
|
|
||||||
|
TQByteArray bytes(mSocket->bytesAvailable());
|
||||||
|
mSocket->readBlock(bytes.data(), bytes.size());
|
||||||
|
// Write the data to the buffer.
|
||||||
|
mBuffer.write(bytes);
|
||||||
|
|
||||||
|
if (mVerified == false && mBuffer.size() >= 4)
|
||||||
|
{
|
||||||
|
TQByteArray foo = mBuffer.read(4);
|
||||||
|
if (TQString(foo) == "foo"){
|
||||||
|
kdDebug (14140) << k_funcinfo << "Bridge (" << name() << ") CONNECTION verified." << endl;
|
||||||
|
mVerified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(mBuffer.size() > 0)
|
||||||
|
{
|
||||||
|
if (mBuffer.size() >= 4 && mLength == 0)
|
||||||
|
{
|
||||||
|
TQByteArray 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(TQ_UINT32 length)
|
||||||
|
: TQByteArray(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpTransportBridge::Buffer::~Buffer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//BEGIN Public Methods
|
||||||
|
|
||||||
|
void TcpTransportBridge::Buffer::write(const TQByteArray& bytes)
|
||||||
|
{
|
||||||
|
resize(size() + bytes.size());
|
||||||
|
for (uint i=0; i < bytes.size(); i++){
|
||||||
|
(*this)[size() + i] = bytes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray TcpTransportBridge::Buffer::read(TQ_UINT32 length)
|
||||||
|
{
|
||||||
|
if (length >= size()) return TQByteArray();
|
||||||
|
|
||||||
|
TQByteArray 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"
|
||||||
|
|
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
transport.h - Peer to peer transport
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 <tqobject.h>
|
||||||
|
#include <tqguardedptr.h>
|
||||||
|
#include <tqvaluelist.h>
|
||||||
|
//END
|
||||||
|
|
||||||
|
//BEGIN KDE Includes
|
||||||
|
#include <tdesocketaddress.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@gmail.com> */
|
||||||
|
/** @brief Represents the protocol used to send and receive message between peers. */
|
||||||
|
class Transport : public TQObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** @brief Creates a new instance of the class Transport. */
|
||||||
|
Transport(TQObject* parent, const char* name = 0l);
|
||||||
|
~Transport();
|
||||||
|
/** @brief Get a transport bridge with the specified address, port, type and identifier. */
|
||||||
|
TransportBridge* getBridge(const TQString& address, TQ_UINT16 port, TransportBridgeType type, const TQString& 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 TQString& contact, const TQByteArray& bytes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** @brief Known SocketAddresses of peers. */
|
||||||
|
TQMap<TQString, KNetwork::KInetSocketAddress> mAddresses;
|
||||||
|
/** @brief The list the connected transport bridges. */
|
||||||
|
TQValueList<TransportBridge*> mBridges;
|
||||||
|
/** @brief The default transport bridge (relay). */
|
||||||
|
TQGuardedPtr<MSNSwitchBoardSocket> mDefaultBridge;
|
||||||
|
/** @brief Message formatter used to ser/deser message. */
|
||||||
|
MessageFormatter *mFormatter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Represents the channel connecting two peers. */
|
||||||
|
class TransportBridge : public TQObject
|
||||||
|
{
|
||||||
|
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, TQObject* 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, TQObject* 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 TQString& e);
|
||||||
|
void bytesReceived(const TQByteArray&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
KNetwork::KInetSocketAddress mAddress;
|
||||||
|
bool mConnected;
|
||||||
|
MessageFormatter *mFormatter;
|
||||||
|
TQ_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, TQObject* parent, const char* name = 0l);
|
||||||
|
TcpTransportBridge(KNetwork::KClientSocketBase* socket, MessageFormatter* formatter, TQObject* 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 TQByteArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Buffer(TQ_UINT32 length = 0);
|
||||||
|
~Buffer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void write(const TQByteArray& bytes);
|
||||||
|
TQByteArray read(TQ_UINT32 length);
|
||||||
|
};
|
||||||
|
|
||||||
|
Buffer mBuffer;
|
||||||
|
TQ_UINT32 mLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,29 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||||
|
${CMAKE_BINARY_DIR}/kopete/libkopete/ui
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
|
||||||
|
${TDE_INCLUDE_DIR}
|
||||||
|
${TQT_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### kopetemsnui (static) ######################
|
||||||
|
|
||||||
|
tde_add_library( kopetemsnui STATIC_PIC AUTOMOC
|
||||||
|
SOURCES
|
||||||
|
msnadd.ui msndebugrawcommand_base.ui msninfo.ui msneditaccountui.ui
|
||||||
|
msneditaccountwidget.cpp
|
||||||
|
)
|
@ -0,0 +1,12 @@
|
|||||||
|
METASOURCES = AUTO
|
||||||
|
AM_CPPFLAGS = $(KOPETE_INCLUDES) \
|
||||||
|
-I$(srcdir)/.. \
|
||||||
|
$(all_includes)
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libkopetemsnui.la
|
||||||
|
|
||||||
|
libkopetemsnui_la_SOURCES = msnadd.ui msndebugrawcommand_base.ui msninfo.ui \
|
||||||
|
msneditaccountui.ui msneditaccountwidget.cpp
|
||||||
|
|
||||||
|
EXTRA_DIST = msnadd.ui msninfo.ui
|
||||||
|
|
@ -0,0 +1,97 @@
|
|||||||
|
<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
|
||||||
|
<class>msnAddUI</class>
|
||||||
|
<widget class="TQWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>msnAddUI</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>397</width>
|
||||||
|
<height>347</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<vbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>layout21</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&MSN Passport ID:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" stdset="0">
|
||||||
|
<cstring>addID</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip" stdset="0">
|
||||||
|
<string>The user ID of the MSN contact you would like to add.</string>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis" stdset="0">
|
||||||
|
<string>The user ID of the MSN contact you would like to add. This should be in the form of a valid E-mail address.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>addID</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip" stdset="0">
|
||||||
|
<string>The user ID of the MSN contact you would like to add.</string>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis" stdset="0">
|
||||||
|
<string>The user ID of the MSN contact you would like to add. This should be in the form of a valid E-mail address.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><i>(for example: joe@hotmail.com)</i></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>AlignVCenter|AlignRight</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<spacer>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>spacer13</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>
|
||||||
|
</widget>
|
||||||
|
<layoutdefaults spacing="6" margin="11"/>
|
||||||
|
</UI>
|
@ -0,0 +1,107 @@
|
|||||||
|
<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
|
||||||
|
<class>MSNDebugRawCommand_base</class>
|
||||||
|
<widget class="TQWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>MSNDebugRawCommand_base</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>201</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<grid>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel" row="1" column="0">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Parameters:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" stdset="0">
|
||||||
|
<cstring>m_params</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit" row="0" column="1">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_command</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel" row="0" column="0">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Co&mmand:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" stdset="0">
|
||||||
|
<cstring>m_command</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit" row="1" column="1">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_params</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox" row="2" column="0" rowspan="1" colspan="2">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_addId</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add &ID</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox" row="3" column="0" rowspan="1" colspan="2">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_addNewline</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add &new line</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="KTextEdit" row="5" column="0" rowspan="1" colspan="2">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_msg</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>PlainText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel" row="4" column="0" rowspan="1" colspan="2">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel3</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Message:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</grid>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>m_command</tabstop>
|
||||||
|
<tabstop>m_params</tabstop>
|
||||||
|
<tabstop>m_addId</tabstop>
|
||||||
|
<tabstop>m_addNewline</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<layoutdefaults spacing="6" margin="11"/>
|
||||||
|
<includehints>
|
||||||
|
<includehint>ktextedit.h</includehint>
|
||||||
|
</includehints>
|
||||||
|
</UI>
|
@ -0,0 +1,369 @@
|
|||||||
|
/*
|
||||||
|
msneditaccountwidget.cpp - MSN Account Widget
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Copyright (c) 2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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 "msneditaccountwidget.h"
|
||||||
|
|
||||||
|
#include <tqcheckbox.h>
|
||||||
|
#include <tqgroupbox.h>
|
||||||
|
#include <tqimage.h>
|
||||||
|
#include <tqlabel.h>
|
||||||
|
#include <tqlayout.h>
|
||||||
|
#include <tqlineedit.h>
|
||||||
|
#include <tqlistbox.h>
|
||||||
|
#include <tqpushbutton.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <tqspinbox.h>
|
||||||
|
#include <kcombobox.h>
|
||||||
|
|
||||||
|
#include <kautoconfig.h>
|
||||||
|
#include <tdefiledialog.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
#include <kstandarddirs.h>
|
||||||
|
#include <tdeio/netaccess.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kpassdlg.h>
|
||||||
|
#include <krun.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
#include <kpixmapregionselectordialog.h>
|
||||||
|
|
||||||
|
#include "kopeteuiglobal.h"
|
||||||
|
#include "kopeteglobal.h"
|
||||||
|
|
||||||
|
#include "kopetepasswordwidget.h"
|
||||||
|
#include "kopeteaccountmanager.h"
|
||||||
|
|
||||||
|
#include "msnaccount.h"
|
||||||
|
#include "msncontact.h"
|
||||||
|
#include "msneditaccountui.h"
|
||||||
|
#include "msnnotifysocket.h"
|
||||||
|
#include "msnprotocol.h"
|
||||||
|
|
||||||
|
class MSNEditAccountWidgetPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MSNProtocol *protocol;
|
||||||
|
KAutoConfig *autoConfig;
|
||||||
|
MSNEditAccountUI *ui;
|
||||||
|
|
||||||
|
TQString pictureUrl;
|
||||||
|
TQImage pictureData;
|
||||||
|
};
|
||||||
|
|
||||||
|
MSNEditAccountWidget::MSNEditAccountWidget( MSNProtocol *proto, Kopete::Account *account, TQWidget *parent, const char * /* name */ )
|
||||||
|
: TQWidget( parent ), KopeteEditAccountWidget( account )
|
||||||
|
{
|
||||||
|
d = new MSNEditAccountWidgetPrivate;
|
||||||
|
|
||||||
|
d->protocol=proto;
|
||||||
|
|
||||||
|
( new TQVBoxLayout( this, 0, 0 ) )->setAutoAdd( true );
|
||||||
|
|
||||||
|
d->ui = new MSNEditAccountUI( this );
|
||||||
|
|
||||||
|
d->autoConfig = new KAutoConfig( TQT_TQOBJECT(d->ui) );
|
||||||
|
d->autoConfig->addWidget( d->ui->global_settings_page, "MSN" );
|
||||||
|
d->autoConfig->addWidget( d->ui->privacy_page, "MSN" );
|
||||||
|
//the JabberAccount need to be saved as text, and can't be handled by kautoconfig
|
||||||
|
d->autoConfig->ignoreSubWidget( d->ui->JabberAccount );
|
||||||
|
d->autoConfig->retrieveSettings( true );
|
||||||
|
|
||||||
|
//Get a list of all jabber accounts
|
||||||
|
TDEGlobal::config()->setGroup("MSN");
|
||||||
|
TQString jab_account=TDEGlobal::config()->readEntry("JabberAccount");
|
||||||
|
|
||||||
|
TQPtrList<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts();
|
||||||
|
for(Kopete::Account *a=accounts.first() ; a; a=accounts.next() )
|
||||||
|
{
|
||||||
|
if(a->protocol()->pluginId()=="JabberProtocol")
|
||||||
|
{
|
||||||
|
d->ui->JabberAccount->insertItem(a->accountId());
|
||||||
|
if( jab_account.isEmpty() )
|
||||||
|
jab_account=a->accountId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d->ui->JabberAccount->setCurrentText(jab_account);
|
||||||
|
|
||||||
|
// FIXME: actually, I don't know how to set fonts for qlistboxitem - Olivier
|
||||||
|
d->ui->label_font->hide();
|
||||||
|
|
||||||
|
// default fields
|
||||||
|
if ( account )
|
||||||
|
{
|
||||||
|
TDEConfigGroup * config=account->configGroup();
|
||||||
|
|
||||||
|
d->ui->m_login->setText( account->accountId() );
|
||||||
|
d->ui->m_password->load( &static_cast<MSNAccount *>(account)->password() );
|
||||||
|
|
||||||
|
//remove me after we can change account ids (Matt)
|
||||||
|
d->ui->m_login->setDisabled( true );
|
||||||
|
d->ui->m_autologin->setChecked( account->excludeConnect() );
|
||||||
|
if ( ( static_cast<MSNAccount*>(account)->serverName() != "messenger.hotmail.com" ) || ( static_cast<MSNAccount*>(account)->serverPort() != 1863) ) {
|
||||||
|
d->ui->optionOverrideServer->setChecked( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
d->ui->m_webcamPort->setDisabled(true);
|
||||||
|
uint port=config->readNumEntry("WebcamPort" ,0);
|
||||||
|
d->ui->m_useWebcamPort->setChecked( port != 0);
|
||||||
|
d->ui->m_webcamPort->setValue( port != 0 ? port : 6891 );
|
||||||
|
|
||||||
|
d->ui->optionUseHttpMethod->setChecked( static_cast<MSNAccount*>(account)->useHttpMethod() );
|
||||||
|
|
||||||
|
MSNContact *myself = static_cast<MSNContact *>( account->myself() );
|
||||||
|
|
||||||
|
d->ui->m_displayName->setText( myself->property( Kopete::Global::Properties::self()->nickName()).value().toString() );
|
||||||
|
d->ui->m_phw->setText( config->readEntry("PHW") );
|
||||||
|
d->ui->m_phm->setText( config->readEntry("PHM") );
|
||||||
|
d->ui->m_phh->setText( config->readEntry("PHH") );
|
||||||
|
|
||||||
|
bool connected = account->isConnected();
|
||||||
|
if ( connected )
|
||||||
|
{
|
||||||
|
d->ui->m_warning_1->hide();
|
||||||
|
d->ui->m_warning_2->hide();
|
||||||
|
}
|
||||||
|
d->ui->m_phones->setEnabled( connected );
|
||||||
|
d->ui->m_displayName->setEnabled( connected );
|
||||||
|
d->ui->m_allowButton->setEnabled( connected );
|
||||||
|
d->ui->m_blockButton->setEnabled( connected );
|
||||||
|
|
||||||
|
MSNAccount *m_account = static_cast<MSNAccount*>( account );
|
||||||
|
d->ui->m_serverName->setText( m_account->serverName() );
|
||||||
|
d->ui->m_serverPort->setValue( m_account->serverPort() );
|
||||||
|
|
||||||
|
TQStringList blockList = config->readListEntry( "blockList" );
|
||||||
|
TQStringList allowList = config->readListEntry( "allowList" );
|
||||||
|
//TQStringList reverseList = config->readListEntry("reverseList" );
|
||||||
|
|
||||||
|
for ( TQStringList::Iterator it = blockList.begin(); it != blockList.end(); ++it )
|
||||||
|
d->ui->m_BL->insertItem( *it );
|
||||||
|
|
||||||
|
for ( TQStringList::Iterator it = allowList.begin(); it != allowList.end(); ++it )
|
||||||
|
d->ui->m_AL->insertItem( *it );
|
||||||
|
|
||||||
|
d->ui->m_blp->setChecked( config->readEntry( "BLP" ) == "BL" );
|
||||||
|
|
||||||
|
d->pictureUrl = locateLocal( "appdata", "msnpicture-" +
|
||||||
|
account->accountId().lower().replace( TQRegExp("[./~]" ), "-" ) + ".png" );
|
||||||
|
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
|
||||||
|
{
|
||||||
|
d->ui->tab_contacts->setDisabled( true );
|
||||||
|
d->ui->m_displayName->setDisabled( true );
|
||||||
|
d->ui->m_phones->setDisabled( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
connect( d->ui->m_allowButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAllow() ) );
|
||||||
|
connect( d->ui->m_blockButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBlock() ) );
|
||||||
|
connect( d->ui->m_selectImage, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSelectImage() ) );
|
||||||
|
connect( d->ui->m_RLButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotShowReverseList() ) );
|
||||||
|
connect( d->ui->buttonRegister, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotOpenRegister()));
|
||||||
|
TQWidget::setTabOrder( d->ui->m_login, d->ui->m_password->mRemembered );
|
||||||
|
TQWidget::setTabOrder( d->ui->m_password->mRemembered, d->ui->m_password->mPassword );
|
||||||
|
TQWidget::setTabOrder( d->ui->m_password->mPassword, d->ui->m_autologin );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNEditAccountWidget::~MSNEditAccountWidget()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kopete::Account * MSNEditAccountWidget::apply()
|
||||||
|
{
|
||||||
|
d->autoConfig->saveSettings();
|
||||||
|
TDEGlobal::config()->setGroup("MSN");
|
||||||
|
TDEGlobal::config()->writeEntry("JabberAccount", d->ui->JabberAccount->currentText());
|
||||||
|
|
||||||
|
if ( !account() )
|
||||||
|
setAccount( new MSNAccount( d->protocol, d->ui->m_login->text() ) );
|
||||||
|
|
||||||
|
TDEConfigGroup *config=account()->configGroup();
|
||||||
|
|
||||||
|
account()->setExcludeConnect( d->ui->m_autologin->isChecked() );
|
||||||
|
d->ui->m_password->save( &static_cast<MSNAccount *>(account())->password() );
|
||||||
|
|
||||||
|
config->writeEntry( "exportCustomPicture", d->ui->m_useDisplayPicture->isChecked() );
|
||||||
|
if (d->ui->optionOverrideServer->isChecked() ) {
|
||||||
|
config->writeEntry( "serverName", d->ui->m_serverName->text() );
|
||||||
|
config->writeEntry( "serverPort", d->ui->m_serverPort->value() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
config->writeEntry( "serverName", "messenger.hotmail.com" );
|
||||||
|
config->writeEntry( "serverPort", "1863" );
|
||||||
|
}
|
||||||
|
|
||||||
|
config->writeEntry( "useHttpMethod", d->ui->optionUseHttpMethod->isChecked() );
|
||||||
|
|
||||||
|
if(d->ui->m_useWebcamPort->isChecked())
|
||||||
|
config->writeEntry( "WebcamPort" , d->ui->m_webcamPort->value() );
|
||||||
|
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() )
|
||||||
|
{
|
||||||
|
d->pictureUrl = locateLocal( "appdata", "msnpicture-" +
|
||||||
|
account()->accountId().lower().replace( TQRegExp("[./~]" ), "-" ) + ".png" );
|
||||||
|
if ( d->pictureData.save( d->pictureUrl, "PNG" ) )
|
||||||
|
{
|
||||||
|
static_cast<MSNAccount *>( account() )->setPictureUrl( d->pictureUrl );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KMessageBox::sorry( this, i18n( "<qt>An error occurred when trying to change the display picture.<br>"
|
||||||
|
"Make sure that you have selected a correct image file</qt>" ), i18n( "MSN Plugin" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_cast<MSNAccount *>( account() )->resetPictureObject();
|
||||||
|
|
||||||
|
if ( account()->isConnected() )
|
||||||
|
{
|
||||||
|
MSNContact *myself = static_cast<MSNContact *>( account()->myself() );
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount *>( account() )->notifySocket();
|
||||||
|
if ( d->ui->m_displayName->text() != myself->property( Kopete::Global::Properties::self()->nickName()).value().toString() )
|
||||||
|
static_cast<MSNAccount *>( account() )->setPublicName( d->ui->m_displayName->text() );
|
||||||
|
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
if ( d->ui->m_phw->text() != myself->phoneWork() && ( !d->ui->m_phw->text().isEmpty() || !myself->phoneWork().isEmpty() ) )
|
||||||
|
notify->changePhoneNumber( "PHW", d->ui->m_phw->text() );
|
||||||
|
if( d->ui->m_phh->text() != myself->phoneHome() && ( !d->ui->m_phh->text().isEmpty() || !myself->phoneHome().isEmpty() ) )
|
||||||
|
notify->changePhoneNumber( "PHH", d->ui->m_phh->text() );
|
||||||
|
if( d->ui->m_phm->text() != myself->phoneMobile() && ( !d->ui->m_phm->text().isEmpty() || !myself->phoneMobile().isEmpty() ) )
|
||||||
|
notify->changePhoneNumber( "PHM", d->ui->m_phm->text() );
|
||||||
|
// (the && .isEmpty is because one can be null and the other empty)
|
||||||
|
|
||||||
|
if ( ( config->readEntry("BLP") == "BL" ) != d->ui->m_blp->isChecked() )
|
||||||
|
{
|
||||||
|
// Yes, I know, calling sendCommand here is not very clean - Olivier
|
||||||
|
notify->sendCommand( "BLP", d->ui->m_blp->isChecked() ? "BL" : "AL" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return account();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSNEditAccountWidget::validateData()
|
||||||
|
{
|
||||||
|
TQString userid = d->ui->m_login->text();
|
||||||
|
if ( MSNProtocol::validContactId( userid ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
|
||||||
|
i18n( "<qt>You must enter a valid email address.</qt>" ), i18n( "MSN Plugin" ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNEditAccountWidget::slotAllow()
|
||||||
|
{
|
||||||
|
//TODO: play with multiple selection
|
||||||
|
TQListBoxItem *item = d->ui->m_BL->selectedItem();
|
||||||
|
if ( !item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQString handle = item->text();
|
||||||
|
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount *>( account() )->notifySocket();
|
||||||
|
if ( !notify )
|
||||||
|
return;
|
||||||
|
notify->removeContact( handle, MSNProtocol::BL, TQString(), TQString() );
|
||||||
|
|
||||||
|
d->ui->m_BL->takeItem( item );
|
||||||
|
d->ui->m_AL->insertItem( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNEditAccountWidget::slotBlock()
|
||||||
|
{
|
||||||
|
//TODO: play with multiple selection
|
||||||
|
TQListBoxItem *item = d->ui->m_AL->selectedItem();
|
||||||
|
if ( !item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQString handle = item->text();
|
||||||
|
|
||||||
|
MSNNotifySocket *notify = static_cast<MSNAccount *>( account() )->notifySocket();
|
||||||
|
if ( !notify )
|
||||||
|
return;
|
||||||
|
|
||||||
|
notify->removeContact( handle, MSNProtocol::AL, TQString(), TQString() );
|
||||||
|
|
||||||
|
d->ui->m_AL->takeItem( item );
|
||||||
|
d->ui->m_BL->insertItem( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNEditAccountWidget::slotShowReverseList()
|
||||||
|
{
|
||||||
|
TQStringList reverseList = account()->configGroup()->readListEntry( "reverseList" );
|
||||||
|
KMessageBox::informationList( this, i18n( "Here you can see a list of contacts who added you to their contact list" ), reverseList,
|
||||||
|
i18n( "Reverse List - MSN Plugin" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNEditAccountWidget::slotSelectImage()
|
||||||
|
{
|
||||||
|
TQString path = 0;
|
||||||
|
bool remoteFile = false;
|
||||||
|
KURL filePath = KFileDialog::getImageOpenURL( TQString(), this, i18n( "MSN Display Picture" ) );
|
||||||
|
if( filePath.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !filePath.isLocalFile() ) {
|
||||||
|
if(!TDEIO::NetAccess::download( filePath, path, this )) {
|
||||||
|
KMessageBox::sorry( this, i18n( "Downloading of display image failed" ), i18n( "MSN Plugin" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remoteFile = true;
|
||||||
|
}
|
||||||
|
else path = filePath.path();
|
||||||
|
|
||||||
|
TQImage img( path );
|
||||||
|
img = KPixmapRegionSelectorDialog::getSelectedImage( TQPixmap(img), 96, 96, this );
|
||||||
|
|
||||||
|
if(!img.isNull())
|
||||||
|
{
|
||||||
|
img = MSNProtocol::protocol()->scalePicture(img);
|
||||||
|
|
||||||
|
d->ui->m_displayPicture->setPixmap( TQPixmap(img) );
|
||||||
|
d->pictureData = img;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KMessageBox::sorry( this, i18n( "<qt>An error occurred when trying to change the display picture.<br>"
|
||||||
|
"Make sure that you have selected a correct image file</qt>" ), i18n( "MSN Plugin" ) );
|
||||||
|
}
|
||||||
|
if( remoteFile ) TDEIO::NetAccess::removeTempFile( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNEditAccountWidget::slotOpenRegister()
|
||||||
|
{
|
||||||
|
KRun::runURL( "http://register.passport.net/", "text/html" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msneditaccountwidget.moc"
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
msneditaccountwidget.h - MSN Account Widget
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
Copyright (c) 2003 by Martijn Klingens <klingens@kde.org>
|
||||||
|
|
||||||
|
Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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 MSNEDITACCOUNTWIDEGET_H
|
||||||
|
#define MSNEDITACCOUNTWIDEGET_H
|
||||||
|
|
||||||
|
#include <tqwidget.h>
|
||||||
|
|
||||||
|
#include "editaccountwidget.h"
|
||||||
|
|
||||||
|
namespace Kopete { class Account; }
|
||||||
|
|
||||||
|
class MSNProtocol;
|
||||||
|
|
||||||
|
class MSNEditAccountWidgetPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Goffart <ogoffart @ kde.org>
|
||||||
|
*/
|
||||||
|
class MSNEditAccountWidget : public TQWidget, public KopeteEditAccountWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNEditAccountWidget( MSNProtocol *proto, Kopete::Account *account, TQWidget *parent = 0, const char *name = 0 );
|
||||||
|
~MSNEditAccountWidget();
|
||||||
|
virtual bool validateData();
|
||||||
|
virtual Kopete::Account * apply();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotAllow();
|
||||||
|
void slotBlock();
|
||||||
|
void slotShowReverseList();
|
||||||
|
void slotSelectImage();
|
||||||
|
void slotOpenRegister();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MSNEditAccountWidgetPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: set noet ts=4 sts=4 sw=4:
|
||||||
|
|
@ -0,0 +1,221 @@
|
|||||||
|
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
|
||||||
|
<class>MSNInfo</class>
|
||||||
|
<widget class="TQWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>MSNInfo</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>457</width>
|
||||||
|
<height>360</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<vbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Layout22</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel2_2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>4</hsizetype>
|
||||||
|
<vsizetype>4</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Email address:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_id</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Layout22_2</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel2_2_2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy>
|
||||||
|
<hsizetype>4</hsizetype>
|
||||||
|
<vsizetype>4</vsizetype>
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Display name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_displayName</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLayoutWidget">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>layout3</cstring>
|
||||||
|
</property>
|
||||||
|
<hbox>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>textLabel1</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Personal message:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_personalMessage</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</hbox>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQGroupBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>GroupBox2</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Phones</string>
|
||||||
|
</property>
|
||||||
|
<grid>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>unnamed</cstring>
|
||||||
|
</property>
|
||||||
|
<widget class="TQLabel" row="1" column="0">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel5</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Home:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel" row="0" column="0">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel6</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Work:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit" row="0" column="1">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_phw</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit" row="1" column="1">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_phh</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLabel" row="2" column="0">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>TextLabel7</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Mobile:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQLineEdit" row="2" column="1">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_phm</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</grid>
|
||||||
|
</widget>
|
||||||
|
<widget class="TQCheckBox">
|
||||||
|
<property name="name">
|
||||||
|
<cstring>m_reversed</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>I am on &the contact list of this contact</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip" stdset="0">
|
||||||
|
<string>Show whether you are on the contact list of this user</string>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis" stdset="0">
|
||||||
|
<string>If this box is checked, you are on this user's contact list.
|
||||||
|
If not, the user has not added you to their list, or has removed you.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<spacer>
|
||||||
|
<property name="name">
|
||||||
|
<cstring>Spacer10</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>
|
||||||
|
</vbox>
|
||||||
|
</widget>
|
||||||
|
<layoutdefaults spacing="6" margin="11"/>
|
||||||
|
</UI>
|
@ -0,0 +1,891 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "webcam.h"
|
||||||
|
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <kbufferedsocket.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
#include <kserversocket.h>
|
||||||
|
#include <tdemessagebox.h>
|
||||||
|
#include <tqlabel.h>
|
||||||
|
#include <tqguardedptr.h>
|
||||||
|
#include <tqtimer.h>
|
||||||
|
#include <tqevent.h>
|
||||||
|
#include <tqdatetime.h>
|
||||||
|
#include <tdeconfig.h>
|
||||||
|
|
||||||
|
#include "dispatcher.h"
|
||||||
|
|
||||||
|
#include "mimicwrapper.h"
|
||||||
|
#include "msnwebcamdialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "avdevice/videodevicepool.h"
|
||||||
|
|
||||||
|
using namespace KNetwork;
|
||||||
|
|
||||||
|
namespace P2P {
|
||||||
|
|
||||||
|
Webcam::Webcam(Who who, const TQString& to, Dispatcher *parent, TQ_UINT32 sessionId)
|
||||||
|
: TransferContext(to,parent,sessionId) , m_who(who) , m_timerId(0)
|
||||||
|
{
|
||||||
|
setType(P2P::WebcamType);
|
||||||
|
m_direction = Incoming;
|
||||||
|
m_listener = 0l;
|
||||||
|
m_webcamSocket=0L;
|
||||||
|
// m_webcamState=wsNegotiating;
|
||||||
|
|
||||||
|
m_mimic=0L;
|
||||||
|
m_widget=0L;
|
||||||
|
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
|
||||||
|
// Read the configuration to get the number of frame per second to send
|
||||||
|
int webCamFps=config->readNumEntry("WebcamFPS", 25);
|
||||||
|
m_timerFps = 1000 / webCamFps;
|
||||||
|
}
|
||||||
|
|
||||||
|
Webcam::~Webcam()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo<< "################################################" << endl;
|
||||||
|
m_dispatcher=0l;
|
||||||
|
delete m_mimic;
|
||||||
|
delete m_webcamSocket;
|
||||||
|
delete m_widget;
|
||||||
|
|
||||||
|
if(m_timerId != 0) //if we were sending
|
||||||
|
{
|
||||||
|
Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
|
||||||
|
videoDevice->stopCapturing();
|
||||||
|
videoDevice->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::askIncommingInvitation()
|
||||||
|
{
|
||||||
|
m_direction = Incoming;
|
||||||
|
//protect, in case this is deleted when the messagebox is active
|
||||||
|
TQGuardedPtr<Webcam> _this = this;
|
||||||
|
TQString message= (m_who==wProducer) ?
|
||||||
|
i18n("<qt>The contact %1 wants to see <b>your</b> webcam, do you want them to see it?</qt>") :
|
||||||
|
i18n("The contact %1 wants to show you his/her webcam, do you want to see it?") ;
|
||||||
|
int result=KMessageBox::questionYesNo( 0L , message.arg(m_recipient),
|
||||||
|
i18n("Webcam invitation - Kopete MSN Plugin") , i18n("Accept") , i18n("Decline"));
|
||||||
|
if(!_this)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TQString content = TQString("SessionID: %1\r\n\r\n").arg(m_sessionId);
|
||||||
|
if(result==KMessageBox::Yes)
|
||||||
|
{
|
||||||
|
//Send two message, an OK, and an invite.
|
||||||
|
//Normaly, the user should decline the invite (i hope)
|
||||||
|
|
||||||
|
// Send a 200 OK message to the recipient.
|
||||||
|
sendMessage(OK, content);
|
||||||
|
|
||||||
|
|
||||||
|
//send an INVITE message we want the user decline
|
||||||
|
//need to change the branch of the second message
|
||||||
|
m_branch=Uid::createUid();
|
||||||
|
m_state = Negotiation; //set type to application/x-msnmsgr-transreqbody
|
||||||
|
|
||||||
|
content=TQString("Bridges: TRUDPv1 TCPv1\r\n"
|
||||||
|
"NetID: -1280904111\r\n"
|
||||||
|
"Conn-Type: Firewall\r\n"
|
||||||
|
"UPnPNat: false\r\n"
|
||||||
|
"ICF: false\r\n\r\n");
|
||||||
|
|
||||||
|
sendMessage(INVITE, content);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Decline the invitation
|
||||||
|
sendMessage(DECLINE, content);
|
||||||
|
m_state=Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::sendBYEMessage()
|
||||||
|
{
|
||||||
|
m_state=Finished;
|
||||||
|
TQString content="Context: dAMAgQ==\r\n";
|
||||||
|
sendMessage(BYE,content);
|
||||||
|
|
||||||
|
//If ever the opposite client was dead or something, we'll ack anyway, so everything get cleaned
|
||||||
|
TQTimer::singleShot(60*1000 , this, TQT_SLOT(acknowledged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Webcam::acknowledged()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
switch(m_state)
|
||||||
|
{
|
||||||
|
case Invitation:
|
||||||
|
{
|
||||||
|
// m_state=Negotiation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
case Negotiation:
|
||||||
|
{
|
||||||
|
if(m_type == UserDisplayIcon)
|
||||||
|
{
|
||||||
|
<<< Data preparation acknowledge message.
|
||||||
|
m_state = DataTransfer;
|
||||||
|
m_identifier++;
|
||||||
|
Start sending data.
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DataTransfer:
|
||||||
|
NOTE <<< Data acknowledged message.
|
||||||
|
<<< Bye message should follow.
|
||||||
|
if(m_type == File)
|
||||||
|
{
|
||||||
|
if(m_handshake == 0x01)
|
||||||
|
{
|
||||||
|
Data handshake acknowledge message.
|
||||||
|
Start sending data.
|
||||||
|
slotSendData();
|
||||||
|
}
|
||||||
|
else if(m_handshake == 0x02)
|
||||||
|
{
|
||||||
|
Data acknowledge message.
|
||||||
|
Send the recipient a BYE message.
|
||||||
|
m_state = Finished;
|
||||||
|
sendMessage(BYE, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case Finished:
|
||||||
|
//BYE or DECLINE acknowledge message.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Webcam::processMessage(const Message& message)
|
||||||
|
{
|
||||||
|
if(message.header.dataOffset+message.header.dataSize >= message.header.totalDataSize)
|
||||||
|
acknowledge( message ); //aknowledge if needed
|
||||||
|
|
||||||
|
if(message.applicationIdentifier != 4l)
|
||||||
|
{
|
||||||
|
TQString body = TQCString(message.body.data(), message.header.dataSize);
|
||||||
|
kdDebug(14141) << k_funcinfo << "received, " << body << endl;
|
||||||
|
|
||||||
|
if(body.startsWith("MSNSLP/1.0 200 OK"))
|
||||||
|
{
|
||||||
|
m_direction = Outgoing;
|
||||||
|
}
|
||||||
|
if(body.startsWith("INVITE"))
|
||||||
|
{
|
||||||
|
if(m_direction == Outgoing)
|
||||||
|
{
|
||||||
|
TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
|
||||||
|
regex.search(body);
|
||||||
|
m_branch=regex.cap(1);
|
||||||
|
//decline
|
||||||
|
sendMessage(DECLINE);
|
||||||
|
makeSIPMessage("syn",0x17,0x2a,0x01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(body.startsWith("MSNSLP/1.0 603 DECLINE"))
|
||||||
|
{
|
||||||
|
//if it is the declinaison of the second invite message, we have to don't care
|
||||||
|
//TODO anyway, if it's the declinaison of our invitation, we have to something
|
||||||
|
}
|
||||||
|
else if(body.startsWith("BYE"))
|
||||||
|
{
|
||||||
|
m_state = Finished;
|
||||||
|
|
||||||
|
// Dispose of this transfer context.
|
||||||
|
m_dispatcher->detach(this);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Let's take the fun, we entering into the delicious webcam negotiation binary protocol
|
||||||
|
|
||||||
|
//well, there is maybe better to take utf16, but it's ascii, so no problem.
|
||||||
|
TQByteArray dataMessage=message.body;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TQString echoS="";
|
||||||
|
unsigned int f=0;
|
||||||
|
while(f<dataMessage.size())
|
||||||
|
{
|
||||||
|
echoS+="\n";
|
||||||
|
for(unsigned int q=0; q<16 ; q++)
|
||||||
|
{
|
||||||
|
if(q+f<dataMessage.size())
|
||||||
|
{
|
||||||
|
unsigned int N=(unsigned int) (dataMessage[q+f]);
|
||||||
|
if(N<16)
|
||||||
|
echoS+="0";
|
||||||
|
echoS+=TQString::number( N ,16)+" ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echoS+=" ";
|
||||||
|
}
|
||||||
|
echoS+=" ";
|
||||||
|
|
||||||
|
for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
|
||||||
|
{
|
||||||
|
unsigned char X=dataMessage[q+f];
|
||||||
|
char C=((char)(( X<128 && X>31 ) ? X : '.'));
|
||||||
|
echoS+=TQString::fromLatin1(&C,1);
|
||||||
|
}
|
||||||
|
f+=16;
|
||||||
|
}
|
||||||
|
kdDebug(14141) << k_funcinfo << dataMessage.size() << echoS << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for(uint pos=m_content.isNull() ? 10 : 0; pos<dataMessage.size(); pos+=2)
|
||||||
|
{
|
||||||
|
if(dataMessage[pos] !=0 )
|
||||||
|
m_content+=dataMessage[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message.header.dataOffset+message.header.dataSize < message.header.totalDataSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kdDebug(14141) << k_funcinfo << "Message contents: " << m_content << "\n" << endl;
|
||||||
|
if(m_content.startsWith("syn"))
|
||||||
|
{
|
||||||
|
if(m_direction == Incoming)
|
||||||
|
makeSIPMessage("syn",0x17,0x2a,0x01);
|
||||||
|
else
|
||||||
|
makeSIPMessage("ack",0xea,0x00,0x00);
|
||||||
|
}
|
||||||
|
else if(m_content.startsWith("ack"))
|
||||||
|
{
|
||||||
|
if(m_direction == Incoming)
|
||||||
|
makeSIPMessage("ack",0xea,0x00,0x00);
|
||||||
|
|
||||||
|
if(m_who==wProducer)
|
||||||
|
{
|
||||||
|
uint sess=rand()%1000+5000;
|
||||||
|
uint rid=rand()%100+50;
|
||||||
|
m_myAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid).arg(sess);
|
||||||
|
kdDebug(14140) << k_funcinfo << "m_myAuth= " << m_myAuth << endl;
|
||||||
|
TQString producerxml=xml(sess , rid);
|
||||||
|
kdDebug(14140) << k_funcinfo << "producerxml= " << producerxml << endl;
|
||||||
|
makeSIPMessage(producerxml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(m_content.contains("<producer>") || m_content.contains("<viewer>"))
|
||||||
|
{
|
||||||
|
TQRegExp rx("<rid>([0-9]*)</rid>.*<session>([0-9]*)</session>");
|
||||||
|
rx.search(m_content);
|
||||||
|
TQString rid=rx.cap(1);
|
||||||
|
TQString sess=rx.cap(2);
|
||||||
|
if(m_content.contains("<producer>"))
|
||||||
|
{
|
||||||
|
|
||||||
|
TQString viewerxml=xml(sess.toUInt() , rid.toUInt());
|
||||||
|
kdDebug(14140) << k_funcinfo << "vewerxml= " << viewerxml << endl;
|
||||||
|
makeSIPMessage( viewerxml ,0x00,0x09,0x00 );
|
||||||
|
m_peerAuth=m_myAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
|
||||||
|
kdDebug(14140) << k_funcinfo << "m_auth= " << m_myAuth << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_peerAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
|
||||||
|
|
||||||
|
makeSIPMessage("receivedViewerData", 0xec , 0xda , 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_listener)
|
||||||
|
{
|
||||||
|
//it should have been creed in xml
|
||||||
|
sendBYEMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//m_listener->setResolutionEnabled(true);
|
||||||
|
// Create the callback that will try to accept incoming connections.
|
||||||
|
TQObject::connect(m_listener, TQT_SIGNAL(readyAccept()), this, TQT_SLOT(slotAccept()));
|
||||||
|
TQObject::connect(m_listener, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotListenError(int)));
|
||||||
|
// Listen for incoming connections.
|
||||||
|
bool isListening = m_listener->listen();
|
||||||
|
kdDebug(14140) << k_funcinfo << (isListening ? TQString("listening %1").arg(m_listener->localAddress().toString()) : TQString("not listening")) << endl;
|
||||||
|
|
||||||
|
rx=TQRegExp("<tcpport>([^<]*)</tcpport>");
|
||||||
|
rx.search(m_content);
|
||||||
|
TQString port1=rx.cap(1);
|
||||||
|
if(port1=="0")
|
||||||
|
port1=TQString();
|
||||||
|
|
||||||
|
rx=TQRegExp("<tcplocalport>([^<]*)</tcplocalport>");
|
||||||
|
rx.search(m_content);
|
||||||
|
TQString port2=rx.cap(1);
|
||||||
|
if(port2==port1 || port2=="0")
|
||||||
|
port2=TQString();
|
||||||
|
|
||||||
|
rx=TQRegExp("<tcpexternalport>([^<]*)</tcpexternalport>");
|
||||||
|
rx.search(m_content);
|
||||||
|
TQString port3=rx.cap(1);
|
||||||
|
if(port3==port1 || port3==port2 || port3=="0")
|
||||||
|
port3=TQString();
|
||||||
|
|
||||||
|
int an=0;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
an++;
|
||||||
|
if(!m_content.contains( TQString("<tcpipaddress%1>").arg(an) ))
|
||||||
|
break;
|
||||||
|
rx=TQRegExp(TQString("<tcpipaddress%1>([^<]*)</tcpipaddress%2>").arg(an).arg(an));
|
||||||
|
rx.search(m_content);
|
||||||
|
TQString ip=rx.cap(1);
|
||||||
|
if(ip.isNull())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!port1.isNull())
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port1 << endl;
|
||||||
|
TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port1, this );
|
||||||
|
m_allSockets.append(sock);
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
sock->connect(ip, port1);
|
||||||
|
kdDebug(14140) << k_funcinfo << "okok " << sock << " - " << sock->peerAddress().toString() << " ; " << sock->localAddress().toString() << endl;
|
||||||
|
}
|
||||||
|
if(!port2.isNull())
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port2 << endl;
|
||||||
|
TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port2, this );
|
||||||
|
m_allSockets.append(sock);
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
sock->connect(ip, port2);
|
||||||
|
}
|
||||||
|
if(!port3.isNull())
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port3 << endl;
|
||||||
|
TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port3, this );
|
||||||
|
m_allSockets.append(sock);
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
|
||||||
|
TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
sock->connect(ip, port3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TQValueList<TDEBufferedSocket*>::iterator it;
|
||||||
|
for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
|
||||||
|
{
|
||||||
|
TDEBufferedSocket *sock=(*it);
|
||||||
|
|
||||||
|
//sock->enableRead( false );
|
||||||
|
kdDebug(14140) << k_funcinfo << "connect to " << sock << " - "<< sock->peerAddress().toString() << " ; " << sock->localAddress().toString() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(m_content.contains("receivedViewerData"))
|
||||||
|
{
|
||||||
|
//I'm happy you received the xml i sent, really.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error();
|
||||||
|
m_content=TQString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::makeSIPMessage(const TQString &message, TQ_UINT8 XX, TQ_UINT8 YY , TQ_UINT8 ZZ)
|
||||||
|
{
|
||||||
|
TQByteArray dataMessage; //(12+message.length()*2);
|
||||||
|
TQDataStream writer(dataMessage, IO_WriteOnly);
|
||||||
|
writer.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
writer << (TQ_UINT8)0x80;
|
||||||
|
writer << (TQ_UINT8)XX;
|
||||||
|
writer << (TQ_UINT8)YY;
|
||||||
|
writer << (TQ_UINT8)ZZ;
|
||||||
|
writer << (TQ_UINT8)0x08;
|
||||||
|
writer << (TQ_UINT8)0x00;
|
||||||
|
writer << message+'\0';
|
||||||
|
//writer << (TQ_UINT16)0x0000;
|
||||||
|
|
||||||
|
/*TQString echoS="";
|
||||||
|
unsigned int f=0;
|
||||||
|
while(f<dataMessage.size())
|
||||||
|
{
|
||||||
|
echoS+="\n";
|
||||||
|
for(unsigned int q=0; q<16 ; q++)
|
||||||
|
{
|
||||||
|
if(q+f<dataMessage.size())
|
||||||
|
{
|
||||||
|
unsigned int N=(unsigned int) (dataMessage[q+f]);
|
||||||
|
if(N<16)
|
||||||
|
echoS+="0";
|
||||||
|
echoS+=TQString::number( N ,16)+" ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echoS+=" ";
|
||||||
|
}
|
||||||
|
echoS+=" ";
|
||||||
|
|
||||||
|
for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
|
||||||
|
{
|
||||||
|
unsigned char X=dataMessage[q+f];
|
||||||
|
char C=((char)(( X<128 && X>31 ) ? X : '.'));
|
||||||
|
echoS+=TQString::fromLatin1(&C,1);
|
||||||
|
}
|
||||||
|
f+=16;
|
||||||
|
}
|
||||||
|
kdDebug(14141) << k_funcinfo << dataMessage.size() << echoS << endl;*/
|
||||||
|
|
||||||
|
|
||||||
|
sendBigP2PMessage(dataMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::sendBigP2PMessage( const TQByteArray & dataMessage)
|
||||||
|
{
|
||||||
|
unsigned int size=m_totalDataSize=dataMessage.size();
|
||||||
|
m_offset=0;
|
||||||
|
++m_identifier;
|
||||||
|
|
||||||
|
for(unsigned int f=0;f<size;f+=1200)
|
||||||
|
{
|
||||||
|
m_offset=f;
|
||||||
|
TQByteArray dm2;
|
||||||
|
dm2.duplicate(dataMessage.data()+m_offset, TQMIN(1200,m_totalDataSize-m_offset));
|
||||||
|
sendData( dm2 );
|
||||||
|
m_offset+=dm2.size();
|
||||||
|
}
|
||||||
|
m_offset=0;
|
||||||
|
m_totalDataSize=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TQString Webcam::xml(uint session , uint rid)
|
||||||
|
{
|
||||||
|
TQString who= ( m_who == wProducer ) ? TQString("producer") : TQString("viewer");
|
||||||
|
|
||||||
|
TQString ip;
|
||||||
|
|
||||||
|
uint ip_number=1;
|
||||||
|
TQStringList::iterator it;
|
||||||
|
TQStringList ips=m_dispatcher->localIp();
|
||||||
|
for ( it = ips.begin(); it != ips.end(); ++it )
|
||||||
|
{
|
||||||
|
ip+=TQString("<tcpipaddress%1>%2</tcpipaddress%3>").arg(ip_number).arg(*it).arg(ip_number);
|
||||||
|
++ip_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString port = TQString::number(getAvailablePort());
|
||||||
|
|
||||||
|
m_listener = new TDEServerSocket(port, this) ;
|
||||||
|
|
||||||
|
return "<" + who + "><version>2.0</version><rid>"+TQString::number(rid)+"</rid><udprid>"+TQString::number(rid+1)+"</udprid><session>"+TQString::number(session)+"</session><ctypes>0</ctypes><cpu>2931</cpu>" +
|
||||||
|
"<tcp><tcpport>"+port+"</tcpport>\t\t\t\t\t\t\t\t <tcplocalport>"+port+"</tcplocalport>\t\t\t\t\t\t\t\t <tcpexternalport>"+port+"</tcpexternalport>"+ip+"</tcp>"+
|
||||||
|
"<udp><udplocalport>7786</udplocalport><udpexternalport>31863</udpexternalport><udpexternalip>"+ ip +"</udpexternalip><a1_port>31859</a1_port><b1_port>31860</b1_port><b2_port>31861</b2_port><b3_port>31862</b3_port><symmetricallocation>1</symmetricallocation><symmetricallocationincrement>1</symmetricallocationincrement><udpversion>1</udpversion><udpinternalipaddress1>127.0.0.1</udpinternalipaddress1></udp>"+
|
||||||
|
"<codec></codec><channelmode>1</channelmode></"+who+">\r\n\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int Webcam::getAvailablePort()
|
||||||
|
{
|
||||||
|
TDEConfig *config = TDEGlobal::config();
|
||||||
|
config->setGroup( "MSN" );
|
||||||
|
TQString 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
|
||||||
|
//
|
||||||
|
TDEServerSocket *ss = new TDEServerSocket();
|
||||||
|
ss->setFamily(KResolver::InetFamily);
|
||||||
|
bool found = false;
|
||||||
|
unsigned int port = firstport;
|
||||||
|
for( ; port <= lastport; ++port) {
|
||||||
|
ss->setAddress( TQString::number( port ) );
|
||||||
|
bool success = ss->listen();
|
||||||
|
if( found = ( success && ss->error() == TDESocketBase::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()
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo <<"##########################" << endl;
|
||||||
|
|
||||||
|
m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
|
||||||
|
if(!m_webcamSocket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "Connection established on " << m_webcamSocket->peerAddress().toString() << " ; " << m_webcamSocket->localAddress().toString() << endl;
|
||||||
|
|
||||||
|
m_webcamSocket->setBlocking(false);
|
||||||
|
m_webcamSocket->enableRead(true);
|
||||||
|
m_webcamSocket->enableWrite(false);
|
||||||
|
|
||||||
|
// Create the callback that will try to read bytes from the accepted socket.
|
||||||
|
TQObject::connect(m_webcamSocket, TQT_SIGNAL(readyRead()), this, TQT_SLOT(slotSocketRead()));
|
||||||
|
// Create the callback that will try to handle the socket close event.
|
||||||
|
TQObject::connect(m_webcamSocket, TQT_SIGNAL(closed()), this, TQT_SLOT(slotSocketClosed()));
|
||||||
|
// Create the callback that will try to handle the socket error event.
|
||||||
|
// TQObject::connect(m_webcamSocket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
|
||||||
|
m_webcamStates[m_webcamSocket]=wsConnected;
|
||||||
|
TQCString to_send=m_peerAuth.utf8();
|
||||||
|
m_webcamSocket->writeBlock(to_send.data(), to_send.length());
|
||||||
|
kdDebug(14140) << k_funcinfo << "sending "<< m_peerAuth << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Webcam::slotAccept()
|
||||||
|
{
|
||||||
|
// Try to accept an incoming connection from the sending client.
|
||||||
|
m_webcamSocket = static_cast<TDEBufferedSocket*>(m_listener->accept());
|
||||||
|
if(!m_webcamSocket)
|
||||||
|
{
|
||||||
|
// NOTE If direct connection fails, the sending
|
||||||
|
// client wil transfer the file data through the
|
||||||
|
// existing session.
|
||||||
|
kdDebug(14140) << k_funcinfo << "Direct connection failed." << endl;
|
||||||
|
// Close the listening endpoint.
|
||||||
|
// m_listener->close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "################################ Direct connection established." << endl;
|
||||||
|
|
||||||
|
// Set the socket to non blocking,
|
||||||
|
// enable the ready read signal and disable
|
||||||
|
// ready write signal.
|
||||||
|
// NOTE readyWrite consumes too much cpu usage.
|
||||||
|
m_webcamSocket->setBlocking(false);
|
||||||
|
m_webcamSocket->enableRead(true);
|
||||||
|
m_webcamSocket->enableWrite(false);
|
||||||
|
|
||||||
|
// Create the callback that will try to read bytes from the accepted socket.
|
||||||
|
TQObject::connect(m_webcamSocket, TQT_SIGNAL(readyRead()), this, TQT_SLOT(slotSocketRead()));
|
||||||
|
// Create the callback that will try to handle the socket close event.
|
||||||
|
TQObject::connect(m_webcamSocket, TQT_SIGNAL(closed()), this, TQT_SLOT(slotSocketClosed()));
|
||||||
|
// Create the callback that will try to handle the socket error event.
|
||||||
|
TQObject::connect(m_webcamSocket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
|
||||||
|
|
||||||
|
m_allSockets.append(m_webcamSocket);
|
||||||
|
m_webcamStates[m_webcamSocket]=wsNegotiating;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::slotSocketRead()
|
||||||
|
{
|
||||||
|
m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
|
||||||
|
|
||||||
|
uint available = m_webcamSocket->bytesAvailable();
|
||||||
|
kdDebug(14140) << k_funcinfo << m_webcamSocket << "############# " << available << " bytes available." << endl;
|
||||||
|
|
||||||
|
TQByteArray avail_buff(available);
|
||||||
|
m_webcamSocket->peekBlock(avail_buff.data(), avail_buff.size());
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << m_webcamSocket << avail_buff << endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const TQString connected_str("connected\r\n\r\n");
|
||||||
|
switch(m_webcamStates[m_webcamSocket])
|
||||||
|
{
|
||||||
|
case wsNegotiating:
|
||||||
|
{
|
||||||
|
if(available < m_myAuth.length())
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "waiting more data ( " << available << " of " <<m_myAuth.length()<< " )"<< endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TQByteArray buffer(available);
|
||||||
|
m_webcamSocket->readBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << buffer.data() << endl;
|
||||||
|
|
||||||
|
if(TQString(buffer) == m_myAuth )
|
||||||
|
{
|
||||||
|
closeAllOtherSockets();
|
||||||
|
kdDebug(14140) << k_funcinfo << "Sending " << connected_str << endl;
|
||||||
|
TQCString conne=connected_str.utf8();
|
||||||
|
m_webcamSocket->writeBlock(conne.data(), conne.length());
|
||||||
|
m_webcamStates[m_webcamSocket]=wsConnecting;
|
||||||
|
|
||||||
|
//SHOULD NOT BE THERE
|
||||||
|
m_mimic=new MimicWrapper();
|
||||||
|
if(m_who==wProducer)
|
||||||
|
{
|
||||||
|
Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
|
||||||
|
videoDevice->open();
|
||||||
|
videoDevice->setSize(320, 240);
|
||||||
|
videoDevice->startCapturing();
|
||||||
|
|
||||||
|
m_timerId=startTimer(m_timerFps);
|
||||||
|
kdDebug(14140) << k_funcinfo << "new timer" << m_timerId << endl;
|
||||||
|
}
|
||||||
|
m_widget=new MSNWebcamDialog(m_recipient);
|
||||||
|
connect(m_widget, TQT_SIGNAL( closingWebcamDialog() ) , this , TQT_SLOT(sendBYEMessage()));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Auth failed" << endl;
|
||||||
|
m_webcamSocket->disconnect();
|
||||||
|
m_webcamSocket->deleteLater();
|
||||||
|
m_allSockets.remove(m_webcamSocket);
|
||||||
|
m_webcamSocket=0l;
|
||||||
|
//sendBYEMessage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case wsConnecting:
|
||||||
|
case wsConnected:
|
||||||
|
{
|
||||||
|
if(available < connected_str.length())
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "waiting more data ( " << available << " of " <<connected_str.length()<< " )"<< endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TQByteArray buffer(connected_str.length());
|
||||||
|
m_webcamSocket->readBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
// kdDebug(14140) << k_funcinfo << "state " << m_webcamState << " received :" << TQCString(buffer) << endl;
|
||||||
|
|
||||||
|
|
||||||
|
if(TQString(buffer) == connected_str)
|
||||||
|
{
|
||||||
|
if(m_webcamStates[m_webcamSocket]==wsConnected)
|
||||||
|
{
|
||||||
|
closeAllOtherSockets();
|
||||||
|
kdDebug(14140) << k_funcinfo << "Sending " << connected_str << endl;
|
||||||
|
TQCString conne=connected_str.utf8();
|
||||||
|
m_webcamSocket->writeBlock(conne.data(), conne.length());
|
||||||
|
|
||||||
|
//SHOULD BE DONE IN ALL CASE
|
||||||
|
m_mimic=new MimicWrapper();
|
||||||
|
if(m_who==wProducer)
|
||||||
|
{
|
||||||
|
Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
|
||||||
|
videoDevice->open();
|
||||||
|
videoDevice->setSize(320, 240);
|
||||||
|
videoDevice->startCapturing();
|
||||||
|
|
||||||
|
m_timerId=startTimer(m_timerFps);
|
||||||
|
kdDebug(14140) << k_funcinfo << "new timer" << m_timerId << endl;
|
||||||
|
}
|
||||||
|
m_widget=new MSNWebcamDialog(m_recipient);
|
||||||
|
connect(m_widget, TQT_SIGNAL( closingWebcamDialog() ) , this , TQT_SLOT(sendBYEMessage()));
|
||||||
|
|
||||||
|
}
|
||||||
|
m_webcamStates[m_webcamSocket]=wsTransfer;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Connecting failed" << endl;
|
||||||
|
m_webcamSocket->disconnect();
|
||||||
|
m_webcamSocket->deleteLater();
|
||||||
|
m_allSockets.remove(m_webcamSocket);
|
||||||
|
m_webcamSocket=0l;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case wsTransfer:
|
||||||
|
{
|
||||||
|
if(m_who==wProducer)
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "data received when we are producer"<< endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(available < 24)
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "waiting more data ( " << available << " of " <<24<< " )"<< endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TQByteArray buffer(24);
|
||||||
|
m_webcamSocket->peekBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
TQ_UINT32 paysize=(uchar)buffer[8] + ((uchar)buffer[9]<<8) + ((uchar)buffer[10]<<16) + ((uchar)buffer[11]<<24);
|
||||||
|
|
||||||
|
if(available < (paysize+24))
|
||||||
|
{
|
||||||
|
kdDebug(14140) << k_funcinfo << "waiting more data ( " << available << " of " <<paysize<< " )"<< endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_webcamSocket->readBlock(buffer.data(), 24); //flush
|
||||||
|
buffer.resize(paysize);
|
||||||
|
m_webcamSocket->readBlock(buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
TQPixmap pix=m_mimic->decode(buffer);
|
||||||
|
if(pix.isNull())
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "incorrect pixmap returned, better to stop everything"<< endl;
|
||||||
|
m_webcamSocket->disconnect();
|
||||||
|
sendBYEMessage();
|
||||||
|
}
|
||||||
|
m_widget->newImage(pix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::slotListenError(int errorCode)
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Error " << errorCode << " : " << m_listener->errorString() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::slotSocketClosed()
|
||||||
|
{
|
||||||
|
if(!m_dispatcher) //we are in this destructor
|
||||||
|
return;
|
||||||
|
|
||||||
|
TDEBufferedSocket *m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << m_webcamSocket << endl;
|
||||||
|
|
||||||
|
if(m_listener)
|
||||||
|
{ //if we are still waiting for other socket to connect, just remove this socket from the socket list
|
||||||
|
m_webcamSocket->disconnect();
|
||||||
|
m_webcamSocket->deleteLater();
|
||||||
|
m_allSockets.remove(m_webcamSocket);
|
||||||
|
m_webcamSocket=0l;
|
||||||
|
}
|
||||||
|
else // else, close the session
|
||||||
|
sendBYEMessage();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::slotSocketError(int errorCode)
|
||||||
|
{
|
||||||
|
TDEBufferedSocket *socket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
|
||||||
|
kdDebug(14140) << k_funcinfo << socket << " - " << errorCode << " : " << socket->TDESocketBase::errorString() << endl;
|
||||||
|
//sendBYEMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webcam::closeAllOtherSockets()
|
||||||
|
{
|
||||||
|
//m_lisener->close();
|
||||||
|
delete m_listener;
|
||||||
|
m_listener=0l;
|
||||||
|
|
||||||
|
TQValueList<TDEBufferedSocket*>::iterator it;
|
||||||
|
for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
|
||||||
|
{
|
||||||
|
TDEBufferedSocket *sock=(*it);
|
||||||
|
if(sock != m_webcamSocket)
|
||||||
|
delete sock;
|
||||||
|
}
|
||||||
|
m_allSockets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Webcam::timerEvent( TQTimerEvent *e )
|
||||||
|
{
|
||||||
|
if(e->timerId() != m_timerId)
|
||||||
|
return TransferContext::timerEvent(e);
|
||||||
|
|
||||||
|
// kdDebug(14140) << k_funcinfo << endl;
|
||||||
|
|
||||||
|
Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
|
||||||
|
videoDevice->getFrame();
|
||||||
|
TQImage img;
|
||||||
|
videoDevice->getImage(&img);
|
||||||
|
|
||||||
|
if(m_widget)
|
||||||
|
m_widget->newImage(img);
|
||||||
|
|
||||||
|
if(img.width()!=320 || img.height()!=240)
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Bad image size " <<img.width() << "x" << img.height() << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *bits=img.bits();
|
||||||
|
TQByteArray image_data(img.width()*img.height()*3);
|
||||||
|
uint b2=0;
|
||||||
|
uint imgsize=img.width()*img.height()*4;
|
||||||
|
for(uint f=0; f< imgsize; f+=4)
|
||||||
|
{
|
||||||
|
image_data[b2+0]=bits[f+2];
|
||||||
|
image_data[b2+1]=bits[f+1];
|
||||||
|
image_data[b2+2]=bits[f+0];
|
||||||
|
b2+=3;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray frame=m_mimic->encode(image_data);
|
||||||
|
|
||||||
|
|
||||||
|
kdDebug(14140) << k_funcinfo << "Sendinf frame of size " << frame.size() << endl;
|
||||||
|
//build the header.
|
||||||
|
TQByteArray header;
|
||||||
|
|
||||||
|
TQDataStream writer(header, IO_WriteOnly);
|
||||||
|
writer.setByteOrder(TQDataStream::LittleEndian);
|
||||||
|
writer << (TQ_UINT16)24; // header size
|
||||||
|
writer << (TQ_UINT16)img.width();
|
||||||
|
writer << (TQ_UINT16)img.height();
|
||||||
|
writer << (TQ_UINT16)0x0000; //wtf .?
|
||||||
|
writer << (TQ_UINT32)frame.size();
|
||||||
|
writer << (TQ_UINT8)('M') << (TQ_UINT8)('L') << (TQ_UINT8)('2') << (TQ_UINT8)('0');
|
||||||
|
writer << (TQ_UINT32)0x00000000; //wtf .?
|
||||||
|
writer << TQTime::currentTime(); //FIXME: possible midnight bug ?
|
||||||
|
|
||||||
|
m_webcamSocket->writeBlock(header.data(), header.size());
|
||||||
|
m_webcamSocket->writeBlock(frame.data(), frame.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "webcam.moc"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef P2PWEBCAM_H
|
||||||
|
#define P2PWEBCAM_H
|
||||||
|
|
||||||
|
#include "p2p.h"
|
||||||
|
|
||||||
|
#if MSN_WEBCAM
|
||||||
|
|
||||||
|
namespace KNetwork{ class TDEServerSocket; class TDEBufferedSocket; }
|
||||||
|
|
||||||
|
class MimicWrapper;
|
||||||
|
class TQLabel;
|
||||||
|
class MSNWebcamDialog;
|
||||||
|
class TQTimerEvent;
|
||||||
|
|
||||||
|
namespace P2P {
|
||||||
|
|
||||||
|
|
||||||
|
class Webcam : public TransferContext
|
||||||
|
{ Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Who { wProducer , wViewer };
|
||||||
|
|
||||||
|
Webcam( Who who , const TQString& to, Dispatcher *parent, TQ_UINT32 sessionID);
|
||||||
|
~Webcam( );
|
||||||
|
|
||||||
|
virtual void processMessage(const Message& message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void askIncommingInvitation();
|
||||||
|
virtual void acknowledged();
|
||||||
|
void sendBYEMessage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void makeSIPMessage(const TQString &message, TQ_UINT8 XX=0, TQ_UINT8 YY=9 , TQ_UINT8 ZZ=0);
|
||||||
|
void sendBigP2PMessage( const TQByteArray& dataMessage );
|
||||||
|
void closeAllOtherSockets();
|
||||||
|
TQString m_content;
|
||||||
|
|
||||||
|
TQString xml(uint session , uint rid);
|
||||||
|
int getAvailablePort();
|
||||||
|
|
||||||
|
|
||||||
|
KNetwork::TDEServerSocket *m_listener;
|
||||||
|
KNetwork::TDEBufferedSocket *m_webcamSocket;
|
||||||
|
|
||||||
|
enum WebcamStatus { wsNegotiating , wsConnecting, wsConnected, wsTransfer } ;
|
||||||
|
|
||||||
|
Who m_who;
|
||||||
|
|
||||||
|
TQString m_myAuth;
|
||||||
|
TQString m_peerAuth;
|
||||||
|
|
||||||
|
MimicWrapper *m_mimic;
|
||||||
|
MSNWebcamDialog *m_widget;
|
||||||
|
|
||||||
|
TQValueList<KNetwork::TDEBufferedSocket* > m_allSockets;
|
||||||
|
TQMap<KNetwork::TDEBufferedSocket*, WebcamStatus> m_webcamStates;
|
||||||
|
|
||||||
|
int m_timerId;
|
||||||
|
int m_timerFps;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotListenError(int errorCode);
|
||||||
|
void slotAccept();
|
||||||
|
void slotSocketRead();
|
||||||
|
void slotSocketClosed();
|
||||||
|
void slotSocketError(int errorCode);
|
||||||
|
void slotSocketConnected();
|
||||||
|
// void slotReadyWrite();
|
||||||
|
protected:
|
||||||
|
virtual void timerEvent( TQTimerEvent * );
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,28 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
add_subdirectory( libmimic )
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/kopete/libkopete
|
||||||
|
${TDE_INCLUDE_DIR}
|
||||||
|
${TQT_INCLUDE_DIRS}
|
||||||
|
${GLIB2_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### mimicwrapper (static) #####################
|
||||||
|
|
||||||
|
tde_add_library( mimicwrapper STATIC_PIC AUTOMOC
|
||||||
|
SOURCES mimicwrapper.cpp msnwebcamdialog.cpp
|
||||||
|
LINK mimic-static
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
METASOURCES = AUTO
|
||||||
|
SUBDIRS = libmimic
|
||||||
|
AM_CPPFLAGS = -I$(srcdir)/libmimic \
|
||||||
|
$(KOPETE_INCLUDES) \
|
||||||
|
$(all_includes) \
|
||||||
|
$(GLIB_CFLAGS)
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libmimicwrapper.la
|
||||||
|
|
||||||
|
libmimicwrapper_la_SOURCES = mimicwrapper.cpp msnwebcamdialog.cpp
|
||||||
|
libmimicwrapper_la_LIBADD = ./libmimic/libmimic.la
|
||||||
|
libmimicwrapper_la_LDFLAGS = -no-undefined $(GLIB_LIBS) $(all_libraries)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
|
@ -0,0 +1,24 @@
|
|||||||
|
#################################################
|
||||||
|
#
|
||||||
|
# (C) 2010-2011 Serghei Amelian
|
||||||
|
# serghei (DOT) amelian (AT) gmail.com
|
||||||
|
#
|
||||||
|
# Improvements and feedback are welcome
|
||||||
|
#
|
||||||
|
# This file is released under GPL >= 2
|
||||||
|
#
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${GLIB2_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##### mimic (static) ############################
|
||||||
|
|
||||||
|
tde_add_library( mimic STATIC_PIC
|
||||||
|
SOURCES
|
||||||
|
mimic.c encode.c decode.c bitstring.c vlc_common.c vlc_encode.c
|
||||||
|
vlc_decode.c fdct_quant.c idct_dequant.c colorspace.c deblock.c
|
||||||
|
LINK ${GLIB2_LIBRARIES}
|
||||||
|
)
|
@ -0,0 +1,24 @@
|
|||||||
|
# INCLUDES = @GLIB_CFLAGS@
|
||||||
|
AM_CPPFLAGS = $(all_includes) $(GLIB_CFLAGS)
|
||||||
|
|
||||||
|
# libmimicincludedir = $(includedir)
|
||||||
|
# libmimicinclude_HEADERS = mimic.h
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libmimic.la
|
||||||
|
libmimic_la_SOURCES = \
|
||||||
|
mimic.c \
|
||||||
|
encode.c \
|
||||||
|
decode.c \
|
||||||
|
bitstring.c \
|
||||||
|
vlc_common.c \
|
||||||
|
vlc_encode.c \
|
||||||
|
vlc_decode.c \
|
||||||
|
fdct_quant.c \
|
||||||
|
idct_dequant.c \
|
||||||
|
colorspace.c \
|
||||||
|
deblock.c \
|
||||||
|
mimic-private.h
|
||||||
|
# libmimic_la_LDFLAGS = \
|
||||||
|
# -version-info $(MIMIC_CURRENT):$(MIMIC_REVISION):$(MIMIC_AGE) \
|
||||||
|
# -export-symbols-regex "^[^_].*"
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
ABOUT
|
||||||
|
-----
|
||||||
|
|
||||||
|
libmimic is an open source video encoding/decoding library for Mimic V2.x-
|
||||||
|
encoded content (fourCC: ML20), which is the encoding used by MSN Messenger
|
||||||
|
for webcam conversations.
|
||||||
|
|
||||||
|
It was written because there was no third-party MSN-client that supported
|
||||||
|
this feature due to this proprietary/unknown codec involved. I didn't like
|
||||||
|
this lack of interoperability, so I decided to do something about it. After
|
||||||
|
studying the official MSN-client a little closer, it became clear that the
|
||||||
|
codec involved was statically linked into the executable, so there was no
|
||||||
|
easy way to use the codec code through Wine. So for fun, and challenge, I
|
||||||
|
reverse-engineered the original implementation by studying the massive
|
||||||
|
amount of assembly code involved, and after a lot of hard work I ended
|
||||||
|
up with this implementation in C.
|
||||||
|
|
||||||
|
It should be noted that reverse-engineering for interoperability is 100%
|
||||||
|
legal here in Norway (and in most European countries).
|
||||||
|
|
||||||
|
|
||||||
|
THANKS
|
||||||
|
------
|
||||||
|
|
||||||
|
Special thanks to Rob Taylor and the rest of the Farsight-team for all
|
||||||
|
the feedback and inspiration during development, you guys rock! :-)
|
||||||
|
|
||||||
|
|
||||||
|
BOTTOM LINE
|
||||||
|
-----------
|
||||||
|
|
||||||
|
If you like my work and decide to use it in your project, please feel free
|
||||||
|
to credit me. I put a lot of time and hard work into this, so I hope others
|
||||||
|
will find it useful.
|
||||||
|
|
||||||
|
Well, enough chit chat, enjoy! :-)
|
||||||
|
|
||||||
|
Ole André Vadla Ravnås
|
||||||
|
oleavr at gmail dot com
|
||||||
|
|
@ -0,0 +1,88 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _read_bits
|
||||||
|
*
|
||||||
|
* Internal helper-function used to read num_bits
|
||||||
|
* from stream.
|
||||||
|
*/
|
||||||
|
guint32 _read_bits(MimCtx *ctx, gint num_bits)
|
||||||
|
{
|
||||||
|
guint32 bits;
|
||||||
|
|
||||||
|
if (ctx->cur_chunk_len >= 16) {
|
||||||
|
guchar *input_buf = (guchar *) ctx->data_buffer + ctx->data_index;
|
||||||
|
|
||||||
|
if (!ctx->read_odd) {
|
||||||
|
ctx->read_odd = TRUE;
|
||||||
|
|
||||||
|
ctx->cur_chunk = (input_buf[3] << 24) |
|
||||||
|
(input_buf[2] << 16) |
|
||||||
|
(input_buf[1] << 8) |
|
||||||
|
input_buf[0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ctx->read_odd = FALSE;
|
||||||
|
|
||||||
|
ctx->cur_chunk = (input_buf[1] << 24) |
|
||||||
|
(input_buf[0] << 16) |
|
||||||
|
(input_buf[7] << 8) |
|
||||||
|
input_buf[6];
|
||||||
|
|
||||||
|
ctx->data_index += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->cur_chunk_len -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = (ctx->cur_chunk << ctx->cur_chunk_len) >> (32 - num_bits);
|
||||||
|
ctx->cur_chunk_len += num_bits;
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _write_bits
|
||||||
|
*
|
||||||
|
* Internal helper-function used to write "length"
|
||||||
|
* bits of "bits" to stream.
|
||||||
|
*/
|
||||||
|
void _write_bits(MimCtx *ctx, guint32 bits, gint length)
|
||||||
|
{
|
||||||
|
/* Left-align the bit string within its 32-bit container. */
|
||||||
|
bits <<= (32 - length);
|
||||||
|
|
||||||
|
/* Append the bit string (one or more of the trailing bits might not fit, but that's ok). */
|
||||||
|
ctx->cur_chunk |= bits >> ctx->cur_chunk_len;
|
||||||
|
ctx->cur_chunk_len += length;
|
||||||
|
|
||||||
|
/* Is it full? */
|
||||||
|
if (ctx->cur_chunk_len >= 32) {
|
||||||
|
|
||||||
|
/* Add the full 32-bit chunk to the stream and update counter. */
|
||||||
|
ctx->chunk_ptr[0] = GUINT32_TO_LE(ctx->cur_chunk);
|
||||||
|
ctx->chunk_ptr++;
|
||||||
|
ctx->cur_chunk_len -= 32;
|
||||||
|
|
||||||
|
/* Add any trailing bits that didn't fit. */
|
||||||
|
ctx->cur_chunk = bits << (length - ctx->cur_chunk_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,161 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
#define RED_INDEX_1 0
|
||||||
|
#define GREEN_INDEX_1 1
|
||||||
|
#define BLUE_INDEX_1 2
|
||||||
|
|
||||||
|
#define RED_INDEX_2 3
|
||||||
|
#define GREEN_INDEX_2 4
|
||||||
|
#define BLUE_INDEX_2 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _rgb_to_yuv
|
||||||
|
*
|
||||||
|
* Internal helper-function used to convert an image
|
||||||
|
* from RGB 24-bpp packed-pixel to YUV420 planar.
|
||||||
|
*/
|
||||||
|
void _rgb_to_yuv(const guchar *input_rgb,
|
||||||
|
guchar *output_y,
|
||||||
|
guchar *output_cb,
|
||||||
|
guchar *output_cr,
|
||||||
|
gint width,
|
||||||
|
gint height)
|
||||||
|
{
|
||||||
|
gint y, x;
|
||||||
|
|
||||||
|
for (y = 0; y < height; y += 2) {
|
||||||
|
|
||||||
|
const guchar *src1, *src2;
|
||||||
|
guchar *dst1, *dst2, *dst3, *dst4;
|
||||||
|
gint num_cols;
|
||||||
|
|
||||||
|
src1 = input_rgb + ((height - 1 - y) * width * 3);
|
||||||
|
src2 = input_rgb + ((height - 2 - y) * width * 3);
|
||||||
|
|
||||||
|
dst1 = output_y + (y * width);
|
||||||
|
dst2 = output_y + ((y + 1) * width);
|
||||||
|
dst3 = output_cb + ((y / 2) * (width / 2));
|
||||||
|
dst4 = output_cr + ((y / 2) * (width / 2));
|
||||||
|
|
||||||
|
num_cols = width / 2;
|
||||||
|
|
||||||
|
for (x = 0; x < num_cols; x++) {
|
||||||
|
|
||||||
|
gint expr1, expr2, expr3, expr4, expr5, v;
|
||||||
|
|
||||||
|
expr1 = (src1[BLUE_INDEX_1] * 19595) + (src1[GREEN_INDEX_1] * 38470) + (src1[RED_INDEX_1] * 7471);
|
||||||
|
expr2 = (src1[BLUE_INDEX_2] * 19595) + (src1[GREEN_INDEX_2] * 38470) + (src1[RED_INDEX_2] * 7471);
|
||||||
|
expr3 = (src2[BLUE_INDEX_1] * 19595) + (src2[GREEN_INDEX_1] * 38470) + (src2[RED_INDEX_1] * 7471);
|
||||||
|
expr4 = (src2[BLUE_INDEX_2] * 19595) + (src2[GREEN_INDEX_2] * 38470) + (src2[RED_INDEX_2] * 7471);
|
||||||
|
|
||||||
|
expr5 = expr1 + expr2 + expr3 + expr4;
|
||||||
|
|
||||||
|
dst1[0] = expr1 >> 16;
|
||||||
|
dst1[1] = expr2 >> 16;
|
||||||
|
dst2[0] = expr3 >> 16;
|
||||||
|
dst2[1] = expr4 >> 16;
|
||||||
|
|
||||||
|
v = (((src1[BLUE_INDEX_1] + src1[BLUE_INDEX_2] + src2[BLUE_INDEX_1] + src2[BLUE_INDEX_2]) << 16) - expr5 + 131071) >> 16;
|
||||||
|
dst3[0] = _clamp_value(((v * 57475) >> 18) + 128);
|
||||||
|
|
||||||
|
v = (((src1[RED_INDEX_1] + src1[RED_INDEX_2] + src2[RED_INDEX_1] + src2[RED_INDEX_2]) << 16) - expr5 + 131071) >> 16;
|
||||||
|
dst4[0] = ((v * 32244) >> 18) + 128;
|
||||||
|
|
||||||
|
src1 += 6;
|
||||||
|
src2 += 6;
|
||||||
|
|
||||||
|
dst1 += 2;
|
||||||
|
dst2 += 2;
|
||||||
|
dst3++;
|
||||||
|
dst4++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _yuv_to_rgb
|
||||||
|
*
|
||||||
|
* Internal helper-function used to convert an image
|
||||||
|
* from YUV420 planar to RGB 24-bpp packed-pixel.
|
||||||
|
*/
|
||||||
|
void _yuv_to_rgb(const guchar *input_y,
|
||||||
|
const guchar *input_cb,
|
||||||
|
const guchar *input_cr,
|
||||||
|
guchar *output_rgb,
|
||||||
|
guint width,
|
||||||
|
guint height)
|
||||||
|
{
|
||||||
|
const guchar *src_y, *src_cb, *src_cr;
|
||||||
|
guchar *dst_rgb;
|
||||||
|
guint i, j, rgb_stride;
|
||||||
|
|
||||||
|
src_y = input_y;
|
||||||
|
src_cb = input_cb;
|
||||||
|
src_cr = input_cr;
|
||||||
|
|
||||||
|
rgb_stride = width * 3;
|
||||||
|
dst_rgb = output_rgb + (rgb_stride * (height - 1));
|
||||||
|
|
||||||
|
for (i = 0; i < height; i++) {
|
||||||
|
const guchar *p_y, *p_cb, *p_cr;
|
||||||
|
guchar *p_rgb;
|
||||||
|
|
||||||
|
p_y = src_y;
|
||||||
|
p_cb = src_cb;
|
||||||
|
p_cr = src_cr;
|
||||||
|
|
||||||
|
p_rgb = dst_rgb;
|
||||||
|
|
||||||
|
for (j = 0; j < width; j++) {
|
||||||
|
gint v;
|
||||||
|
|
||||||
|
v = ((p_y[0] * 65536) + ((p_cr[0] - 128) * 133169)) / 65536;
|
||||||
|
p_rgb[0] = _clamp_value(v);
|
||||||
|
|
||||||
|
v = ((p_y[0] * 65536) - ((p_cr[0] - 128) * 25821) - ((p_cb[0] - 128) * 38076)) / 65536;
|
||||||
|
p_rgb[1] = _clamp_value(v);
|
||||||
|
|
||||||
|
v = ((p_y[0] * 65536) + ((p_cb[0] - 128) * 74711)) / 65536;
|
||||||
|
p_rgb[2] = _clamp_value(v);
|
||||||
|
|
||||||
|
p_y++;
|
||||||
|
if ((j + 1) % 2 == 0) {
|
||||||
|
p_cb++;
|
||||||
|
p_cr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_rgb += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_y += width;
|
||||||
|
if ((i + 1) % 2 == 0) {
|
||||||
|
src_cb += (width + 1) / 2;
|
||||||
|
src_cr += (width + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_rgb -= rgb_stride;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,450 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
static void deblock_horizontal(guchar *blocks, guint stride, guint row_count);
|
||||||
|
static void deblock_vertical(guchar *blocks, guint stride, guint row_count);
|
||||||
|
|
||||||
|
static gboolean deblock_h_consider_entire(guchar *blocks, guint stride);
|
||||||
|
static void deblock_h_do_entire(guchar *blocks, guint stride);
|
||||||
|
static void deblock_h_do_boundaries(guchar *blocks, guint stride);
|
||||||
|
|
||||||
|
static gboolean deblock_v_consider_entire(guchar *blocks, guint stride);
|
||||||
|
static void deblock_v_do_entire(guchar *blocks, guint stride);
|
||||||
|
static void deblock_v_do_boundaries(guchar *blocks, guint stride);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _deblock
|
||||||
|
*
|
||||||
|
* Internal helper-function used for de-blocking.
|
||||||
|
*/
|
||||||
|
void _deblock(guchar *blocks, guint stride, guint row_count)
|
||||||
|
{
|
||||||
|
deblock_horizontal(blocks, stride, row_count);
|
||||||
|
deblock_vertical(blocks, stride, row_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_horizontal(guchar *blocks, guint stride, guint row_count)
|
||||||
|
{
|
||||||
|
guchar *p1;
|
||||||
|
gint i, j, n1, n2;
|
||||||
|
|
||||||
|
if (stride <= 8 || row_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p1 = blocks + 4;
|
||||||
|
n1 = ((row_count - 1) >> 2) + 1;
|
||||||
|
n2 = ((stride - 9) >> 3) + 1;
|
||||||
|
|
||||||
|
for (i = 0; i < n1; i++) {
|
||||||
|
guchar *p;
|
||||||
|
|
||||||
|
p = p1;
|
||||||
|
|
||||||
|
for (j = 0; j < n2; j++) {
|
||||||
|
|
||||||
|
if (deblock_h_consider_entire(p - 1, stride) == TRUE) {
|
||||||
|
|
||||||
|
gint v1, v2, v;
|
||||||
|
|
||||||
|
v1 = p[0];
|
||||||
|
v2 = p[7];
|
||||||
|
|
||||||
|
v = v1 - v2;
|
||||||
|
if (v <= 0)
|
||||||
|
v = v2 - v1;
|
||||||
|
|
||||||
|
if (v < 20)
|
||||||
|
deblock_h_do_entire(p - 1, stride);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
deblock_h_do_boundaries(p - 1, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 += stride * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_vertical(guchar *blocks, guint stride, guint row_count)
|
||||||
|
{
|
||||||
|
gint i, j, k, n1, n2;
|
||||||
|
guchar *p1, *p2;
|
||||||
|
|
||||||
|
if (stride == 0 || row_count <= 8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p1 = blocks + (stride * 3);
|
||||||
|
p2 = blocks + (stride * 4);
|
||||||
|
|
||||||
|
n1 = ((row_count - 9) >> 3) + 1;
|
||||||
|
n2 = ((stride - 1) >> 3) + 1;
|
||||||
|
|
||||||
|
for (i = 0; i < n1; i++) {
|
||||||
|
guchar *p3, *p4;
|
||||||
|
|
||||||
|
p3 = p1;
|
||||||
|
p4 = p2;
|
||||||
|
|
||||||
|
for (j = 0; j < n2; j++) {
|
||||||
|
|
||||||
|
if (deblock_v_consider_entire(p3, stride) == TRUE) {
|
||||||
|
guchar *p5;
|
||||||
|
gboolean do_entire;
|
||||||
|
|
||||||
|
p5 = p3 + (stride * 8);
|
||||||
|
do_entire = TRUE;
|
||||||
|
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
gint v1, v2, v;
|
||||||
|
|
||||||
|
v1 = p4[k];
|
||||||
|
v2 = p5[k];
|
||||||
|
|
||||||
|
v = v1 - v2;
|
||||||
|
if (v <= 0)
|
||||||
|
v = v2 - v1;
|
||||||
|
|
||||||
|
if (v > 20) {
|
||||||
|
do_entire = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_entire)
|
||||||
|
deblock_v_do_entire(p3, stride);
|
||||||
|
} else {
|
||||||
|
deblock_v_do_boundaries(p3, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
p3 += 8;
|
||||||
|
p4 += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 += stride * 8;
|
||||||
|
p2 += stride * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean deblock_h_consider_entire(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
guchar *p;
|
||||||
|
gint i, j, count;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
p = blocks;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
|
||||||
|
for (j = 1; j <= 7; j++) {
|
||||||
|
gint v1, v2, v;
|
||||||
|
|
||||||
|
v1 = p[j];
|
||||||
|
v2 = p[j+1];
|
||||||
|
|
||||||
|
v = v1 - v2;
|
||||||
|
if (v <= 0)
|
||||||
|
v = v2 - v1;
|
||||||
|
|
||||||
|
if (v <= 1)
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (count <= -20);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_h_do_entire(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
guchar buf[8], *p;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
p = blocks;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gint v, low, high;
|
||||||
|
|
||||||
|
v = p[0] - p[1];
|
||||||
|
if (v <= 0)
|
||||||
|
v = p[1] - p[0];
|
||||||
|
|
||||||
|
if (v < 10)
|
||||||
|
low = p[0];
|
||||||
|
else
|
||||||
|
low = p[1];
|
||||||
|
|
||||||
|
v = p[8] - p[9];
|
||||||
|
if (v <= 0)
|
||||||
|
v = p[9] - p[8];
|
||||||
|
|
||||||
|
if (v >= 10)
|
||||||
|
high = p[8];
|
||||||
|
else
|
||||||
|
high = p[9];
|
||||||
|
|
||||||
|
v = (low * 3) + p[1] + p[2] + p[3] + p[4] + 4;
|
||||||
|
buf[0] = (((p[1] + v) << 1) - p[4] + p[5]) >> 4;
|
||||||
|
|
||||||
|
v += p[5] - low;
|
||||||
|
buf[1] = (((p[2] + v) << 1) - p[5] + p[6]) >> 4;
|
||||||
|
|
||||||
|
v += p[6] - low;
|
||||||
|
buf[2] = (((p[3] + v) << 1) - p[6] + p[7]) >> 4;
|
||||||
|
|
||||||
|
v += p[7] - low;
|
||||||
|
buf[3] = (((p[4] + v) << 1) - p[1] - p[7] + p[8] + low) >> 4;
|
||||||
|
|
||||||
|
v += p[8] - p[1];
|
||||||
|
buf[4] = (((p[5] + v) << 1) + p[1] - p[2] - p[8] + high) >> 4;
|
||||||
|
|
||||||
|
v += high - p[2];
|
||||||
|
buf[5] = (((p[6] + v) << 1) + p[2] - p[3]) >> 4;
|
||||||
|
|
||||||
|
v += high - p[3];
|
||||||
|
buf[6] = (((p[7] + v) << 1) + p[3] - p[4]) >> 4;
|
||||||
|
|
||||||
|
v += high;
|
||||||
|
buf[7] = (((p[8] + v) << 1) - p[4] - p[5]) >> 4;
|
||||||
|
|
||||||
|
memcpy(p + 1, buf, 8);
|
||||||
|
|
||||||
|
p += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_h_do_boundaries(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
guchar *p;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
p = blocks;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gint v, v1, v2, v3;
|
||||||
|
|
||||||
|
v = p[4] - p[5];
|
||||||
|
|
||||||
|
if ((v / 2) != 0) {
|
||||||
|
|
||||||
|
v1 = ((p[3] - p[6]) * 2) - (v * 5);
|
||||||
|
|
||||||
|
if (abs(v1) < 80) {
|
||||||
|
|
||||||
|
v2 = ((p[3] - p[2]) * 5) + ((p[1] - p[4]) * 2);
|
||||||
|
v3 = (p[5] * 2) + (p[7] * 5) - (p[8] * 7);
|
||||||
|
|
||||||
|
v = abs(v1) - MIN(abs(v2), abs(v3));
|
||||||
|
|
||||||
|
if (v > 0) {
|
||||||
|
|
||||||
|
v = ((v * 5) + 32) >> 6;
|
||||||
|
if (v > 0) {
|
||||||
|
|
||||||
|
v2 = (p[4] - p[5]) / 2;
|
||||||
|
v3 = (((v1 < 0) * 2) - 1) * v;
|
||||||
|
|
||||||
|
if (v2 > 0)
|
||||||
|
v = MIN(v2, ((v3 < 0) - 1) & v3);
|
||||||
|
else
|
||||||
|
v = MAX(v2, ((v3 > 0) - 1) & v3);
|
||||||
|
|
||||||
|
p[4] -= v;
|
||||||
|
p[5] += v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean deblock_v_consider_entire(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
gint count, i, j;
|
||||||
|
guchar *p1, *p2;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
p1 = blocks + stride;
|
||||||
|
p2 = blocks + (stride * 2);
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++) {
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
gint v1, v2, v;
|
||||||
|
|
||||||
|
v1 = p1[j];
|
||||||
|
v2 = p2[j];
|
||||||
|
|
||||||
|
v = v1 - v2;
|
||||||
|
if (v <= 0)
|
||||||
|
v = v2 - v1;
|
||||||
|
|
||||||
|
if (v <= 1)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 += stride;
|
||||||
|
p2 += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (count > 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_v_do_entire(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
gint offset0, offset1, offset2, offset3;
|
||||||
|
gint offset4, offset5, offset6, offset7;
|
||||||
|
gint offset8, i;
|
||||||
|
guchar *p, buf[8];
|
||||||
|
|
||||||
|
offset0 = stride - (stride * 6);
|
||||||
|
offset1 = (stride * 2) - (stride * 6);
|
||||||
|
offset2 = (stride * 3) - (stride * 6);
|
||||||
|
offset3 = (stride * 4) - (stride * 6);
|
||||||
|
offset4 = (stride * 5) - (stride * 6);
|
||||||
|
offset5 = 0;
|
||||||
|
offset6 = (stride * 7) - (stride * 6);
|
||||||
|
offset7 = (stride * 8) - (stride * 6);
|
||||||
|
offset8 = (stride * 9) - (stride * 6);
|
||||||
|
|
||||||
|
p = blocks + (stride * 6);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
gint v, low, high;
|
||||||
|
|
||||||
|
v = blocks[i] - p[offset0];
|
||||||
|
if (v <= 0)
|
||||||
|
v = p[offset0] - blocks[i];
|
||||||
|
|
||||||
|
if (v < 10)
|
||||||
|
low = blocks[i];
|
||||||
|
else
|
||||||
|
low = p[offset0];
|
||||||
|
|
||||||
|
v = p[offset7] - p[offset8];
|
||||||
|
if (v <= 0)
|
||||||
|
v = p[offset8] - p[offset7];
|
||||||
|
|
||||||
|
if (v < 10)
|
||||||
|
high = p[offset8];
|
||||||
|
else
|
||||||
|
high = p[offset7];
|
||||||
|
|
||||||
|
v = p[offset0] + (low * 3) + p[offset1] + p[offset2] + p[offset3] + 4;
|
||||||
|
|
||||||
|
buf[0] = (((p[offset0] + v) << 1) - p[offset3] + p[offset4]) >> 4;
|
||||||
|
|
||||||
|
v += p[offset4] - low;
|
||||||
|
|
||||||
|
buf[1] = (((p[offset1] + v) << 1) - p[offset4] + p[0]) >> 4;
|
||||||
|
|
||||||
|
v += p[0] - low;
|
||||||
|
|
||||||
|
buf[2] = (((p[offset2] + v) << 1) - p[0] + p[offset6]) >> 4;
|
||||||
|
|
||||||
|
v += p[offset6] - low;
|
||||||
|
|
||||||
|
buf[3] = (((p[offset3] + v) << 1) - p[offset0] - p[offset6] + p[offset7] + low) >> 4;
|
||||||
|
|
||||||
|
v += p[offset7] - p[offset0];
|
||||||
|
|
||||||
|
buf[4] = (((p[offset4] + v) << 1) - p[offset7] - p[offset1] + p[offset0] + high) >> 4;
|
||||||
|
|
||||||
|
v += high - p[offset1];
|
||||||
|
|
||||||
|
buf[5] = (((p[0] + v) << 1) - p[offset2] + p[offset1]) >> 4;
|
||||||
|
|
||||||
|
v += high - p[offset2];
|
||||||
|
|
||||||
|
buf[6] = (((p[offset6] + v) << 1) - p[offset3] + p[offset2]) >> 4;
|
||||||
|
|
||||||
|
v += high;
|
||||||
|
|
||||||
|
buf[7] = (((p[offset7] + v) << 1) - p[offset4] - p[offset3]) >> 4;
|
||||||
|
|
||||||
|
p[offset0] = buf[0];
|
||||||
|
p[offset1] = buf[1];
|
||||||
|
p[offset2] = buf[2];
|
||||||
|
p[offset3] = buf[3];
|
||||||
|
p[offset4] = buf[4];
|
||||||
|
p[offset5] = buf[5];
|
||||||
|
p[offset6] = buf[6];
|
||||||
|
p[offset7] = buf[7];
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deblock_v_do_boundaries(guchar *blocks, guint stride)
|
||||||
|
{
|
||||||
|
guchar *p;
|
||||||
|
gint offset0, offset1, offset2, offset3;
|
||||||
|
gint offset4, offset5, offset6, offset7;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
p = blocks + (stride * 3);
|
||||||
|
|
||||||
|
offset0 = stride - (stride * 3);
|
||||||
|
offset1 = (stride * 2) - (stride * 3);
|
||||||
|
offset2 = 0;
|
||||||
|
offset3 = (stride * 4) - (stride * 3);
|
||||||
|
offset4 = (stride * 5) - (stride * 3);
|
||||||
|
offset5 = (stride * 6) - (stride * 3);
|
||||||
|
offset6 = (stride * 7) - (stride * 3);
|
||||||
|
offset7 = (stride * 8) - (stride * 3);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
gint v1, v2, v3, v;
|
||||||
|
|
||||||
|
v1 = ((p[offset4] - p[offset3]) * 5) + ((p[offset2] - p[offset5]) * 2);
|
||||||
|
|
||||||
|
if (abs(v1) < 80) {
|
||||||
|
|
||||||
|
v2 = ((p[offset2] - p[offset1]) * 5) + ((p[offset0] - p[offset3]) * 2);
|
||||||
|
v3 = ((p[offset6] - p[offset5]) * 5) + ((p[offset4] - p[offset7]) * 2);
|
||||||
|
|
||||||
|
v = abs(v1) - MIN(abs(v2), abs(v3));
|
||||||
|
if (v < 0)
|
||||||
|
v = 0;
|
||||||
|
|
||||||
|
v2 = (p[offset3] - p[offset4]) / 2;
|
||||||
|
v3 = (((v * 5) + 32) >> 6) * (((v1 < 0) * 2) - 1);
|
||||||
|
|
||||||
|
if (v2 > 0)
|
||||||
|
v = MIN(v2, ((v3 < 0) - 1) & v3);
|
||||||
|
else
|
||||||
|
v = MAX(v2, ((v3 > 0) - 1) & v3);
|
||||||
|
} else {
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p[offset3] -= v;
|
||||||
|
p[offset4] += v;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,311 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean decode(MimCtx *ctx, gboolean is_pframe);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a MIMIC-encoded frame into RGB data.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context
|
||||||
|
* @param input_buffer buffer containing the MIMIC-encoded frame to decode
|
||||||
|
* @param output_buffer buffer that will receive the decoded frame in RGB 24-bpp packed pixel top-down format
|
||||||
|
* (use #mimic_get_property to determine the required buffer size, as well as frame width and height)
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_decode_frame(MimCtx *ctx,
|
||||||
|
const guchar *input_buffer,
|
||||||
|
guchar *output_buffer)
|
||||||
|
{
|
||||||
|
gboolean result, is_pframe;
|
||||||
|
guchar *input_y, *input_cr, *input_cb;
|
||||||
|
gint width, height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some sanity checks.
|
||||||
|
*/
|
||||||
|
if (ctx == NULL || input_buffer == NULL || output_buffer == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->decoder_initialized)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get frame dimensions.
|
||||||
|
*/
|
||||||
|
width = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 4)));
|
||||||
|
height = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 6)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolution changing is not supported.
|
||||||
|
*/
|
||||||
|
if (width != ctx->frame_width ||
|
||||||
|
height != ctx->frame_height)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment frame counter.
|
||||||
|
*/
|
||||||
|
ctx->frame_num++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize state.
|
||||||
|
*/
|
||||||
|
ctx->quality = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 2)));
|
||||||
|
is_pframe = GUINT32_FROM_LE(*((guint32 *) (input_buffer + 12)));
|
||||||
|
ctx->num_coeffs = input_buffer[16];
|
||||||
|
|
||||||
|
ctx->data_buffer = (gchar *) (input_buffer + 20);
|
||||||
|
ctx->data_index = 0;
|
||||||
|
ctx->cur_chunk_len = 16;
|
||||||
|
ctx->read_odd = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode frame.
|
||||||
|
*/
|
||||||
|
if (!(is_pframe && ctx->prev_frame_buf == NULL))
|
||||||
|
result = decode(ctx, is_pframe);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform YUV 420 to RGB conversion.
|
||||||
|
*/
|
||||||
|
input_y = ctx->cur_frame_buf;
|
||||||
|
input_cr = ctx->cur_frame_buf + ctx->y_size;
|
||||||
|
input_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size;
|
||||||
|
|
||||||
|
_yuv_to_rgb(input_y,
|
||||||
|
input_cb,
|
||||||
|
input_cr,
|
||||||
|
output_buffer,
|
||||||
|
ctx->frame_width,
|
||||||
|
ctx->frame_height);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* decode_main
|
||||||
|
*
|
||||||
|
* Main decoding loop.
|
||||||
|
*/
|
||||||
|
static gboolean decode(MimCtx *ctx, gboolean is_pframe)
|
||||||
|
{
|
||||||
|
gint y, x, i, j, chrom_ch, *bptr, base_offset, offset;
|
||||||
|
gint dct_block[64];
|
||||||
|
guchar *src, *dst, *p;
|
||||||
|
guint32 bit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear Cr and Cb planes.
|
||||||
|
*/
|
||||||
|
p = ctx->cur_frame_buf + ctx->y_size;
|
||||||
|
memset(p, 128, 2 * ctx->crcb_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode Y plane.
|
||||||
|
*/
|
||||||
|
for (y = 0; y < ctx->num_vblocks_y; y++) {
|
||||||
|
|
||||||
|
base_offset = ctx->y_stride * 8 * y;
|
||||||
|
|
||||||
|
src = ctx->prev_frame_buf + base_offset;
|
||||||
|
dst = ctx->cur_frame_buf + base_offset;
|
||||||
|
|
||||||
|
for (x = 0; x < ctx->num_hblocks_y; x++) {
|
||||||
|
|
||||||
|
/* Check for a change condition in the current block. */
|
||||||
|
|
||||||
|
if (is_pframe)
|
||||||
|
bit = _read_bits(ctx, 1);
|
||||||
|
else
|
||||||
|
bit = 0;
|
||||||
|
|
||||||
|
if (bit == 0) {
|
||||||
|
|
||||||
|
/* Yes: Is the new content the same as it was in one of
|
||||||
|
* the 15 last frames preceding the previous? */
|
||||||
|
|
||||||
|
if (is_pframe)
|
||||||
|
bit = _read_bits(ctx, 1);
|
||||||
|
|
||||||
|
if (bit == 0) {
|
||||||
|
|
||||||
|
/* No: decode it. */
|
||||||
|
|
||||||
|
if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_idct_dequant_block(ctx, dct_block, 0);
|
||||||
|
|
||||||
|
bptr = dct_block;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
offset = ctx->y_stride * i;
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
guint v;
|
||||||
|
|
||||||
|
if (bptr[j] <= 255)
|
||||||
|
v = (bptr[j] >= 0) ? bptr[j] : 0;
|
||||||
|
else
|
||||||
|
v = 255;
|
||||||
|
|
||||||
|
*(dst + offset + j) = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bptr += 8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
guint32 backref;
|
||||||
|
|
||||||
|
/* Yes: read the backreference (4 bits) and copy. */
|
||||||
|
|
||||||
|
backref = _read_bits(ctx, 4);
|
||||||
|
|
||||||
|
p = ctx->buf_ptrs[(ctx->ptr_index + backref) % 16];
|
||||||
|
p += base_offset + (x * 8);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
offset = ctx->y_stride * i;
|
||||||
|
|
||||||
|
memcpy(dst + offset, p + offset, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* No change no worries: just copy from the previous frame. */
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
offset = ctx->y_stride * i;
|
||||||
|
|
||||||
|
memcpy(dst + offset, src + offset, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src += 8;
|
||||||
|
dst += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode Cr and Cb planes.
|
||||||
|
*/
|
||||||
|
for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
|
||||||
|
|
||||||
|
base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch);
|
||||||
|
|
||||||
|
for (y = 0; y < ctx->num_vblocks_cbcr; y++) {
|
||||||
|
guint num_rows = 8;
|
||||||
|
|
||||||
|
/* The last row of blocks in chrominance for 160x120 resolution
|
||||||
|
* is half the normal height and must be accounted for. */
|
||||||
|
if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0)
|
||||||
|
num_rows = 4;
|
||||||
|
|
||||||
|
offset = base_offset + (ctx->crcb_stride * 8 * y);
|
||||||
|
|
||||||
|
src = ctx->prev_frame_buf + offset;
|
||||||
|
dst = ctx->cur_frame_buf + offset;
|
||||||
|
|
||||||
|
for (x = 0; x < ctx->num_hblocks_cbcr; x++) {
|
||||||
|
|
||||||
|
/* Check for a change condition in the current block. */
|
||||||
|
|
||||||
|
if (is_pframe)
|
||||||
|
bit = _read_bits(ctx, 1);
|
||||||
|
else
|
||||||
|
bit = 1;
|
||||||
|
|
||||||
|
if (bit == 1) {
|
||||||
|
|
||||||
|
/* Yes: decode it. */
|
||||||
|
|
||||||
|
if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
|
||||||
|
|
||||||
|
/* Corrupted frame: clear Cr and Cb planes and return. */
|
||||||
|
p = ctx->cur_frame_buf + ctx->y_size;
|
||||||
|
memset(p, 128, ctx->crcb_size * 2);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_idct_dequant_block(ctx, dct_block, 1);
|
||||||
|
|
||||||
|
for (i = 0; i < num_rows; i++) {
|
||||||
|
p = dst + (ctx->crcb_stride * i);
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
p[j] = dct_block[(i * 8) + j];
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* No change no worries: just copy from the previous frame. */
|
||||||
|
|
||||||
|
for (i = 0; i < num_rows; i++) {
|
||||||
|
offset = ctx->crcb_stride * i;
|
||||||
|
|
||||||
|
memcpy(dst + offset, src + offset, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src += 8;
|
||||||
|
dst += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a copy of the current frame and store in
|
||||||
|
* the circular pointer list of 16 entries.
|
||||||
|
*/
|
||||||
|
ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index];
|
||||||
|
memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf,
|
||||||
|
ctx->y_size + (ctx->crcb_size * 2));
|
||||||
|
|
||||||
|
if (--ctx->ptr_index < 0)
|
||||||
|
ctx->ptr_index = 15;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform deblocking on all planes.
|
||||||
|
*/
|
||||||
|
_deblock(ctx->cur_frame_buf,
|
||||||
|
ctx->y_stride, ctx->y_row_count);
|
||||||
|
|
||||||
|
_deblock(ctx->cur_frame_buf + ctx->y_size,
|
||||||
|
ctx->crcb_stride, ctx->crcb_row_count);
|
||||||
|
|
||||||
|
_deblock(ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size,
|
||||||
|
ctx->crcb_stride, ctx->crcb_row_count);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,419 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
#define LUMINANCE_THRESHOLD 32.0f
|
||||||
|
#define CHROMINANCE_THRESHOLD 36.0f
|
||||||
|
|
||||||
|
static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a MIMIC-encoded frame from RGB data.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context
|
||||||
|
* @param input_buffer buffer containing pixeldata in RGB 24-bpp packed pixel top-down format
|
||||||
|
* @param output_buffer buffer that will receive the MIMIC-encoded frame
|
||||||
|
* (use #mimic_get_property to determine the required buffer size)
|
||||||
|
* @param output_length pointer to an integer that receives the length of the encoded data
|
||||||
|
* written to output_buffer
|
||||||
|
* @param make_keyframe whether the encoder should make this frame a keyframe
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_encode_frame(MimCtx *ctx,
|
||||||
|
const guchar *input_buffer,
|
||||||
|
guchar *output_buffer,
|
||||||
|
gint *output_length,
|
||||||
|
gboolean make_keyframe)
|
||||||
|
{
|
||||||
|
guchar *output_y, *output_cb, *output_cr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some sanity checks.
|
||||||
|
*/
|
||||||
|
if (ctx == NULL || input_buffer == NULL ||
|
||||||
|
output_buffer == NULL || output_length == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->encoder_initialized)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize state.
|
||||||
|
*/
|
||||||
|
ctx->chunk_ptr = (guint32 *) (output_buffer + 20);
|
||||||
|
ctx->cur_chunk = 0;
|
||||||
|
ctx->cur_chunk_len = 0;
|
||||||
|
|
||||||
|
if (ctx->frame_num == 0)
|
||||||
|
make_keyframe = TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write header.
|
||||||
|
*/
|
||||||
|
memset(output_buffer, 0, 20);
|
||||||
|
*((guint16 *) (output_buffer + 0)) = GUINT16_TO_LE(256);
|
||||||
|
*((guint16 *) (output_buffer + 2)) = GUINT16_TO_LE(ctx->quality);
|
||||||
|
*((guint16 *) (output_buffer + 4)) = GUINT16_TO_LE(ctx->frame_width);
|
||||||
|
*((guint16 *) (output_buffer + 6)) = GUINT16_TO_LE(ctx->frame_height);
|
||||||
|
*((guint32 *) (output_buffer + 12)) = GUINT32_TO_LE((make_keyframe == 0));
|
||||||
|
*(output_buffer + 16) = ctx->num_coeffs;
|
||||||
|
*(output_buffer + 17) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform RGB to YUV 420 conversion.
|
||||||
|
*/
|
||||||
|
output_y = ctx->cur_frame_buf;
|
||||||
|
output_cr = ctx->cur_frame_buf + ctx->y_size;
|
||||||
|
output_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size;
|
||||||
|
|
||||||
|
_rgb_to_yuv(input_buffer,
|
||||||
|
output_y,
|
||||||
|
output_cb,
|
||||||
|
output_cr,
|
||||||
|
ctx->frame_width,
|
||||||
|
ctx->frame_height);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode frame.
|
||||||
|
*/
|
||||||
|
encode_main(ctx, output_buffer, (make_keyframe == FALSE));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out any pending bits to stream by zero-padding with 32 bits.
|
||||||
|
*/
|
||||||
|
_write_bits(ctx, 0, 32);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate bytes written.
|
||||||
|
*/
|
||||||
|
*output_length = (guchar *) ctx->chunk_ptr - output_buffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment frame counter.
|
||||||
|
*/
|
||||||
|
ctx->frame_num++;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gdouble compare_blocks(const guchar *p1,
|
||||||
|
const guchar *p2,
|
||||||
|
gint stride,
|
||||||
|
gint row_count,
|
||||||
|
gboolean is_chrom);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* encode_main
|
||||||
|
*
|
||||||
|
* Main encoding loop.
|
||||||
|
*/
|
||||||
|
static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe)
|
||||||
|
{
|
||||||
|
gint x, y, i, offset, chrom_ch;
|
||||||
|
gint dct_block[64];
|
||||||
|
guchar *src, *dst, *p1, *p2;
|
||||||
|
gdouble match;
|
||||||
|
gboolean encoded;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Round down small differences in luminance channel.
|
||||||
|
*/
|
||||||
|
if (is_pframe) {
|
||||||
|
|
||||||
|
p1 = ctx->cur_frame_buf;
|
||||||
|
p2 = ctx->prev_frame_buf;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->y_size; i++) {
|
||||||
|
|
||||||
|
if (abs(p2[0] - p1[0]) < 7)
|
||||||
|
p1[0] = p2[0];
|
||||||
|
|
||||||
|
p1++;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode Y plane.
|
||||||
|
*/
|
||||||
|
for (y = 0; y < ctx->num_vblocks_y; y++) {
|
||||||
|
|
||||||
|
for (x = 0; x < ctx->num_hblocks_y; x++) {
|
||||||
|
|
||||||
|
/* Calculate final offset into buffer. */
|
||||||
|
offset = (ctx->y_stride * 8 * y) + (x * 8);
|
||||||
|
|
||||||
|
src = NULL;
|
||||||
|
encoded = FALSE;
|
||||||
|
|
||||||
|
if (is_pframe) {
|
||||||
|
|
||||||
|
/* Is the current block similar enough to what it was in the previous frame? */
|
||||||
|
|
||||||
|
match = compare_blocks(ctx->cur_frame_buf + offset,
|
||||||
|
ctx->prev_frame_buf + offset,
|
||||||
|
ctx->y_stride, 8,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (match > LUMINANCE_THRESHOLD) {
|
||||||
|
|
||||||
|
/* Yes: write out '1' to indicate a no-change condition. */
|
||||||
|
|
||||||
|
_write_bits(ctx, 1, 1);
|
||||||
|
|
||||||
|
src = ctx->prev_frame_buf + offset;
|
||||||
|
encoded = TRUE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* No: Is the current block similar enough to what it was in one
|
||||||
|
* of the (up to) 15 last frames preceding the previous? */
|
||||||
|
|
||||||
|
gint best_index = 0;
|
||||||
|
gdouble best_match = 0.0;
|
||||||
|
|
||||||
|
gint num_backrefs = ctx->frame_num - 1;
|
||||||
|
if (num_backrefs > 15)
|
||||||
|
num_backrefs = 15;
|
||||||
|
|
||||||
|
for (i = 1; i <= num_backrefs; i++) {
|
||||||
|
|
||||||
|
match = compare_blocks(ctx->buf_ptrs[(ctx->ptr_index + i) % 16] + offset,
|
||||||
|
ctx->cur_frame_buf + offset,
|
||||||
|
ctx->y_stride, 8,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (match > LUMINANCE_THRESHOLD && match > best_match) {
|
||||||
|
best_index = i;
|
||||||
|
best_match = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_index != 0) {
|
||||||
|
|
||||||
|
/* Yes: write out '01' to indicate a "change but like previous"-condition,
|
||||||
|
* followed by 4 bits containing the back-reference. */
|
||||||
|
_write_bits(ctx, 0, 1);
|
||||||
|
_write_bits(ctx, 1, 1);
|
||||||
|
_write_bits(ctx, best_index, 4);
|
||||||
|
|
||||||
|
src = ctx->buf_ptrs[(ctx->ptr_index + best_index) % 16] + offset;
|
||||||
|
encoded = TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encoded) {
|
||||||
|
|
||||||
|
/* Keyframe or in any case no? ;-) Well, encode it then. */
|
||||||
|
|
||||||
|
if (is_pframe) {
|
||||||
|
_write_bits(ctx, 0, 1);
|
||||||
|
_write_bits(ctx, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fdct_quant_block(ctx,
|
||||||
|
dct_block,
|
||||||
|
ctx->cur_frame_buf + offset,
|
||||||
|
ctx->y_stride,
|
||||||
|
FALSE,
|
||||||
|
ctx->num_coeffs);
|
||||||
|
|
||||||
|
_vlc_encode_block(ctx,
|
||||||
|
dct_block,
|
||||||
|
ctx->num_coeffs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And if there was some kind of no-change condition,
|
||||||
|
* we want to copy the previous block. */
|
||||||
|
if (src != NULL) {
|
||||||
|
|
||||||
|
dst = ctx->cur_frame_buf + offset;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
|
||||||
|
memcpy(dst, src, 8);
|
||||||
|
|
||||||
|
src += ctx->y_stride;
|
||||||
|
dst += ctx->y_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode Cr and Cb planes.
|
||||||
|
*/
|
||||||
|
for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
|
||||||
|
|
||||||
|
/* Calculate base offset into buffer. */
|
||||||
|
gint base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch);
|
||||||
|
|
||||||
|
for (y = 0; y < ctx->num_vblocks_cbcr; y++) {
|
||||||
|
guchar tmp_block[64];
|
||||||
|
guint num_rows = 8;
|
||||||
|
|
||||||
|
/* The last row of blocks in chrominance for 160x120 resolution
|
||||||
|
* is half the normal height and must be accounted for. */
|
||||||
|
if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0)
|
||||||
|
num_rows = 4;
|
||||||
|
|
||||||
|
for (x = 0; x < ctx->num_hblocks_cbcr; x++) {
|
||||||
|
|
||||||
|
/* Calculate final offset into buffer. */
|
||||||
|
offset = base_offset + (ctx->crcb_stride * 8 * y) + (x * 8);
|
||||||
|
|
||||||
|
src = NULL;
|
||||||
|
encoded = FALSE;
|
||||||
|
|
||||||
|
if (is_pframe) {
|
||||||
|
|
||||||
|
/* Is the current block similar enough to what it was in the previous frame? */
|
||||||
|
|
||||||
|
match = compare_blocks(ctx->prev_frame_buf + offset,
|
||||||
|
ctx->cur_frame_buf + offset,
|
||||||
|
ctx->crcb_stride, num_rows,
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
if (match > CHROMINANCE_THRESHOLD) {
|
||||||
|
|
||||||
|
/* Yes: write out '0' to indicate a no-change condition. */
|
||||||
|
|
||||||
|
_write_bits(ctx, 0, 1);
|
||||||
|
|
||||||
|
encoded = TRUE;
|
||||||
|
|
||||||
|
src = ctx->prev_frame_buf + offset;
|
||||||
|
dst = ctx->cur_frame_buf + offset;
|
||||||
|
for (i = 0; i < num_rows; i++) {
|
||||||
|
|
||||||
|
memcpy(dst, src, 8);
|
||||||
|
|
||||||
|
src += ctx->crcb_stride;
|
||||||
|
dst += ctx->crcb_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encoded) {
|
||||||
|
|
||||||
|
/* Keyframe or just not similar enough? ;-) Well, encode it then. */
|
||||||
|
|
||||||
|
if (is_pframe)
|
||||||
|
_write_bits(ctx, 1, 1);
|
||||||
|
|
||||||
|
/* Use a temporary array to handle cases where the
|
||||||
|
* current block is not of normal height (see above). */
|
||||||
|
src = ctx->cur_frame_buf + offset;
|
||||||
|
dst = tmp_block;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
|
||||||
|
memcpy(dst, src, 8);
|
||||||
|
|
||||||
|
if (i < (num_rows - 1))
|
||||||
|
src += ctx->crcb_stride;
|
||||||
|
dst += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fdct_quant_block(ctx,
|
||||||
|
dct_block,
|
||||||
|
tmp_block,
|
||||||
|
8,
|
||||||
|
TRUE,
|
||||||
|
ctx->num_coeffs);
|
||||||
|
|
||||||
|
_vlc_encode_block(ctx,
|
||||||
|
dct_block,
|
||||||
|
ctx->num_coeffs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a copy of the current frame and store in
|
||||||
|
* the circular pointer list of 16 entries.
|
||||||
|
*/
|
||||||
|
ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index];
|
||||||
|
memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf,
|
||||||
|
ctx->y_size + (ctx->crcb_size * 2));
|
||||||
|
|
||||||
|
if (--ctx->ptr_index < 0)
|
||||||
|
ctx->ptr_index = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compare_blocks
|
||||||
|
*
|
||||||
|
* Helper-function used to compare two blocks and
|
||||||
|
* determine how similar they are.
|
||||||
|
*/
|
||||||
|
static gdouble compare_blocks(const guchar *p1,
|
||||||
|
const guchar *p2,
|
||||||
|
gint stride,
|
||||||
|
gint row_count,
|
||||||
|
gboolean is_chrom)
|
||||||
|
{
|
||||||
|
gint i, j, sum;
|
||||||
|
gdouble d;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < row_count; i++) {
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
|
||||||
|
gint d = p2[j] - p1[j];
|
||||||
|
|
||||||
|
sum += d * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 += stride;
|
||||||
|
p2 += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_chrom) {
|
||||||
|
if (row_count == 8)
|
||||||
|
d = sum * 0.015625;
|
||||||
|
else
|
||||||
|
d = sum * 0.03125;
|
||||||
|
} else {
|
||||||
|
d = sum / 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d == 0.0f)
|
||||||
|
return 100.0f;
|
||||||
|
else
|
||||||
|
return (10.0f * log(65025.0f / d)) / G_LN10;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,181 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
extern guchar _col_zag[64];
|
||||||
|
|
||||||
|
void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src,
|
||||||
|
gint stride, gboolean is_chrom, gint num_coeffs)
|
||||||
|
{
|
||||||
|
gint sum1, sum2, sum3, sum4;
|
||||||
|
gint diff1, diff2, diff3, diff4;
|
||||||
|
gint ex1, ex2, ex3, ex4, ex5;
|
||||||
|
gint i, j;
|
||||||
|
const guchar *p1;
|
||||||
|
gint *iptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward DCT, first pass (horizontal).
|
||||||
|
*/
|
||||||
|
p1 = src;
|
||||||
|
iptr = block;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
sum1 = p1[0] + p1[7];
|
||||||
|
sum2 = p1[1] + p1[6];
|
||||||
|
sum3 = p1[2] + p1[5];
|
||||||
|
sum4 = p1[3] + p1[4];
|
||||||
|
|
||||||
|
diff1 = p1[0] - p1[7];
|
||||||
|
diff2 = p1[1] - p1[6];
|
||||||
|
diff3 = p1[2] - p1[5];
|
||||||
|
diff4 = p1[3] - p1[4];
|
||||||
|
|
||||||
|
ex1 = ((diff1 + diff4) * 851) - (diff1 * 282);
|
||||||
|
ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804);
|
||||||
|
ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204);
|
||||||
|
ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420);
|
||||||
|
|
||||||
|
iptr[0] = sum1 + sum2 + sum3 + sum4;
|
||||||
|
iptr[2] = (((sum1 - sum4) * 1337) + ((sum2 - sum3) * 554)) >> 10;
|
||||||
|
iptr[4] = sum1 - sum2 - sum3 + sum4;
|
||||||
|
|
||||||
|
iptr[1] = (ex1 + ex2 + ex3 + ex4) >> 10;
|
||||||
|
iptr[3] = ((ex4 - ex2) * 181) >> 17;
|
||||||
|
iptr[5] = ((ex1 - ex3) * 181) >> 17;
|
||||||
|
|
||||||
|
p1 += stride;
|
||||||
|
iptr += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = src;
|
||||||
|
iptr = block;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward DCT, first pass (vertical).
|
||||||
|
*
|
||||||
|
* This is only known to be correct for i == 0, though it seems to be ...
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
sum1 = iptr[ 0 + i] + iptr[56 + i];
|
||||||
|
sum2 = iptr[ 8 + i] + iptr[48 + i];
|
||||||
|
sum3 = iptr[16 + i] + iptr[40 + i];
|
||||||
|
sum4 = iptr[24 + i] + iptr[32 + i];
|
||||||
|
|
||||||
|
diff1 = iptr[ 0 + i] - iptr[56 + i];
|
||||||
|
diff2 = iptr[ 8 + i] - iptr[48 + i];
|
||||||
|
diff3 = iptr[16 + i] - iptr[40 + i];
|
||||||
|
diff4 = iptr[24 + i] - iptr[32 + i];
|
||||||
|
|
||||||
|
ex1 = ((diff1 + diff4) * 851) - (diff1 * 282);
|
||||||
|
ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804);
|
||||||
|
ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204);
|
||||||
|
ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420);
|
||||||
|
|
||||||
|
ex5 = (sum1 + sum2 - sum3 - sum4) * 554;
|
||||||
|
|
||||||
|
for (j = 0; j < 7 - i; j++) {
|
||||||
|
switch (j) {
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
iptr[ 0 + i] = (16 + sum1 + sum2 + sum3 + sum4) >> 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
iptr[ 8 + i] = (16384 + ex1 + ex2 + ex3 + ex4) >> 15;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
iptr[16 + i] = (16384 + ((sum1 - sum4) * 783) + ex5) >> 15;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
iptr[24 + i] = (8192 + (((ex4 - ex2) >> 8) * 181)) >> 14;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
iptr[32 + i] = (16 + sum1 - sum2 - sum3 + sum4) >> 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
iptr[40 + i] = (8192 + (((ex1 - ex3) >> 8) * 181)) >> 14;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
iptr[48 + i] = (16384 - ((sum2 - sum3) * 1891) + ex5) >> 15;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quantize.
|
||||||
|
*/
|
||||||
|
block[0] /= 2;
|
||||||
|
block[8] /= 4;
|
||||||
|
block[1] /= 4;
|
||||||
|
block[6] = 0;
|
||||||
|
|
||||||
|
if (num_coeffs > 3) {
|
||||||
|
|
||||||
|
gdouble s = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5;
|
||||||
|
|
||||||
|
if (s > 10.0)
|
||||||
|
s = 10.0;
|
||||||
|
else if (is_chrom != 0 && s < 1.0)
|
||||||
|
s = 1.0;
|
||||||
|
else if (s < 2.0)
|
||||||
|
s = 2.0;
|
||||||
|
|
||||||
|
s = 1.0 / s;
|
||||||
|
|
||||||
|
for (i = 3; i < num_coeffs; i++) {
|
||||||
|
|
||||||
|
gdouble coeff, r;
|
||||||
|
|
||||||
|
coeff = block[_col_zag[i]] * s;
|
||||||
|
r = coeff - (gint) coeff;
|
||||||
|
|
||||||
|
if (r >= 0.6)
|
||||||
|
block[_col_zag[i]] = (gint) (coeff + 1.0);
|
||||||
|
else if (r <= -0.6)
|
||||||
|
block[_col_zag[i]] = (gint) (coeff - 1.0);
|
||||||
|
else
|
||||||
|
block[_col_zag[i]] = (gint) coeff;
|
||||||
|
|
||||||
|
if (block[_col_zag[i]] > 120)
|
||||||
|
block[_col_zag[i]] = 120;
|
||||||
|
else if (block[_col_zag[i]] < -120)
|
||||||
|
block[_col_zag[i]] = -120;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block[8] > 120)
|
||||||
|
block[8] = 120;
|
||||||
|
else if (block[8] < -120)
|
||||||
|
block[8] = -120;
|
||||||
|
|
||||||
|
if (block[1] > 120)
|
||||||
|
block[1] = 120;
|
||||||
|
else if (block[1] < -120)
|
||||||
|
block[1] = -120;
|
||||||
|
|
||||||
|
for (i = num_coeffs; i < 64; i++)
|
||||||
|
block[_col_zag[i]] = 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom)
|
||||||
|
{
|
||||||
|
gdouble f;
|
||||||
|
gint i, *p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* De-quantize.
|
||||||
|
*/
|
||||||
|
f = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5;
|
||||||
|
|
||||||
|
if (f > 10.0)
|
||||||
|
f = 10.0;
|
||||||
|
|
||||||
|
if (!is_chrom) {
|
||||||
|
if (f < 2.0)
|
||||||
|
f = 2.0;
|
||||||
|
} else {
|
||||||
|
if (f < 1.0)
|
||||||
|
f = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
block[0] <<= 1;
|
||||||
|
block[1] <<= 2;
|
||||||
|
block[8] <<= 2;
|
||||||
|
|
||||||
|
for (i = 2; i < 64; i++) {
|
||||||
|
if (i == 8)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
block[i] *= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inverse DCT, first pass (horizontal).
|
||||||
|
*/
|
||||||
|
p = block;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
gint v1, v2, v3, v4, v5, v6, v7, v8;
|
||||||
|
gint va, vb;
|
||||||
|
|
||||||
|
va = (p[0] << 11) + (p[4] << 11);
|
||||||
|
vb = ((p[2] << 2) * 392) + (((p[2] << 2) + (p[6] << 2)) * 277);
|
||||||
|
v1 = va + vb + 512;
|
||||||
|
v2 = va - vb + 512;
|
||||||
|
|
||||||
|
va = (p[0] << 11) - (p[4] << 11);
|
||||||
|
vb = (((p[2] << 2) + (p[6] << 2)) * 277) - ((p[6] << 2) * 946);
|
||||||
|
v3 = va + vb + 512;
|
||||||
|
v4 = va - vb + 512;
|
||||||
|
|
||||||
|
va = (p[1] << 9) + (p[3] * 724) + (p[7] << 9);
|
||||||
|
vb = (p[1] << 9) + (p[5] * 724) - (p[7] << 9);
|
||||||
|
v5 = (((va + vb) * 213) - (vb * 71)) >> 6;
|
||||||
|
v6 = (((va + vb) * 213) - (va * 355)) >> 6;
|
||||||
|
|
||||||
|
va = (p[1] << 9) - (p[3] * 724) + (p[7] << 9);
|
||||||
|
vb = (p[1] << 9) - (p[5] * 724) - (p[7] << 9);
|
||||||
|
v7 = (((va + vb) * 251) - (va * 201)) >> 6;
|
||||||
|
v8 = (((va + vb) * 251) - (vb * 301)) >> 6;
|
||||||
|
|
||||||
|
p[0] = (v1 + v5) >> 10;
|
||||||
|
p[1] = (v3 + v7) >> 10;
|
||||||
|
p[2] = (v4 + v8) >> 10;
|
||||||
|
p[3] = (v2 + v6) >> 10;
|
||||||
|
p[4] = (v2 - v6) >> 10;
|
||||||
|
p[5] = (v4 - v8) >> 10;
|
||||||
|
p[6] = (v3 - v7) >> 10;
|
||||||
|
p[7] = (v1 - v5) >> 10;
|
||||||
|
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inverse dct, second pass (vertical).
|
||||||
|
*/
|
||||||
|
p = block;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
gint v1, v2, v3, v4, v5, v6, v7, v8;
|
||||||
|
gint va, vb;
|
||||||
|
|
||||||
|
va = (p[0] << 9) + (p[32] << 9);
|
||||||
|
vb = ((p[16] + p[48]) * 277) + (p[16] * 392);
|
||||||
|
v1 = va + vb + 1024;
|
||||||
|
v2 = va - vb + 1024;
|
||||||
|
|
||||||
|
va = (p[0] << 9) - (p[32] << 9);
|
||||||
|
vb = ((p[16] + p[48]) * 277) - (p[48] * 946);
|
||||||
|
v3 = va + vb + 1024;
|
||||||
|
v4 = va - vb + 1024;
|
||||||
|
|
||||||
|
va = ((p[8] << 7) + (p[24] * 181) + (p[56] << 7)) >> 6;
|
||||||
|
vb = ((p[8] << 7) + (p[40] * 181) - (p[56] << 7)) >> 6;
|
||||||
|
v5 = ((va + vb) * 213) - (vb * 71);
|
||||||
|
v6 = ((va + vb) * 213) - (va * 355);
|
||||||
|
|
||||||
|
va = ((p[8] << 7) - (p[24] * 181) + (p[56] << 7)) >> 6;
|
||||||
|
vb = ((p[8] << 7) - (p[40] * 181) - (p[56] << 7)) >> 6;
|
||||||
|
v7 = ((va + vb) * 251) - (va * 201);
|
||||||
|
v8 = ((va + vb) * 251) - (vb * 301);
|
||||||
|
|
||||||
|
p[0] = (v1 + v5) >> 11;
|
||||||
|
p[8] = (v3 + v7) >> 11;
|
||||||
|
p[16] = (v4 + v8) >> 11;
|
||||||
|
p[24] = (v2 + v6) >> 11;
|
||||||
|
p[32] = (v2 - v6) >> 11;
|
||||||
|
p[40] = (v4 - v8) >> 11;
|
||||||
|
p[48] = (v3 - v7) >> 11;
|
||||||
|
p[56] = (v1 - v5) >> 11;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIMIC_PRIVATE_H
|
||||||
|
#define MIMIC_PRIVATE_H
|
||||||
|
|
||||||
|
#include "mimic.h"
|
||||||
|
|
||||||
|
#define ENCODER_BUFFER_SIZE 16384
|
||||||
|
#define ENCODER_QUALITY_DEFAULT 0
|
||||||
|
#define ENCODER_QUALITY_MIN 0
|
||||||
|
#define ENCODER_QUALITY_MAX 10000
|
||||||
|
|
||||||
|
struct _MimCtx {
|
||||||
|
gboolean encoder_initialized;
|
||||||
|
gboolean decoder_initialized;
|
||||||
|
|
||||||
|
gint frame_width;
|
||||||
|
gint frame_height;
|
||||||
|
gint quality;
|
||||||
|
gint num_coeffs;
|
||||||
|
|
||||||
|
gint y_stride;
|
||||||
|
gint y_row_count;
|
||||||
|
gint y_size;
|
||||||
|
|
||||||
|
gint crcb_stride;
|
||||||
|
gint crcb_row_count;
|
||||||
|
gint crcb_size;
|
||||||
|
|
||||||
|
gint num_vblocks_y;
|
||||||
|
gint num_hblocks_y;
|
||||||
|
|
||||||
|
gint num_vblocks_cbcr;
|
||||||
|
gint num_hblocks_cbcr;
|
||||||
|
|
||||||
|
guchar *cur_frame_buf;
|
||||||
|
guchar *prev_frame_buf;
|
||||||
|
|
||||||
|
gint8 vlcdec_lookup[2296];
|
||||||
|
|
||||||
|
gchar *data_buffer;
|
||||||
|
guint data_index;
|
||||||
|
|
||||||
|
guint32 cur_chunk;
|
||||||
|
gint cur_chunk_len;
|
||||||
|
|
||||||
|
guint32 *chunk_ptr;
|
||||||
|
gboolean read_odd;
|
||||||
|
|
||||||
|
gint frame_num;
|
||||||
|
|
||||||
|
gint ptr_index;
|
||||||
|
guchar *buf_ptrs[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guchar length1;
|
||||||
|
guint32 part1;
|
||||||
|
|
||||||
|
guchar length2;
|
||||||
|
guint32 part2;
|
||||||
|
} VlcSymbol;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint32 magic;
|
||||||
|
guchar pos_add;
|
||||||
|
guchar num_bits;
|
||||||
|
} VlcMagic;
|
||||||
|
|
||||||
|
void _mimic_init(MimCtx *ctx, gint width, gint height);
|
||||||
|
guchar _clamp_value(gint value);
|
||||||
|
|
||||||
|
guint32 _read_bits(MimCtx *ctx, gint num_bits);
|
||||||
|
void _write_bits(MimCtx *ctx, guint32 bits, gint length);
|
||||||
|
|
||||||
|
void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs);
|
||||||
|
gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs);
|
||||||
|
|
||||||
|
void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src,
|
||||||
|
gint stride, gboolean is_chrom, gint num_coeffs);
|
||||||
|
void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom);
|
||||||
|
|
||||||
|
VlcMagic *_find_magic(guint magic);
|
||||||
|
void _initialize_vlcdec_lookup(gint8 *lookup_tbl);
|
||||||
|
|
||||||
|
void _rgb_to_yuv(const guchar *input_rgb,
|
||||||
|
guchar *output_y,
|
||||||
|
guchar *output_cb,
|
||||||
|
guchar *output_cr,
|
||||||
|
gint width,
|
||||||
|
gint height);
|
||||||
|
void _yuv_to_rgb(const guchar *input_y,
|
||||||
|
const guchar *input_cb,
|
||||||
|
const guchar *input_cr,
|
||||||
|
guchar *output_rgb,
|
||||||
|
guint width,
|
||||||
|
guint height);
|
||||||
|
|
||||||
|
void _deblock(guchar *blocks, guint stride, guint row_count);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,334 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance and returns a pointer to the new context
|
||||||
|
* that can be used for either encoding or decoding by calling
|
||||||
|
* #mimic_encoder_init or #mimic_decoder_init.
|
||||||
|
*
|
||||||
|
* #mimic_close is called to free any resources associated with
|
||||||
|
* the context once done.
|
||||||
|
*
|
||||||
|
* @returns a new mimic context
|
||||||
|
*/
|
||||||
|
MimCtx *mimic_open()
|
||||||
|
{
|
||||||
|
MimCtx *ctx;
|
||||||
|
|
||||||
|
ctx = g_new0(MimCtx, 1);
|
||||||
|
|
||||||
|
ctx->encoder_initialized = FALSE;
|
||||||
|
ctx->decoder_initialized = FALSE;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees any resources associated with the given context.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context to free
|
||||||
|
*/
|
||||||
|
void mimic_close(MimCtx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->encoder_initialized || ctx->decoder_initialized) {
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_free(ctx->cur_frame_buf);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
g_free(ctx->buf_ptrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mimic_init
|
||||||
|
*
|
||||||
|
* Internal helper-function used to initialize
|
||||||
|
* a given context.
|
||||||
|
*/
|
||||||
|
static void mimic_init(MimCtx *ctx, gint width, gint height)
|
||||||
|
{
|
||||||
|
gint bufsize, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dimensions-related.
|
||||||
|
*/
|
||||||
|
ctx->frame_width = width;
|
||||||
|
ctx->frame_height = height;
|
||||||
|
|
||||||
|
ctx->y_stride = ctx->frame_width;
|
||||||
|
ctx->y_row_count = ctx->frame_height;
|
||||||
|
ctx->y_size = ctx->y_stride * ctx->y_row_count;
|
||||||
|
|
||||||
|
ctx->crcb_stride = ctx->y_stride / 2;
|
||||||
|
ctx->crcb_row_count = ctx->y_row_count / 2;
|
||||||
|
ctx->crcb_size = ctx->crcb_stride * ctx->crcb_row_count;
|
||||||
|
|
||||||
|
ctx->num_vblocks_y = ctx->frame_height / 8;
|
||||||
|
ctx->num_hblocks_y = ctx->frame_width / 8;
|
||||||
|
|
||||||
|
ctx->num_vblocks_cbcr = ctx->frame_height / 16;
|
||||||
|
ctx->num_hblocks_cbcr = ctx->frame_width / 16;
|
||||||
|
|
||||||
|
if (ctx->frame_height % 16 != 0)
|
||||||
|
ctx->num_vblocks_cbcr++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize state.
|
||||||
|
*/
|
||||||
|
ctx->frame_num = 0;
|
||||||
|
ctx->ptr_index = 15;
|
||||||
|
ctx->num_coeffs = 28;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory for buffers.
|
||||||
|
*/
|
||||||
|
ctx->cur_frame_buf = g_new(guchar, (320 * 240 * 3) / 2);
|
||||||
|
|
||||||
|
bufsize = ctx->y_size + (ctx->crcb_size * 2);
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
ctx->buf_ptrs[i] = g_new(guchar, bufsize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vlc lookup used by decoder.
|
||||||
|
*/
|
||||||
|
_initialize_vlcdec_lookup(ctx->vlcdec_lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the mimic encoder and prepare for encoding by
|
||||||
|
* initializing internal state and allocating resources as
|
||||||
|
* needed.
|
||||||
|
*
|
||||||
|
* After initializing use #mimic_get_property to determine
|
||||||
|
* the size of the output buffer needed for calls to
|
||||||
|
* #mimic_encode_frame. Use #mimic_set_property to set
|
||||||
|
* encoding quality.
|
||||||
|
*
|
||||||
|
* Note that once a given context has been initialized
|
||||||
|
* for either encoding or decoding it is not possible
|
||||||
|
* to initialize it again.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context to initialize
|
||||||
|
* @param resolution a #MimicResEnum used to specify the resolution
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution)
|
||||||
|
{
|
||||||
|
gint width, height;
|
||||||
|
|
||||||
|
/* Check if we've been initialized before. */
|
||||||
|
if (ctx->encoder_initialized || ctx->decoder_initialized)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Check resolution. */
|
||||||
|
if (resolution == MIMIC_RES_LOW) {
|
||||||
|
width = 160;
|
||||||
|
height = 120;
|
||||||
|
} else if (resolution == MIMIC_RES_HIGH) {
|
||||||
|
width = 320;
|
||||||
|
height = 240;
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize! */
|
||||||
|
mimic_init(ctx, width, height);
|
||||||
|
|
||||||
|
/* Set a default quality setting. */
|
||||||
|
ctx->quality = ENCODER_QUALITY_DEFAULT;
|
||||||
|
|
||||||
|
ctx->encoder_initialized = TRUE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the mimic decoder. The frame passed in frame_buffer
|
||||||
|
* is used to determine the resolution so that the internal state
|
||||||
|
* can be prepared and resources allocated accordingly. Note that
|
||||||
|
* the frame passed has to be a keyframe.
|
||||||
|
*
|
||||||
|
* After initializing use #mimic_get_property to determine required
|
||||||
|
* buffer-size, resolution, quality, etc.
|
||||||
|
*
|
||||||
|
* Note that once a given context has been initialized
|
||||||
|
* for either encoding or decoding it is not possible
|
||||||
|
* to initialize it again.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context to initialize
|
||||||
|
* @param frame_buffer buffer containing the first frame to decode
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer)
|
||||||
|
{
|
||||||
|
gint width, height;
|
||||||
|
gboolean is_keyframe;
|
||||||
|
|
||||||
|
/* Check if we've been initialized before and that
|
||||||
|
* frame_buffer is not NULL. */
|
||||||
|
if (ctx->encoder_initialized || ctx->decoder_initialized ||
|
||||||
|
frame_buffer == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check resolution. */
|
||||||
|
width = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 4)));
|
||||||
|
height = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 6)));
|
||||||
|
|
||||||
|
if (!(width == 160 && height == 120) && !(width == 320 && height == 240))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Check that we're initialized with a keyframe. */
|
||||||
|
is_keyframe = (GUINT32_FROM_LE(*((guint32 *) (frame_buffer + 12))) == 0);
|
||||||
|
|
||||||
|
if (!is_keyframe)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Get quality setting (in case we get queried for it before decoding). */
|
||||||
|
ctx->quality = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 2)));
|
||||||
|
|
||||||
|
/* Initialize! */
|
||||||
|
mimic_init(ctx, width, height);
|
||||||
|
|
||||||
|
ctx->decoder_initialized = TRUE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property from a given mimic context. The context
|
||||||
|
* has to be initialized.
|
||||||
|
*
|
||||||
|
* Currently the following properties are defined:
|
||||||
|
* - "buffer_size"
|
||||||
|
* - Required output buffer size
|
||||||
|
* - "width"
|
||||||
|
* - Frame width
|
||||||
|
* - "height"
|
||||||
|
* - Frame height
|
||||||
|
* - "quality"
|
||||||
|
* - Encoder: Encoding quality used
|
||||||
|
* - Decoder: Decoding quality of the last known frame
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context to retrieve the property from
|
||||||
|
* @param name of the property to retrieve the current value of
|
||||||
|
* @param data pointer to the data that will receive the retrieved value
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data)
|
||||||
|
{
|
||||||
|
/* Either the encoder or the decoder has to be initialized. */
|
||||||
|
if (!ctx->encoder_initialized && !ctx->decoder_initialized)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (ctx->encoder_initialized) {
|
||||||
|
|
||||||
|
if (strcmp(name, "buffer_size") == 0) {
|
||||||
|
*((gint *) data) = ENCODER_BUFFER_SIZE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* decoder_initialized */
|
||||||
|
|
||||||
|
if (strcmp(name, "buffer_size") == 0) {
|
||||||
|
*((gint *) data) = ctx->frame_width * ctx->frame_height * 3;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(name, "width") == 0) {
|
||||||
|
*((gint *) data) = ctx->frame_width;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
} else if (strcmp(name, "height") == 0) {
|
||||||
|
*((gint *) data) = ctx->frame_height;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
} else if (strcmp(name, "quality") == 0) {
|
||||||
|
*((gint *) data) = ctx->quality;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property in a given mimic context. The context
|
||||||
|
* has to be initialized.
|
||||||
|
*
|
||||||
|
* Currently the following properties are defined:
|
||||||
|
* - "quality"
|
||||||
|
* - Encoding quality used by encoder.
|
||||||
|
*
|
||||||
|
* @param ctx the mimic context to set a property in
|
||||||
|
* @param name of the property to set to a new value
|
||||||
|
* @param data pointer to the data that contains the new value
|
||||||
|
* @returns #TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data)
|
||||||
|
{
|
||||||
|
/* Either the encoder or the decoder has to be initialized. */
|
||||||
|
if (!ctx->encoder_initialized && !ctx->decoder_initialized)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (ctx->encoder_initialized) {
|
||||||
|
|
||||||
|
if (strcmp(name, "quality") == 0) {
|
||||||
|
gint new_quality = *((gint *) data);
|
||||||
|
|
||||||
|
if (new_quality < ENCODER_QUALITY_MIN ||
|
||||||
|
new_quality > ENCODER_QUALITY_MAX)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->quality = new_quality;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* decoder_initialized */ }
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _clamp_value
|
||||||
|
*
|
||||||
|
* Internal helper-function used to clamp a given
|
||||||
|
* value to the range [ 0, 255 ].
|
||||||
|
*/
|
||||||
|
guchar _clamp_value(gint value)
|
||||||
|
{
|
||||||
|
if (value < 0)
|
||||||
|
return 0;
|
||||||
|
else if (value > 255)
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIMIC_H
|
||||||
|
#define MIMIC_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup libmimic libmimic public API
|
||||||
|
* @brief The public API of the libmimic library
|
||||||
|
*
|
||||||
|
* libmimic provides the API required for encoding and decoding
|
||||||
|
* MIMIC v2.x-encoded content.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mimic encoding/decoding context returned by #mimic_open
|
||||||
|
* and used for all further API calls until #mimic_close.
|
||||||
|
*/
|
||||||
|
typedef struct _MimCtx MimCtx;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MIMIC_RES_LOW, /**< 160x120 resolution */
|
||||||
|
MIMIC_RES_HIGH /**< 320x240 resolution */
|
||||||
|
} MimicResEnum;
|
||||||
|
|
||||||
|
MimCtx *mimic_open();
|
||||||
|
void mimic_close(MimCtx *ctx);
|
||||||
|
|
||||||
|
gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution);
|
||||||
|
gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer);
|
||||||
|
|
||||||
|
gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data);
|
||||||
|
gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data);
|
||||||
|
|
||||||
|
gboolean mimic_encode_frame(MimCtx *ctx,
|
||||||
|
const guchar *input_buffer,
|
||||||
|
guchar *output_buffer,
|
||||||
|
gint *output_length,
|
||||||
|
gboolean make_keyframe);
|
||||||
|
gboolean mimic_decode_frame(MimCtx *ctx,
|
||||||
|
const guchar *input_buffer,
|
||||||
|
guchar *output_buffer);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,119 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
extern guchar _col_zag[64];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _vlc_decode_block
|
||||||
|
*
|
||||||
|
* De-serialize (reconstruct) a variable length coded 8x8 block.
|
||||||
|
*/
|
||||||
|
gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs)
|
||||||
|
{
|
||||||
|
guint pos;
|
||||||
|
|
||||||
|
memset(block, 0, 64 * sizeof(gint));
|
||||||
|
|
||||||
|
/* The DC-value is read in as is. */
|
||||||
|
block[0] = _read_bits(ctx, 8);
|
||||||
|
|
||||||
|
for (pos = 1; pos < num_coeffs; pos++) {
|
||||||
|
|
||||||
|
guint prev_data_index, prev_cur_chunk_len, prev_chunk;
|
||||||
|
guint value, num_bits;
|
||||||
|
gboolean prev_read_odd, found_magic;
|
||||||
|
|
||||||
|
/* Save context. */
|
||||||
|
prev_data_index = ctx->data_index;
|
||||||
|
prev_cur_chunk_len = ctx->cur_chunk_len;
|
||||||
|
prev_chunk = ctx->cur_chunk;
|
||||||
|
prev_read_odd = ctx->read_odd;
|
||||||
|
|
||||||
|
/* Grab 16 bits. */
|
||||||
|
value = _read_bits(ctx, 16) << 16;
|
||||||
|
|
||||||
|
/* Restore context. */
|
||||||
|
ctx->data_index = prev_data_index;
|
||||||
|
ctx->cur_chunk_len = prev_cur_chunk_len;
|
||||||
|
ctx->cur_chunk = prev_chunk;
|
||||||
|
ctx->read_odd = prev_read_odd;
|
||||||
|
|
||||||
|
/* Analyze and determine number of bits to read initially. */
|
||||||
|
num_bits = 3;
|
||||||
|
if ((value >> 30) == 0 || (value >> 30) == 1) {
|
||||||
|
num_bits = 2;
|
||||||
|
} else if ((value & 0xE0000000) != 0x80000000) {
|
||||||
|
guint nibble = value >> 28;
|
||||||
|
|
||||||
|
if (nibble == 11 || nibble == 12) {
|
||||||
|
num_bits = 4;
|
||||||
|
} else if (nibble == 10) {
|
||||||
|
_read_bits(ctx, 4);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
if (((value << 2) & 0x8000000) == 0)
|
||||||
|
num_bits = 2;
|
||||||
|
|
||||||
|
num_bits += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read that number of bits. */
|
||||||
|
value = _read_bits(ctx, num_bits);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the current value against the magic ones,
|
||||||
|
* and continue extending it bit by bit from the input
|
||||||
|
* stream until the magic value is found or we have
|
||||||
|
* read 32 bits (in which case we give up).
|
||||||
|
*/
|
||||||
|
found_magic = FALSE;
|
||||||
|
while (!found_magic) {
|
||||||
|
VlcMagic *magic;
|
||||||
|
|
||||||
|
if (num_bits > 32)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
magic = _find_magic(value);
|
||||||
|
|
||||||
|
if (magic != NULL) {
|
||||||
|
pos += magic->pos_add;
|
||||||
|
num_bits = magic->num_bits;
|
||||||
|
|
||||||
|
found_magic = TRUE;
|
||||||
|
} else {
|
||||||
|
value <<= 1;
|
||||||
|
value |= _read_bits(ctx, 1);
|
||||||
|
|
||||||
|
num_bits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the number of bits given by magic value entry. */
|
||||||
|
value = _read_bits(ctx, num_bits);
|
||||||
|
|
||||||
|
/* Gotcha! :-) */
|
||||||
|
block[_col_zag[pos]] = ctx->vlcdec_lookup[(num_bits * 255) + value];
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
|||||||
|
/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "mimic-private.h"
|
||||||
|
|
||||||
|
extern guchar _col_zag[64];
|
||||||
|
extern VlcSymbol _vlc_alphabet[16][128];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _vlc_encode_block
|
||||||
|
*
|
||||||
|
* Serialize an 8x8 block using variable length coding.
|
||||||
|
*/
|
||||||
|
void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs)
|
||||||
|
{
|
||||||
|
gint i, num_zeroes;
|
||||||
|
|
||||||
|
/* The DC value is written out as is. */
|
||||||
|
_write_bits(ctx, block[0], 8);
|
||||||
|
|
||||||
|
/* Number of zeroes prefixing the next non-zero value. */
|
||||||
|
num_zeroes = 0;
|
||||||
|
|
||||||
|
for (i = 1; i < num_coeffs && num_zeroes <= 14; i++) {
|
||||||
|
|
||||||
|
/* Fetch AC coefficients from block in zig-zag order. */
|
||||||
|
gint value = block[_col_zag[i]];
|
||||||
|
|
||||||
|
if (value != 0) {
|
||||||
|
VlcSymbol sym;
|
||||||
|
|
||||||
|
/* Clip input values to [-128, +128]. */
|
||||||
|
if (value < -128)
|
||||||
|
value = -128;
|
||||||
|
else if (value > 128)
|
||||||
|
value = 128;
|
||||||
|
|
||||||
|
/* Look up symbol for the current non-zero value. */
|
||||||
|
sym = _vlc_alphabet[num_zeroes][abs(value) - 1];
|
||||||
|
|
||||||
|
/* No symbol? very rare... */
|
||||||
|
if (sym.length1 <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The symbols for negative values are the same as for positives, minus one. */
|
||||||
|
if (value < 0) {
|
||||||
|
if (sym.length2 > 0)
|
||||||
|
sym.part2 -= 1;
|
||||||
|
else
|
||||||
|
sym.part1 -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write out the full symbol. */
|
||||||
|
_write_bits(ctx, sym.part1, sym.length1);
|
||||||
|
if (sym.length2 > 0)
|
||||||
|
_write_bits(ctx, sym.part2, sym.length2);
|
||||||
|
|
||||||
|
/* Start counting zeroes again. */
|
||||||
|
num_zeroes = 0;
|
||||||
|
} else {
|
||||||
|
num_zeroes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write out EOB if necessary. */
|
||||||
|
if (num_zeroes > 0)
|
||||||
|
_write_bits(ctx, 0xA, 4);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "mimicwrapper.h"
|
||||||
|
|
||||||
|
#include "libmimic/mimic.h"
|
||||||
|
|
||||||
|
//#include <tqbytearray.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tqimage.h>
|
||||||
|
|
||||||
|
MimicWrapper::MimicWrapper() : m_init(false)
|
||||||
|
{
|
||||||
|
m_mimctx=mimic_open();
|
||||||
|
}
|
||||||
|
|
||||||
|
MimicWrapper::~MimicWrapper()
|
||||||
|
{
|
||||||
|
mimic_close(m_mimctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TQPixmap MimicWrapper::decode(const TQByteArray& data)
|
||||||
|
{
|
||||||
|
if(!m_init)
|
||||||
|
{
|
||||||
|
if(!mimic_decoder_init(m_mimctx, (guchar*)(data.data())))
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to init decoder" << endl;
|
||||||
|
return TQPixmap();
|
||||||
|
}
|
||||||
|
if (!mimic_get_property( m_mimctx, "buffer_size", &m_bufferSize) )
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to get buffer size" << endl;
|
||||||
|
return TQPixmap();
|
||||||
|
}
|
||||||
|
m_init=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray buff(m_bufferSize);
|
||||||
|
if(!mimic_decode_frame(m_mimctx, (guchar*)(data.data()) , (guchar*)(buff.data()) ) )
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to decode frame" << endl;
|
||||||
|
return TQPixmap();
|
||||||
|
}
|
||||||
|
int width,height;
|
||||||
|
mimic_get_property(m_mimctx, "width", &width);
|
||||||
|
mimic_get_property(m_mimctx, "height", &height);
|
||||||
|
|
||||||
|
|
||||||
|
TQByteArray buff2(m_bufferSize*4/3);
|
||||||
|
uint b2=0;
|
||||||
|
for(uint f=0;f<m_bufferSize;f+=3)
|
||||||
|
{
|
||||||
|
buff2[b2+0]=buff[f+2];
|
||||||
|
buff2[b2+1]=buff[f+1];
|
||||||
|
buff2[b2+2]=buff[f+0];
|
||||||
|
buff2[b2+3]=0x00;
|
||||||
|
b2+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQImage img( (uchar*)(buff2.data()) , width , height , 32 , 0L , 0, TQImage::BigEndian );
|
||||||
|
return TQPixmap(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray MimicWrapper::encode(const TQByteArray& data)
|
||||||
|
{
|
||||||
|
if(!m_init)
|
||||||
|
{
|
||||||
|
if(!mimic_encoder_init(m_mimctx, MIMIC_RES_HIGH))
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to init encoder" << endl;
|
||||||
|
return TQByteArray();
|
||||||
|
}
|
||||||
|
if (!mimic_get_property( m_mimctx, "buffer_size", &m_bufferSize) )
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to get buffer size" << endl;
|
||||||
|
return TQByteArray();
|
||||||
|
}
|
||||||
|
m_init=true;
|
||||||
|
m_numFrames=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQByteArray buff(m_bufferSize);
|
||||||
|
int buff_new_size;
|
||||||
|
if(!mimic_encode_frame(m_mimctx, (guchar*)(data.data()) , (guchar*)(buff.data()) , (gint*)(&buff_new_size) , m_numFrames%15==0 ) )
|
||||||
|
{
|
||||||
|
kdWarning(14140) << k_funcinfo << "Impossible to decode frame" << endl;
|
||||||
|
return TQByteArray();
|
||||||
|
}
|
||||||
|
buff.resize(buff_new_size);
|
||||||
|
++m_numFrames;
|
||||||
|
return buff;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart@ kde.org>
|
||||||
|
|
||||||
|
*************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIMICWRAPPER_H
|
||||||
|
#define MIMICWREPPER_H
|
||||||
|
|
||||||
|
#include <tqpixmap.h>
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
typedef struct _MimCtx MimCtx;
|
||||||
|
|
||||||
|
class KOPETE_EXPORT MimicWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MimicWrapper();
|
||||||
|
~MimicWrapper();
|
||||||
|
|
||||||
|
TQPixmap decode(const TQByteArray &data);
|
||||||
|
TQByteArray encode(const TQByteArray &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MimCtx *m_mimctx;
|
||||||
|
bool m_init;
|
||||||
|
uint m_bufferSize;
|
||||||
|
uint m_numFrames;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Kopete MSN Protocol
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart @kde.org>
|
||||||
|
|
||||||
|
Note: this is just YahooWebcamDialog with s/Yahoo/MSN/g
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Matt Rogers <mattr@kde.org>
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 "msnwebcamdialog.h"
|
||||||
|
|
||||||
|
#include <tqframe.h>
|
||||||
|
#include <tqobject.h>
|
||||||
|
#include <tqwidget.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <tdelocale.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MSNWebcamDialog::MSNWebcamDialog( const TQString& contact, TQWidget * parent, const char * name )
|
||||||
|
: KDialogBase( KDialogBase::Plain, i18n( "Webcam for %1" ).arg( contact ),
|
||||||
|
KDialogBase::Close, KDialogBase::Close, parent, name, false, true /*seperator*/ ),
|
||||||
|
m_imageContainer( this )
|
||||||
|
{
|
||||||
|
setInitialSize( TQSize(320,290), true );
|
||||||
|
|
||||||
|
setEscapeButton( KDialogBase::Close );
|
||||||
|
/*
|
||||||
|
TQObject::connect( contact, TQT_SIGNAL( signalReceivedWebcamImage( const TQPixmap& ) ),
|
||||||
|
this, TQT_SLOT( newImage( const TQPixmap& ) ) );
|
||||||
|
*/
|
||||||
|
TQObject::connect( this, TQT_SIGNAL( closeClicked() ), this, TQT_SIGNAL( closingWebcamDialog() ) );
|
||||||
|
/*
|
||||||
|
TQObject::connect( contact, TQT_SIGNAL( webcamClosed( int ) ), this, TQT_SLOT( webcamClosed( int ) ) );
|
||||||
|
*/
|
||||||
|
TQFrame* page = plainPage();
|
||||||
|
if ( page )
|
||||||
|
{
|
||||||
|
kdDebug(14180) << k_funcinfo << "Adding webcam image container" << endl;
|
||||||
|
//m_imageContainer.setText( i18n( "No webcam image received" ) );
|
||||||
|
//m_imageContainer.setAlignment( TQt::AlignCenter );
|
||||||
|
m_imageContainer.setMinimumSize(320,240);
|
||||||
|
}
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
MSNWebcamDialog::~ MSNWebcamDialog( )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSNWebcamDialog::newImage( const TQPixmap & image )
|
||||||
|
{
|
||||||
|
kdDebug(14180) << k_funcinfo << "New image received" << endl;
|
||||||
|
// kdDebug(14180) << image << endl;
|
||||||
|
//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( TQString::number( reason ) ) );
|
||||||
|
//m_imageContainer.setAlignment( TQt::AlignCenter );
|
||||||
|
//show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// kate: indent-mode csands; tab-width 4;
|
||||||
|
|
||||||
|
#include "msnwebcamdialog.moc"
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Kopete MSN Protocol
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Olivier Goffart <ogoffart @kde.org>
|
||||||
|
|
||||||
|
Note: this is just YahooWebcamDialog with s/Yahoo/MSN/g
|
||||||
|
|
||||||
|
Copyright (c) 2005 by Matt Rogers <mattr@kde.org>
|
||||||
|
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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 YAHOOWEBCAMDIALOG_H_
|
||||||
|
#define YAHOOWEBCAMDIALOG_H_
|
||||||
|
|
||||||
|
//#include <tqlabel.h>
|
||||||
|
#include <webcamwidget.h>
|
||||||
|
#include <kdialogbase.h>
|
||||||
|
|
||||||
|
#include "kopete_export.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TQPixmap;
|
||||||
|
class TQWidget;
|
||||||
|
class MSNContact;
|
||||||
|
|
||||||
|
class KOPETE_EXPORT MSNWebcamDialog : public KDialogBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MSNWebcamDialog( const TQString& contact, TQWidget* parent = 0, const char* name = 0 );
|
||||||
|
~MSNWebcamDialog();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void newImage( const TQPixmap& image );
|
||||||
|
void webcamClosed( int );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closingWebcamDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Kopete::WebcamWidget m_imageContainer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
//kate: indent-mode csands; auto-insert-doxygen on;
|