Bonjour nick name is in Latin1 encoding
[kdenetwork.git] / kopete / protocols / msn / webcam.cpp
blobe3bdfb403351c8028f319432372bb87a72551893
1 /*
2 Copyright (c) 2005 by Olivier Goffart <ogoffart@kde.org>
4 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
6 *************************************************************************
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 *************************************************************************
16 #include "webcam.h"
18 //#if MSN_WEBCAM
19 #if 0
21 #include <stdlib.h>
22 #include <kdebug.h>
23 #include <QRegExp>
24 #include <QPixmap>
25 #include <QByteArray>
26 #include <QTimerEvent>
28 #include <kconfig.h>
29 #include <kbufferedsocket.h>
30 #include <klocale.h>
31 #include <kserversocket.h>
32 #include <kmessagebox.h>
33 #include <qlabel.h>
34 #include <qpointer.h>
35 #include <qtimer.h>
36 #include <qevent.h>
37 #include <qdatetime.h>
39 #include "dispatcher.h"
41 #include "mimicwrapper.h"
42 #include "msnwebcamdialog.h"
45 #include "avdevice/videodevicepool.h"
47 using namespace KNetwork;
49 namespace P2P {
51 Webcam::Webcam(Who who, const QString& to, Dispatcher *parent, quint32 sessionId)
52 : TransferContext(to,parent,sessionId) , m_who(who) , m_timerId(0)
54 setType(P2P::WebcamType);
55 m_direction = Incoming;
56 m_listener = 0l;
57 m_webcamSocket=0L;
58 m_webcamState=wsNegotiating;
60 m_mimic=0L;
61 m_widget=0L;
63 KSharedConfig::Ptr config = KGlobal::config();
64 config->setGroup( "MSN" );
66 // Read the configuration to get the number of frame per second to send
67 int webCamFps=config->readNumEntry("WebcamFPS", 25);
68 m_timerFps = 1000 / webCamFps;
71 Webcam::~Webcam()
73 kDebug(14140) << "################################################";
74 m_dispatcher=0l;
75 delete m_mimic;
76 delete m_webcamSocket;
77 delete m_widget;
79 if(m_timerId != 0) //if we were sending
81 Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
82 videoDevice->stopCapturing();
83 videoDevice->close();
88 void Webcam::askIncommingInvitation()
90 m_direction = Incoming;
91 //protect, in case this is deleted when the messagebox is active
92 QPointer<Webcam> _this = this;
93 QString message= (m_who==wProducer) ?
94 i18n("<qt>The contact %1 wants to see <b>your</b> webcam, do you want them to see it?</qt>", m_recipient) :
95 i18n("The contact %1 wants to show you his/her webcam, do you want to see it?", m_recipient) ;
96 int result=KMessageBox::questionYesNo( 0L , message,
97 i18n("Webcam invitation - Kopete MSN Plugin") , i18n("Accept") , i18n("Decline"));
98 if(!_this)
99 return;
101 QString content = QString("SessionID: %1\r\n\r\n").arg(m_sessionId);
102 if(result==KMessageBox::Yes)
104 //Send two message, an OK, and an invite.
105 //Normaly, the user should decline the invite (i hope)
107 // Send a 200 OK message to the recipient.
108 sendMessage(OK, content);
111 //send an INVITE message we want the user decline
112 //need to change the branch of the second message
113 m_branch=Uid::createUid();
114 m_state = Negotiation; //set type to application/x-msnmsgr-transreqbody
116 content=QString("Bridges: TRUDPv1 TCPv1\r\n"
117 "NetID: -1280904111\r\n"
118 "Conn-Type: Firewall\r\n"
119 "UPnPNat: false\r\n"
120 "ICF: false\r\n\r\n");
122 sendMessage(INVITE, content);
125 else
127 //Decline the invitation
128 sendMessage(DECLINE, content);
129 m_state=Finished;
133 void Webcam::sendBYEMessage()
135 m_state=Finished;
136 QString content="Context: dAMAgQ==\r\n";
137 sendMessage(BYE,content);
139 //If ever the opposite client was dead or something, we'll ack anyway, so everything get cleaned
140 QTimer::singleShot(60*1000 , this, SLOT(acknowledged()));
145 void Webcam::acknowledged()
147 kDebug(14140) ;
149 switch(m_state)
151 case Invitation:
153 // m_state=Negotiation;
154 break;
158 case Negotiation:
160 if(m_type == UserDisplayIcon)
162 <<< Data preparation acknowledge message.
163 m_state = DataTransfer;
164 m_identifier++;
165 Start sending data.
166 slotSendData();
168 break;
171 case DataTransfer:
172 NOTE <<< Data acknowledged message.
173 <<< Bye message should follow.
174 if(m_type == File)
176 if(m_handshake == 0x01)
178 Data handshake acknowledge message.
179 Start sending data.
180 slotSendData();
182 else if(m_handshake == 0x02)
184 Data acknowledge message.
185 Send the recipient a BYE message.
186 m_state = Finished;
187 sendMessage(BYE, "\r\n");
191 break;
193 case Finished:
194 //BYE or DECLINE acknowledge message.
195 m_dispatcher->detach(this);
196 break;
197 default:
198 break;
205 void Webcam::processMessage(const Message& message)
207 if(message.header.dataOffset+message.header.dataSize >= message.header.totalDataSize)
208 acknowledge( message ); //aknowledge if needed
210 if(message.applicationIdentifier != 4l)
212 QString body = QByteArray(message.body.data(), message.header.dataSize);
213 kDebug(14141) << "received, " << body;
215 if(body.startsWith("MSNSLP/1.0 200 OK"))
217 m_direction = Outgoing;
219 if(body.startsWith("INVITE"))
221 if(m_direction == Outgoing)
223 QRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
224 regex.search(body);
225 m_branch=regex.cap(1);
226 //decline
227 sendMessage(DECLINE);
228 makeSIPMessage("syn",0x17,0x2a,0x01);
231 else if(body.startsWith("MSNSLP/1.0 603 DECLINE"))
233 //if it is the declinaison of the second invite message, we have to don't care
234 //TODO anyway, if it's the declinaison of our invitation, we have to something
236 else if(body.startsWith("BYE"))
238 m_state = Finished;
240 // Dispose of this transfer context.
241 m_dispatcher->detach(this);
243 return;
248 //Let's take the fun, we entering into the delicious webcam negotiation binary protocol
250 //well, there is maybe better to take utf16, but it's ascii, so no problem.
251 QByteArray dataMessage=message.body;
253 #if 0
254 QString echoS="";
255 unsigned int f=0;
256 while(f<dataMessage.size())
258 echoS+='\n';
259 for(unsigned int q=0; q<16 ; q++)
261 if(q+f<dataMessage.size())
263 unsigned int N=(unsigned int) (dataMessage[q+f]);
264 if(N<16)
265 echoS+='0';
266 echoS+=QString::number( N ,16)+' ';
268 else
269 echoS+=" ";
271 echoS+=" ";
273 for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
275 unsigned char X=dataMessage[q+f];
276 char C=((char)(( X<128 && X>31 ) ? X : '.'));
277 echoS+=QString::fromLatin1(&C,1);
279 f+=16;
281 kDebug(14141) << dataMessage.size() << echoS;
282 #endif
288 for(uint pos=m_content.isNull() ? 10 : 0; pos<dataMessage.size(); pos+=2)
290 if(dataMessage[pos])
291 m_content+=dataMessage[pos];
294 if(message.header.dataOffset+message.header.dataSize < message.header.totalDataSize)
295 return;
297 kDebug(14141) << "Message contents: " << m_content << '\n';
298 if(m_content.startsWith("syn"))
300 if(m_direction == Incoming)
301 makeSIPMessage("syn",0x17,0x2a,0x01);
302 else
303 makeSIPMessage("ack",0xea,0x00,0x00);
305 else if(m_content.startsWith("ack"))
307 if(m_direction == Incoming)
308 makeSIPMessage("ack",0xea,0x00,0x00);
310 if(m_who==wProducer)
312 uint sess=rand()%1000+5000;
313 uint rid=rand()%100+50;
314 m_myAuth=QString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid).arg(sess);
315 kDebug(14140) << "m_myAuth= " << m_myAuth;
316 QString producerxml=xml(sess , rid);
317 kDebug(14140) << "producerxml= " << producerxml;
318 makeSIPMessage(producerxml);
321 else if(m_content.contains("<producer>") || m_content.contains("<viewer>"))
323 QRegExp rx("<rid>([0-9]*)</rid>.*<session>([0-9]*)</session>");
324 rx.search(m_content);
325 QString rid=rx.cap(1);
326 QString sess=rx.cap(2);
327 if(m_content.contains("<producer>"))
330 QString viewerxml=xml(sess.toUInt() , rid.toUInt());
331 kDebug(14140) << "vewerxml= " << viewerxml;
332 makeSIPMessage( viewerxml ,0x00,0x09,0x00 );
333 m_peerAuth=m_myAuth=QString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
334 kDebug(14140) << "m_auth= " << m_myAuth;
336 else
338 m_peerAuth=QString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
340 makeSIPMessage("receivedViewerData", 0xec , 0xda , 0x03);
343 m_listener = new KServerSocket("7786",this);
344 //m_listener->setResolutionEnabled(true);
345 // Create the callback that will try to accept incoming connections.
346 QObject::connect(m_listener, SIGNAL(readyAccept()), this, SLOT(slotAccept()));
347 QObject::connect(m_listener, SIGNAL(gotError(int)), this, SLOT(slotListenError(int)));
348 // Listen for incoming connections.
349 bool isListening = m_listener->listen();
350 kDebug(14140) << (isListening ? QString("listening %1").arg(m_listener->localAddress().toString()) : QString("not listening"));
352 rx=QRegExp("<tcpport>([^<]*)</tcpport>");
353 rx.search(m_content);
354 QString port1=rx.cap(1);
355 if(port1=="0")
356 port1.clear();
358 rx=QRegExp("<tcplocalport>([^<]*)</tcplocalport>");
359 rx.search(m_content);
360 QString port2=rx.cap(1);
361 if(port2==port1 || port2=="0")
362 port2.clear();
364 rx=QRegExp("<tcpexternalport>([^<]*)</tcpexternalport>");
365 rx.search(m_content);
366 QString port3=rx.cap(1);
367 if(port3==port1 || port3==port2 || port3=="0")
368 port3.clear();
370 int an=0;
371 while(true)
373 an++;
374 if(!m_content.contains( QString("<tcpipaddress%1>").arg(an) ))
375 break;
376 rx=QRegExp(QString("<tcpipaddress%1>([^<]*)</tcpipaddress%2>").arg(an).arg(an));
377 rx.search(m_content);
378 QString ip=rx.cap(1);
379 if(ip.isEmpty())
380 continue;
382 if(!port1.isEmpty())
384 kDebug(14140) << "trying to connect on " << ip <<':' << port1;
385 KBufferedSocket *sock=new KBufferedSocket( ip, port1, this );
386 m_allSockets.append(sock);
387 QObject::connect( sock, SIGNAL( connected( const KResolverEntry&) ), this, SLOT( slotSocketConnected() ) );
388 QObject::connect( sock, SIGNAL( gotError(int)), this, SLOT(slotSocketError(int)));
389 sock->connect(ip, port1);
390 kDebug(14140) << "okok " << sock << " - " << sock->peerAddress().toString() << " ; " << sock->localAddress().toString();
392 if(!port2.isEmpty())
394 kDebug(14140) << "trying to connect on " << ip <<':' << port2;
395 KBufferedSocket *sock=new KBufferedSocket( ip, port2, this );
396 m_allSockets.append(sock);
397 QObject::connect( sock, SIGNAL( connected( const KResolverEntry&) ), this, SLOT( slotSocketConnected() ) );
398 QObject::connect( sock, SIGNAL( gotError(int)), this, SLOT(slotSocketError(int)));
399 sock->connect(ip, port2);
401 if(!port3.isEmpty())
403 kDebug(14140) << "trying to connect on " << ip <<':' << port3;
404 KBufferedSocket *sock=new KBufferedSocket( ip, port3, this );
405 m_allSockets.append(sock);
406 QObject::connect( sock, SIGNAL( connected( const KResolverEntry&) ), this, SLOT( slotSocketConnected() ) );
407 QObject::connect( sock, SIGNAL( gotError(int)), this, SLOT(slotSocketError(int)));
408 sock->connect(ip, port3);
411 QList<KBufferedSocket*>::iterator it;
412 for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
414 KBufferedSocket *sock=(*it);
416 //sock->enableRead( false );
417 kDebug(14140) << "connect to " << sock << " - "<< sock->peerAddress().toString() << " ; " << sock->localAddress().toString();
420 else if(m_content.contains("receivedViewerData"))
422 //I'm happy you received the xml i sent, really.
424 else
425 error();
426 m_content.clear();
429 void Webcam::makeSIPMessage(const QString &message, quint8 XX, quint8 YY , quint8 ZZ)
431 QByteArray dataMessage; //(12+message.length()*2);
432 QDataStream writer( &dataMessage,QIODevice::WriteOnly);
433 writer.setVersion(QDataStream::Qt_3_3);
434 writer.setByteOrder(QDataStream::LittleEndian);
435 writer << (quint8)0x80;
436 writer << (quint8)XX;
437 writer << (quint8)YY;
438 writer << (quint8)ZZ;
439 writer << (quint8)0x08;
440 writer << (quint8)0x00;
441 writer << message+'\0';
442 //writer << (quint16)0x0000;
444 /*QString echoS="";
445 unsigned int f=0;
446 while(f<dataMessage.size())
448 echoS+='\n';
449 for(unsigned int q=0; q<16 ; q++)
451 if(q+f<dataMessage.size())
453 unsigned int N=(unsigned int) (dataMessage[q+f]);
454 if(N<16)
455 echoS+='0';
456 echoS+=QString::number( N ,16)+' ';
458 else
459 echoS+=" ";
461 echoS+=" ";
463 for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
465 unsigned char X=dataMessage[q+f];
466 char C=((char)(( X<128 && X>31 ) ? X : '.'));
467 echoS+=QString::fromLatin1(&C,1);
469 f+=16;
471 kDebug(14141) << dataMessage.size() << echoS;*/
474 sendBigP2PMessage(dataMessage);
477 void Webcam::sendBigP2PMessage( const QByteArray & dataMessage)
479 unsigned int size=m_totalDataSize=dataMessage.size();
480 m_offset=0;
481 ++m_identifier;
483 for(unsigned int f=0;f<size;f+=1200)
485 m_offset=f;
486 QByteArray dm2;
487 unsigned int tempValue1, tempValue2;
488 tempValue1 = 1200;
489 tempValue2 = m_totalDataSize-m_offset;
490 dm2.duplicate(dataMessage.data()+m_offset, qMin(tempValue1,tempValue2));
491 sendData( dm2 );
492 m_offset+=dm2.size();
494 m_offset=0;
495 m_totalDataSize=0;
500 QString Webcam::xml(uint session , uint rid)
502 QString who= ( m_who == wProducer ) ? QString("producer") : QString("viewer");
504 QString ip;
506 uint ip_number=1;
507 QStringList::iterator it;
508 QStringList ips=m_dispatcher->localIp();
509 for ( it = ips.begin(); it != ips.end(); ++it )
511 ip+=QString("<tcpipaddress%1>%2</tcpipaddress%3>").arg(ip_number).arg(*it).arg(ip_number);
512 ++ip_number;
515 QString port = QString::number(getAvailablePort());
517 m_listener = new KServerSocket(port, this) ;
519 return '<' + who + "><version>2.0</version><rid>"+QString::number(rid)+"</rid><udprid>"+QString::number(rid+1)+"</udprid><session>"+QString::number(session)+"</session><ctypes>0</ctypes><cpu>2931</cpu>" +
520 "<tcp><tcpport>7786</tcpport>\t\t\t\t\t\t\t\t <tcplocalport>7786</tcplocalport>\t\t\t\t\t\t\t\t <tcpexternalport>7786</tcpexternalport>"+ip+"</tcp>"+
521 "<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>"+
522 "<codec></codec><channelmode>1</channelmode></"+who+">\r\n\r\n";
525 int Webcam::getAvailablePort()
527 KConfigGroup config = KGlobal::config()->group("MSN");
528 QString basePort=config.readEntry("WebcamPort");
529 if(basePort.isEmpty() || basePort == "0" )
530 basePort="6891";
532 uint firstport = basePort.toInt();
533 uint maxOffset=config.readEntry("WebcamMaxPortOffset", 10);
534 uint lastport = firstport + maxOffset;
536 // try to find an available port
538 KServerSocket *ss = new KServerSocket();
539 ss->setFamily(KResolver::InetFamily);
540 bool found = false;
541 unsigned int port = firstport;
542 for( ; port <= lastport; ++port) {
543 ss->setAddress( QString::number( port ) );
544 bool success = ss->listen();
545 if( found = ( success && ss->error() == KSocketBase::NoError ) )
546 break;
547 ss->close();
549 delete ss;
552 kDebug(14140) << "found available port : " << port;
554 return port;
558 /* ---------- Now functions about the dirrect connection --------- */
560 void Webcam::slotSocketConnected()
562 kDebug(14140) <<"##########################";
564 m_webcamSocket=const_cast<KBufferedSocket*>(static_cast<const KBufferedSocket*>(sender()));
565 if(!m_webcamSocket)
566 return;
568 delete m_listener;
569 m_listener=0L;
571 QList<KBufferedSocket*>::iterator it;
572 for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
574 KBufferedSocket *sock=(*it);
575 if(sock!=m_webcamSocket)
576 delete sock;
578 m_allSockets.clear();
580 kDebug(14140) << "Connection established on " << m_webcamSocket->peerAddress().toString() << " ; " << m_webcamSocket->localAddress().toString();
582 m_webcamSocket->setBlocking(false);
583 m_webcamSocket->enableRead(true);
584 m_webcamSocket->enableWrite(false);
586 // Create the callback that will try to read bytes from the accepted socket.
587 QObject::connect(m_webcamSocket, SIGNAL(readyRead()), this, SLOT(slotSocketRead()));
588 // Create the callback that will try to handle the socket close event.
589 QObject::connect(m_webcamSocket, SIGNAL(closed()), this, SLOT(slotSocketClosed()));
590 // Create the callback that will try to handle the socket error event.
591 // QObject::connect(m_webcamSocket, SIGNAL(gotError(int)), this, SLOT(slotSocketError(int)));
593 m_webcamState=wsConnected;
594 QByteArray to_send=m_peerAuth.toUtf8();
595 m_webcamSocket->write(to_send.data(), to_send.length());
596 kDebug(14140) << "sending "<< m_peerAuth;
601 void Webcam::slotAccept()
603 // Try to accept an incoming connection from the sending client.
604 m_webcamSocket = static_cast<KBufferedSocket*>(m_listener->accept());
605 if(!m_webcamSocket)
607 // NOTE If direct connection fails, the sending
608 // client wil transfer the file data through the
609 // existing session.
610 kDebug(14140) << "Direct connection failed.";
611 // Close the listening endpoint.
612 // m_listener->close();
613 return;
616 kDebug(14140) << "Direct connection established.";
618 // Set the socket to non blocking,
619 // enable the ready read signal and disable
620 // ready write signal.
621 // NOTE readyWrite consumes too much cpu usage.
622 m_webcamSocket->setBlocking(false);
623 m_webcamSocket->enableRead(true);
624 m_webcamSocket->enableWrite(false);
626 // Create the callback that will try to read bytes from the accepted socket.
627 QObject::connect(m_webcamSocket, SIGNAL(readyRead()), this, SLOT(slotSocketRead()));
628 // Create the callback that will try to handle the socket close event.
629 QObject::connect(m_webcamSocket, SIGNAL(closed()), this, SLOT(slotSocketClosed()));
630 // Create the callback that will try to handle the socket error event.
631 QObject::connect(m_webcamSocket, SIGNAL(gotError(int)), this, SLOT(slotSocketError(int)));
633 m_allSockets.append(m_webcamSocket);
636 void Webcam::slotSocketRead()
638 m_webcamSocket=const_cast<KBufferedSocket*>(static_cast<const KBufferedSocket*>(sender()));
640 uint available = m_webcamSocket->bytesAvailable();
641 kDebug(14140) << m_webcamSocket << "############# " << available << " bytes available.";
642 static const QString connected_str("connected\r\n\r\n");
643 switch(m_webcamState)
645 case wsNegotiating:
647 if(available < m_myAuth.length())
649 kDebug(14140) << "waiting more data ( " << available << " of " <<m_myAuth.length()<< " )";
650 break;
652 QByteArray buffer(available);
653 m_webcamSocket->read(buffer.data(), buffer.size());
655 kDebug(14140) << buffer.data();
657 if(QString(buffer) == m_myAuth )
659 closeAllOtherSockets();
660 kDebug(14140) << "Sending " << connected_str;
661 QByteArray conne=connected_str.toUtf8();
662 m_webcamSocket->write(conne.data(), conne.length());
663 m_webcamState=wsConnecting;
665 //SHOULD NOT BE THERE
666 m_mimic=new MimicWrapper();
667 if(m_who==wProducer)
669 Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
670 videoDevice->open();
671 videoDevice->setSize(320, 240);
672 videoDevice->startCapturing();
674 m_timerId=startTimer(1000);
675 kDebug(14140) << "new timer" << m_timerId;
677 m_widget=new MSNWebcamDialog(m_recipient);
678 connect(m_widget, SIGNAL( closingWebcamDialog() ) , this , SLOT(sendBYEMessage()));
681 else
683 kWarning(14140) << "Auth failed";
684 m_webcamSocket->disconnect();
685 m_webcamSocket->deleteLater();
686 m_allSockets.remove(m_webcamSocket);
687 m_webcamSocket=0l;
688 //sendBYEMessage();
690 break;
692 case wsConnecting:
693 case wsConnected:
695 if(available < connected_str.length())
697 kDebug(14140) << "waiting more data ( " << available << " of " <<connected_str.length()<< " )";
698 break;
700 QByteArray buffer(connected_str.length());
701 m_webcamSocket->read(buffer.data(), buffer.size());
703 // kDebug(14140) << "state " << m_webcamState << " received :" << QCString(buffer);
706 if(QString(buffer) == connected_str)
708 if(m_webcamState==wsConnected)
710 closeAllOtherSockets();
711 kDebug(14140) << "Sending " << connected_str;
712 QByteArray conne=connected_str.toUtf8();
713 m_webcamSocket->write(conne.data(), conne.length());
715 //SHOULD BE DONE IN ALL CASE
716 m_mimic=new MimicWrapper();
717 if(m_who==wProducer)
719 Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
720 videoDevice->open();
721 videoDevice->setSize(320, 240);
722 videoDevice->startCapturing();
724 m_timerId=startTimer(1000);
725 kDebug(14140) << "new timer" << m_timerId;
727 m_widget=new MSNWebcamDialog(m_recipient);
728 connect(m_widget, SIGNAL( closingWebcamDialog() ) , this , SLOT(sendBYEMessage()));
731 m_webcamState=wsTransfer;
734 else
736 kWarning(14140) << "Connecting failed";
737 m_webcamSocket->disconnect();
738 m_webcamSocket->deleteLater();
739 m_allSockets.remove(m_webcamSocket);
740 m_webcamSocket=0l;
742 break;
744 case wsTransfer:
746 if(m_who==wProducer)
748 kWarning(14140) << "data received when we are producer";
749 break;
751 if(available < 24)
753 kDebug(14140) << "waiting more data ( " << available << " of " <<24<< " )";
754 break;
756 QByteArray buffer(available);
757 m_webcamSocket->peek(buffer.data(), buffer.size());
759 quint32 paysize=(uchar)buffer[8] + ((uchar)buffer[9]<<8) + ((uchar)buffer[10]<<16) + ((uchar)buffer[11]<<24);
761 if(available < (paysize+24))
763 kDebug(14140) << "waiting more data ( " << available << " of " <<paysize<< " )";
764 break;
766 m_webcamSocket->read(buffer.data(), 24); //flush
767 buffer.resize(paysize);
768 m_webcamSocket->read(buffer.data(), buffer.size());
770 QPixmap pix=m_mimic->decode(buffer);
771 if(pix.isNull())
773 kWarning(14140) << "incorrect pixmap returned, better to stop everything";
774 m_webcamSocket->disconnect();
775 sendBYEMessage();
777 m_widget->newImage(pix);
778 break;
780 default:
781 break;
786 void Webcam::slotListenError(int errorCode)
788 kWarning(14140) << "Error " << errorCode << " : " << m_listener->errorString();
791 void Webcam::slotSocketClosed()
793 if(!m_dispatcher) //we are in this destructor
794 return;
795 kDebug(14140) ;
796 sendBYEMessage();
799 void Webcam::slotSocketError(int errorCode)
801 kDebug(14140) << errorCode;
802 //sendBYEMessage();
805 void Webcam::closeAllOtherSockets()
807 //m_lisener->close();
808 delete m_listener;
809 m_listener=0l;
811 QList<KBufferedSocket*>::iterator it;
812 for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
814 KBufferedSocket *sock=(*it);
815 delete sock;
817 m_allSockets.clear();
821 void Webcam::timerEvent( QTimerEvent *e )
823 if(e->timerId() != m_timerId)
824 return TransferContext::timerEvent(e);
826 // kDebug(14140) ;
828 Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
829 videoDevice->getFrame();
830 QImage img;
831 videoDevice->getImage(&img);
833 if(m_widget)
834 m_widget->newImage(QPixmap::fromImage(img.mirrored(VideoDevice->getImageAsMirror(),false)));
836 if(img.width()!=320 || img.height()!=240)
838 kWarning(14140) << "Bad image size " <<img.width() << 'x' << img.height();
839 return;
842 uchar *bits=img.bits();
843 QByteArray image_data(img.width()*img.height()*3);
844 uint b2=0;
845 uint imgsize=img.width()*img.height()*4;
846 for(uint f=0; f< imgsize; f+=4)
848 image_data[b2+0]=bits[f+2];
849 image_data[b2+1]=bits[f+1];
850 image_data[b2+2]=bits[f+0];
851 b2+=3;
854 QByteArray frame=m_mimic->encode(image_data);
857 kDebug(14140) << "Sendinf frame of size " << frame.size();
858 //build the header.
859 QByteArray header;
861 QDataStream writer( &header,QIODevice::WriteOnly);
862 writer.setVersion(QDataStream::Qt_3_3);
863 writer.setByteOrder(QDataStream::LittleEndian);
864 writer << (quint16)24; // header size
865 writer << (quint16)img.width();
866 writer << (quint16)img.height();
867 writer << (quint16)0x0000; //wtf .?
868 writer << (quint32)frame.size();
869 writer << (quint8)('M') << (quint8)('L') << (quint8)('2') << (quint8)('0');
870 writer << (quint32)0x00000000; //wtf .?
871 writer << QTime::currentTime(); //FIXME: possible midnight bug ?
873 m_webcamSocket->write(header.data(), header.size());
874 m_webcamSocket->write(frame.data(), frame.size());
881 #include "webcam.moc"
883 #endif