/*
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 <klocale.h>
# include <kserversocket.h>
# include <kmessagebox.h>
# include <tqlabel.h>
# include <tqguardedptr.h>
# include <tqtimer.h>
# include <tqevent.h>
# include <tqdatetime.h>
# include <kconfig.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 ;
KConfig * config = KGlobal : : 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 ;
KBufferedSocket * sock = new KBufferedSocket ( 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 ;
KBufferedSocket * sock = new KBufferedSocket ( 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 ;
KBufferedSocket * sock = new KBufferedSocket ( 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 < KBufferedSocket * > : : iterator it ;
for ( it = m_allSockets . begin ( ) ; it ! = m_allSockets . end ( ) ; + + it )
{
KBufferedSocket * 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 KServerSocket ( 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 ( )
{
KConfig * config = KGlobal : : 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
//
KServerSocket * ss = new KServerSocket ( ) ;
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 ( ) = = KSocketBase : : NoError ) )
break ;
ss - > close ( ) ;
}
delete ss ;
kdDebug ( 14140 ) < < k_funcinfo < < " found available port : " < < port < < endl ;
return port ;
}
/* ---------- Now functions about the dirrect connection --------- */
void Webcam : : slotSocketConnected ( )
{
kdDebug ( 14140 ) < < k_funcinfo < < " ########################## " < < endl ;
m_webcamSocket = const_cast < KBufferedSocket * > ( static_cast < const KBufferedSocket * > ( 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 < KBufferedSocket * > ( 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 < KBufferedSocket * > ( static_cast < const KBufferedSocket * > ( 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 ;
KBufferedSocket * m_webcamSocket = const_cast < KBufferedSocket * > ( static_cast < const KBufferedSocket * > ( 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 )
{
KBufferedSocket * socket = const_cast < KBufferedSocket * > ( static_cast < const KBufferedSocket * > ( sender ( ) ) ) ;
kdDebug ( 14140 ) < < k_funcinfo < < socket < < " - " < < errorCode < < " : " < < socket - > KSocketBase : : errorString ( ) < < endl ;
//sendBYEMessage();
}
void Webcam : : closeAllOtherSockets ( )
{
//m_lisener->close();
delete m_listener ;
m_listener = 0l ;
TQValueList < KBufferedSocket * > : : iterator it ;
for ( it = m_allSockets . begin ( ) ; it ! = m_allSockets . end ( ) ; + + it )
{
KBufferedSocket * 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