summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/jabber/jingle
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/protocols/jabber/jingle
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/protocols/jabber/jingle')
-rw-r--r--kopete/protocols/jabber/jingle/DESIGN121
-rw-r--r--kopete/protocols/jabber/jingle/Makefile.am28
-rw-r--r--kopete/protocols/jabber/jingle/configure.in.bot16
-rw-r--r--kopete/protocols/jabber/jingle/configure.in.in87
-rw-r--r--kopete/protocols/jabber/jingle/jinglesession.cpp72
-rw-r--r--kopete/protocols/jabber/jingle/jinglesession.h94
-rw-r--r--kopete/protocols/jabber/jingle/jinglesessionmanager.cpp205
-rw-r--r--kopete/protocols/jabber/jingle/jinglesessionmanager.h89
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicecaller.cpp376
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicecaller.h72
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicesession.cpp333
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicesession.h70
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp208
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h66
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui369
-rw-r--r--kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp75
-rw-r--r--kopete/protocols/jabber/jingle/jinglewatchsessiontask.h39
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/AUTHORS1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/COPYING25
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/ChangeLog4
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/INSTALL229
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/Makefile.am4
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/NEWS1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/README59
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/libjingle.pro142
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am62
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h56
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc83
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h91
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc197
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h68
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc83
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h59
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc194
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h29
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h53
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc165
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h71
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/common.h231
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h120
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc99
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/host.h59
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc77
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h47
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h138
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h222
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h45
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c256
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc321
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h164
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc382
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/network.h136
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc1117
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h52
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h259
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h2700
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h158
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc1130
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h181
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc267
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h154
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc58
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h58
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h50
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h53
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h266
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc238
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/task.h186
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc92
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h64
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc273
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h141
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h101
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am16
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro19
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc62
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc390
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h88
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc196
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h82
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc148
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h46
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc172
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h44
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h213
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am15
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc93
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h71
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc144
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h57
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am47
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h118
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc129
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h51
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc910
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h164
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc869
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h367
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h91
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc640
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h93
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc657
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h210
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro14
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc75
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc421
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h140
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h42
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h94
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc173
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h86
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h133
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc273
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h101
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc576
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h364
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc171
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h72
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc198
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h126
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc160
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro14
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc66
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc250
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h116
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc117
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am11
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc667
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h172
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc545
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h104
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc149
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am3
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am18
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc119
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc258
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h97
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc203
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc170
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h75
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h55
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h95
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc267
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h122
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc331
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h69
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc331
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h129
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h72
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h111
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am92
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms34
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README3
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h43
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c640
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h50
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c343
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h171
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c301
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c574
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h130
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c342
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c132
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h65
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c124
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h64
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h64
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h61
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h64
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h74
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c130
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h66
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c99
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h87
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h90
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c94
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h75
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c250
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h67
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c96
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h61
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c94
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h61
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c168
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c537
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h201
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c194
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h72
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c244
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h84
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c82
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h60
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c148
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h77
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c247
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h78
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c91
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h60
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c56
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h49
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c182
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c246
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c163
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c211
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h64
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c39
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c39
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c218
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h69
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c192
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h66
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c193
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h136
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c114
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h68
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h55
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h62
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h61
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h96
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h74
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c121
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h63
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c495
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h47
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c315
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h35
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c209
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h143
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h111
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am18
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc167
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h87
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc151
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h79
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc65
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h61
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc491
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h231
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc205
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h62
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc250
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h108
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc190
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h49
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am34
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc331
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h300
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc477
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h144
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h80
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h85
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h67
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h59
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc68
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h74
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h65
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc372
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h157
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h94
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h332
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc480
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h262
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc279
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc357
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h95
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h163
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc104
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h96
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc168
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h113
-rw-r--r--kopete/protocols/jabber/jingle/voicecaller.h96
301 files changed, 48184 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jingle/DESIGN b/kopete/protocols/jabber/jingle/DESIGN
new file mode 100644
index 00000000..b1cbd666
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/DESIGN
@@ -0,0 +1,121 @@
+Voice Use cases:
+----------------
+
+In JabberAccount:
+-Account is connected:
+* Init the JingleSessionManager (accessible via account()->jingleSessionManager())
+* Add voice extension to client features.
+* Connect to incomingSession(const QString &sessionType, JingleSession *session) signal in JabberAccount.
+
+-On incoming session
+* Create and show VoiceConversationDialog.
+* VoiceConversationDialog will handle the communcation between the user and the session.
+
+In JabberContact:
+-User select "Start voice conversation..."
+* Get the best resource that support voice. If no compatible resource is found, show a message box.
+* Create a JingleVoiceSession using JingleVoiceSessionManager.
+* Create VoiceConversationDialog
+* and VoiceConversationDialog will handle the communication between the user and the session.
+
+In VoiceConversationDialog:
+-Incoming voice session
+* Accept the session call JingleVoiceSession::accept();
+* Decline the session call JingleVoiceSession::decline();
+
+-Accepted voice session
+* Change GUI to "Voice session in progress."
+
+-On declining voice session or terminating a session.
+* Remove JingleVoiceSession from JingleVoiceSessionManager.
+* Close the dialog.
+
+===================================================================================================
+Design with future in mind. Only voice session type is available today, but others will come.
+
+A session is a connection between two or multiple peers.
+A session do not handle multiple "calls"(or whatever it called depending of the context). That's will be job of SessionManager
+A sesson has a myself user and others users, all identified by their full JID. (maybe their JabberBaseContact or JabberResource object ?)
+
+-Maybe use the Channel pattern, where Session will hold one or multiple Channels. Think for voice+video for example. ?
+
+All manager classes must be unique for each account.
+
+JidList = QValueList<XMPP::Jid> or QStringList if QValueList<XMPP::Jid> doesn't work.
+
+JingleSession and derivated are created by the Manager class.
+
+SessionType is the XML Namespace of the session type (ex: http://jabber.org/protocol/sessions/audio)
+
+JingleSessionManager
+--------------------
+Manage Jingle sessions.
+-Manage global (maybe static ?)objects shared by all sessions (cricket::BasicPortAllocator, cricket::SessionManager).
+
+Has a JingleWatchSessionTask(derived from XMPP::Task) that check for incoming session in JingleSessionManager, that check the session type,
+create the right JingleSession subclass, then emit the required signal. This bypass libjingle to have a better
+control on incoming session request and avoid using multiple Manager for each session type.
+
+JingleSessionManager manage the JingleSession pointers. Do not delete it in user classes.
+
+* JingleSessionManager(JabberAccount *)
+
+* public slots:
+* JingleSession *createSession(const QString &sessionType, const JidList &peers);
+* void removeSession(JingleSession *);
+
+signals:
+* void incomingSession(const QString &sessionType, JingleSession *session);
+
+JingleSession
+-------------
+Base class for Jingle session. A session is a
+
+* JingleSession(JingleSessionManager *manager, const JidList &peers);
+
+* XMPP::Jid &myself(); // account()->client()->jid();
+* JidList &peers();
+* JabberAccount *account();
+* JingleSessionManager *manager();
+
+// Start the negociation phase.
+* virtual void start() = 0;
+// Send the IQ stanza with action "accept"
+* virtual void accept() = 0;
+// Send the IQ stanza with action "
+* virtual void decline() = 0;
+* virtual void terminate() = 0;
+
+// Return Session XML namespace
+* virtual QString sessionType() = 0;
+
+protected slots:
+ void sendStanza(const QString &stanza) { account()->client->send(stanza);
+
+signals:
+ void accepted();
+ void declined();
+ void terminated();
+
+JingleVoiceSession : public JingleSession
+------------------
+Define a VoIP voice session between two peers(for the moment).
+Hold the PhoneSessionClient object.
+
+connect(account()->client(),SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&)));
+
+
+private slots:
+ void receiveStanza(const QString &stanza);
+
+VoiceConversationDialog
+-----------------------
+* VoiceConversationDialog(JingleVoiceSession *)
+VoiceConversationDialog will handle the communcation between the user and a session.
+Should auto-delete when closed.
+It can:
+-Accept a voice session.
+-Decline a voice session.
+-Terminate a voice session(or hang-up).
+
+It is the Action menu that can start a session.
diff --git a/kopete/protocols/jabber/jingle/Makefile.am b/kopete/protocols/jabber/jingle/Makefile.am
new file mode 100644
index 00000000..553be0d7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/Makefile.am
@@ -0,0 +1,28 @@
+SUBDIRS = libjingle
+METASOURCES = AUTO
+AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+ -I$(srcdir)/../libiris/iris/include \
+ -I$(srcdir)/../libiris/iris/xmpp-im \
+ -I$(srcdir)/../libiris/iris/jabber \
+ -I$(srcdir)/../libiris/qca/src \
+ -I$(srcdir)/../libiris/cutestuff/util \
+ -I$(srcdir)/libjingle \
+ -I$(srcdir)/.. \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libkopetejabberjingle.la
+
+# libkopetejabberjingle_la_SOURCES = jinglevoicecaller.cpp \
+# jinglewatchsessiontask.cpp jinglesession.cpp jinglevoicesession.cpp jinglesessionmanager.cpp \
+# jinglevoicesessiondialogbase.ui jinglevoicesessiondialog.cpp
+
+libkopetejabberjingle_la_SOURCES = jinglevoicecaller.cpp jinglevoicesessiondialogbase.ui jinglevoicesessiondialog.cpp
+
+libkopetejabberjingle_la_LIBADD = libjingle/talk/session/phone/libcricketsessionphone.la \
+ libjingle/talk/p2p/client/libcricketp2pclient.la \
+ libjingle/talk/p2p/base/libcricketp2pbase.la \
+ libjingle/talk/xmpp/libcricketxmpp.la \
+ libjingle/talk/xmllite/libcricketxmllite.la \
+ libjingle/talk/base/libcricketbase.la \
+ libjingle/talk/third_party/mediastreamer/libmediastreamer.la \
+ $(EXPAT_LIBS) $(ORTP_LIBS) -lpthread $(ILBC_LIBS) $(SPEEX_LIBS) $(GLIB_LIBS) $(ALSA_LIBS)
diff --git a/kopete/protocols/jabber/jingle/configure.in.bot b/kopete/protocols/jabber/jingle/configure.in.bot
new file mode 100644
index 00000000..f30595e6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/configure.in.bot
@@ -0,0 +1,16 @@
+if test "$with_jingle" = yes; then
+ echo ""
+ echo Supported Jabber Jingle voice Codecs for Kopete:
+ echo Speex: $speex_found
+ echo iLBC: $ilbc_found
+ echo MULAW: yes
+else
+ echo ""
+ echo "You have disabled Jabber Jingle voice support or you are missing required libraries required to compile it."
+ echo "Jingle is a new Jabber standard that define a signaling protocol via XMPP for peer-to-peer applications."
+ echo "Jingle audio is compatible with the Google Talk voice service."
+ echo ""
+ echo "Required Jingle dependencies are listed on this page:"
+ echo "http://wiki.kde.org/tiki-index.php?page=Kopete+Jabber+Jingle"
+ all_tests=bad
+fi
diff --git a/kopete/protocols/jabber/jingle/configure.in.in b/kopete/protocols/jabber/jingle/configure.in.in
new file mode 100644
index 00000000..ee4db3fa
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/configure.in.in
@@ -0,0 +1,87 @@
+AC_DEFINE(PRODUCTION_BUILD, 1, [Build as a production build])
+AC_DEFINE(PRODUCTION, 1, [Build as a production build])
+AC_DEFINE(POSIX, 1, [If we're using configure, we're on POSIX])
+
+# Check if the user want Jabber Jingle voice support
+AC_ARG_ENABLE(jingle, [ --enable-jingle enable Jabber Jingle voice support ], with_jingle=$enableval, with_jingle=no)
+
+# Here we go
+HAVE_EXPAT=no
+AC_CHECK_LIB(expat, XML_ParserCreate, HAVE_EXPAT="yes")
+if test "x$HAVE_EXPAT" = xyes ; then
+ EXPAT_LIBS="-lexpat"
+ AC_SUBST(EXPAT_LIBS)
+else
+ with_jingle=no
+ AC_MSG_WARN([Expat is required to build Jabber Jingle voice support. You can get it from http://expat.sourceforge.net/])
+fi
+
+AC_CHECK_HEADERS(alsa/asoundlib.h,
+ [AC_CHECK_LIB(asound, snd_pcm_open,
+ [ALSA_LIBS="-lasound" ; AC_DEFINE(__ALSA_ENABLED__,1,[Defined when alsa support is enabled]) ])
+ ]
+)
+AC_SUBST(ALSA_LIBS)
+
+# We test for GLIB in protocols/configure.in.in
+if test x$have_glib = xno; then
+ with_jingle=no
+fi
+
+PKG_CHECK_MODULES(ORTP, ortp, enable_ortp=yes, enable_ortp=no)
+if test x$enable_ortp = xno ; then
+ with_jingle=no
+ AC_MSG_WARN([oRTP is required to build Jabber Jingle voice support. You can get it from http://www.linphone.org/ortp/])
+fi
+AC_SUBST(ORTP_CFLAGS)
+AC_SUBST(ORTP_LIBS)
+
+AC_ARG_WITH( speex,
+ [ --with-speex Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ],
+ [ speex_prefix=${withval}],[ speex_prefix="/usr" ])
+
+PKG_CHECK_MODULES(SPEEX, speex, speex_found=yes, speex_found=no)
+AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)],speex_found=no)
+AC_CHECK_HEADERS(speex/speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)],speex_found=no)
+
+if test x$speex_found = xno; then
+ AC_MSG_WARN([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6 from http://www.speex.org/])
+else
+ SPEEX_CFLAGS="$SPEEX_CFLAGS -I${speex_prefix}/include -I${speex_prefix}/include/speex"
+ AC_SUBST(SPEEX_CFLAGS)
+ AC_SUBST(SPEEX_LIBS)
+ AC_DEFINE(HAVE_SPEEX,1,[Speex codec is enabled])
+fi
+
+
+# dnl only accept speex>=1.1.6 or 1.0.5 (the versions that have speex_encode_int )
+# AC_ARG_WITH( speex,
+# [ --with-speex Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ],
+# [ speex_prefix=${withval}],[ speex_prefix="/usr" ])
+#
+# AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)
+# ],speex_found=no)
+#
+# if test "$speex_found" = "no" ; then
+# AC_MSG_WARN([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6 from http://www.speex.org/])
+# else
+# SPEEX_CFLAGS=" -I${speex_prefix}/include -I${speex_prefix}/include/speex"
+# SPEEX_LIBS="-L${speex_prefix}/lib -lspeex -lm"
+# CPPFLAGS_save=$CPPFLAGS
+# CPPFLAGS=$SPEEX_CFLAGS
+# LDFLAGS_save=$LDFLAGS
+# LDFLAGS=$SPEEX_LIBS
+# AC_DEFINE(HAVE_SPEEX,1,[has speex])
+# fi
+#
+# AC_SUBST(SPEEX_CFLAGS)
+# AC_SUBST(SPEEX_LIBS)
+# CPPFLAGS=$CPPFLAGS_save
+# LDFLAGS=$LDFLAGS_save
+ilbc_found="no"
+
+AM_CONDITIONAL(include_jingle, test "$with_jingle" = "yes")
+
+if test "$with_jingle" = "yes" ; then
+ AC_DEFINE(SUPPORT_JINGLE,1,[Jingle support is enabled])
+fi
diff --git a/kopete/protocols/jabber/jingle/jinglesession.cpp b/kopete/protocols/jabber/jingle/jinglesession.cpp
new file mode 100644
index 00000000..6c370fca
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglesession.cpp
@@ -0,0 +1,72 @@
+/*
+ jinglesession.h - Define a Jingle session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 "jinglesession.h"
+
+#include <kdebug.h>
+
+#include "jabberaccount.h"
+#include "jabberprotocol.h"
+
+class JingleSession::Private
+{
+public:
+ Private(JabberAccount *t_account, const JidList &t_peers)
+ : peers(t_peers), account(t_account)
+ {}
+
+ XMPP::Jid myself;
+ JidList peers;
+ JabberAccount *account;
+};
+
+JingleSession::JingleSession(JabberAccount *account, const JidList &peers)
+ : QObject(account, 0), d(new Private(account, peers))
+{
+ d->myself = account->client()->jid();
+}
+
+JingleSession::~JingleSession()
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
+ delete d;
+}
+
+const XMPP::Jid &JingleSession::myself() const
+{
+ return d->myself;
+}
+
+const JingleSession::JidList &JingleSession::peers() const
+{
+ return d->peers;
+}
+
+JingleSession::JidList &JingleSession::peers()
+{
+ return d->peers;
+}
+JabberAccount *JingleSession::account()
+{
+ return d->account;
+}
+
+void JingleSession::sendStanza(const QString &stanza)
+{
+ account()->client()->send( stanza );
+}
+
+#include "jinglesession.moc"
diff --git a/kopete/protocols/jabber/jingle/jinglesession.h b/kopete/protocols/jabber/jingle/jinglesession.h
new file mode 100644
index 00000000..00c192bd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglesession.h
@@ -0,0 +1,94 @@
+/*
+ jinglesession.h - Define a Jingle session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 JINGLESESSION_H
+#define JINGLESESSION_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include <xmpp.h> // XMPP::Jid
+#include <qvaluelist.h>
+
+class JabberAccount;
+/**
+ * @brief Base class for peer-to-peer session that use Jingle signaling
+ *
+ * @author Michaël Larouche <michael.larouche@kdemail.net>
+ */
+class JingleSession : public QObject
+{
+ Q_OBJECT
+public:
+ typedef QValueList<XMPP::Jid> JidList;
+
+ JingleSession(JabberAccount *account, const JidList &peers);
+ virtual ~JingleSession();
+
+ /**
+ * Return the JabberAccount associated with this session.
+ */
+ JabberAccount *account();
+
+ const XMPP::Jid &myself() const;
+ const JidList &peers() const;
+ JidList &peers();
+
+ /**
+ * Return the type of session(ex: voice, video, games)
+ * Note that you must return the XML namespace that define
+ * the session: ex:(http://jabber.org/protocol/jingle/sessions/audio)
+ */
+ virtual QString sessionType() = 0;
+
+public slots:
+ /**
+ * @brief Start a session with the give JID.
+ * You should begin the negociation here.
+ */
+ virtual void start() = 0;
+ /**
+ * @brief Acept a session request.
+ */
+ virtual void accept() = 0;
+ /**
+ * @brief Decline a session request.
+ */
+ virtual void decline() = 0;
+ /**
+ * @brief Terminate a Jingle session.
+ */
+ virtual void terminate() = 0;
+
+protected slots:
+ void sendStanza(const QString &stanza);
+
+signals:
+ /**
+ * Session is started(negocation and connection test are done).
+ */
+ void sessionStarted();
+
+ void accepted();
+ void declined();
+ void terminated();
+
+private:
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/jinglesessionmanager.cpp b/kopete/protocols/jabber/jingle/jinglesessionmanager.cpp
new file mode 100644
index 00000000..aeec2889
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglesessionmanager.cpp
@@ -0,0 +1,205 @@
+/*
+ jinglesessionmanager.cpp - Manage Jingle sessions.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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. *
+ * *
+ *************************************************************************
+*/
+// libjingle before everything else to not clash with Qt
+#define POSIX
+#include "talk/xmpp/constants.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/base/network.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/p2p/client/basicportallocator.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/thread.h"
+#include "talk/base/socketaddress.h"
+#include "talk/session/phone/call.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/session/sessionsendtask.h"
+
+
+#include "jinglesessionmanager.h"
+
+//#include "jinglesession.h"
+#include "jinglevoicesession.h"
+
+#include "jinglewatchsessiontask.h"
+
+#include "jabberaccount.h"
+#include "jabberprotocol.h"
+
+#include <kdebug.h>
+
+#define JINGLE_NS "http://www.google.com/session"
+#define JINGLE_VOICE_SESSION_NS "http://www.google.com/session/phone"
+
+//BEGIN JingleSessionManager::SlotsProxy
+class JingleSessionManager;
+class JingleSessionManager::SlotsProxy : public sigslot::has_slots<>
+{
+public:
+ SlotsProxy(JingleSessionManager *parent)
+ : sessionManager(parent)
+ {}
+
+ void OnSignalingRequest()
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Requesting Jingle signaling." << endl;
+ sessionManager->cricketSessionManager()->OnSignalingReady();
+ }
+
+
+private:
+ JingleSessionManager *sessionManager;
+};
+
+//END JingleSessionManager::SlotsProxy
+
+//BEGIN JingleSessionManager::Private
+class JingeSession;
+class JingleSessionManager::Private
+{
+public:
+ Private(JabberAccount *t_account)
+ : account(t_account), watchSessionTask(0L)
+ {}
+
+ ~Private()
+ {
+ delete networkManager;
+ delete portAllocator;
+ delete sessionThread;
+ delete cricketSessionManager;
+ }
+
+ JabberAccount *account;
+ QValueList<JingleSession*> sessionList;
+ JingleWatchSessionTask *watchSessionTask;
+
+ cricket::NetworkManager *networkManager;
+ cricket::BasicPortAllocator *portAllocator;
+ cricket::Thread *sessionThread;
+ cricket::SessionManager *cricketSessionManager;
+};
+//END JingleSessionManager::Private
+
+JingleSessionManager::JingleSessionManager(JabberAccount *account)
+ : QObject(account, 0), d(new Private(account))
+{
+ // Create slots proxy for libjingle
+ slotsProxy = new SlotsProxy(this);
+
+ // Create watch incoming session task.
+ d->watchSessionTask = new JingleWatchSessionTask(account->client()->rootTask());
+ connect(d->watchSessionTask, SIGNAL(watchSession(const QString &, const QString &)), this, SLOT(slotIncomingSession(const QString &, const QString &)));
+
+ // Create global cricket variables common to all sessions.
+ // Seed random generation with the JID of the account.
+ QString accountJid = account->client()->jid().full();
+ cricket::InitRandom( accountJid.ascii(), accountJid.length() );
+
+ // Create the libjingle NetworkManager that manager local network connections
+ d->networkManager = new cricket::NetworkManager();
+
+ // Init the port allocator(select best ports) with the Google STUN server to help.
+ cricket::SocketAddress *googleStunAddress = new cricket::SocketAddress("64.233.167.126", 19302);
+ // TODO: Define a relay server.
+ d->portAllocator = new cricket::BasicPortAllocator(d->networkManager, googleStunAddress, 0L);
+
+ // Create the Session manager that manager peer-to-peer sessions.
+ d->sessionThread = new cricket::Thread();
+ d->cricketSessionManager = new cricket::SessionManager(d->portAllocator, d->sessionThread);
+ d->cricketSessionManager->SignalRequestSignaling.connect(slotsProxy, &JingleSessionManager::SlotsProxy::OnSignalingRequest);
+ d->cricketSessionManager->OnSignalingReady();
+
+ d->sessionThread->Start();
+}
+
+JingleSessionManager::~JingleSessionManager()
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
+
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Cleaning up Jingle sessions." << endl;
+ QValueList<JingleSession*>::Iterator it, itEnd = d->sessionList.end();
+ for(it = d->sessionList.begin(); it != itEnd; ++it)
+ {
+ JingleSession *deletedSession = *it;
+ if( deletedSession )
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "deleting a session." << endl;
+ delete deletedSession;
+ }
+ }
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Done Cleaning up Jingle sessions." << endl;
+
+ delete d;
+}
+
+cricket::SessionManager *JingleSessionManager::cricketSessionManager()
+{
+ return d->cricketSessionManager;
+}
+
+JabberAccount *JingleSessionManager::account()
+{
+ return d->account;
+}
+
+JingleSession *JingleSessionManager::createSession(const QString &sessionType, const JidList &peers)
+{
+ JingleSession *newSession = 0L;
+
+ if(sessionType == JINGLE_VOICE_SESSION_NS)
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Creating a voice session" << endl;
+ newSession = new JingleVoiceSession(account(), peers);
+ }
+
+ if(newSession)
+ d->sessionList.append(newSession);
+
+ return newSession;
+}
+
+JingleSession *JingleSessionManager::createSession(const QString &sessionType, const XMPP::Jid &user)
+{
+ JingleSessionManager::JidList jidList;
+ jidList.append(user);
+
+ return createSession(sessionType, jidList);
+}
+
+void JingleSessionManager::removeSession(JingleSession *session)
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing a jingle session." << endl;
+
+ d->sessionList.remove(session);
+ delete session;
+}
+
+void JingleSessionManager::slotIncomingSession(const QString &sessionType, const QString &initiator)
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Incoming session: " << sessionType << ". Initiator: " << initiator << endl;
+
+ JingleSession *newSession = createSession(sessionType, XMPP::Jid(initiator));
+ emit incomingSession(sessionType, newSession);
+}
+
+#include "jinglesessionmanager.moc"
diff --git a/kopete/protocols/jabber/jingle/jinglesessionmanager.h b/kopete/protocols/jabber/jingle/jinglesessionmanager.h
new file mode 100644
index 00000000..06951c2f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglesessionmanager.h
@@ -0,0 +1,89 @@
+/*
+ jinglesessionmanager.h - Manage Jingle sessions.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 JINGLESESSIONMANAGER_H
+#define JINGLESESSIONMANAGER_H
+
+#include <xmpp.h>
+#include <im.h>
+
+#include <qobject.h>
+#include <qvaluelist.h>
+
+namespace cricket
+{
+ class SessionManager;
+}
+
+class JingleSession;
+class JingleVoiceSession;
+class JabberAccount;
+
+/**
+ * @brief Manage Jingle sessions.
+ * @author Michaël Larouche <michael.larouche@kdemail.net>
+ */
+class JingleSessionManager : public QObject
+{
+ Q_OBJECT
+public:
+ typedef QValueList<XMPP::Jid> JidList;
+
+ JingleSessionManager(JabberAccount *account);
+ ~JingleSessionManager();
+
+ /**
+ * Get the (single) instance of the cricket session manager.
+ */
+ cricket::SessionManager *cricketSessionManager();
+
+ /**
+ * Return the JabberAccount associated with this session manager.
+ */
+ JabberAccount *account();
+
+public slots:
+ /**
+ * Create a new Jingle session. Returned pointer is managed by this class.
+ * @param sessionType the session you want to create. You must pass its XML namespace(ex: http://jabber.org/protocol/sessions/audio)
+ * @param peers Lists of participants of the session.
+ */
+ JingleSession *createSession(const QString &sessionType, const JidList &peers);
+ /**
+ * Override method that create a session for a one-to-one session.
+ * It behave like createSession method.
+ * @param sessionType the sesion you want to create. You must pass its XML namespace(ex: http://jabber.org/protocol/sessions/audio)
+ * @param user The JID of the user you want to begin a session with.
+ */
+ JingleSession *createSession(const QString &sessionType, const XMPP::Jid &user);
+
+ void removeSession(JingleSession *session);
+
+signals:
+ void incomingSession(const QString &sessionType, JingleSession *session);
+
+private slots:
+ void slotIncomingSession(const QString &sessionType, const QString &initiator);
+
+private:
+ class Private;
+ Private *d;
+
+ class SlotsProxy;
+ SlotsProxy *slotsProxy;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp b/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp
new file mode 100644
index 00000000..3ad6a89a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp
@@ -0,0 +1,376 @@
+
+#define POSIX //FIXME
+#include "talk/xmpp/constants.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/base/network.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/p2p/client/basicportallocator.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/thread.h"
+#include "talk/base/socketaddress.h"
+#include "talk/session/phone/call.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/session/sessionsendtask.h"
+
+
+
+#include <qstring.h>
+#include <qdom.h>
+
+
+
+#include "im.h"
+#include "xmpp.h"
+#include "xmpp_xmlcommon.h"
+#include "jinglevoicecaller.h"
+#include "jabberprotocol.h"
+
+// Should change in the future
+#define JINGLE_NS "http://www.google.com/session"
+
+#include "jabberaccount.h"
+#include <kdebug.h>
+#define qDebug( X ) kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << X << endl
+#define qWarning( X ) kdWarning() <<k_funcinfo<< X << endl
+
+// ----------------------------------------------------------------------------
+
+class JingleIQResponder : public XMPP::Task
+{
+public:
+ JingleIQResponder(XMPP::Task *);
+ ~JingleIQResponder();
+
+ bool take(const QDomElement &);
+};
+
+/**
+ * \class JingleIQResponder
+ * \brief A task that responds to jingle candidate queries with an empty reply.
+ */
+
+JingleIQResponder::JingleIQResponder(Task *parent) :Task(parent)
+{
+}
+
+JingleIQResponder::~JingleIQResponder()
+{
+}
+
+bool JingleIQResponder::take(const QDomElement &e)
+{
+ if(e.tagName() != "iq")
+ return false;
+
+ QDomElement first = e.firstChild().toElement();
+ if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) {
+ QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
+ send(iq);
+ return true;
+ }
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+/**
+ * \brief A class for handling signals from libjingle.
+ */
+class JingleClientSlots : public sigslot::has_slots<>
+{
+public:
+ JingleClientSlots(JingleVoiceCaller *voiceCaller);
+
+ void callCreated(cricket::Call *call);
+ void callDestroyed(cricket::Call *call);
+ void sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza);
+ void requestSignaling();
+ void stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state);
+
+private:
+ JingleVoiceCaller* voiceCaller_;
+};
+
+
+JingleClientSlots::JingleClientSlots(JingleVoiceCaller *voiceCaller) : voiceCaller_(voiceCaller)
+{
+}
+
+void JingleClientSlots::callCreated(cricket::Call *call)
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
+ call->SignalSessionState.connect(this, &JingleClientSlots::stateChanged);
+}
+
+void JingleClientSlots::callDestroyed(cricket::Call *call)
+{
+ qDebug("JingleClientSlots: Call destroyed");
+ Jid jid(call->sessions()[0]->remote_address().c_str());
+ if (voiceCaller_->calling(jid)) {
+ qDebug(QString("Removing unterminated call to %1").arg(jid.full()));
+ voiceCaller_->removeCall(jid);
+ emit voiceCaller_->terminated(jid);
+ }
+}
+
+void JingleClientSlots::sendStanza(cricket::SessionClient*, const buzz::XmlElement *stanza)
+{
+ QString st(stanza->Str().c_str());
+ st.replace("cli:iq","iq");
+ st.replace(":cli=","=");
+ fprintf(stderr,"bling\n");
+ voiceCaller_->sendStanza(st.latin1());
+ fprintf(stderr,"blong\n");
+ fprintf(stderr,"Sending stanza \n%s\n\n",st.latin1());
+}
+
+void JingleClientSlots::requestSignaling()
+{
+ voiceCaller_->session_manager_->OnSignalingReady();
+}
+
+void JingleClientSlots::stateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state)
+{
+ qDebug(QString("jinglevoicecaller.cpp: State changed (%1)").arg(state));
+ // Why is c_str() stuff needed to make it compile on OS X ?
+ Jid jid(session->remote_address().c_str());
+
+ if (state == cricket::Session::STATE_INIT) { }
+ else if (state == cricket::Session::STATE_SENTINITIATE) {
+ voiceCaller_->registerCall(jid,call);
+ }
+ else if (state == cricket::Session::STATE_RECEIVEDINITIATE) {
+ voiceCaller_->registerCall(jid,call);
+ emit voiceCaller_->incoming(jid);
+ }
+ else if (state == cricket::Session::STATE_SENTACCEPT) { }
+ else if (state == cricket::Session::STATE_RECEIVEDACCEPT) {
+ emit voiceCaller_->accepted(jid);
+ }
+ else if (state == cricket::Session::STATE_SENTMODIFY) { }
+ else if (state == cricket::Session::STATE_RECEIVEDMODIFY) {
+ qWarning(QString("jinglevoicecaller.cpp: RECEIVEDMODIFY not implemented yet (was from %1)").arg(jid.full()));
+ }
+ else if (state == cricket::Session::STATE_SENTREJECT) { }
+ else if (state == cricket::Session::STATE_RECEIVEDREJECT) {
+ voiceCaller_->removeCall(jid);
+ emit voiceCaller_->rejected(jid);
+ }
+ else if (state == cricket::Session::STATE_SENTREDIRECT) { }
+ else if (state == cricket::Session::STATE_SENTTERMINATE) {
+ voiceCaller_->removeCall(jid);
+ emit voiceCaller_->terminated(jid);
+ }
+ else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) {
+ voiceCaller_->removeCall(jid);
+ emit voiceCaller_->terminated(jid);
+ }
+ else if (state == cricket::Session::STATE_INPROGRESS) {
+ emit voiceCaller_->in_progress(jid);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+/**
+ * \class JingleVoiceCaller
+ * \brief A Voice Calling implementation using libjingle.
+ */
+
+JingleVoiceCaller::JingleVoiceCaller(PsiAccount* acc) : VoiceCaller(acc)
+{
+ initialized_ = false;
+}
+
+void JingleVoiceCaller::initialize()
+{
+ if (initialized_)
+ return;
+
+ QString jid = ((ClientStream&) account()->client()->client()->stream()).jid().full();
+ qDebug(QString("jinglevoicecaller.cpp: Creating new caller for %1").arg(jid));
+ if (jid.isEmpty()) {
+ qWarning("jinglevoicecaller.cpp: Empty JID");
+ return;
+ }
+
+ buzz::Jid j(jid.ascii());
+ cricket::InitRandom(j.Str().c_str(),j.Str().size());
+
+ // Global variables
+ if (!socket_server_) {
+ socket_server_ = new cricket::PhysicalSocketServer();
+ cricket::Thread *t = new cricket::Thread((cricket::PhysicalSocketServer*)(socket_server_));
+ cricket::ThreadManager::SetCurrent(t);
+ t->Start();
+ thread_ = t;
+
+ stun_addr_ = new cricket::SocketAddress("64.233.167.126",19302);
+ network_manager_ = new cricket::NetworkManager();
+ port_allocator_ = new cricket::BasicPortAllocator((cricket::NetworkManager*)(network_manager_), (cricket::SocketAddress*)(stun_addr_), /* relay server */ NULL);
+ }
+
+ // Session manager
+ session_manager_ = new cricket::SessionManager((cricket::PortAllocator*)(port_allocator_), thread_);
+ slots_ = new JingleClientSlots(this);
+ session_manager_->SignalRequestSignaling.connect(slots_, &JingleClientSlots::requestSignaling);
+ session_manager_->OnSignalingReady();
+
+ // Phone Client
+ phone_client_ = new cricket::PhoneSessionClient(j, (cricket::SessionManager*)(session_manager_));
+ phone_client_->SignalCallCreate.connect(slots_, &JingleClientSlots::callCreated);
+ phone_client_->SignalCallDestroy.connect(slots_, &JingleClientSlots::callDestroyed);
+ phone_client_->SignalSendStanza.connect(slots_, &JingleClientSlots::sendStanza);
+
+ // IQ Responder
+ new JingleIQResponder(account()->client()->rootTask());
+
+ // Listen to incoming packets
+ connect(account()->client()->client(),SIGNAL(xmlIncoming(const QString&)),SLOT(receiveStanza(const QString&)));
+
+ initialized_ = true;
+}
+
+
+void JingleVoiceCaller::deinitialize()
+{
+ if (!initialized_)
+ return;
+
+ // Stop listening to incoming packets
+ disconnect(account()->client(),SIGNAL(xmlIncoming(const QString&)),this,SLOT(receiveStanza(const QString&)));
+
+ // Disconnect signals (is this needed)
+ //phone_client_->SignalCallCreate.disconnect(slots_);
+ //phone_client_->SignalSendStanza.disconnect(slots_);
+
+ // Delete objects
+ delete phone_client_;
+ delete session_manager_;
+ delete slots_;
+
+ initialized_ = false;
+}
+
+
+JingleVoiceCaller::~JingleVoiceCaller()
+{
+}
+
+bool JingleVoiceCaller::calling(const Jid& jid)
+{
+ return calls_.contains(jid.full());
+}
+
+void JingleVoiceCaller::call(const Jid& jid)
+{
+ qDebug(QString("jinglevoicecaller.cpp: Calling %1").arg(jid.full()));
+ cricket::Call *c = ((cricket::PhoneSessionClient*)(phone_client_))->CreateCall();
+ c->InitiateSession(buzz::Jid(jid.full().ascii()));
+ phone_client_->SetFocus(c);
+}
+
+void JingleVoiceCaller::accept(const Jid& j)
+{
+ qDebug("jinglevoicecaller.cpp: Accepting call");
+ cricket::Call* call = calls_[j.full()];
+ if (call != NULL) {
+ call->AcceptSession(call->sessions()[0]);
+ phone_client_->SetFocus(call);
+ }
+}
+
+void JingleVoiceCaller::reject(const Jid& j)
+{
+ qDebug("jinglevoicecaller.cpp: Rejecting call");
+ cricket::Call* call = calls_[j.full()];
+ if (call != NULL) {
+ call->RejectSession(call->sessions()[0]);
+ calls_.remove(j.full());
+ }
+}
+
+void JingleVoiceCaller::terminate(const Jid& j)
+{
+ qDebug(QString("jinglevoicecaller.cpp: Terminating call to %1").arg(j.full()));
+ cricket::Call* call = calls_[j.full()];
+ if (call != NULL) {
+ call->Terminate();
+ calls_.remove(j.full());
+ }
+}
+
+void JingleVoiceCaller::sendStanza(const char* stanza)
+{
+ account()->client()->send(QString(stanza));
+}
+
+void JingleVoiceCaller::registerCall(const Jid& jid, cricket::Call* call)
+{
+ qDebug("jinglevoicecaller.cpp: Registering call\n");
+ kdDebug(14000) << k_funcinfo << jid.full() << endl;
+ if (!calls_.contains(jid.full())) {
+ calls_[jid.full()] = call;
+ }
+// else {
+// qWarning("jinglevoicecaller.cpp: Auto-rejecting call because another call is currently open");
+// call->RejectSession(call->sessions()[0]);
+// }
+}
+
+void JingleVoiceCaller::removeCall(const Jid& j)
+{
+ qDebug(QString("JingleVoiceCaller: Removing call to %1").arg(j.full()));
+ calls_.remove(j.full());
+}
+
+void JingleVoiceCaller::receiveStanza(const QString& stanza)
+{
+ QDomDocument doc;
+ doc.setContent(stanza);
+
+ // Check if it is offline presence from an open chat
+ if (doc.documentElement().tagName() == "presence") {
+ Jid from = Jid(doc.documentElement().attribute("from"));
+ QString type = doc.documentElement().attribute("type");
+ if (type == "unavailable" && calls_.contains(from.full())) {
+ qDebug("JingleVoiceCaller: User went offline without closing a call.");
+ removeCall(from);
+ emit terminated(from);
+ }
+ return;
+ }
+
+ // Check if the packet is destined for libjingle.
+ // We could use Session::IsClientStanza to check this, but this one crashes
+ // for some reason.
+ QDomNode n = doc.documentElement().firstChild();
+ bool ok = false;
+ while (!n.isNull() && !ok) {
+ QDomElement e = n.toElement();
+ if (!e.isNull() && e.attribute("xmlns") == JINGLE_NS) {
+ ok = true;
+ }
+ n = n.nextSibling();
+ }
+
+ // Spread the word
+ if (ok) {
+ qDebug(QString("jinglevoicecaller.cpp: Handing down %1").arg(stanza));
+ buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii());
+ phone_client_->OnIncomingStanza(e);
+ }
+}
+
+cricket::SocketServer* JingleVoiceCaller::socket_server_ = NULL;
+cricket::Thread* JingleVoiceCaller::thread_ = NULL;
+cricket::NetworkManager* JingleVoiceCaller::network_manager_ = NULL;
+cricket::BasicPortAllocator* JingleVoiceCaller::port_allocator_ = NULL;
+cricket::SocketAddress* JingleVoiceCaller::stun_addr_ = NULL;
diff --git a/kopete/protocols/jabber/jingle/jinglevoicecaller.h b/kopete/protocols/jabber/jingle/jinglevoicecaller.h
new file mode 100644
index 00000000..4448d530
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicecaller.h
@@ -0,0 +1,72 @@
+#define PsiAccount JabberAccount
+
+#ifndef JINGLEVOICECALLER_H
+#define JINGLEVOICECALLER_H
+
+#include <qmap.h>
+
+#include "im.h"
+#include "voicecaller.h"
+
+using namespace XMPP;
+
+
+class PsiAccount;
+
+namespace cricket {
+ class SocketServer;
+ class Thread;
+ class NetworkManager;
+ class BasicPortAllocator;
+ class SessionManager;
+ class PhoneSessionClient;
+ class Call;
+ class SocketAddress;
+}
+
+class JingleClientSlots;
+class JingleCallSlots;
+
+
+class JingleVoiceCaller : public VoiceCaller
+{
+ Q_OBJECT
+
+ friend class JingleClientSlots;
+
+public:
+ JingleVoiceCaller(PsiAccount* account);
+ ~JingleVoiceCaller();
+
+ virtual bool calling(const Jid&);
+
+ virtual void initialize();
+ virtual void deinitialize();
+
+ virtual void call(const Jid&);
+ virtual void accept(const Jid&);
+ virtual void reject(const Jid&);
+ virtual void terminate(const Jid&);
+
+protected:
+ void sendStanza(const char*);
+ void registerCall(const Jid&, cricket::Call*);
+ void removeCall(const Jid&);
+
+protected slots:
+ void receiveStanza(const QString&);
+
+private:
+ bool initialized_;
+ static cricket::SocketServer *socket_server_;
+ static cricket::Thread *thread_;
+ static cricket::NetworkManager *network_manager_;
+ static cricket::BasicPortAllocator *port_allocator_;
+ static cricket::SocketAddress *stun_addr_;
+ cricket::SessionManager *session_manager_;
+ cricket::PhoneSessionClient *phone_client_;
+ JingleClientSlots *slots_;
+ QMap<QString,cricket::Call*> calls_;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/jinglevoicesession.cpp b/kopete/protocols/jabber/jingle/jinglevoicesession.cpp
new file mode 100644
index 00000000..09019ce4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicesession.cpp
@@ -0,0 +1,333 @@
+/*
+ jinglevoicesession.cpp - Define a Jingle voice session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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. *
+ * *
+ *************************************************************************
+*/
+
+// libjingle before everything else to not clash with Qt
+#define POSIX
+#include "talk/xmpp/constants.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/base/network.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/p2p/client/basicportallocator.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/thread.h"
+#include "talk/base/socketaddress.h"
+#include "talk/session/phone/call.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/session/sessionsendtask.h"
+
+#include "jinglevoicesession.h"
+#include "jinglesessionmanager.h"
+
+// Qt includes
+#include <qdom.h>
+
+// KDE includes
+#include <kdebug.h>
+
+// Kopete Jabber includes
+#include "jabberaccount.h"
+#include "jabberprotocol.h"
+
+#include <xmpp.h>
+#include <xmpp_xmlcommon.h>
+
+#define JINGLE_NS "http://www.google.com/session"
+#define JINGLE_VOICE_SESSION_NS "http://www.google.com/session/phone"
+
+static bool hasPeer(const JingleVoiceSession::JidList &jidList, const XMPP::Jid &peer)
+{
+ JingleVoiceSession::JidList::ConstIterator it, itEnd = jidList.constEnd();
+ for(it = jidList.constBegin(); it != itEnd; ++it)
+ {
+ if( (*it).compare(peer, true) )
+ return true;
+ }
+
+ return false;
+}
+//BEGIN SlotsProxy
+/**
+ * This class is used to receive signals from libjingle,
+ * which is are not compatible with Qt signals.
+ * So it's a proxy between JingeVoiceSession(qt)<->linjingle class.
+ */
+class JingleVoiceSession::SlotsProxy : public sigslot::has_slots<>
+{
+public:
+ SlotsProxy(JingleVoiceSession *parent)
+ : voiceSession(parent)
+ {}
+
+ void OnCallCreated(cricket::Call* call)
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "SlotsProxy: CallCreated." << endl;
+
+ call->SignalSessionState.connect(this, &JingleVoiceSession::SlotsProxy::PhoneSessionStateChanged);
+ voiceSession->setCall(call);
+ }
+
+ void PhoneSessionStateChanged(cricket::Call *call, cricket::Session *session, cricket::Session::State state)
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "State changed: " << state << endl;
+
+ XMPP::Jid jid(session->remote_address().c_str());
+
+ // Do nothing if the session do not contain a peers.
+ //if( !voiceSession->peers().contains(jid) )
+ if( !hasPeer(voiceSession->peers(), jid) )
+ return;
+
+ if (state == cricket::Session::STATE_INIT)
+ {}
+ else if (state == cricket::Session::STATE_SENTINITIATE)
+ {}
+ else if (state == cricket::Session::STATE_RECEIVEDINITIATE)
+ {
+ voiceSession->setCall(call);
+ }
+ else if (state == cricket::Session::STATE_SENTACCEPT)
+ {}
+ else if (state == cricket::Session::STATE_RECEIVEDACCEPT)
+ {
+ emit voiceSession->accepted();
+ }
+ else if (state == cricket::Session::STATE_SENTMODIFY)
+ {}
+ else if (state == cricket::Session::STATE_RECEIVEDMODIFY)
+ {
+ //qWarning(QString("jinglevoicecaller.cpp: RECEIVEDMODIFY not implemented yet (was from %1)").arg(jid.full()));
+ }
+ else if (state == cricket::Session::STATE_SENTREJECT)
+ {}
+ else if (state == cricket::Session::STATE_RECEIVEDREJECT)
+ {
+ emit voiceSession->declined();
+ }
+ else if (state == cricket::Session::STATE_SENTREDIRECT)
+ {}
+ else if (state == cricket::Session::STATE_SENTTERMINATE)
+ {
+ emit voiceSession->terminated();
+ }
+ else if (state == cricket::Session::STATE_RECEIVEDTERMINATE)
+ {
+ emit voiceSession->terminated();
+ }
+ else if (state == cricket::Session::STATE_INPROGRESS)
+ {
+ emit voiceSession->sessionStarted();
+ }
+ }
+
+ void OnSendingStanza(cricket::SessionClient*, const buzz::XmlElement *buzzStanza)
+ {
+ QString irisStanza(buzzStanza->Str().c_str());
+ irisStanza.replace("cli:iq","iq");
+ irisStanza.replace(":cli=","=");
+
+ voiceSession->sendStanza(irisStanza);
+ }
+private:
+ JingleVoiceSession *voiceSession;
+};
+//END SlotsProxy
+
+//BEGIN JingleIQResponder
+class JingleVoiceSession::JingleIQResponder : public XMPP::Task
+{
+public:
+ JingleIQResponder(XMPP::Task *);
+ ~JingleIQResponder();
+
+ bool take(const QDomElement &);
+};
+
+/**
+ * \class JingleIQResponder
+ * \brief A task that responds to jingle candidate queries with an empty reply.
+ */
+
+JingleVoiceSession::JingleIQResponder::JingleIQResponder(Task *parent) :Task(parent)
+{
+}
+
+JingleVoiceSession::JingleIQResponder::~JingleIQResponder()
+{
+}
+
+bool JingleVoiceSession::JingleIQResponder::take(const QDomElement &e)
+{
+ if(e.tagName() != "iq")
+ return false;
+
+ QDomElement first = e.firstChild().toElement();
+ if (!first.isNull() && first.attribute("xmlns") == JINGLE_NS) {
+ QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
+ send(iq);
+ return true;
+ }
+
+ return false;
+}
+//END JingleIQResponder
+
+class JingleVoiceSession::Private
+{
+public:
+ Private()
+ : phoneSessionClient(0L), currentCall(0L)
+ {}
+
+ ~Private()
+ {
+ if(currentCall)
+ currentCall->Terminate();
+
+ delete currentCall;
+ }
+
+ cricket::PhoneSessionClient *phoneSessionClient;
+ cricket::Call* currentCall;
+};
+
+JingleVoiceSession::JingleVoiceSession(JabberAccount *account, const JidList &peers)
+ : JingleSession(account, peers), d(new Private)
+{
+ slotsProxy = new SlotsProxy(this);
+
+ buzz::Jid buzzJid( account->client()->jid().full().ascii() );
+
+ // Create the phone(voice) session.
+ d->phoneSessionClient = new cricket::PhoneSessionClient( buzzJid, account->sessionManager()->cricketSessionManager() );
+
+ d->phoneSessionClient->SignalSendStanza.connect(slotsProxy, &JingleVoiceSession::SlotsProxy::OnSendingStanza);
+ d->phoneSessionClient->SignalCallCreate.connect(slotsProxy, &JingleVoiceSession::SlotsProxy::OnCallCreated);
+
+ // Listen to incoming packets
+ connect(account->client()->client(), SIGNAL(xmlIncoming(const QString&)), this, SLOT(receiveStanza(const QString&)));
+
+ new JingleIQResponder(account->client()->rootTask());
+}
+
+JingleVoiceSession::~JingleVoiceSession()
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << endl;
+ delete slotsProxy;
+ delete d;
+}
+
+QString JingleVoiceSession::sessionType()
+{
+ return QString(JINGLE_VOICE_SESSION_NS);
+}
+
+void JingleVoiceSession::start()
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Starting a voice session..." << endl;
+ d->currentCall = d->phoneSessionClient->CreateCall();
+
+ QString firstPeerJid = ((XMPP::Jid)peers().first()).full();
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "With peer: " << firstPeerJid << endl;
+ d->currentCall->InitiateSession( buzz::Jid(firstPeerJid.ascii()) );
+
+ d->phoneSessionClient->SetFocus(d->currentCall);
+}
+
+void JingleVoiceSession::accept()
+{
+ if(d->currentCall)
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Accepting a voice session..." << endl;
+
+ d->currentCall->AcceptSession(d->currentCall->sessions()[0]);
+ d->phoneSessionClient->SetFocus(d->currentCall);
+ }
+}
+
+void JingleVoiceSession::decline()
+{
+ if(d->currentCall)
+ {
+ d->currentCall->RejectSession(d->currentCall->sessions()[0]);
+ }
+}
+
+void JingleVoiceSession::terminate()
+{
+ if(d->currentCall)
+ {
+ d->currentCall->Terminate();
+ }
+}
+
+void JingleVoiceSession::setCall(cricket::Call *call)
+{
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating cricket::call object." << endl;
+ d->currentCall = call;
+ d->phoneSessionClient->SetFocus(d->currentCall);
+}
+
+void JingleVoiceSession::receiveStanza(const QString &stanza)
+{
+ QDomDocument doc;
+ doc.setContent(stanza);
+
+ // Check if it is offline presence from an open chat
+ if( doc.documentElement().tagName() == "presence" )
+ {
+ XMPP::Jid from = XMPP::Jid(doc.documentElement().attribute("from"));
+ QString type = doc.documentElement().attribute("type");
+ if( type == "unavailable" && hasPeer(peers(), from) )
+ {
+ //qDebug("JingleVoiceCaller: User went offline without closing a call.");
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "User went offline without closing a call." << endl;
+ emit terminated();
+ }
+ return;
+ }
+
+ // Check if the packet is destined for libjingle.
+ // We could use Session::IsClientStanza to check this, but this one crashes
+ // for some reason.
+ QDomNode node = doc.documentElement().firstChild();
+ bool ok = false;
+ while( !node.isNull() && !ok )
+ {
+ QDomElement element = node.toElement();
+ if( !element.isNull() && element.attribute("xmlns") == JINGLE_NS)
+ {
+ ok = true;
+ }
+ node = node.nextSibling();
+ }
+
+ // Spread the word
+ if( ok )
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Handing down buzz::stanza" << endl;
+ buzz::XmlElement *e = buzz::XmlElement::ForStr(stanza.ascii());
+ d->phoneSessionClient->OnIncomingStanza(e);
+ }
+}
+
+#include "jinglevoicesession.moc"
diff --git a/kopete/protocols/jabber/jingle/jinglevoicesession.h b/kopete/protocols/jabber/jingle/jinglevoicesession.h
new file mode 100644
index 00000000..e70d3b54
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicesession.h
@@ -0,0 +1,70 @@
+/*
+ jinglevoicesession.h - Define a Jingle voice session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 JINGLEVOICESESSION_H
+#define JINGLEVOICESESSION_H
+
+#include <jinglesession.h>
+
+#include <xmpp.h> // XMPP::Jid
+#include <qvaluelist.h>
+
+namespace cricket
+{
+ class Call;
+}
+
+class JabberAccount;
+class JingleSession;
+
+/**
+ * Implement a Jingle voice peer-to-peer session that is compatible with Google Talk voice offering.
+ *
+ * @author Michaël Larouche
+*/
+class JingleVoiceSession : public JingleSession
+{
+ Q_OBJECT
+public:
+ typedef QValueList<XMPP::Jid> JidList;
+
+ JingleVoiceSession(JabberAccount *account, const JidList &peers);
+ virtual ~JingleVoiceSession();
+
+ virtual QString sessionType();
+
+public slots:
+ virtual void accept();
+ virtual void decline();
+ virtual void start();
+ virtual void terminate();
+
+protected slots:
+ void receiveStanza(const QString &stanza);
+
+private:
+ void setCall(cricket::Call *call);
+
+ class Private;
+ Private *d;
+
+ class SlotsProxy;
+ SlotsProxy *slotsProxy;
+
+ class JingleIQResponder;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp b/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp
new file mode 100644
index 00000000..9fb61274
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.cpp
@@ -0,0 +1,208 @@
+/*
+ jinglevoicesessiondialog.cpp - GUI for a voice session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 "jinglevoicesessiondialog.h"
+
+// Qt includes
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qimage.h>
+
+// Jingle includes
+// #include "jinglevoicesession.h"
+// #include "jinglesessionmanager.h"
+#include "voicecaller.h"
+
+// KDE includes
+#include <klocale.h>
+#include <kpushbutton.h>
+
+// Kopete includes
+#include "jabberaccount.h"
+#include "jabbercontact.h"
+#include "jabbercontactpool.h"
+
+#include "kopeteglobal.h"
+#include "kopetemetacontact.h"
+
+using namespace XMPP;
+
+JingleVoiceSessionDialog::JingleVoiceSessionDialog(const Jid &peerJid, VoiceCaller *caller, QWidget *parent, const char *name)
+ : JingleVoiceSessionDialogBase(parent, name), m_session(caller), m_peerJid(peerJid), m_sessionState(Incoming)
+{
+ QString contactJid = m_peerJid.full();
+ setCaption( i18n("Voice session with %1").arg(contactJid) );
+
+ connect(buttonAccept, SIGNAL(clicked()), this, SLOT(slotAcceptClicked()));
+ connect(buttonDecline, SIGNAL(clicked()), this, SLOT(slotDeclineClicked()));
+ connect(buttonTerminate, SIGNAL(clicked()), this, SLOT(slotTerminateClicked()));
+
+// NOTE: Disabled for 0.12
+#if 0
+ connect(m_session, SIGNAL(sessionStarted()), this, SLOT(sessionStarted()));
+ connect(m_session, SIGNAL(accepted()), this, SLOT(sessionAccepted()));
+ connect(m_session, SIGNAL(declined()), this, SLOT(sessionDeclined()));
+ connect(m_session, SIGNAL(terminated()), this, SLOT(sessionTerminated()));
+#endif
+ connect(m_session, SIGNAL(accepted( const Jid & )), this, SLOT( sessionAccepted(const Jid &) ));
+ connect(m_session, SIGNAL(in_progress( const Jid & )), this, SLOT( sessionStarted(const Jid &) ));
+ connect(m_session, SIGNAL(rejected( const Jid& )), this, SLOT( sessionDeclined(const Jid &) ));
+ connect(m_session, SIGNAL(terminated( const Jid& )), this, SLOT( sessionTerminated(const Jid &) ));
+
+ // Find JabberContact for the peer and fill this dialog with contact information.
+ JabberContact *peerContact = static_cast<JabberContact*>( m_session->account()->contactPool()->findRelevantRecipient( m_peerJid ) );
+ if( peerContact )
+ {
+ setContactInformation( peerContact );
+ }
+
+ labelSessionStatus->setText( i18n("Incoming Session...") );
+ buttonAccept->setEnabled(true);
+ buttonDecline->setEnabled(true);
+}
+
+JingleVoiceSessionDialog::~JingleVoiceSessionDialog()
+{
+ //m_session->account()->sessionManager()->removeSession(m_session);
+}
+
+void JingleVoiceSessionDialog::setContactInformation(JabberContact *contact)
+{
+ if( contact->metaContact() )
+ {
+ labelDisplayName->setText( contact->metaContact()->displayName() );
+ labelContactPhoto->setPixmap( QPixmap(contact->metaContact()->photo()) );
+ }
+ else
+ {
+ labelDisplayName->setText( contact->nickName() );
+ labelDisplayName->setPixmap( QPixmap(contact->property(Kopete::Global::Properties::self()->photo()).value().toString()) );
+ }
+}
+
+void JingleVoiceSessionDialog::start()
+{
+ labelSessionStatus->setText( i18n("Waiting for other peer...") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(true);
+ //m_session->start();
+ m_session->call( m_peerJid );
+ m_sessionState = Waiting;
+}
+
+void JingleVoiceSessionDialog::slotAcceptClicked()
+{
+ labelSessionStatus->setText( i18n("Session accepted.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(true);
+
+ //m_session->accept();
+ m_session->accept( m_peerJid );
+ m_sessionState = Accepted;
+}
+
+void JingleVoiceSessionDialog::slotDeclineClicked()
+{
+ labelSessionStatus->setText( i18n("Session declined.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(false);
+
+ //m_session->decline();
+ m_session->reject( m_peerJid );
+ m_sessionState = Declined;
+ finalize();
+}
+
+void JingleVoiceSessionDialog::slotTerminateClicked()
+{
+ labelSessionStatus->setText( i18n("Session terminated.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(false);
+
+ //m_session->terminate();
+ m_session->terminate( m_peerJid );
+ m_sessionState = Terminated;
+ finalize();
+ close();
+}
+
+void JingleVoiceSessionDialog::sessionStarted(const Jid &jid)
+{
+ if( m_peerJid.compare(jid) )
+ {
+ labelSessionStatus->setText( i18n("Session in progress.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(true);
+ m_sessionState = Started;
+ }
+}
+
+void JingleVoiceSessionDialog::sessionAccepted(const Jid &jid)
+{
+ if( m_peerJid.compare(jid) )
+ {
+ labelSessionStatus->setText( i18n("Session accepted.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(true);
+ m_sessionState = Accepted;
+ }
+}
+
+void JingleVoiceSessionDialog::sessionDeclined(const Jid &jid)
+{
+ if( m_peerJid.compare(jid) )
+ {
+ labelSessionStatus->setText( i18n("Session declined.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(false);
+ m_sessionState = Declined;
+ }
+}
+
+void JingleVoiceSessionDialog::sessionTerminated(const Jid &jid)
+{
+ if( m_peerJid.compare(jid) )
+ {
+ labelSessionStatus->setText( i18n("Session terminated.") );
+ buttonAccept->setEnabled(false);
+ buttonDecline->setEnabled(false);
+ buttonTerminate->setEnabled(false);
+ m_sessionState = Terminated;
+ }
+}
+
+void JingleVoiceSessionDialog::reject()
+{
+ finalize();
+ QDialog::reject();
+}
+
+void JingleVoiceSessionDialog::finalize()
+{
+ disconnect(m_session, SIGNAL(accepted( const Jid & )), this, SLOT( sessionAccepted(const Jid &) ));
+ disconnect(m_session, SIGNAL(in_progress( const Jid & )), this, SLOT( sessionStarted(const Jid &) ));
+ disconnect(m_session, SIGNAL(rejected( const Jid& )), this, SLOT( sessionDeclined(const Jid &) ));
+ disconnect(m_session, SIGNAL(terminated( const Jid& )), this, SLOT( sessionTerminated(const Jid &) ));
+}
+
+#include "jinglevoicesessiondialog.moc"
diff --git a/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h b/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h
new file mode 100644
index 00000000..29d0c091
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicesessiondialog.h
@@ -0,0 +1,66 @@
+/*
+ jinglevoicesessiondialog.h - GUI for a voice session.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 JINGLEVOICESESSIONDIALOG_H
+#define JINGLEVOICESESSIONDIALOG_H
+
+#include "jinglevoicesessiondialogbase.h"
+
+#include <im.h>
+#include <xmpp.h>
+
+using namespace XMPP;
+
+class JabberContact;
+class VoiceCaller;
+
+class JingleVoiceSessionDialog : public JingleVoiceSessionDialogBase
+{
+ Q_OBJECT
+public:
+ enum SessionState { Incoming, Waiting, Accepted, Declined, Started, Terminated };
+
+ JingleVoiceSessionDialog(const Jid &peerJid, VoiceCaller *caller, QWidget *parent = 0, const char *name = 0);
+ ~JingleVoiceSessionDialog();
+
+public slots:
+ void start();
+
+protected slots:
+ void reject();
+
+protected:
+ void finalize();
+
+private slots:
+ void slotAcceptClicked();
+ void slotDeclineClicked();
+ void slotTerminateClicked();
+
+ void sessionStarted(const Jid &jid);
+ void sessionAccepted(const Jid &jid);
+ void sessionDeclined(const Jid &jid);
+ void sessionTerminated(const Jid &jid);
+
+private:
+ void setContactInformation(JabberContact *contact);
+
+ VoiceCaller *m_session;
+ Jid m_peerJid;
+ SessionState m_sessionState;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui b/kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui
new file mode 100644
index 00000000..0dc9ab35
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglevoicesessiondialogbase.ui
@@ -0,0 +1,369 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>JingleVoiceSessionDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>JingleVoiceSessionDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>329</width>
+ <height>188</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>JabberVoiceSessionDialogBase</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Voice session with:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelContactPhoto</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>128</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelDisplayName</cstring>
+ </property>
+ <property name="text">
+ <string>Contact displayname</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonAccept</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Accep&amp;t</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonDecline</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Decline</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonTerminate</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Termi&amp;nate</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Current status:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelSessionStatus</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Session status</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp b/kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp
new file mode 100644
index 00000000..fc7de053
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglewatchsessiontask.cpp
@@ -0,0 +1,75 @@
+/*
+ jingleswatchsessiontask.cpp - Watch for incoming Jingle sessions.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 "jinglewatchsessiontask.h"
+
+#include <kdebug.h>
+
+#include "jabberprotocol.h"
+
+#define JINGLE_NS "http://www.google.com/session"
+
+JingleWatchSessionTask::JingleWatchSessionTask(XMPP::Task *parent)
+ : Task(parent)
+{}
+
+JingleWatchSessionTask::~JingleWatchSessionTask()
+{}
+
+//NOTE: This task watch for pre-JEP session.
+bool JingleWatchSessionTask::take(const QDomElement &element)
+{
+ if(element.tagName() != "iq")
+ return false;
+
+ QString sessionType, initiator;
+
+ QDomElement first = element.firstChild().toElement();
+ if( !first.isNull() && first.attribute("xmlns") == JINGLE_NS && first.tagName() == "session" )
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Checking for incoming sesssion." << endl;
+ initiator = first.attribute("initiator");
+
+ // Only proceed initiate type Jingle XMPP call.
+ if( first.attribute("type") != QString::fromUtf8("initiate") )
+ return false;
+
+ int nodeIndex;
+
+ QDomNodeList nodeList = first.childNodes();
+ // Do not check first child
+ for(nodeIndex = 0; nodeIndex < nodeList.length(); nodeIndex++)
+ {
+ QDomElement nodeElement = nodeList.item(nodeIndex).toElement();
+ if(nodeElement.tagName() == "description")
+ {
+ sessionType = nodeElement.attribute("xmlns");
+ }
+ }
+
+ if( !initiator.isEmpty() && !sessionType.isEmpty() )
+ {
+ kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Emmiting incoming sesssion." << endl;
+ emit watchSession(sessionType, initiator);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#include "jinglewatchsessiontask.moc" \ No newline at end of file
diff --git a/kopete/protocols/jabber/jingle/jinglewatchsessiontask.h b/kopete/protocols/jabber/jingle/jinglewatchsessiontask.h
new file mode 100644
index 00000000..99b76661
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/jinglewatchsessiontask.h
@@ -0,0 +1,39 @@
+/*
+ jingleswatchsessiontask.h - Watch for incoming Jingle sessions.
+
+ Copyright (c) 2006 by Michaël Larouche <michael.larouche@kdemail.net>
+
+ Kopete (c) 2001-2006 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 JINGLEWATCHSESSIONTASK_H
+#define JINGLEWATCHSESSIONTASK_H
+
+#include <xmpp_tasks.h>
+
+/**
+ * This task watch for incoming Jingle session and notify manager.
+ * It is declared in the header to be "moc"-able.
+ */
+class JingleWatchSessionTask : public XMPP::Task
+{
+ Q_OBJECT
+public:
+ JingleWatchSessionTask(XMPP::Task *parent);
+ ~JingleWatchSessionTask();
+
+ bool take(const QDomElement &element);
+
+signals:
+ void watchSession(const QString &sessionType, const QString &initiator);
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/AUTHORS b/kopete/protocols/jabber/jingle/libjingle/AUTHORS
new file mode 100644
index 00000000..e491a9e7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/AUTHORS
@@ -0,0 +1 @@
+Google Inc.
diff --git a/kopete/protocols/jabber/jingle/libjingle/COPYING b/kopete/protocols/jabber/jingle/libjingle/COPYING
new file mode 100644
index 00000000..d58182b1
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2004--2005, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/kopete/protocols/jabber/jingle/libjingle/ChangeLog b/kopete/protocols/jabber/jingle/libjingle/ChangeLog
new file mode 100644
index 00000000..6d15ac52
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/ChangeLog
@@ -0,0 +1,4 @@
+Libjingle
+
+0.1.0 - Dec 15 2005
+ - Initial release
diff --git a/kopete/protocols/jabber/jingle/libjingle/INSTALL b/kopete/protocols/jabber/jingle/libjingle/INSTALL
new file mode 100644
index 00000000..a4b34144
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/INSTALL
@@ -0,0 +1,229 @@
+Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/Makefile.am
new file mode 100644
index 00000000..164f7058
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS=talk
+
+dist-hook:
+ sed -i -f talk/sanitize.sed `find $(distdir) -type f` \ No newline at end of file
diff --git a/kopete/protocols/jabber/jingle/libjingle/NEWS b/kopete/protocols/jabber/jingle/libjingle/NEWS
new file mode 100644
index 00000000..1694c754
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/NEWS
@@ -0,0 +1 @@
+* Initial source release
diff --git a/kopete/protocols/jabber/jingle/libjingle/README b/kopete/protocols/jabber/jingle/libjingle/README
new file mode 100644
index 00000000..ec130b36
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/README
@@ -0,0 +1,59 @@
+Libjingle
+
+Libjingle is a set of components provided by Google to interoperate with Google
+Talk's peer-to-peer and voice capabilities. This package will create several
+static libraries you may link to your project as needed.
+
+-talk - No source files in talk/, just these subdirectories
+|-base - Contains basic low-level portable utility functions for
+| things like threads and sockets
+|-p2p - The P2P stack
+ |-base - Base p2p functionality
+ |-client - Hooks to tie it into XMPP
+|-session - Signaling
+ |-phone - Signaling code specific to making phone calls
+|-third_party - Components that aren't ours
+ |-mediastreamer - Media components for dealing with sound hardware and
+ | voice codecs
+|-xmllite - XML parser
+|-xmpp - XMPP engine
+
+In addition, this package contains two examples in talk/examples which
+illustrate the basic concepts of how the provided classes work.
+
+The xmllite component of libjingle depends on expat. You can download expat
+from http://expat.sourceforge.net/.
+
+mediastreamer, the media components used by the example applications depend on
+the oRTP and iLBC components from linphone, which can be found at
+http://www.linphone.org. Linphone, in turn depends on GLib, which can be found
+at http://www.gtk.org. This GLib dependency should be removed in future
+releases.
+
+Building Libjingle
+
+Once the dependencies are installed, run ./configure. ./configure will return
+an error if it failed to locate the proper dependencies. If ./configure
+succeeds, run 'make' to build the components and examples.
+
+When the build is complete, you can run the call example from
+talk/examples/call. This will ask you for your GMail username and your GMail
+auth cookie. Your GMail auth cookie is the GX cookie from mail.google.com
+found in your web browser.
+
+Relay Server
+
+Libjingle will also build a relay server that may be used to relay traffic
+when a direct peer-to-peer connection could not be established. The relay
+server will build in talk/p2p/base/relayserver and will listen on UDP
+ports 5000 and 5001. See the Libjingle Developer Guide at
+http://code.google.com/apis/talk/index.html for information about configuring
+a client to use this relay server.
+
+STUN Server
+
+Lastly, Libjingle builds a STUN server which implements the STUN protocol for
+Simple Traversal of UDP over NAT. The STUN server is built as
+talk/p2p/base/stunserver and listens on UDP port 7000. See the Libjingle
+Developer Guide at http://code.google.com/apis/talk/index.html for information
+about configuring a client to use this STUN server.
diff --git a/kopete/protocols/jabber/jingle/libjingle/libjingle.pro b/kopete/protocols/jabber/jingle/libjingle/libjingle.pro
new file mode 100644
index 00000000..53c8e293
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/libjingle.pro
@@ -0,0 +1,142 @@
+TEMPLATE = lib
+CONFIG += staticlib
+CONFIG += debug
+
+target.extra = true
+
+exists(../../conf.pri) {
+ include(../../conf.pri)
+}
+
+JINGLE_CPP = .
+INCLUDEPATH += $$JINGLE_CPP $$JINGLE_CPP/talk/third_party/mediastreamer
+DEFINES += POSIX
+OBJECTS_DIR = $$JINGLE_CPP/.obj
+
+# Base
+SOURCES += \
+ $$JINGLE_CPP/talk/base/asyncpacketsocket.cc \
+ $$JINGLE_CPP/talk/base/asynctcpsocket.cc \
+ $$JINGLE_CPP/talk/base/asyncudpsocket.cc \
+ $$JINGLE_CPP/talk/base/base64.cc \
+ $$JINGLE_CPP/talk/base/bytebuffer.cc \
+ $$JINGLE_CPP/talk/base/md5c.c \
+ $$JINGLE_CPP/talk/base/messagequeue.cc \
+ $$JINGLE_CPP/talk/base/network.cc \
+ $$JINGLE_CPP/talk/base/physicalsocketserver.cc \
+ $$JINGLE_CPP/talk/base/socketadapters.cc \
+ $$JINGLE_CPP/talk/base/socketaddress.cc \
+ $$JINGLE_CPP/talk/base/task.cc \
+ $$JINGLE_CPP/talk/base/taskrunner.cc \
+ $$JINGLE_CPP/talk/base/thread.cc \
+ $$JINGLE_CPP/talk/base/time.cc
+
+# Not needed ?
+#$$JINGLE_CPP/talk/base/socketaddresspair.cc \
+#$$JINGLE_CPP/talk/base/host.cc \
+
+# P2P Base
+SOURCES += \
+ $$JINGLE_CPP/talk/p2p/base/helpers.cc \
+ $$JINGLE_CPP/talk/p2p/base/p2psocket.cc \
+ $$JINGLE_CPP/talk/p2p/base/port.cc \
+ $$JINGLE_CPP/talk/p2p/base/relayport.cc \
+ $$JINGLE_CPP/talk/p2p/base/session.cc \
+ $$JINGLE_CPP/talk/p2p/base/sessionmanager.cc \
+ $$JINGLE_CPP/talk/p2p/base/socketmanager.cc \
+ $$JINGLE_CPP/talk/p2p/base/stun.cc \
+ $$JINGLE_CPP/talk/p2p/base/stunport.cc \
+ $$JINGLE_CPP/talk/p2p/base/stunrequest.cc \
+ $$JINGLE_CPP/talk/p2p/base/tcpport.cc \
+ $$JINGLE_CPP/talk/p2p/base/udpport.cc
+
+# P2P Client
+SOURCES += \
+ $$JINGLE_CPP/talk/p2p/client/basicportallocator.cc \
+ $$JINGLE_CPP/talk/p2p/client/sessionclient.cc \
+ $$JINGLE_CPP/talk/p2p/client/socketmonitor.cc
+
+
+# XMLLite
+SOURCES += \
+ $$JINGLE_CPP/talk/xmllite/qname.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlbuilder.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlconstants.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlelement.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlnsstack.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlparser.cc \
+ $$JINGLE_CPP/talk/xmllite/xmlprinter.cc
+
+# XMPP
+SOURCES += \
+ $$JINGLE_CPP/talk/xmpp/constants.cc \
+ $$JINGLE_CPP/talk/xmpp/jid.cc \
+ $$JINGLE_CPP/talk/xmpp/saslmechanism.cc \
+ $$JINGLE_CPP/talk/xmpp/xmppclient.cc \
+ $$JINGLE_CPP/talk/xmpp/xmppengineimpl.cc \
+ $$JINGLE_CPP/talk/xmpp/xmppengineimpl_iq.cc \
+ $$JINGLE_CPP/talk/xmpp/xmpplogintask.cc \
+ $$JINGLE_CPP/talk/xmpp/xmppstanzaparser.cc \
+ $$JINGLE_CPP/talk/xmpp/xmpptask.cc
+
+# Session
+SOURCES += \
+ $$JINGLE_CPP/talk/session/phone/call.cc \
+ $$JINGLE_CPP/talk/session/phone/audiomonitor.cc \
+ $$JINGLE_CPP/talk/session/phone/phonesessionclient.cc \
+ $$JINGLE_CPP/talk/session/phone/channelmanager.cc \
+ $$JINGLE_CPP/talk/session/phone/linphonemediaengine.cc \
+ $$JINGLE_CPP/talk/session/phone/voicechannel.cc
+
+#contains(DEFINES, HAVE_PORTAUDIO) {
+# SOURCES += \
+# $$JINGLE_CPP/talk/session/phone/portaudiomediaengine.cc
+#}
+
+
+# Mediastreamer
+SOURCES += \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/audiostream.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/ms.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msAlawdec.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msAlawenc.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msbuffer.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mscodec.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mscopy.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msfdispatcher.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msfifo.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msfilter.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msilbcdec.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msilbcenc.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msMUlawdec.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msMUlawenc.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msnosync.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msossread.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msosswrite.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msqdispatcher.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msqueue.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msread.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msringplayer.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msrtprecv.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msrtpsend.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mssoundread.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mssoundwrite.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msspeexdec.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/msspeexenc.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mssync.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mstimer.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/mswrite.c \
+ $$JINGLE_CPP/talk/third_party/mediastreamer/sndcard.c
+
+contains(DEFINES, HAVE_ALSA_ASOUNDLIB_H) {
+ SOURCES += $$JINGLE_CPP/talk/third_party/mediastreamer/alsacard.c
+}
+
+contains(DEFINES, HAVE_PORTAUDIO) {
+ SOURCES += $$JINGLE_CPP/talk/third_party/mediastreamer/portaudiocard.c
+}
+
+#$$JINGLE_CPP/talk/third_party/mediastreamer/osscard.c \
+#$$JINGLE_CPP/talk/third_party/mediastreamer/jackcard.c \
+#$$JINGLE_CPP/talk/third_party/mediastreamer/hpuxsndcard.c \
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am
new file mode 100644
index 00000000..2a845dc0
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=base p2p xmllite xmpp session third_party
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am
new file mode 100644
index 00000000..2921049a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am
@@ -0,0 +1,62 @@
+## Does not compile with final
+KDE_OPTIONS = nofinal
+
+libcricketbase_la_SOURCES = socketaddress.cc \
+ jtime.cc \
+ asyncudpsocket.cc \
+ messagequeue.cc \
+ thread.cc \
+ physicalsocketserver.cc \
+ bytebuffer.cc \
+ asyncpacketsocket.cc \
+ network.cc \
+ asynctcpsocket.cc \
+ socketadapters.cc \
+ md5c.c \
+ base64.cc \
+ task.cc \
+ taskrunner.cc \
+ host.cc \
+ socketaddresspair.cc
+
+noinst_HEADERS = asyncfile.h \
+ common.h \
+ asyncpacketsocket.h \
+ socketfactory.h \
+ asyncsocket.h \
+ socket.h \
+ asynctcpsocket.h \
+ linked_ptr.h \
+ asyncudpsocket.h \
+ logging.h \
+ socketserver.h \
+ base64.h \
+ md5.h \
+ stl_decl.h \
+ basicdefs.h \
+ messagequeue.h \
+ basictypes.h \
+ stringutils.h \
+ bytebuffer.h \
+ task.h \
+ byteorder.h \
+ taskrunner.h \
+ criticalsection.h \
+ network.h \
+ thread.h \
+ jtime.h \
+ physicalsocketserver.h \
+ proxyinfo.h \
+ host.h \
+ scoped_ptr.h \
+ sigslot.h \
+ winping.h \
+ socketadapters.h \
+ socketaddress.h \
+ host.h \
+ socketaddresspair.h
+
+AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../.. -I$(top_builddir) $(all_includes)
+noinst_LTLIBRARIES = libcricketbase.la
+DEFAULT_INCLUDES = -I$(srcdir)/../..
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h
new file mode 100644
index 00000000..0faac9ea
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h
@@ -0,0 +1,56 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CRICKET_BASE_ASYNCFILEH_H__
+#define CRICKET_BASE_ASYNCFILEH_H__
+
+#include "talk/base/sigslot.h"
+
+namespace cricket {
+
+// Provides the ability to perform file I/O asynchronously.
+// TODO: Create a common base class with AsyncSocket.
+class AsyncFile {
+public:
+ virtual ~AsyncFile() {}
+
+ // Determines whether the file will receive read events.
+ virtual bool readable() = 0;
+ virtual void set_readable(bool value) = 0;
+
+ // Determines whether the file will receive write events.
+ virtual bool writable() = 0;
+ virtual void set_writable(bool value) = 0;
+
+ sigslot::signal1<AsyncFile*> SignalReadEvent;
+ sigslot::signal1<AsyncFile*> SignalWriteEvent;
+ sigslot::signal2<AsyncFile*,int> SignalCloseEvent;
+};
+
+} // namespace cricket
+
+#endif // CRICKET_BASE_ASYNCFILEH_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc
new file mode 100644
index 00000000..10cfa617
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc
@@ -0,0 +1,83 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/asyncpacketsocket.h"
+
+namespace cricket {
+
+AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) {
+}
+
+AsyncPacketSocket::~AsyncPacketSocket() {
+ delete socket_;
+}
+
+SocketAddress AsyncPacketSocket::GetLocalAddress() const {
+ return socket_->GetLocalAddress();
+}
+
+SocketAddress AsyncPacketSocket::GetRemoteAddress() const {
+ return socket_->GetRemoteAddress();
+}
+
+int AsyncPacketSocket::Bind(const SocketAddress& addr) {
+ return socket_->Bind(addr);
+}
+
+int AsyncPacketSocket::Connect(const SocketAddress& addr) {
+ return socket_->Connect(addr);
+}
+
+int AsyncPacketSocket::Send(const void *pv, size_t cb) {
+ return socket_->Send(pv, cb);
+}
+
+int AsyncPacketSocket::SendTo(
+ const void *pv, size_t cb, const SocketAddress& addr) {
+ return socket_->SendTo(pv, cb, addr);
+}
+
+int AsyncPacketSocket::Close() {
+ return socket_->Close();
+}
+
+int AsyncPacketSocket::SetOption(Socket::Option opt, int value) {
+ return socket_->SetOption(opt, value);
+}
+
+int AsyncPacketSocket::GetError() const {
+ return socket_->GetError();
+}
+
+void AsyncPacketSocket::SetError(int error) {
+ return socket_->SetError(error);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h
new file mode 100644
index 00000000..b5119c8d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h
@@ -0,0 +1,63 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASYNCPACKETSOCKET_H__
+#define __ASYNCPACKETSOCKET_H__
+
+#include "talk/base/asyncsocket.h"
+
+namespace cricket {
+
+// Provides the ability to receive packets asynchronously. Sends are not
+// buffered since it is acceptable to drop packets under high load.
+class AsyncPacketSocket : public sigslot::has_slots<> {
+public:
+ AsyncPacketSocket(AsyncSocket* socket);
+ virtual ~AsyncPacketSocket();
+
+ // Relevant socket methods:
+ virtual SocketAddress GetLocalAddress() const;
+ virtual SocketAddress GetRemoteAddress() const;
+ virtual int Bind(const SocketAddress& addr);
+ virtual int Connect(const SocketAddress& addr);
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+ virtual int Close();
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError() const;
+ virtual void SetError(int error);
+
+ // Emitted each time a packet is read.
+ sigslot::signal4<const char*, size_t, const SocketAddress&, AsyncPacketSocket*> SignalReadPacket;
+
+protected:
+ AsyncSocket* socket_;
+};
+
+} // namespace cricket
+
+#endif // __ASYNCPACKETSOCKET_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h
new file mode 100644
index 00000000..d6404232
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h
@@ -0,0 +1,91 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASYNCSOCKET_H__
+#define __ASYNCSOCKET_H__
+
+#include "talk/base/sigslot.h"
+#include "talk/base/socket.h"
+
+namespace cricket {
+
+// Provides the ability to perform socket I/O asynchronously.
+class AsyncSocket : public Socket, public sigslot::has_slots<> {
+public:
+ virtual ~AsyncSocket() {}
+
+ sigslot::signal1<AsyncSocket*> SignalReadEvent; // ready to read
+ sigslot::signal1<AsyncSocket*> SignalWriteEvent; // ready to write
+ sigslot::signal1<AsyncSocket*> SignalConnectEvent; // connected
+ sigslot::signal2<AsyncSocket*,int> SignalCloseEvent; // closed
+ // TODO: error
+};
+
+class AsyncSocketAdapter : public AsyncSocket {
+public:
+ AsyncSocketAdapter(Socket * socket) : socket_(socket) {
+ }
+ AsyncSocketAdapter(AsyncSocket * socket) : socket_(socket) {
+ socket->SignalConnectEvent.connect(this, &AsyncSocketAdapter::OnConnectEvent);
+ socket->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent);
+ socket->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent);
+ socket->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent);
+ }
+ virtual ~AsyncSocketAdapter() { delete socket_; }
+
+ virtual SocketAddress GetLocalAddress() const { return socket_->GetLocalAddress(); }
+ virtual SocketAddress GetRemoteAddress() const { return socket_->GetRemoteAddress(); }
+
+ virtual int Bind(const SocketAddress& addr) { return socket_->Bind(addr); }
+ virtual int Connect(const SocketAddress& addr) { return socket_->Connect(addr); }
+ virtual int Send(const void *pv, size_t cb) { return socket_->Send(pv, cb); }
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { return socket_->SendTo(pv, cb, addr); }
+ virtual int Recv(void *pv, size_t cb) { return socket_->Recv(pv, cb); }
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { return socket_->RecvFrom(pv, cb, paddr); }
+ virtual int Listen(int backlog) { return socket_->Listen(backlog); }
+ virtual Socket *Accept(SocketAddress *paddr) { return socket_->Accept(paddr); }
+ virtual int Close() { return socket_->Close(); }
+ virtual int GetError() const { return socket_->GetError(); }
+ virtual void SetError(int error) { return socket_->SetError(error); }
+
+ virtual ConnState GetState() const { return socket_->GetState(); }
+
+ virtual int EstimateMTU(uint16* mtu) { return socket_->EstimateMTU(mtu); }
+ virtual int SetOption(Option opt, int value) { return socket_->SetOption(opt, value); }
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket) { SignalConnectEvent(this); }
+ virtual void OnReadEvent(AsyncSocket * socket) { SignalReadEvent(this); }
+ virtual void OnWriteEvent(AsyncSocket * socket) { SignalWriteEvent(this); }
+ virtual void OnCloseEvent(AsyncSocket * socket, int err) { SignalCloseEvent(this, err); }
+
+ Socket * socket_;
+};
+
+} // namespace cricket
+
+#endif // __ASYNCSOCKET_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc
new file mode 100644
index 00000000..6d4697a6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc
@@ -0,0 +1,197 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/asynctcpsocket.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+const size_t MAX_PACKET_SIZE = 64 * 1024;
+
+typedef uint16 PacketLength;
+const size_t PKT_LEN_SIZE = sizeof(PacketLength);
+
+const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
+
+AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) {
+ inbuf_ = new char[insize_];
+ outbuf_ = new char[outsize_];
+
+ ASSERT(socket_ != NULL);
+ socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent);
+ socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent);
+ socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent);
+ socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent);
+}
+
+AsyncTCPSocket::~AsyncTCPSocket() {
+ delete [] inbuf_;
+ delete [] outbuf_;
+}
+
+int AsyncTCPSocket::Send(const void *pv, size_t cb) {
+ if (cb > MAX_PACKET_SIZE) {
+ socket_->SetError(EMSGSIZE);
+ return -1;
+ }
+
+ // If we are blocking on send, then silently drop this packet
+ if (outpos_)
+ return static_cast<int>(cb);
+
+ PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
+ memcpy(outbuf_, &pkt_len, PKT_LEN_SIZE);
+ memcpy(outbuf_ + PKT_LEN_SIZE, pv, cb);
+ outpos_ = PKT_LEN_SIZE + cb;
+
+ int res = Flush();
+ if (res <= 0) {
+ // drop packet if we made no progress
+ outpos_ = 0;
+ return res;
+ }
+
+ // We claim to have sent the whole thing, even if we only sent partial
+ return static_cast<int>(cb);
+}
+
+int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ if (addr == GetRemoteAddress())
+ return Send(pv, cb);
+
+ ASSERT(false);
+ socket_->SetError(ENOTCONN);
+ return -1;
+}
+
+int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) {
+ if (outpos_ + cb > outsize_) {
+ socket_->SetError(EMSGSIZE);
+ return -1;
+ }
+
+ memcpy(outbuf_ + outpos_, pv, cb);
+ outpos_ += cb;
+
+ return Flush();
+}
+
+void AsyncTCPSocket::ProcessInput(char * data, size_t& len) {
+ SocketAddress remote_addr(GetRemoteAddress());
+
+ while (true) {
+ if (len < PKT_LEN_SIZE)
+ return;
+
+ PacketLength pkt_len;
+ memcpy(&pkt_len, data, PKT_LEN_SIZE);
+ pkt_len = NetworkToHost16(pkt_len);
+
+ if (len < PKT_LEN_SIZE + pkt_len)
+ return;
+
+ SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this);
+
+ len -= PKT_LEN_SIZE + pkt_len;
+ if (len > 0) {
+ memmove(data, data + PKT_LEN_SIZE + pkt_len, len);
+ }
+ }
+}
+
+int AsyncTCPSocket::Flush() {
+ int res = socket_->Send(outbuf_, outpos_);
+ if (res <= 0) {
+ return res;
+ }
+ if (static_cast<size_t>(res) <= outpos_) {
+ outpos_ -= res;
+ } else {
+ ASSERT(false);
+ return -1;
+ }
+ if (outpos_ > 0) {
+ memmove(outbuf_, outbuf_ + res, outpos_);
+ }
+ return res;
+}
+
+void AsyncTCPSocket::OnConnectEvent(AsyncSocket* socket) {
+ SignalConnect(this);
+}
+
+void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+
+ int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ LOG(INFO) << "recvfrom: " << errno << " " << std::strerror(errno);
+ return;
+ }
+
+ inpos_ += len;
+
+ ProcessInput(inbuf_, inpos_);
+
+ if (inpos_ >= insize_) {
+ LOG(INFO) << "input buffer overflow";
+ ASSERT(false);
+ inpos_ = 0;
+ }
+}
+
+void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+
+ if (outpos_ > 0) {
+ Flush();
+ }
+}
+
+void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) {
+ SignalClose(this, error);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h
new file mode 100644
index 00000000..e93e5e7d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h
@@ -0,0 +1,68 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASYNCTCPSOCKET_H__
+#define __ASYNCTCPSOCKET_H__
+
+#include "talk/base/asyncpacketsocket.h"
+
+namespace cricket {
+
+// Simulates UDP semantics over TCP. Send and Recv packet sizes
+// are preserved, and drops packets silently on Send, rather than
+// buffer them in user space.
+class AsyncTCPSocket : public AsyncPacketSocket {
+public:
+ AsyncTCPSocket(AsyncSocket* socket);
+ virtual ~AsyncTCPSocket();
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+
+ sigslot::signal1<AsyncTCPSocket*> SignalConnect;
+ sigslot::signal2<AsyncTCPSocket*,int> SignalClose;
+
+protected:
+ int SendRaw(const void * pv, size_t cb);
+ virtual void ProcessInput(char * data, size_t& len);
+
+private:
+ char* inbuf_, * outbuf_;
+ size_t insize_, inpos_, outsize_, outpos_;
+
+ int Flush();
+
+ // Called by the underlying socket
+ void OnConnectEvent(AsyncSocket* socket);
+ void OnReadEvent(AsyncSocket* socket);
+ void OnWriteEvent(AsyncSocket* socket);
+ void OnCloseEvent(AsyncSocket* socket, int error);
+};
+
+} // namespace cricket
+
+#endif // __ASYNCSTCPOCKET_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc
new file mode 100644
index 00000000..5b8c2466
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc
@@ -0,0 +1,83 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/logging.h"
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+const int BUF_SIZE = 64 * 1024;
+
+AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket) {
+ size_ = BUF_SIZE;
+ buf_ = new char[size_];
+
+ assert(socket_);
+ // The socket should start out readable but not writable.
+ socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
+}
+
+AsyncUDPSocket::~AsyncUDPSocket() {
+ delete [] buf_;
+}
+
+void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
+ assert(socket == socket_);
+
+ SocketAddress remote_addr;
+ int len = socket_->RecvFrom(buf_, size_, &remote_addr);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ PLOG(LS_ERROR, socket_->GetError()) << "recvfrom";
+ return;
+ }
+
+ // TODO: Make sure that we got all of the packet. If we did not, then we
+ // should resize our buffer to be large enough.
+
+ SignalReadPacket(buf_, (size_t)len, remote_addr, this);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h
new file mode 100644
index 00000000..7fac7713
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h
@@ -0,0 +1,59 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASYNCUDPSOCKET_H__
+#define __ASYNCUDPSOCKET_H__
+
+#include "talk/base/asyncpacketsocket.h"
+#include "talk/base/socketfactory.h"
+
+namespace cricket {
+
+// Provides the ability to receive packets asynchronously. Sends are not
+// buffered since it is acceptable to drop packets under high load.
+class AsyncUDPSocket : public AsyncPacketSocket {
+public:
+ AsyncUDPSocket(AsyncSocket* socket);
+ virtual ~AsyncUDPSocket();
+
+private:
+ char* buf_;
+ size_t size_;
+
+ // Called when the underlying socket is ready to be read from.
+ void OnReadEvent(AsyncSocket* socket);
+};
+
+// Creates a new socket for sending asynchronous UDP packets using an
+// asynchronous socket from the given factory.
+inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) {
+ return new AsyncUDPSocket(factory->CreateAsyncSocket(SOCK_DGRAM));
+}
+
+} // namespace cricket
+
+#endif // __ASYNCSUDPOCKET_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc
new file mode 100644
index 00000000..e0ec1b90
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc
@@ -0,0 +1,194 @@
+
+//*********************************************************************
+//* Base64 - a simple base64 encoder and decoder.
+//*
+//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
+//*
+//* This code may be freely used for any purpose, either personal
+//* or commercial, provided the authors copyright notice remains
+//* intact.
+//*
+//* Enhancements by Stanley Yamane:
+//* o reverse lookup table for the decode function
+//* o reserve string buffer space in advance
+//*
+//*********************************************************************
+
+#include "talk/base/base64.h"
+
+using namespace std;
+
+static const char fillchar = '=';
+static const string::size_type np = string::npos;
+
+const string Base64::Base64Table(
+ // 0000000000111111111122222222223333333333444444444455555555556666
+ // 0123456789012345678901234567890123456789012345678901234567890123
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+
+// Decode Table gives the index of any valid base64 character in the Base64 table]
+// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
+
+ // 0 1 2 3 4 5 6 7 8 9
+const string::size_type Base64::DecodeTable[] = {
+ np,np,np,np,np,np,np,np,np,np, // 0 - 9
+ np,np,np,np,np,np,np,np,np,np, //10 -19
+ np,np,np,np,np,np,np,np,np,np, //20 -29
+ np,np,np,np,np,np,np,np,np,np, //30 -39
+ np,np,np,62,np,np,np,63,52,53, //40 -49
+ 54,55,56,57,58,59,60,61,np,np, //50 -59
+ np,np,np,np,np, 0, 1, 2, 3, 4, //60 -69
+ 5, 6, 7, 8, 9,10,11,12,13,14, //70 -79
+ 15,16,17,18,19,20,21,22,23,24, //80 -89
+ 25,np,np,np,np,np,np,26,27,28, //90 -99
+ 29,30,31,32,33,34,35,36,37,38, //100 -109
+ 39,40,41,42,43,44,45,46,47,48, //110 -119
+ 49,50,51,np,np,np,np,np,np,np, //120 -129
+ np,np,np,np,np,np,np,np,np,np, //130 -139
+ np,np,np,np,np,np,np,np,np,np, //140 -149
+ np,np,np,np,np,np,np,np,np,np, //150 -159
+ np,np,np,np,np,np,np,np,np,np, //160 -169
+ np,np,np,np,np,np,np,np,np,np, //170 -179
+ np,np,np,np,np,np,np,np,np,np, //180 -189
+ np,np,np,np,np,np,np,np,np,np, //190 -199
+ np,np,np,np,np,np,np,np,np,np, //200 -209
+ np,np,np,np,np,np,np,np,np,np, //210 -219
+ np,np,np,np,np,np,np,np,np,np, //220 -229
+ np,np,np,np,np,np,np,np,np,np, //230 -239
+ np,np,np,np,np,np,np,np,np,np, //240 -249
+ np,np,np,np,np,np //250 -256
+};
+
+string Base64::encodeFromArray(const char * data, size_t len) {
+ size_t i;
+ char c;
+ string ret;
+
+ ret.reserve(len * 2);
+
+ for (i = 0; i < len; ++i)
+ {
+ c = (data[i] >> 2) & 0x3f;
+ ret.append(1, Base64Table[c]);
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 4) & 0x0f;
+
+ ret.append(1, Base64Table[c]);
+ if (i < len)
+ {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 6) & 0x03;
+
+ ret.append(1, Base64Table[c]);
+ }
+ else
+ {
+ ++i;
+ ret.append(1, fillchar);
+ }
+
+ if (i < len)
+ {
+ c = data[i] & 0x3f;
+ ret.append(1, Base64Table[c]);
+ }
+ else
+ {
+ ret.append(1, fillchar);
+ }
+ }
+
+ return(ret);
+}
+
+
+string Base64::encode(const string& data)
+{
+ string::size_type i;
+ char c;
+ string::size_type len = data.length();
+ string ret;
+
+ ret.reserve(len * 2);
+
+ for (i = 0; i < len; ++i)
+ {
+ c = (data[i] >> 2) & 0x3f;
+ ret.append(1, Base64Table[c]);
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 4) & 0x0f;
+
+ ret.append(1, Base64Table[c]);
+ if (i < len)
+ {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 6) & 0x03;
+
+ ret.append(1, Base64Table[c]);
+ }
+ else
+ {
+ ++i;
+ ret.append(1, fillchar);
+ }
+
+ if (i < len)
+ {
+ c = data[i] & 0x3f;
+ ret.append(1, Base64Table[c]);
+ }
+ else
+ {
+ ret.append(1, fillchar);
+ }
+ }
+
+ return(ret);
+}
+
+string Base64::decode(const string& data)
+{
+ string::size_type i;
+ char c;
+ char c1;
+ string::size_type len = data.length();
+ string ret;
+
+ ret.reserve(len);
+
+ for (i = 0; i < len; ++i)
+ {
+ c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ ++i;
+ c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ c = (c << 2) | ((c1 >> 4) & 0x3);
+ ret.append(1, c);
+ if (++i < len)
+ {
+ c = data[i];
+ if (fillchar == c)
+ break;
+
+ c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
+ ret.append(1, c1);
+ }
+
+ if (++i < len)
+ {
+ c1 = data[i];
+ if (fillchar == c1)
+ break;
+
+ c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ c = ((c << 6) & 0xc0) | c1;
+ ret.append(1, c);
+ }
+ }
+
+ return(ret);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h
new file mode 100644
index 00000000..4622b329
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h
@@ -0,0 +1,29 @@
+
+//*********************************************************************
+//* C_Base64 - a simple base64 encoder and decoder.
+//*
+//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
+//*
+//* This code may be freely used for any purpose, either personal
+//* or commercial, provided the authors copyright notice remains
+//* intact.
+//*********************************************************************
+
+#ifndef Base64_H
+#define Base64_H
+
+#include <string>
+using std::string; // comment if your compiler doesn't use namespaces
+
+class Base64
+{
+public:
+ static string encode(const string & data);
+ static string decode(const string & data);
+ static string encodeFromArray(const char * data, size_t len);
+private:
+ static const string Base64Table;
+ static const string::size_type DecodeTable[];
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h
new file mode 100644
index 00000000..171bc9f9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h
@@ -0,0 +1,53 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASICDEFS_H__
+#define __BASICDEFS_H__
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+// Used in GUI when referring to the product name (& Version Resource Product Name)
+#define PRODUCT_NAME "Google Talk"
+
+// Used in GUI when referring to the publisher of the product
+#define COMPANY_NAME "Google"
+
+// Used in filenames, directories, registry key names, etc to refer to the product
+#define DIRECTORY_NAME "Google Talk"
+
+// Used in URLs, registry values, etc, where we prefer not to use a space
+#define PRODUCT_SIGNATURE "googletalk"
+
+// Used whenever we do HTTP
+#define USERAGENT_STRING "Google Talk"
+
+#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
+
+#endif // __BASICDEFS_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h
new file mode 100644
index 00000000..ea393c09
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h
@@ -0,0 +1,85 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASICTYPES_H__
+#define __BASICTYPES_H__
+
+#ifdef COMPILER_MSVC
+typedef __int64 int64;
+#else
+typedef long long int64;
+#endif /* COMPILER_MSVC */
+typedef long int32;
+typedef short int16;
+typedef char int8;
+
+#ifdef COMPILER_MSVC
+typedef unsigned __int64 uint64;
+typedef __int64 int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif /* COMPILER_MSVC */
+typedef unsigned long uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+
+#ifdef WIN32
+typedef int socklen_t;
+#endif
+
+namespace cricket {
+ template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
+ template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
+}
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ DISALLOW_EVIL_CONSTRUCTORS(TypeName)
+
+#ifndef UNUSED
+#define UNUSED(x) Unused(static_cast<const void *>(&x))
+#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
+#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
+#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
+#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
+inline void Unused(const void *) { }
+#endif // UNUSED
+
+#endif // __BASICTYPES_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc
new file mode 100644
index 00000000..067f50ed
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc
@@ -0,0 +1,165 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/basictypes.h"
+#include "talk/base/bytebuffer.h"
+#include "talk/base/byteorder.h"
+#include <algorithm>
+#include <cassert>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::memcpy;
+}
+#endif
+
+namespace cricket {
+
+const int DEFAULT_SIZE = 4096;
+
+ByteBuffer::ByteBuffer() {
+ start_ = 0;
+ end_ = 0;
+ size_ = DEFAULT_SIZE;
+ bytes_ = new char[size_];
+}
+
+ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
+ start_ = 0;
+ end_ = len;
+ size_ = len;
+ bytes_ = new char[size_];
+ memcpy(bytes_, bytes, end_);
+}
+
+ByteBuffer::ByteBuffer(const char* bytes) {
+ start_ = 0;
+ end_ = strlen(bytes);
+ size_ = end_;
+ bytes_ = new char[size_];
+ memcpy(bytes_, bytes, end_);
+}
+
+ByteBuffer::~ByteBuffer() {
+ delete bytes_;
+}
+
+bool ByteBuffer::ReadUInt8(uint8& val) {
+ return ReadBytes(reinterpret_cast<char*>(&val), 1);
+}
+
+bool ByteBuffer::ReadUInt16(uint16& val) {
+ uint16 v;
+ if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
+ return false;
+ } else {
+ val = NetworkToHost16(v);
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadUInt32(uint32& val) {
+ uint32 v;
+ if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
+ return false;
+ } else {
+ val = NetworkToHost32(v);
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadString(std::string& val, size_t len) {
+ if (len > Length()) {
+ return false;
+ } else {
+ val.append(bytes_ + start_, len);
+ start_ += len;
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadBytes(char* val, size_t len) {
+ if (len > Length()) {
+ return false;
+ } else {
+ memcpy(val, bytes_ + start_, len);
+ start_ += len;
+ return true;
+ }
+}
+
+void ByteBuffer::WriteUInt8(uint8 val) {
+ WriteBytes(reinterpret_cast<const char*>(&val), 1);
+}
+
+void ByteBuffer::WriteUInt16(uint16 val) {
+ uint16 v = HostToNetwork16(val);
+ WriteBytes(reinterpret_cast<const char*>(&v), 2);
+}
+
+void ByteBuffer::WriteUInt32(uint32 val) {
+ uint32 v = HostToNetwork32(val);
+ WriteBytes(reinterpret_cast<const char*>(&v), 4);
+}
+
+void ByteBuffer::WriteString(const std::string& val) {
+ WriteBytes(val.c_str(), val.size());
+}
+
+void ByteBuffer::WriteBytes(const char* val, size_t len) {
+ if (Length() + len > Capacity())
+ Resize(Length() + len);
+
+ memcpy(bytes_ + end_, val, len);
+ end_ += len;
+}
+
+void ByteBuffer::Resize(size_t size) {
+ if (size > size_)
+ size = _max(size, 3 * size_ / 2);
+
+ size_t len = _min(end_ - start_, size);
+ char* new_bytes = new char[size];
+ memcpy(new_bytes, bytes_ + start_, len);
+ delete [] bytes_;
+
+ start_ = 0;
+ end_ = len;
+ size_ = size;
+ bytes_ = new_bytes;
+}
+
+void ByteBuffer::Shift(size_t size) {
+ if (size > Length())
+ return;
+
+ end_ = Length() - size;
+ memmove(bytes_, bytes_ + start_ + size, end_);
+ start_ = 0;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h
new file mode 100644
index 00000000..b0a52344
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h
@@ -0,0 +1,71 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BYTEBUFFER_H__
+#define __BYTEBUFFER_H__
+
+#include "talk/base/basictypes.h"
+#include <string>
+
+namespace cricket {
+
+class ByteBuffer {
+public:
+ ByteBuffer();
+ ByteBuffer(const char* bytes, size_t len);
+ ByteBuffer(const char* bytes); // uses strlen
+ ~ByteBuffer();
+
+ const char* Data() const { return bytes_ + start_; }
+ size_t Length() { return end_ - start_; }
+ size_t Capacity() { return size_ - start_; }
+
+ bool ReadUInt8(uint8& val);
+ bool ReadUInt16(uint16& val);
+ bool ReadUInt32(uint32& val);
+ bool ReadString(std::string& val, size_t len); // append to val
+ bool ReadBytes(char* val, size_t len);
+
+ void WriteUInt8(uint8 val);
+ void WriteUInt16(uint16 val);
+ void WriteUInt32(uint32 val);
+ void WriteString(const std::string& val);
+ void WriteBytes(const char* val, size_t len);
+
+ void Resize(size_t size);
+ void Shift(size_t size);
+
+private:
+ char* bytes_;
+ size_t size_;
+ size_t start_;
+ size_t end_;
+};
+
+} // namespace cricket
+
+#endif // __BYTEBUFFER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h
new file mode 100644
index 00000000..4b70f47e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h
@@ -0,0 +1,63 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BYTEORDER_H__
+#define __BYTEORDER_H__
+
+#include "talk/base/basictypes.h"
+
+#ifdef POSIX
+extern "C" {
+#include <arpa/inet.h>
+}
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+namespace cricket {
+
+inline uint16 HostToNetwork16(uint16 n) {
+ return htons(n);
+}
+
+inline uint32 HostToNetwork32(uint32 n) {
+ return htonl(n);
+}
+
+inline uint16 NetworkToHost16(uint16 n) {
+ return ntohs(n);
+}
+
+inline uint32 NetworkToHost32(uint32 n) {
+ return ntohl(n);
+}
+
+} // namespace cricket
+
+#endif // __BYTEORDER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h
new file mode 100644
index 00000000..b21be2f1
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h
@@ -0,0 +1,231 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _common_h_
+#define _common_h_
+
+#if defined(_MSC_VER)
+// warning C4355: 'this' : used in base member initializer list
+#pragma warning(disable:4355)
+#endif
+
+#if defined(ENABLE_DEBUG_MALLOC) && !defined(ENABLE_DEBUG)
+#define ENABLE_DEBUG 1
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// General Utilities
+//////////////////////////////////////////////////////////////////////
+
+#ifndef UNUSED
+#define UNUSED(x) Unused(static_cast<const void *>(&x))
+#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
+#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
+#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
+#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
+inline void Unused(const void *) { }
+#endif // UNUSED
+
+#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
+
+/////////////////////////////////////////////////////////////////////////////
+// std:min/std:max on msvc
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
+
+#undef min
+#undef max
+
+namespace std {
+
+
+ /**
+ * @brief This does what you think it does.
+ * @param a A thing of arbitrary type.
+ * @param b Another thing of arbitrary type.
+ * @return The lesser of the parameters.
+ *
+ * This is the simple classic generic implementation. It will work on
+ * temporary expressions, since they are only evaluated once, unlike a
+ * preprocessor macro.
+ */
+ template<typename _Tp>
+ inline const _Tp&
+ min(const _Tp& __a, const _Tp& __b)
+ {
+ //return __b < __a ? __b : __a;
+ if (__b < __a) return __b; return __a;
+ }
+
+ /**
+ * @brief This does what you think it does.
+ * @param a A thing of arbitrary type.
+ * @param b Another thing of arbitrary type.
+ * @return The greater of the parameters.
+ *
+ * This is the simple classic generic implementation. It will work on
+ * temporary expressions, since they are only evaluated once, unlike a
+ * preprocessor macro.
+ */
+ template<typename _Tp>
+ inline const _Tp&
+ max(const _Tp& __a, const _Tp& __b)
+ {
+ //return __a < __b ? __b : __a;
+ if (__a < __b) return __b; return __a;
+ }
+
+ /**
+ * @brief This does what you think it does.
+ * @param a A thing of arbitrary type.
+ * @param b Another thing of arbitrary type.
+ * @param comp A @link s20_3_3_comparisons comparison functor@endlink.
+ * @return The lesser of the parameters.
+ *
+ * This will work on temporary expressions, since they are only evaluated
+ * once, unlike a preprocessor macro.
+ */
+ template<typename _Tp, typename _Compare>
+ inline const _Tp&
+ min(const _Tp& __a, const _Tp& __b, _Compare __comp)
+ {
+ //return __comp(__b, __a) ? __b : __a;
+ if (__comp(__b, __a)) return __b; return __a;
+ }
+
+ /**
+ * @brief This does what you think it does.
+ * @param a A thing of arbitrary type.
+ * @param b Another thing of arbitrary type.
+ * @param comp A @link s20_3_3_comparisons comparison functor@endlink.
+ * @return The greater of the parameters.
+ *
+ * This will work on temporary expressions, since they are only evaluated
+ * once, unlike a preprocessor macro.
+ */
+ template<typename _Tp, typename _Compare>
+ inline const _Tp&
+ max(const _Tp& __a, const _Tp& __b, _Compare __comp)
+ {
+ //return __comp(__a, __b) ? __b : __a;
+ if (__comp(__a, __b)) return __b; return __a;
+ }
+
+}
+
+#endif // _MSC_VER <= 1200
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Assertions
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef ENABLE_DEBUG
+
+namespace buzz {
+
+// Break causes the debugger to stop executing, or the program to abort
+void Break();
+
+// LogAssert writes information about an assertion to the log
+void LogAssert(const char * function, const char * file, int line, const char * expression);
+
+inline void Assert(bool result, const char * function, const char * file, int line, const char * expression) {
+ if (!result) {
+ LogAssert(function, file, line, expression);
+ Break();
+ }
+}
+
+}; // namespace buzz
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#define __FUNCTION__ ""
+#endif
+
+#define ASSERT(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
+#define VERIFY(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
+
+#else // !ENABLE_DEBUG
+
+#define ASSERT(x) (void)0
+#define VERIFY(x) (void)(x)
+
+#endif // !ENABLE_DEBUG
+
+#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr]
+#define CTA_UNIQUE_NAME MAKE_NAME(__LINE__)
+#define CTA_MAKE_NAME(line) MAKE_NAME2(line)
+#define CTA_MAKE_NAME2(line) constraint_ ## line
+
+//////////////////////////////////////////////////////////////////////
+// Memory leak tracking
+//////////////////////////////////////////////////////////////////////
+
+#include <sys/types.h>
+
+#ifdef ENABLE_DEBUG_MALLOC
+
+namespace buzz {
+
+void * DebugAllocate(size_t size, const char * fname = 0, int line = 0);
+void DebugDeallocate(void * ptr, const char * fname = 0, int line = 0);
+bool LeakCheck();
+bool LeakCheckU();
+void LeakMarkBaseline();
+void LeakClearBaseline();
+
+}; // namespace buzz
+
+inline void * operator new(size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); }
+inline void operator delete(void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); }
+
+#if !(defined(TRACK_ARRAY_ALLOC_PROBLEM) && \
+ defined(_MSC_VER) && _MSC_VER <= 1200) // 1200 == VC++ 6.0
+
+inline void * operator new[](size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); }
+inline void operator delete[](void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); }
+
+#endif // TRACK_ARRAY_ALLOC_PROBLEM
+
+
+// If you put "#define new TRACK_NEW" in your .cc file after all includes, it should track the calling function name
+
+#define TRACK_NEW new(__FILE__,__LINE__)
+#define TRACK_DEL delete(__FILE__,__LINE__)
+
+#else // !ENABLE_DEBUG_MALLOC
+
+#define TRACK_NEW new
+#define TRACK_DEL delete
+
+#endif // !ENABLE_DEBUG_MALLOC
+
+//////////////////////////////////////////////////////////////////////
+
+#endif // _common_h_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h
new file mode 100644
index 00000000..b75ad5c7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h
@@ -0,0 +1,120 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _criticalsection_h_
+#define _criticalsection_h_
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+#ifdef POSIX
+#include <pthread.h>
+#endif
+
+#ifdef _DEBUG
+#define CS_TRACK_OWNER 1
+#endif // _DEBUG
+
+#if CS_TRACK_OWNER
+#define TRACK_OWNER(x) x
+#else // !CS_TRACK_OWNER
+#define TRACK_OWNER(x)
+#endif // !CS_TRACK_OWNER
+
+namespace cricket {
+
+#ifdef WIN32
+class CriticalSection {
+public:
+ CriticalSection() {
+ InitializeCriticalSection(&crit_);
+ // Windows docs say 0 is not a valid thread id
+ TRACK_OWNER(thread_ = 0);
+ }
+ ~CriticalSection() {
+ DeleteCriticalSection(&crit_);
+ }
+ void Enter() {
+ EnterCriticalSection(&crit_);
+ TRACK_OWNER(thread_ = GetCurrentThreadId());
+ }
+ void Leave() {
+ TRACK_OWNER(thread_ = 0);
+ LeaveCriticalSection(&crit_);
+ }
+
+#if CS_TRACK_OWNER
+ bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
+#endif // CS_TRACK_OWNER
+
+private:
+ CRITICAL_SECTION crit_;
+ TRACK_OWNER(DWORD thread_); // The section's owning thread id
+};
+#endif // WIN32
+
+#ifdef POSIX
+class CriticalSection {
+public:
+ CriticalSection() {
+ pthread_mutexattr_t mutex_attribute;
+ pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mutex_, &mutex_attribute);
+ }
+ ~CriticalSection() {
+ pthread_mutex_destroy(&mutex_);
+ }
+ void Enter() {
+ pthread_mutex_lock(&mutex_);
+ }
+ void Leave() {
+ pthread_mutex_unlock(&mutex_);
+ }
+private:
+ pthread_mutex_t mutex_;
+};
+#endif // POSIX
+
+// CritScope, for serializing exection through a scope
+
+class CritScope {
+public:
+ CritScope(CriticalSection *pcrit) {
+ pcrit_ = pcrit;
+ pcrit_->Enter();
+ }
+ ~CritScope() {
+ pcrit_->Leave();
+ }
+private:
+ CriticalSection *pcrit_;
+};
+
+} // namespace cricket
+
+#endif // _criticalsection_h_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc
new file mode 100644
index 00000000..7b7490d9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc
@@ -0,0 +1,99 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/host.h"
+#include "talk/base/logging.h"
+#include "talk/base/network.h"
+#include "talk/base/socket.h"
+#include <string>
+#include <iostream>
+#include <cassert>
+#include <errno.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+ using ::exit;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <sys/utsname.h>
+}
+#endif // POSIX
+
+namespace {
+
+void FatalError(const std::string& name, int err) {
+ PLOG(LERROR, err) << name;
+ std::exit(1);
+}
+
+}
+
+namespace cricket {
+
+#ifdef POSIX
+std::string GetHostName() {
+ struct utsname nm;
+ if (uname(&nm) < 0)
+ FatalError("uname", errno);
+ return std::string(nm.nodename);
+}
+#endif
+
+#ifdef WIN32
+std::string GetHostName() {
+ // TODO: fix this
+ return "cricket";
+}
+#endif
+
+// Records information about the local host.
+Host* gLocalHost = 0;
+
+const Host& LocalHost() {
+ if (!gLocalHost) {
+ std::vector<Network*>* networks = new std::vector<Network*>;
+ NetworkManager::CreateNetworks(*networks);
+#ifdef WIN32
+ // This is sort of problematic... one part of the code (the unittests) wants
+ // 127.0.0.1 to be present and another part (port allocators) don't. Right
+ // now, they use different APIs, so we can have different behavior. But
+ // there is something wrong with this.
+ networks->push_back(new Network("localhost",
+ SocketAddress::StringToIP("127.0.0.1")));
+#endif
+ gLocalHost = new Host(GetHostName(), networks);
+ assert(gLocalHost->networks().size() > 0);
+ }
+
+ return *gLocalHost;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.h
new file mode 100644
index 00000000..16f31a78
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.h
@@ -0,0 +1,59 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HOST_H__
+#define __HOST_H__
+
+#include "talk/base/network.h"
+#include <string>
+#include <vector>
+
+namespace cricket {
+
+// Provides information about a host in the network.
+class Host {
+public:
+ Host(const std::string& name, std::vector<Network*>* networks)
+ : name_(name), networks_(networks) { }
+
+ const std::string& name() const { return name_; }
+ const std::vector<Network*>& networks() const { return *networks_; }
+
+private:
+ std::string name_;
+ std::vector<Network*>* networks_;
+};
+
+// Returns a reference to the description of the local host.
+const Host& LocalHost();
+
+// Returns the name of the local host.
+std::string GetHostName();
+
+} // namespace cricket
+
+#endif // __HOST_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc
new file mode 100644
index 00000000..5befe9fd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc
@@ -0,0 +1,77 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/jtime.h"
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+
+namespace cricket {
+
+#ifdef POSIX
+#include <sys/time.h>
+uint32 Time() {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+uint32 Time() {
+ return GetTickCount();
+}
+#endif
+
+bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier) {
+ if (earlier <= later) {
+ return ((earlier <= middle) && (middle <= later));
+ } else {
+ return !((later < middle) && (middle < earlier));
+ }
+}
+
+int32 TimeDiff(uint32 later, uint32 earlier) {
+ uint32 LAST = 0xFFFFFFFF;
+ uint32 HALF = 0x80000000;
+ if (TimeIsBetween(earlier + HALF, later, earlier)) {
+ if (earlier <= later) {
+ return static_cast<long>(later - earlier);
+ } else {
+ return static_cast<long>(later + (LAST - earlier) + 1);
+ }
+ } else {
+ if (later <= earlier) {
+ return -static_cast<long>(earlier - later);
+ } else {
+ return -static_cast<long>(earlier + (LAST - later) + 1);
+ }
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h
new file mode 100644
index 00000000..d7dff0fb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h
@@ -0,0 +1,47 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __JTIME_H__
+#define __JTIME_H__
+
+#include "talk/base/basictypes.h"
+
+namespace cricket {
+
+// Returns the current time in milliseconds.
+uint32 Time();
+
+// TODO: Delete this old version.
+#define GetMillisecondCount Time
+
+// Comparisons between time values, which can wrap around.
+bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier);
+int32 TimeDiff(uint32 later, uint32 earlier);
+
+} // namespace cricket
+
+#endif // __TIME_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h
new file mode 100644
index 00000000..94b62ad3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h
@@ -0,0 +1,138 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * linked_ptr - simple reference linked pointer
+ * (like reference counting, just using a linked list of the references
+ * instead of their count.)
+ *
+ * The implementation stores three pointers for every linked_ptr, but
+ * does not allocate anything on the free store.
+ */
+
+#ifndef _LINKED_PTR_H_
+#define _LINKED_PTR_H_
+
+/* For ANSI-challenged compilers, you may want to #define
+ * NO_MEMBER_TEMPLATES, explicit or mutable */
+#define NO_MEMBER_TEMPLATES
+
+template <class X> class linked_ptr
+{
+public:
+
+#ifndef NO_MEMBER_TEMPLATES
+# define TEMPLATE_FUNCTION template <class Y>
+ TEMPLATE_FUNCTION friend class linked_ptr<Y>;
+#else
+# define TEMPLATE_FUNCTION
+ typedef X Y;
+#endif
+
+ typedef X element_type;
+
+ explicit linked_ptr(X* p = 0) throw()
+ : itsPtr(p) {itsPrev = itsNext = this;}
+ ~linked_ptr()
+ {release();}
+ linked_ptr(const linked_ptr& r) throw()
+ {acquire(r);}
+ linked_ptr& operator=(const linked_ptr& r)
+ {
+ if (this != &r) {
+ release();
+ acquire(r);
+ }
+ return *this;
+ }
+
+#ifndef NO_MEMBER_TEMPLATES
+ template <class Y> friend class linked_ptr<Y>;
+ template <class Y> linked_ptr(const linked_ptr<Y>& r) throw()
+ {acquire(r);}
+ template <class Y> linked_ptr& operator=(const linked_ptr<Y>& r)
+ {
+ if (this != &r) {
+ release();
+ acquire(r);
+ }
+ return *this;
+ }
+#endif // NO_MEMBER_TEMPLATES
+
+ X& operator*() const throw() {return *itsPtr;}
+ X* operator->() const throw() {return itsPtr;}
+ X* get() const throw() {return itsPtr;}
+ bool unique() const throw() {return itsPrev ? itsPrev==this : true;}
+
+private:
+ X* itsPtr;
+ mutable const linked_ptr* itsPrev;
+ mutable const linked_ptr* itsNext;
+
+ void acquire(const linked_ptr& r) throw()
+ { // insert this to the list
+ itsPtr = r.itsPtr;
+ itsNext = r.itsNext;
+ itsNext->itsPrev = this;
+ itsPrev = &r;
+#ifndef mutable
+ r.itsNext = this;
+#else // for ANSI-challenged compilers
+ (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
+#endif
+ }
+
+#ifndef NO_MEMBER_TEMPLATES
+ template <class Y> void acquire(const linked_ptr<Y>& r) throw()
+ { // insert this to the list
+ itsPtr = r.itsPtr;
+ itsNext = r.itsNext;
+ itsNext->itsPrev = this;
+ itsPrev = &r;
+#ifndef mutable
+ r.itsNext = this;
+#else // for ANSI-challenged compilers
+ (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
+#endif
+ }
+#endif // NO_MEMBER_TEMPLATES
+
+ void release()
+ { // erase this from the list, delete if unique
+ if (unique()) delete itsPtr;
+ else {
+ itsPrev->itsNext = itsNext;
+ itsNext->itsPrev = itsPrev;
+ itsPrev = itsNext = 0;
+ }
+ itsPtr = 0;
+ }
+};
+
+#endif // LINKED_PTR_H
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h
new file mode 100644
index 00000000..500386ed
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h
@@ -0,0 +1,222 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// LOG(...) an ostream target that can be used to send formatted
+// output to a variety of logging targets, such as debugger console, stderr,
+// file, or any StreamInterface.
+// The severity level passed as the first argument to the the LOGging
+// functions is used as a filter, to limit the verbosity of the logging.
+// Static members of LogMessage documented below are used to control the
+// verbosity and target of the output.
+// There are several variations on the LOG macro which facilitate logging
+// of common error conditions, detailed below.
+
+#ifndef TALK_BASE_LOGGING_H__
+#define TALK_BASE_LOGGING_H__
+
+#include <sstream>
+#include "talk/base/basictypes.h"
+class StreamInterface;
+
+///////////////////////////////////////////////////////////////////////////////
+// ConstantLabel can be used to easily generate string names from constant
+// values. This can be useful for logging descriptive names of error messages.
+// Usage:
+// const ConstantLabel LIBRARY_ERRORS[] = {
+// KLABEL(SOME_ERROR),
+// KLABEL(SOME_OTHER_ERROR),
+// ...
+// LASTLABEL
+// }
+//
+// int err = LibraryFunc();
+// LOG(LS_ERROR) << "LibraryFunc returned: "
+// << ErrorName(err, LIBRARY_ERRORS);
+
+struct ConstantLabel { int value; const char * label; };
+#define KLABEL(x) { x, #x }
+#define TLABEL(x,y) { x, y }
+#define LASTLABEL { 0, 0 }
+
+const char * FindLabel(int value, const ConstantLabel entries[]);
+std::string ErrorName(int err, const ConstantLabel * err_table);
+
+//////////////////////////////////////////////////////////////////////
+
+// Note that the non-standard LoggingSeverity aliases exist because they are
+// still in broad use. The meanings of the levels are:
+// LS_SENSITIVE: Information which should only be logged with the consent
+// of the user, due to privacy concerns.
+// LS_VERBOSE: This level is for data which we do not want to appear in the
+// normal debug log, but should appear in diagnostic logs.
+// LS_INFO: Chatty level used in debugging for all sorts of things, the default
+// in debug builds.
+// LS_WARNING: Something that may warrant investigation.
+// LS_ERROR: Something that should not have occurred.
+enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR,
+ INFO = LS_INFO,
+ WARNING = LS_WARNING,
+ LERROR = LS_ERROR };
+
+// LogErrorContext assists in interpreting the meaning of an error value.
+// ERRCTX_ERRNO: the value was read from global 'errno'
+// ERRCTX_HRESULT: the value is a Windows HRESULT
+enum LogErrorContext { ERRCTX_NONE, ERRCTX_ERRNO, ERRCTX_HRESULT };
+
+// If LOGGING is not explicitly defined, default to enabled in debug mode
+#if !defined(LOGGING)
+#if defined(_DEBUG) && !defined(NDEBUG)
+#define LOGGING 1
+#else
+#define LOGGING 0
+#endif
+#endif // !defined(LOGGING)
+
+#if LOGGING
+
+#define LOG(sev) \
+ if (LogMessage::Loggable(sev)) \
+ LogMessage(__FILE__, __LINE__, sev).stream()
+
+// PLOG and LOG_ERR attempt to provide a string description of an errno derived
+// error. LOG_ERR reads errno directly, so care must be taken to call it before
+// errno is reset.
+#define PLOG(sev, err) \
+ if (LogMessage::Loggable(sev)) \
+ LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, err).stream()
+#define LOG_ERR(sev) \
+ if (LogMessage::Loggable(sev)) \
+ LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, errno).stream()
+
+// LOG_GLE(M) attempt to provide a string description of the HRESULT returned
+// by GetLastError. The second variant allows searching of a dll's string
+// table for the error description.
+#ifdef WIN32
+#define LOG_GLE(sev) \
+ if (LogMessage::Loggable(sev)) \
+ LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError()).stream()
+#define LOG_GLEM(sev, mod) \
+ if (LogMessage::Loggable(sev)) \
+ LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError(), mod) \
+ .stream()
+#endif // WIN32
+
+// TODO: Add an "assert" wrapper that logs in the same manner.
+
+#else // !LOGGING
+
+// Hopefully, the compiler will optimize away some of this code.
+// Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++,
+// converted to "while (false)"
+#define LOG(sev) \
+ while (false) LogMessage(NULL, 0, sev).stream()
+#define PLOG(sev, err) \
+ while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream()
+#define LOG_ERR(sev) \
+ while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream()
+#ifdef WIN32
+#define LOG_GLE(sev) \
+ while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream()
+#define LOG_GLEM(sev, mod) \
+ while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream()
+#endif // WIN32
+
+#endif // !LOGGING
+
+class LogMessage {
+ public:
+ LogMessage(const char* file, int line, LoggingSeverity sev,
+ LogErrorContext err_ctx = ERRCTX_NONE, int err = 0,
+ const char* module = NULL);
+ ~LogMessage();
+
+ static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); }
+ std::ostream& stream() { return print_stream_; }
+
+ enum { NO_LOGGING = LS_ERROR + 1 };
+
+ // These are attributes which apply to all logging channels
+ // LogContext: Display the file and line number of the message
+ static void LogContext(int min_sev);
+ // LogThreads: Display the thread identifier of the current thread
+ static void LogThreads(bool on = true);
+ // LogTimestamps: Display the elapsed time of the program
+ static void LogTimestamps(bool on = true);
+
+ // Timestamps begin with program execution, but can be reset with this
+ // function for measuring the duration of an activity, or to synchronize
+ // timestamps between multiple instances.
+ static void ResetTimestamps();
+
+ // These are the available logging channels
+ // Debug: Debug console on Windows, otherwise stderr
+ static void LogToDebug(int min_sev);
+ static int GetLogToDebug() { return dbg_sev_; }
+ // Stream: Any non-blocking stream interface. LogMessage takes ownership of
+ // the stream.
+ static void LogToStream(StreamInterface* stream, int min_sev);
+ static int GetLogToStream() { return stream_sev_; }
+
+ // Testing against MinLogSeverity allows code to avoid potentially expensive
+ // logging operations by pre-checking the logging level.
+ static int GetMinLogSeverity() { return min_sev_; }
+
+ private:
+ // These assist in formatting some parts of the debug output.
+ static const char* Describe(LoggingSeverity sev);
+ static const char* DescribeFile(const char* file);
+
+ // The ostream that buffers the formatted message before output
+ std::ostringstream print_stream_;
+
+ // The severity level of this message
+ LoggingSeverity severity_;
+
+ // String data generated in the constructor, that should be appended to
+ // the message before output.
+ std::string extra_;
+
+ // dbg_sev_ and stream_sev_ are the thresholds for those output targets
+ // min_sev_ is the minimum (most verbose) of those levels, and is used
+ // as a short-circuit in the logging macros to identify messages that won't
+ // be logged.
+ // ctx_sev_ is the minimum level at which file context is displayed
+ static int min_sev_, dbg_sev_, stream_sev_, ctx_sev_;
+
+ // The output stream, if any
+ static StreamInterface * stream_;
+
+ // Flags for formatting options
+ static bool thread_, timestamp_;
+
+ // The timestamp at which logging started.
+ static uint32 start_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(LogMessage);
+};
+
+#endif // TALK_BASE_LOGGING_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h
new file mode 100644
index 00000000..c2e22cc5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h
@@ -0,0 +1,45 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef long unsigned int uint32;
+typedef struct MD5Context MD5_CTX;
+
+#define md5byte unsigned char
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ uint32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !MD5_H */
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c
new file mode 100644
index 00000000..eb2c034d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c
@@ -0,0 +1,256 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+ ((unsigned)buf[1]<<8 | buf[0]);
+ *(uint32 *)buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = (unsigned char *)ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = (unsigned char*)(ctx->in) + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
+ ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ byteReverse((unsigned char *)ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc
new file mode 100644
index 00000000..f10489f7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc
@@ -0,0 +1,321 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/messagequeue.h"
+#include "talk/base/physicalsocketserver.h"
+
+#ifdef POSIX
+extern "C" {
+#include <sys/time.h>
+}
+#endif
+
+namespace cricket {
+
+//------------------------------------------------------------------
+// MessageQueueManager
+
+MessageQueueManager* MessageQueueManager::instance_;
+
+MessageQueueManager* MessageQueueManager::Instance() {
+ // Note: This is not thread safe, but it is first called before threads are
+ // spawned.
+ if (!instance_)
+ instance_ = new MessageQueueManager;
+ return instance_;
+}
+
+MessageQueueManager::MessageQueueManager() {
+}
+
+MessageQueueManager::~MessageQueueManager() {
+}
+
+void MessageQueueManager::Add(MessageQueue *message_queue) {
+ CritScope cs(&crit_);
+ message_queues_.push_back(message_queue);
+}
+
+void MessageQueueManager::Remove(MessageQueue *message_queue) {
+ CritScope cs(&crit_);
+ std::vector<MessageQueue *>::iterator iter;
+ iter = std::find(message_queues_.begin(), message_queues_.end(), message_queue);
+ if (iter != message_queues_.end())
+ message_queues_.erase(iter);
+}
+
+void MessageQueueManager::Clear(MessageHandler *handler) {
+ CritScope cs(&crit_);
+ std::vector<MessageQueue *>::iterator iter;
+ for (iter = message_queues_.begin(); iter != message_queues_.end(); iter++)
+ (*iter)->Clear(handler);
+}
+
+//------------------------------------------------------------------
+// MessageQueue
+
+MessageQueue::MessageQueue(SocketServer* ss)
+ : ss_(ss), new_ss(false), fStop_(false), fPeekKeep_(false) {
+ if (!ss_) {
+ new_ss = true;
+ ss_ = new PhysicalSocketServer();
+ }
+ MessageQueueManager::Instance()->Add(this);
+}
+
+MessageQueue::~MessageQueue() {
+ Clear(NULL);
+ if (new_ss)
+ delete ss_;
+ MessageQueueManager::Instance()->Remove(this);
+}
+
+void MessageQueue::set_socketserver(SocketServer* ss) {
+ if (new_ss)
+ delete ss_;
+ new_ss = false;
+ ss_ = ss;
+}
+
+void MessageQueue::Stop() {
+ fStop_ = true;
+ ss_->WakeUp();
+}
+
+bool MessageQueue::IsStopping() {
+ return fStop_;
+}
+
+void MessageQueue::Restart() {
+ fStop_ = false;
+}
+
+bool MessageQueue::Peek(Message *pmsg, int cmsWait) {
+ if (fStop_)
+ return false;
+ if (fPeekKeep_) {
+ *pmsg = msgPeek_;
+ return true;
+ }
+ if (!Get(pmsg, cmsWait))
+ return false;
+ msgPeek_ = *pmsg;
+ fPeekKeep_ = true;
+ return true;
+}
+
+bool MessageQueue::Get(Message *pmsg, int cmsWait) {
+ // Force stopping
+
+ if (fStop_)
+ return false;
+
+ // Return and clear peek if present
+ // Always return the peek if it exists so there is Peek/Get symmetry
+
+ if (fPeekKeep_) {
+ *pmsg = msgPeek_;
+ fPeekKeep_ = false;
+ return true;
+ }
+
+ // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch
+
+ int cmsTotal = cmsWait;
+ int cmsElapsed = 0;
+ uint32 msStart = GetMillisecondCount();
+ uint32 msCurrent = msStart;
+ while (!fStop_) {
+ // Check for sent messages
+
+ ReceiveSends();
+
+ // Check queues
+
+ int cmsDelayNext = -1;
+ {
+ CritScope cs(&crit_);
+
+ // Check for delayed messages that have been triggered
+ // Calc the next trigger too
+
+ while (!dmsgq_.empty()) {
+ if (msCurrent < dmsgq_.top().msTrigger_) {
+ cmsDelayNext = dmsgq_.top().msTrigger_ - msCurrent;
+ break;
+ }
+ msgq_.push(dmsgq_.top().msg_);
+ dmsgq_.pop();
+ }
+
+ // Check for posted events
+
+ if (!msgq_.empty()) {
+ *pmsg = msgq_.front();
+ msgq_.pop();
+ return true;
+ }
+ }
+
+ // Which is shorter, the delay wait or the asked wait?
+
+ int cmsNext;
+ if (cmsWait == -1) {
+ cmsNext = cmsDelayNext;
+ } else {
+ cmsNext = cmsTotal - cmsElapsed;
+ if (cmsNext < 0)
+ cmsNext = 0;
+ if (cmsDelayNext != -1 && cmsDelayNext < cmsNext)
+ cmsNext = cmsDelayNext;
+ }
+
+ // Wait and multiplex in the meantime
+ ss_->Wait(cmsNext, true);
+
+ // If the specified timeout expired, return
+
+ msCurrent = GetMillisecondCount();
+ cmsElapsed = msCurrent - msStart;
+ if (cmsWait != -1) {
+ if (cmsElapsed >= cmsWait)
+ return false;
+ }
+ }
+ return false;
+}
+
+void MessageQueue::ReceiveSends() {
+}
+
+void MessageQueue::Post(MessageHandler *phandler, uint32 id,
+ MessageData *pdata) {
+ // Keep thread safe
+ // Add the message to the end of the queue
+ // Signal for the multiplexer to return
+
+ CritScope cs(&crit_);
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ msgq_.push(msg);
+ ss_->WakeUp();
+}
+
+void MessageQueue::PostDelayed(int cmsDelay, MessageHandler *phandler,
+ uint32 id, MessageData *pdata) {
+ // Keep thread safe
+ // Add to the priority queue. Gets sorted soonest first.
+ // Signal for the multiplexer to return.
+
+ CritScope cs(&crit_);
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ dmsgq_.push(DelayedMessage(cmsDelay, &msg));
+ ss_->WakeUp();
+}
+
+int MessageQueue::GetDelay() {
+ CritScope cs(&crit_);
+
+ if (!msgq_.empty())
+ return 0;
+
+ if (!dmsgq_.empty()) {
+ int delay = dmsgq_.top().msTrigger_ - GetMillisecondCount();
+ if (delay < 0)
+ delay = 0;
+ return delay;
+ }
+
+ return -1;
+}
+
+void MessageQueue::Clear(MessageHandler *phandler, uint32 id) {
+ CritScope cs(&crit_);
+
+ // Remove messages with phandler
+
+ if (fPeekKeep_) {
+ if (phandler == NULL || msgPeek_.phandler == phandler) {
+ if (id == (uint32)-1 || msgPeek_.message_id == id) {
+ delete msgPeek_.pdata;
+ fPeekKeep_ = false;
+ }
+ }
+ }
+
+ // Remove from ordered message queue
+
+ size_t c = msgq_.size();
+ while (c-- != 0) {
+ Message msg = msgq_.front();
+ msgq_.pop();
+ if (phandler != NULL && msg.phandler != phandler) {
+ msgq_.push(msg);
+ } else {
+ if (id == (uint32)-1 || msg.message_id == id) {
+ delete msg.pdata;
+ } else {
+ msgq_.push(msg);
+ }
+ }
+ }
+
+ // Remove from priority queue. Not directly iterable, so use this approach
+
+ std::queue<DelayedMessage> dmsgs;
+ while (!dmsgq_.empty()) {
+ DelayedMessage dmsg = dmsgq_.top();
+ dmsgq_.pop();
+ if (phandler != NULL && dmsg.msg_.phandler != phandler) {
+ dmsgs.push(dmsg);
+ } else {
+ if (id == (uint32)-1 || dmsg.msg_.message_id == id) {
+ delete dmsg.msg_.pdata;
+ } else {
+ dmsgs.push(dmsg);
+ }
+ }
+ }
+ while (!dmsgs.empty()) {
+ dmsgq_.push(dmsgs.front());
+ dmsgs.pop();
+ }
+}
+
+void MessageQueue::Dispatch(Message *pmsg) {
+ pmsg->phandler->OnMessage(pmsg);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h
new file mode 100644
index 00000000..2a9cbed6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h
@@ -0,0 +1,164 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MESSAGEQUEUE_H__
+#define __MESSAGEQUEUE_H__
+
+#include "talk/base/basictypes.h"
+#include "talk/base/criticalsection.h"
+#include "talk/base/socketserver.h"
+#include "talk/base/jtime.h"
+#include <vector>
+#include <queue>
+#include <algorithm>
+
+namespace cricket {
+
+struct Message;
+class MessageQueue;
+class MessageHandler;
+
+// MessageQueueManager does cleanup of of message queues
+
+class MessageQueueManager {
+public:
+ static MessageQueueManager* Instance();
+
+ void Add(MessageQueue *message_queue);
+ void Remove(MessageQueue *message_queue);
+ void Clear(MessageHandler *handler);
+
+private:
+ MessageQueueManager();
+ ~MessageQueueManager();
+
+ static MessageQueueManager* instance_;
+ std::vector<MessageQueue *> message_queues_;
+ CriticalSection crit_;
+};
+
+// Messages get dispatched to a MessageHandler
+
+class MessageHandler {
+public:
+ virtual ~MessageHandler() {
+ MessageQueueManager::Instance()->Clear(this);
+ }
+
+ virtual void OnMessage(Message *pmsg) = 0;
+};
+
+// Derive from this for specialized data
+// App manages lifetime, except when messages are purged
+
+class MessageData {
+public:
+ MessageData() {}
+ virtual ~MessageData() {}
+};
+
+template <class arg1_type>
+class TypedMessageData : public MessageData {
+public:
+ TypedMessageData(arg1_type data) {
+ data_ = data;
+ }
+ arg1_type data() {
+ return data_;
+ }
+private:
+ arg1_type data_;
+};
+
+// No destructor
+
+struct Message {
+ Message() {
+ memset(this, 0, sizeof(*this));
+ }
+ MessageHandler *phandler;
+ uint32 message_id;
+ MessageData *pdata;
+};
+
+// DelayedMessage goes into a priority queue, sorted by trigger time
+
+class DelayedMessage {
+public:
+ DelayedMessage(int cmsDelay, Message *pmsg) {
+ cmsDelay_ = cmsDelay;
+ msTrigger_ = GetMillisecondCount() + cmsDelay;
+ msg_ = *pmsg;
+ }
+
+ bool operator< (const DelayedMessage& dmsg) const {
+ return dmsg.msTrigger_ < msTrigger_;
+ }
+
+ int cmsDelay_; // for debugging
+ uint32 msTrigger_;
+ Message msg_;
+};
+
+class MessageQueue {
+public:
+ MessageQueue(SocketServer* ss = 0);
+ virtual ~MessageQueue();
+
+ SocketServer* socketserver() { return ss_; }
+ void set_socketserver(SocketServer* ss);
+
+ // Once the queue is stopped, all calls to Get/Peek will return false.
+ virtual void Stop();
+ virtual bool IsStopping();
+ virtual void Restart();
+
+ virtual bool Get(Message *pmsg, int cmsWait = -1);
+ virtual bool Peek(Message *pmsg, int cmsWait = 0);
+ virtual void Post(MessageHandler *phandler, uint32 id = 0,
+ MessageData *pdata = NULL);
+ virtual void PostDelayed(int cmsDelay, MessageHandler *phandler,
+ uint32 id = 0, MessageData *pdata = NULL);
+ virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1);
+ virtual void Dispatch(Message *pmsg);
+ virtual void ReceiveSends();
+ virtual int GetDelay();
+
+protected:
+ SocketServer* ss_;
+ bool new_ss;
+ bool fStop_;
+ bool fPeekKeep_;
+ Message msgPeek_;
+ std::queue<Message> msgq_;
+ std::priority_queue<DelayedMessage> dmsgq_;
+ CriticalSection crit_;
+};
+
+} // namespace cricket
+
+#endif // __MESSAGEQUEUE_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc
new file mode 100644
index 00000000..21b3a08f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc
@@ -0,0 +1,382 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/host.h"
+#include "talk/base/logging.h"
+#include "talk/base/network.h"
+#include "talk/base/socket.h" // this includes something that makes windows happy
+#include "talk/base/jtime.h"
+#include "talk/base/basicdefs.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cfloat>
+#include <cmath>
+#include <sstream>
+
+#ifdef POSIX
+extern "C" {
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <errno.h>
+}
+#endif // POSIX
+
+#ifdef WIN32
+#include <Iphlpapi.h>
+#endif
+
+namespace {
+
+const double kAlpha = 0.5; // weight for data infinitely far in the past
+const double kHalfLife = 2000; // half life of exponential decay (in ms)
+const double kLog2 = 0.693147180559945309417;
+const double kLambda = kLog2 / kHalfLife;
+
+// assume so-so quality unless data says otherwise
+const double kDefaultQuality = cricket::QUALITY_FAIR;
+
+typedef std::map<std::string,std::string> StrMap;
+
+void BuildMap(const StrMap& map, std::string& str) {
+ str.append("{");
+ bool first = true;
+ for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) {
+ if (!first) str.append(",");
+ str.append(i->first);
+ str.append("=");
+ str.append(i->second);
+ first = false;
+ }
+ str.append("}");
+}
+
+void ParseCheck(std::istringstream& ist, char ch) {
+ if (ist.get() != ch)
+ LOG(LERROR) << "Expecting '" << ch << "'";
+}
+
+std::string ParseString(std::istringstream& ist) {
+ std::string str;
+ int count = 0;
+ while (ist) {
+ char ch = ist.peek();
+ if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) {
+ break;
+ } else if (ch == '{') {
+ count += 1;
+ } else if (ch == '}') {
+ count -= 1;
+ if (count < 0)
+ LOG(LERROR) << "mismatched '{' and '}'";
+ }
+ str.append(1, static_cast<char>(ist.get()));
+ }
+ return str;
+}
+
+void ParseMap(const std::string& str, StrMap& map) {
+ if (str.size() == 0)
+ return;
+ std::istringstream ist(str);
+ ParseCheck(ist, '{');
+ for (;;) {
+ std::string key = ParseString(ist);
+ ParseCheck(ist, '=');
+ std::string val = ParseString(ist);
+ map[key] = val;
+ if (ist.peek() == ',')
+ ist.get();
+ else
+ break;
+ }
+ ParseCheck(ist, '}');
+ if (ist.rdbuf()->in_avail() != 0)
+ LOG(LERROR) << "Unexpected characters at end";
+}
+
+#if 0
+const std::string TEST_MAP0_IN = "";
+const std::string TEST_MAP0_OUT = "{}";
+const std::string TEST_MAP1 = "{a=12345}";
+const std::string TEST_MAP2 = "{a=12345,b=67890}";
+const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}";
+const std::string TEST_MAP4 = "{a={d=12345,e=67890}}";
+const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}";
+const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}";
+const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}";
+
+class MyTest {
+public:
+ MyTest() {
+ test(TEST_MAP0_IN, TEST_MAP0_OUT);
+ test(TEST_MAP1, TEST_MAP1);
+ test(TEST_MAP2, TEST_MAP2);
+ test(TEST_MAP3, TEST_MAP3);
+ test(TEST_MAP4, TEST_MAP4);
+ test(TEST_MAP5, TEST_MAP5);
+ test(TEST_MAP6, TEST_MAP6);
+ test(TEST_MAP7, TEST_MAP7);
+ }
+ void test(const std::string& input, const std::string& exp_output) {
+ StrMap map;
+ ParseMap(input, map);
+ std::string output;
+ BuildMap(map, output);
+ LOG(INFO) << " ******** " << (output == exp_output);
+ }
+};
+
+static MyTest myTest;
+#endif
+
+template <typename T>
+std::string ToString(T val) {
+ std::ostringstream ost;
+ ost << val;
+ return ost.str();
+}
+
+template <typename T>
+T FromString(std::string str) {
+ std::istringstream ist(str);
+ T val;
+ ist >> val;
+ return val;
+}
+
+}
+
+namespace cricket {
+
+#ifdef POSIX
+void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
+ int fd;
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ PLOG(LERROR, errno) << "socket";
+ return;
+ }
+
+ struct ifconf ifc;
+ ifc.ifc_len = 64 * sizeof(struct ifreq);
+ ifc.ifc_buf = new char[ifc.ifc_len];
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ PLOG(LERROR, errno) << "ioctl";
+ return;
+ }
+ assert(ifc.ifc_len < static_cast<int>(64 * sizeof(struct ifreq)));
+
+ struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf);
+ struct ifreq* end =
+ reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len);
+
+ while (ptr < end) {
+ struct sockaddr_in* inaddr =
+ reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr);
+ if (inaddr->sin_family == AF_INET) {
+ uint32 ip = ntohl(inaddr->sin_addr.s_addr);
+ networks.push_back(new Network(std::string(ptr->ifr_name), ip));
+ }
+#ifdef _SIZEOF_ADDR_IFREQ
+ ptr = reinterpret_cast<struct ifreq*>(
+ reinterpret_cast<char*>(ptr) + _SIZEOF_ADDR_IFREQ(*ptr));
+#else
+ ptr++;
+#endif
+ }
+
+ delete [] ifc.ifc_buf;
+ close(fd);
+}
+#endif
+
+#ifdef WIN32
+void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
+ IP_ADAPTER_INFO info_temp;
+ ULONG len = 0;
+
+ if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW)
+ return;
+ IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len];
+ if (GetAdaptersInfo(infos, &len) != NO_ERROR)
+ return;
+
+ int count = 0;
+ for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) {
+ if (info->Type == MIB_IF_TYPE_LOOPBACK)
+ continue;
+ if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0)
+ continue;
+
+ // In production, don't transmit the network name because of
+ // privacy concerns. Transmit a number instead.
+
+ std::string name;
+#if defined(PRODUCTION)
+ std::ostringstream ost;
+ ost << count;
+ name = ost.str();
+ count++;
+#else
+ name = info->Description;
+#endif
+
+ networks.push_back(new Network(name,
+ SocketAddress::StringToIP(info->IpAddressList.IpAddress.String)));
+ }
+
+ delete infos;
+}
+#endif
+
+void NetworkManager::GetNetworks(std::vector<Network*>& result) {
+ std::vector<Network*> list;
+ CreateNetworks(list);
+
+ for (uint32 i = 0; i < list.size(); ++i) {
+ NetworkMap::iterator iter = networks_.find(list[i]->name());
+
+ Network* network;
+ if (iter == networks_.end()) {
+ network = list[i];
+ } else {
+ network = iter->second;
+ network->set_ip(list[i]->ip());
+ delete list[i];
+ }
+
+ networks_[network->name()] = network;
+ result.push_back(network);
+ }
+}
+
+std::string NetworkManager::GetState() {
+ StrMap map;
+ for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i)
+ map[i->first] = i->second->GetState();
+
+ std::string str;
+ BuildMap(map, str);
+ return str;
+}
+
+void NetworkManager::SetState(std::string str) {
+ StrMap map;
+ ParseMap(str, map);
+
+ for (StrMap::iterator i = map.begin(); i != map.end(); ++i) {
+ std::string name = i->first;
+ std::string state = i->second;
+
+ Network* network = new Network(name, 0);
+ network->SetState(state);
+ networks_[name] = network;
+ }
+}
+
+Network::Network(const std::string& name, uint32 ip)
+ : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0),
+ exponential_numerator_(0), exponential_denominator_(0),
+ quality_(kDefaultQuality) {
+
+ last_data_time_ = Time();
+
+ // TODO: seed the historical data with one data point based on the link speed
+ // metric from XP (4.0 if < 50, 3.0 otherwise).
+}
+
+void Network::StartSession(NetworkSession* session) {
+ assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end());
+ sessions_.push_back(session);
+}
+
+void Network::StopSession(NetworkSession* session) {
+ SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session);
+ if (iter != sessions_.end())
+ sessions_.erase(iter);
+}
+
+void Network::EstimateQuality() {
+ uint32 now = Time();
+
+ // Add new data points for the current time.
+ for (uint32 i = 0; i < sessions_.size(); ++i) {
+ if (sessions_[i]->HasQuality())
+ AddDataPoint(now, sessions_[i]->GetCurrentQuality());
+ }
+
+ // Construct the weighted average using both uniform and exponential weights.
+
+ double exp_shift = exp(-kLambda * (now - last_data_time_));
+ double numerator = uniform_numerator_ + exp_shift * exponential_numerator_;
+ double denominator = uniform_denominator_ + exp_shift * exponential_denominator_;
+
+ if (denominator < DBL_EPSILON)
+ quality_ = kDefaultQuality;
+ else
+ quality_ = numerator / denominator;
+}
+
+void Network::AddDataPoint(uint32 time, double quality) {
+ uniform_numerator_ += kAlpha * quality;
+ uniform_denominator_ += kAlpha;
+
+ double exp_shift = exp(-kLambda * (time - last_data_time_));
+ exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_;
+ exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_;
+
+ last_data_time_ = time;
+}
+
+std::string Network::GetState() {
+ StrMap map;
+ map["lt"] = ToString<uint32>(last_data_time_);
+ map["un"] = ToString<double>(uniform_numerator_);
+ map["ud"] = ToString<double>(uniform_denominator_);
+ map["en"] = ToString<double>(exponential_numerator_);
+ map["ed"] = ToString<double>(exponential_denominator_);
+
+ std::string str;
+ BuildMap(map, str);
+ return str;
+}
+
+void Network::SetState(std::string str) {
+ StrMap map;
+ ParseMap(str, map);
+
+ last_data_time_ = FromString<uint32>(map["lt"]);
+ uniform_numerator_ = FromString<double>(map["un"]);
+ uniform_denominator_ = FromString<double>(map["ud"]);
+ exponential_numerator_ = FromString<double>(map["en"]);
+ exponential_denominator_ = FromString<double>(map["ed"]);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h
new file mode 100644
index 00000000..2cc9128a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h
@@ -0,0 +1,136 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NETWORK_H__
+#define __NETWORK_H__
+
+#include "talk/base/basictypes.h"
+
+#include <deque>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace cricket {
+
+class Network;
+class NetworkSession;
+
+// Keeps track of the available network interfaces over time so that quality
+// information can be aggregated and recorded.
+class NetworkManager {
+public:
+
+ // Updates and returns the current list of networks available on this machine.
+ // This version will make sure that repeated calls return the same object for
+ // a given network, so that quality is tracked appropriately.
+ void GetNetworks(std::vector<Network*>& networks);
+
+ // Reads and writes the state of the quality database in a string format.
+ std::string GetState();
+ void SetState(std::string str);
+
+ // Creates a network object for each network available on the machine.
+ static void CreateNetworks(std::vector<Network*>& networks);
+
+private:
+ typedef std::map<std::string,Network*> NetworkMap;
+
+ NetworkMap networks_;
+};
+
+// Represents a Unix-type network interface, with a name and single address.
+// It also includes the ability to track and estimate quality.
+class Network {
+public:
+ Network(const std::string& name, uint32 ip);
+
+ // Returns the OS name of this network. This is considered the primary key
+ // that identifies each network.
+ const std::string& name() const { return name_; }
+
+ // Identifies the current IP address used by this network.
+ uint32 ip() const { return ip_; }
+ void set_ip(uint32 ip) { ip_ = ip; }
+
+ // Updates the list of sessions that are ongoing.
+ void StartSession(NetworkSession* session);
+ void StopSession(NetworkSession* session);
+
+ // Re-computes the estimate of near-future quality based on the information
+ // as of this exact moment.
+ void EstimateQuality();
+
+ // Returns the current estimate of the near-future quality of connections
+ // that use this local interface.
+ double quality() { return quality_; }
+
+private:
+ typedef std::vector<NetworkSession*> SessionList;
+
+ std::string name_;
+ uint32 ip_;
+ SessionList sessions_;
+ double uniform_numerator_;
+ double uniform_denominator_;
+ double exponential_numerator_;
+ double exponential_denominator_;
+ uint32 last_data_time_;
+ double quality_;
+
+ // Updates the statistics maintained to include the given estimate.
+ void AddDataPoint(uint32 time, double quality);
+
+ // Converts the internal state to and from a string. This is used to record
+ // quality information into a permanent store.
+ void SetState(std::string str);
+ std::string GetState();
+
+ friend class NetworkManager;
+};
+
+// Represents a session that is in progress using a particular network and can
+// provide data about the quality of the network at any given moment.
+class NetworkSession {
+public:
+ // Determines whether this session has an estimate at this moment. We will
+ // only call GetCurrentQuality when this returns true.
+ virtual bool HasQuality() = 0;
+
+ // Returns an estimate of the quality at this exact moment. The result should
+ // be a MOS (mean opinion score) value.
+ virtual float GetCurrentQuality() = 0;
+
+};
+
+const double QUALITY_BAD = 3.0;
+const double QUALITY_FAIR = 3.35;
+const double QUALITY_GOOD = 3.7;
+
+} // namespace cricket
+
+#endif // __NETWORK_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc
new file mode 100644
index 00000000..91d2daad
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc
@@ -0,0 +1,1117 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <unistd.h>
+}
+#endif
+
+#include "talk/base/basictypes.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/jtime.h"
+#include "talk/base/winping.h"
+
+#ifdef __linux
+#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h
+#endif // __linux
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#undef SetPort
+
+#include <algorithm>
+#include <iostream>
+
+class WinsockInitializer {
+public:
+ WinsockInitializer() {
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(1, 0);
+ err_ = WSAStartup(wVersionRequested, &wsaData);
+ }
+ ~WinsockInitializer() {
+ WSACleanup();
+ }
+ int error() {
+ return err_;
+ }
+private:
+ int err_;
+};
+WinsockInitializer g_winsockinit;
+#endif
+
+namespace cricket {
+
+const int kfRead = 0x0001;
+const int kfWrite = 0x0002;
+const int kfConnect = 0x0004;
+const int kfClose = 0x0008;
+
+
+// Standard MTUs
+const uint16 PACKET_MAXIMUMS[] = {
+ 65535, // Theoretical maximum, Hyperchannel
+ 32000, // Nothing
+ 17914, // 16Mb IBM Token Ring
+ 8166, // IEEE 802.4
+ //4464, // IEEE 802.5 (4Mb max)
+ 4352, // FDDI
+ //2048, // Wideband Network
+ 2002, // IEEE 802.5 (4Mb recommended)
+ //1536, // Expermental Ethernet Networks
+ //1500, // Ethernet, Point-to-Point (default)
+ 1492, // IEEE 802.3
+ 1006, // SLIP, ARPANET
+ //576, // X.25 Networks
+ //544, // DEC IP Portal
+ //512, // NETBIOS
+ 508, // IEEE 802/Source-Rt Bridge, ARCNET
+ 296, // Point-to-Point (low delay)
+ 68, // Official minimum
+ 0, // End of list marker
+};
+
+const uint32 IP_HEADER_SIZE = 20;
+const uint32 ICMP_HEADER_SIZE = 8;
+
+class PhysicalSocket : public AsyncSocket {
+public:
+ PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET)
+ : ss_(ss), s_(s), enabled_events_(0), error_(0),
+ state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED) {
+ if (s != INVALID_SOCKET)
+ enabled_events_ = kfRead | kfWrite;
+ }
+
+ virtual ~PhysicalSocket() {
+ Close();
+ }
+
+ // Creates the underlying OS socket (same as the "socket" function).
+ virtual bool Create(int type) {
+ Close();
+ s_ = ::socket(AF_INET, type, 0);
+ UpdateLastError();
+ enabled_events_ = kfRead | kfWrite;
+ return s_ != INVALID_SOCKET;
+ }
+
+ SocketAddress GetLocalAddress() const {
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ int result = ::getsockname(s_, (struct sockaddr*)&addr, &addrlen);
+ assert(addrlen == sizeof(addr));
+ if (result >= 0) {
+ return SocketAddress(NetworkToHost32(addr.sin_addr.s_addr),
+ NetworkToHost16(addr.sin_port));
+ } else {
+ return SocketAddress();
+ }
+ }
+
+ SocketAddress GetRemoteAddress() const {
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ int result = ::getpeername(s_, (struct sockaddr*)&addr, &addrlen);
+ assert(addrlen == sizeof(addr));
+ if (result >= 0) {
+ return SocketAddress(
+ NetworkToHost32(addr.sin_addr.s_addr),
+ NetworkToHost16(addr.sin_port));
+ } else {
+ assert(errno == ENOTCONN);
+ return SocketAddress();
+ }
+ }
+
+ int Bind(const SocketAddress& addr) {
+ struct sockaddr_in saddr;
+ IP2SA(&addr, &saddr);
+ int err = ::bind(s_, (struct sockaddr*)&saddr, sizeof(saddr));
+ UpdateLastError();
+ return err;
+ }
+
+ int Connect(const SocketAddress& addr) {
+ // TODO: Implicit creation is required to reconnect...
+ // ...but should we make it more explicit?
+ if ((s_ == INVALID_SOCKET) && !Create(SOCK_STREAM))
+ return SOCKET_ERROR;
+ SocketAddress addr2(addr);
+ if (addr2.IsUnresolved()) {
+ LOG(INFO) << "Resolving addr in PhysicalSocket::Connect";
+ addr2.Resolve(); // TODO: Do this async later?
+ }
+ struct sockaddr_in saddr;
+ IP2SA(&addr2, &saddr);
+ int err = ::connect(s_, (struct sockaddr*)&saddr, sizeof(saddr));
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_;
+ if (err == 0) {
+ state_ = CS_CONNECTED;
+ } else if (IsBlockingError(error_)) {
+ state_ = CS_CONNECTING;
+ enabled_events_ |= kfConnect;
+ }
+ return err;
+ }
+
+ int GetError() const {
+ return error_;
+ }
+
+ void SetError(int error) {
+ error_ = error;
+ }
+
+ ConnState GetState() const {
+ return state_;
+ }
+
+ int SetOption(Option opt, int value) {
+ assert(opt == OPT_DONTFRAGMENT);
+#ifdef WIN32
+ value = (value == 0) ? 0 : 1;
+ return ::setsockopt(
+ s_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast<char*>(&value),
+ sizeof(value));
+#endif
+#ifdef __linux
+ value = (value == 0) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO;
+ return ::setsockopt(
+ s_, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value));
+#endif
+#ifdef OSX
+ // This is not possible on OSX.
+ return -1;
+#endif
+ }
+
+ int Send(const void *pv, size_t cb) {
+ int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, 0);
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_;
+ ASSERT(sent <= static_cast<int>(cb)); // We have seen minidumps where this may be false
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= kfWrite;
+ }
+ return sent;
+ }
+
+ int SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ struct sockaddr_in saddr;
+ IP2SA(&addr, &saddr);
+ int sent = ::sendto(
+ s_, (const char *)pv, (int)cb, 0, (struct sockaddr*)&saddr,
+ sizeof(saddr));
+ UpdateLastError();
+ ASSERT(sent <= static_cast<int>(cb)); // We have seen minidumps where this may be false
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= kfWrite;
+ }
+ return sent;
+ }
+
+ int Recv(void *pv, size_t cb) {
+ int received = ::recv(s_, (char *)pv, (int)cb, 0);
+ UpdateLastError();
+ if ((received >= 0) || IsBlockingError(error_)) {
+ enabled_events_ |= kfRead;
+ }
+ return received;
+ }
+
+ int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ struct sockaddr saddr;
+ socklen_t cbAddr = sizeof(saddr);
+ int received = ::recvfrom(s_, (char *)pv, (int)cb, 0, &saddr, &cbAddr);
+ UpdateLastError();
+ if ((received >= 0) && (paddr != NULL))
+ SA2IP(&saddr, paddr);
+ if ((received >= 0) || IsBlockingError(error_)) {
+ enabled_events_ |= kfRead;
+ }
+ return received;
+ }
+
+ int Listen(int backlog) {
+ int err = ::listen(s_, backlog);
+ UpdateLastError();
+ if (err == 0)
+ state_ = CS_CONNECTING;
+ return err;
+ }
+
+ Socket* Accept(SocketAddress *paddr) {
+ struct sockaddr saddr;
+ socklen_t cbAddr = sizeof(saddr);
+ SOCKET s = ::accept(s_, &saddr, &cbAddr);
+ UpdateLastError();
+ if (s == INVALID_SOCKET)
+ return NULL;
+ if (paddr != NULL)
+ SA2IP(&saddr, paddr);
+ return ss_->WrapSocket(s);
+ }
+
+ int Close() {
+ if (s_ == INVALID_SOCKET)
+ return 0;
+ int err = ::closesocket(s_);
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Close() Ret: " << err << " Error: " << error_;
+ s_ = INVALID_SOCKET;
+ state_ = CS_CLOSED;
+ enabled_events_ = 0;
+ return err;
+ }
+
+ int EstimateMTU(uint16* mtu) {
+ SocketAddress addr = GetRemoteAddress();
+ if (addr.IsAny()) {
+ error_ = ENOTCONN;
+ return -1;
+ }
+
+#ifdef WIN32
+
+ WinPing ping;
+ if (!ping.IsValid()) {
+ error_ = EINVAL; // can't think of a better error ID
+ return -1;
+ }
+
+ for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) {
+ int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
+ if (ping.Ping(addr.ip(), size, 0, 1, false) != WinPing::PING_TOO_LARGE) {
+ *mtu = PACKET_MAXIMUMS[level];
+ return 0;
+ }
+ }
+
+ assert(false);
+ return 0;
+
+#endif // WIN32
+
+#ifdef __linux
+
+ int value;
+ socklen_t vlen = sizeof(value);
+ int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen);
+ if (err < 0) {
+ UpdateLastError();
+ return err;
+ }
+
+ assert((0 <= value) && (value <= 65536));
+ *mtu = uint16(value);
+ return 0;
+
+#endif // __linux
+
+ // TODO: OSX support
+ }
+
+ SocketServer* socketserver() { return ss_; }
+
+protected:
+ PhysicalSocketServer* ss_;
+ SOCKET s_;
+ uint32 enabled_events_;
+ int error_;
+ ConnState state_;
+
+ void UpdateLastError() {
+#ifdef WIN32
+ error_ = WSAGetLastError();
+#endif
+#ifdef POSIX
+ error_ = errno;
+#endif
+ }
+
+ void IP2SA(const SocketAddress *paddr, struct sockaddr_in *psaddr) {
+ memset(psaddr, 0, sizeof(*psaddr));
+ psaddr->sin_family = AF_INET;
+ psaddr->sin_port = HostToNetwork16(paddr->port());
+ if (paddr->ip() == 0)
+ psaddr->sin_addr.s_addr = INADDR_ANY;
+ else
+ psaddr->sin_addr.s_addr = HostToNetwork32(paddr->ip());
+ }
+
+ void SA2IP(const struct sockaddr *psaddr, SocketAddress *paddr) {
+ const struct sockaddr_in *psaddr_in =
+ reinterpret_cast<const struct sockaddr_in*>(psaddr);
+ paddr->SetIP(NetworkToHost32(psaddr_in->sin_addr.s_addr));
+ paddr->SetPort(NetworkToHost16(psaddr_in->sin_port));
+ }
+};
+
+#ifdef POSIX
+class Dispatcher {
+public:
+ virtual uint32 GetRequestedEvents() = 0;
+ virtual void OnPreEvent(uint32 ff) = 0;
+ virtual void OnEvent(uint32 ff, int err) = 0;
+ virtual int GetDescriptor() = 0;
+};
+
+class EventDispatcher : public Dispatcher {
+public:
+ EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
+ if (pipe(afd_) < 0)
+ LOG(LERROR) << "pipe failed";
+ ss_->Add(this);
+ }
+
+ virtual ~EventDispatcher() {
+ ss_->Remove(this);
+ close(afd_[0]);
+ close(afd_[1]);
+ }
+
+ virtual void Signal() {
+ CritScope cs(&crit_);
+ if (!fSignaled_) {
+ uint8 b = 0;
+ if (write(afd_[1], &b, sizeof(b)) < 0)
+ LOG(LERROR) << "write failed";
+ fSignaled_ = true;
+ }
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return kfRead;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ // It is not possible to perfectly emulate an auto-resetting event with
+ // pipes. This simulates it by resetting before the event is handled.
+
+ CritScope cs(&crit_);
+ if (fSignaled_) {
+ uint8 b;
+ read(afd_[0], &b, sizeof(b));
+ fSignaled_ = false;
+ }
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ assert(false);
+ }
+
+ virtual int GetDescriptor() {
+ return afd_[0];
+ }
+
+private:
+ PhysicalSocketServer *ss_;
+ int afd_[2];
+ bool fSignaled_;
+ CriticalSection crit_;
+};
+
+class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+public:
+ SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
+ ss_->Add(this);
+ }
+ SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) {
+ ss_->Add(this);
+ }
+
+ virtual ~SocketDispatcher() {
+ ss_->Remove(this);
+ }
+
+ bool Initialize() {
+ fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK);
+ return true;
+ }
+
+ virtual bool Create(int type) {
+ // Change the socket to be non-blocking.
+ if (!PhysicalSocket::Create(type))
+ return false;
+
+ return Initialize();
+ }
+
+ virtual int GetDescriptor() {
+ return s_;
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return enabled_events_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ if ((ff & kfRead) != 0) {
+ enabled_events_ &= ~kfRead;
+ SignalReadEvent(this);
+ }
+ if ((ff & kfWrite) != 0) {
+ enabled_events_ &= ~kfWrite;
+ SignalWriteEvent(this);
+ }
+ if ((ff & kfConnect) != 0) {
+ enabled_events_ &= ~kfConnect;
+ SignalConnectEvent(this);
+ }
+ if ((ff & kfClose) != 0)
+ SignalCloseEvent(this, err);
+ }
+};
+
+class FileDispatcher: public Dispatcher, public AsyncFile {
+public:
+ FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) {
+ set_readable(true);
+
+ ss_->Add(this);
+
+ fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK);
+ }
+
+ virtual ~FileDispatcher() {
+ ss_->Remove(this);
+ }
+
+ SocketServer* socketserver() { return ss_; }
+
+ virtual int GetDescriptor() {
+ return fd_;
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return flags_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ if ((ff & kfRead) != 0)
+ SignalReadEvent(this);
+ if ((ff & kfWrite) != 0)
+ SignalWriteEvent(this);
+ if ((ff & kfClose) != 0)
+ SignalCloseEvent(this, err);
+ }
+
+ virtual bool readable() {
+ return (flags_ & kfRead) != 0;
+ }
+
+ virtual void set_readable(bool value) {
+ flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead);
+ }
+
+ virtual bool writable() {
+ return (flags_ & kfWrite) != 0;
+ }
+
+ virtual void set_writable(bool value) {
+ flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite);
+ }
+
+private:
+ PhysicalSocketServer* ss_;
+ int fd_;
+ int flags_;
+};
+
+AsyncFile* PhysicalSocketServer::CreateFile(int fd) {
+ return new FileDispatcher(fd, this);
+}
+
+#endif // POSIX
+
+#ifdef WIN32
+class Dispatcher {
+public:
+ virtual uint32 GetRequestedEvents() = 0;
+ virtual void OnPreEvent(uint32 ff) = 0;
+ virtual void OnEvent(uint32 ff, int err) = 0;
+ virtual WSAEVENT GetWSAEvent() = 0;
+ virtual SOCKET GetSocket() = 0;
+ virtual bool CheckSignalClose() = 0;
+};
+
+uint32 FlagsToEvents(uint32 events) {
+ uint32 ffFD = FD_CLOSE | FD_ACCEPT;
+ if (events & kfRead)
+ ffFD |= FD_READ;
+ if (events & kfWrite)
+ ffFD |= FD_WRITE;
+ if (events & kfConnect)
+ ffFD |= FD_CONNECT;
+ return ffFD;
+}
+
+class EventDispatcher : public Dispatcher {
+public:
+ EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) {
+ if (hev_ = WSACreateEvent()) {
+ ss_->Add(this);
+ }
+ }
+
+ ~EventDispatcher() {
+ if (hev_ != NULL) {
+ ss_->Remove(this);
+ WSACloseEvent(hev_);
+ hev_ = NULL;
+ }
+ }
+
+ virtual void Signal() {
+ if (hev_ != NULL)
+ WSASetEvent(hev_);
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return 0;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ WSAResetEvent(hev_);
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ }
+
+ virtual WSAEVENT GetWSAEvent() {
+ return hev_;
+ }
+
+ virtual SOCKET GetSocket() {
+ return INVALID_SOCKET;
+ }
+
+ virtual bool CheckSignalClose() { return false; }
+
+private:
+ PhysicalSocketServer* ss_;
+ WSAEVENT hev_;
+};
+
+class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+public:
+ static int next_id_;
+ int id_;
+ bool signal_close_;
+ int signal_err_;
+
+ SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) {
+ }
+ SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) {
+ }
+
+ virtual ~SocketDispatcher() {
+ Close();
+ }
+
+ bool Initialize() {
+ assert(s_ != INVALID_SOCKET);
+ // Must be a non-blocking
+ u_long argp = 1;
+ ioctlsocket(s_, FIONBIO, &argp);
+ ss_->Add(this);
+ return true;
+ }
+
+ virtual bool Create(int type) {
+ // Create socket
+ if (!PhysicalSocket::Create(type))
+ return false;
+
+ if (!Initialize())
+ return false;
+
+ do { id_ = ++next_id_; } while (id_ == 0);
+ return true;
+ }
+
+ virtual int Close() {
+ if (s_ == INVALID_SOCKET)
+ return 0;
+
+ id_ = 0;
+ signal_close_ = false;
+ ss_->Remove(this);
+ return PhysicalSocket::Close();
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return enabled_events_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ if ((ff & kfConnect) != 0)
+ state_ = CS_CONNECTED;
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ int cache_id = id_;
+ if ((ff & kfRead) != 0) {
+ enabled_events_ &= ~kfRead;
+ SignalReadEvent(this);
+ }
+ if (((ff & kfWrite) != 0) && (id_ == cache_id)) {
+ enabled_events_ &= ~kfWrite;
+ SignalWriteEvent(this);
+ }
+ if (((ff & kfConnect) != 0) && (id_ == cache_id)) {
+ enabled_events_ &= ~kfConnect;
+ SignalConnectEvent(this);
+ }
+ if (((ff & kfClose) != 0) && (id_ == cache_id)) {
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] OnClose() Error: " << err;
+ signal_close_ = true;
+ signal_err_ = err;
+ }
+ }
+
+ virtual WSAEVENT GetWSAEvent() {
+ return WSA_INVALID_EVENT;
+ }
+
+ virtual SOCKET GetSocket() {
+ return s_;
+ }
+
+ virtual bool CheckSignalClose() {
+ if (!signal_close_)
+ return false;
+
+ char ch;
+ if (recv(s_, &ch, 1, MSG_PEEK) > 0)
+ return false;
+
+ signal_close_ = false;
+ SignalCloseEvent(this, signal_err_);
+ return true;
+ }
+};
+
+int SocketDispatcher::next_id_ = 0;
+
+#endif // WIN32
+
+// Sets the value of a boolean value to false when signaled.
+class Signaler : public EventDispatcher {
+public:
+ Signaler(PhysicalSocketServer* ss, bool* pf)
+ : EventDispatcher(ss), pf_(pf) {
+ }
+ virtual ~Signaler() { }
+
+ void OnEvent(uint32 ff, int err) {
+ if (pf_)
+ *pf_ = false;
+ }
+
+private:
+ bool *pf_;
+};
+
+PhysicalSocketServer::PhysicalSocketServer() : fWait_(false),
+ last_tick_tracked_(0), last_tick_dispatch_count_(0) {
+ signal_wakeup_ = new Signaler(this, &fWait_);
+}
+
+PhysicalSocketServer::~PhysicalSocketServer() {
+ delete signal_wakeup_;
+}
+
+void PhysicalSocketServer::WakeUp() {
+ signal_wakeup_->Signal();
+}
+
+Socket* PhysicalSocketServer::CreateSocket(int type) {
+ PhysicalSocket* socket = new PhysicalSocket(this);
+ if (socket->Create(type)) {
+ return socket;
+ } else {
+ delete socket;
+ return 0;
+ }
+}
+
+AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) {
+ SocketDispatcher* dispatcher = new SocketDispatcher(this);
+ if (dispatcher->Create(type)) {
+ return dispatcher;
+ } else {
+ delete dispatcher;
+ return 0;
+ }
+}
+
+AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) {
+ SocketDispatcher* dispatcher = new SocketDispatcher(s, this);
+ if (dispatcher->Initialize()) {
+ return dispatcher;
+ } else {
+ delete dispatcher;
+ return 0;
+ }
+}
+
+void PhysicalSocketServer::Add(Dispatcher *pdispatcher) {
+ CritScope cs(&crit_);
+ dispatchers_.push_back(pdispatcher);
+}
+
+void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) {
+ CritScope cs(&crit_);
+ dispatchers_.erase(std::remove(dispatchers_.begin(), dispatchers_.end(), pdispatcher), dispatchers_.end());
+}
+
+#ifdef POSIX
+bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
+ // Calculate timing information
+
+ struct timeval *ptvWait = NULL;
+ struct timeval tvWait;
+ struct timeval tvStop;
+ if (cmsWait != -1) {
+ // Calculate wait timeval
+ tvWait.tv_sec = cmsWait / 1000;
+ tvWait.tv_usec = (cmsWait % 1000) * 1000;
+ ptvWait = &tvWait;
+
+ // Calculate when to return in a timeval
+ gettimeofday(&tvStop, NULL);
+ tvStop.tv_sec += tvWait.tv_sec;
+ tvStop.tv_usec += tvWait.tv_usec;
+ if (tvStop.tv_usec >= 1000000) {
+ tvStop.tv_usec -= 1000000;
+ tvStop.tv_sec += 1;
+ }
+ }
+
+ // Zero all fd_sets. Don't need to do this inside the loop since
+ // select() zeros the descriptors not signaled
+
+ fd_set fdsRead;
+ FD_ZERO(&fdsRead);
+ fd_set fdsWrite;
+ FD_ZERO(&fdsWrite);
+
+ fWait_ = true;
+
+ while (fWait_) {
+ int fdmax = -1;
+ {
+ CritScope cr(&crit_);
+ for (unsigned i = 0; i < dispatchers_.size(); i++) {
+ // Query dispatchers for read and write wait state
+
+ Dispatcher *pdispatcher = dispatchers_[i];
+ assert(pdispatcher);
+ if (!process_io && (pdispatcher != signal_wakeup_))
+ continue;
+ int fd = pdispatcher->GetDescriptor();
+ if (fd > fdmax)
+ fdmax = fd;
+ uint32 ff = pdispatcher->GetRequestedEvents();
+ if (ff & kfRead)
+ FD_SET(fd, &fdsRead);
+ if (ff & (kfWrite | kfConnect))
+ FD_SET(fd, &fdsWrite);
+ }
+ }
+
+ // Wait then call handlers as appropriate
+ // < 0 means error
+ // 0 means timeout
+ // > 0 means count of descriptors ready
+ int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait);
+
+ // If error, return error
+ // todo: do something intelligent
+
+ if (n < 0)
+ return false;
+
+ // If timeout, return success
+
+ if (n == 0)
+ return true;
+
+ // We have signaled descriptors
+
+ {
+ CritScope cr(&crit_);
+ for (unsigned i = 0; i < dispatchers_.size(); i++) {
+ Dispatcher *pdispatcher = dispatchers_[i];
+ int fd = pdispatcher->GetDescriptor();
+ uint32 ff = 0;
+ if (FD_ISSET(fd, &fdsRead)) {
+ FD_CLR(fd, &fdsRead);
+ ff |= kfRead;
+ }
+ if (FD_ISSET(fd, &fdsWrite)) {
+ FD_CLR(fd, &fdsWrite);
+ if (pdispatcher->GetRequestedEvents() & kfConnect) {
+ ff |= kfConnect;
+ } else {
+ ff |= kfWrite;
+ }
+ }
+ if (ff != 0) {
+ pdispatcher->OnPreEvent(ff);
+ pdispatcher->OnEvent(ff, 0);
+ }
+ }
+ }
+
+ // Recalc the time remaining to wait. Doing it here means it doesn't get
+ // calced twice the first time through the loop
+
+ if (cmsWait != -1) {
+ ptvWait->tv_sec = 0;
+ ptvWait->tv_usec = 0;
+ struct timeval tvT;
+ gettimeofday(&tvT, NULL);
+ if (tvStop.tv_sec >= tvT.tv_sec) {
+ ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
+ ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
+ if (ptvWait->tv_usec < 0) {
+ ptvWait->tv_usec += 1000000;
+ ptvWait->tv_sec -= 1;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+#endif // POSIX
+
+#ifdef WIN32
+bool PhysicalSocketServer::Wait(int cmsWait, bool process_io)
+{
+ int cmsTotal = cmsWait;
+ int cmsElapsed = 0;
+ uint32 msStart = GetMillisecondCount();
+
+#if LOGGING
+ if (last_tick_dispatch_count_ == 0) {
+ last_tick_tracked_ = msStart;
+ }
+#endif
+
+ WSAEVENT socket_ev = WSACreateEvent();
+
+ fWait_ = true;
+ while (fWait_) {
+ std::vector<WSAEVENT> events;
+ std::vector<Dispatcher *> event_owners;
+
+ events.push_back(socket_ev);
+
+ {
+ CritScope cr(&crit_);
+ for (size_t i = 0; i < dispatchers_.size(); ++i) {
+ Dispatcher * disp = dispatchers_[i];
+ if (!process_io && (disp != signal_wakeup_))
+ continue;
+ SOCKET s = disp->GetSocket();
+ if (disp->CheckSignalClose()) {
+ // We just signalled close, don't poll this socket
+ } else if (s != INVALID_SOCKET) {
+ WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents()));
+ } else {
+ events.push_back(disp->GetWSAEvent());
+ event_owners.push_back(disp);
+ }
+ }
+ }
+
+ // Which is shorter, the delay wait or the asked wait?
+
+ int cmsNext;
+ if (cmsWait == -1) {
+ cmsNext = cmsWait;
+ } else {
+ cmsNext = cmsTotal - cmsElapsed;
+ if (cmsNext < 0)
+ cmsNext = 0;
+ }
+
+ // Wait for one of the events to signal
+ DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0], false, cmsNext, false);
+
+#if 0 // LOGGING
+ // we track this information purely for logging purposes.
+ last_tick_dispatch_count_++;
+ if (last_tick_dispatch_count_ >= 1000) {
+ uint32 now = GetMillisecondCount();
+ LOG(INFO) << "PhysicalSocketServer took " << TimeDiff(now, last_tick_tracked_) << "ms for 1000 events";
+
+ // If we get more than 1000 events in a second, we are spinning badly
+ // (normally it should take about 8-20 seconds).
+ assert(TimeDiff(now, last_tick_tracked_) > 1000);
+
+ last_tick_tracked_ = now;
+ last_tick_dispatch_count_ = 0;
+ }
+#endif
+
+ // Failed?
+ // todo: need a better strategy than this!
+
+ if (dw == WSA_WAIT_FAILED) {
+ int error = WSAGetLastError();
+ assert(false);
+ WSACloseEvent(socket_ev);
+ return false;
+ }
+
+ // Timeout?
+
+ if (dw == WSA_WAIT_TIMEOUT) {
+ WSACloseEvent(socket_ev);
+ return true;
+ }
+
+ // Figure out which one it is and call it
+
+ {
+ CritScope cr(&crit_);
+ int index = dw - WSA_WAIT_EVENT_0;
+ if (index > 0) {
+ --index; // The first event is the socket event
+ event_owners[index]->OnPreEvent(0);
+ event_owners[index]->OnEvent(0, 0);
+ } else if (process_io) {
+ for (size_t i = 0; i < dispatchers_.size(); ++i) {
+ Dispatcher * disp = dispatchers_[i];
+ SOCKET s = disp->GetSocket();
+ if (s == INVALID_SOCKET)
+ continue;
+
+ WSANETWORKEVENTS wsaEvents;
+ int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents);
+ if (err == 0) {
+
+#if LOGGING
+ {
+ if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT];
+ }
+ }
+#endif
+ uint32 ff = 0;
+ int errcode = 0;
+ if (wsaEvents.lNetworkEvents & FD_READ)
+ ff |= kfRead;
+ if (wsaEvents.lNetworkEvents & FD_WRITE)
+ ff |= kfWrite;
+ if (wsaEvents.lNetworkEvents & FD_CONNECT) {
+ if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
+ ff |= kfConnect;
+ } else {
+ // TODO: Decide whether we want to signal connect, but with an error code
+ ff |= kfClose;
+ errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
+ }
+ }
+ if (wsaEvents.lNetworkEvents & FD_ACCEPT)
+ ff |= kfRead;
+ if (wsaEvents.lNetworkEvents & FD_CLOSE) {
+ ff |= kfClose;
+ errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
+ }
+ if (ff != 0) {
+ disp->OnPreEvent(ff);
+ disp->OnEvent(ff, errcode);
+ }
+ }
+ }
+ }
+
+ // Reset the network event until new activity occurs
+ WSAResetEvent(socket_ev);
+ }
+
+ // Break?
+
+ if (!fWait_)
+ break;
+ cmsElapsed = GetMillisecondCount() - msStart;
+ if (cmsWait != -1) {
+ if (cmsElapsed >= cmsWait)
+ break;
+ }
+ }
+
+ // Done
+
+ WSACloseEvent(socket_ev);
+ return true;
+}
+#endif // WIN32
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h
new file mode 100644
index 00000000..305b64d9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h
@@ -0,0 +1,80 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PHYSICALSOCKETSERVER_H__
+#define __PHYSICALSOCKETSERVER_H__
+
+#include "talk/base/asyncfile.h"
+#include "talk/base/socketserver.h"
+#include "talk/base/criticalsection.h"
+#include <vector>
+
+#ifdef POSIX
+typedef int SOCKET;
+#endif // POSIX
+
+namespace cricket {
+
+class Dispatcher;
+class Signaler;
+
+// A socket server that provides the real sockets of the underlying OS.
+class PhysicalSocketServer : public SocketServer {
+public:
+ PhysicalSocketServer();
+ virtual ~PhysicalSocketServer();
+
+ // SocketFactory:
+ virtual Socket* CreateSocket(int type);
+ virtual AsyncSocket* CreateAsyncSocket(int type);
+
+ // Internal Factory for Accept
+ AsyncSocket* WrapSocket(SOCKET s);
+
+ // SocketServer:
+ virtual bool Wait(int cms, bool process_io);
+ virtual void WakeUp();
+
+ void Add(Dispatcher* dispatcher);
+ void Remove(Dispatcher* dispatcher);
+
+#ifdef POSIX
+ AsyncFile* CreateFile(int fd);
+#endif
+
+private:
+ std::vector<Dispatcher*> dispatchers_;
+ Signaler* signal_wakeup_;
+ CriticalSection crit_;
+ bool fWait_;
+ uint32 last_tick_tracked_;
+ int last_tick_dispatch_count_;
+};
+
+} // namespace cricket
+
+#endif // __PHYSICALSOCKETSERVER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h
new file mode 100644
index 00000000..1bd817b9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h
@@ -0,0 +1,52 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PROXYINFO_H__
+#define __PROXYINFO_H__
+
+#include <string>
+#include "talk/base/socketaddress.h"
+// TODO: move xmpppassword into base
+#include "talk/xmpp/xmpppassword.h"
+
+namespace cricket {
+
+enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN };
+const char * ProxyToString(ProxyType proxy);
+
+struct ProxyInfo {
+ ProxyType type;
+ SocketAddress address;
+ std::string username;
+ buzz::XmppPassword password;
+
+ ProxyInfo() : type(PROXY_NONE) { }
+};
+
+} // namespace cricket
+
+#endif // __PROXYINFO_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h
new file mode 100644
index 00000000..0470ff83
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h
@@ -0,0 +1,259 @@
+#ifndef SCOPED_PTR_H
+#define SCOPED_PTR_H
+
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// Copyright (c) 2001, 2002 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
+//
+
+// scoped_ptr mimics a built-in pointer except that it guarantees deletion
+// of the object pointed to, either on destruction of the scoped_ptr or via
+// an explicit reset(). scoped_ptr is a simple solution for simple needs;
+// use shared_ptr or std::auto_ptr if your needs are more complex.
+
+// scoped_ptr_malloc added in by Google. When one of
+// these goes out of scope, instead of doing a delete or delete[], it
+// calls free(). scoped_ptr_malloc<char> is likely to see much more
+// use than any other specializations.
+
+// release() added in by Google. Use this to conditionally
+// transfer ownership of a heap-allocated object to the caller, usually on
+// method success.
+
+#include <cstddef> // for std::ptrdiff_t
+#include <assert.h> // for assert
+#include <stdlib.h> // for free() decl
+
+#ifdef _WIN32
+namespace std { using ::ptrdiff_t; };
+#endif // _WIN32
+
+namespace buzz {
+
+template <typename T>
+class scoped_ptr {
+ private:
+
+ T* ptr;
+
+ scoped_ptr(scoped_ptr const &);
+ scoped_ptr & operator=(scoped_ptr const &);
+
+ public:
+
+ typedef T element_type;
+
+ explicit scoped_ptr(T* p = 0): ptr(p) {}
+
+ ~scoped_ptr() {
+ typedef char type_must_be_complete[sizeof(T)];
+ delete ptr;
+ }
+
+ void reset(T* p = 0) {
+ typedef char type_must_be_complete[sizeof(T)];
+
+ if (ptr != p) {
+ delete ptr;
+ ptr = p;
+ }
+ }
+
+ T& operator*() const {
+ assert(ptr != 0);
+ return *ptr;
+ }
+
+ T* operator->() const {
+ assert(ptr != 0);
+ return ptr;
+ }
+
+ T* get() const {
+ return ptr;
+ }
+
+ void swap(scoped_ptr & b) {
+ T* tmp = b.ptr;
+ b.ptr = ptr;
+ ptr = tmp;
+ }
+
+ T* release() {
+ T* tmp = ptr;
+ ptr = 0;
+ return tmp;
+ }
+
+ T** accept() {
+ if (ptr) {
+ delete ptr;
+ ptr = 0;
+ }
+ return &ptr;
+ }
+
+ T** use() {
+ return &ptr;
+ }
+};
+
+template<typename T> inline
+void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
+ a.swap(b);
+}
+
+
+
+
+// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
+// is guaranteed, either on destruction of the scoped_array or via an explicit
+// reset(). Use shared_array or std::vector if your needs are more complex.
+
+template<typename T>
+class scoped_array {
+ private:
+
+ T* ptr;
+
+ scoped_array(scoped_array const &);
+ scoped_array & operator=(scoped_array const &);
+
+ public:
+
+ typedef T element_type;
+
+ explicit scoped_array(T* p = 0) : ptr(p) {}
+
+ ~scoped_array() {
+ typedef char type_must_be_complete[sizeof(T)];
+ delete[] ptr;
+ }
+
+ void reset(T* p = 0) {
+ typedef char type_must_be_complete[sizeof(T)];
+
+ if (ptr != p) {
+ delete [] ptr;
+ ptr = p;
+ }
+ }
+
+ T& operator[](std::ptrdiff_t i) const {
+ assert(ptr != 0);
+ assert(i >= 0);
+ return ptr[i];
+ }
+
+ T* get() const {
+ return ptr;
+ }
+
+ void swap(scoped_array & b) {
+ T* tmp = b.ptr;
+ b.ptr = ptr;
+ ptr = tmp;
+ }
+
+ T* release() {
+ T* tmp = ptr;
+ ptr = 0;
+ return tmp;
+ }
+
+ T** accept() {
+ if (ptr) {
+ delete [] ptr;
+ ptr = 0;
+ }
+ return &ptr;
+ }
+};
+
+template<class T> inline
+void swap(scoped_array<T>& a, scoped_array<T>& b) {
+ a.swap(b);
+}
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the function used to free the object.
+
+template<typename T, void (*FF)(void*) = free> class scoped_ptr_malloc {
+ private:
+
+ T* ptr;
+
+ scoped_ptr_malloc(scoped_ptr_malloc const &);
+ scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
+
+ public:
+
+ typedef T element_type;
+
+ explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
+
+ ~scoped_ptr_malloc() {
+ typedef char type_must_be_complete[sizeof(T)];
+ FF(static_cast<void*>(ptr));
+ }
+
+ void reset(T* p = 0) {
+ typedef char type_must_be_complete[sizeof(T)];
+
+ if (ptr != p) {
+ FF(static_cast<void*>(ptr));
+ ptr = p;
+ }
+ }
+
+ T& operator*() const {
+ assert(ptr != 0);
+ return *ptr;
+ }
+
+ T* operator->() const {
+ assert(ptr != 0);
+ return ptr;
+ }
+
+ T* get() const {
+ return ptr;
+ }
+
+ void swap(scoped_ptr_malloc & b) {
+ T* tmp = b.ptr;
+ b.ptr = ptr;
+ ptr = tmp;
+ }
+
+ T* release() {
+ T* tmp = ptr;
+ ptr = 0;
+ return tmp;
+ }
+
+ T** accept() {
+ if (ptr) {
+ FF(static_cast<void*>(ptr));
+ ptr = 0;
+ }
+ return &ptr;
+ }
+};
+
+template<typename T, void (*FF)(void*)> inline
+void swap(scoped_ptr_malloc<T,FF>& a, scoped_ptr_malloc<T,FF>& b) {
+ a.swap(b);
+}
+
+}
+
+using buzz::scoped_ptr;
+
+#endif // #ifndef SCOPED_PTR_H
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h
new file mode 100644
index 00000000..446516b8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h
@@ -0,0 +1,2700 @@
+// sigslot.h: Signal/Slot classes
+//
+// Written by Sarah Thompson (sarah@telergy.com) 2002.
+//
+// License: Public domain. You are free to use this code however you like, with the proviso that
+// the author takes on no responsibility or liability for any use.
+//
+// QUICK DOCUMENTATION
+//
+// (see also the full documentation at http://sigslot.sourceforge.net/)
+//
+// #define switches
+// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables
+// all of the thread safety support on platforms where it is
+// available.
+//
+// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than
+// gcc on a platform that supports Posix threads. (When using gcc,
+// this is the default - use SIGSLOT_PURE_ISO to disable this if
+// necessary)
+//
+// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global.
+// Otherwise, the default is single_threaded. #define this yourself to
+// override the default. In pure ISO mode, anything other than
+// single_threaded will cause a compiler error.
+//
+// PLATFORM NOTES
+//
+// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream
+// compilers do this by default, but you may need to define it
+// yourself if your build environment is less standard. This causes
+// the Win32 thread support to be compiled in and used automatically.
+//
+// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads
+// available, so they are used automatically. You can override this
+// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
+// something other than gcc but still want to use Posix threads, you
+// need to #define SIGSLOT_USE_POSIX_THREADS.
+//
+// ISO C++ - If none of the supported platforms are detected, or if
+// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
+// along with any code that might cause a pure ISO C++ environment to
+// complain. Before you ask, gcc -ansi -pedantic won't compile this
+// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
+// errors that aren't really there. If you feel like investigating this,
+// please contact the author.
+//
+//
+// THREADING MODES
+//
+// single_threaded - Your program is assumed to be single threaded from the point of view
+// of signal/slot usage (i.e. all objects using signals and slots are
+// created and destroyed from a single thread). Behaviour if objects are
+// destroyed concurrently is undefined (i.e. you'll get the occasional
+// segmentation fault/memory exception).
+//
+// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and
+// slots can be safely created and destroyed from any thread, even when
+// connections exist. In multi_threaded_global mode, this is achieved by a
+// single global mutex (actually a critical section on Windows because they
+// are faster). This option uses less OS resources, but results in more
+// opportunities for contention, possibly resulting in more context switches
+// than are strictly necessary.
+//
+// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global,
+// except that each signal, and each object that inherits has_slots, all
+// have their own mutex/critical section. In practice, this means that
+// mutex collisions (and hence context switches) only happen if they are
+// absolutely essential. However, on some platforms, creating a lot of
+// mutexes can slow down the whole OS, so use this option with care.
+//
+// USING THE LIBRARY
+//
+// See the full documentation at http://sigslot.sourceforge.net/
+//
+//
+
+#ifndef SIGSLOT_H__
+#define SIGSLOT_H__
+
+#include <set>
+#include <list>
+
+// On our copy of sigslot.h, we force single threading
+#define SIGSLOT_PURE_ISO
+
+#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
+# define _SIGSLOT_SINGLE_THREADED
+#elif defined(WIN32)
+# define _SIGSLOT_HAS_WIN32_THREADS
+# include <windows.h>
+#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
+# define _SIGSLOT_HAS_POSIX_THREADS
+# include <pthread.h>
+#else
+# define _SIGSLOT_SINGLE_THREADED
+#endif
+
+#ifndef SIGSLOT_DEFAULT_MT_POLICY
+# ifdef _SIGSLOT_SINGLE_THREADED
+# define SIGSLOT_DEFAULT_MT_POLICY single_threaded
+# else
+# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
+# endif
+#endif
+
+
+namespace sigslot {
+
+ class single_threaded
+ {
+ public:
+ single_threaded()
+ {
+ ;
+ }
+
+ virtual ~single_threaded()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ ;
+ }
+
+ virtual void unlock()
+ {
+ ;
+ }
+ };
+
+#ifdef _SIGSLOT_HAS_WIN32_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ static bool isinitialised = false;
+
+ if(!isinitialised)
+ {
+ InitializeCriticalSection(get_critsec());
+ isinitialised = true;
+ }
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ virtual ~multi_threaded_global()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ EnterCriticalSection(get_critsec());
+ }
+
+ virtual void unlock()
+ {
+ LeaveCriticalSection(get_critsec());
+ }
+
+ private:
+ CRITICAL_SECTION* get_critsec()
+ {
+ static CRITICAL_SECTION g_critsec;
+ return &g_critsec;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ virtual ~multi_threaded_local()
+ {
+ DeleteCriticalSection(&m_critsec);
+ }
+
+ virtual void lock()
+ {
+ EnterCriticalSection(&m_critsec);
+ }
+
+ virtual void unlock()
+ {
+ LeaveCriticalSection(&m_critsec);
+ }
+
+ private:
+ CRITICAL_SECTION m_critsec;
+ };
+#endif // _SIGSLOT_HAS_WIN32_THREADS
+
+#ifdef _SIGSLOT_HAS_POSIX_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ pthread_mutex_init(get_mutex(), NULL);
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ virtual ~multi_threaded_global()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ pthread_mutex_lock(get_mutex());
+ }
+
+ virtual void unlock()
+ {
+ pthread_mutex_unlock(get_mutex());
+ }
+
+ private:
+ pthread_mutex_t* get_mutex()
+ {
+ static pthread_mutex_t g_mutex;
+ return &g_mutex;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ virtual ~multi_threaded_local()
+ {
+ pthread_mutex_destroy(&m_mutex);
+ }
+
+ virtual void lock()
+ {
+ pthread_mutex_lock(&m_mutex);
+ }
+
+ virtual void unlock()
+ {
+ pthread_mutex_unlock(&m_mutex);
+ }
+
+ private:
+ pthread_mutex_t m_mutex;
+ };
+#endif // _SIGSLOT_HAS_POSIX_THREADS
+
+ template<class mt_policy>
+ class lock_block
+ {
+ public:
+ mt_policy *m_mutex;
+
+ lock_block(mt_policy *mtx)
+ : m_mutex(mtx)
+ {
+ m_mutex->lock();
+ }
+
+ ~lock_block()
+ {
+ m_mutex->unlock();
+ }
+ };
+
+ template<class mt_policy>
+ class has_slots;
+
+ template<class mt_policy>
+ class _connection_base0
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit() = 0;
+ virtual _connection_base0* clone() = 0;
+ virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _connection_base1
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type) = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* clone() = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _connection_base2
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type) = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection_base3
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type) = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _connection_base4
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _connection_base5
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type) = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone() = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _connection_base6
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type) = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone() = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection_base7
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type) = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _connection_base8
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type, arg8_type) = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class mt_policy>
+ class _signal_base : public mt_policy
+ {
+ public:
+ virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
+ virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0;
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class has_slots : public mt_policy
+ {
+ private:
+ typedef typename std::set<_signal_base<mt_policy> *> sender_set;
+ typedef typename sender_set::const_iterator const_iterator;
+
+ public:
+ has_slots()
+ {
+ ;
+ }
+
+ has_slots(const has_slots& hs)
+ : mt_policy(hs)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = hs.m_senders.begin();
+ const_iterator itEnd = hs.m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_duplicate(&hs, this);
+ m_senders.insert(*it);
+ ++it;
+ }
+ }
+
+ void signal_connect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.insert(sender);
+ }
+
+ void signal_disconnect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.erase(sender);
+ }
+
+ virtual ~has_slots()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_senders.begin();
+ const_iterator itEnd = m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_disconnect(this);
+ ++it;
+ }
+
+ m_senders.erase(m_senders.begin(), m_senders.end());
+ }
+
+ private:
+ sender_set m_senders;
+ };
+
+ template<class mt_policy>
+ class _signal_base0 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base0<mt_policy> *> connections_list;
+
+ _signal_base0()
+ {
+ ;
+ }
+
+ _signal_base0(const _signal_base0& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ ~_signal_base0()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _signal_base1 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base1<arg1_type, mt_policy> *> connections_list;
+
+ _signal_base1()
+ {
+ ;
+ }
+
+ _signal_base1(const _signal_base1<arg1_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base1()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _signal_base2 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>
+ connections_list;
+
+ _signal_base2()
+ {
+ ;
+ }
+
+ _signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base2()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _signal_base3 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>
+ connections_list;
+
+ _signal_base3()
+ {
+ ;
+ }
+
+ _signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base3()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _signal_base4 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy> *> connections_list;
+
+ _signal_base4()
+ {
+ ;
+ }
+
+ _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base4()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _signal_base5 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy> *> connections_list;
+
+ _signal_base5()
+ {
+ ;
+ }
+
+ _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base5()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _signal_base6 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy> *> connections_list;
+
+ _signal_base6()
+ {
+ ;
+ }
+
+ _signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base6()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _signal_base7 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *> connections_list;
+
+ _signal_base7()
+ {
+ ;
+ }
+
+ _signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base7()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _signal_base8 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>
+ connections_list;
+
+ _signal_base8()
+ {
+ ;
+ }
+
+ _signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base8()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#ifdef _DEBUG
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+
+ template<class dest_type, class mt_policy>
+ class _connection0 : public _connection_base0<mt_policy>
+ {
+ public:
+ _connection0()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection0(dest_type* pobject, void (dest_type::*pmemfun)())
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base0<mt_policy>* clone()
+ {
+ return new _connection0<dest_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit()
+ {
+ (m_pobject->*m_pmemfun)();
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)();
+ };
+
+ template<class dest_type, class arg1_type, class mt_policy>
+ class _connection1 : public _connection_base1<arg1_type, mt_policy>
+ {
+ public:
+ _connection1()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* clone()
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1)
+ {
+ (m_pobject->*m_pmemfun)(a1);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class mt_policy>
+ class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ _connection2()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ _connection3()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class mt_policy>
+ class _connection4 : public _connection_base4<arg1_type, arg2_type,
+ arg3_type, arg4_type, mt_policy>
+ {
+ public:
+ _connection4()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3,
+ arg4_type a4)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,
+ arg4_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class mt_policy>
+ class _connection5 : public _connection_base5<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ _connection5()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone()
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class mt_policy>
+ class _connection6 : public _connection_base6<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ _connection6()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone()
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection7 : public _connection_base7<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ _connection7()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone()
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type,
+ class arg8_type, class mt_policy>
+ class _connection8 : public _connection_base8<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ _connection8()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type);
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal0 : public _signal_base0<mt_policy>
+ {
+ public:
+ typedef _signal_base0<mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal0()
+ {
+ ;
+ }
+
+ signal0(const signal0<mt_policy>& s)
+ : _signal_base0<mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)())
+ {
+ lock_block<mt_policy> lock(this);
+ _connection0<desttype, mt_policy>* conn =
+ new _connection0<desttype, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+
+ void operator()()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal1 : public _signal_base1<arg1_type, mt_policy>
+ {
+ public:
+ typedef _signal_base1<arg1_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal1()
+ {
+ ;
+ }
+
+ signal1(const signal1<arg1_type, mt_policy>& s)
+ : _signal_base1<arg1_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection1<desttype, arg1_type, mt_policy>* conn =
+ new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ typedef _signal_base2<arg1_type, arg2_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal2()
+ {
+ ;
+ }
+
+ signal2(const signal2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base2<arg1_type, arg2_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ typedef _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal3()
+ {
+ ;
+ }
+
+ signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn =
+ new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,
+ pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>
+ {
+ public:
+ typedef _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal4()
+ {
+ ;
+ }
+
+ signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*
+ conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ typedef _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal5()
+ {
+ ;
+ }
+
+ signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+ };
+
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ typedef _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal6()
+ {
+ ;
+ }
+
+ signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* conn =
+ new _connection6<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ typedef _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal7()
+ {
+ ;
+ }
+
+ signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* conn =
+ new _connection7<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ typedef _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal8()
+ {
+ ;
+ }
+
+ signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn =
+ new _connection8<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type,
+ arg8_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+ };
+
+}; // namespace sigslot
+
+#endif // SIGSLOT_H__
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h
new file mode 100644
index 00000000..d4a49d96
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h
@@ -0,0 +1,158 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _socket_h_
+#define _socket_h_
+
+#include "talk/base/basictypes.h"
+#include "talk/base/socketaddress.h"
+
+#ifdef POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#endif
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+// Rather than converting errors into a private namespace,
+// Reuse the POSIX socket api errors. Note this depends on
+// Win32 compatibility.
+
+#ifdef WIN32
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+#undef ENAMETOOLONG // remove errno.h's definition
+#define ENAMETOOLONG WSAENAMETOOLONG
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#undef ENOTEMPTY // remove errno.h's definition
+#define ENOTEMPTY WSAENOTEMPTY
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+#undef EACCES
+#define EACCES WSAEACCES
+#endif // WIN32
+
+#ifdef POSIX
+#define INVALID_SOCKET (-1)
+#define SOCKET_ERROR (-1)
+#define closesocket(s) close(s)
+#endif // POSIX
+
+namespace cricket {
+
+inline bool IsBlockingError(int e) {
+ return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS);
+}
+
+// General interface for the socket implementations of various networks. The
+// methods match those of normal UNIX sockets very closely.
+class Socket {
+public:
+ virtual ~Socket() {}
+
+ // Returns the address to which the socket is bound. If the socket is not
+ // bound, then the any-address is returned.
+ virtual SocketAddress GetLocalAddress() const = 0;
+
+ // Returns the address to which the socket is connected. If the socket is
+ // not connected, then the any-address is returned.
+ virtual SocketAddress GetRemoteAddress() const = 0;
+
+ virtual int Bind(const SocketAddress& addr) = 0;
+ virtual int Connect(const SocketAddress& addr) = 0;
+ virtual int Send(const void *pv, size_t cb) = 0;
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
+ virtual int Recv(void *pv, size_t cb) = 0;
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) = 0;
+ virtual int Listen(int backlog) = 0;
+ virtual Socket *Accept(SocketAddress *paddr) = 0;
+ virtual int Close() = 0;
+ virtual int GetError() const = 0;
+ virtual void SetError(int error) = 0;
+ inline bool IsBlocking() const { return IsBlockingError(GetError()); }
+
+ enum ConnState {
+ CS_CLOSED,
+ CS_CONNECTING,
+ CS_CONNECTED
+ };
+ virtual ConnState GetState() const = 0;
+
+ // Fills in the given uint16 with the current estimate of the MTU along the
+ // path to the address to which this socket is connected.
+ virtual int EstimateMTU(uint16* mtu) = 0;
+
+ enum Option {
+ OPT_DONTFRAGMENT
+ };
+ virtual int SetOption(Option opt, int value) = 0;
+
+protected:
+ Socket() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Socket);
+};
+
+} // namespace cricket
+
+#endif // _socket_h_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc
new file mode 100644
index 00000000..049e923c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc
@@ -0,0 +1,1130 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <time.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#include <wininet.h> // HTTP_STATUS_PROXY_AUTH_REQ
+#define SECURITY_WIN32
+#include <security.h>
+#endif
+
+#include <cassert>
+
+#include "talk/base/base64.h"
+#include "talk/base/basicdefs.h"
+#include "talk/base/bytebuffer.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/md5.h"
+#include "talk/base/socketadapters.h"
+#include "talk/base/stringutils.h"
+
+#include <errno.h>
+
+
+#ifdef WIN32
+#include "talk/base/sec_buffer.h"
+#endif // WIN32
+
+namespace cricket {
+
+#ifdef WIN32
+extern const ConstantLabel SECURITY_ERRORS[];
+#endif
+
+BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size)
+ : AsyncSocketAdapter(socket), buffer_size_(buffer_size), data_len_(0), buffering_(false) {
+ buffer_ = new char[buffer_size_];
+}
+
+BufferedReadAdapter::~BufferedReadAdapter() {
+ delete [] buffer_;
+}
+
+int BufferedReadAdapter::Send(const void *pv, size_t cb) {
+ if (buffering_) {
+ // TODO: Spoof error better; Signal Writeable
+ socket_->SetError(EWOULDBLOCK);
+ return -1;
+ }
+ return AsyncSocketAdapter::Send(pv, cb);
+}
+
+int BufferedReadAdapter::Recv(void *pv, size_t cb) {
+ if (buffering_) {
+ socket_->SetError(EWOULDBLOCK);
+ return -1;
+ }
+
+ size_t read = 0;
+
+ if (data_len_) {
+ read = _min(cb, data_len_);
+ memcpy(pv, buffer_, read);
+ data_len_ -= read;
+ if (data_len_ > 0) {
+ memmove(buffer_, buffer_ + read, data_len_);
+ }
+ pv = static_cast<char *>(pv) + read;
+ cb -= read;
+ }
+
+ // FIX: If cb == 0, we won't generate another read event
+
+ int res = AsyncSocketAdapter::Recv(pv, cb);
+ if (res < 0)
+ return res;
+
+ return res + static_cast<int>(read);
+}
+
+void BufferedReadAdapter::BufferInput(bool on) {
+ buffering_ = on;
+}
+
+void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
+ assert(socket == socket_);
+
+ if (!buffering_) {
+ AsyncSocketAdapter::OnReadEvent(socket);
+ return;
+ }
+
+ if (data_len_ >= buffer_size_) {
+ LOG(INFO) << "Input buffer overflow";
+ assert(false);
+ data_len_ = 0;
+ }
+
+ int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ LOG(INFO) << "Recv: " << errno << " " << std::strerror(errno);
+ return;
+ }
+
+ data_len_ += len;
+
+ ProcessInput(buffer_, data_len_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const uint8 SSL_SERVER_HELLO[] = {
+ 22,3,1,0,74,2,0,0,70,3,1,66,133,69,167,39,169,93,160,
+ 179,197,231,83,218,72,43,63,198,90,202,137,193,88,82,
+ 161,120,60,91,23,70,0,133,63,32,14,211,6,114,91,91,
+ 27,95,21,172,19,249,136,83,157,155,232,61,123,12,48,
+ 50,110,56,77,162,117,87,65,108,52,92,0,4,0
+};
+
+const char SSL_CLIENT_HELLO[] = {
+ -128,70,1,3,1,0,45,0,0,0,16,1,0,-128,3,0,-128,7,0,-64,6,0,64,2,0,
+ -128,4,0,-128,0,0,4,0,-2,-1,0,0,10,0,-2,-2,0,0,9,0,0,100,0,0,98,0,
+ 0,3,0,0,6,31,23,12,-90,47,0,120,-4,70,85,46,-79,-125,57,-15,-22
+};
+
+AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) : BufferedReadAdapter(socket, 1024) {
+}
+
+int AsyncSSLSocket::Connect(const SocketAddress& addr) {
+ // Begin buffering before we connect, so that there isn't a race condition between
+ // potential senders and receiving the OnConnectEvent signal
+ BufferInput(true);
+ return BufferedReadAdapter::Connect(addr);
+}
+
+void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
+ assert(socket == socket_);
+
+ // TODO: we could buffer output too...
+ int res = DirectSend(SSL_CLIENT_HELLO, sizeof(SSL_CLIENT_HELLO));
+ assert(res == sizeof(SSL_CLIENT_HELLO));
+}
+
+void AsyncSSLSocket::ProcessInput(char * data, size_t& len) {
+ if (len < sizeof(SSL_SERVER_HELLO))
+ return;
+
+ if (memcmp(SSL_SERVER_HELLO, data, sizeof(SSL_SERVER_HELLO)) != 0) {
+ Close();
+ SignalCloseEvent(this, 0); // TODO: error code?
+ return;
+ }
+
+ len -= sizeof(SSL_SERVER_HELLO);
+ if (len > 0) {
+ memmove(data, data + sizeof(SSL_SERVER_HELLO), len);
+ }
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define TEST_DIGEST 0
+#if TEST_DIGEST
+/*
+const char * const DIGEST_CHALLENGE =
+ "Digest realm=\"testrealm@host.com\","
+ " qop=\"auth,auth-int\","
+ " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
+ " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+const char * const DIGEST_METHOD = "GET";
+const char * const DIGEST_URI =
+ "/dir/index.html";;
+const char * const DIGEST_CNONCE =
+ "0a4f113b";
+const char * const DIGEST_RESPONSE =
+ "6629fae49393a05397450978507c4ef1";
+//user_ = "Mufasa";
+//pass_ = "Circle Of Life";
+*/
+const char * const DIGEST_CHALLENGE =
+ "Digest realm=\"Squid proxy-caching web server\","
+ " nonce=\"Nny4QuC5PwiSDixJ\","
+ " qop=\"auth\","
+ " stale=false";
+const char * const DIGEST_URI =
+ "/";
+const char * const DIGEST_CNONCE =
+ "6501d58e9a21cee1e7b5fec894ded024";
+const char * const DIGEST_RESPONSE =
+ "edffcb0829e755838b073a4a42de06bc";
+#endif
+
+static std::string MD5(const std::string& data) {
+ MD5_CTX ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx, const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(data.data())), static_cast<unsigned int>(data.size()));
+ unsigned char digest[16];
+ MD5Final(digest, &ctx);
+ std::string hex_digest;
+ const char HEX[] = "0123456789abcdef";
+ for (int i=0; i<16; ++i) {
+ hex_digest += HEX[digest[i] >> 4];
+ hex_digest += HEX[digest[i] & 0xf];
+ }
+ return hex_digest;
+}
+
+static std::string Quote(const std::string& str) {
+ std::string result;
+ result.push_back('"');
+ for (size_t i=0; i<str.size(); ++i) {
+ if ((str[i] == '"') || (str[i] == '\\'))
+ result.push_back('\\');
+ result.push_back(str[i]);
+ }
+ result.push_back('"');
+ return result;
+}
+
+#ifdef WIN32
+struct NegotiateAuthContext : public AsyncHttpsProxySocket::AuthContext {
+ CredHandle cred;
+ CtxtHandle ctx;
+ size_t steps;
+ bool specified_credentials;
+
+ NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
+ : AuthContext(auth), cred(c1), ctx(c2), steps(0), specified_credentials(false) { }
+
+ virtual ~NegotiateAuthContext() {
+ DeleteSecurityContext(&ctx);
+ FreeCredentialsHandle(&cred);
+ }
+};
+#endif // WIN32
+
+AsyncHttpsProxySocket::AuthResult
+AsyncHttpsProxySocket::Authenticate(const char * challenge, size_t len,
+ const SocketAddress& server,
+ const std::string& method, const std::string& uri,
+ const std::string& username, const buzz::XmppPassword& password,
+ AuthContext *& context, std::string& response, std::string& auth_method) {
+#if TEST_DIGEST
+ challenge = DIGEST_CHALLENGE;
+ len = strlen(challenge);
+#endif
+
+ std::map<std::string, std::string> args;
+ ParseAuth(challenge, len, auth_method, args);
+
+ if (context && (context->auth_method != auth_method))
+ return AR_IGNORE;
+
+ // BASIC
+ if (stricmp(auth_method.c_str(), "basic") == 0) {
+ if (context)
+ return AR_CREDENTIALS; // Bad credentials
+ if (username.empty())
+ return AR_CREDENTIALS; // Missing credentials
+
+ context = new AuthContext(auth_method);
+
+ // TODO: convert sensitive to a secure buffer that gets securely deleted
+ //std::string decoded = username + ":" + password;
+ size_t len = username.size() + password.GetLength() + 2;
+ char * sensitive = new char[len];
+ size_t pos = strcpyn(sensitive, len, username.data(), username.size());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ password.CopyTo(sensitive + pos, true);
+
+ response = auth_method;
+ response.append(" ");
+ // TODO: create a sensitive-source version of Base64::encode
+ response.append(Base64::encode(sensitive));
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ return AR_RESPONSE;
+ }
+
+ // DIGEST
+ if (stricmp(auth_method.c_str(), "digest") == 0) {
+ if (context)
+ return AR_CREDENTIALS; // Bad credentials
+ if (username.empty())
+ return AR_CREDENTIALS; // Missing credentials
+
+ context = new AuthContext(auth_method);
+
+ std::string cnonce, ncount;
+#if TEST_DIGEST
+ method = DIGEST_METHOD;
+ uri = DIGEST_URI;
+ cnonce = DIGEST_CNONCE;
+#else
+ char buffer[256];
+ sprintf(buffer, "%d", time(0));
+ cnonce = MD5(buffer);
+#endif
+ ncount = "00000001";
+
+ // TODO: convert sensitive to be secure buffer
+ //std::string A1 = username + ":" + args["realm"] + ":" + password;
+ size_t len = username.size() + args["realm"].size() + password.GetLength() + 3;
+ char * sensitive = new char[len]; // A1
+ size_t pos = strcpyn(sensitive, len, username.data(), username.size());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ pos += strcpyn(sensitive + pos, len - pos, args["realm"].c_str());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ password.CopyTo(sensitive + pos, true);
+
+ std::string A2 = method + ":" + uri;
+ std::string middle;
+ if (args.find("qop") != args.end()) {
+ args["qop"] = "auth";
+ middle = args["nonce"] + ":" + ncount + ":" + cnonce + ":" + args["qop"];
+ } else {
+ middle = args["nonce"];
+ }
+ std::string HA1 = MD5(sensitive);
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ std::string HA2 = MD5(A2);
+ std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
+
+#if TEST_DIGEST
+ assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
+#endif
+
+ std::stringstream ss;
+ ss << auth_method;
+ ss << " username=" << Quote(username);
+ ss << ", realm=" << Quote(args["realm"]);
+ ss << ", nonce=" << Quote(args["nonce"]);
+ ss << ", uri=" << Quote(uri);
+ if (args.find("qop") != args.end()) {
+ ss << ", qop=" << args["qop"];
+ ss << ", nc=" << ncount;
+ ss << ", cnonce=" << Quote(cnonce);
+ }
+ ss << ", response=\"" << dig_response << "\"";
+ if (args.find("opaque") != args.end()) {
+ ss << ", opaque=" << Quote(args["opaque"]);
+ }
+ response = ss.str();
+ return AR_RESPONSE;
+ }
+
+#ifdef WIN32
+#if 1
+ bool want_negotiate = (stricmp(auth_method.c_str(), "negotiate") == 0);
+ bool want_ntlm = (stricmp(auth_method.c_str(), "ntlm") == 0);
+ // SPNEGO & NTLM
+ if (want_negotiate || want_ntlm) {
+ const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
+ char out_buf[MAX_MESSAGE], spn[MAX_SPN];
+
+#if 0 // Requires funky windows versions
+ DWORD len = MAX_SPN;
+ if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(), 0, &len, spn) != ERROR_SUCCESS) {
+ LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) - DsMakeSpn failed";
+ return AR_IGNORE;
+ }
+#else
+ sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());
+#endif
+
+ SecBuffer out_sec;
+ out_sec.pvBuffer = out_buf;
+ out_sec.cbBuffer = sizeof(out_buf);
+ out_sec.BufferType = SECBUFFER_TOKEN;
+
+ SecBufferDesc out_buf_desc;
+ out_buf_desc.ulVersion = 0;
+ out_buf_desc.cBuffers = 1;
+ out_buf_desc.pBuffers = &out_sec;
+
+ const ULONG NEG_FLAGS_DEFAULT =
+ //ISC_REQ_ALLOCATE_MEMORY
+ ISC_REQ_CONFIDENTIALITY
+ //| ISC_REQ_EXTENDED_ERROR
+ //| ISC_REQ_INTEGRITY
+ | ISC_REQ_REPLAY_DETECT
+ | ISC_REQ_SEQUENCE_DETECT
+ //| ISC_REQ_STREAM
+ //| ISC_REQ_USE_SUPPLIED_CREDS
+ ;
+
+ TimeStamp lifetime;
+ SECURITY_STATUS ret = S_OK;
+ ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT;
+
+ bool specify_credentials = !username.empty();
+ size_t steps = 0;
+
+ //uint32 now = cricket::Time();
+
+ NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context);
+ if (neg) {
+ const size_t max_steps = 10;
+ if (++neg->steps >= max_steps) {
+ LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries";
+ return AR_ERROR;
+ }
+ steps = neg->steps;
+
+ std::string decoded_challenge = Base64::decode(args[""]);
+ if (!decoded_challenge.empty()) {
+ SecBuffer in_sec;
+ in_sec.pvBuffer = const_cast<char *>(decoded_challenge.data());
+ in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size());
+ in_sec.BufferType = SECBUFFER_TOKEN;
+
+ SecBufferDesc in_buf_desc;
+ in_buf_desc.ulVersion = 0;
+ in_buf_desc.cBuffers = 1;
+ in_buf_desc.pBuffers = &in_sec;
+
+ ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
+ //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now);
+ if (FAILED(ret)) {
+ LOG(LS_ERROR) << "InitializeSecurityContext returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ return AR_ERROR;
+ }
+ } else if (neg->specified_credentials) {
+ // Try again with default credentials
+ specify_credentials = false;
+ delete context;
+ context = neg = 0;
+ } else {
+ return AR_CREDENTIALS;
+ }
+ }
+
+ if (!neg) {
+ unsigned char userbuf[256], passbuf[256], domainbuf[16];
+ SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0;
+ if (specify_credentials) {
+ memset(&auth_id, 0, sizeof(auth_id));
+ size_t len = password.GetLength()+1;
+ char * sensitive = new char[len];
+ password.CopyTo(sensitive, true);
+ std::string::size_type pos = username.find('\\');
+ if (pos == std::string::npos) {
+ auth_id.UserLength = static_cast<unsigned long>(
+ _min(sizeof(userbuf) - 1, username.size()));
+ memcpy(userbuf, username.c_str(), auth_id.UserLength);
+ userbuf[auth_id.UserLength] = 0;
+ auth_id.DomainLength = 0;
+ domainbuf[auth_id.DomainLength] = 0;
+ auth_id.PasswordLength = static_cast<unsigned long>(
+ _min(sizeof(passbuf) - 1, password.GetLength()));
+ memcpy(passbuf, sensitive, auth_id.PasswordLength);
+ passbuf[auth_id.PasswordLength] = 0;
+ } else {
+ auth_id.UserLength = static_cast<unsigned long>(
+ _min(sizeof(userbuf) - 1, username.size() - pos - 1));
+ memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength);
+ userbuf[auth_id.UserLength] = 0;
+ auth_id.DomainLength = static_cast<unsigned long>(
+ _min(sizeof(domainbuf) - 1, pos));
+ memcpy(domainbuf, username.c_str(), auth_id.DomainLength);
+ domainbuf[auth_id.DomainLength] = 0;
+ auth_id.PasswordLength = static_cast<unsigned long>(
+ _min(sizeof(passbuf) - 1, password.GetLength()));
+ memcpy(passbuf, sensitive, auth_id.PasswordLength);
+ passbuf[auth_id.PasswordLength] = 0;
+ }
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ auth_id.User = userbuf;
+ auth_id.Domain = domainbuf;
+ auth_id.Password = passbuf;
+ auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+ pauth_id = &auth_id;
+ LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials";
+ } else {
+ LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials";
+ }
+
+ CredHandle cred;
+ ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime);
+ //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << cricket::TimeDiff(cricket::Time(), now);
+ if (ret != SEC_E_OK) {
+ LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ return AR_IGNORE;
+ }
+
+ //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
+
+ CtxtHandle ctx;
+ ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime);
+ //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now);
+ if (FAILED(ret)) {
+ LOG(LS_ERROR) << "InitializeSecurityContext returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ FreeCredentialsHandle(&cred);
+ return AR_IGNORE;
+ }
+
+ assert(!context);
+ context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
+ neg->specified_credentials = specify_credentials;
+ neg->steps = steps;
+ }
+
+ if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
+ ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
+ //LOG(INFO) << "$$$ CompleteAuthToken @ " << cricket::TimeDiff(cricket::Time(), now);
+ LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ if (FAILED(ret)) {
+ return AR_ERROR;
+ }
+ }
+
+ //LOG(INFO) << "$$$ NEGOTIATE took " << cricket::TimeDiff(cricket::Time(), now) << "ms";
+
+ std::string decoded(out_buf, out_buf + out_sec.cbBuffer);
+ response = auth_method;
+ response.append(" ");
+ response.append(Base64::encode(decoded));
+ return AR_RESPONSE;
+ }
+#endif
+#endif // WIN32
+
+ return AR_IGNORE;
+}
+
+inline bool end_of_name(size_t pos, size_t len, const char * data) {
+ if (pos >= len)
+ return true;
+ if (isspace(data[pos]))
+ return true;
+ // The reason for this complexity is that some non-compliant auth schemes (like Negotiate)
+ // use base64 tokens in the challenge instead of name=value. This could confuse us when the
+ // base64 ends in equal signs.
+ if ((pos+1 < len) && (data[pos] == '=') && !isspace(data[pos+1]) && (data[pos+1] != '='))
+ return true;
+ return false;
+}
+
+void AsyncHttpsProxySocket::ParseAuth(const char * data, size_t len, std::string& method, std::map<std::string,std::string>& args) {
+ size_t pos = 0;
+ while ((pos < len) && isspace(data[pos])) ++pos;
+ size_t start = pos;
+ while ((pos < len) && !isspace(data[pos])) ++pos;
+ method.assign(data + start, data + pos);
+ while (pos < len) {
+ while ((pos < len) && isspace(data[pos])) ++pos;
+ if (pos >= len)
+ return;
+
+ start = pos;
+ while (!end_of_name(pos, len, data)) ++pos;
+ //while ((pos < len) && !isspace(data[pos]) && (data[pos] != '=')) ++pos;
+ std::string name(data + start, data + pos), value;
+
+ if ((pos < len) && (data[pos] == '=')) {
+ ++pos; // Skip '='
+ // Check if quoted value
+ if ((pos < len) && (data[pos] == '"')) {
+ while (++pos < len) {
+ if (data[pos] == '"') {
+ ++pos;
+ break;
+ }
+ if ((data[pos] == '\\') && (pos + 1 < len))
+ ++pos;
+ value.append(1, data[pos]);
+ }
+ } else {
+ while ((pos < len) && !isspace(data[pos]) && (data[pos] != ','))
+ value.append(1, data[pos++]);
+ }
+ } else {
+ value = name;
+ name.clear();
+ }
+
+ args.insert(std::make_pair(name, value));
+ if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ','
+ }
+}
+
+AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const buzz::XmppPassword& password)
+ : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password),
+ state_(PS_ERROR), context_(0) {
+}
+
+AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
+ delete context_;
+}
+
+int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect(" << proxy_.ToString() << ")";
+ dest_ = addr;
+ if (dest_.port() != 80) {
+ BufferInput(true);
+ }
+ return BufferedReadAdapter::Connect(proxy_);
+}
+
+SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
+ return dest_;
+}
+
+int AsyncHttpsProxySocket::Close() {
+ headers_.clear();
+ state_ = PS_ERROR;
+ delete context_;
+ context_ = 0;
+ return BufferedReadAdapter::Close();
+}
+
+void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
+ // TODO: Decide whether tunneling or not should be explicitly set,
+ // or indicated by destination port (as below)
+ if (dest_.port() == 80) {
+ state_ = PS_TUNNEL;
+ BufferedReadAdapter::OnConnectEvent(socket);
+ return;
+ }
+ SendRequest();
+}
+
+void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
+ if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
+ state_ = PS_ERROR;
+ Connect(dest_);
+ } else {
+ BufferedReadAdapter::OnCloseEvent(socket, err);
+ }
+}
+
+void AsyncHttpsProxySocket::ProcessInput(char * data, size_t& len) {
+ size_t start = 0;
+ for (size_t pos = start; (state_ < PS_TUNNEL) && (pos < len); ) {
+ if (state_ == PS_SKIP_BODY) {
+ size_t consume = _min(len - pos, content_length_);
+ pos += consume;
+ start = pos;
+ content_length_ -= consume;
+ if (content_length_ == 0) {
+ EndResponse();
+ }
+ continue;
+ }
+
+ if (data[pos++] != '\n')
+ continue;
+
+ size_t len = pos - start - 1;
+ if ((len > 0) && (data[start + len - 1] == '\r'))
+ --len;
+
+ data[start + len] = 0;
+ ProcessLine(data + start, len);
+ start = pos;
+ }
+
+ len -= start;
+ if (len > 0) {
+ memmove(data, data + start, len);
+ }
+
+ if (state_ != PS_TUNNEL)
+ return;
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this); // TODO: signal this??
+}
+
+void AsyncHttpsProxySocket::SendRequest() {
+ std::stringstream ss;
+ ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
+ ss << "User-Agent: " USERAGENT_STRING "\r\n";
+ ss << "Host: " << dest_.IPAsString() << "\r\n";
+ ss << "Content-Length: 0\r\n";
+ ss << "Proxy-Connection: Keep-Alive\r\n";
+ ss << headers_;
+ ss << "\r\n";
+ std::string str = ss.str();
+ DirectSend(str.c_str(), str.size());
+ state_ = PS_LEADER;
+ expect_close_ = true;
+ content_length_ = 0;
+ headers_.clear();
+
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
+}
+
+void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
+
+ if (len == 0) {
+ if (state_ == PS_TUNNEL_HEADERS) {
+ state_ = PS_TUNNEL;
+ } else if (state_ == PS_ERROR_HEADERS) {
+ Error(defer_error_);
+ return;
+ } else if (state_ == PS_SKIP_HEADERS) {
+ if (content_length_) {
+ state_ = PS_SKIP_BODY;
+ } else {
+ EndResponse();
+ return;
+ }
+ } else {
+ static bool report = false;
+ if (!unknown_mechanisms_.empty() && !report) {
+ report = true;
+ std::string msg(
+ "Unable to connect to the Google Talk service due to an incompatibility "
+ "with your proxy.\r\nPlease help us resolve this issue by submitting the "
+ "following information to us using our technical issue submission form "
+ "at:\r\n\r\n"
+ "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
+ "We apologize for the inconvenience.\r\n\r\n"
+ "Information to submit to Google: "
+ );
+ //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: ");
+ msg.append(unknown_mechanisms_);
+#ifdef WIN32
+ MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
+#endif
+#ifdef POSIX
+ //TODO: Raise a signal or something so the UI can be separated.
+ LOG(LS_ERROR) << "Oops!\n\n" << msg;
+#endif
+ }
+ // Unexpected end of headers
+ Error(0);
+ return;
+ }
+ } else if (state_ == PS_LEADER) {
+ uint32 code;
+ if (sscanf(data, "HTTP/%*lu.%*lu %lu", &code) != 1) {
+ Error(0);
+ return;
+ }
+ switch (code) {
+ case 200:
+ // connection good!
+ state_ = PS_TUNNEL_HEADERS;
+ return;
+#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
+#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
+#endif
+ case 407: // HTTP_STATUS_PROXY_AUTH_REQ
+ state_ = PS_AUTHENTICATE;
+ return;
+ default:
+ defer_error_ = 0;
+ state_ = PS_ERROR_HEADERS;
+ return;
+ }
+ } else if ((state_ == PS_AUTHENTICATE) && (strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
+ std::string response, auth_method;
+ switch (Authenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_, pass_, context_, response, auth_method)) {
+ case AR_IGNORE:
+ LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
+ if (!unknown_mechanisms_.empty())
+ unknown_mechanisms_.append(", ");
+ unknown_mechanisms_.append(auth_method);
+ break;
+ case AR_RESPONSE:
+ headers_ = "Proxy-Authorization: ";
+ headers_.append(response);
+ headers_.append("\r\n");
+ state_ = PS_SKIP_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ case AR_CREDENTIALS:
+ defer_error_ = EACCES;
+ state_ = PS_ERROR_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ case AR_ERROR:
+ defer_error_ = 0;
+ state_ = PS_ERROR_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ }
+ } else if (strnicmp(data, "Content-Length:", 15) == 0) {
+ content_length_ = strtoul(data + 15, 0, 0);
+ } else if (strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) {
+ expect_close_ = false;
+ /*
+ } else if (strnicmp(data, "Connection: close", 17) == 0) {
+ expect_close_ = true;
+ */
+ }
+}
+
+void AsyncHttpsProxySocket::EndResponse() {
+ if (!expect_close_) {
+ SendRequest();
+ return;
+ }
+
+ // No point in waiting for the server to close... let's close now
+ // TODO: Refactor out PS_WAIT_CLOSE
+ state_ = PS_WAIT_CLOSE;
+ BufferedReadAdapter::Close();
+ OnCloseEvent(this, 0);
+}
+
+void AsyncHttpsProxySocket::Error(int error) {
+ BufferInput(false);
+ Close();
+ SetError(error);
+ SignalCloseEvent(this, error);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const buzz::XmppPassword& password)
+ : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password),
+ state_(SS_ERROR) {
+}
+
+int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
+ dest_ = addr;
+ BufferInput(true);
+ return BufferedReadAdapter::Connect(proxy_);
+}
+
+SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
+ return dest_;
+}
+
+void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket * socket) {
+ SendHello();
+}
+
+void AsyncSocksProxySocket::ProcessInput(char * data, size_t& len) {
+ assert(state_ < SS_TUNNEL);
+
+ ByteBuffer response(data, len);
+
+ if (state_ == SS_HELLO) {
+ uint8 ver, method;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(method))
+ return;
+
+ if (ver != 5) {
+ Error(0);
+ return;
+ }
+
+ if (method == 0) {
+ SendConnect();
+ } else if (method == 2) {
+ SendAuth();
+ } else {
+ Error(0);
+ return;
+ }
+ } else if (state_ == SS_AUTH) {
+ uint8 ver, status;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(status))
+ return;
+
+ if ((ver != 1) || (status != 0)) {
+ Error(EACCES);
+ return;
+ }
+
+ SendConnect();
+ } else if (state_ == SS_CONNECT) {
+ uint8 ver, rep, rsv, atyp;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(rep) ||
+ !response.ReadUInt8(rsv) ||
+ !response.ReadUInt8(atyp))
+ return;
+
+ if ((ver != 5) || (rep != 0)) {
+ Error(0);
+ return;
+ }
+
+ uint16 port;
+ if (atyp == 1) {
+ uint32 addr;
+ if (!response.ReadUInt32(addr) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
+ } else if (atyp == 3) {
+ uint8 len;
+ std::string addr;
+ if (!response.ReadUInt8(len) ||
+ !response.ReadString(addr, len) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
+ } else if (atyp == 4) {
+ std::string addr;
+ if (!response.ReadString(addr, 16) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
+ } else {
+ Error(0);
+ return;
+ }
+
+ state_ = SS_TUNNEL;
+ }
+
+ // Consume parsed data
+ len = response.Length();
+ memcpy(data, response.Data(), len);
+
+ if (state_ != SS_TUNNEL)
+ return;
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this); // TODO: signal this??
+}
+
+void AsyncSocksProxySocket::SendHello() {
+ ByteBuffer request;
+ request.WriteUInt8(5); // Socks Version
+ if (user_.empty()) {
+ request.WriteUInt8(1); // Authentication Mechanisms
+ request.WriteUInt8(0); // No authentication
+ } else {
+ request.WriteUInt8(2); // Authentication Mechanisms
+ request.WriteUInt8(0); // No authentication
+ request.WriteUInt8(2); // Username/Password
+ }
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_HELLO;
+}
+
+void AsyncSocksProxySocket::SendAuth() {
+ ByteBuffer request;
+ request.WriteUInt8(1); // Negotiation Version
+ request.WriteUInt8(static_cast<uint8>(user_.size()));
+ request.WriteString(user_); // Username
+ request.WriteUInt8(static_cast<uint8>(pass_.GetLength()));
+ size_t len = pass_.GetLength() + 1;
+ char * sensitive = new char[len];
+ pass_.CopyTo(sensitive, true);
+ request.WriteString(sensitive); // Password
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_AUTH;
+}
+
+void AsyncSocksProxySocket::SendConnect() {
+ ByteBuffer request;
+ request.WriteUInt8(5); // Socks Version
+ request.WriteUInt8(1); // CONNECT
+ request.WriteUInt8(0); // Reserved
+ if (dest_.IsUnresolved()) {
+ std::string hostname = dest_.IPAsString();
+ request.WriteUInt8(3); // DOMAINNAME
+ request.WriteUInt8(static_cast<uint8>(hostname.size()));
+ request.WriteString(hostname); // Destination Hostname
+ } else {
+ request.WriteUInt8(1); // IPV4
+ request.WriteUInt32(dest_.ip()); // Destination IP
+ }
+ request.WriteUInt16(dest_.port()); // Destination Port
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_CONNECT;
+}
+
+void AsyncSocksProxySocket::Error(int error) {
+ state_ = SS_ERROR;
+ BufferInput(false);
+ Close();
+ SetError(EACCES);
+ SignalCloseEvent(this, error);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+LoggingAdapter::LoggingAdapter(AsyncSocket* socket, LoggingSeverity level,
+ const char * label)
+ : AsyncSocketAdapter(socket), level_(level)
+{
+ label_.append("[");
+ label_.append(label);
+ label_.append("]");
+}
+
+int
+LoggingAdapter::Send(const void *pv, size_t cb) {
+ int res = AsyncSocketAdapter::Send(pv, cb);
+ if (res > 0)
+ LogMultiline(false, static_cast<const char *>(pv), res);
+ return res;
+}
+
+int
+LoggingAdapter::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ int res = AsyncSocketAdapter::SendTo(pv, cb, addr);
+ if (res > 0)
+ LogMultiline(false, static_cast<const char *>(pv), res);
+ return res;
+}
+
+int
+LoggingAdapter::Recv(void *pv, size_t cb) {
+ int res = AsyncSocketAdapter::Recv(pv, cb);
+ if (res > 0)
+ LogMultiline(true, static_cast<const char *>(pv), res);
+ return res;
+}
+
+int
+LoggingAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
+ if (res > 0)
+ LogMultiline(true, static_cast<const char *>(pv), res);
+ return res;
+}
+
+void
+LoggingAdapter::OnConnectEvent(AsyncSocket * socket) {
+ LOG(level_) << label_ << " Connected";
+ AsyncSocketAdapter::OnConnectEvent(socket);
+}
+
+void
+LoggingAdapter::OnCloseEvent(AsyncSocket * socket, int err) {
+ LOG(level_) << label_ << " Closed with error: " << err;
+ AsyncSocketAdapter::OnCloseEvent(socket, err);
+}
+
+void
+LoggingAdapter::LogMultiline(bool input, const char * data, size_t len) {
+ const char * direction = (input ? " << " : " >> ");
+ std::string str(data, len);
+ while (!str.empty()) {
+ std::string::size_type pos = str.find('\n');
+ std::string substr = str;
+ if (pos == std::string::npos) {
+ substr = str;
+ str.clear();
+ } else if ((pos > 0) && (str[pos-1] == '\r')) {
+ substr = str.substr(0, pos - 1);
+ str = str.substr(pos + 1);
+ } else {
+ substr = str.substr(0, pos);
+ str = str.substr(pos + 1);
+ }
+
+ // Filter out any private data
+ std::string::size_type pos_private = substr.find("Email");
+ if (pos_private == std::string::npos) {
+ pos_private = substr.find("Passwd");
+ }
+ if (pos_private == std::string::npos) {
+ LOG(level_) << label_ << direction << substr;
+ } else {
+ LOG(level_) << label_ << direction << "## TEXT REMOVED ##";
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h
new file mode 100644
index 00000000..1c65aa79
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h
@@ -0,0 +1,181 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKETADAPTERS_H__
+#define __SOCKETADAPTERS_H__
+
+#include <map>
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/logging.h"
+#include "talk/xmpp/xmpppassword.h" // TODO: move xmpppassword to base
+
+namespace cricket {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class BufferedReadAdapter : public AsyncSocketAdapter {
+public:
+ BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size);
+ virtual ~BufferedReadAdapter();
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int Recv(void *pv, size_t cb);
+
+protected:
+ int DirectSend(const void *pv, size_t cb) { return AsyncSocketAdapter::Send(pv, cb); }
+
+ void BufferInput(bool on = true);
+ virtual void ProcessInput(char * data, size_t& len) = 0;
+
+ virtual void OnReadEvent(AsyncSocket * socket);
+
+private:
+ char * buffer_;
+ size_t buffer_size_, data_len_;
+ bool buffering_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncSSLSocket : public BufferedReadAdapter {
+public:
+ AsyncSSLSocket(AsyncSocket* socket);
+
+ virtual int Connect(const SocketAddress& addr);
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void ProcessInput(char * data, size_t& len);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncHttpsProxySocket : public BufferedReadAdapter {
+public:
+ AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const buzz::XmppPassword& password);
+ virtual ~AsyncHttpsProxySocket();
+
+ virtual int Connect(const SocketAddress& addr);
+ virtual SocketAddress GetRemoteAddress() const;
+ virtual int Close();
+
+ struct AuthContext {
+ std::string auth_method;
+ AuthContext(const std::string& auth) : auth_method(auth) { }
+ virtual ~AuthContext() { }
+ };
+
+ // 'context' is used by this function to record information between calls.
+ // Start by passing a null pointer, then pass the same pointer each additional
+ // call. When the authentication attempt is finished, delete the context.
+ enum AuthResult { AR_RESPONSE, AR_IGNORE, AR_CREDENTIALS, AR_ERROR };
+ static AuthResult Authenticate(const char * challenge, size_t len,
+ const SocketAddress& server,
+ const std::string& method, const std::string& uri,
+ const std::string& username, const buzz::XmppPassword& password,
+ AuthContext *& context, std::string& response, std::string& auth_method);
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void OnCloseEvent(AsyncSocket * socket, int err);
+ virtual void ProcessInput(char * data, size_t& len);
+
+ void SendRequest();
+ void ProcessLine(char * data, size_t len);
+ void EndResponse();
+ void Error(int error);
+
+ static void ParseAuth(const char * data, size_t len, std::string& method, std::map<std::string,std::string>& args);
+
+private:
+ SocketAddress proxy_, dest_;
+ std::string user_, headers_;
+ buzz::XmppPassword pass_;
+ size_t content_length_;
+ int defer_error_;
+ bool expect_close_;
+ enum ProxyState { PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS, PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR } state_;
+ AuthContext * context_;
+ std::string unknown_mechanisms_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncSocksProxySocket : public BufferedReadAdapter {
+public:
+ AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const buzz::XmppPassword& password);
+
+ virtual int Connect(const SocketAddress& addr);
+ virtual SocketAddress GetRemoteAddress() const;
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void ProcessInput(char * data, size_t& len);
+
+ void SendHello();
+ void SendConnect();
+ void SendAuth();
+ void Error(int error);
+
+private:
+ SocketAddress proxy_, dest_;
+ std::string user_;
+ buzz::XmppPassword pass_;
+ enum SocksState { SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR } state_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class LoggingAdapter : public AsyncSocketAdapter {
+public:
+ LoggingAdapter(AsyncSocket* socket, LoggingSeverity level,
+ const char * label);
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+ virtual int Recv(void *pv, size_t cb);
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr);
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void OnCloseEvent(AsyncSocket * socket, int err);
+
+private:
+ void LogMultiline(bool input, const char * data, size_t len);
+
+ LoggingSeverity level_;
+ std::string label_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace cricket
+
+#endif // __SOCKETADAPTERS_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc
new file mode 100644
index 00000000..f0228fbd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc
@@ -0,0 +1,267 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/socketaddress.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/logging.h"
+#include <cstring>
+#include <sstream>
+#include <cassert>
+
+#ifdef WIN32
+#undef SetPort
+int inet_aton(const char * cp, struct in_addr * inp) {
+ inp->s_addr = inet_addr(cp);
+ return (inp->s_addr == INADDR_NONE) ? 0 : 1;
+}
+#endif // WIN32
+
+#ifdef POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#ifdef _DEBUG
+#define DISABLE_DNS 0
+#else // !_DEBUG
+#define DISABLE_DNS 0
+#endif // !_DEBUG
+
+namespace cricket {
+
+SocketAddress::SocketAddress() {
+ Zero();
+}
+
+SocketAddress::SocketAddress(const std::string& hostname, int port, bool use_dns) {
+ Zero();
+ SetIP(hostname, use_dns);
+ SetPort(port);
+}
+
+SocketAddress::SocketAddress(uint32 ip, int port) {
+ Zero();
+ SetIP(ip);
+ SetPort(port);
+}
+
+SocketAddress::SocketAddress(const SocketAddress& addr) {
+ Zero();
+ this->operator=(addr);
+}
+
+void SocketAddress::Zero() {
+ ip_ = 0;
+ port_ = 0;
+}
+
+SocketAddress& SocketAddress::operator =(const SocketAddress& addr) {
+ hostname_ = addr.hostname_;
+ ip_ = addr.ip_;
+ port_ = addr.port_;
+ return *this;
+}
+
+void SocketAddress::SetIP(uint32 ip) {
+ hostname_.clear();
+ ip_ = ip;
+}
+
+bool SocketAddress::SetIP(const std::string& hostname, bool use_dns) {
+ hostname_ = hostname;
+ ip_ = 0;
+ return Resolve(true, use_dns);
+}
+
+void SocketAddress::SetResolvedIP(uint32 ip) {
+ ip_ = ip;
+}
+
+void SocketAddress::SetPort(int port) {
+ assert((0 <= port) && (port < 65536));
+ port_ = port;
+}
+
+uint32 SocketAddress::ip() const {
+ return ip_;
+}
+
+uint16 SocketAddress::port() const {
+ return port_;
+}
+
+std::string SocketAddress::IPAsString() const {
+ if (!hostname_.empty())
+ return hostname_;
+ return IPToString(ip_);
+}
+
+std::string SocketAddress::PortAsString() const {
+ std::ostringstream ost;
+ ost << port_;
+ return ost.str();
+}
+
+std::string SocketAddress::ToString() const {
+ std::ostringstream ost;
+ ost << IPAsString();
+ ost << ":";
+ ost << port();
+ return ost.str();
+}
+
+bool SocketAddress::IsAny() const {
+ return (ip_ == 0);
+}
+
+bool SocketAddress::IsLocalIP() const {
+ return (ip_ >> 24) == 127;
+}
+
+bool SocketAddress::IsPrivateIP() const {
+ return ((ip_ >> 24) == 127) ||
+ ((ip_ >> 24) == 10) ||
+ ((ip_ >> 20) == ((172 << 4) | 1)) ||
+ ((ip_ >> 16) == ((192 << 8) | 168));
+}
+
+bool SocketAddress::IsUnresolved() const {
+ return IsAny() && !hostname_.empty();
+}
+
+bool SocketAddress::Resolve(bool force, bool use_dns) {
+ if (hostname_.empty()) {
+ // nothing to resolve
+ } else if (!force && !IsAny()) {
+ // already resolved
+ } else if (uint32 ip = StringToIP(hostname_, use_dns)) {
+ ip_ = ip;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool SocketAddress::operator ==(const SocketAddress& addr) const {
+ return EqualIPs(addr) && EqualPorts(addr);
+}
+
+bool SocketAddress::operator <(const SocketAddress& addr) const {
+ if (ip_ < addr.ip_)
+ return true;
+ else if (addr.ip_ < ip_)
+ return false;
+
+ // We only check hostnames if both IPs are zero. This matches EqualIPs()
+ if (addr.ip_ == 0) {
+ if (hostname_ < addr.hostname_)
+ return true;
+ else if (addr.hostname_ < hostname_)
+ return false;
+ }
+
+ return port_ < addr.port_;
+}
+
+bool SocketAddress::EqualIPs(const SocketAddress& addr) const {
+ return (ip_ == addr.ip_) && ((ip_ != 0) || (hostname_ == addr.hostname_));
+}
+
+bool SocketAddress::EqualPorts(const SocketAddress& addr) const {
+ return (port_ == addr.port_);
+}
+
+size_t SocketAddress::Hash() const {
+ size_t h = 0;
+ h ^= ip_;
+ h ^= port_ | (port_ << 16);
+ return h;
+}
+
+size_t SocketAddress::Size_() const {
+ return sizeof(ip_) + sizeof(port_);
+}
+
+void SocketAddress::Write_(char* buf, int len) const {
+ // TODO: Depending on how this is used, we may want/need to write hostname
+ assert((size_t)len >= Size_());
+ reinterpret_cast<uint32*>(buf)[0] = ip_;
+ buf += sizeof(ip_);
+ reinterpret_cast<uint16*>(buf)[0] = port_;
+}
+
+void SocketAddress::Read_(const char* buf, int len) {
+ assert((size_t)len >= Size_());
+ ip_ = reinterpret_cast<const uint32*>(buf)[0];
+ buf += sizeof(ip_);
+ port_ = reinterpret_cast<const uint16*>(buf)[0];
+}
+
+std::string SocketAddress::IPToString(uint32 ip) {
+ std::ostringstream ost;
+ ost << ((ip >> 24) & 0xff);
+ ost << '.';
+ ost << ((ip >> 16) & 0xff);
+ ost << '.';
+ ost << ((ip >> 8) & 0xff);
+ ost << '.';
+ ost << ((ip >> 0) & 0xff);
+ return ost.str();
+}
+
+uint32 SocketAddress::StringToIP(const std::string& hostname, bool use_dns) {
+ uint32 ip = 0;
+ in_addr addr;
+ if (inet_aton(hostname.c_str(), &addr) != 0) {
+ ip = NetworkToHost32(addr.s_addr);
+ } else if (use_dns) {
+ // Note: this is here so we can spot spurious DNS resolutions for a while
+ LOG(INFO) << "=== DNS RESOLUTION (" << hostname << ") ===";
+#if DISABLE_DNS
+ LOG(WARNING) << "*** DNS DISABLED ***";
+#if WIN32
+ WSASetLastError(WSAHOST_NOT_FOUND);
+#endif // WIN32
+#endif // DISABLE_DNS
+ if (hostent * pHost = gethostbyname(hostname.c_str())) {
+ ip = NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[0]));
+ } else {
+#if WIN32
+ LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError();
+#else
+ LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno);
+#endif
+ }
+ LOG(INFO) << hostname << " resolved to " << IPToString(ip);
+ }
+ return ip;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h
new file mode 100644
index 00000000..b8a165d3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h
@@ -0,0 +1,154 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKETADDRESS_H__
+#define __SOCKETADDRESS_H__
+
+#include "talk/base/basictypes.h"
+#include <string>
+#undef SetPort
+
+namespace cricket {
+
+// Records an IP address and port, which are 32 and 16 bit integers,
+// respectively, both in <b>host byte-order</b>.
+class SocketAddress {
+public:
+ // Creates a missing / unknown address.
+ SocketAddress();
+
+ // Creates the address with the given host and port. If use_dns is true,
+ // the hostname will be immediately resolved to an IP (which may block for
+ // several seconds if DNS is not available). Alternately, set use_dns to
+ // false, and then call Resolve() to complete resolution later, or use
+ // SetResolvedIP to set the IP explictly.
+ SocketAddress(const std::string& hostname, int port = 0, bool use_dns = true);
+
+ // Creates the address with the given IP and port.
+ SocketAddress(uint32 ip, int port);
+
+ // Creates a copy of the given address.
+ SocketAddress(const SocketAddress& addr);
+
+ // Replaces our address with the given one.
+ SocketAddress& operator =(const SocketAddress& addr);
+
+ // Changes the IP of this address to the given one, and clears the hostname.
+ void SetIP(uint32 ip);
+
+ // Changes the hostname of this address to the given one.
+ // Calls Resolve and returns the result.
+ bool SetIP(const std::string& hostname, bool use_dns = true);
+
+ // Sets the IP address while retaining the hostname. Useful for bypassing
+ // DNS for a pre-resolved IP.
+ void SetResolvedIP(uint32 ip);
+
+ // Changes the port of this address to the given one.
+ void SetPort(int port);
+
+ // Returns the IP address.
+ uint32 ip() const;
+
+ // Returns the port part of this address.
+ uint16 port() const;
+
+ // Returns the IP address in dotted form.
+ std::string IPAsString() const;
+
+ // Returns the port as a string
+ std::string PortAsString() const;
+
+ // Returns a display version of the IP/port.
+ std::string ToString() const;
+
+ // Determines whether this represents a missing / any address.
+ bool IsAny() const;
+
+ // Synomym for missing / any.
+ bool IsNil() const { return IsAny(); }
+
+ // Determines whether the IP address refers to the local host, i.e. within
+ // the range 127.0.0.0/8.
+ bool IsLocalIP() const;
+
+ // Determines whether the IP address is in one of the private ranges:
+ // 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12.
+ bool IsPrivateIP() const;
+
+ // Determines whether the hostname has been resolved to an IP
+ bool IsUnresolved() const;
+
+ // Attempt to resolve a hostname to IP address.
+ // Returns false if resolution is required but failed.
+ // 'force' will cause re-resolution of hostname.
+ //
+ bool Resolve(bool force = false, bool use_dns = true);
+
+ // Determines whether this address is identical to the given one.
+ bool operator ==(const SocketAddress& addr) const;
+
+ // Compares based on IP and then port.
+ bool operator <(const SocketAddress& addr) const;
+
+ // Determines whether this address has the same IP as the one given.
+ bool EqualIPs(const SocketAddress& addr) const;
+
+ // Deteremines whether this address has the same port as the one given.
+ bool EqualPorts(const SocketAddress& addr) const;
+
+ // Hashes this address into a small number.
+ size_t Hash() const;
+
+ // Returns the size of this address when written.
+ size_t Size_() const;
+
+ // Writes this address into the given buffer.
+ void Write_(char* buf, int len) const;
+
+ // Reads this address from the given buffer.
+ void Read_(const char* buf, int len);
+
+ // Converts the IP address given in compact form into dotted form.
+ static std::string IPToString(uint32 ip);
+
+ // Converts the IP address given in dotted form into compact form.
+ // Without 'use_dns', only dotted names (A.B.C.D) are resolved.
+ static uint32 StringToIP(const std::string& str, bool use_dns = true);
+
+private:
+ std::string hostname_;
+ uint32 ip_;
+ uint16 port_;
+
+ // Initializes the address to missing / any.
+ void Zero();
+};
+
+} // namespace cricket
+
+#endif // __SOCKETADDRESS_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc
new file mode 100644
index 00000000..2166be09
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc
@@ -0,0 +1,58 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/socketaddresspair.h"
+
+namespace cricket {
+
+SocketAddressPair::SocketAddressPair(
+ const SocketAddress& src, const SocketAddress& dest)
+ : src_(src), dest_(dest) {
+}
+
+
+bool SocketAddressPair::operator ==(const SocketAddressPair& p) const {
+ return (src_ == p.src_) && (dest_ == p.dest_);
+}
+
+bool SocketAddressPair::operator <(const SocketAddressPair& p) const {
+ if (src_ < p.src_)
+ return true;
+ if (p.src_ < src_)
+ return false;
+ if (dest_ < p.dest_)
+ return true;
+ if (p.dest_ < dest_)
+ return false;
+ return false;
+}
+
+size_t SocketAddressPair::Hash() const {
+ return src_.Hash() ^ dest_.Hash();
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h
new file mode 100644
index 00000000..098bafdb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h
@@ -0,0 +1,58 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKETADDRESSPAIR_H__
+#define __SOCKETADDRESSPAIR_H__
+
+#include "talk/base/socketaddress.h"
+
+namespace cricket {
+
+// Records a pair (source,destination) of socket addresses. The two addresses
+// identify a connection between two machines. (For UDP, this "connection" is
+// not maintained explicitly in a socket.)
+class SocketAddressPair {
+public:
+ SocketAddressPair() {}
+ SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest);
+
+ const SocketAddress& source() const { return src_; }
+ const SocketAddress& destination() const { return dest_; }
+
+ bool operator ==(const SocketAddressPair& r) const;
+ bool operator <(const SocketAddressPair& r) const;
+
+ size_t Hash() const;
+
+private:
+ SocketAddress src_;
+ SocketAddress dest_;
+};
+
+} // namespace cricket
+
+#endif // __SOCKETADDRESSPAIR_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h
new file mode 100644
index 00000000..67386160
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h
@@ -0,0 +1,50 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKETFACTORY_H__
+#define __SOCKETFACTORY_H__
+
+#include "talk/base/socket.h"
+#include "talk/base/asyncsocket.h"
+
+namespace cricket {
+
+class SocketFactory {
+public:
+
+ // Returns a new socket for blocking communication. The type can be
+ // SOCK_DGRAM and SOCK_STREAM.
+ virtual Socket* CreateSocket(int type) = 0;
+
+ // Returns a new socket for nonblocking communication. The type can be
+ // SOCK_DGRAM and SOCK_STREAM.
+ virtual AsyncSocket* CreateAsyncSocket(int type) = 0;
+};
+
+} // namespace cricket
+
+#endif // __SOCKETFACTORY_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h
new file mode 100644
index 00000000..d0e7a22a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h
@@ -0,0 +1,53 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKETSERVER_H__
+#define __SOCKETSERVER_H__
+
+#include "talk/base/socketfactory.h"
+
+namespace cricket {
+
+// Provides the ability to wait for activity on a set of sockets. The Thread
+// class provides a nice wrapper on a socket server.
+//
+// The server is also a socket factory. The sockets it creates will be
+// notified of asynchronous I/O from this server's Wait method.
+class SocketServer : public SocketFactory {
+public:
+
+ // Performs I/O or sleeps for the given number of milliseconds.
+ // If process_io is false, just sleeps until WakeUp.
+ virtual bool Wait(int cms, bool process_io) = 0;
+
+ // Causes the current wait (if one is in progress) to wake up.
+ virtual void WakeUp() = 0;
+};
+
+} // namespace cricket
+
+#endif // __SOCKETSERVER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h
new file mode 100644
index 00000000..9c2506f1
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h
@@ -0,0 +1,85 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _STL_DECL_H
+#define _STL_DECL_H
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
+#pragma warning(disable:4786)
+#endif
+
+#include <sys/types.h>
+
+namespace std {
+ template <class Key> struct hash;
+ template <class Key> struct equal_to;
+ template <class Key> struct less;
+ template <class T> class allocator;
+ template <class Key, class Val,
+ class Compare,
+ class Alloc> class map;
+ template <class T, class Alloc> class vector;
+ template <class T, class Alloc> class list;
+ template <class T, class Alloc> class slist;
+ template <class T, class Alloc, size_t BufSiz> class deque;
+ template <class T, class Sequence> class stack;
+ template <class T, class Sequence> class queue;
+ template <class T, class Sequence, class Compare> class priority_queue;
+ template <class T1, class T2> struct pair;
+ template <class Key, class Compare, class Alloc> class set;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Workaround declaration problem with defaults
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
+
+#define STD_MAP(T1, T2) \
+ std::map<T1 , T2, std::less<T1>, std::allocator<T2> >
+
+#define STD_VECTOR(T1) \
+ std::vector<T1, std::allocator<T1> >
+
+#define STD_SET(T1) \
+ std::set<T1, std::less<T1>, std::allocator<T1> >
+
+#else
+
+#define STD_MAP(T1, T2) \
+ std::map<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2 > > >
+
+#define STD_VECTOR(T1) \
+ std::vector<T1, std::allocator<T1> >
+
+#define STD_SET(T1) \
+ std::set<T1, std::less<T1>, std::allocator<T1> >
+
+#endif
+
+
+#endif // _STL_DECL_H
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h
new file mode 100644
index 00000000..a23132dd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h
@@ -0,0 +1,266 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STRINGUTILS_H__
+#define __STRINGUTILS_H__
+
+#include <cctype>
+#include <cstdarg>
+#include <cstdio>
+#ifdef WIN32
+#include <wchar.h>
+#endif // WIN32
+
+#include <string>
+
+///////////////////////////////////////////////////////////////////////////////
+// Rename a bunch of common string functions so they are consistent across
+// platforms and between char and wchar_t variants.
+// Here is the full list of functions that are unified:
+// strlen, strcmp, stricmp, strncmp, strnicmp
+// strchr, vsnprintf, strtoul, tolowercase
+// tolowercase is like tolower, but not compatible with end-of-file value
+// Note that the wchar_t versions are not available on Linux
+///////////////////////////////////////////////////////////////////////////////
+
+inline char tolowercase(char c) {
+ return static_cast<char>(tolower(c));
+}
+
+#ifdef WIN32
+
+inline size_t strlen(const wchar_t* s) {
+ return wcslen(s);
+}
+inline int strcmp(const wchar_t* s1, const wchar_t* s2) {
+ return wcscmp(s1, s2);
+}
+inline int stricmp(const wchar_t* s1, const wchar_t* s2) {
+ return wcsicmp(s1, s2);
+}
+inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
+ return wcsncmp(s1, s2, n);
+}
+inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
+ return wcsnicmp(s1, s2, n);
+}
+inline const wchar_t* strchr(const wchar_t* s, wchar_t c) {
+ return wcschr(s, c);
+}
+inline int vsnprintf(char* buf, size_t n, const char* fmt, va_list args) {
+ return _vsnprintf(buf, n, fmt, args);
+}
+inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) {
+ return _vsnwprintf(buf, n, fmt, args);
+}
+inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) {
+ return wcstoul(snum, end, base);
+}
+inline wchar_t tolowercase(wchar_t c) {
+ return static_cast<wchar_t>(towlower(c));
+}
+
+#endif // WIN32
+
+#ifdef POSIX
+
+inline int stricmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline int strnicmp(const char* s1, const char* s2, size_t n) {
+ return strncasecmp(s1, s2, n);
+}
+
+#endif // POSIX
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits simplifies porting string functions to be CTYPE-agnostic
+///////////////////////////////////////////////////////////////////////////////
+
+namespace cricket {
+
+const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
+
+template<class CTYPE>
+struct Traits {
+ // STL string type
+ //typedef XXX string;
+ // Null-terminated string
+ //inline static const CTYPE* empty_str();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// String utilities which work with char or wchar_t
+///////////////////////////////////////////////////////////////////////////////
+
+template<class CTYPE>
+inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) {
+ return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
+}
+
+template<class CTYPE>
+const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
+ for (size_t i=0; str[i]; ++i) {
+ for (size_t j=0; chs[j]; ++j) {
+ if (str[i] == chs[j]) {
+ return str + i;
+ }
+ }
+ }
+ return 0;
+}
+
+template<class CTYPE>
+const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
+ for (size_t i=0; i<slen && str[i]; ++i) {
+ if (str[i] == ch) {
+ return str + i;
+ }
+ }
+ return 0;
+}
+
+template<class CTYPE>
+size_t strlenn(const CTYPE* buffer, size_t buflen) {
+ size_t bufpos = 0;
+ while (buffer[bufpos] && (bufpos < buflen)) {
+ ++bufpos;
+ }
+ return bufpos;
+}
+
+template<class CTYPE>
+size_t strcpyn(CTYPE* buffer, size_t buflen,
+ const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
+ if (buflen <= 0)
+ return 0;
+
+ if (srclen == SIZE_UNKNOWN) {
+ srclen = strlenn(source, buflen - 1);
+ } else if (srclen >= buflen) {
+ srclen = buflen - 1;
+ }
+ memcpy(buffer, source, srclen * sizeof(CTYPE));
+ buffer[srclen] = 0;
+ return srclen;
+}
+
+// Safe versions of snprintf and vsnprintf that always null-terminate
+
+template<class CTYPE>
+size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
+ va_list args;
+ va_start(args, format);
+ size_t len = vsprintfn(buffer, buflen, format, args);
+ va_end(args);
+ return len;
+}
+
+template<class CTYPE>
+size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format,
+ va_list args) {
+ int len = vsnprintf(buffer, buflen, format, args);
+ if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
+ len = static_cast<int>(buflen - 1);
+ buffer[len] = 0;
+ }
+ return len;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Allow safe comparing and copying ascii (not UTF-8) with both wide and
+// non-wide character strings.
+///////////////////////////////////////////////////////////////////////////////
+
+inline int asccmp(const char* s1, const char* s2) {
+ return strcmp(s1, s2);
+}
+inline int ascicmp(const char* s1, const char* s2) {
+ return stricmp(s1, s2);
+}
+inline int ascncmp(const char* s1, const char* s2, size_t n) {
+ return strncmp(s1, s2, n);
+}
+inline int ascnicmp(const char* s1, const char* s2, size_t n) {
+ return strnicmp(s1, s2, n);
+}
+inline size_t asccpyn(char* buffer, size_t buflen,
+ const char* source, size_t srclen = SIZE_UNKNOWN) {
+ return strcpyn(buffer, buflen, source, srclen);
+}
+
+#ifdef WIN32
+
+typedef wchar_t(*CharacterTransformation)(wchar_t);
+inline wchar_t identity(wchar_t c) { return c; }
+int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
+ CharacterTransformation transformation);
+
+inline int asccmp(const wchar_t* s1, const char* s2) {
+ return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity);
+}
+inline int ascicmp(const wchar_t* s1, const char* s2) {
+ return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase);
+}
+inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) {
+ return ascii_string_compare(s1, s2, n, identity);
+}
+inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
+ return ascii_string_compare(s1, s2, n, tolowercase);
+}
+size_t asccpyn(wchar_t* buffer, size_t buflen,
+ const char* source, size_t srclen = SIZE_UNKNOWN);
+
+#endif // WIN32
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits<char> specializations
+///////////////////////////////////////////////////////////////////////////////
+
+template<>
+struct Traits<char> {
+ typedef std::string string;
+ inline static const char* empty_str() { return ""; }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits<wchar_t> specializations (Windows only, currently)
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef WIN32
+
+template<>
+struct Traits<wchar_t> {
+ typedef std::wstring string;
+ inline static const wchar_t* Traits<wchar_t>::empty_str() { return L""; }
+};
+
+#endif // WIN32
+
+} // namespace cricket
+
+#endif // __STRINGUTILS_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc
new file mode 100644
index 00000000..a5a94941
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc
@@ -0,0 +1,238 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "task.h"
+#include "taskrunner.h"
+
+#include <algorithm>
+
+namespace buzz {
+
+Task::Task(Task * parent) :
+ state_(STATE_INIT),
+ parent_(parent),
+ blocked_(false),
+ done_(false),
+ aborted_(false),
+ busy_(false),
+ error_(false),
+ child_error_(false),
+ start_time_(0) {
+ runner_ = ((parent == NULL) ? (TaskRunner *)this : parent->GetRunner());
+ if (parent_ != NULL) {
+ parent_->AddChild(this);
+ }
+}
+
+unsigned long long
+Task::CurrentTime() {
+ return runner_->CurrentTime();
+}
+
+unsigned long long
+Task::ElapsedTime() {
+ return CurrentTime() - start_time_;
+}
+
+void
+Task::Start() {
+ if (state_ != STATE_INIT)
+ return;
+ GetRunner()->StartTask(this);
+ start_time_ = CurrentTime();
+}
+
+void
+Task::Step() {
+ if (done_) {
+#ifdef DEBUG
+ // we do not know how !blocked_ happens when done_ - should be impossible.
+ // But it causes problems, so in retail build, we force blocked_, and
+ // under debug we assert.
+ assert(blocked_);
+#else
+ blocked_ = true;
+#endif
+ return;
+ }
+
+ // Async Error() was called
+ if (error_) {
+ done_ = true;
+ state_ = STATE_ERROR;
+ blocked_ = true;
+// obsolete - an errored task is not considered done now
+// SignalDone();
+ Stop();
+ return;
+ }
+
+ busy_ = true;
+ int new_state = Process(state_);
+ busy_ = false;
+
+ if (aborted_) {
+ Abort(true); // no need to wake because we're awake
+ return;
+ }
+
+ if (new_state == STATE_BLOCKED) {
+ blocked_ = true;
+ }
+ else {
+ state_ = new_state;
+ blocked_ = false;
+ }
+
+ if (new_state == STATE_DONE) {
+ done_ = true;
+ }
+ else if (new_state == STATE_ERROR) {
+ done_ = true;
+ error_ = true;
+ }
+
+ if (done_) {
+// obsolete - call this yourself
+// SignalDone();
+ Stop();
+ blocked_ = true;
+ }
+}
+
+void
+Task::Abort(bool nowake) {
+ if (aborted_ || done_)
+ return;
+ aborted_ = true;
+ if (!busy_) {
+ done_ = true;
+ blocked_ = true;
+ error_ = true;
+ Stop();
+ if (!nowake)
+ Wake(); // to self-delete
+ }
+}
+
+void
+Task::Wake() {
+ if (done_)
+ return;
+ if (blocked_) {
+ blocked_ = false;
+ GetRunner()->WakeTasks();
+ }
+}
+
+void
+Task::Error() {
+ if (error_ || done_)
+ return;
+ error_ = true;
+ Wake();
+}
+
+std::string
+Task::GetStateName(int state) const {
+ static const std::string STR_BLOCKED("BLOCKED");
+ static const std::string STR_INIT("INIT");
+ static const std::string STR_START("START");
+ static const std::string STR_DONE("DONE");
+ static const std::string STR_ERROR("ERROR");
+ static const std::string STR_RESPONSE("RESPONSE");
+ static const std::string STR_HUH("??");
+ switch (state) {
+ case STATE_BLOCKED: return STR_BLOCKED;
+ case STATE_INIT: return STR_INIT;
+ case STATE_START: return STR_START;
+ case STATE_DONE: return STR_DONE;
+ case STATE_ERROR: return STR_ERROR;
+ case STATE_RESPONSE: return STR_RESPONSE;
+ }
+ return STR_HUH;
+}
+
+int Task::Process(int state) {
+ switch (state) {
+ case STATE_INIT:
+ return STATE_START;
+ case STATE_START:
+ return ProcessStart();
+ case STATE_RESPONSE:
+ return ProcessResponse();
+ case STATE_DONE:
+ case STATE_ERROR:
+ return STATE_BLOCKED;
+ }
+ return STATE_ERROR;
+}
+
+void
+Task::AddChild(Task * child) {
+ children_.insert(child);
+}
+
+bool
+Task::AllChildrenDone() {
+ for (ChildSet::iterator it = children_.begin(); it != children_.end(); ++it) {
+ if (!(*it)->IsDone())
+ return false;
+ }
+ return true;
+}
+
+bool
+Task::AnyChildError() {
+ return child_error_;
+}
+
+void
+Task::AbortAllChildren() {
+ if (children_.size() > 0) {
+ ChildSet copy = children_;
+ for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) {
+ (*it)->Abort(true); // Note we do not wake
+ }
+ }
+}
+
+void
+Task::Stop() {
+ AbortAllChildren(); // No need to wake because we're either awake or in abort
+ parent_->OnChildStopped(this);
+}
+
+void
+Task::OnChildStopped(Task * child) {
+ if (child->HasError())
+ child_error_ = true;
+ children_.erase(child);
+}
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.h
new file mode 100644
index 00000000..5a486198
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.h
@@ -0,0 +1,186 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TASK_H_
+#define _TASK_H_
+
+#include <vector>
+#include <string>
+
+#include "talk/base/sigslot.h"
+
+/////////////////////////////////////////////////////////////////////
+//
+// TASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// Task is a state machine infrastructure. States are pushed forward by
+// pushing forwards a TaskRunner that holds on to all Tasks. The purpose
+// of Task is threefold:
+//
+// (1) It manages ongoing work on the UI thread. Multitasking without
+// threads, keeping it easy, keeping it real. :-) It does this by
+// organizing a set of states for each task. When you return from your
+// Process*() function, you return an integer for the next state. You do
+// not go onto the next state yourself. Every time you enter a state,
+// you check to see if you can do anything yet. If not, you return
+// STATE_BLOCKED. If you _could_ do anything, do not return
+// STATE_BLOCKED - even if you end up in the same state, return
+// STATE_mysamestate. When you are done, return STATE_DONE and then the
+// task will self-delete sometimea afterwards.
+//
+// (2) It helps you avoid all those reentrancy problems when you chain
+// too many triggers on one thread. Basically if you want to tell a task
+// to process something for you, you feed your task some information and
+// then you Wake() it. Don't tell it to process it right away. If it
+// might be working on something as you send it infomration, you may want
+// to have a queue in the task.
+//
+// (3) Finally it helps manage parent tasks and children. If a parent
+// task gets aborted, all the children tasks are too. The nice thing
+// about this, for example, is if you have one parent task that
+// represents, say, and Xmpp connection, then you can spawn a whole bunch
+// of infinite lifetime child tasks and now worry about cleaning them up.
+// When the parent task goes to STATE_DONE, the task engine will make
+// sure all those children are aborted and get deleted.
+//
+// Notice that Task has a few built-in states, e.g.,
+//
+// STATE_INIT - the task isn't running yet
+// STATE_START - the task is in its first state
+// STATE_RESPONSE - the task is in its second state
+// STATE_DONE - the task is done
+//
+// STATE_ERROR - indicates an error - we should audit the error code in
+// light of any usage of it to see if it should be improved. When I
+// first put down the task stuff I didn't have a good sense of what was
+// needed for Abort and Error, and now the subclasses of Task will ground
+// the design in a stronger way.
+//
+// STATE_NEXT - the first undefined state number. (like WM_USER) - you
+// can start defining more task states there.
+//
+// When you define more task states, just override Process(int state) and
+// add your own switch statement. If you want to delegate to
+// Task::Process, you can effectively delegate to its switch statement.
+// No fancy method pointers or such - this is all just pretty low tech,
+// easy to debug, and fast.
+//
+
+namespace buzz {
+
+class TaskRunner;
+
+// A task executes a sequence of steps
+
+class Task;
+class RootTask;
+
+class Task {
+public:
+ Task(Task * parent);
+ virtual ~Task() {}
+
+ void Start();
+ void Step();
+ int GetState() const { return state_; }
+ bool HasError() const { return (GetState() == STATE_ERROR); }
+ bool Blocked() const { return blocked_; }
+ bool IsDone() const { return done_; }
+ unsigned long long ElapsedTime();
+ virtual void Poll() {}
+
+ Task * GetParent() { return parent_; }
+ TaskRunner * GetRunner() { return runner_; }
+ virtual Task * GetParent(int code) { return parent_->GetParent(code); }
+
+ // Called from outside to stop task without any more callbacks
+ void Abort(bool nowake = false);
+
+ // For managing children
+ bool AllChildrenDone();
+ bool AnyChildError();
+
+
+protected:
+
+ enum {
+ STATE_BLOCKED = -1,
+ STATE_INIT = 0,
+ STATE_START = 1,
+ STATE_DONE = 2,
+ STATE_ERROR = 3,
+ STATE_RESPONSE = 4,
+ STATE_NEXT = 5, // Subclasses which need more states start here and higher
+ };
+
+ // Called inside the task to signal that the task may be unblocked
+ void Wake();
+
+ // Called inside to advise that the task should wake and signal an error
+ void Error();
+
+ unsigned long long CurrentTime();
+
+ virtual std::string GetStateName(int state) const;
+ virtual int Process(int state);
+ virtual void Stop();
+ virtual int ProcessStart() = 0;
+ virtual int ProcessResponse() { return STATE_DONE; }
+
+ // for managing children (if any)
+ void AddChild(Task * child);
+ void AbortAllChildren();
+
+private:
+ void Done();
+ void OnChildStopped(Task * child);
+
+ int state_;
+ Task * parent_;
+ TaskRunner * runner_;
+ bool blocked_;
+ bool done_;
+ bool aborted_;
+ bool busy_;
+ bool error_;
+ bool child_error_;
+ unsigned long long start_time_;
+
+ // for managing children
+ typedef std::set<Task *> ChildSet;
+ ChildSet children_;
+
+};
+
+
+
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc
new file mode 100644
index 00000000..b5ecc55e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc
@@ -0,0 +1,92 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "taskrunner.h"
+#include "task.h"
+#include <algorithm>
+
+
+namespace buzz {
+
+TaskRunner::~TaskRunner() {
+ // this kills and deletes children silently!
+ AbortAllChildren();
+ RunTasks();
+}
+
+void
+TaskRunner::StartTask(Task * task) {
+ tasks_.push_back(task);
+ WakeTasks();
+}
+
+void
+TaskRunner::RunTasks() {
+ // Running continues until all tasks are Blocked (ok for a small # of tasks)
+ if (tasks_running_) {
+ return; // don't reenter
+ }
+
+ tasks_running_ = true;
+
+ int did_run = true;
+ while (did_run) {
+ did_run = false;
+ // use indexing instead of iterators because tasks_ may grow
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ while (!tasks_[i]->Blocked()) {
+ tasks_[i]->Step();
+ did_run = true;
+ }
+ }
+ }
+ // Tasks are deleted when running has paused
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ if (tasks_[i]->IsDone()) {
+ Task* task = tasks_[i];
+ delete task;
+ tasks_[i] = NULL;
+ }
+ }
+ // Finally, remove nulls
+ tasks_.erase(std::remove(tasks_.begin(), tasks_.end(), (Task *)NULL), tasks_.end());
+
+ tasks_running_ = false;
+}
+
+void
+TaskRunner::PollTasks() {
+ // every task gets hit once with a poll - they wake if needed
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ if (!tasks_[i]->IsDone()) {
+ tasks_[i]->Poll();
+ }
+ }
+}
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h
new file mode 100644
index 00000000..eab16eb9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h
@@ -0,0 +1,64 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TASKRUNNER_H_
+#define _TASKRUNNER_H_
+
+#include <vector>
+
+#include "talk/base/sigslot.h"
+#include "talk/base/task.h"
+
+
+namespace buzz {
+
+
+class Task;
+
+class TaskRunner : public Task, public sigslot::has_slots<> {
+public:
+ TaskRunner() : Task(NULL), tasks_running_(false) {}
+ virtual ~TaskRunner();
+
+ virtual void WakeTasks() = 0;
+ virtual unsigned long long CurrentTime() = 0 ;
+
+ void StartTask(Task * task);
+ void RunTasks();
+ void PollTasks();
+
+ // dummy state machine - never run.
+ virtual int ProcessStart() { return STATE_DONE; }
+
+private:
+ std::vector<Task *> tasks_;
+ bool tasks_running_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc
new file mode 100644
index 00000000..8f18a992
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc
@@ -0,0 +1,273 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef POSIX
+extern "C" {
+#include <sys/time.h>
+}
+#endif
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/thread.h"
+#include "talk/base/jtime.h"
+
+namespace cricket {
+
+ThreadManager g_thmgr;
+
+#ifdef POSIX
+pthread_key_t ThreadManager::key_;
+
+ThreadManager::ThreadManager() {
+ pthread_key_create(&key_, NULL);
+ main_thread_ = new Thread();
+ SetCurrent(main_thread_);
+}
+
+ThreadManager::~ThreadManager() {
+ pthread_key_delete(key_);
+ delete main_thread_;
+}
+
+Thread *ThreadManager::CurrentThread() {
+ return (Thread *)pthread_getspecific(key_);
+}
+
+void ThreadManager::SetCurrent(Thread *thread) {
+ pthread_setspecific(key_, thread);
+}
+#endif
+
+#ifdef WIN32
+DWORD ThreadManager::key_;
+
+ThreadManager::ThreadManager() {
+ key_ = TlsAlloc();
+ main_thread_ = new Thread();
+ SetCurrent(main_thread_);
+}
+
+ThreadManager::~ThreadManager() {
+ TlsFree(key_);
+ delete main_thread_;
+}
+
+Thread *ThreadManager::CurrentThread() {
+ return (Thread *)TlsGetValue(key_);
+}
+
+void ThreadManager::SetCurrent(Thread *thread) {
+ TlsSetValue(key_, thread);
+}
+#endif
+
+void ThreadManager::Add(Thread *thread) {
+ CritScope cs(&crit_);
+ threads_.push_back(thread);
+}
+
+void ThreadManager::Remove(Thread *thread) {
+ CritScope cs(&crit_);
+ threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end());
+}
+
+Thread::Thread(SocketServer* ss) : MessageQueue(ss) {
+ g_thmgr.Add(this);
+ started_ = false;
+ has_sends_ = false;
+}
+
+Thread::~Thread() {
+ Stop();
+ Clear(NULL);
+ g_thmgr.Remove(this);
+}
+
+#ifdef POSIX
+void Thread::Start() {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_create(&thread_, &attr, PreLoop, this);
+ started_ = true;
+}
+
+void Thread::Join() {
+ if (started_) {
+ void *pv;
+ pthread_join(thread_, &pv);
+ }
+}
+#endif
+
+#ifdef WIN32
+void Thread::Start() {
+ thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreLoop, this, 0, NULL);
+ started_ = true;
+}
+
+void Thread::Join() {
+ if (started_) {
+ WaitForSingleObject(thread_, INFINITE);
+ CloseHandle(thread_);
+ started_ = false;
+ }
+}
+#endif
+
+void *Thread::PreLoop(void *pv) {
+ Thread *thread = (Thread *)pv;
+ ThreadManager::SetCurrent(thread);
+ thread->Loop();
+ return NULL;
+}
+
+void Thread::Loop(int cmsLoop) {
+ uint32 msEnd;
+ if (cmsLoop != -1)
+ msEnd = GetMillisecondCount() + cmsLoop;
+ int cmsNext = cmsLoop;
+
+ while (true) {
+ Message msg;
+ if (!Get(&msg, cmsNext))
+ return;
+ Dispatch(&msg);
+
+ if (cmsLoop != -1) {
+ uint32 msCur = GetMillisecondCount();
+ if (msCur >= msEnd)
+ return;
+ cmsNext = msEnd - msCur;
+ }
+ }
+}
+
+void Thread::Stop() {
+ MessageQueue::Stop();
+ Join();
+}
+
+void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) {
+ // Sent messages are sent to the MessageHandler directly, in the context
+ // of "thread", like Win32 SendMessage. If in the right context,
+ // call the handler directly.
+
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ if (IsCurrent()) {
+ phandler->OnMessage(&msg);
+ return;
+ }
+
+ AutoThread thread;
+ Thread *current_thread = Thread::Current();
+ ASSERT(current_thread != NULL); // AutoThread ensures this
+
+ crit_.Enter();
+ bool ready = false;
+ _SendMessage smsg;
+ smsg.thread = current_thread;
+ smsg.msg = msg;
+ smsg.ready = &ready;
+ sendlist_.push_back(smsg);
+ has_sends_ = true;
+ crit_.Leave();
+
+ // Wait for a reply
+
+ ss_->WakeUp();
+ while (!ready) {
+ current_thread->ReceiveSends();
+ current_thread->socketserver()->Wait(-1, false);
+ }
+}
+
+void Thread::ReceiveSends() {
+ // Before entering critical section, check boolean.
+
+ if (!has_sends_)
+ return;
+
+ // Receive a sent message. Cleanup scenarios:
+ // - thread sending exits: We don't allow this, since thread can exit
+ // only via Join, so Send must complete.
+ // - thread receiving exits: Wakeup/set ready in Thread::Clear()
+ // - object target cleared: Wakeup/set ready in Thread::Clear()
+ crit_.Enter();
+ while (!sendlist_.empty()) {
+ _SendMessage smsg = sendlist_.front();
+ sendlist_.pop_front();
+ crit_.Leave();
+ smsg.msg.phandler->OnMessage(&smsg.msg);
+ crit_.Enter();
+ *smsg.ready = true;
+ smsg.thread->socketserver()->WakeUp();
+ }
+ has_sends_ = false;
+ crit_.Leave();
+}
+
+void Thread::Clear(MessageHandler *phandler, uint32 id) {
+ CritScope cs(&crit_);
+
+ // Remove messages on sendlist_ with phandler
+ // Object target cleared: remove from send list, wakeup/set ready
+ // if sender not NULL.
+
+ std::list<_SendMessage>::iterator iter = sendlist_.begin();
+ while (iter != sendlist_.end()) {
+ _SendMessage smsg = *iter;
+ if (phandler == NULL || smsg.msg.phandler == phandler) {
+ if (id == (uint32)-1 || smsg.msg.message_id == id) {
+ iter = sendlist_.erase(iter);
+ *smsg.ready = true;
+ smsg.thread->socketserver()->WakeUp();
+ continue;
+ }
+ }
+ ++iter;
+ }
+
+ MessageQueue::Clear(phandler, id);
+}
+
+AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
+ if (!ThreadManager::CurrentThread()) {
+ ThreadManager::SetCurrent(this);
+ }
+}
+
+AutoThread::~AutoThread() {
+ if (ThreadManager::CurrentThread() == this) {
+ ThreadManager::SetCurrent(NULL);
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h
new file mode 100644
index 00000000..56c23384
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h
@@ -0,0 +1,141 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __THREAD_H__
+#define __THREAD_H__
+
+#include "talk/base/messagequeue.h"
+
+#include <algorithm>
+#include <list>
+#include <vector>
+
+#ifdef POSIX
+#include <pthread.h>
+#endif
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+namespace cricket {
+
+class Thread;
+
+class ThreadManager {
+public:
+ ThreadManager();
+ ~ThreadManager();
+
+ static Thread *CurrentThread();
+ static void SetCurrent(Thread *thread);
+ void Add(Thread *thread);
+ void Remove(Thread *thread);
+
+private:
+ Thread *main_thread_;
+ std::vector<Thread *> threads_;
+ CriticalSection crit_;
+
+#ifdef POSIX
+ static pthread_key_t key_;
+#endif
+
+#ifdef WIN32
+ static DWORD key_;
+#endif
+};
+
+class Thread;
+
+struct _SendMessage {
+ _SendMessage() {}
+ Thread *thread;
+ Message msg;
+ bool *ready;
+};
+
+class Thread : public MessageQueue {
+public:
+ Thread(SocketServer* ss = 0);
+ virtual ~Thread();
+
+ static inline Thread* Current() {
+ return ThreadManager::CurrentThread();
+ }
+ inline bool IsCurrent() const {
+ return (ThreadManager::CurrentThread() == this);
+ }
+
+ virtual void Start();
+ virtual void Stop();
+ virtual void Loop(int cms = -1);
+ virtual void Send(MessageHandler *phandler, uint32 id = 0,
+ MessageData *pdata = NULL);
+
+ // From MessageQueue
+ virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1);
+ virtual void ReceiveSends();
+
+#ifdef WIN32
+ HANDLE GetHandle() {
+ return thread_;
+ }
+#endif
+
+private:
+ static void *PreLoop(void *pv);
+ void Join();
+
+ std::list<_SendMessage> sendlist_;
+ bool started_;
+ bool has_sends_;
+
+#ifdef POSIX
+ pthread_t thread_;
+#endif
+
+#ifdef WIN32
+ HANDLE thread_;
+#endif
+
+ friend class ThreadManager;
+};
+
+// AutoThread automatically installs itself at construction
+// uninstalls at destruction, if a Thread object is
+// _not already_ associated with the current OS thread.
+
+class AutoThread : public Thread {
+public:
+ AutoThread(SocketServer* ss = 0);
+ virtual ~AutoThread();
+};
+
+} // namespace cricket
+
+#endif // __THREAD_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h
new file mode 100644
index 00000000..99ba2fdc
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h
@@ -0,0 +1,101 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _WINPING_H_
+#define _WINPING_H_
+
+#ifdef WIN32
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "talk/base/basictypes.h"
+
+#include <winsock2.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#undef SetPort
+
+// This class wraps a Win32 API for doing ICMP pinging. This API, unlike the
+// the normal socket APIs (as implemented on Win9x), will return an error if
+// an ICMP packet with the dont-fragment bit set is too large. This means this
+// class can be used to detect the MTU to a given address.
+
+typedef struct ip_option_information {
+ UCHAR Ttl; // Time To Live
+ UCHAR Tos; // Type Of Service
+ UCHAR Flags; // IP header flags
+ UCHAR OptionsSize; // Size in bytes of options data
+ PUCHAR OptionsData; // Pointer to options data
+} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;
+
+typedef HANDLE (WINAPI *PIcmpCreateFile)();
+
+typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle);
+
+typedef DWORD (WINAPI *PIcmpSendEcho)(
+ HANDLE IcmpHandle,
+ ULONG DestinationAddress,
+ LPVOID RequestData,
+ WORD RequestSize,
+ PIP_OPTION_INFORMATION RequestOptions,
+ LPVOID ReplyBuffer,
+ DWORD ReplySize,
+ DWORD Timeout);
+
+class WinPing {
+public:
+ WinPing();
+ ~WinPing();
+
+ // Determines whether the class was initialized correctly.
+ bool IsValid() { return valid_; }
+
+ // Attempts to send a ping with the given parameters.
+ enum PingResult { PING_FAIL, PING_TOO_LARGE, PING_TIMEOUT, PING_SUCCESS };
+ PingResult Ping(
+ uint32 ip, uint32 data_size, uint32 timeout_millis, uint8 ttl,
+ bool allow_fragments);
+
+private:
+ HMODULE dll_;
+ HANDLE hping_;
+ PIcmpCreateFile create_;
+ PIcmpCloseHandle close_;
+ PIcmpSendEcho send_;
+ char* data_;
+ uint32 dlen_;
+ char* reply_;
+ uint32 rlen_;
+ bool valid_;
+};
+
+#endif // WIN32
+
+#endif // _WINPING_H_
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am
new file mode 100644
index 00000000..43b0edb5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=login call
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am
new file mode 100644
index 00000000..81cf9345
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/Makefile.am
@@ -0,0 +1,16 @@
+bin_PROGRAMS = call
+call_CXXFLAGS = $(AM_CXXFLAGS)
+call_SOURCES = call_main.cc callclient.cc console.cc presencepushtask.cc presenceouttask.cc
+noinst_HEADERS = callclient.h console.h presenceouttask.h presencepushtask.h status.h
+call_LDADD = \
+ $(srcdir)/../../../talk/examples/login/libcricketexampleslogin.la \
+ $(srcdir)/../../../talk/session/phone/libcricketsessionphone.la \
+ $(srcdir)/../../../talk/p2p/client/libcricketp2pclient.la \
+ $(srcdir)/../../../talk/p2p/base/libcricketp2pbase.la \
+ $(srcdir)/../../../talk/xmpp/libcricketxmpp.la \
+ $(srcdir)/../../../talk/xmllite/libcricketxmllite.la \
+ $(srcdir)/../../../talk/base/libcricketbase.la \
+ $(srcdir)/../../../talk/third_party/mediastreamer/libmediastreamer.la \
+ $(EXPAT_LIBS) $(ORTP_LIBS) -lpthread $(ILBC_LIBS) $(SPEEX_LIBS) $(GLIB_LIBS) -lasound
+AM_CPPFLAGS = -DPOSIX
+DEFAULT_INCLUDES = -I$(srcdir)/../../.. \ No newline at end of file
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro
new file mode 100644
index 00000000..ccf0638b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call.pro
@@ -0,0 +1,19 @@
+TEMPLATE = app
+INCLUDEPATH = ../../..
+DEFINES += POSIX
+
+include(../../../../../conf.pri)
+
+# Input
+SOURCES += \
+ call_main.cc \
+ callclient.cc \
+ console.cc \
+ presenceouttask.cc \
+ presencepushtask.cc \
+ ../login/xmppauth.cc \
+ ../login/xmpppump.cc \
+ ../login/xmppsocket.cc \
+ ../login/xmppthread.cc
+
+LIBS += ../../../liblibjingle.a
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc
new file mode 100644
index 00000000..1a965326
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/call_main.cc
@@ -0,0 +1,62 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/examples/login/xmppthread.h"
+#include "talk/examples/login/xmppauth.h"
+#include "talk/examples/call/callclient.h"
+#include "talk/examples/call/console.h"
+
+void GetString(const char* desc, char* out) {
+ printf("%s: ", desc);
+ fflush(stdout);
+ scanf("%s", out);
+}
+
+int main(int argc, char **argv) {
+ // TODO: Make this into a console task
+ char username[256], auth_cookie[256];
+ GetString("Username", username);
+ GetString("Auth Cookie", auth_cookie);
+
+ printf("Logging in as %s@gmail.com\n", username);
+
+ // We will run the console and the XMPP client on the main thread. The
+ // CallClient maintains a separate worker thread for voice.
+
+ cricket::PhysicalSocketServer ss;
+ cricket::Thread main_thread(&ss);
+ cricket::ThreadManager::SetCurrent(&main_thread);
+
+ InitConsole(&ss);
+ XmppPump pump;
+ CallClient client(pump.client());
+
+ buzz::XmppClientSettings xcs;
+ xcs.set_user(username);
+ xcs.set_host("gmail.com");
+ xcs.set_use_tls(false);
+ xcs.set_auth_cookie(auth_cookie);
+ xcs.set_server(cricket::SocketAddress("talk.google.com", 5222));
+ pump.DoLogin(xcs, new XmppSocket(false), new XmppAuth());
+
+ main_thread.Loop();
+
+ return 0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc
new file mode 100644
index 00000000..c8c28310
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.cc
@@ -0,0 +1,390 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+#include <vector>
+
+#include "talk/xmpp/constants.h"
+#include "talk/base/thread.h"
+#include "talk/base/network.h"
+#include "talk/base/socketaddress.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/p2p/client/basicportallocator.h"
+#include "talk/session/receiver.h"
+#include "talk/session/sessionsendtask.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/examples/call/callclient.h"
+#include "talk/examples/call/console.h"
+#include "talk/examples/call/presencepushtask.h"
+#include "talk/examples/call/presenceouttask.h"
+
+namespace {
+
+const char* CALL_COMMANDS =
+"Available commands:\n"
+"\n"
+" hangup Ends the call.\n"
+" mute Stops sending voice.\n"
+" unmute Re-starts sending voice.\n"
+"";
+
+class CallTask: public ConsoleTask, public sigslot::has_slots<> {
+public:
+ CallTask(CallClient* call_client, const buzz::Jid& jid, cricket::Call* call)
+ : call_client_(call_client), jid_(jid), call_(call) {
+ }
+
+ virtual ~CallTask() {}
+
+ virtual void Start() {
+ call_client_->phone_client()->SignalCallDestroy.connect(
+ this, &CallTask::OnCallDestroy);
+ if (!call_) {
+ call_ = call_client_->phone_client()->CreateCall();
+ call_->SignalSessionState.connect(this, &CallTask::OnSessionState);
+ session_ = call_->InitiateSession(jid_);
+ }
+ call_client_->phone_client()->SetFocus(call_);
+ }
+
+ virtual std::string GetPrompt() { return jid_.node(); }
+
+ virtual void ProcessLine(const std::string& line) {
+ std::vector<std::string> words;
+ ParseLine(line, &words);
+
+ if ((words.size() == 1) && (words[0] == "hangup")) {
+ call_->Terminate();
+ SignalDone(this);
+ } else if ((words.size() == 1) && (words[0] == "mute")) {
+ call_->Mute(true);
+ } else if ((words.size() == 1) && (words[0] == "unmute")) {
+ call_->Mute(false);
+ } else {
+ console()->Print(CALL_COMMANDS);
+ }
+ }
+
+private:
+ CallClient* call_client_;
+ buzz::Jid jid_;
+ cricket::Call* call_;
+ cricket::Session* session_;
+
+ void OnCallDestroy(cricket::Call* call) {
+ if (call == call_) {
+ console()->Print("call destroyed");
+ SignalDone(this);
+ }
+ }
+
+ void OnSessionState(cricket::Call* call,
+ cricket::Session* session,
+ cricket::Session::State state) {
+ if (state == cricket::Session::STATE_SENTINITIATE) {
+ console()->Print("calling...");
+ } else if (state == cricket::Session::STATE_RECEIVEDACCEPT) {
+ console()->Print("call answered");
+ } else if (state == cricket::Session::STATE_RECEIVEDREJECT) {
+ console()->Print("call not answered");
+ SignalDone(this);
+ } else if (state == cricket::Session::STATE_INPROGRESS) {
+ console()->Print("call in progress");
+ } else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) {
+ console()->Print("other side hung up");
+ SignalDone(this);
+ }
+ }
+};
+
+const char* RECEIVE_COMMANDS =
+"Available commands:\n"
+"\n"
+" accept Accepts the incoming call and switches to it.\n"
+" reject Rejects the incoming call and stays with the current call.\n"
+"";
+
+class ReceiveTask: public ConsoleTask {
+public:
+ ReceiveTask(CallClient* call_client,
+ const buzz::Jid& jid,
+ cricket::Call* call)
+ : call_client_(call_client), jid_(jid), call_(call) {
+ }
+
+ virtual std::string GetPrompt() { return jid_.node(); }
+
+ virtual void ProcessLine(const std::string& line) {
+ std::vector<std::string> words;
+ ParseLine(line, &words);
+
+ if ((words.size() == 1) && (words[0] == "accept")) {
+ assert(call_->sessions().size() == 1);
+ call_->AcceptSession(call_->sessions()[0]);
+ Console()->Push(new CallTask(call_client_, jid_, call_));
+ SignalDone(this);
+ } else if ((words.size() == 1) && (words[0] == "reject")) {
+ call_->RejectSession(call_->sessions()[0]);
+ SignalDone(this);
+ } else {
+ console()->Print(RECEIVE_COMMANDS);
+ }
+ }
+
+private:
+ CallClient* call_client_;
+ buzz::Jid jid_;
+ cricket::Call* call_;
+};
+
+const char* CONSOLE_COMMANDS =
+"Available commands:\n"
+"\n"
+" roster Prints the online friends from your roster.\n"
+" call <name> Initiates a call to the friend with the given name.\n"
+" quit Quits the application.\n"
+"";
+
+class CallConsoleTask: public ConsoleTask {
+public:
+ CallConsoleTask(CallClient* call_client) : call_client_(call_client) {}
+ virtual ~CallConsoleTask() {}
+
+ virtual std::string GetPrompt() { return "console"; }
+
+ virtual void ProcessLine(const std::string& line) {
+ std::vector<std::string> words;
+ ParseLine(line, &words);
+
+ if ((words.size() == 1) && (words[0] == "quit")) {
+ SignalDone(this);
+ } else if ((words.size() == 1) && (words[0] == "roster")) {
+ call_client_->PrintRoster();
+ } else if ((words.size() == 2) && (words[0] == "call")) {
+ call_client_->MakeCallTo(words[1]);
+ } else {
+ console()->Print(CONSOLE_COMMANDS);
+ }
+ }
+
+private:
+ CallClient* call_client_;
+};
+
+const char* DescribeStatus(buzz::Status::Show show, const std::string& desc) {
+ switch (show) {
+ case buzz::Status::SHOW_XA: return desc.c_str();
+ case buzz::Status::SHOW_ONLINE: return "online";
+ case buzz::Status::SHOW_AWAY: return "away";
+ case buzz::Status::SHOW_DND: return "do not disturb";
+ case buzz::Status::SHOW_CHAT: return "ready to chat";
+ delault: return "offline";
+ }
+}
+
+} // namespace
+
+CallClient::CallClient(buzz::XmppClient* xmpp_client)
+ : xmpp_client_(xmpp_client), roster_(new RosterMap) {
+ xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
+ Console()->Push(new CallConsoleTask(this));
+}
+
+CallClient::~CallClient() {
+ delete roster_;
+}
+
+const std::string CallClient::strerror(buzz::XmppEngine::Error err) {
+ switch (err) {
+ case buzz::XmppEngine::ERROR_NONE:
+ return "";
+ case buzz::XmppEngine::ERROR_XML:
+ return "Malformed XML or encoding error";
+ case buzz::XmppEngine::ERROR_STREAM:
+ return "XMPP stream error";
+ case buzz::XmppEngine::ERROR_VERSION:
+ return "XMPP version error";
+ case buzz::XmppEngine::ERROR_UNAUTHORIZED:
+ return "User is not authorized (Confirm your GX cookie at mail.google.com)";
+ case buzz::XmppEngine::ERROR_TLS:
+ return "TLS could not be negotiated";
+ case buzz::XmppEngine::ERROR_AUTH:
+ return "Authentication could not be negotiated";
+ case buzz::XmppEngine::ERROR_BIND:
+ return "Resource or session binding could not be negotiated";
+ case buzz::XmppEngine::ERROR_CONNECTION_CLOSED:
+ return "Connection closed by output handler.";
+ case buzz::XmppEngine::ERROR_DOCUMENT_CLOSED:
+ return "Closed by </stream:stream>";
+ case buzz::XmppEngine::ERROR_SOCKET:
+ return "Socket error";
+ }
+}
+
+void CallClient::OnStateChange(buzz::XmppEngine::State state) {
+ switch (state) {
+ case buzz::XmppEngine::STATE_START:
+ Console()->Print("connecting...");
+ break;
+
+ case buzz::XmppEngine::STATE_OPENING:
+ Console()->Print("logging in...");
+ break;
+
+ case buzz::XmppEngine::STATE_OPEN:
+ Console()->Print("logged in...");
+ InitPhone();
+ InitPresence();
+ break;
+
+ case buzz::XmppEngine::STATE_CLOSED:
+ buzz::XmppEngine::Error error = xmpp_client_->GetError();
+ Console()->Print("logged out..." + strerror(error));
+ exit(0);
+ }
+}
+
+void CallClient::InitPhone() {
+ std::string client_unique = xmpp_client_->jid().Str();
+ cricket::InitRandom(client_unique.c_str(), client_unique.size());
+
+ worker_thread_ = new cricket::Thread();
+
+ network_manager_ = new cricket::NetworkManager();
+
+ cricket::SocketAddress *stun_addr = new cricket::SocketAddress("64.233.167.126", 19302);
+ port_allocator_ = new cricket::BasicPortAllocator(network_manager_, stun_addr, NULL);
+
+ session_manager_ = new cricket::SessionManager(
+ port_allocator_, worker_thread_);
+ session_manager_->SignalRequestSignaling.connect(
+ this, &CallClient::OnRequestSignaling);
+ session_manager_->OnSignalingReady();
+
+ phone_client_ = new cricket::PhoneSessionClient(
+ xmpp_client_->jid(),session_manager_);
+ phone_client_->SignalCallCreate.connect(this, &CallClient::OnCallCreate);
+ phone_client_->SignalSendStanza.connect(this, &CallClient::OnSendStanza);
+
+ receiver_ = new cricket::Receiver(xmpp_client_, phone_client_);
+ receiver_->Start();
+
+ worker_thread_->Start();
+}
+
+void CallClient::OnRequestSignaling() {
+ session_manager_->OnSignalingReady();
+}
+
+void CallClient::OnCallCreate(cricket::Call* call) {
+ call->SignalSessionState.connect(this, &CallClient::OnSessionState);
+}
+
+void CallClient::OnSessionState(cricket::Call* call,
+ cricket::Session* session,
+ cricket::Session::State state) {
+ if (state == cricket::Session::STATE_RECEIVEDINITIATE) {
+ buzz::Jid jid(session->remote_address());
+ Console()->Printf("Incoming call from '%s'", jid.Str().c_str());
+ Console()->Push(new ReceiveTask(this, jid, call));
+ }
+}
+
+void CallClient::OnSendStanza(cricket::SessionClient *client, const buzz::XmlElement* stanza) {
+ cricket::SessionSendTask* sender =
+ new cricket::SessionSendTask(xmpp_client_, phone_client_);
+ sender->Send(stanza);
+ sender->Start();
+}
+
+void CallClient::InitPresence() {
+ presence_push_ = new buzz::PresencePushTask(xmpp_client_);
+ presence_push_->SignalStatusUpdate.connect(
+ this, &CallClient::OnStatusUpdate);
+ presence_push_->Start();
+
+ buzz::Status my_status;
+ my_status.set_jid(xmpp_client_->jid());
+ my_status.set_available(true);
+ my_status.set_invisible(false);
+ my_status.set_show(buzz::Status::SHOW_ONLINE);
+ my_status.set_priority(0);
+ my_status.set_know_capabilities(true);
+ my_status.set_phone_capability(true);
+ my_status.set_is_google_client(true);
+ my_status.set_version("1.0.0.66");
+
+ buzz::PresenceOutTask* presence_out_ =
+ new buzz::PresenceOutTask(xmpp_client_);
+ presence_out_->Send(my_status);
+ presence_out_->Start();
+}
+
+void CallClient::OnStatusUpdate(const buzz::Status& status) {
+ RosterItem item;
+ item.jid = status.jid();
+ item.show = status.show();
+ item.status = status.status();
+
+ std::string key = item.jid.Str();
+
+ if (status.available() && status.phone_capability()) {
+ Console()->Printf("Adding to roster: %s", key.c_str());
+ (*roster_)[key] = item;
+ } else {
+ Console()->Printf("Removing from roster: %s", key.c_str());
+ RosterMap::iterator iter = roster_->find(key);
+ if (iter != roster_->end())
+ roster_->erase(iter);
+ }
+}
+
+void CallClient::PrintRoster() {
+ Console()->Printf("Roster contains %d callable", roster_->size());
+ RosterMap::iterator iter = roster_->begin();
+ while (iter != roster_->end()) {
+ Console()->Printf("%s - %s",
+ iter->second.jid.BareJid().Str().c_str(),
+ DescribeStatus(iter->second.show, iter->second.status));
+ iter++;
+ }
+}
+
+void CallClient::MakeCallTo(const std::string& name) {
+ bool found = false;
+ buzz::Jid found_jid;
+
+ RosterMap::iterator iter = roster_->begin();
+ while (iter != roster_->end()) {
+ if (iter->second.jid.node() == name) {
+ found = true;
+ found_jid = iter->second.jid;
+ break;
+ }
+ ++iter;
+ }
+
+ if (found) {
+ Console()->Printf("Found online friend '%s'", found_jid.Str().c_str());
+ Console()->Push(new CallTask(this, found_jid, NULL));
+ } else {
+ Console()->Printf("Could not find online friend '%s'", name.c_str());
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h
new file mode 100644
index 00000000..2400b7db
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/callclient.h
@@ -0,0 +1,88 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
+#define CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
+
+#include <map>
+#include <string>
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/xmpp/xmppclient.h"
+#include "talk/examples/call/status.h"
+
+namespace buzz {
+class PresencePushTask;
+class Status;
+}
+
+namespace cricket {
+class Thread;
+class NetworkManager;
+class PortAllocator;
+class PhoneSessionClient;
+class Receiver;
+class Call;
+}
+
+struct RosterItem {
+ buzz::Jid jid;
+ buzz::Status::Show show;
+ std::string status;
+};
+
+class CallClient: public sigslot::has_slots<> {
+public:
+ CallClient(buzz::XmppClient* xmpp_client);
+ ~CallClient();
+
+ cricket::PhoneSessionClient* phone_client() const { return phone_client_; }
+
+ void PrintRoster();
+ void MakeCallTo(const std::string& name);
+
+private:
+ typedef std::map<std::string,RosterItem> RosterMap;
+
+ buzz::XmppClient* xmpp_client_;
+ cricket::Thread* worker_thread_;
+ cricket::NetworkManager* network_manager_;
+ cricket::PortAllocator* port_allocator_;
+ cricket::SessionManager* session_manager_;
+ cricket::PhoneSessionClient* phone_client_;
+ cricket::Receiver* receiver_;
+ buzz::PresencePushTask* presence_push_;
+ RosterMap* roster_;
+
+ void OnStateChange(buzz::XmppEngine::State state);
+
+ void InitPhone();
+ void OnRequestSignaling();
+ void OnCallCreate(cricket::Call* call);
+ const std::string strerror(buzz::XmppEngine::Error err);
+ void OnSessionState(cricket::Call* call,
+ cricket::Session* session,
+ cricket::Session::State state);
+ void OnSendStanza(cricket::SessionClient *client, const buzz::XmlElement* stanza);
+
+ void InitPresence();
+ void OnStatusUpdate(const buzz::Status& status);
+};
+
+#endif // CRICKET_EXAMPLES_CALL_CALLCLIENT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc
new file mode 100644
index 00000000..4150f281
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.cc
@@ -0,0 +1,196 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+}
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdarg>
+
+#include "talk/examples/call/console.h"
+
+namespace {
+
+void PError(const char* desc) {
+ perror(desc);
+ exit(1);
+}
+
+CConsole* gConsole = NULL;
+
+const uint32 MSG_UPDATE = 1;
+
+} // namespace
+
+void InitConsole(cricket::PhysicalSocketServer* ss) {
+ assert(gConsole == NULL);
+ assert(ss);
+ gConsole = new CConsole(ss);
+}
+
+CConsole* Console() {
+ assert(gConsole);
+ return gConsole;
+}
+
+CConsole::CConsole(cricket::PhysicalSocketServer* ss)
+ : prompting_(false), prompt_dirty_(false) {
+ stdin_ = ss->CreateFile(0);
+ stdin_->SignalReadEvent.connect(this, &CConsole::OnReadInput);
+
+ tasks_ = new std::vector<ConsoleTask*>;
+}
+
+CConsole::~CConsole() {
+ delete stdin_;
+ delete tasks_;
+}
+
+void CConsole::Push(ConsoleTask* task) {
+ task->set_console(this);
+ task->SignalDone.connect(this, &CConsole::OnTaskDone);
+ tasks_->push_back(task);
+ task->Start();
+ UpdatePrompt();
+}
+
+void CConsole::Remove(ConsoleTask* task) {
+ int index = -1;
+ for (size_t i = 0; i < tasks_->size(); ++i) {
+ if ((*tasks_)[i] == task)
+ index = i;
+ }
+
+ assert(index >= 0);
+ tasks_->erase(tasks_->begin() + index);
+ if (static_cast<int>(tasks_->size()) == index)
+ UpdatePrompt();
+
+ delete task;
+
+ if (tasks_->size() == 0)
+ exit(0);
+}
+
+void CConsole::Print(const char* str) {
+ if (prompting_)
+ printf("\r");
+ printf("%s\n", str);
+ prompting_ = false;
+ UpdatePrompt();
+}
+
+void CConsole::Print(const std::string& str) {
+ Print(str.c_str());
+}
+
+void CConsole::Printf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+
+ char buf[4096];
+ int size = vsnprintf(buf, sizeof(buf), format, ap);
+ assert(size >= 0);
+ assert(size < static_cast<int>(sizeof(buf)));
+ buf[size] = '\0';
+ Print(buf);
+
+ va_end(ap);
+}
+
+void CConsole::OnTaskDone(ConsoleTask* task) {
+ Remove(task);
+}
+
+void CConsole::OnReadInput(cricket::AsyncFile* file) {
+ assert(file == stdin_);
+
+ char buf[4096];
+ int size = read(0, buf, sizeof(buf));
+ if (size < 0)
+ PError("read");
+
+ prompting_ = (buf[size-1] != '\n');
+
+ int start = 0;
+ for (int i = 0; i < size; ++i) {
+ if (buf[i] == '\n') {
+ std::string line = input_;
+ line.append(buf + start, i + 1 - start);
+ input_.clear();
+
+ assert(tasks_->size() > 0);
+ tasks_->back()->ProcessLine(line);
+
+ start = i + 1;
+ }
+ }
+
+ input_.append(buf + start, size - start);
+}
+
+void CConsole::OnMessage(cricket::Message* pmsg) {
+ assert(pmsg->message_id == MSG_UPDATE);
+ assert(tasks_->size() > 0);
+ if (prompting_)
+ printf("\n");
+ printf("%s: %s", tasks_->back()->GetPrompt().c_str(), input_.c_str());
+ fflush(stdout);
+ prompting_ = true;
+ prompt_dirty_ = false;
+}
+
+void CConsole::UpdatePrompt() {
+ if (!prompt_dirty_) {
+ prompt_dirty_ = true;
+ cricket::Thread::Current()->Post(this, MSG_UPDATE);
+ }
+}
+
+void ConsoleTask::ParseLine(const std::string& line,
+ std::vector<std::string>* words) {
+ assert(line.size() > 0);
+ assert(line[line.size() - 1] == '\n');
+
+ int start = -1;
+ int state = 0;
+ for (int index = 0; index <= static_cast<int>(line.size()); ++index) {
+ if (state == 0) {
+ if (!isspace(line[index])) {
+ start = index;
+ state = 1;
+ }
+ } else {
+ assert(state == 1);
+ assert(start >= 0);
+ if (isspace(line[index])) {
+ std::string word(line, start, index - start);
+ words->push_back(word);
+ start = -1;
+ state = 0;
+ }
+ }
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h
new file mode 100644
index 00000000..aca229b9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/console.h
@@ -0,0 +1,82 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef CRICKET_EXAMPLES_CALL_CONSOLE_H__
+#define CRICKET_EXAMPLES_CALL_CONSOLE_H__
+
+#include <string>
+#include <vector>
+
+#include "talk/base/sigslot.h"
+#include "talk/base/thread.h"
+#include "talk/base/physicalsocketserver.h"
+
+class CConsole;
+
+class ConsoleTask {
+public:
+ ConsoleTask() : console_(NULL) {}
+ virtual ~ConsoleTask() {}
+
+ CConsole* console() const { return console_; }
+ void set_console(CConsole* console) { console_ = console; }
+
+ virtual void Start() {}
+ virtual std::string GetPrompt() = 0;
+ virtual void ProcessLine(const std::string& line) = 0; // includes newline
+
+ sigslot::signal1<ConsoleTask*> SignalDone;
+
+protected:
+ void ParseLine(const std::string& line, std::vector<std::string>* words);
+
+private:
+ CConsole* console_;
+};
+
+class CConsole: public cricket::MessageHandler, public sigslot::has_slots<> {
+public:
+ CConsole(cricket::PhysicalSocketServer* ss);
+ ~CConsole();
+
+ void Push(ConsoleTask* task);
+ void Remove(ConsoleTask* task);
+
+ // final newline should not be included
+ void Print(const char* str);
+ void Print(const std::string& str);
+ void Printf(const char* format, ...);
+
+private:
+ cricket::AsyncFile* stdin_;
+ std::vector<ConsoleTask*>* tasks_;
+ std::string input_;
+ bool prompting_;
+ bool prompt_dirty_;
+
+ void OnTaskDone(ConsoleTask* task);
+ void OnReadInput(cricket::AsyncFile* file);
+ void OnMessage(cricket::Message* pmsg);
+ void UpdatePrompt();
+};
+
+void InitConsole(cricket::PhysicalSocketServer* ss);
+CConsole* Console();
+
+#endif // CRICKET_EXAMPLES_CALL_CONSOLE_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc
new file mode 100644
index 00000000..3ecdb420
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.cc
@@ -0,0 +1,148 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sstream>
+#include <time.h>
+#include "talk/xmpp/constants.h"
+#include "talk/xmpp/xmppclient.h"
+#include "talk/examples/call/presenceouttask.h"
+
+namespace buzz {
+
+// string helper functions -----------------------------------------------------
+template <class T> static
+bool FromString(const std::string& s,
+ T * t) {
+ std::istringstream iss(s);
+ return !(iss>>*t).fail();
+}
+
+template <class T> static
+bool ToString(const T &t,
+ std::string* s) {
+ std::ostringstream oss;
+ oss << t;
+ *s = oss.str();
+ return !oss.fail();
+}
+
+XmppReturnStatus
+PresenceOutTask::Send(const Status & s) {
+ if (GetState() != STATE_INIT)
+ return XMPP_RETURN_BADSTATE;
+
+ stanza_.reset(TranslateStatus(s));
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+PresenceOutTask::SendDirected(const Jid & j, const Status & s) {
+ if (GetState() != STATE_INIT)
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement * presence = TranslateStatus(s);
+ presence->AddAttr(QN_TO, j.Str());
+ stanza_.reset(presence);
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus PresenceOutTask::SendProbe(const Jid & jid) {
+ if (GetState() != STATE_INIT)
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement * presence = new XmlElement(QN_PRESENCE);
+ presence->AddAttr(QN_TO, jid.Str());
+ presence->AddAttr(QN_TYPE, "probe");
+
+ stanza_.reset(presence);
+ return XMPP_RETURN_OK;
+}
+
+int
+PresenceOutTask::ProcessStart() {
+ if (SendStanza(stanza_.get()) != XMPP_RETURN_OK)
+ return STATE_ERROR;
+ return STATE_DONE;
+}
+
+XmlElement *
+PresenceOutTask::TranslateStatus(const Status & s) {
+ XmlElement * result = new XmlElement(QN_PRESENCE);
+ if (!s.available()) {
+ result->AddAttr(QN_TYPE, STR_UNAVAILABLE);
+ }
+ else {
+ if (s.invisible()) {
+ result->AddAttr(QN_TYPE, STR_INVISIBLE);
+ }
+
+ if (s.show() != Status::SHOW_ONLINE && s.show() != Status::SHOW_OFFLINE) {
+ result->AddElement(new XmlElement(QN_SHOW));
+ switch (s.show()) {
+ default:
+ result->AddText(STR_SHOW_AWAY, 1);
+ break;
+ case Status::SHOW_XA:
+ result->AddText(STR_SHOW_XA, 1);
+ break;
+ case Status::SHOW_DND:
+ result->AddText(STR_SHOW_DND, 1);
+ break;
+ case Status::SHOW_CHAT:
+ result->AddText(STR_SHOW_CHAT, 1);
+ break;
+ }
+ }
+
+ result->AddElement(new XmlElement(QN_STATUS));
+ result->AddText(s.status(), 1);
+
+ std::string pri;
+ ToString(s.priority(), &pri);
+
+ result->AddElement(new XmlElement(QN_PRIORITY));
+ result->AddText(pri, 1);
+
+ if (s.know_capabilities() && s.is_google_client()) {
+ result->AddElement(new XmlElement(QN_CAPS_C, true));
+ result->AddAttr(QN_NODE, GOOGLE_CLIENT_NODE, 1);
+ result->AddAttr(QN_VER, s.version(), 1);
+ result->AddAttr(QN_EXT, s.phone_capability() ? "voice-v1" : "", 1);
+ }
+
+ // Put the delay mark on the presence according to JEP-0091
+ {
+ result->AddElement(new XmlElement(kQnDelayX, true));
+
+ // This here is why we *love* the C runtime
+ time_t current_time_seconds;
+ time(&current_time_seconds);
+ struct tm* current_time = gmtime(&current_time_seconds);
+ char output[256];
+ strftime(output, ARRAY_SIZE(output), "%Y%m%dT%H:%M:%S", current_time);
+ result->AddAttr(kQnStamp, output, 1);
+ }
+
+ }
+
+ return result;
+}
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h
new file mode 100644
index 00000000..868bda59
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presenceouttask.h
@@ -0,0 +1,46 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _PRESENCEOUTTASK_H_
+#define _PRESENCEOUTTASK_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/examples/call/status.h"
+
+namespace buzz {
+
+class PresenceOutTask : public XmppTask {
+public:
+ PresenceOutTask(Task * parent) : XmppTask(parent) {}
+ virtual ~PresenceOutTask() {}
+
+ XmppReturnStatus Send(const Status & s);
+ XmppReturnStatus SendDirected(const Jid & j, const Status & s);
+ XmppReturnStatus SendProbe(const Jid& jid);
+
+ virtual int ProcessStart();
+private:
+ XmlElement * TranslateStatus(const Status & s);
+ scoped_ptr<XmlElement> stanza_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc
new file mode 100644
index 00000000..d0543b99
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.cc
@@ -0,0 +1,172 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "talk/examples/call/presencepushtask.h"
+#include "talk/xmpp/constants.h"
+#include <sstream>
+
+
+namespace buzz {
+
+// string helper functions -----------------------------------------------------
+template <class T> static
+bool FromString(const std::string& s,
+ T * t) {
+ std::istringstream iss(s);
+ return !(iss>>*t).fail();
+}
+
+template <class T> static
+bool ToString(const T &t,
+ std::string* s) {
+ std::ostringstream oss;
+ oss << t;
+ *s = oss.str();
+ return !oss.fail();
+}
+
+static bool
+IsXmlSpace(int ch) {
+ return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
+}
+
+static bool
+ListContainsToken(const std::string & list, const std::string & token) {
+ size_t i = list.find(token);
+ if (i == std::string::npos || token.empty())
+ return false;
+ bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
+ bool boundary_after = (i == list.length() - token.length() || IsXmlSpace(list[i + token.length()]));
+ return boundary_before && boundary_after;
+}
+
+
+bool
+PresencePushTask::HandleStanza(const XmlElement * stanza) {
+ if (stanza->Name() != QN_PRESENCE)
+ return false;
+ if (stanza->HasAttr(QN_TYPE) && stanza->Attr(QN_TYPE) != STR_UNAVAILABLE)
+ return false;
+ QueueStanza(stanza);
+ return true;
+}
+
+static bool IsUtf8FirstByte(int c) {
+ return (((c)&0x80)==0) || // is single byte
+ ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
+}
+
+int
+PresencePushTask::ProcessStart() {
+ const XmlElement * stanza = NextStanza();
+ if (stanza == NULL)
+ return STATE_BLOCKED;
+ Status s;
+
+ s.set_jid(Jid(stanza->Attr(QN_FROM)));
+
+ if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
+ s.set_available(false);
+ SignalStatusUpdate(s);
+ }
+ else {
+ s.set_available(true);
+ const XmlElement * status = stanza->FirstNamed(QN_STATUS);
+ if (status != NULL) {
+ s.set_status(status->BodyText());
+
+ // Truncate status messages longer than 300 bytes
+ if (s.status().length() > 300) {
+ size_t len = 300;
+
+ // Be careful not to split legal utf-8 chars in half
+ while (!IsUtf8FirstByte(s.status()[len]) && len > 0) {
+ len -= 1;
+ }
+ std::string truncated(s.status(), 0, len);
+ s.set_status(truncated);
+ }
+ }
+
+ const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
+ if (priority != NULL) {
+ int pri;
+ if (FromString(priority->BodyText(), &pri)) {
+ s.set_priority(pri);
+ }
+ }
+
+ const XmlElement * show = stanza->FirstNamed(QN_SHOW);
+ if (show == NULL || show->FirstChild() == NULL) {
+ s.set_show(Status::SHOW_ONLINE);
+ }
+ else {
+ if (show->BodyText() == "away") {
+ s.set_show(Status::SHOW_AWAY);
+ }
+ else if (show->BodyText() == "xa") {
+ s.set_show(Status::SHOW_XA);
+ }
+ else if (show->BodyText() == "dnd") {
+ s.set_show(Status::SHOW_DND);
+ }
+ else if (show->BodyText() == "chat") {
+ s.set_show(Status::SHOW_CHAT);
+ }
+ else {
+ s.set_show(Status::SHOW_ONLINE);
+ }
+ }
+
+ const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
+ if (caps != NULL) {
+ std::string node = caps->Attr(QN_NODE);
+ std::string ver = caps->Attr(QN_VER);
+ std::string exts = caps->Attr(QN_EXT);
+
+ s.set_know_capabilities(true);
+
+ if (node == GOOGLE_CLIENT_NODE) {
+ s.set_is_google_client(true);
+ s.set_version(ver);
+ if (ListContainsToken(exts, "voice-v1")) {
+ s.set_phone_capability(true);
+ }
+ }
+ }
+
+ const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
+ if (delay != NULL) {
+ // Ideally we would parse this according to the Psuedo ISO-8601 rules
+ // that are laid out in JEP-0082:
+ // http://www.jabber.org/jeps/jep-0082.html
+ std::string stamp = delay->Attr(kQnStamp);
+ s.set_sent_time(stamp);
+ }
+
+ SignalStatusUpdate(s);
+ }
+
+ return STATE_START;
+}
+
+
+}
+
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h
new file mode 100644
index 00000000..45bc9020
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/presencepushtask.h
@@ -0,0 +1,44 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _PRESENCEPUSHTASK_H_
+#define _PRESENCEPUSHTASK_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/base/sigslot.h"
+#include "talk/examples/call/status.h"
+
+namespace buzz {
+
+class PresencePushTask : public XmppTask {
+
+public:
+ PresencePushTask(Task * parent) : XmppTask(parent, XmppEngine::HL_TYPE) {}
+ virtual int ProcessStart();
+ sigslot::signal1<const Status &>SignalStatusUpdate;
+
+protected:
+ virtual bool HandleStanza(const XmlElement * stanza);
+};
+
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h
new file mode 100644
index 00000000..a1e76f62
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/call/status.h
@@ -0,0 +1,213 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/constants.h"
+
+#define GOOGLE_CLIENT_NODE "http://www.google.com/xmpp/client/caps"
+
+namespace buzz {
+
+class Status {
+public:
+ Status() :
+ pri_(0),
+ show_(SHOW_NONE),
+ available_(false),
+ invisible_(false),
+ e_code_(0),
+ phone_capability_(false),
+ know_capabilities_(false),
+ is_google_client_(false),
+ feedback_probation_(false) {};
+
+ ~Status() {}
+
+ // These are arranged in "priority order", i.e., if we see
+ // two statuses at the same priority but with different Shows,
+ // we will show the one with the highest show in the following
+ // order.
+ enum Show {
+ SHOW_NONE = 0,
+ SHOW_INVISIBLE = 1,
+ SHOW_OFFLINE = 2,
+ SHOW_XA = 3,
+ SHOW_AWAY = 4,
+ SHOW_DND = 5,
+ SHOW_ONLINE = 6,
+ SHOW_CHAT = 7,
+ };
+
+ const Jid & jid() const { return jid_; }
+ int priority() const { return pri_; }
+ Show show() const { return show_; }
+ const std::string & status() const { return status_; }
+ bool available() const { return available_ ; }
+ bool invisible() const { return invisible_; }
+ int error_code() const { return e_code_; }
+ const std::string & error_string() const { return e_str_; }
+ bool know_capabilities() const { return know_capabilities_; }
+ bool phone_capability() const { return phone_capability_; }
+ bool is_google_client() const { return is_google_client_; }
+ const std::string & version() const { return version_; }
+ bool feedback_probation() const { return feedback_probation_; }
+ const std::string& sent_time() const { return sent_time_; }
+
+ void set_jid(const Jid & jid) { jid_ = jid; }
+ void set_priority(int pri) { pri_ = pri; }
+ void set_show(Show show) { show_ = show; }
+ void set_status(const std::string & status) { status_ = status; }
+ void set_available(bool a) { available_ = a; }
+ void set_invisible(bool i) { invisible_ = i; }
+ void set_error(int e_code, const std::string e_str)
+ { e_code_ = e_code; e_str_ = e_str; }
+ void set_know_capabilities(bool f) { know_capabilities_ = f; }
+ void set_phone_capability(bool f) { phone_capability_ = f; }
+ void set_is_google_client(bool f) { is_google_client_ = f; }
+ void set_version(const std::string & v) { version_ = v; }
+ void set_feedback_probation(bool f) { feedback_probation_ = f; }
+ void set_sent_time(const std::string& time) { sent_time_ = time; }
+
+ void UpdateWith(const Status & new_value) {
+ if (!new_value.know_capabilities()) {
+ bool k = know_capabilities();
+ bool i = is_google_client();
+ bool p = phone_capability();
+ std::string v = version();
+
+ *this = new_value;
+
+ set_know_capabilities(k);
+ set_is_google_client(i);
+ set_phone_capability(p);
+ set_version(v);
+ }
+ else {
+ *this = new_value;
+ }
+ }
+
+ bool HasQuietStatus() const {
+ if (status_.empty())
+ return false;
+ return !(QuietStatus().empty());
+ }
+
+ // Knowledge of other clients' silly automatic status strings -
+ // Don't show these.
+ std::string QuietStatus() const {
+ if (jid_.resource().find("Psi") != std::string::npos) {
+ if (status_ == "Online" ||
+ status_.find("Auto Status") != std::string::npos)
+ return STR_EMPTY;
+ }
+ if (jid_.resource().find("Gaim") != std::string::npos) {
+ if (status_ == "Sorry, I ran out for a bit!")
+ return STR_EMPTY;
+ }
+ return TrimStatus(status_);
+ }
+
+ std::string ExplicitStatus() const {
+ std::string result = QuietStatus();
+ if (result.empty()) {
+ result = ShowStatus();
+ }
+ return result;
+ }
+
+ std::string ShowStatus() const {
+ std::string result;
+ if (!available()) {
+ result = "Offline";
+ }
+ else {
+ switch (show()) {
+ case SHOW_AWAY:
+ case SHOW_XA:
+ result = "Idle";
+ break;
+ case SHOW_DND:
+ result = "Busy";
+ break;
+ case SHOW_CHAT:
+ result = "Chatty";
+ break;
+ default:
+ result = "Available";
+ break;
+ }
+ }
+ return result;
+ }
+
+ static std::string TrimStatus(const std::string & st) {
+ std::string s(st);
+ int j = 0;
+ bool collapsing = true;
+ for (unsigned int i = 0; i < s.length(); i+= 1) {
+ if (s[i] <= ' ' && s[i] >= 0) {
+ if (collapsing) {
+ continue;
+ }
+ else {
+ s[j] = ' ';
+ j += 1;
+ collapsing = true;
+ }
+ }
+ else {
+ s[j] = s[i];
+ j += 1;
+ collapsing = false;
+ }
+ }
+ if (collapsing && j > 0) {
+ j -= 1;
+ }
+ s.erase(j, s.length());
+ return s;
+ }
+
+private:
+ Jid jid_;
+ int pri_;
+ Show show_;
+ std::string status_;
+ bool available_;
+ bool invisible_;
+ int e_code_;
+ std::string e_str_;
+ bool feedback_probation_;
+
+ // capabilities (valid only if know_capabilities_
+ bool know_capabilities_;
+ bool phone_capability_;
+ bool is_google_client_;
+ std::string version_;
+
+ std::string sent_time_; // from the jabber:x:delay element
+};
+
+}
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am
new file mode 100644
index 00000000..16164fb7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LTLIBRARIES= libcricketexampleslogin.la
+libcricketexampleslogin_la_SOURCES = xmppsocket.cc \
+ xmppauth.cc \
+ xmppthread.cc \
+ xmpppump.cc
+noinst_HEADERS = xmppauth.h xmpppump.h xmppsocket.h xmppthread.h
+bin_PROGRAMS = login
+login_CXXFLAGS = $(AM_CXXFLAGS)
+login_SOURCES = login_main.cc xmppsocket.cc xmppthread.cc xmpppump.cc xmppauth.cc
+login_LDADD = $(srcdir)/../../../talk/xmpp/libcricketxmpp.la \
+ $(srcdir)/../../../talk/xmllite/libcricketxmllite.la \
+ $(srcdir)/../../../talk/base/libcricketbase.la \
+ $(EXPAT_LIBS) -lpthread
+AM_CPPFLAGS = -DPOSIX
+DEFAULT_INCLUDES = -I$(srcdir)/../../..
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc
new file mode 100644
index 00000000..2939c79f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/login_main.cc
@@ -0,0 +1,63 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/thread.h"
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/examples/login/xmppthread.h"
+#include <iostream>
+
+int main(int argc, char **argv) {
+ printf("Auth Cookie: ");
+ fflush(stdout);
+
+ char auth_cookie[256];
+ scanf("%s", auth_cookie);
+
+ char username[256];
+ scanf("%s", username);
+
+ // Start xmpp on a different thread
+ XmppThread thread;
+ thread.Start();
+
+ buzz::XmppClientSettings xcs;
+ xcs.set_user(username);
+ xcs.set_host("gmail.com");
+ xcs.set_use_tls(false);
+ xcs.set_auth_cookie(auth_cookie);
+ xcs.set_server(cricket::SocketAddress("talk.google.com", 5222));
+ thread.Login(xcs);
+
+ // Use main thread for console input
+ std::string line;
+ while (std::getline(std::cin, line)) {
+ if (line == "quit")
+ break;
+ }
+ return 0;
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc
new file mode 100644
index 00000000..66191f12
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.cc
@@ -0,0 +1,93 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include "talk/examples/login/xmppauth.h"
+#include "talk/xmpp/saslcookiemechanism.h"
+#include "talk/xmpp/saslplainmechanism.h"
+
+XmppAuth::XmppAuth() : done_(false), error_(false) {
+}
+
+XmppAuth::~XmppAuth() {
+}
+
+void XmppAuth::StartPreXmppAuth(const buzz::Jid & jid,
+ const cricket::SocketAddress & server,
+ const buzz::XmppPassword & pass,
+ const std::string & auth_cookie) {
+ jid_ = jid;
+ passwd_ = pass;
+ auth_cookie_ = auth_cookie;
+ error_ = auth_cookie.empty();
+ done_ = true;
+
+ SignalAuthDone();
+}
+
+std::string XmppAuth::ChooseBestSaslMechanism(
+ const std::vector<std::string> & mechanisms,
+ bool encrypted) {
+ std::vector<std::string>::const_iterator it;
+
+ // a token is the weakest auth - 15s, service-limited, so prefer it.
+ it = std::find(mechanisms.begin(), mechanisms.end(), "X-GOOGLE-TOKEN");
+ if (it != mechanisms.end())
+ return "X-GOOGLE-TOKEN";
+
+ // a cookie is the next weakest - 14 days
+ it = std::find(mechanisms.begin(), mechanisms.end(), "X-GOOGLE-COOKIE");
+ if (it != mechanisms.end())
+ return "X-GOOGLE-COOKIE";
+
+ // never pass @google.com passwords without encryption!!
+ if (!encrypted && (jid_.domain() == "google.com"))
+ return "";
+
+ // as a last resort, use plain authentication
+ if (jid_.domain() != "google.com") {
+ it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
+ if (it != mechanisms.end())
+ return "PLAIN";
+ }
+
+ // No good mechanism found
+ return "";
+}
+
+buzz::SaslMechanism* XmppAuth::CreateSaslMechanism(
+ const std::string & mechanism) {
+ if (mechanism == "X-GOOGLE-TOKEN") {
+ return new buzz::SaslCookieMechanism(mechanism, jid_.Str(), auth_cookie_);
+ //} else if (mechanism == "X-GOOGLE-COOKIE") {
+ // return new buzz::SaslCookieMechanism(mechanism, jid.Str(), sid_);
+ } else if (mechanism == "PLAIN") {
+ return new buzz::SaslPlainMechanism(jid_, passwd_);
+ } else {
+ return NULL;
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h
new file mode 100644
index 00000000..57743f90
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppauth.h
@@ -0,0 +1,71 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPAUTH_H_
+#define _XMPPAUTH_H_
+
+#include <vector>
+
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/saslhandler.h"
+#include "talk/xmpp/prexmppauth.h"
+#include "talk/xmpp/xmpppassword.h"
+
+class XmppAuth: public buzz::PreXmppAuth {
+public:
+ XmppAuth();
+ virtual ~XmppAuth();
+
+ virtual void StartPreXmppAuth(const buzz::Jid & jid,
+ const cricket::SocketAddress & server,
+ const buzz::XmppPassword & pass,
+ const std::string & auth_cookie);
+
+ virtual bool IsAuthDone() { return done_; }
+ virtual bool IsAuthorized() { return !error_; }
+ virtual bool HadError() { return error_; }
+ virtual buzz::CaptchaChallenge GetCaptchaChallenge() {
+ return buzz::CaptchaChallenge();
+ }
+ virtual std::string GetAuthCookie() { return auth_cookie_; }
+
+ virtual std::string ChooseBestSaslMechanism(
+ const std::vector<std::string> & mechanisms,
+ bool encrypted);
+
+ virtual buzz::SaslMechanism * CreateSaslMechanism(
+ const std::string & mechanism);
+
+private:
+ buzz::Jid jid_;
+ buzz::XmppPassword passwd_;
+ std::string auth_cookie_;
+ bool done_, error_;
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc
new file mode 100644
index 00000000..7d966fb3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.cc
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/examples/login/xmpppump.h"
+#include "talk/examples/login/xmppauth.h"
+
+XmppPump::XmppPump(XmppPumpNotify * notify) {
+ state_ = buzz::XmppEngine::STATE_NONE;
+ notify_ = notify;
+ client_ = new buzz::XmppClient(this); // NOTE: deleted by TaskRunner
+}
+
+void XmppPump::DoLogin(const buzz::XmppClientSettings & xcs,
+ buzz::AsyncSocket* socket,
+ buzz::PreXmppAuth* auth) {
+ OnStateChange(buzz::XmppEngine::STATE_START);
+ client_->SignalStateChange.connect(this, &XmppPump::OnStateChange);
+ client_->Connect(xcs, socket, auth);
+ client_->Start();
+}
+
+void XmppPump::DoDisconnect() {
+ client_->Disconnect();
+ OnStateChange(buzz::XmppEngine::STATE_CLOSED);
+}
+
+void XmppPump::OnStateChange(buzz::XmppEngine::State state) {
+ if (state_ == state)
+ return;
+ state_ = state;
+ if (notify_ != NULL)
+ notify_->OnStateChange(state);
+}
+
+void XmppPump::WakeTasks() {
+ cricket::Thread::Current()->Post(this);
+}
+
+unsigned long long XmppPump::CurrentTime() {
+ return cricket::Time();
+}
+
+void XmppPump::OnMessage(cricket::Message *pmsg) {
+ RunTasks();
+}
+
+buzz::XmppReturnStatus XmppPump::SendStanza(const buzz::XmlElement *stanza) {
+ return client_->SendStanza(stanza);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h
new file mode 100644
index 00000000..fd6f88bb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmpppump.h
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPPUMP_H_
+#define _XMPPPUMP_H_
+
+#include "talk/base/messagequeue.h"
+#include "talk/base/taskrunner.h"
+#include "talk/base/thread.h"
+#include "talk/base/jtime.h"
+#include "talk/xmpp/xmppclient.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+
+// Simple xmpp pump
+
+class XmppPumpNotify {
+public:
+ virtual void OnStateChange(buzz::XmppEngine::State state) = 0;
+};
+
+class XmppPump : public cricket::MessageHandler, public buzz::TaskRunner {
+public:
+ XmppPump(XmppPumpNotify * notify = NULL);
+
+ buzz::XmppClient *client() { return client_; }
+
+ void DoLogin(const buzz::XmppClientSettings & xcs,
+ buzz::AsyncSocket* socket,
+ buzz::PreXmppAuth* auth);
+ void DoDisconnect();
+
+ void OnStateChange(buzz::XmppEngine::State state);
+
+ void WakeTasks();
+
+ unsigned long long CurrentTime();
+
+ void OnMessage(cricket::Message *pmsg);
+
+ buzz::XmppReturnStatus SendStanza(const buzz::XmlElement *stanza);
+
+private:
+ buzz::XmppClient *client_;
+ buzz::XmppEngine::State state_;
+ XmppPumpNotify *notify_;
+};
+
+#endif // _XMPPPUMP_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc
new file mode 100644
index 00000000..33aabf3e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.cc
@@ -0,0 +1,144 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include "talk/base/basicdefs.h"
+#include "talk/base/logging.h"
+#include "talk/base/thread.h"
+#ifdef FEATURE_ENABLE_SSL
+#include "talk/base/schanneladapter.h"
+#endif
+#include "xmppsocket.h"
+
+XmppSocket::XmppSocket(bool tls) : tls_(tls) {
+ cricket::Thread* pth = cricket::Thread::Current();
+ cricket::AsyncSocket* socket =
+ pth->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+#ifdef FEATURE_ENABLE_SSL
+ if (tls_)
+ socket = new cricket::SChannelAdapter(socket);
+#endif
+ cricket_socket_ = socket;
+ cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent);
+ cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent);
+ cricket_socket_->SignalConnectEvent.connect(this,
+ &XmppSocket::OnConnectEvent);
+ state_ = buzz::AsyncSocket::STATE_CLOSED;
+}
+
+XmppSocket::~XmppSocket() {
+ Close();
+ delete cricket_socket_;
+}
+
+void XmppSocket::OnReadEvent(cricket::AsyncSocket * socket) {
+ SignalRead();
+}
+
+void XmppSocket::OnWriteEvent(cricket::AsyncSocket * socket) {
+ // Write bytes if there are any
+ while (buffer_.Length() != 0) {
+ int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length());
+ if (written > 0) {
+ buffer_.Shift(written);
+ continue;
+ }
+ if (!cricket_socket_->IsBlocking())
+ LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError();
+ return;
+ }
+}
+
+void XmppSocket::OnConnectEvent(cricket::AsyncSocket * socket) {
+#if defined(FEATURE_ENABLE_SSL)
+ if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) {
+ state_ = buzz::AsyncSocket::STATE_TLS_OPEN;
+ SignalSSLConnected();
+ OnWriteEvent(cricket_socket_);
+ return;
+ }
+#endif // !defined(FEATURE_ENABLE_SSL)
+ state_ = buzz::AsyncSocket::STATE_OPEN;
+ SignalConnected();
+}
+
+buzz::AsyncSocket::State XmppSocket::state() {
+ return state_;
+}
+
+buzz::AsyncSocket::Error XmppSocket::error() {
+ return buzz::AsyncSocket::ERROR_NONE;
+}
+
+bool XmppSocket::Connect(const cricket::SocketAddress& addr) {
+ if (cricket_socket_->Connect(addr) < 0) {
+ return cricket_socket_->IsBlocking();
+ }
+ return true;
+}
+
+bool XmppSocket::Read(char * data, size_t len, size_t* len_read) {
+ int read = cricket_socket_->Recv(data, len);
+ if (read > 0) {
+ *len_read = (size_t)read;
+ return true;
+ }
+ return false;
+}
+
+bool XmppSocket::Write(const char * data, size_t len) {
+ buffer_.WriteBytes(data, len);
+ OnWriteEvent(cricket_socket_);
+ return true;
+}
+
+bool XmppSocket::Close() {
+ if (state_ != buzz::AsyncSocket::STATE_OPEN)
+ return false;
+ if (cricket_socket_->Close() == 0) {
+ state_ = buzz::AsyncSocket::STATE_CLOSED;
+ SignalClosed();
+ return true;
+ }
+ return false;
+}
+
+bool XmppSocket::StartTls(const std::string & domainname) {
+#if defined(FEATURE_ENABLE_SSL)
+ if (!tls_)
+ return false;
+ cricket::SChannelAdapter * ssl =
+ static_cast<cricket::SChannelAdapter *>(cricket_socket_);
+ ssl->set_ignore_bad_cert(true);
+ if (ssl->StartSSL(domainname.c_str(), false) != 0)
+ return false;
+ state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING;
+ return true;
+#else // !defined(FEATURE_ENABLE_SSL)
+ return false;
+#endif // !defined(FEATURE_ENABLE_SSL)
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h
new file mode 100644
index 00000000..f6c53d7d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppsocket.h
@@ -0,0 +1,63 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPSOCKET_H_
+#define _XMPPSOCKET_H_
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/bytebuffer.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/asyncsocket.h"
+
+extern cricket::AsyncSocket* cricket_socket_;
+
+class XmppSocket : public buzz::AsyncSocket, public sigslot::has_slots<> {
+public:
+ XmppSocket(bool tls);
+ ~XmppSocket();
+
+ virtual buzz::AsyncSocket::State state();
+ virtual buzz::AsyncSocket::Error error();
+
+ virtual bool Connect(const cricket::SocketAddress& addr);
+ virtual bool Read(char * data, size_t len, size_t* len_read);
+ virtual bool Write(const char * data, size_t len);
+ virtual bool Close();
+ virtual bool StartTls(const std::string & domainname);
+
+private:
+ void OnReadEvent(cricket::AsyncSocket * socket);
+ void OnWriteEvent(cricket::AsyncSocket * socket);
+ void OnConnectEvent(cricket::AsyncSocket * socket);
+
+ cricket::AsyncSocket * cricket_socket_;
+ buzz::AsyncSocket::State state_;
+ cricket::ByteBuffer buffer_;
+ bool tls_;
+};
+
+#endif // _XMPPSOCKET_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc
new file mode 100644
index 00000000..7a1b2a13
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.cc
@@ -0,0 +1,80 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/examples/login/xmppthread.h"
+#include "talk/examples/login/xmppauth.h"
+
+namespace {
+
+const uint32 MSG_LOGIN = 1;
+const uint32 MSG_DISCONNECT = 2;
+
+struct LoginData: public cricket::MessageData {
+ LoginData(const buzz::XmppClientSettings& s) : xcs(s) {}
+ virtual ~LoginData() {}
+
+ buzz::XmppClientSettings xcs;
+};
+
+} // namespace
+
+XmppThread::XmppThread() {
+ pump_ = new XmppPump(this);
+}
+
+XmppThread::~XmppThread() {
+ delete pump_;
+}
+
+void XmppThread::Loop(int cms) {
+ Thread::Loop(cms);
+}
+
+void XmppThread::Login(const buzz::XmppClientSettings& xcs) {
+ Post(this, MSG_LOGIN, new LoginData(xcs));
+}
+
+void XmppThread::Disconnect() {
+ Post(this, MSG_DISCONNECT);
+}
+
+void XmppThread::OnStateChange(buzz::XmppEngine::State state) {
+}
+
+void XmppThread::OnMessage(cricket::Message* pmsg) {
+ if (pmsg->message_id == MSG_LOGIN) {
+ assert(pmsg->pdata);
+ LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata);
+ pump_->DoLogin(data->xcs, new XmppSocket(false), new XmppAuth());
+ delete data;
+ } else if (pmsg->message_id == MSG_DISCONNECT) {
+ pump_->DoDisconnect();
+ } else {
+ assert(false);
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h
new file mode 100644
index 00000000..533a2376
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/examples/login/xmppthread.h
@@ -0,0 +1,57 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPTHREAD_H_
+#define _XMPPTHREAD_H_
+
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/base/thread.h"
+#include "talk/examples/login/xmpppump.h"
+#include "talk/examples/login/xmppsocket.h"
+#include <iostream>
+
+class XmppThread:
+ public cricket::Thread, XmppPumpNotify, cricket::MessageHandler {
+public:
+ XmppThread();
+ ~XmppThread();
+
+ buzz::XmppClient* client() { return pump_->client(); }
+
+ void Loop(int cms);
+
+ void Login(const buzz::XmppClientSettings & xcs);
+ void Disconnect();
+
+private:
+ XmppPump* pump_;
+
+ void OnStateChange(buzz::XmppEngine::State state);
+ void OnMessage(cricket::Message* pmsg);
+};
+
+#endif // _XMPPTHREAD_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am
new file mode 100644
index 00000000..c935a6bd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=base client
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am
new file mode 100644
index 00000000..6cc30f15
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/Makefile.am
@@ -0,0 +1,47 @@
+## Does not compile with final
+KDE_OPTIONS = nofinal
+
+libcricketp2pbase_la_SOURCES = stun.cc \
+ port.cc \
+ udpport.cc \
+ tcpport.cc \
+ helpers.cc \
+ sessionmanager.cc \
+ session.cc \
+ p2psocket.cc \
+ relayport.cc \
+ stunrequest.cc \
+ stunport.cc \
+ socketmanager.cc
+
+noinst_HEADERS = candidate.h \
+ portallocator.h \
+ relayport.h \
+ session.h \
+ sessionmessage.h \
+ stunport.h \
+ tcpport.h \
+ helpers.h \
+ port.h \
+ sessionid.h \
+ socketmanager.h \
+ stunrequest.h \
+ udpport.h \
+ p2psocket.h \
+ sessiondescription.h \
+ sessionmanager.h \
+ stun.h \
+ relayserver.h \
+ stunserver.h
+
+AM_CPPFLAGS = -DPOSIX $(all_includes) -I$(srcdir)/../../..
+
+bin_PROGRAMS = relayserver stunserver
+relayserver_SOURCES = relayserver.cc relayserver_main.cc
+relayserver_LDADD = ../../base/libcricketbase.la libcricketp2pbase.la -lpthread
+stunserver_SOURCES = stunserver.cc stunserver_main.cc
+stunserver_LDADD = ../../base/libcricketbase.la libcricketp2pbase.la -lpthread
+
+noinst_LTLIBRARIES = libcricketp2pbase.la
+
+DEFAULT_INCLUDES = -I$(srcdir)/../../..
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h
new file mode 100644
index 00000000..c2f974b8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/candidate.h
@@ -0,0 +1,118 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CANDIDATE_H_
+#define _CANDIDATE_H_
+
+#include <string>
+#include <sstream>
+#include "talk/base/socketaddress.h"
+
+namespace cricket {
+
+// Candidate for ICE based connection discovery.
+
+class Candidate {
+public:
+
+ const std::string & name() const { return name_; }
+ void set_name(const std::string & name) { name_ = name; }
+
+ const std::string & protocol() const { return protocol_; }
+ void set_protocol(const std::string & protocol) { protocol_ = protocol; }
+
+ const SocketAddress & address() const { return address_; }
+ void set_address(const SocketAddress & address) { address_ = address; }
+
+ const float preference() const { return preference_; }
+ void set_preference(const float preference) { preference_ = preference; }
+ const std::string preference_str() const {
+ std::ostringstream ost;
+ ost << preference_;
+ return ost.str();
+ }
+ void set_preference_str(const std::string & preference) {
+ std::istringstream ist(preference);
+ ist >> preference_;
+ }
+
+ const std::string & username() const { return username_; }
+ void set_username(const std::string & username) { username_ = username; }
+
+ const std::string & password() const { return password_; }
+ void set_password(const std::string & password) { password_ = password; }
+
+ const std::string & type() const { return type_; }
+ void set_type(const std::string & type) { type_ = type; }
+
+ const std::string & network_name() const { return network_name_; }
+ void set_network_name(const std::string & network_name) {
+ network_name_ = network_name;
+ }
+
+ // Candidates in a new generation replace those in the old generation.
+ uint32 generation() const { return generation_; }
+ void set_generation(uint32 generation) { generation_ = generation; }
+ const std::string generation_str() const {
+ std::ostringstream ost;
+ ost << generation_;
+ return ost.str();
+ }
+ void set_generation_str(const std::string& str) {
+ std::istringstream ist(str);
+ ist >> generation_;
+ }
+
+ // Determines whether this candidate is equivalent to the given one.
+ bool IsEquivalent(const Candidate& c) const {
+ // We ignore the network name, since that is just debug information, and
+ // the preference, since that should be the same if the rest is (and it's
+ // a float so equality checking is always worrisome).
+ return (name_ == c.name_) &&
+ (protocol_ == c.protocol_) &&
+ (address_ == c.address_) &&
+ (username_ == c.username_) &&
+ (password_ == c.password_) &&
+ (type_ == c.type_) &&
+ (generation_ == c.generation_);
+ }
+
+private:
+ std::string name_;
+ std::string protocol_;
+ SocketAddress address_;
+ float preference_;
+ std::string username_;
+ std::string password_;
+ std::string type_;
+ std::string network_name_;
+ uint32 generation_;
+};
+
+} // namespace cricket
+
+#endif // _CANDIDATE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc
new file mode 100644
index 00000000..83e02a27
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.cc
@@ -0,0 +1,129 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/p2p/base/helpers.h"
+#include "talk/base/jtime.h"
+#include <cstdlib>
+#include <cassert>
+
+// TODO: Change this implementation to use OpenSSL's RAND_bytes. That will
+// give cryptographically random values on all platforms.
+
+#ifdef WIN32
+#include <time.h>
+#include <windows.h>
+#endif
+
+namespace cricket {
+
+static long g_seed = 1L;
+
+int GetRandom() {
+ return ((g_seed = g_seed * 214013L + 2531011L) >> 16) & 0x7fff;
+}
+
+void SetRandomSeed(unsigned long seed)
+{
+ g_seed = (long)seed;
+}
+
+static bool s_initrandom;
+
+void InitRandom(const char *client_unique, size_t len) {
+ s_initrandom = true;
+
+ // Hash this string - unique per client
+
+ uint32 hash = 0;
+ if (client_unique != NULL) {
+ for (int i = 0; i < (int)len; i++)
+ hash = ((hash << 2) + hash) + client_unique[i];
+ }
+
+ // Now initialize the seed against a high resolution
+ // counter
+
+#ifdef WIN32
+ LARGE_INTEGER big;
+ QueryPerformanceCounter(&big);
+ SetRandomSeed(big.LowPart ^ hash);
+#else
+ SetRandomSeed(Time() ^ hash);
+#endif
+}
+
+const char BASE64[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+// Generates a random string of the given length. We generate base64 values so
+// that they will be printable, though that's not necessary.
+
+std::string CreateRandomString(int len) {
+ // Random number generator should of been initialized!
+ assert(s_initrandom);
+ if (!s_initrandom)
+ InitRandom(0, 0);
+
+ std::string str;
+ for (int i = 0; i < len; i++)
+#if defined(_MSC_VER) && _MSC_VER < 1300
+ str.insert(str.end(), BASE64[GetRandom() & 63]);
+#else
+ str.push_back(BASE64[GetRandom() & 63]);
+#endif
+ return str;
+}
+
+uint32 CreateRandomId() {
+ uint8 b1 = (uint8)(GetRandom() & 255);
+ uint8 b2 = (uint8)(GetRandom() & 255);
+ uint8 b3 = (uint8)(GetRandom() & 255);
+ uint8 b4 = (uint8)(GetRandom() & 255);
+ return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+}
+
+bool IsBase64Char(char ch) {
+ return (('A' <= ch) && (ch <= 'Z')) ||
+ (('a' <= ch) && (ch <= 'z')) ||
+ (('0' <= ch) && (ch <= '9')) ||
+ (ch == '+') || (ch == '/');
+}
+
+bool IsBase64Encoded(const std::string& str) {
+ for (size_t i = 0; i < str.size(); ++i) {
+ if (!IsBase64Char(str.at(i)))
+ return false;
+ }
+ return true;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h
new file mode 100644
index 00000000..1c8dfa7f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/helpers.h
@@ -0,0 +1,51 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HELPERS_H__
+#define __HELPERS_H__
+
+#include "talk/base/basictypes.h"
+#include <string>
+
+namespace cricket {
+
+// srand initializer
+void InitRandom(const char *client_unique, size_t len);
+
+// Generates a (cryptographically) random string of the given length.
+std::string CreateRandomString(int length);
+
+// Generates a random id
+uint32 CreateRandomId();
+
+// Determines whether the given string consists entirely of valid base64
+// encoded characters.
+bool IsBase64Encoded(const std::string& str);
+
+} // namespace cricket
+
+#endif // __HELPERS_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc
new file mode 100644
index 00000000..eb53efeb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.cc
@@ -0,0 +1,910 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Description of the P2PSocket class in P2PSocket.h
+//
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include <iostream>
+#include <cassert>
+#include "talk/base/logging.h"
+#include "talk/p2p/base/p2psocket.h"
+#include <errno.h>
+namespace {
+
+// messages for queuing up work for ourselves
+const uint32 MSG_SORT = 1;
+const uint32 MSG_PING = 2;
+const uint32 MSG_ALLOCATE = 3;
+
+// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
+// for pinging. When the socket is writable, we will use only 1 Kbps because
+// we don't want to degrade the quality on a modem. These numbers should work
+// well on a 28.8K modem, which is the slowest connection on which the voice
+// quality is reasonable at all.
+static const uint32 PING_PACKET_SIZE = 60 * 8;
+static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000; // 480ms
+static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000;// 50ms
+
+// If there is a current writable connection, then we will also try hard to
+// make sure it is pinged at this rate.
+static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900; // 2*WRITABLE_DELAY - bit
+
+// The minimum improvement in MOS that justifies a switch.
+static const double kMinImprovement = 10;
+
+// Amount of time that we wait when *losing* writability before we try doing
+// another allocation.
+static const int kAllocateDelay = 1 * 1000; // 1 second
+
+// We will try creating a new allocator from scratch after a delay of this
+// length without becoming writable (or timing out).
+static const int kAllocatePeriod = 20 * 1000; // 20 seconds
+
+cricket::Port::CandidateOrigin GetOrigin(cricket::Port* port,
+ cricket::Port* origin_port) {
+ if (!origin_port)
+ return cricket::Port::ORIGIN_MESSAGE;
+ else if (port == origin_port)
+ return cricket::Port::ORIGIN_THIS_PORT;
+ else
+ return cricket::Port::ORIGIN_OTHER_PORT;
+}
+
+// Compares two connections based only on static information about them.
+int CompareConnectionCandidates(cricket::Connection* a,
+ cricket::Connection* b) {
+ // Combine local and remote preferences
+ assert(a->local_candidate().preference() == a->port()->preference());
+ assert(b->local_candidate().preference() == b->port()->preference());
+ double a_pref = a->local_candidate().preference()
+ * a->remote_candidate().preference();
+ double b_pref = b->local_candidate().preference()
+ * b->remote_candidate().preference();
+
+ // Now check combined preferences. Lower values get sorted last.
+ if (a_pref > b_pref)
+ return 1;
+ if (a_pref < b_pref)
+ return -1;
+
+ return 0;
+}
+
+// Compare two connections based on their writability and static preferences.
+int CompareConnections(cricket::Connection *a, cricket::Connection *b) {
+ // Sort based on write-state. Better states have lower values.
+ if (a->write_state() < b->write_state())
+ return 1;
+ if (a->write_state() > b->write_state())
+ return -1;
+
+ // Compare the candidate information.
+ return CompareConnectionCandidates(a, b);
+}
+
+// Wraps the comparison connection into a less than operator that puts higher
+// priority writable connections first.
+class ConnectionCompare {
+public:
+ bool operator()(const cricket::Connection *ca,
+ const cricket::Connection *cb) {
+ cricket::Connection* a = const_cast<cricket::Connection*>(ca);
+ cricket::Connection* b = const_cast<cricket::Connection*>(cb);
+
+ // Compare first on writability and static preferences.
+ int cmp = CompareConnections(a, b);
+ if (cmp > 0)
+ return true;
+ if (cmp < 0)
+ return false;
+
+ // Otherwise, sort based on latency estimate.
+ return a->rtt() < b->rtt();
+
+ // Should we bother checking for the last connection that last received
+ // data? It would help rendezvous on the connection that is also receiving
+ // packets.
+ //
+ // TODO: Yes we should definitely do this. The TCP protocol gains
+ // efficiency by being used bidirectionally, as opposed to two separate
+ // unidirectional streams. This test should probably occur before
+ // comparison of local prefs (assuming combined prefs are the same). We
+ // need to be careful though, not to bounce back and forth with both sides
+ // trying to rendevous with the other.
+ }
+};
+
+// Determines whether we should switch between two connections, based first on
+// static preferences and then (if those are equal) on latency estimates.
+bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
+ if (a_conn == b_conn)
+ return false;
+
+ if ((a_conn == NULL) || (b_conn == NULL)) // don't think the latter should happen
+ return true;
+
+ int prefs_cmp = CompareConnections(a_conn, b_conn);
+ if (prefs_cmp < 0)
+ return true;
+ if (prefs_cmp > 0)
+ return false;
+
+ return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
+}
+
+} // unnamed namespace
+
+namespace cricket {
+
+P2PSocket::P2PSocket(const std::string &name, PortAllocator *allocator)
+: worker_thread_(Thread::Current()), name_(name), allocator_(allocator),
+ error_(0), state_(STATE_CONNECTING), waiting_for_signaling_(false),
+ best_connection_(NULL), pinging_started_(false), sort_dirty_(false),
+ was_writable_(false), was_timed_out_(true) {
+}
+
+P2PSocket::~P2PSocket() {
+ assert(worker_thread_ == Thread::Current());
+
+ thread()->Clear(this);
+
+ for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
+ delete allocator_sessions_[i];
+}
+
+// Add the allocator session to our list so that we know which sessions
+// are still active.
+void P2PSocket::AddAllocatorSession(PortAllocatorSession* session) {
+ session->set_generation(static_cast<uint32>(allocator_sessions_.size()));
+ allocator_sessions_.push_back(session);
+
+ // We now only want to apply new candidates that we receive to the ports
+ // created by this new session because these are replacing those of the
+ // previous sessions.
+ ports_.clear();
+
+ session->SignalPortReady.connect(this, &P2PSocket::OnPortReady);
+ session->SignalCandidatesReady.connect(this, &P2PSocket::OnCandidatesReady);
+ session->GetInitialPorts();
+ if (pinging_started_)
+ session->StartGetAllPorts();
+}
+
+// Go into the state of processing candidates, and running in general
+void P2PSocket::StartProcessingCandidates() {
+ assert(worker_thread_ == Thread::Current());
+
+ // Kick off an allocator session
+ OnAllocate();
+
+ // Start pinging as the ports come in.
+ thread()->Post(this, MSG_PING);
+}
+
+// Reset the socket, clear up any previous allocations and start over
+void P2PSocket::Reset() {
+ assert(worker_thread_ == Thread::Current());
+
+ // Get rid of all the old allocators. This should clean up everything.
+ for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
+ delete allocator_sessions_[i];
+
+ allocator_sessions_.clear();
+ ports_.clear();
+ connections_.clear();
+ best_connection_ = NULL;
+
+ // Forget about all of the candidates we got before.
+ remote_candidates_.clear();
+
+ // Revert to the connecting state.
+ set_state(STATE_CONNECTING);
+
+ // Reinitialize the rest of our state.
+ waiting_for_signaling_ = false;
+ pinging_started_ = false;
+ sort_dirty_ = false;
+ was_writable_ = false;
+ was_timed_out_ = true;
+
+ // Start a new allocator.
+ OnAllocate();
+
+ // Start pinging as the ports come in.
+ thread()->Clear(this);
+ thread()->Post(this, MSG_PING);
+}
+
+// A new port is available, attempt to make connections for it
+void P2PSocket::OnPortReady(PortAllocatorSession *session, Port* port) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Set in-effect options on the new port
+ for (OptionMap::const_iterator it = options_.begin(); it != options_.end(); ++it) {
+ int val = port->SetOption(it->first, it->second);
+ if (val < 0) {
+ LOG(WARNING) << "SetOption(" << it->first << ", " << it->second << ") failed: " << port->GetError();
+ }
+ }
+
+ // Remember the ports and candidates, and signal that candidates are ready.
+ // The session will handle this, and send an initiate/accept/modify message
+ // if one is pending.
+
+ ports_.push_back(port);
+ port->SignalUnknownAddress.connect(this, &P2PSocket::OnUnknownAddress);
+ port->SignalDestroyed.connect(this, &P2PSocket::OnPortDestroyed);
+
+ // Attempt to create a connection from this new port to all of the remote
+ // candidates that we were given so far.
+
+ std::vector<RemoteCandidate>::iterator iter;
+ for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
+ ++iter)
+ CreateConnection(port, *iter, iter->origin_port(), false);
+
+ SortConnections();
+}
+
+// A new candidate is available, let listeners know
+void P2PSocket::OnCandidatesReady(PortAllocatorSession *session,
+ const std::vector<Candidate>& candidates) {
+ SignalCandidatesReady(this, candidates);
+}
+
+// Handle stun packets
+void P2PSocket::OnUnknownAddress(Port *port,
+ const SocketAddress &address,
+ StunMessage *stun_msg,
+ const std::string &remote_username) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Port has received a valid stun packet from an address that no Connection
+ // is currently available for. See if the remote user name is in the remote
+ // candidate list. If it isn't return error to the stun request.
+
+ const Candidate *candidate = NULL;
+ std::vector<RemoteCandidate>::iterator it;
+ for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
+ if ((*it).username() == remote_username) {
+ candidate = &(*it);
+ break;
+ }
+ }
+ if (candidate == NULL) {
+ // Don't know about this username, the request is bogus
+ // This sometimes happens if a binding response comes in before the ACCEPT
+ // message. It is totally valid; the retry state machine will try again.
+
+ port->SendBindingErrorResponse(stun_msg, address,
+ STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS);
+ delete stun_msg;
+ return;
+ }
+
+ // Check for connectivity to this address. Create connections
+ // to this address across all local ports. First, add this as a new remote
+ // address
+
+ Candidate new_remote_candidate = *candidate;
+ new_remote_candidate.set_address(address);
+ //new_remote_candidate.set_protocol(port->protocol());
+
+ // This remote username exists. Now create connections using this candidate,
+ // and resort
+
+ if (CreateConnections(new_remote_candidate, port, true)) {
+ // Send the pinger a successful stun response.
+ port->SendBindingResponse(stun_msg, address);
+
+ // Update the list of connections since we just added another. We do this
+ // after sending the response since it could (in principle) delete the
+ // connection in question.
+ SortConnections();
+ } else {
+ // Hopefully this won't occur, because changing a destination address
+ // shouldn't cause a new connection to fail
+ assert(false);
+ port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
+ STUN_ERROR_REASON_SERVER_ERROR);
+ }
+
+ delete stun_msg;
+}
+
+// We received a candidate from the other side, make connections so we
+// can try to use these remote candidates with our local candidates.
+void P2PSocket::AddRemoteCandidates(
+ const std::vector<Candidate> &remote_candidates) {
+ assert(worker_thread_ == Thread::Current());
+
+ // The remote candidates have come in. Remember them and start to establish
+ // connections
+
+ std::vector<Candidate>::const_iterator it;
+ for (it = remote_candidates.begin(); it != remote_candidates.end(); ++it)
+ CreateConnections(*it, NULL, false);
+
+ // Resort the connections
+
+ SortConnections();
+}
+
+// Creates connections from all of the ports that we care about to the given
+// remote candidate. The return value is true iff we created a connection from
+// the origin port.
+bool P2PSocket::CreateConnections(const Candidate &remote_candidate,
+ Port* origin_port,
+ bool readable) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Add a new connection for this candidate to every port that allows such a
+ // connection (i.e., if they have compatible protocols) and that does not
+ // already have a connection to an equivalent candidate. We must be careful
+ // to make sure that the origin port is included, even if it was pruned,
+ // since that may be the only port that can create this connection.
+
+ bool created = false;
+
+ std::vector<Port *>::reverse_iterator it;
+ for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
+ if (CreateConnection(*it, remote_candidate, origin_port, readable)) {
+ if (*it == origin_port)
+ created = true;
+ }
+ }
+
+ if ((origin_port != NULL) &&
+ find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
+ if (CreateConnection(origin_port, remote_candidate, origin_port, readable))
+ created = true;
+ }
+
+ // Remember this remote candidate so that we can add it to future ports.
+ RememberRemoteCandidate(remote_candidate, origin_port);
+
+ return created;
+}
+
+// Setup a connection object for the local and remote candidate combination.
+// And then listen to connection object for changes.
+bool P2PSocket::CreateConnection(Port* port,
+ const Candidate& remote_candidate,
+ Port* origin_port,
+ bool readable) {
+ // Look for an existing connection with this remote address. If one is not
+ // found, then we can create a new connection for this address.
+ Connection* connection = port->GetConnection(remote_candidate.address());
+ if (connection != NULL) {
+ // It is not legal to try to change any of the parameters of an existing
+ // connection; however, the other side can send a duplicate candidate.
+ if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
+ LOG(INFO) << "Attempt to change a remote candidate";
+ return false;
+ }
+ } else {
+ Port::CandidateOrigin origin = GetOrigin(port, origin_port);
+ connection = port->CreateConnection(remote_candidate, origin);
+ if (!connection)
+ return false;
+
+ connections_.push_back(connection);
+ connection->SignalReadPacket.connect(this, &P2PSocket::OnReadPacket);
+ connection->SignalStateChange.connect(this, &P2PSocket::OnConnectionStateChange);
+ connection->SignalDestroyed.connect(this, &P2PSocket::OnConnectionDestroyed);
+ }
+
+ // If we are readable, it is because we are creating this in response to a
+ // ping from the other side. This will cause the state to become readable.
+ if (readable)
+ connection->ReceivedPing();
+
+ return true;
+}
+
+// Maintain our remote candidate list, adding this new remote one.
+void P2PSocket::RememberRemoteCandidate(const Candidate& remote_candidate,
+ Port* origin_port) {
+ // Remove any candidates whose generation is older than this one. The
+ // presence of a new generation indicates that the old ones are not useful.
+ uint32 i = 0;
+ while (i < remote_candidates_.size()) {
+ if (remote_candidates_[i].generation() < remote_candidate.generation()) {
+ remote_candidates_.erase(remote_candidates_.begin() + i);
+ LOG(INFO) << "Pruning candidate from old generation: "
+ << remote_candidates_[i].address().ToString();
+
+ } else {
+ i += 1;
+ }
+ }
+
+ // Make sure this candidate is not a duplicate.
+ for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
+ if (remote_candidates_[i].IsEquivalent(remote_candidate)) {
+ LOG(INFO) << "Duplicate candidate: "
+ << remote_candidate.address().ToString();
+ return;
+ }
+ }
+
+ // Try this candidate for all future ports.
+ remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
+
+ // We have some candidates from the other side, we are now serious about
+ // this connection. Let's do the StartGetAllPorts thing.
+ if (!pinging_started_) {
+ pinging_started_ = true;
+ for (size_t i = 0; i < allocator_sessions_.size(); ++i) {
+ if (!allocator_sessions_[i]->IsGettingAllPorts())
+ allocator_sessions_[i]->StartGetAllPorts();
+ }
+ }
+}
+
+// Send data to the other side, using our best connection
+int P2PSocket::Send(const char *data, size_t len) {
+ // This can get called on any thread that is convenient to write from!
+ if (best_connection_ == NULL) {
+ error_ = EWOULDBLOCK;
+ return SOCKET_ERROR;
+ }
+ int sent = best_connection_->Send(data, len);
+ if (sent <= 0) {
+ assert(sent < 0);
+ error_ = best_connection_->GetError();
+ }
+ return sent;
+}
+
+// Monitor connection states
+void P2PSocket::UpdateConnectionStates() {
+ uint32 now = Time();
+
+ // We need to copy the list of connections since some may delete themselves
+ // when we call UpdateState.
+ for (uint32 i = 0; i < connections_.size(); ++i)
+ connections_[i]->UpdateState(now);
+}
+
+// Prepare for best candidate sorting
+void P2PSocket::RequestSort() {
+ if (!sort_dirty_) {
+ worker_thread_->Post(this, MSG_SORT);
+ sort_dirty_ = true;
+ }
+}
+
+// Sort the available connections to find the best one. We also monitor
+// the number of available connections and the current state so that we
+// can possibly kick off more allocators (for more connections).
+void P2PSocket::SortConnections() {
+ assert(worker_thread_ == Thread::Current());
+
+ // Make sure the connection states are up-to-date since this affects how they
+ // will be sorted.
+ UpdateConnectionStates();
+
+ // Any changes after this point will require a re-sort.
+ sort_dirty_ = false;
+
+ // Get a list of the networks that we are using.
+ std::set<Network*> networks;
+ for (uint32 i = 0; i < connections_.size(); ++i)
+ networks.insert(connections_[i]->port()->network());
+
+ // Find the best alternative connection by sorting. It is important to note
+ // that amongst equal preference, writable connections, this will choose the
+ // one whose estimated latency is lowest. So it is the only one that we
+ // need to consider switching to.
+
+ ConnectionCompare cmp;
+ std::stable_sort(connections_.begin(), connections_.end(), cmp);
+ Connection* top_connection = NULL;
+ if (connections_.size() > 0)
+ top_connection = connections_[0];
+
+ // If necessary, switch to the new choice.
+ if (ShouldSwitch(best_connection_, top_connection))
+ SwitchBestConnectionTo(top_connection);
+
+ // We can prune any connection for which there is a writable connection on
+ // the same network with better or equal prefences. We leave those with
+ // better preference just in case they become writable later (at which point,
+ // we would prune out the current best connection). We leave connections on
+ // other networks because they may not be using the same resources and they
+ // may represent very distinct paths over which we can switch.
+ std::set<Network*>::iterator network;
+ for (network = networks.begin(); network != networks.end(); ++network) {
+ Connection* primier = GetBestConnectionOnNetwork(*network);
+ if (!primier || (primier->write_state() != Connection::STATE_WRITABLE))
+ continue;
+
+ for (uint32 i = 0; i < connections_.size(); ++i) {
+ if ((connections_[i] != primier) &&
+ (connections_[i]->port()->network() == *network) &&
+ (CompareConnectionCandidates(primier, connections_[i]) >= 0)) {
+ connections_[i]->Prune();
+ }
+ }
+ }
+
+ // Count the number of connections in the various states.
+
+ int writable = 0;
+ int write_connect = 0;
+ int write_timeout = 0;
+
+ for (uint32 i = 0; i < connections_.size(); ++i) {
+ switch (connections_[i]->write_state()) {
+ case Connection::STATE_WRITABLE:
+ ++writable;
+ break;
+ case Connection::STATE_WRITE_CONNECT:
+ ++write_connect;
+ break;
+ case Connection::STATE_WRITE_TIMEOUT:
+ ++write_timeout;
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ if (writable > 0) {
+ HandleWritable();
+ } else if (write_connect > 0) {
+ HandleNotWritable();
+ } else {
+ HandleAllTimedOut();
+ }
+
+ // Notify of connection state change
+ SignalConnectionMonitor(this);
+}
+
+// Track the best connection, and let listeners know
+void P2PSocket::SwitchBestConnectionTo(Connection* conn) {
+ best_connection_ = conn;
+ if (best_connection_)
+ SignalConnectionChanged(this,
+ best_connection_->remote_candidate().address());
+}
+
+// We checked the status of our connections and we had at least one that
+// was writable, go into the writable state.
+void P2PSocket::HandleWritable() {
+ //
+ // One or more connections writable!
+ //
+ if (state_ != STATE_WRITABLE) {
+ for (uint32 i = 0; i < allocator_sessions_.size(); ++i) {
+ if (allocator_sessions_[i]->IsGettingAllPorts()) {
+ allocator_sessions_[i]->StopGetAllPorts();
+ }
+ }
+
+ // Stop further allocations.
+ thread()->Clear(this, MSG_ALLOCATE);
+ }
+
+ // We're writable, obviously we aren't timed out
+ was_writable_ = true;
+ was_timed_out_ = false;
+ set_state(STATE_WRITABLE);
+}
+
+// We checked the status of our connections and we didn't have any that
+// were writable, go into the connecting state (kick off a new allocator
+// session).
+void P2PSocket::HandleNotWritable() {
+ //
+ // No connections are writable but not timed out!
+ //
+ if (was_writable_) {
+ // If we were writable, let's kick off an allocator session immediately
+ was_writable_ = false;
+ OnAllocate();
+ }
+
+ // We were connecting, obviously not ALL timed out.
+ was_timed_out_ = false;
+ set_state(STATE_CONNECTING);
+}
+
+// We checked the status of our connections and not only weren't they writable
+// but they were also timed out, we really need a new allocator.
+void P2PSocket::HandleAllTimedOut() {
+ //
+ // No connections... all are timed out!
+ //
+ if (!was_timed_out_) {
+ // We weren't timed out before, so kick off an allocator now (we'll still
+ // be in the fully timed out state until the allocator actually gives back
+ // new ports)
+ OnAllocate();
+ }
+
+ // NOTE: we start was_timed_out_ in the true state so that we don't get
+ // another allocator created WHILE we are in the process of building up
+ // our first allocator.
+ was_timed_out_ = true;
+ was_writable_ = false;
+ set_state(STATE_CONNECTING);
+}
+
+// If we have a best connection, return it, otherwise return top one in the
+// list (later we will mark it best).
+Connection* P2PSocket::GetBestConnectionOnNetwork(Network* network) {
+ // If the best connection is on this network, then it wins.
+ if (best_connection_ && (best_connection_->port()->network() == network))
+ return best_connection_;
+
+ // Otherwise, we return the top-most in sorted order.
+ for (uint32 i = 0; i < connections_.size(); ++i) {
+ if (connections_[i]->port()->network() == network)
+ return connections_[i];
+ }
+
+ return NULL;
+}
+
+// Handle any queued up requests
+void P2PSocket::OnMessage(Message *pmsg) {
+ if (pmsg->message_id == MSG_SORT)
+ OnSort();
+ else if (pmsg->message_id == MSG_PING)
+ OnPing();
+ else if (pmsg->message_id == MSG_ALLOCATE)
+ OnAllocate();
+ else
+ assert(false);
+}
+
+// Handle queued up sort request
+void P2PSocket::OnSort() {
+ // Resort the connections based on the new statistics.
+ SortConnections();
+}
+
+// Handle queued up ping request
+void P2PSocket::OnPing() {
+ // Make sure the states of the connections are up-to-date (since this affects
+ // which ones are pingable).
+ UpdateConnectionStates();
+
+ // Find the oldest pingable connection and have it do a ping.
+ Connection* conn = FindNextPingableConnection();
+ if (conn)
+ conn->Ping(Time());
+
+ // Post ourselves a message to perform the next ping.
+ uint32 delay = (state_ == STATE_WRITABLE) ? WRITABLE_DELAY : UNWRITABLE_DELAY;
+ thread()->PostDelayed(delay, this, MSG_PING);
+}
+
+// Is the connection in a state for us to even consider pinging the other side?
+bool P2PSocket::IsPingable(Connection* conn) {
+ // An unconnected connection cannot be written to at all, so pinging is out
+ // of the question.
+ if (!conn->connected())
+ return false;
+
+ if (state_ == STATE_WRITABLE) {
+ // If we are writable, then we only want to ping connections that could be
+ // better than this one, i.e., the ones that were not pruned.
+ return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT);
+ } else {
+ // If we are not writable, then we need to try everything that might work.
+ // This includes both connections that do not have write timeout as well as
+ // ones that do not have read timeout. A connection could be readable but
+ // be in write-timeout if we pruned it before. Since the other side is
+ // still pinging it, it very well might still work.
+ return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) ||
+ (conn->read_state() != Connection::STATE_READ_TIMEOUT);
+ }
+}
+
+// Returns the next pingable connection to ping. This will be the oldest
+// pingable connection unless we have a writable connection that is past the
+// maximum acceptable ping delay.
+Connection* P2PSocket::FindNextPingableConnection() {
+ uint32 now = Time();
+ if (best_connection_ &&
+ (best_connection_->write_state() == Connection::STATE_WRITABLE) &&
+ (best_connection_->last_ping_sent()
+ + MAX_CURRENT_WRITABLE_DELAY <= now)) {
+ return best_connection_;
+ }
+
+ Connection* oldest_conn = NULL;
+ uint32 oldest_time = 0xFFFFFFFF;
+ for (uint32 i = 0; i < connections_.size(); ++i) {
+ if (IsPingable(connections_[i])) {
+ if (connections_[i]->last_ping_sent() < oldest_time) {
+ oldest_time = connections_[i]->last_ping_sent();
+ oldest_conn = connections_[i];
+ }
+ }
+ }
+ return oldest_conn;
+}
+
+// return the number of "pingable" connections
+uint32 P2PSocket::NumPingableConnections() {
+ uint32 count = 0;
+ for (uint32 i = 0; i < connections_.size(); ++i) {
+ if (IsPingable(connections_[i]))
+ count += 1;
+ }
+ return count;
+}
+
+// When a connection's state changes, we need to figure out who to use as
+// the best connection again. It could have become usable, or become unusable.
+void P2PSocket::OnConnectionStateChange(Connection *connection) {
+ assert(worker_thread_ == Thread::Current());
+
+ // We have to unroll the stack before doing this because we may be changing
+ // the state of connections while sorting.
+ RequestSort();
+}
+
+// When a connection is removed, edit it out, and then update our best
+// connection.
+void P2PSocket::OnConnectionDestroyed(Connection *connection) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Remove this connection from the list.
+ std::vector<Connection*>::iterator iter =
+ find(connections_.begin(), connections_.end(), connection);
+ assert(iter != connections_.end());
+ connections_.erase(iter);
+
+ LOG(INFO) << "Removed connection from p2p socket: "
+ << static_cast<int>(connections_.size()) << " remaining";
+
+ // If this is currently the best connection, then we need to pick a new one.
+ // The call to SortConnections will pick a new one. It looks at the current
+ // best connection in order to avoid switching between fairly similar ones.
+ // Since this connection is no longer an option, we can just set best to NULL
+ // and re-choose a best assuming that there was no best connection.
+ if (best_connection_ == connection) {
+ SwitchBestConnectionTo(NULL);
+ RequestSort();
+ }
+}
+
+// When a port is destroyed remove it from our list of ports to use for
+// connection attempts.
+void P2PSocket::OnPortDestroyed(Port* port) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Remove this port from the list (if we didn't drop it already).
+ std::vector<Port*>::iterator iter = find(ports_.begin(), ports_.end(), port);
+ if (iter != ports_.end())
+ ports_.erase(iter);
+
+ LOG(INFO) << "Removed port from p2p socket: "
+ << static_cast<int>(ports_.size()) << " remaining";
+}
+
+// We data is available, let listeners know
+void P2PSocket::OnReadPacket(Connection *connection,
+ const char *data, size_t len) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Let the client know of an incoming packet
+
+ SignalReadPacket(this, data, len);
+}
+
+// return socket name
+const std::string &P2PSocket::name() const {
+ return name_;
+}
+
+// return socket error value
+int P2PSocket::GetError() {
+ return error_;
+}
+
+// return a reference to the list of connections
+const std::vector<Connection *>& P2PSocket::connections() {
+ return connections_;
+}
+
+// Set options on ourselves is simply setting options on all of our available
+// port objects.
+int P2PSocket::SetOption(Socket::Option opt, int value) {
+ OptionMap::iterator it = options_.find(opt);
+ if (it == options_.end()) {
+ options_.insert(std::make_pair(opt, value));
+ } else if (it->second == value) {
+ return 0;
+ } else {
+ it->second = value;
+ }
+
+ for (uint32 i = 0; i < ports_.size(); ++i) {
+ int val = ports_[i]->SetOption(opt, value);
+ if (val < 0) {
+ // Because this also occurs deferred, probably no point in reporting an error
+ LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: " << ports_[i]->GetError();
+ }
+ }
+ return 0;
+}
+
+// returns the current state
+P2PSocket::State P2PSocket::state() {
+ return state_;
+}
+
+// Set the current state, and let listeners know when it changes
+void P2PSocket::set_state(P2PSocket::State state) {
+ assert(worker_thread_ == Thread::Current());
+ if (state != state_) {
+ state_ = state;
+ SignalState(this, state);
+ }
+}
+
+// Time for a new allocator, lets make sure we have a signalling channel
+// to communicate candidates through first.
+void P2PSocket::OnAllocate() {
+ // Allocation timer went off
+ waiting_for_signaling_ = true;
+ SignalRequestSignaling();
+}
+
+// When the signalling channel is ready, we can really kick off the allocator
+void P2PSocket::OnSignalingReady() {
+ if (waiting_for_signaling_) {
+ waiting_for_signaling_ = false;
+ AddAllocatorSession(allocator_->CreateSession(name_));
+ thread()->PostDelayed(kAllocatePeriod, this, MSG_ALLOCATE);
+ }
+}
+
+// return the current best connection writable state.
+bool P2PSocket::writable() {
+ assert(worker_thread_ == Thread::Current());
+
+ if (best_connection_ == NULL)
+ return false;
+ return best_connection_->write_state() == Connection::STATE_WRITABLE;
+}
+
+// return the worker thread
+Thread *P2PSocket::thread() {
+ return worker_thread_;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h
new file mode 100644
index 00000000..32eb1f6d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/p2psocket.h
@@ -0,0 +1,164 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// P2PSocket wraps up the state management of the connection between two
+// P2P clients. Clients have candidate ports for connecting, and connections
+// which are combinations of candidates from each end (Alice and Bob each
+// have candidates, one candidate from Alice and one candidate from Bob are
+// used to make a connection, repeat to make many connections).
+//
+// When all of the available connections become invalid (non-writable), we
+// kick off a process of determining more candidates and more connections.
+//
+#ifndef _CRICKET_P2P_BASE_P2PSOCKET_H_
+#define _CRICKET_P2P_BASE_P2PSOCKET_H_
+
+#include <vector>
+#include <string>
+#include "talk/base/sigslot.h"
+#include "talk/p2p/base/candidate.h"
+#include "talk/p2p/base/port.h"
+#include "talk/p2p/base/portallocator.h"
+
+namespace cricket {
+
+// Adds the port on which the candidate originated.
+class RemoteCandidate: public Candidate {
+ public:
+ RemoteCandidate(const Candidate& c, Port* origin_port)
+ : Candidate(c), origin_port_(origin_port) {}
+
+ Port* origin_port() { return origin_port_; }
+
+ private:
+ Port* origin_port_;
+};
+
+// P2PSocket manages the candidates and connection process to keep two P2P
+// clients connected to each other.
+class P2PSocket : public MessageHandler, public sigslot::has_slots<> {
+ public:
+ enum State {
+ STATE_CONNECTING = 0, // establishing writability
+ STATE_WRITABLE, // connected - ready for writing
+ };
+
+ P2PSocket(const std::string &name, PortAllocator *allocator);
+ virtual ~P2PSocket();
+
+ // Typically SocketManager calls these
+
+ const std::string &name() const;
+ void StartProcessingCandidates();
+ void AddRemoteCandidates(const std::vector<Candidate> &remote_candidates);
+ void OnSignalingReady();
+ void Reset();
+
+ // Typically the Session Client calls these
+
+ int Send(const char *data, size_t len);
+ int SetOption(Socket::Option opt, int value);
+ int GetError();
+
+ State state();
+ bool writable();
+ const std::vector<Connection *>& connections();
+ Connection* best_connection() { return best_connection_; }
+ Thread *thread();
+
+ sigslot::signal2<P2PSocket *, State> SignalState;
+ sigslot::signal0<> SignalRequestSignaling;
+ sigslot::signal3<P2PSocket *, const char *, size_t> SignalReadPacket;
+ sigslot::signal2<P2PSocket *, const SocketAddress &> SignalConnectionChanged;
+ sigslot::signal2<P2PSocket *, const std::vector<Candidate>&>
+ SignalCandidatesReady;
+ sigslot::signal1<P2PSocket *> SignalConnectionMonitor;
+
+ // Handler for internal messages.
+ virtual void OnMessage(Message *pmsg);
+
+ private:
+ void set_state(State state);
+ void UpdateConnectionStates();
+ void RequestSort();
+ void SortConnections();
+ void SwitchBestConnectionTo(Connection* conn);
+ void HandleWritable();
+ void HandleNotWritable();
+ void HandleAllTimedOut();
+ Connection* GetBestConnectionOnNetwork(Network* network);
+ bool CreateConnections(const Candidate &remote_candidate, Port* origin_port,
+ bool readable);
+ bool CreateConnection(Port* port, const Candidate& remote_candidate,
+ Port* origin_port, bool readable);
+ void RememberRemoteCandidate(const Candidate& remote_candidate,
+ Port* origin_port);
+ void OnUnknownAddress(Port *port, const SocketAddress &addr,
+ StunMessage *stun_msg,
+ const std::string &remote_username);
+ void OnPortReady(PortAllocatorSession *session, Port* port);
+ void OnCandidatesReady(PortAllocatorSession *session,
+ const std::vector<Candidate>& candidates);
+ void OnConnectionStateChange(Connection *connection);
+ void OnConnectionDestroyed(Connection *connection);
+ void OnPortDestroyed(Port* port);
+ void OnAllocate();
+ void OnReadPacket(Connection *connection, const char *data, size_t len);
+ void OnSort();
+ void OnPing();
+ bool IsPingable(Connection* conn);
+ Connection* FindNextPingableConnection();
+ uint32 NumPingableConnections();
+ PortAllocatorSession* allocator_session() {
+ return allocator_sessions_.back();
+ }
+ void AddAllocatorSession(PortAllocatorSession* session);
+
+ Thread *worker_thread_;
+ State state_;
+ bool waiting_for_signaling_;
+ int error_;
+ std::string name_;
+ PortAllocator *allocator_;
+ std::vector<PortAllocatorSession*> allocator_sessions_;
+ std::vector<Port *> ports_;
+ std::vector<Connection *> connections_;
+ Connection *best_connection_;
+ std::vector<RemoteCandidate> remote_candidates_;
+ bool pinging_started_; // indicates whether StartGetAllCandidates has been called
+ bool sort_dirty_; // indicates whether another sort is needed right now
+ bool was_writable_;
+ bool was_timed_out_;
+ typedef std::map<Socket::Option, int> OptionMap;
+ OptionMap options_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(P2PSocket);
+};
+
+} // namespace cricket
+
+#endif // _CRICKET_P2P_BASE_P2PSOCKET_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc
new file mode 100644
index 00000000..14549b5b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.cc
@@ -0,0 +1,869 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/logging.h"
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/asynctcpsocket.h"
+#include "talk/base/socketadapters.h"
+#include "talk/p2p/base/port.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/base/scoped_ptr.h"
+#include <errno.h>
+#include <algorithm>
+#include <iostream>
+#include <cassert>
+#include <vector>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::memcmp;
+}
+#endif
+
+namespace {
+
+// The length of time we wait before timing out readability on a connection.
+const uint32 CONNECTION_READ_TIMEOUT = 30 * 1000; // 30 seconds
+
+// The length of time we wait before timing out writability on a connection.
+const uint32 CONNECTION_WRITE_TIMEOUT = 15 * 1000; // 15 seconds
+
+// The length of time we wait before we become unwritable.
+const uint32 CONNECTION_WRITE_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds
+
+// The number of pings that must fail to respond before we become unwritable.
+const uint32 CONNECTION_WRITE_CONNECT_FAILURES = 5;
+
+// This is the length of time that we wait for a ping response to come back.
+const int CONNECTION_RESPONSE_TIMEOUT = 5 * 1000; // 5 seconds
+
+// Determines whether we have seen at least the given maximum number of
+// pings fail to have a response.
+inline bool TooManyFailures(
+ const std::vector<uint32>& pings_since_last_response,
+ uint32 maximum_failures,
+ uint32 rtt_estimate,
+ uint32 now) {
+
+ // If we haven't sent that many pings, then we can't have failed that many.
+ if (pings_since_last_response.size() < maximum_failures)
+ return false;
+
+ // Check if the window in which we would expect a response to the ping has
+ // already elapsed.
+ return pings_since_last_response[maximum_failures - 1] + rtt_estimate < now;
+}
+
+// Determines whether we have gone too long without seeing any response.
+inline bool TooLongWithoutResponse(
+ const std::vector<uint32>& pings_since_last_response,
+ uint32 maximum_time,
+ uint32 now) {
+
+ if (pings_since_last_response.size() == 0)
+ return false;
+
+ return pings_since_last_response[0] + maximum_time < now;
+}
+
+// We will restrict RTT estimates (when used for determining state) to be
+// within a reasonable range.
+const uint32 MINIMUM_RTT = 100; // 0.1 seconds
+const uint32 MAXIMUM_RTT = 3000; // 3 seconds
+
+// When we don't have any RTT data, we have to pick something reasonable. We
+// use a large value just in case the connection is really slow.
+const uint32 DEFAULT_RTT = MAXIMUM_RTT;
+
+// Computes our estimate of the RTT given the current estimate and the number
+// of data points on which it is based.
+inline uint32 ConservativeRTTEstimate(uint32 rtt, uint32 rtt_data_points) {
+ if (rtt_data_points == 0)
+ return DEFAULT_RTT;
+ else
+ return cricket::_max(MINIMUM_RTT, cricket::_min(MAXIMUM_RTT, 2 * rtt));
+}
+
+// Weighting of the old rtt value to new data.
+const int RTT_RATIO = 3; // 3 : 1
+
+// The delay before we begin checking if this port is useless.
+const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
+
+const uint32 MSG_CHECKTIMEOUT = 1;
+const uint32 MSG_DELETE = 1;
+
+}
+
+namespace cricket {
+
+static const char * const PROTO_NAMES[PROTO_LAST+1] = { "udp", "tcp", "ssltcp" };
+
+const char * ProtoToString(ProtocolType proto) {
+ return PROTO_NAMES[proto];
+}
+
+bool StringToProto(const char * value, ProtocolType& proto) {
+ for (size_t i=0; i<=PROTO_LAST; ++i) {
+ if (strcmp(PROTO_NAMES[i], value) == 0) {
+ proto = static_cast<ProtocolType>(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+ProxyInfo Port::proxy_;
+
+Port::Port(Thread* thread, const std::string& type, SocketFactory* factory,
+ Network* network)
+ : thread_(thread), factory_(factory), type_(type), network_(network),
+ preference_(-1), lifetime_(LT_PRESTART) {
+
+ if (factory_ == NULL)
+ factory_ = thread_->socketserver();
+
+ set_username_fragment(CreateRandomString(16));
+ set_password(CreateRandomString(16));
+}
+
+Port::~Port() {
+ // Delete all of the remaining connections. We copy the list up front
+ // because each deletion will cause it to be modified.
+
+ std::vector<Connection*> list;
+
+ AddressMap::iterator iter = connections_.begin();
+ while (iter != connections_.end()) {
+ list.push_back(iter->second);
+ ++iter;
+ }
+
+ for (uint32 i = 0; i < list.size(); i++)
+ delete list[i];
+}
+
+Connection* Port::GetConnection(const SocketAddress& remote_addr) {
+ AddressMap::const_iterator iter = connections_.find(remote_addr);
+ if (iter != connections_.end())
+ return iter->second;
+ else
+ return NULL;
+}
+
+void Port::set_username_fragment(const std::string& username_fragment) {
+ username_frag_ = username_fragment;
+}
+
+void Port::set_password(const std::string& password) {
+ password_ = password;
+}
+
+void Port::add_address(const SocketAddress& address, const std::string& protocol, bool final) {
+ Candidate c;
+ c.set_name(name_);
+ c.set_type(type_);
+ c.set_protocol(protocol);
+ c.set_address(address);
+ c.set_preference(preference_);
+ c.set_username(username_frag_);
+ c.set_password(password_);
+ c.set_network_name(network_->name());
+ c.set_generation(generation_);
+ candidates_.push_back(c);
+
+ if (final)
+ SignalAddressReady(this);
+}
+
+void Port::AddConnection(Connection* conn) {
+ connections_[conn->remote_candidate().address()] = conn;
+ conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
+ SignalConnectionCreated(this, conn);
+}
+
+void Port::OnReadPacket(
+ const char* data, size_t size, const SocketAddress& addr) {
+
+ // If this is an authenticated STUN request, then signal unknown address and
+ // send back a proper binding response.
+ StunMessage* msg;
+ std::string remote_username;
+ if (!GetStunMessage(data, size, addr, msg, remote_username)) {
+ LOG(LERROR) << "Received non-STUN packet from unknown address: "
+ << addr.ToString();
+ } else if (!msg) {
+ // STUN message handled already
+ } else if (msg->type() == STUN_BINDING_REQUEST) {
+ SignalUnknownAddress(this, addr, msg, remote_username);
+ } else {
+ LOG(LERROR) << "Received unexpected STUN message type (" << msg->type()
+ << ") from unknown address: " << addr.ToString();
+ delete msg;
+ }
+}
+
+void Port::SendBindingRequest(Connection* conn) {
+
+ // Construct the request message.
+
+ StunMessage request;
+ request.SetType(STUN_BINDING_REQUEST);
+ request.SetTransactionID(CreateRandomString(16));
+
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ std::string username = conn->remote_candidate().username();
+ username.append(username_frag_);
+ username_attr->CopyBytes(username.c_str(), (uint16)username.size());
+ request.AddAttribute(username_attr);
+
+ // Send the request message.
+ // NOTE: If we wanted to, this is where we would add the HMAC.
+ ByteBuffer buf;
+ request.Write(&buf);
+ SendTo(buf.Data(), buf.Length(), conn->remote_candidate().address(), false);
+}
+
+bool Port::GetStunMessage(const char* data, size_t size,
+ const SocketAddress& addr, StunMessage *& msg,
+ std::string& remote_username) {
+ // NOTE: This could clearly be optimized to avoid allocating any memory.
+ // However, at the data rates we'll be looking at on the client side,
+ // this probably isn't worth worrying about.
+
+ msg = 0;
+
+ // Parse the request message. If the packet is not a complete and correct
+ // STUN message, then ignore it.
+ buzz::scoped_ptr<StunMessage> stun_msg(new StunMessage());
+ ByteBuffer buf(data, size);
+ if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
+ return false;
+ }
+
+ // The packet must include a username that either begins or ends with our
+ // fragment. It should begin with our fragment if it is a request and it
+ // should end with our fragment if it is a response.
+ const StunByteStringAttribute* username_attr =
+ stun_msg->GetByteString(STUN_ATTR_USERNAME);
+
+ int remote_frag_len = (username_attr ? username_attr->length() : 0);
+ remote_frag_len -= static_cast<int>(username_frag_.size());
+
+ if (stun_msg->type() == STUN_BINDING_REQUEST) {
+ if ((remote_frag_len < 0)
+ || (std::memcmp(username_attr->bytes(),
+ username_frag_.c_str(), username_frag_.size()) != 0)) {
+ LOG(LERROR) << "Received STUN request with bad username";
+ SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
+ STUN_ERROR_REASON_BAD_REQUEST);
+ return true;
+ }
+
+ remote_username.assign(username_attr->bytes() + username_frag_.size(),
+ username_attr->bytes() + username_attr->length());
+ } else if ((stun_msg->type() == STUN_BINDING_RESPONSE)
+ || (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
+ if ((remote_frag_len < 0)
+ || (std::memcmp(username_attr->bytes() + remote_frag_len,
+ username_frag_.c_str(), username_frag_.size()) != 0)) {
+ LOG(LERROR) << "Received STUN response with bad username";
+ // Do not send error response to a response
+ return true;
+ }
+
+ remote_username.assign(username_attr->bytes(),
+ username_attr->bytes() + remote_frag_len);
+
+ if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
+ if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
+ LOG(LERROR) << "Received STUN binding error:"
+ << " class=" << error_code->error_class()
+ << " number=" << error_code->number()
+ << " reason='" << error_code->reason() << "'";
+ // Return message to allow error-specific processing
+ } else {
+ LOG(LERROR) << "Received STUN error response with no error code";
+ // Drop corrupt message
+ return true;
+ }
+ }
+ } else {
+ LOG(LERROR) << "Received STUN packet with invalid type: "
+ << stun_msg->type();
+ return true;
+ }
+
+ // Return the STUN message found.
+ msg = stun_msg.release();
+ return true;
+}
+
+void Port::SendBindingResponse(
+ StunMessage* request, const SocketAddress& addr) {
+
+ assert(request->type() == STUN_BINDING_REQUEST);
+
+ // Retrieve the username from the request.
+ const StunByteStringAttribute* username_attr =
+ request->GetByteString(STUN_ATTR_USERNAME);
+ assert(username_attr);
+
+ // Fill in the response message.
+
+ StunMessage response;
+ response.SetType(STUN_BINDING_RESPONSE);
+ response.SetTransactionID(request->transaction_id());
+
+ StunByteStringAttribute* username2_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username2_attr->CopyBytes(username_attr->bytes(), username_attr->length());
+ response.AddAttribute(username2_attr);
+
+ StunAddressAttribute* addr_attr =
+ StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ addr_attr->SetFamily(1);
+ addr_attr->SetPort(addr.port());
+ addr_attr->SetIP(addr.ip());
+ response.AddAttribute(addr_attr);
+
+ // Send the response message.
+ // NOTE: If we wanted to, this is where we would add the HMAC.
+ ByteBuffer buf;
+ response.Write(&buf);
+ SendTo(buf.Data(), buf.Length(), addr, false);
+
+ // The fact that we received a successful request means that this connection
+ // (if one exists) should now be readable.
+ Connection* conn = GetConnection(addr);
+ assert(conn);
+ if (conn)
+ conn->ReceivedPing();
+}
+
+void Port::SendBindingErrorResponse(
+ StunMessage* request, const SocketAddress& addr, int error_code,
+ const std::string& reason) {
+
+ assert(request->type() == STUN_BINDING_REQUEST);
+
+ // Retrieve the username from the request. If it didn't have one, we
+ // shouldn't be responding at all.
+ const StunByteStringAttribute* username_attr =
+ request->GetByteString(STUN_ATTR_USERNAME);
+ assert(username_attr);
+
+ // Fill in the response message.
+
+ StunMessage response;
+ response.SetType(STUN_BINDING_ERROR_RESPONSE);
+ response.SetTransactionID(request->transaction_id());
+
+ StunByteStringAttribute* username2_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username2_attr->CopyBytes(username_attr->bytes(), username_attr->length());
+ response.AddAttribute(username2_attr);
+
+ StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
+ error_attr->SetErrorCode(error_code);
+ error_attr->SetReason(reason);
+ response.AddAttribute(error_attr);
+
+ // Send the response message.
+ // NOTE: If we wanted to, this is where we would add the HMAC.
+ ByteBuffer buf;
+ response.Write(&buf);
+ SendTo(buf.Data(), buf.Length(), addr, false);
+}
+
+AsyncPacketSocket * Port::CreatePacketSocket(ProtocolType proto) {
+ if (proto == PROTO_UDP) {
+ return new AsyncUDPSocket(factory_->CreateAsyncSocket(SOCK_DGRAM));
+ } else if ((proto == PROTO_TCP) || (proto == PROTO_SSLTCP)) {
+ AsyncSocket * socket = factory_->CreateAsyncSocket(SOCK_STREAM);
+ switch (proxy().type) {
+ case PROXY_NONE:
+ break;
+ case PROXY_SOCKS5:
+ socket = new AsyncSocksProxySocket(socket, proxy().address, proxy().username, proxy().password);
+ break;
+ case PROXY_HTTPS:
+ default:
+ socket = new AsyncHttpsProxySocket(socket, proxy().address, proxy().username, proxy().password);
+ break;
+ }
+ if (proto == PROTO_SSLTCP) {
+ socket = new AsyncSSLSocket(socket);
+ }
+ return new AsyncTCPSocket(socket);
+ } else {
+ LOG(INFO) << "Unknown protocol: " << proto;
+ return 0;
+ }
+}
+
+void Port::OnMessage(Message *pmsg) {
+ assert(pmsg->message_id == MSG_CHECKTIMEOUT);
+ assert(lifetime_ == LT_PRETIMEOUT);
+ lifetime_ = LT_POSTTIMEOUT;
+ CheckTimeout();
+}
+
+void Port::Start() {
+ // The port sticks around for a minimum lifetime, after which
+ // we destroy it when it drops to zero connections.
+ if (lifetime_ == LT_PRESTART) {
+ lifetime_ = LT_PRETIMEOUT;
+ thread_->PostDelayed(kPortTimeoutDelay, this, MSG_CHECKTIMEOUT);
+ } else {
+ LOG(WARNING) << "Port restart attempted";
+ }
+}
+
+void Port::OnConnectionDestroyed(Connection* conn) {
+ AddressMap::iterator iter = connections_.find(conn->remote_candidate().address());
+ assert(iter != connections_.end());
+ connections_.erase(iter);
+
+ CheckTimeout();
+}
+
+void Port::CheckTimeout() {
+ // If this port has no connections, then there's no reason to keep it around.
+ // When the connections time out (both read and write), they will delete
+ // themselves, so if we have any connections, they are either readable or
+ // writable (or still connecting).
+ if ((lifetime_ == LT_POSTTIMEOUT) && connections_.empty()) {
+ LOG(INFO) << "Destroying port: " << name_ << "-" << type_;
+ SignalDestroyed(this);
+ delete this;
+ }
+}
+
+// A ConnectionRequest is a simple STUN ping used to determine writability.
+class ConnectionRequest : public StunRequest {
+public:
+ ConnectionRequest(Connection* connection) : connection_(connection) {
+ }
+
+ virtual ~ConnectionRequest() {
+ }
+
+ virtual void Prepare(StunMessage* request) {
+ request->SetType(STUN_BINDING_REQUEST);
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ std::string username = connection_->remote_candidate().username();
+ username.append(connection_->port()->username_fragment());
+ username_attr->CopyBytes(username.c_str(), (uint16)username.size());
+ request->AddAttribute(username_attr);
+ }
+
+ virtual void OnResponse(StunMessage* response) {
+ connection_->OnConnectionRequestResponse(response, Elapsed());
+ }
+
+ virtual void OnErrorResponse(StunMessage* response) {
+ connection_->OnConnectionRequestErrorResponse(response, Elapsed());
+ }
+
+ virtual void OnTimeout() {
+ }
+
+ virtual int GetNextDelay() {
+ // Each request is sent only once. After a single delay , the request will
+ // time out.
+ timeout_ = true;
+ return CONNECTION_RESPONSE_TIMEOUT;
+ }
+
+private:
+ Connection* connection_;
+};
+
+//
+// Connection
+//
+
+Connection::Connection(Port* port, size_t index, const Candidate& remote_candidate)
+ : requests_(port->thread()), port_(port), local_candidate_index_(index),
+ remote_candidate_(remote_candidate), read_state_(STATE_READ_TIMEOUT),
+ write_state_(STATE_WRITE_CONNECT), connected_(true), pruned_(false),
+ rtt_(0), rtt_data_points_(0), last_ping_sent_(0), last_ping_received_(0),
+ recv_total_bytes_(0), recv_bytes_second_(0),
+ last_recv_bytes_second_time_((uint32)-1), last_recv_bytes_second_calc_(0),
+ sent_total_bytes_(0), sent_bytes_second_(0),
+ last_sent_bytes_second_time_((uint32)-1), last_sent_bytes_second_calc_(0) {
+
+ // Wire up to send stun packets
+ requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
+}
+
+Connection::~Connection() {
+}
+
+const Candidate& Connection::local_candidate() const {
+ if (local_candidate_index_ < port_->candidates().size())
+ return port_->candidates()[local_candidate_index_];
+ assert(false);
+ static Candidate foo;
+ return foo;
+}
+
+void Connection::set_read_state(ReadState value) {
+ ReadState old_value = read_state_;
+ read_state_ = value;
+ if (value != old_value) {
+ SignalStateChange(this);
+ CheckTimeout();
+ }
+}
+
+void Connection::set_write_state(WriteState value) {
+ WriteState old_value = write_state_;
+ write_state_ = value;
+ if (value != old_value) {
+ SignalStateChange(this);
+ CheckTimeout();
+ }
+}
+
+void Connection::set_connected(bool value) {
+ bool old_value = connected_;
+ connected_ = value;
+
+ // When connectedness is turned off, this connection is done.
+ if (old_value && !value)
+ set_write_state(STATE_WRITE_TIMEOUT);
+}
+
+void Connection::OnSendStunPacket(const void* data, size_t size) {
+ port_->SendTo(data, size, remote_candidate_.address(), false);
+}
+
+void Connection::OnReadPacket(const char* data, size_t size) {
+ StunMessage* msg;
+ std::string remote_username;
+ const SocketAddress& addr(remote_candidate_.address());
+ if (!port_->GetStunMessage(data, size, addr, msg, remote_username)) {
+ // The packet did not parse as a valid STUN message
+
+ // If this connection is readable, then pass along the packet.
+ if (read_state_ == STATE_READABLE) {
+ // readable means data from this address is acceptable
+ // Send it on!
+
+ recv_total_bytes_ += size;
+ SignalReadPacket(this, data, size);
+
+ // If timed out sending writability checks, start up again
+ if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
+ set_write_state(STATE_WRITE_CONNECT);
+ } else {
+ // Not readable means the remote address hasn't send a valid
+ // binding request yet.
+
+ LOG(WARNING) << "Received non-STUN packet from an unreadable connection.";
+ }
+ } else if (!msg) {
+ // The packet was STUN, but was already handled
+ } else if (remote_username != remote_candidate_.username()) {
+ // Not destined this connection
+ LOG(LERROR) << "Received STUN packet on wrong address.";
+ if (msg->type() == STUN_BINDING_REQUEST) {
+ port_->SendBindingErrorResponse(msg, addr, STUN_ERROR_BAD_REQUEST,
+ STUN_ERROR_REASON_BAD_REQUEST);
+ }
+ delete msg;
+ } else {
+ // The packet is STUN, with the current username
+ // If this is a STUN request, then update the readable bit and respond.
+ // If this is a STUN response, then update the writable bit.
+
+ switch (msg->type()) {
+ case STUN_BINDING_REQUEST:
+ // Incoming, validated stun request from remote peer.
+ // This call will also set the connection readable.
+
+ port_->SendBindingResponse(msg, addr);
+
+ // If timed out sending writability checks, start up again
+ if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
+ set_write_state(STATE_WRITE_CONNECT);
+ break;
+
+ case STUN_BINDING_RESPONSE:
+ case STUN_BINDING_ERROR_RESPONSE:
+ // Response from remote peer. Does it match request sent?
+ // This doesn't just check, it makes callbacks if transaction
+ // id's match
+ requests_.CheckResponse(msg);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ // Done with the message; delete
+
+ delete msg;
+ }
+}
+
+void Connection::Prune() {
+ pruned_ = true;
+ requests_.Clear();
+ set_write_state(STATE_WRITE_TIMEOUT);
+}
+
+void Connection::Destroy() {
+ set_read_state(STATE_READ_TIMEOUT);
+ set_write_state(STATE_WRITE_TIMEOUT);
+}
+
+void Connection::UpdateState(uint32 now) {
+ // Check the readable state.
+ //
+ // Since we don't know how many pings the other side has attempted, the best
+ // test we can do is a simple window.
+
+ if ((read_state_ == STATE_READABLE) &&
+ (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now)) {
+ set_read_state(STATE_READ_TIMEOUT);
+ }
+
+ // Check the writable state. (The order of these checks is important.)
+ //
+ // Before becoming unwritable, we allow for a fixed number of pings to fail
+ // (i.e., receive no response). We also have to give the response time to
+ // get back, so we include a conservative estimate of this.
+ //
+ // Before timing out writability, we give a fixed amount of time. This is to
+ // allow for changes in network conditions.
+
+ uint32 rtt = ConservativeRTTEstimate(rtt_, rtt_data_points_);
+
+ if ((write_state_ == STATE_WRITABLE) &&
+ TooManyFailures(pings_since_last_response_,
+ CONNECTION_WRITE_CONNECT_FAILURES,
+ rtt,
+ now) &&
+ TooLongWithoutResponse(pings_since_last_response_,
+ CONNECTION_WRITE_CONNECT_TIMEOUT,
+ now)) {
+ set_write_state(STATE_WRITE_CONNECT);
+ }
+
+ if ((write_state_ == STATE_WRITE_CONNECT) &&
+ TooLongWithoutResponse(pings_since_last_response_,
+ CONNECTION_WRITE_TIMEOUT,
+ now)) {
+ set_write_state(STATE_WRITE_TIMEOUT);
+ }
+}
+
+void Connection::Ping(uint32 now) {
+ assert(connected_);
+ last_ping_sent_ = now;
+ pings_since_last_response_.push_back(now);
+ requests_.Send(new ConnectionRequest(this));
+}
+
+void Connection::ReceivedPing() {
+ last_ping_received_ = Time();
+ set_read_state(STATE_READABLE);
+}
+
+void Connection::OnConnectionRequestResponse(StunMessage *response, uint32 rtt) {
+ // We have a potentially valid reply from the remote address.
+ // The packet must include a username that ends with our fragment,
+ // since it is a response.
+
+ // Check exact message type
+ bool valid = true;
+ if (response->type() != STUN_BINDING_RESPONSE)
+ valid = false;
+
+ // Must have username attribute
+ const StunByteStringAttribute* username_attr =
+ response->GetByteString(STUN_ATTR_USERNAME);
+ if (valid) {
+ if (!username_attr) {
+ LOG(LERROR) << "Received likely STUN packet with no username";
+ valid = false;
+ }
+ }
+
+ // Length must be at least the size of our fragment (actually, should
+ // be bigger since our fragment is at the end!)
+ if (valid) {
+ if (username_attr->length() <= port_->username_fragment().size()) {
+ LOG(LERROR) << "Received likely STUN packet with short username";
+ valid = false;
+ }
+ }
+
+ // Compare our fragment with the end of the username - must be exact match
+ if (valid) {
+ std::string username_fragment = port_->username_fragment();
+ int offset = (int)(username_attr->length() - username_fragment.size());
+ if (std::memcmp(username_attr->bytes() + offset,
+ username_fragment.c_str(), username_fragment.size()) != 0) {
+ LOG(LERROR) << "Received STUN response with bad username";
+ valid = false;
+ }
+ }
+
+ if (valid) {
+ // Valid response. If we're not already, become writable. We may be
+ // bringing a pruned connection back to life, but if we don't really want
+ // it, we can always prune it again.
+ set_write_state(STATE_WRITABLE);
+
+ pings_since_last_response_.clear();
+ rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
+ rtt_data_points_ += 1;
+ }
+}
+
+void Connection::OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt) {
+ const StunErrorCodeAttribute* error = response->GetErrorCode();
+ uint32 error_code = error ? error->error_code() : STUN_ERROR_GLOBAL_FAILURE;
+
+ if ((error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE)
+ || (error_code == STUN_ERROR_SERVER_ERROR)
+ || (error_code == STUN_ERROR_UNAUTHORIZED)) {
+ // Recoverable error, retry
+ } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
+ // Race failure, retry
+ } else {
+ // This is not a valid connection.
+ set_connected(false);
+ }
+}
+
+void Connection::CheckTimeout() {
+ // If both read and write have timed out, then this connection can contribute
+ // no more to p2p socket unless at some later date readability were to come
+ // back. However, we gave readability a long time to timeout, so at this
+ // point, it seems fair to get rid of this connectoin.
+ if ((read_state_ == STATE_READ_TIMEOUT) &&
+ (write_state_ == STATE_WRITE_TIMEOUT)) {
+ port_->thread()->Post(this, MSG_DELETE);
+ }
+}
+
+void Connection::OnMessage(Message *pmsg) {
+ assert(pmsg->message_id == MSG_DELETE);
+
+ LOG(INFO) << "Destroying connection: from "
+ << local_candidate().address().ToString()
+ << " to " << remote_candidate_.address().ToString();
+
+ SignalDestroyed(this);
+ delete this;
+}
+
+size_t Connection::recv_bytes_second() {
+ // Snapshot bytes / second calculator
+
+ uint32 current_time = Time();
+ if (last_recv_bytes_second_time_ != (uint32)-1) {
+ int delta = TimeDiff(current_time, last_recv_bytes_second_time_);
+ if (delta >= 1000) {
+ int fraction_time = delta % 1000;
+ int seconds_time = delta - fraction_time;
+ int fraction_bytes = (int)(recv_total_bytes_ - last_recv_bytes_second_calc_) * fraction_time / delta;
+ recv_bytes_second_ = (recv_total_bytes_ - last_recv_bytes_second_calc_ - fraction_bytes) * seconds_time / delta;
+ last_recv_bytes_second_time_ = current_time - fraction_time;
+ last_recv_bytes_second_calc_ = recv_total_bytes_ - fraction_bytes;
+ }
+ }
+ if (last_recv_bytes_second_time_ == (uint32)-1) {
+ last_recv_bytes_second_time_ = current_time;
+ last_recv_bytes_second_calc_ = recv_total_bytes_;
+ }
+
+ return recv_bytes_second_;
+}
+
+size_t Connection::recv_total_bytes() {
+ return recv_total_bytes_;
+}
+
+size_t Connection::sent_bytes_second() {
+ // Snapshot bytes / second calculator
+
+ uint32 current_time = Time();
+ if (last_sent_bytes_second_time_ != (uint32)-1) {
+ int delta = TimeDiff(current_time, last_sent_bytes_second_time_);
+ if (delta >= 1000) {
+ int fraction_time = delta % 1000;
+ int seconds_time = delta - fraction_time;
+ int fraction_bytes = (int)(sent_total_bytes_ - last_sent_bytes_second_calc_) * fraction_time / delta;
+ sent_bytes_second_ = (sent_total_bytes_ - last_sent_bytes_second_calc_ - fraction_bytes) * seconds_time / delta;
+ last_sent_bytes_second_time_ = current_time - fraction_time;
+ last_sent_bytes_second_calc_ = sent_total_bytes_ - fraction_bytes;
+ }
+ }
+ if (last_sent_bytes_second_time_ == (uint32)-1) {
+ last_sent_bytes_second_time_ = current_time;
+ last_sent_bytes_second_calc_ = sent_total_bytes_;
+ }
+
+ return sent_bytes_second_;
+}
+
+size_t Connection::sent_total_bytes() {
+ return sent_total_bytes_;
+}
+
+ProxyConnection::ProxyConnection(Port* port, size_t index, const Candidate& candidate)
+ : Connection(port, index, candidate), error_(0) {
+}
+
+int ProxyConnection::Send(const void* data, size_t size) {
+ if (write_state() != STATE_WRITABLE) {
+ error_ = EWOULDBLOCK;
+ return SOCKET_ERROR;
+ }
+ int sent = port_->SendTo(data, size, remote_candidate_.address(), true);
+ if (sent <= 0) {
+ assert(sent < 0);
+ error_ = port_->GetError();
+ } else {
+ sent_total_bytes_ += sent;
+ }
+ return sent;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h
new file mode 100644
index 00000000..c22fad28
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/port.h
@@ -0,0 +1,367 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PORT_H__
+#define __PORT_H__
+
+#include "talk/base/network.h"
+#include "talk/base/socketaddress.h"
+#include "talk/base/proxyinfo.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/base/candidate.h"
+#include "talk/p2p/base/stun.h"
+#include "talk/p2p/base/stunrequest.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace cricket {
+
+class Connection;
+class AsyncPacketSocket;
+
+enum ProtocolType { PROTO_UDP, PROTO_TCP, PROTO_SSLTCP, PROTO_LAST = PROTO_SSLTCP };
+const char * ProtoToString(ProtocolType proto);
+bool StringToProto(const char * value, ProtocolType& proto);
+
+struct ProtocolAddress {
+ SocketAddress address;
+ ProtocolType proto;
+
+ ProtocolAddress(const SocketAddress& a, ProtocolType p) : address(a), proto(p) { }
+};
+
+// Represents a local communication mechanism that can be used to create
+// connections to similar mechanisms of the other client. Subclasses of this
+// one add support for specific mechanisms like local UDP ports.
+class Port: public MessageHandler, public sigslot::has_slots<> {
+public:
+ Port(Thread* thread, const std::string &type, SocketFactory* factory,
+ Network* network);
+ virtual ~Port();
+
+ // The thread on which this port performs its I/O.
+ Thread* thread() { return thread_; }
+
+ // The factory used to create the sockets of this port.
+ SocketFactory* socket_factory() const { return factory_; }
+ void set_socket_factory(SocketFactory* factory) { factory_ = factory; }
+
+ // Each port is identified by a name (for debugging purposes).
+ const std::string& name() const { return name_; }
+ void set_name(const std::string& name) { name_ = name; }
+
+ // In order to establish a connection to this Port (so that real data can be
+ // sent through), the other side must send us a STUN binding request that is
+ // authenticated with this username and password.
+ const std::string& username_fragment() const { return username_frag_; }
+ const std::string& password() const { return password_; }
+
+ // A value in [0,1] that indicates the preference for this port versus other
+ // ports on this client. (Larger indicates more preference.)
+ float preference() const { return preference_; }
+ void set_preference(float preference) { preference_ = preference; }
+
+ // Identifies the port type.
+ //const std::string& protocol() const { return proto_; }
+ const std::string& type() const { return type_; }
+
+ // Identifies network that this port was allocated on.
+ Network* network() { return network_; }
+
+ // Identifies the generation that this port was created in.
+ uint32 generation() { return generation_; }
+ void set_generation(uint32 generation) { generation_ = generation; }
+
+ // PrepareAddress will attempt to get an address for this port that other
+ // clients can send to. It may take some time before the address is read.
+ // Once it is ready, we will send SignalAddressReady.
+ virtual void PrepareAddress() = 0;
+ sigslot::signal1<Port*> SignalAddressReady;
+ //const SocketAddress& address() const { return address_; }
+
+ // Provides all of the above information in one handy object.
+ const std::vector<Candidate>& candidates() const { return candidates_; }
+
+ // Returns a map containing all of the connections of this port, keyed by the
+ // remote address.
+ typedef std::map<SocketAddress, Connection*> AddressMap;
+ const AddressMap& connections() { return connections_; }
+
+ // Returns the connection to the given address or NULL if none exists.
+ Connection* GetConnection(const SocketAddress& remote_addr);
+
+ // Creates a new connection to the given address.
+ enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE };
+ virtual Connection* CreateConnection(const Candidate& remote_candidate, CandidateOrigin origin) = 0;
+
+ // Called each time a connection is created.
+ sigslot::signal2<Port*, Connection*> SignalConnectionCreated;
+
+ // Sends the given packet to the given address, provided that the address is
+ // that of a connection or an address that has sent to us already.
+ virtual int SendTo(
+ const void* data, size_t size, const SocketAddress& addr, bool payload) = 0;
+
+ // Indicates that we received a successful STUN binding request from an
+ // address that doesn't correspond to any current connection. To turn this
+ // into a real connection, call CreateConnection.
+ sigslot::signal4<Port*, const SocketAddress&, StunMessage*, const std::string&> SignalUnknownAddress;
+
+ // Sends a response message (normal or error) to the given request. One of
+ // these methods should be called as a response to SignalUnknownAddress.
+ // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse.
+ void SendBindingResponse(StunMessage* request, const SocketAddress& addr);
+ void SendBindingErrorResponse(
+ StunMessage* request, const SocketAddress& addr, int error_code,
+ const std::string& reason);
+
+ // Indicates that errors occurred when performing I/O.
+ sigslot::signal2<Port*, int> SignalReadError;
+ sigslot::signal2<Port*, int> SignalWriteError;
+
+ // Functions on the underlying socket(s).
+ virtual int SetOption(Socket::Option opt, int value) = 0;
+ virtual int GetError() = 0;
+
+ static void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; }
+ static const ProxyInfo& proxy() { return proxy_; }
+
+ AsyncPacketSocket * CreatePacketSocket(ProtocolType proto);
+
+ virtual void OnMessage(Message *pmsg);
+
+ // Indicates to the port that its official use has now begun. This will
+ // start the timer that checks to see if the port is being used.
+ void Start();
+
+ // Signaled when this port decides to delete itself because it no longer has
+ // any usefulness.
+ sigslot::signal1<Port*> SignalDestroyed;
+
+protected:
+ Thread* thread_;
+ SocketFactory* factory_;
+ std::string type_;
+ Network* network_;
+ uint32 generation_;
+ std::string name_;
+ std::string username_frag_;
+ std::string password_;
+ float preference_;
+ std::vector<Candidate> candidates_;
+ AddressMap connections_;
+ enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
+
+ // Fills in the username fragment and password. These will be initially set
+ // in the constructor to random values. Subclasses can override, though.
+ void set_username_fragment(const std::string& username_fragment);
+ void set_password(const std::string& password);
+
+ // Fills in the local address of the port.
+ void add_address(const SocketAddress& address, const std::string& protocol, bool final = true);
+
+ // Adds the given connection to the list. (Deleting removes them.)
+ void AddConnection(Connection* conn);
+
+ // Called when a packet is received from an unknown address that is not
+ // currently a connection. If this is an authenticated STUN binding request,
+ // then we will signal the client.
+ void OnReadPacket(const char* data, size_t size, const SocketAddress& addr);
+
+ // Constructs a STUN binding request for the given connection and sends it.
+ void SendBindingRequest(Connection* conn);
+
+ // If the given data comprises a complete and correct STUN message then the
+ // return value is true, otherwise false. If the message username corresponds
+ // with this port's username fragment, msg will contain the parsed STUN
+ // message. Otherwise, the function may send a STUN response internally.
+ // remote_username contains the remote fragment of the STUN username.
+ bool GetStunMessage(const char* data, size_t size, const SocketAddress& addr,
+ StunMessage *& msg, std::string& remote_username);
+
+ friend class Connection;
+
+private:
+ // Called when one of our connections deletes itself.
+ void OnConnectionDestroyed(Connection* conn);
+
+ // Checks if this port is useless, and hence, should be destroyed.
+ void CheckTimeout();
+
+ static ProxyInfo proxy_;
+};
+
+// Represents a communication link between a port on the local client and a
+// port on the remote client.
+class Connection : public MessageHandler, public sigslot::has_slots<> {
+public:
+ virtual ~Connection();
+
+ // The local port where this connection sends and receives packets.
+ Port* port() { return port_; }
+ const Port* port() const { return port_; }
+
+ // Returns the description of the local port
+ virtual const Candidate& local_candidate() const;
+
+ // Returns the description of the remote port to which we communicate.
+ const Candidate& remote_candidate() const { return remote_candidate_; }
+
+ enum ReadState {
+ STATE_READABLE = 0, // we have received pings recently
+ STATE_READ_TIMEOUT = 1 // we haven't received pings in a while
+ };
+
+ ReadState read_state() const { return read_state_; }
+
+ enum WriteState {
+ STATE_WRITABLE = 0, // we have received ping responses recently
+ STATE_WRITE_CONNECT = 1, // we have had a few ping failures
+ STATE_WRITE_TIMEOUT = 2 // we have had a large number of ping failures
+ };
+
+ WriteState write_state() const { return write_state_; }
+
+ // Determines whether the connection has finished connecting. This can only
+ // be false for TCP connections.
+ bool connected() const { return connected_; }
+
+ // Estimate of the round-trip time over this connection.
+ uint32 rtt() const { return rtt_; }
+
+ size_t sent_total_bytes();
+ size_t sent_bytes_second();
+ size_t recv_total_bytes();
+ size_t recv_bytes_second();
+ sigslot::signal1<Connection*> SignalStateChange;
+
+ // Sent when the connection has decided that it is no longer of value. It
+ // will delete itself immediately after this call.
+ sigslot::signal1<Connection*> SignalDestroyed;
+
+ // The connection can send and receive packets asynchronously. This matches
+ // the interface of AsyncPacketSocket, which may use UDP or TCP under the covers.
+ virtual int Send(const void* data, size_t size) = 0;
+
+ // Error if Send() returns < 0
+ virtual int GetError() = 0;
+
+ sigslot::signal3<Connection*, const char*, size_t> SignalReadPacket;
+
+ // Called when a packet is received on this connection.
+ void OnReadPacket(const char* data, size_t size);
+
+ // Called when a connection is determined to be no longer useful to us. We
+ // still keep it around in case the other side wants to use it. But we can
+ // safely stop pinging on it and we can allow it to time out if the other
+ // side stops using it as well.
+ bool pruned() { return pruned_; }
+ void Prune();
+
+ // Makes the connection go away.
+ void Destroy();
+
+ // Checks that the state of this connection is up-to-date. The argument is
+ // the current time, which is compared against various timeouts.
+ void UpdateState(uint32 now);
+
+ // Called when this connection should try checking writability again.
+ uint32 last_ping_sent() { return last_ping_sent_; }
+ void Ping(uint32 now);
+
+ // Called whenever a valid ping is received on this connection. This is
+ // public because the connection intercepts the first ping for us.
+ void ReceivedPing();
+
+protected:
+ Port* port_;
+ size_t local_candidate_index_;
+ Candidate remote_candidate_;
+ ReadState read_state_;
+ WriteState write_state_;
+ bool connected_;
+ bool pruned_;
+ StunRequestManager requests_;
+ uint32 rtt_;
+ uint32 rtt_data_points_;
+ uint32 last_ping_sent_; // last time we sent a ping to the other side
+ uint32 last_ping_received_; // last time we received a ping from the other side
+ std::vector<uint32> pings_since_last_response_;
+
+ size_t recv_total_bytes_;
+ size_t recv_bytes_second_;
+ uint32 last_recv_bytes_second_time_;
+ size_t last_recv_bytes_second_calc_;
+
+ size_t sent_total_bytes_;
+ size_t sent_bytes_second_;
+ uint32 last_sent_bytes_second_time_;
+ size_t last_sent_bytes_second_calc_;
+
+ // Callbacks from ConnectionRequest
+ void OnConnectionRequestResponse(StunMessage *response, uint32 rtt);
+ void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt);
+
+ // Called back when StunRequestManager has a stun packet to send
+ void OnSendStunPacket(const void* data, size_t size);
+
+ // Constructs a new connection to the given remote port.
+ Connection(Port* port, size_t index, const Candidate& candidate);
+
+ // Changes the state and signals if necessary.
+ void set_read_state(ReadState value);
+ void set_write_state(WriteState value);
+ void set_connected(bool value);
+
+ // Checks if this connection is useless, and hence, should be destroyed.
+ void CheckTimeout();
+
+ void OnMessage(Message *pmsg);
+
+ friend class Port;
+ friend class ConnectionRequest;
+};
+
+// ProxyConnection defers all the interesting work to the port
+
+class ProxyConnection : public Connection {
+public:
+ ProxyConnection(Port* port, size_t index, const Candidate& candidate);
+
+ virtual int Send(const void* data, size_t size);
+ virtual int GetError() { return error_; }
+
+private:
+ int error_;
+};
+
+} // namespace cricket
+
+#endif // __PORT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h
new file mode 100644
index 00000000..3246f29f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/portallocator.h
@@ -0,0 +1,91 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PORTALLOCATOR_H_
+#define _PORTALLOCATOR_H_
+
+#include "talk/base/sigslot.h"
+#include "talk/p2p/base/port.h"
+#include <string>
+#undef SetPort
+
+namespace cricket {
+
+// PortAllocator is responsible for allocating Port types for a given
+// P2PSocket. It also handles port freeing.
+//
+// Clients can override this class to control port allocation, including
+// what kinds of ports are allocated.
+
+class PortAllocatorSession : public sigslot::has_slots<> {
+public:
+ // Prepares an initial set of ports to try.
+ virtual void GetInitialPorts() = 0;
+
+ // Starts and stops the flow of additional ports to try.
+ virtual void StartGetAllPorts() = 0;
+ virtual void StopGetAllPorts() = 0;
+ virtual bool IsGettingAllPorts() = 0;
+
+ sigslot::signal2<PortAllocatorSession*, Port*> SignalPortReady;
+ sigslot::signal2<PortAllocatorSession*, const std::vector<Candidate>&> SignalCandidatesReady;
+
+ uint32 generation() { return generation_; }
+ void set_generation(uint32 generation) { generation_ = generation; }
+
+private:
+ uint32 generation_;
+};
+
+const uint32 PORTALLOCATOR_DISABLE_UDP = 0x01;
+const uint32 PORTALLOCATOR_DISABLE_STUN = 0x02;
+const uint32 PORTALLOCATOR_DISABLE_RELAY = 0x04;
+const uint32 PORTALLOCATOR_DISABLE_TCP = 0x08;
+const uint32 PORTALLOCATOR_ENABLE_SHAKER = 0x10;
+
+const uint32 kDefaultPortAllocatorFlags = 0;
+
+class PortAllocator {
+public:
+ PortAllocator() : flags_(kDefaultPortAllocatorFlags) {}
+
+ virtual PortAllocatorSession *CreateSession(const std::string &name) = 0;
+
+ uint32 flags() const { return flags_; }
+ void set_flags(uint32 flags) { flags_ = flags; }
+
+ const ProxyInfo& proxy() const { return proxy_; }
+ void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; }
+
+protected:
+ uint32 flags_;
+ ProxyInfo proxy_;
+};
+
+} // namespace cricket
+
+#endif // _PORTALLOCATOR_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc
new file mode 100644
index 00000000..4ba12be3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.cc
@@ -0,0 +1,640 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/logging.h"
+#include "talk/base/asynctcpsocket.h"
+#include "talk/p2p/base/relayport.h"
+#include "talk/p2p/base/helpers.h"
+#include <iostream>
+#include <cassert>
+#ifdef OSX
+#include <errno.h>
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+const int KEEPALIVE_DELAY = 10 * 60 * 1000;
+const int RETRY_DELAY = 50; // 50ms, from ICE spec
+const uint32 RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs
+
+const uint32 MSG_DISPOSE_SOCKET = 100; // needs to be more than ID used by Port
+typedef TypedMessageData<AsyncPacketSocket *> DisposeSocketData;
+
+class AsyncTCPSocket;
+
+// Manages a single connection to the relayserver. We aim to use each
+// connection for only a specific destination address so that we can avoid
+// wrapping every packet in a STUN send / data indication.
+class RelayEntry : public sigslot::has_slots<> {
+public:
+ RelayEntry(RelayPort* port, const SocketAddress& ext_addr, const SocketAddress& local_addr);
+ ~RelayEntry();
+
+ RelayPort* port() { return port_; }
+
+ const SocketAddress& address() { return ext_addr_; }
+ void set_address(const SocketAddress& addr) { ext_addr_ = addr; }
+
+ AsyncPacketSocket* socket() { return socket_; }
+
+ bool connected() { return connected_; }
+ void set_connected(bool connected) { connected_ = connected; }
+
+ bool locked() { return locked_; }
+
+ // Returns the last error on the socket of this entry.
+ int GetError() { return socket_->GetError(); }
+
+ // Sends the STUN requests to the server to initiate this connection.
+ void Connect();
+
+ // Called when this entry becomes connected. The address given is the one
+ // exposed to the outside world on the relay server.
+ void OnConnect(const SocketAddress& mapped_addr);
+
+ // Sends a packet to the given destination address using the socket of this
+ // entry. This will wrap the packet in STUN if necessary.
+ int SendTo(const void* data, size_t size, const SocketAddress& addr);
+
+ // Schedules a keep-alive allocate request.
+ void ScheduleKeepAlive();
+
+ void SetServerIndex(size_t sindex) { server_index_ = sindex; }
+ size_t ServerIndex() const { return server_index_; }
+
+ // Try a different server address
+ void HandleConnectFailure();
+
+private:
+ RelayPort* port_;
+ SocketAddress ext_addr_, local_addr_;
+ size_t server_index_;
+ AsyncPacketSocket* socket_;
+ bool connected_;
+ bool locked_;
+ StunRequestManager requests_;
+
+ // Called when a TCP connection is established or fails
+ void OnSocketConnect(AsyncTCPSocket* socket);
+ void OnSocketClose(AsyncTCPSocket* socket, int error);
+
+ // Called when a packet is received on this socket.
+ void OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+ // Called on behalf of a StunRequest to write data to the socket. This is
+ // already STUN intended for the server, so no wrapping is necessary.
+ void OnSendPacket(const void* data, size_t size);
+
+ // Sends the given data on the socket to the server with no wrapping. This
+ // returns the number of bytes written or -1 if an error occurred.
+ int SendPacket(const void* data, size_t size);
+};
+
+// Handles an allocate request for a particular RelayEntry.
+class AllocateRequest : public StunRequest {
+public:
+ AllocateRequest(RelayEntry* entry);
+ virtual ~AllocateRequest() {}
+
+ virtual void Prepare(StunMessage* request);
+
+ virtual int GetNextDelay();
+
+ virtual void OnResponse(StunMessage* response);
+ virtual void OnErrorResponse(StunMessage* response);
+ virtual void OnTimeout();
+
+private:
+ RelayEntry* entry_;
+ uint32 start_time_;
+};
+
+const std::string RELAY_PORT_TYPE("relay");
+
+RelayPort::RelayPort(
+ Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& local_addr, const std::string& username,
+ const std::string& password, const std::string& magic_cookie)
+ : Port(thread, RELAY_PORT_TYPE, factory, network), local_addr_(local_addr),
+ ready_(false), magic_cookie_(magic_cookie), error_(0) {
+
+ entries_.push_back(new RelayEntry(this, SocketAddress(), local_addr_));
+
+ set_username_fragment(username);
+ set_password(password);
+
+ if (magic_cookie_.size() == 0)
+ magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4);
+}
+
+RelayPort::~RelayPort() {
+ for (unsigned i = 0; i < entries_.size(); ++i)
+ delete entries_[i];
+ thread_->Clear(this);
+}
+
+void RelayPort::AddServerAddress(const ProtocolAddress& addr) {
+ // Since HTTP proxies usually only allow 443, let's up the priority on PROTO_SSLTCP
+ if ((addr.proto == PROTO_SSLTCP)
+ && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) {
+ server_addr_.push_front(addr);
+ } else {
+ server_addr_.push_back(addr);
+ }
+}
+
+void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
+ std::string proto_name = ProtoToString(addr.proto);
+ for (std::vector<Candidate>::const_iterator it = candidates().begin(); it != candidates().end(); ++it) {
+ if ((it->address() == addr.address) && (it->protocol() == proto_name)) {
+ LOG(INFO) << "Redundant relay address: " << proto_name << " @ " << addr.address.ToString();
+ return;
+ }
+ }
+ add_address(addr.address, proto_name, false);
+}
+
+void RelayPort::SetReady() {
+ if (!ready_) {
+ ready_ = true;
+ SignalAddressReady(this);
+ }
+}
+
+const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
+ if ((index >= 0) && (index < server_addr_.size()))
+ return &server_addr_[index];
+ return 0;
+}
+
+bool RelayPort::HasMagicCookie(const char* data, size_t size) {
+ if (size < 24 + magic_cookie_.size()) {
+ return false;
+ } else {
+ return 0 == std::memcmp(data + 24,
+ magic_cookie_.c_str(),
+ magic_cookie_.size());
+ }
+}
+
+void RelayPort::PrepareAddress() {
+ // We initiate a connect on the first entry. If this completes, it will fill
+ // in the server address as the address of this port.
+ assert(entries_.size() == 1);
+ entries_[0]->Connect();
+ ready_ = false;
+}
+
+Connection* RelayPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
+ // We only create connections to non-udp sockets if they are incoming on this port
+ if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT))
+ return 0;
+
+ // We don't support loopback on relays
+ if (address.type() == type())
+ return 0;
+
+ size_t index = 0;
+ for (size_t i = 0; i < candidates().size(); ++i) {
+ const Candidate& local = candidates()[i];
+ if (local.protocol() == address.protocol()) {
+ index = i;
+ break;
+ }
+ }
+
+ Connection * conn = new ProxyConnection(this, index, address);
+ AddConnection(conn);
+ return conn;
+}
+
+int RelayPort::SendTo(const void* data,
+ size_t size,
+ const SocketAddress& addr, bool payload) {
+
+ // Try to find an entry for this specific address. Note that the first entry
+ // created was not given an address initially, so it can be set to the first
+ // address that comes along.
+
+ RelayEntry* entry = 0;
+
+ for (unsigned i = 0; i < entries_.size(); ++i) {
+ if (entries_[i]->address().IsAny() && payload) {
+ entry = entries_[i];
+ entry->set_address(addr);
+ break;
+ } else if (entries_[i]->address() == addr) {
+ entry = entries_[i];
+ break;
+ }
+ }
+
+ // If we did not find one, then we make a new one. This will not be useable
+ // until it becomes connected, however.
+ if (!entry && payload) {
+ entry = new RelayEntry(this, addr, local_addr_);
+ if (!entries_.empty()) {
+ // Use the same port to connect to relay server
+ entry->SetServerIndex(entries_[0]->ServerIndex());
+ }
+ entry->Connect();
+ entries_.push_back(entry);
+ }
+
+ // If the entry is connected, then we can send on it (though wrapping may
+ // still be necessary). Otherwise, we can't yet use this connection, so we
+ // default to the first one.
+ if (!entry || !entry->connected()) {
+ assert(!entries_.empty());
+ entry = entries_[0];
+ if (!entry->connected()) {
+ error_ = EWOULDBLOCK;
+ return SOCKET_ERROR;
+ }
+ }
+
+ // Send the actual contents to the server using the usual mechanism.
+ int sent = entry->SendTo(data, size, addr);
+ if (sent <= 0) {
+ assert(sent < 0);
+ error_ = entry->GetError();
+ return SOCKET_ERROR;
+ }
+
+ // The caller of the function is expecting the number of user data bytes,
+ // rather than the size of the packet.
+ return (int)size;
+}
+
+void RelayPort::OnMessage(Message *pmsg) {
+ switch (pmsg->message_id) {
+ case MSG_DISPOSE_SOCKET: {
+ DisposeSocketData * data = static_cast<DisposeSocketData *>(pmsg->pdata);
+ delete data->data();
+ delete data;
+ break; }
+ default:
+ Port::OnMessage(pmsg);
+ }
+}
+
+int RelayPort::SetOption(Socket::Option opt, int value) {
+ int result = 0;
+ for (unsigned i = 0; i < entries_.size(); ++i) {
+ if (entries_[i]->socket()->SetOption(opt, value) < 0) {
+ result = -1;
+ error_ = entries_[i]->socket()->GetError();
+ }
+ }
+ options_.push_back(OptionValue(opt, value));
+ return result;
+}
+
+int RelayPort::GetError() {
+ return error_;
+}
+
+void RelayPort::OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr) {
+ if (Connection* conn = GetConnection(remote_addr)) {
+ conn->OnReadPacket(data, size);
+ } else {
+ Port::OnReadPacket(data, size, remote_addr);
+ }
+}
+
+void RelayPort::DisposeSocket(AsyncPacketSocket * socket) {
+ thread_->Post(this, MSG_DISPOSE_SOCKET, new DisposeSocketData(socket));
+}
+
+RelayEntry::RelayEntry(RelayPort* port, const SocketAddress& ext_addr,
+ const SocketAddress& local_addr)
+ : port_(port), ext_addr_(ext_addr), local_addr_(local_addr), server_index_(0),
+ socket_(0), connected_(false), locked_(false), requests_(port->thread()) {
+
+ requests_.SignalSendPacket.connect(this, &RelayEntry::OnSendPacket);
+}
+
+RelayEntry::~RelayEntry() {
+ delete socket_;
+}
+
+void RelayEntry::Connect() {
+ assert(socket_ == 0);
+ const ProtocolAddress * ra = port()->ServerAddress(server_index_);
+ if (!ra) {
+ LOG(INFO) << "Out of relay server connections";
+ return;
+ }
+
+ LOG(INFO) << "Connecting to relay via " << ProtoToString(ra->proto) << " @ " << ra->address.ToString();
+
+ socket_ = port_->CreatePacketSocket(ra->proto);
+ assert(socket_ != 0);
+
+ socket_->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
+ if (socket_->Bind(local_addr_) < 0)
+ LOG(INFO) << "bind: " << std::strerror(socket_->GetError());
+
+ for (unsigned i = 0; i < port_->options().size(); ++i)
+ socket_->SetOption(port_->options()[i].first, port_->options()[i].second);
+
+ if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
+ AsyncTCPSocket * tcp = static_cast<AsyncTCPSocket *>(socket_);
+ tcp->SignalClose.connect(this, &RelayEntry::OnSocketClose);
+ tcp->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+ tcp->Connect(ra->address);
+ } else {
+ requests_.Send(new AllocateRequest(this));
+ }
+}
+
+void RelayEntry::OnConnect(const SocketAddress& mapped_addr) {
+ ProtocolType proto = PROTO_UDP;
+ LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto) << " @ " << mapped_addr.ToString();
+ connected_ = true;
+
+ port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
+ port_->SetReady();
+}
+
+int RelayEntry::SendTo(const void* data,
+ size_t size,
+ const SocketAddress& addr) {
+
+ // If this connection is locked to the address given, then we can send the
+ // packet with no wrapper.
+ if (locked_ && (ext_addr_ == addr))
+ return SendPacket(data, size);
+
+ // Otherwise, we must wrap the given data in a STUN SEND request so that we
+ // can communicate the destination address to the server.
+ //
+ // Note that we do not use a StunRequest here. This is because there is
+ // likely no reason to resend this packet. If it is late, we just drop it.
+ // The next send to this address will try again.
+
+ StunMessage request;
+ request.SetType(STUN_SEND_REQUEST);
+ request.SetTransactionID(CreateRandomString(16));
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
+ (uint16)port_->magic_cookie().size());
+ request.AddAttribute(magic_cookie_attr);
+
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username_attr->CopyBytes(port_->username_fragment().c_str(),
+ (uint16)port_->username_fragment().size());
+ request.AddAttribute(username_attr);
+
+ StunAddressAttribute* addr_attr =
+ StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ addr_attr->SetFamily(1);
+ addr_attr->SetIP(addr.ip());
+ addr_attr->SetPort(addr.port());
+ request.AddAttribute(addr_attr);
+
+ // Attempt to lock
+ if (ext_addr_ == addr) {
+ StunUInt32Attribute* options_attr =
+ StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
+ options_attr->SetValue(0x1);
+ request.AddAttribute(options_attr);
+ }
+
+ StunByteStringAttribute* data_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_DATA);
+ data_attr->CopyBytes(data, (uint16)size);
+ request.AddAttribute(data_attr);
+
+ // TODO: compute the HMAC.
+
+ ByteBuffer buf;
+ request.Write(&buf);
+
+ return SendPacket(buf.Data(), buf.Length());
+}
+
+void RelayEntry::ScheduleKeepAlive() {
+ requests_.SendDelayed(new AllocateRequest(this), KEEPALIVE_DELAY);
+}
+
+void RelayEntry::HandleConnectFailure() {
+ //if (GetMillisecondCount() - start_time_ > RETRY_TIMEOUT)
+ // return;
+ //ScheduleKeepAlive();
+
+ connected_ = false;
+ port()->DisposeSocket(socket_);
+ socket_ = 0;
+ server_index_ += 1;
+ Connect();
+}
+
+void RelayEntry::OnSocketConnect(AsyncTCPSocket* socket) {
+ assert(socket == socket_);
+ LOG(INFO) << "relay tcp connected to " << socket->GetRemoteAddress().ToString();
+ requests_.Send(new AllocateRequest(this));
+}
+
+void RelayEntry::OnSocketClose(AsyncTCPSocket* socket, int error) {
+ assert(socket == socket_);
+ PLOG(LERROR, error) << "relay tcp connect failed";
+ HandleConnectFailure();
+}
+
+void RelayEntry::OnReadPacket(const char* data,
+ size_t size,
+ const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ assert(socket == socket_);
+ //assert(remote_addr == port_->server_addr()); TODO: are we worried about this?
+
+ // If the magic cookie is not present, then this is an unwrapped packet sent
+ // by the server, The actual remote address is the one we recorded.
+ if (!port_->HasMagicCookie(data, size)) {
+ if (locked_) {
+ port_->OnReadPacket(data, size, ext_addr_);
+ } else {
+ LOG(WARNING) << "Dropping packet: entry not locked";
+ }
+ return;
+ }
+
+ ByteBuffer buf(data, size);
+ StunMessage msg;
+ if (!msg.Read(&buf)) {
+ LOG(INFO) << "Incoming packet was not STUN";
+ return;
+ }
+
+ // The incoming packet should be a STUN ALLOCATE response, SEND response, or
+ // DATA indication.
+ if (requests_.CheckResponse(&msg)) {
+ return;
+ } else if (msg.type() == STUN_SEND_RESPONSE) {
+ if (const StunUInt32Attribute* options_attr = msg.GetUInt32(STUN_ATTR_OPTIONS)) {
+ if (options_attr->value() & 0x1) {
+ locked_ = true;
+ }
+ }
+ return;
+ } else if (msg.type() != STUN_DATA_INDICATION) {
+ LOG(INFO) << "Received BAD stun type from server: " << msg.type()
+ ;
+ return;
+ }
+
+ // This must be a data indication.
+
+ const StunAddressAttribute* addr_attr =
+ msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+ if (!addr_attr) {
+ LOG(INFO) << "Data indication has no source address";
+ return;
+ } else if (addr_attr->family() != 1) {
+ LOG(INFO) << "Source address has bad family";
+ return;
+ }
+
+ SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port());
+
+ const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
+ if (!data_attr) {
+ LOG(INFO) << "Data indication has no data";
+ return;
+ }
+
+ // Process the actual data and remote address in the normal manner.
+ port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2);
+}
+
+void RelayEntry::OnSendPacket(const void* data, size_t size) {
+ SendPacket(data, size);
+}
+
+int RelayEntry::SendPacket(const void* data, size_t size) {
+ const ProtocolAddress * ra = port_->ServerAddress(server_index_);
+ if (!ra) {
+ socket_->SetError(ENOTCONN);
+ return SOCKET_ERROR;
+ }
+ int sent = socket_->SendTo(data, size, ra->address);
+ if (sent <= 0) {
+ LOG(LS_VERBOSE) << "sendto: " << std::strerror(socket_->GetError());
+ assert(sent < 0);
+ }
+ return sent;
+}
+
+AllocateRequest::AllocateRequest(RelayEntry* entry) : entry_(entry) {
+ start_time_ = GetMillisecondCount();
+}
+
+void AllocateRequest::Prepare(StunMessage* request) {
+ request->SetType(STUN_ALLOCATE_REQUEST);
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(
+ entry_->port()->magic_cookie().c_str(),
+ (uint16)entry_->port()->magic_cookie().size());
+ request->AddAttribute(magic_cookie_attr);
+
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username_attr->CopyBytes(
+ entry_->port()->username_fragment().c_str(),
+ (uint16)entry_->port()->username_fragment().size());
+ request->AddAttribute(username_attr);
+}
+
+int AllocateRequest::GetNextDelay() {
+ int delay = 100 * _max(1 << count_, 2);
+ count_ += 1;
+ if (count_ == 5)
+ timeout_ = true;
+ return delay;
+}
+
+void AllocateRequest::OnResponse(StunMessage* response) {
+ const StunAddressAttribute* addr_attr =
+ response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ if (!addr_attr) {
+ LOG(INFO) << "Allocate response missing mapped address.";
+ } else if (addr_attr->family() != 1) {
+ LOG(INFO) << "Mapped address has bad family";
+ } else {
+ SocketAddress addr(addr_attr->ip(), addr_attr->port());
+ entry_->OnConnect(addr);
+ }
+
+ // We will do a keep-alive regardless of whether this request suceeds.
+ // This should have almost no impact on network usage.
+ entry_->ScheduleKeepAlive();
+}
+
+void AllocateRequest::OnErrorResponse(StunMessage* response) {
+ const StunErrorCodeAttribute* attr = response->GetErrorCode();
+ if (!attr) {
+ LOG(INFO) << "Bad allocate response error code";
+ } else {
+ LOG(INFO) << "Allocate error response:"
+ << " code=" << static_cast<int>(attr->error_code())
+ << " reason='" << attr->reason() << "'";
+ }
+
+ if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
+ entry_->ScheduleKeepAlive();
+}
+
+void AllocateRequest::OnTimeout() {
+ LOG(INFO) << "Allocate request timed out";
+ entry_->HandleConnectFailure();
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h
new file mode 100644
index 00000000..7cfdc015
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayport.h
@@ -0,0 +1,93 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RELAYPORT_H__
+#define __RELAYPORT_H__
+
+#include "talk/p2p/base/port.h"
+#include "talk/p2p/base/stunrequest.h"
+#include <vector>
+
+namespace cricket {
+
+extern const std::string RELAY_PORT_TYPE;
+class RelayEntry;
+
+// Communicates using an allocated port on the relay server.
+class RelayPort: public Port {
+public:
+ RelayPort(
+ Thread* thread, SocketFactory* factory, Network*,
+ const SocketAddress& local_addr,
+ const std::string& username, const std::string& password,
+ const std::string& magic_cookie);
+ virtual ~RelayPort();
+
+ void AddServerAddress(const ProtocolAddress& addr);
+ void AddExternalAddress(const ProtocolAddress& addr);
+
+ typedef std::pair<Socket::Option, int> OptionValue;
+ const std::vector<OptionValue>& options() const { return options_; }
+
+ const std::string& magic_cookie() const { return magic_cookie_; }
+ bool HasMagicCookie(const char* data, size_t size);
+
+ virtual void PrepareAddress();
+ virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
+
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError();
+
+ const ProtocolAddress * ServerAddress(size_t index) const;
+
+ void DisposeSocket(AsyncPacketSocket * socket);
+
+protected:
+ void SetReady();
+
+ virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
+ virtual void OnMessage(Message *pmsg);
+
+ // Dispatches the given packet to the port or connection as appropriate.
+ void OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr);
+
+private:
+ friend class RelayEntry;
+
+ SocketAddress local_addr_;
+ std::deque<ProtocolAddress> server_addr_;
+ bool ready_;
+ std::vector<RelayEntry*> entries_;
+ std::vector<OptionValue> options_;
+ std::string magic_cookie_;
+ int error_;
+};
+
+} // namespace cricket
+
+#endif // __RELAYPORT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc
new file mode 100644
index 00000000..bb52a1d5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.cc
@@ -0,0 +1,657 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/p2p/base/relayserver.h"
+#include "talk/p2p/base/helpers.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+// By default, we require a ping every 90 seconds.
+const int MAX_LIFETIME = 15 * 60 * 1000;
+
+// The number of bytes in each of the usernames we use.
+const uint32 USERNAME_LENGTH = 16;
+
+// Calls SendTo on the given socket and logs any bad results.
+void Send(AsyncPacketSocket* socket, const char* bytes, size_t size,
+ const SocketAddress& addr) {
+ int result = socket->SendTo(bytes, size, addr);
+ if (result < int(size)) {
+ std::cerr << "SendTo wrote only " << result << " of " << int(size)
+ << " bytes" << std::endl;
+ } else if (result < 0) {
+ std::cerr << "SendTo: " << std::strerror(errno) << std::endl;
+ }
+}
+
+// Sends the given STUN message on the given socket.
+void SendStun(const StunMessage& msg,
+ AsyncPacketSocket* socket,
+ const SocketAddress& addr) {
+ ByteBuffer buf;
+ msg.Write(&buf);
+ Send(socket, buf.Data(), buf.Length(), addr);
+}
+
+// Constructs a STUN error response and sends it on the given socket.
+void SendStunError(const StunMessage& msg, AsyncPacketSocket* socket,
+ const SocketAddress& remote_addr, int error_code,
+ const char* error_desc, const std::string& magic_cookie) {
+
+ StunMessage err_msg;
+ err_msg.SetType(GetStunErrorResponseType(msg.type()));
+ err_msg.SetTransactionID(msg.transaction_id());
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+ if (magic_cookie.size() == 0)
+ magic_cookie_attr->CopyBytes(cricket::STUN_MAGIC_COOKIE_VALUE, 4);
+ else
+ magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
+ err_msg.AddAttribute(magic_cookie_attr);
+
+ StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
+ err_code->SetErrorClass(error_code / 100);
+ err_code->SetNumber(error_code % 100);
+ err_code->SetReason(error_desc);
+ err_msg.AddAttribute(err_code);
+
+ SendStun(err_msg, socket, remote_addr);
+}
+
+RelayServer::RelayServer(Thread* thread) : thread_(thread) {
+}
+
+RelayServer::~RelayServer() {
+ for (unsigned i = 0; i < internal_sockets_.size(); i++)
+ delete internal_sockets_[i];
+ for (unsigned i = 0; i < external_sockets_.size(); i++)
+ delete external_sockets_[i];
+}
+
+void RelayServer::AddInternalSocket(AsyncPacketSocket* socket) {
+ assert(internal_sockets_.end() ==
+ std::find(internal_sockets_.begin(), internal_sockets_.end(), socket));
+ internal_sockets_.push_back(socket);
+ socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);
+}
+
+void RelayServer::RemoveInternalSocket(AsyncPacketSocket* socket) {
+ SocketList::iterator iter =
+ std::find(internal_sockets_.begin(), internal_sockets_.end(), socket);
+ assert(iter != internal_sockets_.end());
+ internal_sockets_.erase(iter);
+ socket->SignalReadPacket.disconnect(this);
+}
+
+void RelayServer::AddExternalSocket(AsyncPacketSocket* socket) {
+ assert(external_sockets_.end() ==
+ std::find(external_sockets_.begin(), external_sockets_.end(), socket));
+ external_sockets_.push_back(socket);
+ socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);
+}
+
+void RelayServer::RemoveExternalSocket(AsyncPacketSocket* socket) {
+ SocketList::iterator iter =
+ std::find(external_sockets_.begin(), external_sockets_.end(), socket);
+ assert(iter != external_sockets_.end());
+ external_sockets_.erase(iter);
+ socket->SignalReadPacket.disconnect(this);
+}
+
+void RelayServer::OnInternalPacket(
+ const char* bytes, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+
+ // Get the address of the connection we just received on.
+ SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
+ assert(!ap.destination().IsAny());
+
+ // If this did not come from an existing connection, it should be a STUN
+ // allocate request.
+ ConnectionMap::iterator piter = connections_.find(ap);
+ if (piter == connections_.end()) {
+ HandleStunAllocate(bytes, size, ap, socket);
+ return;
+ }
+
+ RelayServerConnection* int_conn = piter->second;
+
+ // Handle STUN requests to the server itself.
+ if (int_conn->binding()->HasMagicCookie(bytes, size)) {
+ HandleStun(int_conn, bytes, size);
+ return;
+ }
+
+ // Otherwise, this is a non-wrapped packet that we are to forward. Make sure
+ // that this connection has been locked. (Otherwise, we would not know what
+ // address to forward to.)
+ if (!int_conn->locked()) {
+ std::cerr << "Dropping packet: connection not locked" << std::endl;
+ return;
+ }
+
+ // Forward this to the destination address into the connection.
+ RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(
+ int_conn->default_destination());
+ if (ext_conn) {
+ // TODO: Check the HMAC.
+ ext_conn->Send(bytes, size);
+ } else {
+ // This happens very often and is not an error.
+ //std::cerr << "Dropping packet: no external connection" << std::endl;
+ }
+}
+
+void RelayServer::OnExternalPacket(
+ const char* bytes, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+
+ // Get the address of the connection we just received on.
+ SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
+ assert(!ap.destination().IsAny());
+
+ // If this connection already exists, then forward the traffic.
+ ConnectionMap::iterator piter = connections_.find(ap);
+ if (piter != connections_.end()) {
+ // TODO: Check the HMAC.
+ RelayServerConnection* ext_conn = piter->second;
+ RelayServerConnection* int_conn =
+ ext_conn->binding()->GetInternalConnection(
+ ext_conn->addr_pair().source());
+ assert(int_conn);
+ int_conn->Send(bytes, size, ext_conn->addr_pair().source());
+ return;
+ }
+
+ // The first packet should always be a STUN / TURN packet. If it isn't, then
+ // we should just ignore this packet.
+ StunMessage msg;
+ ByteBuffer buf = ByteBuffer(bytes, size);
+ if (!msg.Read(&buf)) {
+ std::cerr << "Dropping packet: first packet not STUN" << std::endl;
+ return;
+ }
+
+ // The initial packet should have a username (which identifies the binding).
+ const StunByteStringAttribute* username_attr =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ if (!username_attr) {
+ std::cerr << "Dropping packet: no username" << std::endl;
+ return;
+ }
+
+ uint32 length = _min(uint32(username_attr->length()), USERNAME_LENGTH);
+ std::string username(username_attr->bytes(), length);
+ // TODO: Check the HMAC.
+
+ // The binding should already be present.
+ BindingMap::iterator biter = bindings_.find(username);
+ if (biter == bindings_.end()) {
+ // TODO: Turn this back on. This is the sign of a client bug.
+ //std::cerr << "Dropping packet: no binding with username" << std::endl;
+ return;
+ }
+
+ // Add this authenticted connection to the binding.
+ RelayServerConnection* ext_conn =
+ new RelayServerConnection(biter->second, ap, socket);
+ ext_conn->binding()->AddExternalConnection(ext_conn);
+ AddConnection(ext_conn);
+
+ // We always know where external packets should be forwarded, so we can lock
+ // them from the beginning.
+ ext_conn->Lock();
+
+ // Send this message on the appropriate internal connection.
+ RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(
+ ext_conn->addr_pair().source());
+ assert(int_conn);
+ int_conn->Send(bytes, size, ext_conn->addr_pair().source());
+}
+
+bool RelayServer::HandleStun(
+ const char* bytes, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket, std::string* username, StunMessage* msg) {
+
+ // Parse this into a stun message.
+ ByteBuffer buf = ByteBuffer(bytes, size);
+ if (!msg->Read(&buf)) {
+ SendStunError(*msg, socket, remote_addr, 400, "Bad Request", "");
+ return false;
+ }
+
+ // The initial packet should have a username (which identifies the binding).
+ const StunByteStringAttribute* username_attr =
+ msg->GetByteString(STUN_ATTR_USERNAME);
+ if (!username_attr) {
+ SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");
+ return false;
+ }
+
+ // Record the username if requested.
+ if (username)
+ username->append(username_attr->bytes(), username_attr->length());
+
+ // TODO: Check for unknown attributes (<= 0x7fff)
+
+ return true;
+}
+
+void RelayServer::HandleStunAllocate(
+ const char* bytes, size_t size, const SocketAddressPair& ap,
+ AsyncPacketSocket* socket) {
+
+ // Make sure this is a valid STUN request.
+ StunMessage request;
+ std::string username;
+ if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))
+ return;
+
+ // Make sure this is a an allocate request.
+ if (request.type() != STUN_ALLOCATE_REQUEST) {
+ SendStunError(request,
+ socket,
+ ap.source(),
+ 600,
+ "Operation Not Supported",
+ "");
+ return;
+ }
+
+ // TODO: Check the HMAC.
+
+ // Find or create the binding for this username.
+
+ RelayServerBinding* binding;
+
+ BindingMap::iterator biter = bindings_.find(username);
+ if (biter != bindings_.end()) {
+
+ binding = biter->second;
+
+ } else {
+
+ // NOTE: In the future, bindings will be created by the bot only. This
+ // else-branch will then disappear.
+
+ // Compute the appropriate lifetime for this binding.
+ uint32 lifetime = MAX_LIFETIME;
+ const StunUInt32Attribute* lifetime_attr =
+ request.GetUInt32(STUN_ATTR_LIFETIME);
+ if (lifetime_attr)
+ lifetime = _min(lifetime, lifetime_attr->value() * 1000);
+
+ binding = new RelayServerBinding(this, username, "0", lifetime);
+ binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);
+ bindings_[username] = binding;
+
+ std::cout << "Added new binding: " << bindings_.size() << " total" << std::endl;
+ }
+
+ // Add this connection to the binding. It starts out unlocked.
+ RelayServerConnection* int_conn =
+ new RelayServerConnection(binding, ap, socket);
+ binding->AddInternalConnection(int_conn);
+ AddConnection(int_conn);
+
+ // Now that we have a connection, this other method takes over.
+ HandleStunAllocate(int_conn, request);
+}
+
+void RelayServer::HandleStun(
+ RelayServerConnection* int_conn, const char* bytes, size_t size) {
+
+ // Make sure this is a valid STUN request.
+ StunMessage request;
+ std::string username;
+ if (!HandleStun(bytes, size, int_conn->addr_pair().source(),
+ int_conn->socket(), &username, &request))
+ return;
+
+ // Make sure the username is the one were were expecting.
+ if (username != int_conn->binding()->username()) {
+ int_conn->SendStunError(request, 430, "Stale Credentials");
+ return;
+ }
+
+ // TODO: Check the HMAC.
+
+ // Send this request to the appropriate handler.
+ if (request.type() == STUN_SEND_REQUEST)
+ HandleStunSend(int_conn, request);
+ else if (request.type() == STUN_ALLOCATE_REQUEST)
+ HandleStunAllocate(int_conn, request);
+ else
+ int_conn->SendStunError(request, 600, "Operation Not Supported");
+}
+
+void RelayServer::HandleStunAllocate(
+ RelayServerConnection* int_conn, const StunMessage& request) {
+
+ // Create a response message that includes an address with which external
+ // clients can communicate.
+
+ StunMessage response;
+ response.SetType(STUN_ALLOCATE_RESPONSE);
+ response.SetTransactionID(request.transaction_id());
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
+ int_conn->binding()->magic_cookie().size());
+ response.AddAttribute(magic_cookie_attr);
+
+ size_t index = rand() % external_sockets_.size();
+ SocketAddress ext_addr = external_sockets_[index]->GetLocalAddress();
+
+ StunAddressAttribute* addr_attr =
+ StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ addr_attr->SetFamily(1);
+ addr_attr->SetIP(ext_addr.ip());
+ addr_attr->SetPort(ext_addr.port());
+ response.AddAttribute(addr_attr);
+
+ StunUInt32Attribute* res_lifetime_attr =
+ StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
+ res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000);
+ response.AddAttribute(res_lifetime_attr);
+
+ // TODO: Support transport-prefs (preallocate RTCP port).
+ // TODO: Support bandwidth restrictions.
+ // TODO: Add message integrity check.
+
+ // Send a response to the caller.
+ int_conn->SendStun(response);
+}
+
+void RelayServer::HandleStunSend(
+ RelayServerConnection* int_conn, const StunMessage& request) {
+
+ const StunAddressAttribute* addr_attr =
+ request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ if (!addr_attr) {
+ int_conn->SendStunError(request, 400, "Bad Request");
+ return;
+ }
+
+ const StunByteStringAttribute* data_attr =
+ request.GetByteString(STUN_ATTR_DATA);
+ if (!data_attr) {
+ int_conn->SendStunError(request, 400, "Bad Request");
+ return;
+ }
+
+ SocketAddress ext_addr(addr_attr->ip(), addr_attr->port());
+ RelayServerConnection* ext_conn =
+ int_conn->binding()->GetExternalConnection(ext_addr);
+ if (!ext_conn) {
+ // This happens very often and is not an error.
+ //std::cerr << "Dropping packet: no external connection" << std::endl;
+ return;
+ }
+
+ ext_conn->Send(data_attr->bytes(), data_attr->length());
+
+ const StunUInt32Attribute* options_attr =
+ request.GetUInt32(STUN_ATTR_OPTIONS);
+ if (options_attr && (options_attr->value() & 0x01 != 0)) {
+ int_conn->set_default_destination(ext_addr);
+ int_conn->Lock();
+
+ StunMessage response;
+ response.SetType(STUN_SEND_RESPONSE);
+ response.SetTransactionID(request.transaction_id());
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
+ int_conn->binding()->magic_cookie().size());
+ response.AddAttribute(magic_cookie_attr);
+
+ StunUInt32Attribute* options2_attr =
+ StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS);
+ options2_attr->SetValue(0x01);
+ response.AddAttribute(options2_attr);
+
+ int_conn->SendStun(response);
+ }
+}
+
+void RelayServer::AddConnection(RelayServerConnection* conn) {
+ assert(connections_.find(conn->addr_pair()) == connections_.end());
+ connections_[conn->addr_pair()] = conn;
+}
+
+void RelayServer::RemoveConnection(RelayServerConnection* conn) {
+ ConnectionMap::iterator iter = connections_.find(conn->addr_pair());
+ assert(iter != connections_.end());
+ connections_.erase(iter);
+}
+
+void RelayServer::RemoveBinding(RelayServerBinding* binding) {
+ BindingMap::iterator iter = bindings_.find(binding->username());
+ assert(iter != bindings_.end());
+ bindings_.erase(iter);
+
+ std::cout << "Removed a binding: " << bindings_.size() << " remaining" << std::endl;
+}
+
+void RelayServer::OnTimeout(RelayServerBinding* binding) {
+ // This call will result in all of the necessary clean-up.
+ delete binding;
+}
+
+RelayServerConnection::RelayServerConnection(
+ RelayServerBinding* binding, const SocketAddressPair& addrs,
+ AsyncPacketSocket* socket)
+ : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) {
+
+ // The creation of a new connection constitutes a use of the binding.
+ binding_->NoteUsed();
+}
+
+RelayServerConnection::~RelayServerConnection() {
+ // Remove this connection from the server's map (if it exists there).
+ binding_->server()->RemoveConnection(this);
+}
+
+void RelayServerConnection::Send(const char* data, size_t size) {
+ // Note that the binding has been used again.
+ binding_->NoteUsed();
+
+ cricket::Send(socket_, data, size, addr_pair_.source());
+}
+
+void RelayServerConnection::Send(
+ const char* data, size_t size, const SocketAddress& from_addr) {
+ // If the from address is known to the client, we don't need to send it.
+ if (locked() && (from_addr == default_dest_)) {
+ Send(data, size);
+ return;
+ }
+
+ // Wrap the given data in a data-indication packet.
+
+ StunMessage msg;
+ msg.SetType(STUN_DATA_INDICATION);
+ msg.SetTransactionID("0000000000000000");
+
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(),
+ binding_->magic_cookie().size());
+ msg.AddAttribute(magic_cookie_attr);
+
+ StunAddressAttribute* addr_attr =
+ StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
+ addr_attr->SetFamily(1);
+ addr_attr->SetIP(from_addr.ip());
+ addr_attr->SetPort(from_addr.port());
+ msg.AddAttribute(addr_attr);
+
+ StunByteStringAttribute* data_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_DATA);
+ assert(size <= 65536);
+ data_attr->CopyBytes(data, uint16(size));
+ msg.AddAttribute(data_attr);
+
+ SendStun(msg);
+}
+
+void RelayServerConnection::SendStun(const StunMessage& msg) {
+ // Note that the binding has been used again.
+ binding_->NoteUsed();
+
+ cricket::SendStun(msg, socket_, addr_pair_.source());
+}
+
+void RelayServerConnection::SendStunError(
+ const StunMessage& request, int error_code, const char* error_desc) {
+ // An error does not indicate use. If no legitimate use off the binding
+ // occurs, we want it to be cleaned up even if errors are still occuring.
+
+ cricket::SendStunError(
+ request, socket_, addr_pair_.source(), error_code, error_desc,
+ binding_->magic_cookie());
+}
+
+void RelayServerConnection::Lock() {
+ locked_ = true;
+}
+
+void RelayServerConnection::Unlock() {
+ locked_ = false;
+}
+
+// IDs used for posted messages:
+const uint32 MSG_LIFETIME_TIMER = 1;
+
+RelayServerBinding::RelayServerBinding(
+ RelayServer* server, const std::string& username,
+ const std::string& password, uint32 lifetime)
+ : server_(server), username_(username), password_(password),
+ lifetime_(lifetime) {
+
+ // For now, every connection uses the standard magic cookie value.
+ magic_cookie_.append(
+ reinterpret_cast<const char*>(STUN_MAGIC_COOKIE_VALUE), 4);
+
+ // Initialize the last-used time to now.
+ NoteUsed();
+
+ // Set the first timeout check.
+ server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
+}
+
+RelayServerBinding::~RelayServerBinding() {
+ // Clear the outstanding timeout check.
+ server_->thread()->Clear(this);
+
+ // Clean up all of the connections.
+ for (size_t i = 0; i < internal_connections_.size(); ++i)
+ delete internal_connections_[i];
+ for (size_t i = 0; i < external_connections_.size(); ++i)
+ delete external_connections_[i];
+
+ // Remove this binding from the server's map.
+ server_->RemoveBinding(this);
+}
+
+void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
+ internal_connections_.push_back(conn);
+}
+
+void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
+ external_connections_.push_back(conn);
+}
+
+void RelayServerBinding::NoteUsed() {
+ last_used_ = GetMillisecondCount();
+}
+
+bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
+ if (size < 24 + magic_cookie_.size()) {
+ return false;
+ } else {
+ return 0 == std::memcmp(
+ bytes + 24, magic_cookie_.c_str(), magic_cookie_.size());
+ }
+}
+
+RelayServerConnection* RelayServerBinding::GetInternalConnection(
+ const SocketAddress& ext_addr) {
+
+ // Look for an internal connection that is locked to this address.
+ for (size_t i = 0; i < internal_connections_.size(); ++i) {
+ if (internal_connections_[i]->locked() &&
+ (ext_addr == internal_connections_[i]->default_destination()))
+ return internal_connections_[i];
+ }
+
+ // If one was not found, we send to the first connection.
+ assert(internal_connections_.size() > 0);
+ return internal_connections_[0];
+}
+
+RelayServerConnection* RelayServerBinding::GetExternalConnection(
+ const SocketAddress& ext_addr) {
+ for (size_t i = 0; i < external_connections_.size(); ++i) {
+ if (ext_addr == external_connections_[i]->addr_pair().source())
+ return external_connections_[i];
+ }
+ return 0;
+}
+
+void RelayServerBinding::OnMessage(Message *pmsg) {
+ if (pmsg->message_id == MSG_LIFETIME_TIMER) {
+ assert(!pmsg->pdata);
+
+ // If the lifetime timeout has been exceeded, then send a signal.
+ // Otherwise, just keep waiting.
+ if (GetMillisecondCount() >= last_used_ + lifetime_) {
+ SignalTimeout(this);
+ } else {
+ server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
+ }
+
+ } else {
+ assert(false);
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h
new file mode 100644
index 00000000..01dc3678
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.h
@@ -0,0 +1,210 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RELAYSERVER_H__
+#define __RELAYSERVER_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/socketaddresspair.h"
+#include "talk/base/thread.h"
+#include "talk/base/jtime.h"
+#include "talk/p2p/base/stun.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace cricket {
+
+class RelayServerBinding;
+class RelayServerConnection;
+
+// Relays traffic between connections to the server that are "bound" together.
+// All connections created with the same username/password are bound together.
+class RelayServer : public sigslot::has_slots<> {
+public:
+ // Creates a server, which will use this thread to post messages to itself.
+ RelayServer(Thread* thread);
+ ~RelayServer();
+
+ Thread* thread() { return thread_; }
+
+ // Updates the set of sockets that the server uses to talk to "internal"
+ // clients. These are clients that do the "port allocations".
+ void AddInternalSocket(AsyncPacketSocket* socket);
+ void RemoveInternalSocket(AsyncPacketSocket* socket);
+
+ // Updates the set of sockets that the server uses to talk to "external"
+ // clients. These are the clients that do not do allocations. They do not
+ // know that these addresses represent a relay server.
+ void AddExternalSocket(AsyncPacketSocket* socket);
+ void RemoveExternalSocket(AsyncPacketSocket* socket);
+
+private:
+ typedef std::vector<AsyncPacketSocket*> SocketList;
+ typedef std::map<std::string,RelayServerBinding*> BindingMap;
+ typedef std::map<SocketAddressPair,RelayServerConnection*> ConnectionMap;
+
+ Thread* thread_;
+ SocketList internal_sockets_;
+ SocketList external_sockets_;
+ BindingMap bindings_;
+ ConnectionMap connections_;
+
+ // Called when a packet is received by the server on one of its sockets.
+ void OnInternalPacket(
+ const char* bytes, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+ void OnExternalPacket(
+ const char* bytes, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+ // Processes the relevant STUN request types from the client.
+ bool HandleStun(const char* bytes, size_t size,
+ const SocketAddress& remote_addr, AsyncPacketSocket* socket,
+ std::string* username, StunMessage* msg);
+ void HandleStunAllocate(const char* bytes, size_t size,
+ const SocketAddressPair& ap,
+ AsyncPacketSocket* socket);
+ void HandleStun(RelayServerConnection* int_conn, const char* bytes,
+ size_t size);
+ void HandleStunAllocate(RelayServerConnection* int_conn,
+ const StunMessage& msg);
+ void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg);
+
+ // Adds/Removes the a connection or binding.
+ void AddConnection(RelayServerConnection* conn);
+ void RemoveConnection(RelayServerConnection* conn);
+ void RemoveBinding(RelayServerBinding* binding);
+
+ // Called when the timer for checking lifetime times out.
+ void OnTimeout(RelayServerBinding* binding);
+
+ friend class RelayServerConnection;
+ friend class RelayServerBinding;
+};
+
+// Maintains information about a connection to the server. Each connection is
+// part of one and only one binding.
+class RelayServerConnection {
+public:
+ RelayServerConnection(RelayServerBinding* binding,
+ const SocketAddressPair& addrs,
+ AsyncPacketSocket* socket);
+ ~RelayServerConnection();
+
+ RelayServerBinding* binding() { return binding_; }
+ AsyncPacketSocket* socket() { return socket_; }
+
+ // Returns a pair where the source is the remote address and the destination
+ // is the local address.
+ const SocketAddressPair& addr_pair() { return addr_pair_; }
+
+ // Sends a packet to the connected client. If an address is provided, then
+ // we make sure the internal client receives it, wrapping if necessary.
+ void Send(const char* data, size_t size);
+ void Send(const char* data, size_t size, const SocketAddress& ext_addr);
+
+ // Sends a STUN message to the connected client with no wrapping.
+ void SendStun(const StunMessage& msg);
+ void SendStunError(const StunMessage& request, int code, const char* desc);
+
+ // A locked connection is one for which we know the intended destination of
+ // any raw packet received.
+ bool locked() const { return locked_; }
+ void Lock();
+ void Unlock();
+
+ // Records the address that raw packets should be forwarded to (for internal
+ // packets only; for external, we already know where they go).
+ const SocketAddress& default_destination() const { return default_dest_; }
+ void set_default_destination(const SocketAddress& addr) {
+ default_dest_ = addr;
+ }
+
+private:
+ RelayServerBinding* binding_;
+ SocketAddressPair addr_pair_;
+ AsyncPacketSocket* socket_;
+ bool locked_;
+ SocketAddress default_dest_;
+};
+
+// Records a set of internal and external connections that we relay between,
+// or in other words, that are "bound" together.
+class RelayServerBinding : public MessageHandler {
+public:
+ RelayServerBinding(
+ RelayServer* server, const std::string& username,
+ const std::string& password, uint32 lifetime);
+ virtual ~RelayServerBinding();
+
+ RelayServer* server() { return server_; }
+ uint32 lifetime() { return lifetime_; }
+ const std::string& username() { return username_; }
+ const std::string& password() { return password_; }
+ const std::string& magic_cookie() { return magic_cookie_; }
+
+ // Adds/Removes a connection into the binding.
+ void AddInternalConnection(RelayServerConnection* conn);
+ void AddExternalConnection(RelayServerConnection* conn);
+
+ // We keep track of the use of each binding. If we detect that it was not
+ // used for longer than the lifetime, then we send a signal.
+ void NoteUsed();
+ sigslot::signal1<RelayServerBinding*> SignalTimeout;
+
+ // Determines whether the given packet has the magic cookie present (in the
+ // right place).
+ bool HasMagicCookie(const char* bytes, size_t size) const;
+
+ // Determines the connection to use to send packets to or from the given
+ // external address.
+ RelayServerConnection* GetInternalConnection(const SocketAddress& ext_addr);
+ RelayServerConnection* GetExternalConnection(const SocketAddress& ext_addr);
+
+ // MessageHandler:
+ void OnMessage(Message *pmsg);
+
+private:
+ RelayServer* server_;
+
+ std::string username_;
+ std::string password_;
+ std::string magic_cookie_;
+
+ std::vector<RelayServerConnection*> internal_connections_;
+ std::vector<RelayServerConnection*> external_connections_;
+
+ uint32 lifetime_;
+ uint32 last_used_;
+ // TODO: bandwidth
+};
+
+} // namespace cricket
+
+#endif // __RELAYSERVER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro
new file mode 100644
index 00000000..41bc6b63
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+INCLUDEPATH = ../../..
+DEFINES += POSIX
+
+include(../../../../../conf.pri)
+
+# Input
+SOURCES += \
+ relayserver.cc \
+ relayserver_main.cc \
+ ../../base/host.cc \
+ ../../base/socketaddresspair.cc
+
+LIBS += ../../../liblibjingle.a
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc
new file mode 100644
index 00000000..5f624f37
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc
@@ -0,0 +1,75 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/host.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/base/relayserver.h"
+#include <iostream>
+#include <assert.h>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+using namespace cricket;
+
+int main(int argc, char **argv) {
+ if (argc != 1) {
+ std::cerr << "usage: relayserver" << std::endl;
+ return 1;
+ }
+
+ assert(LocalHost().networks().size() >= 2);
+ SocketAddress int_addr(LocalHost().networks()[1]->ip(), 5000);
+ SocketAddress ext_addr(LocalHost().networks()[1]->ip(), 5001);
+
+ Thread *pthMain = Thread::Current();
+
+ AsyncUDPSocket* int_socket = CreateAsyncUDPSocket(pthMain->socketserver());
+ if (int_socket->Bind(int_addr) < 0) {
+ std::cerr << "bind: " << std::strerror(errno) << std::endl;
+ return 1;
+ }
+
+ AsyncUDPSocket* ext_socket = CreateAsyncUDPSocket(pthMain->socketserver());
+ if (ext_socket->Bind(ext_addr) < 0) {
+ std::cerr << "bind: " << std::strerror(errno) << std::endl;
+ return 1;
+ }
+
+ RelayServer server(pthMain);
+ server.AddInternalSocket(int_socket);
+ server.AddExternalSocket(ext_socket);
+
+ std::cout << "Listening internally at " << int_addr.ToString() << std::endl;
+ std::cout << "Listening externally at " << ext_addr.ToString() << std::endl;
+
+ pthMain->Loop();
+ return 0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc
new file mode 100644
index 00000000..73873338
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.cc
@@ -0,0 +1,421 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/p2p/base/session.h"
+
+namespace cricket {
+
+const uint32 MSG_TIMEOUT = 1;
+const uint32 MSG_ERROR = 2;
+const uint32 MSG_STATE = 3;
+
+Session::Session(SessionManager *session_manager, const std::string &name,
+ const SessionID& id) {
+ session_manager_ = session_manager;
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+ name_ = name;
+ id_ = id;
+ error_ = ERROR_NONE;
+ state_ = STATE_INIT;
+ initiator_ = false;
+ description_ = NULL;
+ remote_description_ = NULL;
+ socket_manager_ = new SocketManager(session_manager_);
+ socket_manager_->SignalCandidatesReady.connect(this, &Session::OnCandidatesReady);
+ socket_manager_->SignalNetworkError.connect(this, &Session::OnNetworkError);
+ socket_manager_->SignalState.connect(this, &Session::OnSocketState);
+ socket_manager_->SignalRequestSignaling.connect(this, &Session::OnRequestSignaling);
+}
+
+Session::~Session() {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+ delete description_;
+ delete remote_description_;
+ delete socket_manager_;
+ session_manager_->signaling_thread()->Clear(this);
+}
+
+P2PSocket *Session::CreateSocket(const std::string &name) {
+ return socket_manager_->CreateSocket(name);
+}
+
+void Session::DestroySocket(P2PSocket *socket) {
+ socket_manager_->DestroySocket(socket);
+}
+
+void Session::OnCandidatesReady(const std::vector<Candidate>& candidates) {
+ SendSessionMessage(SessionMessage::TYPE_CANDIDATES, NULL, &candidates, NULL);
+}
+
+void Session::OnNetworkError() {
+ // Socket manager is experiencing a network error trying to allocate
+ // network resources (usually port allocation)
+
+ set_error(ERROR_NETWORK);
+}
+
+void Session::OnSocketState() {
+ // If the call is not in progress, then we don't care about writability.
+ // We have separate timers for making sure we transition back to the in-
+ // progress state in time.
+ if (state_ != STATE_INPROGRESS)
+ return;
+
+ // Put the timer into the write state. This is called when the state changes,
+ // so we will restart the timer each time we lose writability.
+ if (socket_manager_->writable()) {
+ session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
+ } else {
+ session_manager_->signaling_thread()->PostDelayed(
+ session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
+ }
+}
+
+void Session::OnRequestSignaling() {
+ SignalRequestSignaling();
+}
+
+void Session::OnSignalingReady() {
+ socket_manager_->OnSignalingReady();
+}
+
+void Session::SendSessionMessage(SessionMessage::Type type,
+ const SessionDescription* description,
+ const std::vector<Candidate>* candidates,
+ SessionMessage::Cookie* redirect_cookie) {
+ SessionMessage m;
+ m.set_type(type);
+ m.set_to(remote_address_);
+ m.set_name(name_);
+ m.set_description(description);
+ m.set_session_id(id_);
+ if (candidates)
+ m.set_candidates(*candidates);
+ m.set_redirect_target(redirect_target_);
+ m.set_redirect_cookie(redirect_cookie);
+ SignalOutgoingMessage(this, m);
+}
+
+bool Session::Initiate(const std::string &to, const SessionDescription *description) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Only from STATE_INIT
+ if (state_ != STATE_INIT)
+ return false;
+
+ // Setup for signaling. Initiate is asynchronous. It occurs once the address
+ // candidates are ready.
+ initiator_ = true;
+ remote_address_ = to;
+ description_ = description;
+ SendSessionMessage(SessionMessage::TYPE_INITIATE, description, NULL, NULL);
+ set_state(Session::STATE_SENTINITIATE);
+
+ // Let the socket manager know we now want the candidates
+ socket_manager_->StartProcessingCandidates();
+
+ // Start the session timeout
+ session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
+ session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
+ return true;
+}
+
+bool Session::Accept(const SessionDescription *description) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Only if just received initiate
+ if (state_ != STATE_RECEIVEDINITIATE)
+ return false;
+
+ // Setup for signaling. Accept is asynchronous. It occurs once the address
+ // candidates are ready.
+ initiator_ = false;
+ description_ = description;
+ SendSessionMessage(SessionMessage::TYPE_ACCEPT, description, NULL, NULL);
+ set_state(Session::STATE_SENTACCEPT);
+
+ return true;
+}
+
+bool Session::Modify(const SessionDescription *description) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Only if session already STATE_INPROGRESS
+ if (state_ != STATE_INPROGRESS)
+ return false;
+
+ // Modify is asynchronous. It occurs once the address candidates are ready.
+ // Either side can send a modify. It is only valid in an already accepted
+ // session.
+ description_ = description;
+ SendSessionMessage(SessionMessage::TYPE_MODIFY, description, NULL, NULL);
+ set_state(Session::STATE_SENTMODIFY);
+
+ // Start the session timeout
+ session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
+ session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
+ return true;
+}
+
+bool Session::Redirect(const std::string& target) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Redirect is sent in response to an initiate or modify, to redirect the
+ // request
+ if (state_ != STATE_RECEIVEDINITIATE)
+ return false;
+
+ initiator_ = false;
+ redirect_target_ = target;
+ SendSessionMessage(SessionMessage::TYPE_REDIRECT, NULL, NULL, NULL);
+
+ // A redirect puts us in the same state as reject. It just sends a different
+ // kind of reject message, if you like.
+ set_state(STATE_SENTREDIRECT);
+
+ return true;
+}
+
+bool Session::Reject() {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Reject is sent in response to an initiate or modify, to reject the
+ // request
+ if (state_ != STATE_RECEIVEDINITIATE && state_ != STATE_RECEIVEDMODIFY)
+ return false;
+
+ initiator_ = false;
+ SendSessionMessage(SessionMessage::TYPE_REJECT, NULL, NULL, NULL);
+ set_state(STATE_SENTREJECT);
+
+ return true;
+}
+
+bool Session::Terminate() {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // Either side can terminate, at any time.
+ if (state_ == STATE_SENTTERMINATE && state_ != STATE_RECEIVEDTERMINATE)
+ return false;
+
+ // But we don't need to terminate if we already rejected. The other client
+ // already knows that we're done with this session.
+ if (state_ != STATE_SENTREDIRECT)
+ SendSessionMessage(SessionMessage::TYPE_TERMINATE, NULL, NULL, NULL);
+
+ set_state(STATE_SENTTERMINATE);
+
+ return true;
+}
+
+void Session::OnIncomingError(const SessionMessage &m) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ // If a candidate message errors out or gets dropped for some reason we
+ // ignore the error.
+ if (m.type() != SessionMessage::TYPE_CANDIDATES) {
+ set_error(ERROR_RESPONSE);
+ }
+}
+
+void Session::OnIncomingMessage(const SessionMessage &m) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+
+ switch (m.type()) {
+ case SessionMessage::TYPE_INITIATE:
+ remote_description_ = m.description();
+ remote_address_ = m.from();
+ name_ = m.name();
+ initiator_ = false;
+ set_state(STATE_RECEIVEDINITIATE);
+
+ // Let the socket manager know we now want the initial candidates
+ socket_manager_->StartProcessingCandidates();
+ break;
+
+ case SessionMessage::TYPE_ACCEPT:
+ remote_description_ = m.description();
+ set_state(STATE_RECEIVEDACCEPT);
+ break;
+
+ case SessionMessage::TYPE_MODIFY:
+ remote_description_ = m.description();
+ set_state(STATE_RECEIVEDMODIFY);
+ break;
+
+ case SessionMessage::TYPE_CANDIDATES:
+ socket_manager_->AddRemoteCandidates(m.candidates());
+ break;
+
+ case SessionMessage::TYPE_REJECT:
+ set_state(STATE_RECEIVEDREJECT);
+ break;
+
+ case SessionMessage::TYPE_REDIRECT:
+ OnRedirectMessage(m);
+ break;
+
+ case SessionMessage::TYPE_TERMINATE:
+ set_state(STATE_RECEIVEDTERMINATE);
+ break;
+ }
+}
+
+void Session::OnRedirectMessage(const SessionMessage &m) {
+ ASSERT(state_ == STATE_SENTINITIATE);
+ if (state_ != STATE_SENTINITIATE)
+ return;
+
+ ASSERT(m.redirect_target().size() != 0);
+ remote_address_ = m.redirect_target();
+
+ SendSessionMessage(SessionMessage::TYPE_INITIATE, description_, NULL,
+ m.redirect_cookie()->Copy());
+
+ // Restart the session timeout.
+ session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
+ session_manager_->signaling_thread()->PostDelayed(session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
+
+ // Reset all of the sockets back into the initial state.
+ socket_manager_->ResetSockets();
+}
+
+Session::State Session::state() {
+ return state_;
+}
+
+void Session::set_state(State state) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+ if (state != state_) {
+ state_ = state;
+ SignalState(this, state);
+ session_manager_->signaling_thread()->Post(this, MSG_STATE);
+ }
+}
+
+Session::Error Session::error() {
+ return error_;
+}
+
+void Session::set_error(Error error) {
+ ASSERT(session_manager_->signaling_thread()->IsCurrent());
+ if (error != error_) {
+ error_ = error;
+ SignalError(this, error);
+ session_manager_->signaling_thread()->Post(this, MSG_ERROR);
+ }
+}
+
+const std::string &Session::name() {
+ return name_;
+}
+
+const std::string &Session::remote_address() {
+ return remote_address_;
+}
+
+bool Session::initiator() {
+ return initiator_;
+}
+
+const SessionID& Session::id() {
+ return id_;
+}
+
+const SessionDescription *Session::description() {
+ return description_;
+}
+
+const SessionDescription *Session::remote_description() {
+ return remote_description_;
+}
+
+SessionManager *Session::session_manager() {
+ return session_manager_;
+}
+
+void Session::OnMessage(Message *pmsg) {
+ switch(pmsg->message_id) {
+ case MSG_TIMEOUT:
+ // Session timeout has occured. Check to see if the session is still trying
+ // to signal. If so, the session has timed out.
+ // The Sockets have their own timeout for connectivity.
+ set_error(ERROR_TIME);
+ break;
+
+ case MSG_ERROR:
+ switch (error_) {
+ case ERROR_RESPONSE:
+ // This state could be reached if we get an error in response to an IQ
+ // or if the network is so slow we time out on an individual IQ exchange.
+ // In either case, Terminate (send more messages) and ignore the likely
+ // cascade of more errors.
+
+ // fall through
+ case ERROR_NETWORK:
+ case ERROR_TIME:
+ // Time ran out - no response
+ Terminate();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case MSG_STATE:
+ switch (state_) {
+ case STATE_SENTACCEPT:
+ case STATE_RECEIVEDACCEPT:
+ set_state(STATE_INPROGRESS);
+ session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT);
+ OnSocketState(); // Update the writability timeout state.
+ break;
+
+ case STATE_SENTREJECT:
+ case STATE_SENTREDIRECT:
+ case STATE_RECEIVEDREJECT:
+ Terminate();
+ break;
+
+ case STATE_SENTTERMINATE:
+ case STATE_RECEIVEDTERMINATE:
+ session_manager_->DestroySession(this);
+ break;
+
+ default:
+ // explicitly ignoring some states here
+ break;
+ }
+ break;
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h
new file mode 100644
index 00000000..1414a375
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/session.h
@@ -0,0 +1,140 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSION_H_
+#define _SESSION_H_
+
+#include "talk/base/socketaddress.h"
+#include "talk/p2p/base/sessiondescription.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/sessionmessage.h"
+#include "talk/p2p/base/socketmanager.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/p2p/base/port.h"
+#include <string>
+
+namespace cricket {
+
+class SessionManager;
+class SocketManager;
+
+// A specific Session created by the SessionManager
+// A Session manages signaling for session setup and tear down, and connectivity
+// with P2PSockets
+
+class Session : public MessageHandler, public sigslot::has_slots<> {
+public:
+ enum State {
+ STATE_INIT = 0,
+ STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject
+ STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject
+ STATE_SENTACCEPT, // sent accept. begin connectivity establishment
+ STATE_RECEIVEDACCEPT, // received accept. begin connectivity establishment
+ STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject
+ STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject
+ STATE_SENTREJECT, // sent reject after receiving initiate
+ STATE_RECEIVEDREJECT, // received reject after sending initiate
+ STATE_SENTREDIRECT, // sent direct after receiving initiate
+ STATE_SENTTERMINATE, // sent terminate (any time / either side)
+ STATE_RECEIVEDTERMINATE, // received terminate (any time / either side)
+ STATE_INPROGRESS, // session accepted and in progress
+ };
+
+ enum Error {
+ ERROR_NONE = 0, // no error
+ ERROR_TIME, // no response to signaling
+ ERROR_RESPONSE, // error during signaling
+ ERROR_NETWORK, // network error, could not allocate network resources
+ };
+
+ Session(SessionManager *session_manager, const std::string &name, const SessionID& id);
+ ~Session();
+
+ // From MessageHandler
+ void OnMessage(Message *pmsg);
+
+ P2PSocket *CreateSocket(const std::string & name);
+ void DestroySocket(P2PSocket *socket);
+
+ bool Initiate(const std::string &to, const SessionDescription *description);
+ bool Accept(const SessionDescription *description);
+ bool Modify(const SessionDescription *description);
+ bool Reject();
+ bool Redirect(const std::string& target);
+ bool Terminate();
+
+ SessionManager *session_manager();
+ const std::string &name();
+ const std::string &remote_address();
+ bool initiator();
+ const SessionID& id();
+ const SessionDescription *description();
+ const SessionDescription *remote_description();
+
+ State state();
+ Error error();
+
+ void OnSignalingReady();
+ void OnIncomingMessage(const SessionMessage &m);
+ void OnIncomingError(const SessionMessage &m);
+
+ sigslot::signal2<Session *, State> SignalState;
+ sigslot::signal2<Session *, Error> SignalError;
+ sigslot::signal2<Session *, const SessionMessage &> SignalOutgoingMessage;
+ sigslot::signal0<> SignalRequestSignaling;
+
+private:
+ void SendSessionMessage(SessionMessage::Type type,
+ const SessionDescription* description,
+ const std::vector<Candidate>* candidates,
+ SessionMessage::Cookie* redirect_cookie);
+ void OnCandidatesReady(const std::vector<Candidate>& candidates);
+ void OnNetworkError();
+ void OnSocketState();
+ void OnRequestSignaling();
+ void OnRedirectMessage(const SessionMessage &m);
+
+ void set_state(State state);
+ void set_error(Error error);
+
+ bool initiator_;
+ SessionManager *session_manager_;
+ SessionID id_;
+ SocketManager *socket_manager_;
+ std::string name_;
+ std::string remote_address_;
+ const SessionDescription *description_;
+ const SessionDescription *remote_description_;
+ std::string redirect_target_;
+ State state_;
+ Error error_;
+ CriticalSection crit_;
+};
+
+} // namespace cricket
+
+#endif // _SESSION_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h
new file mode 100644
index 00000000..28b70845
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessiondescription.h
@@ -0,0 +1,42 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSIONDESCRIPTION_H_
+#define _SESSIONDESCRIPTION_H_
+
+namespace cricket {
+
+// The client overrides this with whatever
+
+class SessionDescription {
+public:
+ virtual ~SessionDescription() {}
+};
+
+} // namespace cricket
+
+#endif // _SESSIONDESCRIPTION_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h
new file mode 100644
index 00000000..a12535c0
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionid.h
@@ -0,0 +1,94 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSIONID_H_
+#define _SESSIONID_H_
+
+#include "talk/base/basictypes.h"
+#include <string>
+#include <sstream>
+
+namespace cricket {
+
+// Each session is identified by a pair (from,id), where id is only
+// assumed to be unique to the machine identified by from.
+class SessionID {
+public:
+ SessionID() : id_str_("0") {
+ }
+ SessionID(const std::string& initiator, uint32 id)
+ : initiator_(initiator) {
+ set_id(id);
+ }
+ SessionID(const SessionID& sid)
+ : id_str_(sid.id_str_), initiator_(sid.initiator_) {
+ }
+
+ void set_id(uint32 id) {
+ std::stringstream st;
+ st << id;
+ st >> id_str_;
+ }
+ const std::string id_str() const {
+ return id_str_;
+ }
+ void set_id_str(const std::string &id_str) {
+ id_str_ = id_str;
+ }
+
+ const std::string &initiator() const {
+ return initiator_;
+ }
+ void set_initiator(const std::string &initiator) {
+ initiator_ = initiator;
+ }
+
+ bool operator <(const SessionID& sid) const {
+ int r = initiator_.compare(sid.initiator_);
+ if (r == 0)
+ r = id_str_.compare(sid.id_str_);
+ return r < 0;
+ }
+
+ bool operator ==(const SessionID& sid) const {
+ return (id_str_ == sid.id_str_) && (initiator_ == sid.initiator_);
+ }
+
+ SessionID& operator =(const SessionID& sid) {
+ id_str_ = sid.id_str_;
+ initiator_ = sid.initiator_;
+ return *this;
+ }
+
+private:
+ std::string id_str_;
+ std::string initiator_;
+};
+
+} // namespace cricket
+
+#endif // _SESSIONID_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc
new file mode 100644
index 00000000..4c1c09d9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.cc
@@ -0,0 +1,173 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/common.h"
+#include "talk/p2p/base/helpers.h"
+#include "sessionmanager.h"
+
+namespace cricket {
+
+SessionManager::SessionManager(PortAllocator *allocator, Thread *worker) {
+ allocator_ = allocator;
+ signaling_thread_ = Thread::Current();
+ if (worker == NULL) {
+ worker_thread_ = Thread::Current();
+ } else {
+ worker_thread_ = worker;
+ }
+ timeout_ = 50;
+}
+
+SessionManager::~SessionManager() {
+ // Note: Session::Terminate occurs asynchronously, so it's too late to
+ // delete them now. They better be all gone.
+ ASSERT(session_map_.empty());
+ //TerminateAll();
+}
+
+Session *SessionManager::CreateSession(const std::string &name, const std::string& initiator) {
+ return CreateSession(name, SessionID(initiator, CreateRandomId()), false);
+}
+
+Session *SessionManager::CreateSession(const std::string &name, const SessionID& id, bool received_initiate) {
+ Session *session = new Session(this, name, id);
+ session_map_[session->id()] = session;
+ session->SignalRequestSignaling.connect(this, &SessionManager::OnRequestSignaling);
+ SignalSessionCreate(session, received_initiate);
+ return session;
+}
+
+void SessionManager::DestroySession(Session *session) {
+ if (session != NULL) {
+ std::map<SessionID, Session *>::iterator it = session_map_.find(session->id());
+ if (it != session_map_.end()) {
+ SignalSessionDestroy(session);
+ session_map_.erase(it);
+ delete session;
+ }
+ }
+}
+
+Session *SessionManager::GetSession(const SessionID& id) {
+ // If the id isn't present, the [] operator will make a NULL entry
+ std::map<SessionID, Session *>::iterator it = session_map_.find(id);
+ if (it != session_map_.end())
+ return (*it).second;
+ return NULL;
+}
+
+void SessionManager::TerminateAll() {
+ while (session_map_.begin() != session_map_.end()) {
+ Session *session = session_map_.begin()->second;
+ session->Terminate();
+ }
+}
+
+void SessionManager::OnIncomingError(const SessionMessage &m) {
+ // Incoming signaling error. This means, as the result of trying
+ // to send message m, and error was generated. In all cases, a
+ // session should already exist
+
+ Session *session;
+ switch (m.type()) {
+ case SessionMessage::TYPE_INITIATE:
+ case SessionMessage::TYPE_ACCEPT:
+ case SessionMessage::TYPE_MODIFY:
+ case SessionMessage::TYPE_CANDIDATES:
+ case SessionMessage::TYPE_REJECT:
+ case SessionMessage::TYPE_TERMINATE:
+ session = GetSession(m.session_id());
+ break;
+
+ default:
+ return;
+ }
+
+ if (session != NULL)
+ session->OnIncomingError(m);
+
+}
+
+void SessionManager::OnIncomingMessage(const SessionMessage &m) {
+ // In the case of an incoming initiate, there is no session yet, and one needs to be created.
+ // The other cases have sessions already.
+
+ Session *session;
+ switch (m.type()) {
+ case SessionMessage::TYPE_INITIATE:
+ session = CreateSession(m.name(), m.session_id(), true);
+ break;
+
+ case SessionMessage::TYPE_ACCEPT:
+ case SessionMessage::TYPE_MODIFY:
+ case SessionMessage::TYPE_CANDIDATES:
+ case SessionMessage::TYPE_REJECT:
+ case SessionMessage::TYPE_REDIRECT:
+ case SessionMessage::TYPE_TERMINATE:
+ session = GetSession(m.session_id());
+ break;
+
+ default:
+ return;
+ }
+
+ if (session != NULL)
+ session->OnIncomingMessage(m);
+}
+
+void SessionManager::OnSignalingReady() {
+ for (std::map<SessionID, Session *>::iterator it = session_map_.begin();
+ it != session_map_.end(); ++it) {
+ it->second->OnSignalingReady();
+ }
+}
+
+void SessionManager::OnRequestSignaling() {
+ SignalRequestSignaling();
+}
+
+PortAllocator *SessionManager::port_allocator() const {
+ return allocator_;
+}
+
+Thread *SessionManager::worker_thread() const {
+ return worker_thread_;
+}
+
+Thread *SessionManager::signaling_thread() const {
+ return signaling_thread_;
+}
+
+int SessionManager::session_timeout() {
+ return timeout_;
+}
+
+void SessionManager::set_session_timeout(int timeout) {
+ timeout_ = timeout;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h
new file mode 100644
index 00000000..5ce0e4c5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmanager.h
@@ -0,0 +1,86 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSIONMANAGER_H_
+#define _SESSIONMANAGER_H_
+
+#include "talk/base/thread.h"
+#include "talk/p2p/base/portallocator.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessionmessage.h"
+#include "talk/base/sigslot.h"
+
+#include <string>
+#include <utility>
+#include <map>
+
+namespace cricket {
+
+class Session;
+
+// SessionManager manages session instances
+
+class SessionManager : public sigslot::has_slots<> {
+public:
+ SessionManager(PortAllocator *allocator, Thread *worker_thread = NULL);
+ virtual ~SessionManager();
+
+ Session *CreateSession(const std::string &name, const std::string& initiator);
+ void DestroySession(Session *session);
+ Session *GetSession(const SessionID& id);
+ void TerminateAll();
+ void OnIncomingMessage(const SessionMessage &m);
+ void OnIncomingError(const SessionMessage &m);
+ void OnSignalingReady();
+
+ PortAllocator *port_allocator() const;
+ Thread *worker_thread() const;
+ Thread *signaling_thread() const;
+ int session_timeout();
+ void set_session_timeout(int timeout);
+
+ sigslot::signal2<Session *, bool> SignalSessionCreate;
+ sigslot::signal1<Session *> SignalSessionDestroy;
+
+ // Note: you can connect this directly to OnSignalingReady(), if a signalling
+ // check is not required.
+ sigslot::signal0<> SignalRequestSignaling;
+
+private:
+ Session *CreateSession(const std::string &name, const SessionID& id, bool received_initiate);
+ void OnRequestSignaling();
+
+ int timeout_;
+ Thread *worker_thread_;
+ Thread *signaling_thread_;
+ PortAllocator *allocator_;
+ std::map<SessionID, Session *> session_map_;
+};
+
+} // namespace cricket
+
+#endif // _SESSIONMANAGER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h
new file mode 100644
index 00000000..fc1b0323
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/sessionmessage.h
@@ -0,0 +1,133 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSIONMESSAGE_H_
+#define _SESSIONMESSAGE_H_
+
+#include "talk/p2p/base/candidate.h"
+#include "talk/p2p/base/sessiondescription.h"
+#include "talk/p2p/base/sessionid.h"
+#include "talk/base/basictypes.h"
+#include <string>
+#include <vector>
+#include <sstream>
+
+namespace cricket {
+
+class SessionMessage {
+public:
+ enum Type {
+ TYPE_INITIATE = 0, // Initiate message
+ TYPE_ACCEPT, // Accept message
+ TYPE_MODIFY, // Modify message
+ TYPE_CANDIDATES, // Candidates message
+ TYPE_REJECT, // Reject message
+ TYPE_REDIRECT, // Reject message
+ TYPE_TERMINATE, // Terminate message
+ };
+
+ class Cookie {
+ public:
+ virtual ~Cookie() {}
+
+ // Returns a copy of this cookie.
+ virtual Cookie* Copy() = 0;
+ };
+
+ Type type() const {
+ return type_;
+ }
+ void set_type(Type type) {
+ type_ = type;
+ }
+ const SessionID& session_id() const {
+ return id_;
+ }
+ SessionID& session_id() {
+ return id_;
+ }
+ void set_session_id(const SessionID& id) {
+ id_ = id;
+ }
+ const std::string &from() const {
+ return from_;
+ }
+ void set_from(const std::string &from) {
+ from_ = from;
+ }
+ const std::string &to() const {
+ return to_;
+ }
+ void set_to(const std::string &to) {
+ to_ = to;
+ }
+ const std::string &name() const {
+ return name_;
+ }
+ void set_name(const std::string &name) {
+ name_ = name;
+ }
+ const std::string &redirect_target() const {
+ return redirect_target_;
+ }
+ void set_redirect_target(const std::string &redirect_target) {
+ redirect_target_ = redirect_target;
+ }
+ Cookie *redirect_cookie() const {
+ return redirect_cookie_;
+ }
+ void set_redirect_cookie(Cookie* redirect_cookie) {
+ redirect_cookie_ = redirect_cookie;
+ }
+ const SessionDescription *description() const {
+ return description_;
+ }
+ void set_description(const SessionDescription *description) {
+ description_ = description;
+ }
+ const std::vector<Candidate> &candidates() const {
+ return candidates_;
+ }
+ void set_candidates(const std::vector<Candidate> &candidates) {
+ candidates_ = candidates;
+ }
+
+private:
+ Type type_;
+ SessionID id_;
+ std::string from_;
+ std::string to_;
+ std::string name_;
+ const SessionDescription *description_;
+ std::vector<Candidate> candidates_;
+ std::string redirect_target_;
+ Cookie* redirect_cookie_;
+};
+
+} // namespace cricket
+
+#endif // _SESSIONMESSAGE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc
new file mode 100644
index 00000000..2f0d67b8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.cc
@@ -0,0 +1,273 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "socketmanager.h"
+#include <cassert>
+
+namespace cricket {
+
+const uint32 MSG_CREATESOCKET = 1;
+const uint32 MSG_DESTROYSOCKET = 2;
+const uint32 MSG_ONSIGNALINGREADY = 3;
+const uint32 MSG_CANDIDATESREADY = 4;
+const uint32 MSG_ADDREMOTECANDIDATES = 5;
+const uint32 MSG_ONREQUESTSIGNALING = 6;
+const uint32 MSG_RESETSOCKETS = 7;
+
+struct CreateParams {
+ CreateParams() {}
+ P2PSocket *socket;
+ std::string name;
+};
+
+SocketManager::SocketManager(SessionManager *session_manager) {
+ session_manager_ = session_manager;
+ candidates_requested_ = false;
+ writable_ = false;
+}
+
+SocketManager::~SocketManager() {
+ assert(Thread::Current() == session_manager_->signaling_thread());
+
+ // Are the sockets destroyed? If not, destroy them
+
+ critSM_.Enter();
+ while (sockets_.size() != 0) {
+ P2PSocket *socket = sockets_[0];
+ critSM_.Leave();
+ DestroySocket(socket);
+ critSM_.Enter();
+ }
+ critSM_.Leave();
+
+ // Clear queues
+
+ session_manager_->signaling_thread()->Clear(this);
+ session_manager_->worker_thread()->Clear(this);
+}
+
+P2PSocket *SocketManager::CreateSocket(const std::string &name) {
+ // Can occur on any thread
+ CreateParams params;
+ params.name = name;
+ params.socket = NULL;
+ TypedMessageData<CreateParams *> data(&params);
+ session_manager_->worker_thread()->Send(this, MSG_CREATESOCKET, &data);
+ return data.data()->socket;
+}
+
+P2PSocket *SocketManager::CreateSocket_w(const std::string &name) {
+ // Only on worker thread
+ assert(Thread::Current() == session_manager_->worker_thread());
+ CritScope cs(&critSM_);
+ P2PSocket *socket = new P2PSocket(name, session_manager_->port_allocator());
+ socket->SignalCandidatesReady.connect(this, &SocketManager::OnCandidatesReady);
+ socket->SignalState.connect(this, &SocketManager::OnSocketState);
+ socket->SignalRequestSignaling.connect(this, &SocketManager::OnRequestSignaling);
+ sockets_.push_back(socket);
+ socket->StartProcessingCandidates();
+ return socket;
+}
+
+void SocketManager::DestroySocket(P2PSocket *socket) {
+ // Can occur on any thread
+ TypedMessageData<P2PSocket *> data(socket);
+ session_manager_->worker_thread()->Send(this, MSG_DESTROYSOCKET, &data);
+}
+
+void SocketManager::DestroySocket_w(P2PSocket *socket) {
+ // Only on worker thread
+ assert(Thread::Current() == session_manager_->worker_thread());
+
+ // Only if socket exists
+ CritScope cs(&critSM_);
+ std::vector<P2PSocket *>::iterator it;
+ it = std::find(sockets_.begin(), sockets_.end(), socket);
+ if (it == sockets_.end())
+ return;
+ sockets_.erase(it);
+ delete socket;
+}
+
+void SocketManager::StartProcessingCandidates() {
+ // Only on signaling thread
+ assert(Thread::Current() == session_manager_->signaling_thread());
+
+ // When sockets are created, their candidates are requested.
+ // When the candidates are ready, the client is signaled
+ // on the signaling thread
+ candidates_requested_ = true;
+ session_manager_->signaling_thread()->Post(this, MSG_CANDIDATESREADY);
+}
+
+void SocketManager::OnSignalingReady() {
+ session_manager_->worker_thread()->Post(this, MSG_ONSIGNALINGREADY);
+}
+
+void SocketManager::OnSignalingReady_w() {
+ // Only on worker thread
+ assert(Thread::Current() == session_manager_->worker_thread());
+ for (uint32 i = 0; i < sockets_.size(); ++i) {
+ sockets_[i]->OnSignalingReady();
+ }
+}
+
+void SocketManager::OnCandidatesReady(
+ P2PSocket *socket, const std::vector<Candidate>& candidates) {
+ // Only on worker thread
+ assert(Thread::Current() == session_manager_->worker_thread());
+
+ // Remember candidates
+ CritScope cs(&critSM_);
+ std::vector<Candidate>::const_iterator it;
+ for (it = candidates.begin(); it != candidates.end(); it++)
+ candidates_.push_back(*it);
+
+ // If candidates requested, tell signaling thread
+ if (candidates_requested_)
+ session_manager_->signaling_thread()->Post(this, MSG_CANDIDATESREADY);
+}
+
+void SocketManager::ResetSockets() {
+ assert(Thread::Current() == session_manager_->signaling_thread());
+ session_manager_->worker_thread()->Post(this, MSG_RESETSOCKETS);
+}
+
+void SocketManager::ResetSockets_w() {
+ assert(Thread::Current() == session_manager_->worker_thread());
+
+ for (size_t i = 0; i < sockets_.size(); ++i)
+ sockets_[i]->Reset();
+}
+
+void SocketManager::OnSocketState(P2PSocket* socket, P2PSocket::State state) {
+ assert(Thread::Current() == session_manager_->worker_thread());
+
+ bool writable = false;
+ for (uint32 i = 0; i < sockets_.size(); ++i)
+ if (sockets_[i]->writable())
+ writable = true;
+
+ if (writable_ != writable) {
+ writable_ = writable;
+ SignalState();
+ }
+}
+
+void SocketManager::OnRequestSignaling() {
+ assert(Thread::Current() == session_manager_->worker_thread());
+ session_manager_->signaling_thread()->Post(this, MSG_ONREQUESTSIGNALING);
+}
+
+
+void SocketManager::AddRemoteCandidates(const std::vector<Candidate> &remote_candidates) {
+ assert(Thread::Current() == session_manager_->signaling_thread());
+ TypedMessageData<std::vector<Candidate> > *data = new TypedMessageData<std::vector<Candidate> >(remote_candidates);
+ session_manager_->worker_thread()->Post(this, MSG_ADDREMOTECANDIDATES, data);
+}
+
+void SocketManager::AddRemoteCandidates_w(const std::vector<Candidate> &remote_candidates) {
+ assert(Thread::Current() == session_manager_->worker_thread());
+
+ // Local and remote candidates now exist, so connectivity checking can
+ // commence. Tell the P2PSockets about the remote candidates.
+ // Group candidates by socket name
+
+ CritScope cs(&critSM_);
+ std::vector<P2PSocket *>::iterator it_socket;
+ for (it_socket = sockets_.begin(); it_socket != sockets_.end(); it_socket++) {
+ // Create a vector of remote candidates for each socket
+ std::string name = (*it_socket)->name();
+ std::vector<Candidate> candidate_bundle;
+ std::vector<Candidate>::const_iterator it_candidate;
+ for (it_candidate = remote_candidates.begin(); it_candidate != remote_candidates.end(); it_candidate++) {
+ if ((*it_candidate).name() == name)
+ candidate_bundle.push_back(*it_candidate);
+ }
+ if (candidate_bundle.size() != 0)
+ (*it_socket)->AddRemoteCandidates(candidate_bundle);
+ }
+}
+
+void SocketManager::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CREATESOCKET:
+ {
+ assert(Thread::Current() == session_manager_->worker_thread());
+ TypedMessageData<CreateParams *> *params = static_cast<TypedMessageData<CreateParams *> *>(message->pdata);
+ params->data()->socket = CreateSocket_w(params->data()->name);
+ }
+ break;
+
+ case MSG_DESTROYSOCKET:
+ {
+ assert(Thread::Current() == session_manager_->worker_thread());
+ TypedMessageData<P2PSocket *> *data = static_cast<TypedMessageData<P2PSocket *> *>(message->pdata);
+ DestroySocket_w(data->data());
+ }
+ break;
+
+ case MSG_ONSIGNALINGREADY:
+ assert(Thread::Current() == session_manager_->worker_thread());
+ OnSignalingReady_w();
+ break;
+
+ case MSG_ONREQUESTSIGNALING:
+ assert(Thread::Current() == session_manager_->signaling_thread());
+ SignalRequestSignaling();
+ break;
+
+ case MSG_CANDIDATESREADY:
+ assert(Thread::Current() == session_manager_->signaling_thread());
+ if (candidates_requested_) {
+ CritScope cs(&critSM_);
+ if (candidates_.size() > 0) {
+ SignalCandidatesReady(candidates_);
+ candidates_.clear();
+ }
+ }
+ break;
+
+ case MSG_ADDREMOTECANDIDATES:
+ {
+ assert(Thread::Current() == session_manager_->worker_thread());
+ TypedMessageData<const std::vector<Candidate> > *data = static_cast<TypedMessageData<const std::vector<Candidate> > *>(message->pdata);
+ AddRemoteCandidates_w(data->data());
+ delete data;
+ }
+ break;
+
+ case MSG_RESETSOCKETS:
+ ResetSockets_w();
+ break;
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h
new file mode 100644
index 00000000..3ca1cf74
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/socketmanager.h
@@ -0,0 +1,101 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SOCKETMANAGER_H_
+#define _SOCKETMANAGER_H_
+
+#include "talk/base/criticalsection.h"
+#include "talk/base/messagequeue.h"
+#include "talk/base/sigslot.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/candidate.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/p2p/base/socketmanager.h"
+
+#include <string>
+#include <vector>
+
+namespace cricket {
+
+class SessionManager;
+
+// Manages P2PSocket creation/destruction/readiness.
+// Provides thread separation between session and sockets.
+// This allows session to execute on the signaling thread,
+// and sockets to execute on the worker thread, if desired,
+// which is good for some media types (audio/video for example).
+
+class SocketManager : public MessageHandler, public sigslot::has_slots<> {
+public:
+ SocketManager(SessionManager *session_manager);
+ virtual ~SocketManager();
+
+ // Determines whether any of the created sockets are currently writable.
+ bool writable() { return writable_; }
+
+ P2PSocket *CreateSocket(const std::string & name);
+ void DestroySocket(P2PSocket *socket);
+
+ // Start discovering local candidates
+ void StartProcessingCandidates();
+
+ // Adds the given candidates that were sent by the remote side.
+ void AddRemoteCandidates(const std::vector<Candidate>& candidates);
+
+ // signaling channel is up, ready to transmit candidates as they are discovered
+ void OnSignalingReady();
+
+ // Put all of the sockets back into the initial state.
+ void ResetSockets();
+
+ sigslot::signal1<const std::vector<Candidate>&> SignalCandidatesReady;
+ sigslot::signal0<> SignalNetworkError;
+ sigslot::signal0<> SignalState;
+ sigslot::signal0<> SignalRequestSignaling;
+
+private:
+ P2PSocket *CreateSocket_w(const std::string &name);
+ void DestroySocket_w(P2PSocket *socket);
+ void OnSignalingReady_w();
+ void AddRemoteCandidates_w(const std::vector<Candidate> &candidates);
+ virtual void OnMessage(Message *message);
+ void OnCandidatesReady(P2PSocket *socket, const std::vector<Candidate>&);
+ void OnSocketState(P2PSocket* socket, P2PSocket::State state);
+ void OnRequestSignaling(void);
+ void ResetSockets_w();
+
+ SessionManager *session_manager_;
+ std::vector<Candidate> candidates_;
+ CriticalSection critSM_;
+ std::vector<P2PSocket *> sockets_;
+ bool candidates_requested_;
+ bool writable_;
+};
+
+}
+
+#endif // _SOCKETMANAGER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc
new file mode 100644
index 00000000..6a22b238
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc
@@ -0,0 +1,576 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/logging.h"
+#include "talk/p2p/base/stun.h"
+#include <iostream>
+#include <cassert>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::memcpy;
+}
+#endif
+
+namespace cricket {
+
+const std::string STUN_ERROR_REASON_BAD_REQUEST = "BAD REQUEST";
+const std::string STUN_ERROR_REASON_UNAUTHORIZED = "UNAUTHORIZED";
+const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE = "UNKNOWN ATTRIBUTE";
+const std::string STUN_ERROR_REASON_STALE_CREDENTIALS = "STALE CREDENTIALS";
+const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE = "INTEGRITY CHECK FAILURE";
+const std::string STUN_ERROR_REASON_MISSING_USERNAME = "MISSING USERNAME";
+const std::string STUN_ERROR_REASON_USE_TLS = "USE TLS";
+const std::string STUN_ERROR_REASON_SERVER_ERROR = "SERVER ERROR";
+const std::string STUN_ERROR_REASON_GLOBAL_FAILURE = "GLOBAL FAILURE";
+
+StunMessage::StunMessage() : type_(0), length_(0),
+ transaction_id_("0000000000000000") {
+ assert(transaction_id_.size() == 16);
+ attrs_ = new std::vector<StunAttribute*>();
+}
+
+StunMessage::~StunMessage() {
+ for (unsigned i = 0; i < attrs_->size(); i++)
+ delete (*attrs_)[i];
+ delete attrs_;
+}
+
+void StunMessage::SetTransactionID(const std::string& str) {
+ assert(str.size() == 16);
+ transaction_id_ = str;
+}
+
+void StunMessage::AddAttribute(StunAttribute* attr) {
+ attrs_->push_back(attr);
+ length_ += attr->length() + 4;
+}
+
+const StunAddressAttribute*
+StunMessage::GetAddress(StunAttributeType type) const {
+ switch (type) {
+ case STUN_ATTR_MAPPED_ADDRESS:
+ case STUN_ATTR_RESPONSE_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS:
+ case STUN_ATTR_CHANGED_ADDRESS:
+ case STUN_ATTR_REFLECTED_FROM:
+ case STUN_ATTR_ALTERNATE_SERVER:
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ return reinterpret_cast<const StunAddressAttribute*>(GetAttribute(type));
+
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+const StunUInt32Attribute*
+StunMessage::GetUInt32(StunAttributeType type) const {
+ switch (type) {
+ case STUN_ATTR_CHANGE_REQUEST:
+ case STUN_ATTR_LIFETIME:
+ case STUN_ATTR_BANDWIDTH:
+ case STUN_ATTR_OPTIONS:
+ return reinterpret_cast<const StunUInt32Attribute*>(GetAttribute(type));
+
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+const StunByteStringAttribute*
+StunMessage::GetByteString(StunAttributeType type) const {
+ switch (type) {
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_PASSWORD:
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ case STUN_ATTR_DATA:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return reinterpret_cast<const StunByteStringAttribute*>(GetAttribute(type));
+
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
+ return reinterpret_cast<const StunErrorCodeAttribute*>(
+ GetAttribute(STUN_ATTR_ERROR_CODE));
+}
+
+const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
+ return reinterpret_cast<const StunUInt16ListAttribute*>(
+ GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
+}
+
+const StunTransportPrefsAttribute* StunMessage::GetTransportPrefs() const {
+ return reinterpret_cast<const StunTransportPrefsAttribute*>(
+ GetAttribute(STUN_ATTR_TRANSPORT_PREFERENCES));
+}
+
+const StunAttribute* StunMessage::GetAttribute(StunAttributeType type) const {
+ for (unsigned i = 0; i < attrs_->size(); i++) {
+ if ((*attrs_)[i]->type() == type)
+ return (*attrs_)[i];
+ }
+ return 0;
+}
+
+bool StunMessage::Read(ByteBuffer* buf) {
+ if (!buf->ReadUInt16(type_))
+ return false;
+
+ if (!buf->ReadUInt16(length_))
+ return false;
+
+ std::string transaction_id;
+ if (!buf->ReadString(transaction_id, 16))
+ return false;
+ assert(transaction_id.size() == 16);
+ transaction_id_ = transaction_id;
+
+ if (length_ > buf->Length())
+ return false;
+
+ attrs_->resize(0);
+
+ size_t rest = buf->Length() - length_;
+ while (buf->Length() > rest) {
+ uint16 attr_type, attr_length;
+ if (!buf->ReadUInt16(attr_type))
+ return false;
+ if (!buf->ReadUInt16(attr_length))
+ return false;
+
+ StunAttribute* attr = StunAttribute::Create(attr_type, attr_length);
+ if (!attr || !attr->Read(buf))
+ return false;
+
+ attrs_->push_back(attr);
+ }
+
+ if (buf->Length() != rest) {
+ // fixme: shouldn't be doing this
+ LOG(LERROR) << "wrong message length"
+ << " (" << (int)rest << " != " << (int)buf->Length() << ")";
+ return false;
+ }
+
+ return true;
+}
+
+void StunMessage::Write(ByteBuffer* buf) const {
+ buf->WriteUInt16(type_);
+ buf->WriteUInt16(length_);
+ buf->WriteString(transaction_id_);
+
+ for (unsigned i = 0; i < attrs_->size(); i++) {
+ buf->WriteUInt16((*attrs_)[i]->type());
+ buf->WriteUInt16((*attrs_)[i]->length());
+ (*attrs_)[i]->Write(buf);
+ }
+}
+
+StunAttribute::StunAttribute(uint16 type, uint16 length)
+ : type_(type), length_(length) {
+}
+
+StunAttribute* StunAttribute::Create(uint16 type, uint16 length) {
+ switch (type) {
+ case STUN_ATTR_MAPPED_ADDRESS:
+ case STUN_ATTR_RESPONSE_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS:
+ case STUN_ATTR_CHANGED_ADDRESS:
+ case STUN_ATTR_REFLECTED_FROM:
+ case STUN_ATTR_ALTERNATE_SERVER:
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ if (length != StunAddressAttribute::SIZE)
+ return 0;
+ return new StunAddressAttribute(type);
+
+ case STUN_ATTR_CHANGE_REQUEST:
+ case STUN_ATTR_LIFETIME:
+ case STUN_ATTR_BANDWIDTH:
+ case STUN_ATTR_OPTIONS:
+ if (length != StunUInt32Attribute::SIZE)
+ return 0;
+ return new StunUInt32Attribute(type);
+
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_PASSWORD:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return (length % 4 == 0) ? new StunByteStringAttribute(type, length) : 0;
+
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ return (length == 20) ? new StunByteStringAttribute(type, length) : 0;
+
+ case STUN_ATTR_DATA:
+ return new StunByteStringAttribute(type, length);
+
+ case STUN_ATTR_ERROR_CODE:
+ if (length < StunErrorCodeAttribute::MIN_SIZE)
+ return 0;
+ return new StunErrorCodeAttribute(type, length);
+
+ case STUN_ATTR_UNKNOWN_ATTRIBUTES:
+ return (length % 2 == 0) ? new StunUInt16ListAttribute(type, length) : 0;
+
+ case STUN_ATTR_TRANSPORT_PREFERENCES:
+ if ((length != StunTransportPrefsAttribute::SIZE1) &&
+ (length != StunTransportPrefsAttribute::SIZE2))
+ return 0;
+ return new StunTransportPrefsAttribute(type, length);
+
+ default:
+ return 0;
+ }
+}
+
+StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
+ switch (type) {
+ case STUN_ATTR_MAPPED_ADDRESS:
+ case STUN_ATTR_RESPONSE_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS:
+ case STUN_ATTR_CHANGED_ADDRESS:
+ case STUN_ATTR_REFLECTED_FROM:
+ case STUN_ATTR_ALTERNATE_SERVER:
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ return new StunAddressAttribute(type);
+
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
+ switch (type) {
+ case STUN_ATTR_CHANGE_REQUEST:
+ case STUN_ATTR_LIFETIME:
+ case STUN_ATTR_BANDWIDTH:
+ case STUN_ATTR_OPTIONS:
+ return new StunUInt32Attribute(type);
+
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
+ switch (type) {
+ case STUN_ATTR_USERNAME:
+ case STUN_ATTR_PASSWORD:
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ case STUN_ATTR_DATA:
+ case STUN_ATTR_MAGIC_COOKIE:
+ return new StunByteStringAttribute(type, 0);
+
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
+ return new StunErrorCodeAttribute(
+ STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
+}
+
+StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
+ return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
+}
+
+StunTransportPrefsAttribute* StunAttribute::CreateTransportPrefs() {
+ return new StunTransportPrefsAttribute(
+ STUN_ATTR_TRANSPORT_PREFERENCES, StunTransportPrefsAttribute::SIZE1);
+}
+
+StunAddressAttribute::StunAddressAttribute(uint16 type)
+ : StunAttribute(type, SIZE), family_(0), port_(0), ip_(0) {
+}
+
+bool StunAddressAttribute::Read(ByteBuffer* buf) {
+ uint8 dummy;
+ if (!buf->ReadUInt8(dummy))
+ return false;
+ if (!buf->ReadUInt8(family_))
+ return false;
+ if (!buf->ReadUInt16(port_))
+ return false;
+ if (!buf->ReadUInt32(ip_))
+ return false;
+ return true;
+}
+
+void StunAddressAttribute::Write(ByteBuffer* buf) const {
+ buf->WriteUInt8(0);
+ buf->WriteUInt8(family_);
+ buf->WriteUInt16(port_);
+ buf->WriteUInt32(ip_);
+}
+
+StunUInt32Attribute::StunUInt32Attribute(uint16 type)
+ : StunAttribute(type, SIZE), bits_(0) {
+}
+
+bool StunUInt32Attribute::GetBit(int index) const {
+ assert((0 <= index) && (index < 32));
+ return static_cast<bool>((bits_ >> index) & 0x1);
+}
+
+void StunUInt32Attribute::SetBit(int index, bool value) {
+ assert((0 <= index) && (index < 32));
+ bits_ &= ~(1 << index);
+ bits_ |= value ? (1 << index) : 0;
+}
+
+bool StunUInt32Attribute::Read(ByteBuffer* buf) {
+ if (!buf->ReadUInt32(bits_))
+ return false;
+ return true;
+}
+
+void StunUInt32Attribute::Write(ByteBuffer* buf) const {
+ buf->WriteUInt32(bits_);
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
+ : StunAttribute(type, length), bytes_(0) {
+}
+
+StunByteStringAttribute::~StunByteStringAttribute() {
+ delete [] bytes_;
+}
+
+void StunByteStringAttribute::SetBytes(char* bytes, uint16 length) {
+ delete [] bytes_;
+ bytes_ = bytes;
+ SetLength(length);
+}
+
+void StunByteStringAttribute::CopyBytes(const char* bytes) {
+ CopyBytes(bytes, (uint16)strlen(bytes));
+}
+
+void StunByteStringAttribute::CopyBytes(const void* bytes, uint16 length) {
+ char* new_bytes = new char[length];
+ std::memcpy(new_bytes, bytes, length);
+ SetBytes(new_bytes, length);
+}
+
+uint8 StunByteStringAttribute::GetByte(int index) const {
+ assert(bytes_);
+ assert((0 <= index) && (index < length()));
+ return static_cast<uint8>(bytes_[index]);
+}
+
+void StunByteStringAttribute::SetByte(int index, uint8 value) {
+ assert(bytes_);
+ assert((0 <= index) && (index < length()));
+ bytes_[index] = value;
+}
+
+bool StunByteStringAttribute::Read(ByteBuffer* buf) {
+ bytes_ = new char[length()];
+ if (!buf->ReadBytes(bytes_, length()))
+ return false;
+ return true;
+}
+
+void StunByteStringAttribute::Write(ByteBuffer* buf) const {
+ buf->WriteBytes(bytes_, length());
+}
+
+StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
+ : StunAttribute(type, length), class_(0), number_(0) {
+}
+
+StunErrorCodeAttribute::~StunErrorCodeAttribute() {
+}
+
+void StunErrorCodeAttribute::SetErrorCode(uint32 code) {
+ class_ = (uint8)((code >> 8) & 0x7);
+ number_ = (uint8)(code & 0xff);
+}
+
+void StunErrorCodeAttribute::SetReason(const std::string& reason) {
+ SetLength(MIN_SIZE + (uint16)reason.size());
+ reason_ = reason;
+}
+
+bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
+ uint32 val;
+ if (!buf->ReadUInt32(val))
+ return false;
+
+ if ((val >> 11) != 0)
+ LOG(LERROR) << "error-code bits not zero";
+
+ SetErrorCode(val);
+
+ if (!buf->ReadString(reason_, length() - 4))
+ return false;
+
+ return true;
+}
+
+void StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
+ buf->WriteUInt32(error_code());
+ buf->WriteString(reason_);
+}
+
+StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
+ : StunAttribute(type, length) {
+ attr_types_ = new std::vector<uint16>();
+}
+
+StunUInt16ListAttribute::~StunUInt16ListAttribute() {
+ delete attr_types_;
+}
+
+size_t StunUInt16ListAttribute::Size() const {
+ return attr_types_->size();
+}
+
+uint16 StunUInt16ListAttribute::GetType(int index) const {
+ return (*attr_types_)[index];
+}
+
+void StunUInt16ListAttribute::SetType(int index, uint16 value) {
+ (*attr_types_)[index] = value;
+}
+
+void StunUInt16ListAttribute::AddType(uint16 value) {
+ attr_types_->push_back(value);
+ SetLength((uint16)attr_types_->size() * 2);
+}
+
+bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
+ for (int i = 0; i < length() / 2; i++) {
+ uint16 attr;
+ if (!buf->ReadUInt16(attr))
+ return false;
+ attr_types_->push_back(attr);
+ }
+ return true;
+}
+
+void StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
+ for (unsigned i = 0; i < attr_types_->size(); i++)
+ buf->WriteUInt16((*attr_types_)[i]);
+}
+
+StunTransportPrefsAttribute::StunTransportPrefsAttribute(
+ uint16 type, uint16 length)
+ : StunAttribute(type, length), preallocate_(false), prefs_(0), addr_(0) {
+}
+
+StunTransportPrefsAttribute::~StunTransportPrefsAttribute() {
+ delete addr_;
+}
+
+void StunTransportPrefsAttribute::SetPreallocateAddress(
+ StunAddressAttribute* addr) {
+ if (!addr) {
+ preallocate_ = false;
+ addr_ = 0;
+ SetLength(SIZE1);
+ } else {
+ preallocate_ = true;
+ addr_ = addr;
+ SetLength(SIZE2);
+ }
+}
+
+bool StunTransportPrefsAttribute::Read(ByteBuffer* buf) {
+ uint32 val;
+ if (!buf->ReadUInt32(val))
+ return false;
+
+ if ((val >> 3) != 0)
+ LOG(LERROR) << "transport-preferences bits not zero";
+
+ preallocate_ = static_cast<bool>((val >> 2) & 0x1);
+ prefs_ = (uint8)(val & 0x3);
+
+ if (preallocate_ && (prefs_ == 3))
+ LOG(LERROR) << "transport-preferences imcompatible P and Typ";
+
+ if (!preallocate_) {
+ if (length() != StunUInt32Attribute::SIZE)
+ return false;
+ } else {
+ if (length() != StunUInt32Attribute::SIZE + StunAddressAttribute::SIZE)
+ return false;
+
+ addr_ = new StunAddressAttribute(STUN_ATTR_SOURCE_ADDRESS);
+ addr_->Read(buf);
+ }
+
+ return true;
+}
+
+void StunTransportPrefsAttribute::Write(ByteBuffer* buf) const {
+ buf->WriteUInt32((preallocate_ ? 4 : 0) | prefs_);
+
+ if (preallocate_)
+ addr_->Write(buf);
+}
+
+StunMessageType GetStunResponseType(StunMessageType request_type) {
+ switch (request_type) {
+ case STUN_SHARED_SECRET_REQUEST:
+ return STUN_SHARED_SECRET_RESPONSE;
+ case STUN_ALLOCATE_REQUEST:
+ return STUN_ALLOCATE_RESPONSE;
+ case STUN_SEND_REQUEST:
+ return STUN_SEND_RESPONSE;
+ default:
+ return STUN_BINDING_RESPONSE;
+ }
+}
+
+StunMessageType GetStunErrorResponseType(StunMessageType request_type) {
+ switch (request_type) {
+ case STUN_SHARED_SECRET_REQUEST:
+ return STUN_SHARED_SECRET_ERROR_RESPONSE;
+ case STUN_ALLOCATE_REQUEST:
+ return STUN_ALLOCATE_ERROR_RESPONSE;
+ case STUN_SEND_REQUEST:
+ return STUN_SEND_ERROR_RESPONSE;
+ default:
+ return STUN_BINDING_ERROR_RESPONSE;
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h
new file mode 100644
index 00000000..27a8e4be
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.h
@@ -0,0 +1,364 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STUN_H__
+#define __STUN_H__
+
+// This file contains classes for dealing with the STUN and TURN protocols.
+// Both protocols use the same wire format.
+
+#include "talk/base/basictypes.h"
+#include "talk/base/bytebuffer.h"
+#include <string>
+#include <vector>
+
+namespace cricket {
+
+// These are the types of STUN & TURN messages as of last check.
+enum StunMessageType {
+ STUN_BINDING_REQUEST = 0x0001,
+ STUN_BINDING_RESPONSE = 0x0101,
+ STUN_BINDING_ERROR_RESPONSE = 0x0111,
+ STUN_SHARED_SECRET_REQUEST = 0x0002,
+ STUN_SHARED_SECRET_RESPONSE = 0x0102,
+ STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112,
+ STUN_ALLOCATE_REQUEST = 0x0003,
+ STUN_ALLOCATE_RESPONSE = 0x0103,
+ STUN_ALLOCATE_ERROR_RESPONSE = 0x0113,
+ STUN_SEND_REQUEST = 0x0004,
+ STUN_SEND_RESPONSE = 0x0104,
+ STUN_SEND_ERROR_RESPONSE = 0x0114,
+ STUN_DATA_INDICATION = 0x0115
+};
+
+// These are the types of attributes defined in STUN & TURN. Next to each is
+// the name of the class (T is StunTAttribute) that implements that type.
+enum StunAttributeType {
+ STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address
+ STUN_ATTR_RESPONSE_ADDRESS = 0x0002, // Address
+ STUN_ATTR_CHANGE_REQUEST = 0x0003, // UInt32
+ STUN_ATTR_SOURCE_ADDRESS = 0x0004, // Address
+ STUN_ATTR_CHANGED_ADDRESS = 0x0005, // Address
+ STUN_ATTR_USERNAME = 0x0006, // ByteString, multiple of 4 bytes
+ STUN_ATTR_PASSWORD = 0x0007, // ByteString, multiple of 4 bytes
+ STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes
+ STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode
+ STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List
+ STUN_ATTR_REFLECTED_FROM = 0x000b, // Address
+ STUN_ATTR_TRANSPORT_PREFERENCES = 0x000c, // TransportPrefs
+ STUN_ATTR_LIFETIME = 0x000d, // UInt32
+ STUN_ATTR_ALTERNATE_SERVER = 0x000e, // Address
+ STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes
+ STUN_ATTR_BANDWIDTH = 0x0010, // UInt32
+ STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address
+ STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address
+ STUN_ATTR_DATA = 0x0013, // ByteString
+ STUN_ATTR_OPTIONS = 0x8001 // UInt32
+};
+
+enum StunErrorCodes {
+ STUN_ERROR_BAD_REQUEST = 400,
+ STUN_ERROR_UNAUTHORIZED = 401,
+ STUN_ERROR_UNKNOWN_ATTRIBUTE = 420,
+ STUN_ERROR_STALE_CREDENTIALS = 430,
+ STUN_ERROR_INTEGRITY_CHECK_FAILURE = 431,
+ STUN_ERROR_MISSING_USERNAME = 432,
+ STUN_ERROR_USE_TLS = 433,
+ STUN_ERROR_SERVER_ERROR = 500,
+ STUN_ERROR_GLOBAL_FAILURE = 600
+};
+
+extern const std::string STUN_ERROR_REASON_BAD_REQUEST;
+extern const std::string STUN_ERROR_REASON_UNAUTHORIZED;
+extern const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE;
+extern const std::string STUN_ERROR_REASON_STALE_CREDENTIALS;
+extern const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE;
+extern const std::string STUN_ERROR_REASON_MISSING_USERNAME;
+extern const std::string STUN_ERROR_REASON_USE_TLS;
+extern const std::string STUN_ERROR_REASON_SERVER_ERROR;
+extern const std::string STUN_ERROR_REASON_GLOBAL_FAILURE;
+
+class StunAttribute;
+class StunAddressAttribute;
+class StunUInt32Attribute;
+class StunByteStringAttribute;
+class StunErrorCodeAttribute;
+class StunUInt16ListAttribute;
+class StunTransportPrefsAttribute;
+
+// Records a complete STUN/TURN message. Each message consists of a type and
+// any number of attributes. Each attribute is parsed into an instance of an
+// appropriate class (see above). The Get* methods will return instances of
+// that attribute class.
+class StunMessage {
+public:
+ StunMessage();
+ ~StunMessage();
+
+ StunMessageType type() const { return static_cast<StunMessageType>(type_); }
+ uint16 length() const { return length_; }
+ const std::string& transaction_id() const { return transaction_id_; }
+
+ void SetType(StunMessageType type) { type_ = type; }
+ void SetTransactionID(const std::string& str);
+
+ const StunAddressAttribute* GetAddress(StunAttributeType type) const;
+ const StunUInt32Attribute* GetUInt32(StunAttributeType type) const;
+ const StunByteStringAttribute* GetByteString(StunAttributeType type) const;
+ const StunErrorCodeAttribute* GetErrorCode() const;
+ const StunUInt16ListAttribute* GetUnknownAttributes() const;
+ const StunTransportPrefsAttribute* GetTransportPrefs() const;
+
+ void AddAttribute(StunAttribute* attr);
+
+ // Parses the STUN/TURN packet in the given buffer and records it here. The
+ // return value indicates whether this was successful.
+ bool Read(ByteBuffer* buf);
+
+ // Writes this object into a STUN/TURN packet. Return value is true if
+ // successful.
+ void Write(ByteBuffer* buf) const;
+
+private:
+ uint16 type_;
+ uint16 length_;
+ std::string transaction_id_;
+ std::vector<StunAttribute*>* attrs_;
+
+ const StunAttribute* GetAttribute(StunAttributeType type) const;
+};
+
+// Base class for all STUN/TURN attributes.
+class StunAttribute {
+public:
+ virtual ~StunAttribute() {}
+
+ StunAttributeType type() const {
+ return static_cast<StunAttributeType>(type_);
+ }
+ uint16 length() const { return length_; }
+
+ // Reads the body (not the type or length) for this type of attribute from
+ // the given buffer. Return value is true if successful.
+ virtual bool Read(ByteBuffer* buf) = 0;
+
+ // Writes the body (not the type or length) to the given buffer. Return
+ // value is true if successful.
+ virtual void Write(ByteBuffer* buf) const = 0;
+
+ // Creates an attribute object with the given type and len.
+ static StunAttribute* Create(uint16 type, uint16 length);
+
+ // Creates an attribute object with the given type and smallest length.
+ static StunAddressAttribute* CreateAddress(uint16 type);
+ static StunUInt32Attribute* CreateUInt32(uint16 type);
+ static StunByteStringAttribute* CreateByteString(uint16 type);
+ static StunErrorCodeAttribute* CreateErrorCode();
+ static StunUInt16ListAttribute* CreateUnknownAttributes();
+ static StunTransportPrefsAttribute* CreateTransportPrefs();
+
+protected:
+ StunAttribute(uint16 type, uint16 length);
+
+ void SetLength(uint16 length) { length_ = length; }
+
+private:
+ uint16 type_;
+ uint16 length_;
+};
+
+// Implements STUN/TURN attributes that record an Internet address.
+class StunAddressAttribute : public StunAttribute {
+public:
+ StunAddressAttribute(uint16 type);
+
+#if (_MSC_VER < 1300)
+ enum { SIZE = 8 };
+#else
+ static const uint16 SIZE = 8;
+#endif
+
+ uint8 family() const { return family_; }
+ uint16 port() const { return port_; }
+ uint32 ip() const { return ip_; }
+
+ void SetFamily(uint8 family) { family_ = family; }
+ void SetIP(uint32 ip) { ip_ = ip; }
+ void SetPort(uint16 port) { port_ = port; }
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ uint8 family_;
+ uint16 port_;
+ uint32 ip_;
+};
+
+// Implements STUN/TURN attributs that record a 32-bit integer.
+class StunUInt32Attribute : public StunAttribute {
+public:
+ StunUInt32Attribute(uint16 type);
+
+#if (_MSC_VER < 1300)
+ enum { SIZE = 4 };
+#else
+ static const uint16 SIZE = 4;
+#endif
+
+ uint32 value() const { return bits_; }
+
+ void SetValue(uint32 bits) { bits_ = bits; }
+
+ bool GetBit(int index) const;
+ void SetBit(int index, bool value);
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ uint32 bits_;
+};
+
+// Implements STUN/TURN attributs that record an arbitrary byte string
+class StunByteStringAttribute : public StunAttribute {
+public:
+ StunByteStringAttribute(uint16 type, uint16 length);
+ ~StunByteStringAttribute();
+
+ const char* bytes() const { return bytes_; }
+
+ void SetBytes(char* bytes, uint16 length);
+
+ void CopyBytes(const char* bytes); // uses strlen
+ void CopyBytes(const void* bytes, uint16 length);
+
+ uint8 GetByte(int index) const;
+ void SetByte(int index, uint8 value);
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ char* bytes_;
+};
+
+// Implements STUN/TURN attributs that record an error code.
+class StunErrorCodeAttribute : public StunAttribute {
+public:
+ StunErrorCodeAttribute(uint16 type, uint16 length);
+ ~StunErrorCodeAttribute();
+
+#if (_MSC_VER < 1300)
+ enum { MIN_SIZE = 4 };
+#else
+ static const uint16 MIN_SIZE = 4;
+#endif
+
+ uint32 error_code() const { return (class_ << 8) | number_; }
+ uint8 error_class() const { return class_; }
+ uint8 number() const { return number_; }
+ const std::string& reason() const { return reason_; }
+
+ void SetErrorCode(uint32 code);
+ void SetErrorClass(uint8 eclass) { class_ = eclass; }
+ void SetNumber(uint8 number) { number_ = number; }
+ void SetReason(const std::string& reason);
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ uint8 class_;
+ uint8 number_;
+ std::string reason_;
+};
+
+// Implements STUN/TURN attributs that record a list of attribute names.
+class StunUInt16ListAttribute : public StunAttribute {
+public:
+ StunUInt16ListAttribute(uint16 type, uint16 length);
+ ~StunUInt16ListAttribute();
+
+ size_t Size() const;
+ uint16 GetType(int index) const;
+ void SetType(int index, uint16 value);
+ void AddType(uint16 value);
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ std::vector<uint16>* attr_types_;
+};
+
+// Implements the TURN TRANSPORT-PREFS attribute, which provides information
+// about the ports to allocate.
+class StunTransportPrefsAttribute : public StunAttribute {
+public:
+ StunTransportPrefsAttribute(uint16 type, uint16 length);
+ ~StunTransportPrefsAttribute();
+
+#if (_MSC_VER < 1300)
+ enum { SIZE1 = 4, SIZE2 = 12 };
+#else
+ static const uint16 SIZE1 = 4;
+ static const uint16 SIZE2 = 12;
+#endif
+
+ bool preallocate() const { return preallocate_; }
+ uint8 preference_type() const { return prefs_; }
+ const StunAddressAttribute* address() const { return addr_; }
+
+ void SetPreferenceType(uint8 prefs) { prefs_ = prefs; }
+
+ // Sets the preallocate address to the given value, or if 0 is given, it sets
+ // to not preallocate.
+ void SetPreallocateAddress(StunAddressAttribute* addr);
+
+ bool Read(ByteBuffer* buf);
+ void Write(ByteBuffer* buf) const;
+
+private:
+ bool preallocate_;
+ uint8 prefs_;
+ StunAddressAttribute* addr_;
+};
+
+// The special MAGIC-COOKIE attribute is used to distinguish TURN packets from
+// other kinds of traffic.
+const char STUN_MAGIC_COOKIE_VALUE[] = { 0x72, char(0xc6), 0x4b, char(0xc6) };
+
+// Returns the (successful) response type for the given request type.
+StunMessageType GetStunResponseType(StunMessageType request_type);
+
+// Returns the error response type for the given request type.
+StunMessageType GetStunErrorResponseType(StunMessageType request_type);
+
+} // namespace cricket
+
+#endif // __STUN_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc
new file mode 100644
index 00000000..6d1dc6b1
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.cc
@@ -0,0 +1,171 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/logging.h"
+#include "talk/p2p/base/stunport.h"
+#include "talk/p2p/base/helpers.h"
+#include <iostream>
+#include <cassert>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts
+const int RETRY_DELAY = 50; // 50ms, from ICE spec
+const uint32 RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs
+
+// Handles a binding request sent to the STUN server.
+class StunPortBindingRequest : public StunRequest {
+public:
+ StunPortBindingRequest(StunPort* port) : port_(port) {
+ start_time_ = GetMillisecondCount();
+ }
+
+ virtual ~StunPortBindingRequest() {
+ }
+
+ virtual void Prepare(StunMessage* request) {
+ request->SetType(STUN_BINDING_REQUEST);
+ }
+
+ virtual void OnResponse(StunMessage* response) {
+ const StunAddressAttribute* addr_attr =
+ response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ if (!addr_attr) {
+ LOG(LERROR) << "Binding response missing mapped address.";
+ } else if (addr_attr->family() != 1) {
+ LOG(LERROR) << "Binding address has bad family";
+ } else {
+ SocketAddress addr(addr_attr->ip(), addr_attr->port());
+ if (port_->candidates().empty())
+ port_->add_address(addr, "udp");
+ }
+
+ // We will do a keep-alive regardless of whether this request suceeds.
+ // This should have almost no impact on network usage.
+ port_->requests_.SendDelayed(new StunPortBindingRequest(port_), KEEPALIVE_DELAY);
+ }
+
+ virtual void OnErrorResponse(StunMessage* response) {
+ const StunErrorCodeAttribute* attr = response->GetErrorCode();
+ if (!attr) {
+ LOG(LERROR) << "Bad allocate response error code";
+ } else {
+ LOG(LERROR) << "Binding error response:"
+ << " class=" << attr->error_class()
+ << " number=" << attr->number()
+ << " reason='" << attr->reason() << "'";
+ }
+
+ if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
+ port_->requests_.SendDelayed(new StunPortBindingRequest(port_), KEEPALIVE_DELAY);
+ }
+
+ virtual void OnTimeout() {
+ LOG(LERROR) << "Binding request timed out";
+ if (GetMillisecondCount() - start_time_ <= RETRY_TIMEOUT)
+ port_->requests_.SendDelayed(new StunPortBindingRequest(port_), RETRY_DELAY);
+ }
+
+private:
+ uint32 start_time_;
+ StunPort* port_;
+};
+
+const std::string STUN_PORT_TYPE("stun");
+
+StunPort::StunPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& local_addr,
+ const SocketAddress& server_addr)
+ : UDPPort(thread, STUN_PORT_TYPE, factory, network),
+ server_addr_(server_addr), requests_(thread), error_(0) {
+
+ socket_ = CreatePacketSocket(PROTO_UDP);
+ socket_->SignalReadPacket.connect(this, &StunPort::OnReadPacket);
+ if (socket_->Bind(local_addr) < 0)
+ PLOG(LERROR, socket_->GetError()) << "bind";
+
+ requests_.SignalSendPacket.connect(this, &StunPort::OnSendPacket);
+}
+
+StunPort::~StunPort() {
+ delete socket_;
+}
+
+void StunPort::PrepareAddress() {
+ requests_.Send(new StunPortBindingRequest(this));
+}
+
+int StunPort::SendTo(
+ const void* data, size_t size, const SocketAddress& addr, bool payload) {
+ int sent = socket_->SendTo(data, size, addr);
+ if (sent < 0)
+ error_ = socket_->GetError();
+ return sent;
+}
+
+int StunPort::SetOption(Socket::Option opt, int value) {
+ return socket_->SetOption(opt, value);
+}
+
+int StunPort::GetError() {
+ return error_;
+}
+
+void StunPort::OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ assert(socket == socket_);
+
+ // Look for a response to a binding request.
+ if (requests_.CheckResponse(data, size))
+ return;
+
+ // Process this data packet in the normal manner.
+ UDPPort::OnReadPacket(data, size, remote_addr);
+}
+
+void StunPort::OnSendPacket(const void* data, size_t size) {
+ if (socket_->SendTo(data, size, server_addr_) < 0)
+ PLOG(LERROR, socket_->GetError()) << "sendto";
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h
new file mode 100644
index 00000000..f042ae14
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunport.h
@@ -0,0 +1,72 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STUNPORT_H__
+#define __STUNPORT_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/p2p/base/udpport.h"
+#include "talk/p2p/base/stunrequest.h"
+
+namespace cricket {
+
+extern const std::string STUN_PORT_TYPE;
+
+// Communicates using the address on the outside of a NAT.
+class StunPort : public UDPPort {
+public:
+ StunPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& local_addr, const SocketAddress& server_addr);
+ virtual ~StunPort();
+
+ virtual void PrepareAddress();
+
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError();
+
+protected:
+ virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
+
+ void OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+private:
+ AsyncPacketSocket* socket_;
+ SocketAddress server_addr_;
+ StunRequestManager requests_;
+ int error_;
+
+ friend class StunPortBindingRequest;
+
+ // Sends STUN requests to the server.
+ void OnSendPacket(const void* data, size_t size);
+};
+
+} // namespace cricket
+
+#endif // __STUNPORT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc
new file mode 100644
index 00000000..14d64735
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc
@@ -0,0 +1,198 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/logging.h"
+#include "talk/p2p/base/stunrequest.h"
+#include "talk/p2p/base/helpers.h"
+#include <iostream>
+#include <cassert>
+
+namespace cricket {
+
+const uint32 MSG_STUN_SEND = 1;
+
+const int MAX_SENDS = 9;
+const int DELAY_UNIT = 100; // 100 milliseconds
+const int DELAY_MAX_FACTOR = 16;
+
+StunRequestManager::StunRequestManager(Thread* thread) : thread_(thread) {
+}
+
+StunRequestManager::~StunRequestManager() {
+ while (requests_.begin() != requests_.end()) {
+ StunRequest *request = requests_.begin()->second;
+ requests_.erase(requests_.begin());
+ delete request;
+ }
+}
+
+void StunRequestManager::Send(StunRequest* request) {
+ SendDelayed(request, 0);
+}
+
+void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
+ request->set_manager(this);
+ assert(requests_.find(request->id()) == requests_.end());
+ requests_[request->id()] = request;
+ thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
+}
+
+void StunRequestManager::Remove(StunRequest* request) {
+ assert(request->manager() == this);
+ RequestMap::iterator iter = requests_.find(request->id());
+ if (iter != requests_.end()) {
+ assert(iter->second == request);
+ requests_.erase(iter);
+ thread_->Clear(request);
+ }
+}
+
+void StunRequestManager::Clear() {
+ std::vector<StunRequest*> requests;
+ for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
+ requests.push_back(i->second);
+
+ for (uint32 i = 0; i < requests.size(); ++i)
+ Remove(requests[i]);
+}
+
+bool StunRequestManager::CheckResponse(StunMessage* msg) {
+ RequestMap::iterator iter = requests_.find(msg->transaction_id());
+ if (iter == requests_.end())
+ return false;
+
+ StunRequest* request = iter->second;
+ if (msg->type() == GetStunResponseType(request->type())) {
+ request->OnResponse(msg);
+ } else if (msg->type() == GetStunErrorResponseType(request->type())) {
+ request->OnErrorResponse(msg);
+ } else {
+ LOG(LERROR) << "Received response with wrong type: " << msg->type()
+ << " (expecting " << GetStunResponseType(request->type()) << ")";
+ return false;
+ }
+
+ delete request;
+ return true;
+}
+
+bool StunRequestManager::CheckResponse(const char* data, size_t size) {
+ // Check the appropriate bytes of the stream to see if they match the
+ // transaction ID of a response we are expecting.
+
+ if (size < 20)
+ return false;
+
+ std::string id;
+ id.append(data + 4, 16);
+
+ RequestMap::iterator iter = requests_.find(id);
+ if (iter == requests_.end())
+ return false;
+
+ // Parse the STUN message and continue processing as usual.
+
+ ByteBuffer buf(data, size);
+ StunMessage msg;
+ if (!msg.Read(&buf))
+ return false;
+
+ return CheckResponse(&msg);
+}
+
+StunRequest::StunRequest()
+ : manager_(0), id_(CreateRandomString(16)), msg_(0), count_(0),
+ timeout_(false), tstamp_(0) {
+}
+
+StunRequest::StunRequest(StunMessage* request)
+ : manager_(0), id_(request->transaction_id()), msg_(request),
+ count_(0), timeout_(false) {
+}
+
+StunRequest::~StunRequest() {
+ assert(manager_ != NULL);
+ if (manager_) {
+ manager_->Remove(this);
+ manager_->thread_->Clear(this);
+ }
+ delete msg_;
+}
+
+const StunMessageType StunRequest::type() {
+ assert(msg_);
+ return msg_->type();
+}
+
+void StunRequest::set_manager(StunRequestManager* manager) {
+ assert(!manager_);
+ manager_ = manager;
+}
+
+void StunRequest::OnMessage(Message* pmsg) {
+ assert(manager_);
+ assert(pmsg->message_id == MSG_STUN_SEND);
+
+ if (!msg_) {
+ msg_ = new StunMessage();
+ msg_->SetTransactionID(id_);
+ Prepare(msg_);
+ assert(msg_->transaction_id() == id_);
+ }
+
+ if (timeout_) {
+ OnTimeout();
+ delete this;
+ return;
+ }
+
+ tstamp_ = GetMillisecondCount();
+
+ ByteBuffer buf;
+ msg_->Write(&buf);
+ manager_->SignalSendPacket(buf.Data(), buf.Length());
+
+ int delay = GetNextDelay();
+ manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL);
+}
+
+uint32 StunRequest::Elapsed() const {
+ return (GetMillisecondCount() - tstamp_);
+}
+
+int StunRequest::GetNextDelay() {
+ int delay = DELAY_UNIT * _min(1 << count_, DELAY_MAX_FACTOR);
+ count_ += 1;
+ if (count_ == MAX_SENDS)
+ timeout_ = true;
+ return delay;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h
new file mode 100644
index 00000000..86acff91
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.h
@@ -0,0 +1,126 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STUNREQUESTMANAGER_H__
+#define __STUNREQUESTMANAGER_H__
+
+#include "talk/base/sigslot.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/base/stun.h"
+#include <map>
+#include <string>
+
+namespace cricket {
+
+class StunRequest;
+
+// Manages a set of STUN requests, sending and resending until we receive a
+// response or determine that the request has timed out.
+class StunRequestManager {
+public:
+ StunRequestManager(Thread* thread);
+ ~StunRequestManager();
+
+ // Starts sending the given request (perhaps after a delay).
+ void Send(StunRequest* request);
+ void SendDelayed(StunRequest* request, int delay);
+
+ // Removes a stun request that was added previously. This will happen
+ // automatically when a request succeeds, fails, or times out.
+ void Remove(StunRequest* request);
+
+ // Removes all stun requests that were added previously.
+ void Clear();
+
+ // Determines whether the given message is a response to one of the
+ // outstanding requests, and if so, processes it appropriately.
+ bool CheckResponse(StunMessage* msg);
+ bool CheckResponse(const char* data, size_t size);
+
+ // Raised when there are bytes to be sent.
+ sigslot::signal2<const void*, size_t> SignalSendPacket;
+
+private:
+ typedef std::map<std::string, StunRequest*> RequestMap;
+
+ Thread* thread_;
+ RequestMap requests_;
+
+ friend class StunRequest;
+};
+
+// Represents an individual request to be sent. The STUN message can either be
+// constructed beforehand or built on demand.
+class StunRequest : public MessageHandler {
+public:
+ StunRequest();
+ StunRequest(StunMessage* request);
+ virtual ~StunRequest();
+
+ // The manager handling this request (if it has been scheduled for sending).
+ StunRequestManager* manager() { return manager_; }
+
+ // Returns the transaction ID of this request.
+ const std::string& id() { return id_; }
+
+ // Returns the STUN type of the request message.
+ const StunMessageType type();
+
+ // Handles messages for sending and timeout.
+ void OnMessage(Message* pmsg);
+
+ // Time elapsed since last send (in ms)
+ uint32 Elapsed() const;
+
+protected:
+ int count_;
+ bool timeout_;
+
+ // Fills in the actual request to be sent. Note that the transaction ID will
+ // already be set and cannot be changed.
+ virtual void Prepare(StunMessage* request) {}
+
+ // Called when the message receives a response or times out.
+ virtual void OnResponse(StunMessage* response) {}
+ virtual void OnErrorResponse(StunMessage* response) {}
+ virtual void OnTimeout() {}
+ virtual int GetNextDelay();
+
+private:
+ StunRequestManager* manager_;
+ std::string id_;
+ StunMessage* msg_;
+ uint32 tstamp_;
+
+ void set_manager(StunRequestManager* manager);
+
+ friend class StunRequestManager;
+};
+
+} // namespace cricket
+
+#endif // __STUNREQUESTMANAGER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc
new file mode 100644
index 00000000..6e4f6b66
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc
@@ -0,0 +1,160 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/bytebuffer.h"
+#include "talk/p2p/base/stunserver.h"
+#include <iostream>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+StunServer::StunServer(AsyncUDPSocket* socket) : socket_(socket) {
+ socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
+}
+
+StunServer::~StunServer() {
+ socket_->SignalReadPacket.disconnect(this);
+}
+
+void StunServer::OnPacket(
+ const char* buf, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+
+ // TODO: If appropriate, look for the magic cookie before parsing.
+
+ // Parse the STUN message.
+ ByteBuffer bbuf(buf, size);
+ StunMessage msg;
+ if (!msg.Read(&bbuf)) {
+ SendErrorResponse(msg, remote_addr, 400, "Bad Request");
+ return;
+ }
+
+ // TODO: If this is UDP, then we shouldn't allow non-fully-parsed messages.
+
+ // TODO: If unknown non-optiional (<= 0x7fff) attributes are found, send a
+ // 420 "Unknown Attribute" response.
+
+ // TODO: Check that a message-integrity attribute was given (or send 401
+ // "Unauthorized"). Check that a username attribute was given (or send
+ // 432 "Missing Username"). Look up the username and password. If it
+ // is missing or the HMAC is wrong, send 431 "Integrity Check Failure".
+
+ // Send the message to the appropriate handler function.
+ switch (msg.type()) {
+ case STUN_BINDING_REQUEST:
+ OnBindingRequest(&msg, remote_addr);
+ return;
+
+ case STUN_ALLOCATE_REQUEST:
+ OnAllocateRequest(&msg, remote_addr);
+ return;
+
+ default:
+ SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
+ }
+}
+
+void StunServer::OnBindingRequest(
+ StunMessage* msg, const SocketAddress& remote_addr) {
+ StunMessage response;
+ response.SetType(STUN_BINDING_RESPONSE);
+ response.SetTransactionID(msg->transaction_id());
+
+ // Tell the user the address that we received their request from.
+ StunAddressAttribute* mapped_addr =
+ StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ mapped_addr->SetFamily(1);
+ mapped_addr->SetPort(remote_addr.port());
+ mapped_addr->SetIP(remote_addr.ip());
+ response.AddAttribute(mapped_addr);
+
+ // Tell the user the address that we are sending the response from.
+ SocketAddress local_addr = socket_->GetLocalAddress();
+ StunAddressAttribute* source_addr =
+ StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
+ source_addr->SetFamily(1);
+ source_addr->SetPort(local_addr.port());
+ source_addr->SetIP(local_addr.ip());
+ response.AddAttribute(source_addr);
+
+ // TODO: Add username and message-integrity.
+
+ // TODO: Add changed-address. (Keep information about three other servers.)
+
+ SendResponse(response, remote_addr);
+}
+
+void StunServer::OnAllocateRequest(
+ StunMessage* msg, const SocketAddress& addr) {
+ SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
+}
+
+void StunServer::OnSharedSecretRequest(
+ StunMessage* msg, const SocketAddress& addr) {
+ SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
+}
+
+void StunServer::OnSendRequest(StunMessage* msg, const SocketAddress& addr) {
+ SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
+}
+
+void StunServer::SendErrorResponse(
+ const StunMessage& msg, const SocketAddress& addr, int error_code,
+ const char* error_desc) {
+
+ StunMessage err_msg;
+ err_msg.SetType(GetStunErrorResponseType(msg.type()));
+ err_msg.SetTransactionID(msg.transaction_id());
+
+ StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
+ err_code->SetErrorClass(error_code / 100);
+ err_code->SetNumber(error_code % 100);
+ err_code->SetReason(error_desc);
+ err_msg.AddAttribute(err_code);
+
+ SendResponse(err_msg, addr);
+}
+
+void StunServer::SendResponse(
+ const StunMessage& msg, const SocketAddress& addr) {
+
+ ByteBuffer buf;
+ msg.Write(&buf);
+
+ // TODO: Allow response addr attribute if sent from another stun server.
+
+ if (socket_->SendTo(buf.Data(), buf.Length(), addr) < 0)
+ std::cerr << "sendto: " << std::strerror(errno) << std::endl;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h
new file mode 100644
index 00000000..3043645d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.h
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STUNSERVER_H__
+#define __STUNSERVER_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/p2p/base/stun.h"
+
+namespace cricket {
+
+const int STUN_SERVER_PORT = 3478;
+
+class StunServer : public sigslot::has_slots<> {
+public:
+ // Creates a STUN server, which will listen on the given socket.
+ StunServer(AsyncUDPSocket* socket);
+
+ // Removes the STUN server from the socket, but does not delete the socket.
+ ~StunServer();
+
+protected:
+
+ // Slot for AsyncSocket.PacketRead:
+ void OnPacket(
+ const char* buf, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+ // Handlers for the different types of STUN/TURN requests:
+ void OnBindingRequest(StunMessage* msg, const SocketAddress& addr);
+ void OnAllocateRequest(StunMessage* msg, const SocketAddress& addr);
+ void OnSharedSecretRequest(StunMessage* msg, const SocketAddress& addr);
+ void OnSendRequest(StunMessage* msg, const SocketAddress& addr);
+
+ // Sends an error response to the given message back to the user.
+ void SendErrorResponse(
+ const StunMessage& msg, const SocketAddress& addr, int error_code,
+ const char* error_desc);
+
+ // Sends the given message to the appropriate destination.
+ void SendResponse(const StunMessage& msg, const SocketAddress& addr);
+
+private:
+ AsyncUDPSocket* socket_;
+};
+
+} // namespace cricket
+
+#endif // __STUNSERVER_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro
new file mode 100644
index 00000000..dce92ec4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+INCLUDEPATH = ../../..
+DEFINES += POSIX
+
+include(../../../../../conf.pri)
+
+# Input
+SOURCES += \
+ stunserver.cc \
+ stunserver_main.cc \
+ ../../base/host.cc #\
+# ../../base/socketaddresspair.cc
+
+LIBS += ../../../liblibjingle.a
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc
new file mode 100644
index 00000000..bd8a96e5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc
@@ -0,0 +1,66 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/host.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/base/stunserver.h"
+#include <iostream>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+using namespace cricket;
+
+int main(int argc, char* argv[]) {
+ if (argc != 1) {
+ std::cerr << "usage: stunserver" << std::endl;
+ return 1;
+ }
+
+ SocketAddress server_addr(LocalHost().networks()[1]->ip(), 7000);
+
+ Thread *pthMain = Thread::Current();
+
+ AsyncUDPSocket* server_socket = CreateAsyncUDPSocket(pthMain->socketserver());
+ if (server_socket->Bind(server_addr) < 0) {
+ std::cerr << "bind: " << std::strerror(errno) << std::endl;
+ return 1;
+ }
+
+ StunServer* server = new StunServer(server_socket);
+
+ std::cout << "Listening at " << server_addr.ToString() << std::endl;
+
+ pthMain->Loop();
+
+ delete server;
+ delete server_socket;
+ return 0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc
new file mode 100644
index 00000000..a2d2adc6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.cc
@@ -0,0 +1,250 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/p2p/base/tcpport.h"
+#include "talk/base/logging.h"
+#ifdef WIN32
+#include "talk/base/winfirewall.h"
+#endif // WIN32
+#include <iostream>
+#include <cassert>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+#ifdef WIN32
+static WinFirewall win_firewall;
+#endif // WIN32
+
+TCPPort::TCPPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& address)
+ : Port(thread, LOCAL_PORT_TYPE, factory, network), error_(0) {
+ incoming_only_ = (address.port() != 0);
+ socket_ = thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+ socket_->SignalReadEvent.connect(this, &TCPPort::OnAcceptEvent);
+ if (socket_->Bind(address) < 0)
+ LOG(INFO) << "bind: " << std::strerror(socket_->GetError());
+}
+
+TCPPort::~TCPPort() {
+ delete socket_;
+}
+
+Connection* TCPPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
+ // We only support TCP protocols
+ if ((address.protocol() != "tcp") && (address.protocol() != "ssltcp"))
+ return 0;
+
+ // We can't accept TCP connections incoming on other ports
+ if (origin == ORIGIN_OTHER_PORT)
+ return 0;
+
+ // Check if we are allowed to make outgoing TCP connections
+ if (incoming_only_ && (origin == ORIGIN_MESSAGE))
+ return 0;
+
+ // We don't know how to act as an ssl server yet
+ if ((address.protocol() == "ssltcp") && (origin == ORIGIN_THIS_PORT))
+ return 0;
+
+ TCPConnection* conn = 0;
+ if (AsyncTCPSocket * socket = GetIncoming(address.address(), true)) {
+ socket->SignalReadPacket.disconnect(this);
+ conn = new TCPConnection(this, address, socket);
+ } else {
+ conn = new TCPConnection(this, address);
+ }
+ AddConnection(conn);
+ return conn;
+}
+
+void TCPPort::PrepareAddress() {
+ assert(socket_);
+
+ bool allow_listen = true;
+#ifdef WIN32
+ if (win_firewall.Initialize()) {
+ char module_path[MAX_PATH + 1] = { 0 };
+ ::GetModuleFileNameA(NULL, module_path, MAX_PATH);
+ if (win_firewall.Enabled() && !win_firewall.Authorized(module_path)) {
+ allow_listen = false;
+ }
+ }
+#endif // WIN32
+ if (allow_listen) {
+ if (socket_->Listen(5) < 0)
+ LOG(INFO) << "listen: " << std::strerror(socket_->GetError());
+ } else {
+ LOG(INFO) << "not listening due to firewall restrictions";
+ }
+ // Note: We still add the address, since otherwise the remote side won't recognize
+ // our incoming TCP connections.
+ add_address(socket_->GetLocalAddress(), "tcp");
+}
+
+int TCPPort::SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload) {
+ AsyncTCPSocket * socket = 0;
+
+ if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
+ socket = conn->socket();
+ } else {
+ socket = GetIncoming(addr);
+ }
+ if (!socket) {
+ LOG(INFO) << "Unknown destination for SendTo: " << addr.ToString();
+ return -1; // TODO: Set error_
+ }
+
+ //LOG(INFO) << "TCPPort::SendTo(" << size << ", " << addr.ToString() << ")";
+
+ int sent = socket->Send(data, size);
+ if (sent < 0)
+ error_ = socket->GetError();
+ return sent;
+}
+
+int TCPPort::SetOption(Socket::Option opt, int value) {
+ return socket_->SetOption(opt, value);
+}
+
+int TCPPort::GetError() {
+ assert(socket_);
+ return error_;
+}
+
+void TCPPort::OnAcceptEvent(AsyncSocket* socket) {
+ assert(socket == socket_);
+
+ Incoming incoming;
+ AsyncSocket * newsocket = static_cast<AsyncSocket *>(socket->Accept(&incoming.addr));
+ if (!newsocket) {
+ // TODO: Do something better like forwarding the error to the user.
+ LOG(INFO) << "accept: " << socket_->GetError() << " " << std::strerror(socket_->GetError());
+ return;
+ }
+ incoming.socket = new AsyncTCPSocket(newsocket);
+ incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket);
+
+ LOG(INFO) << "accepted incoming connection from " << incoming.addr.ToString();
+ incoming_.push_back(incoming);
+
+ // Prime a read event in case data is waiting
+ newsocket->SignalReadEvent(newsocket);
+}
+
+AsyncTCPSocket * TCPPort::GetIncoming(const SocketAddress& addr, bool remove) {
+ AsyncTCPSocket * socket = 0;
+ for (std::list<Incoming>::iterator it = incoming_.begin(); it != incoming_.end(); ++it) {
+ if (it->addr == addr) {
+ socket = it->socket;
+ if (remove)
+ incoming_.erase(it);
+ break;
+ }
+ }
+ return socket;
+}
+
+void TCPPort::OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ Port::OnReadPacket(data, size, remote_addr);
+}
+
+TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate, AsyncTCPSocket* socket)
+ : Connection(port, 0, candidate), socket_(socket), error_(0) {
+ bool outgoing = (socket_ == 0);
+ if (outgoing) {
+ socket_ = static_cast<AsyncTCPSocket *>(port->CreatePacketSocket(
+ (candidate.protocol() == "ssltcp") ? PROTO_SSLTCP : PROTO_TCP));
+ }
+ socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
+ socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+ if (outgoing) {
+ connected_ = false;
+ socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
+ socket_->Connect(candidate.address());
+ LOG(INFO) << "Connecting to " << candidate.address().ToString();
+ }
+}
+
+TCPConnection::~TCPConnection() {
+}
+
+int TCPConnection::Send(const void* data, size_t size) {
+ if (write_state() != STATE_WRITABLE)
+ return 0;
+
+ int sent = socket_->Send(data, size);
+ if (sent < 0) {
+ error_ = socket_->GetError();
+ } else {
+ sent_total_bytes_ += sent;
+ }
+ return sent;
+}
+
+int TCPConnection::GetError() {
+ return error_;
+}
+
+TCPPort* TCPConnection::tcpport() {
+ return static_cast<TCPPort*>(port_);
+}
+
+void TCPConnection::OnConnect(AsyncTCPSocket* socket) {
+ assert(socket == socket_);
+ LOG(INFO) << "tcp connected to " << socket->GetRemoteAddress().ToString();
+ set_connected(true);
+}
+
+void TCPConnection::OnClose(AsyncTCPSocket* socket, int error) {
+ assert(socket == socket_);
+ LOG(INFO) << "tcp closed with error: " << error;
+ set_connected(false);
+}
+
+void TCPConnection::OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ assert(socket == socket_);
+ Connection::OnReadPacket(data, size);
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h
new file mode 100644
index 00000000..f6a9beb7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/tcpport.h
@@ -0,0 +1,116 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TCPPORT_H__
+#define __TCPPORT_H__
+
+#include <list>
+#include "talk/base/asynctcpsocket.h"
+#include "talk/p2p/base/port.h"
+
+namespace cricket {
+
+class TCPConnection;
+
+extern const std::string LOCAL_PORT_TYPE; // type of TCP ports
+
+// Communicates using a local TCP port.
+//
+// This class is designed to allow subclasses to take advantage of the
+// connection management provided by this class. A subclass should take of all
+// packet sending and preparation, but when a packet is received, it should
+// call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection.
+class TCPPort : public Port {
+public:
+ TCPPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& address);
+ virtual ~TCPPort();
+
+ virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
+
+ virtual void PrepareAddress();
+
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError();
+
+protected:
+ // Handles sending using the local TCP socket.
+ virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
+
+ // Creates TCPConnection for incoming sockets
+ void OnAcceptEvent(AsyncSocket* socket);
+
+ AsyncSocket* socket() { return socket_; }
+
+private:
+ bool incoming_only_;
+ AsyncSocket* socket_;
+ int error_;
+
+ struct Incoming {
+ SocketAddress addr;
+ AsyncTCPSocket * socket;
+ };
+ std::list<Incoming> incoming_;
+
+ AsyncTCPSocket * GetIncoming(const SocketAddress& addr, bool remove = false);
+
+ // Receives packet signal from the local TCP Socket.
+ void OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+ friend class TCPConnection;
+};
+
+class TCPConnection : public Connection {
+public:
+ // Connection is outgoing unless socket is specified
+ TCPConnection(TCPPort* port, const Candidate& candidate, AsyncTCPSocket* socket = 0);
+ virtual ~TCPConnection();
+
+ virtual int Send(const void* data, size_t size);
+ virtual int GetError();
+
+ AsyncTCPSocket * socket() { return socket_; }
+
+private:
+ TCPPort* tcpport();
+ AsyncTCPSocket* socket_;
+ bool connected_;
+ int error_;
+
+ void OnConnect(AsyncTCPSocket* socket);
+ void OnClose(AsyncTCPSocket* socket, int error);
+ void OnReadPacket(const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+ friend class TCPPort;
+};
+
+} // namespace cricket
+
+#endif // __TCPPORT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc
new file mode 100644
index 00000000..fabbb25b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.cc
@@ -0,0 +1,117 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/logging.h"
+#include "talk/p2p/base/udpport.h"
+#include <iostream>
+#include <cassert>
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace cricket {
+
+const std::string LOCAL_PORT_TYPE("local");
+
+UDPPort::UDPPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& address)
+ : Port(thread, LOCAL_PORT_TYPE, factory, network), error_(0) {
+ socket_ = CreatePacketSocket(PROTO_UDP);
+ socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacketSlot);
+ if (socket_->Bind(address) < 0)
+ PLOG(LERROR, socket_->GetError()) << "bind";
+}
+
+UDPPort::UDPPort(Thread* thread, const std::string &type,
+ SocketFactory* factory, Network* network)
+ : Port(thread, type, factory, network), socket_(0), error_(0) {
+}
+
+UDPPort::~UDPPort() {
+ delete socket_;
+}
+
+void UDPPort::PrepareAddress() {
+ assert(socket_);
+ add_address(socket_->GetLocalAddress(), "udp");
+}
+
+Connection* UDPPort::CreateConnection(const Candidate& address, CandidateOrigin origin) {
+ if (address.protocol() != "udp")
+ return 0;
+
+ Connection * conn = new ProxyConnection(this, 0, address);
+ AddConnection(conn);
+ return conn;
+}
+
+int UDPPort::SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload) {
+ assert(socket_);
+ int sent = socket_->SendTo(data, size, addr);
+ if (sent < 0)
+ error_ = socket_->GetError();
+ return sent;
+}
+
+int UDPPort::SetOption(Socket::Option opt, int value) {
+ return socket_->SetOption(opt, value);
+}
+
+int UDPPort::GetError() {
+ assert(socket_);
+ return error_;
+}
+
+void UDPPort::OnReadPacketSlot(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ assert(socket == socket_);
+ OnReadPacket(data, size, remote_addr);
+}
+
+void UDPPort::OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr) {
+ if (Connection* conn = GetConnection(remote_addr)) {
+ conn->OnReadPacket(data, size);
+ } else {
+ Port::OnReadPacket(data, size, remote_addr);
+ }
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h
new file mode 100644
index 00000000..4bcd113e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/udpport.h
@@ -0,0 +1,81 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __UDPPORT_H__
+#define __UDPPORT_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/p2p/base/port.h"
+
+namespace cricket {
+
+extern const std::string LOCAL_PORT_TYPE; // type of UDP ports
+
+// Communicates using a local UDP port.
+//
+// This class is designed to allow subclasses to take advantage of the
+// connection management provided by this class. A subclass should take of all
+// packet sending and preparation, but when a packet is received, it should
+// call this UDPPort::OnReadPacket (3 arg) to dispatch to a connection.
+class UDPPort : public Port {
+public:
+ UDPPort(Thread* thread, SocketFactory* factory, Network* network,
+ const SocketAddress& address);
+ virtual ~UDPPort();
+
+ virtual void PrepareAddress();
+ virtual Connection* CreateConnection(const Candidate& address, CandidateOrigin origin);
+
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError();
+
+protected:
+ UDPPort(Thread* thread, const std::string &type, SocketFactory* factory,
+ Network* network);
+
+ // Handles sending using the local UDP socket.
+ virtual int SendTo(const void* data, size_t size, const SocketAddress& addr, bool payload);
+
+ // Dispatches the given packet to the port or connection as appropriate.
+ void OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr);
+
+ AsyncPacketSocket* socket() { return socket_; }
+
+private:
+ AsyncPacketSocket* socket_;
+ int error_;
+
+ // Receives packet signal from the local UDP Socket.
+ void OnReadPacketSlot(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+};
+
+} // namespace cricket
+
+#endif // __UDPPORT_H__
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am
new file mode 100644
index 00000000..2bdd95ff
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am
@@ -0,0 +1,11 @@
+libcricketp2pclient_la_SOURCES = sessionclient.cc \
+ basicportallocator.cc \
+ socketmonitor.cc
+
+noinst_HEADERS = basicportallocator.h \
+ sessionclient.h \
+ socketmonitor.h
+
+AM_CPPFLAGS = -I$(srcdir)/../../.. -DLINUX -DPOSIX -DINTERNAL_BUILD
+
+noinst_LTLIBRARIES = libcricketp2pclient.la
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc
new file mode 100644
index 00000000..5192595c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc
@@ -0,0 +1,667 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/base/host.h"
+#include "talk/base/logging.h"
+#include "talk/p2p/client/basicportallocator.h"
+#include "talk/p2p/base/port.h"
+#include "talk/p2p/base/udpport.h"
+#include "talk/p2p/base/tcpport.h"
+#include "talk/p2p/base/stunport.h"
+#include "talk/p2p/base/relayport.h"
+#include "talk/p2p/base/helpers.h"
+#include <cassert>
+
+namespace {
+
+const uint32 MSG_CONFIG_START = 1;
+const uint32 MSG_CONFIG_READY = 2;
+const uint32 MSG_ALLOCATE = 3;
+const uint32 MSG_ALLOCATION_PHASE = 4;
+const uint32 MSG_SHAKE = 5;
+
+const uint32 ALLOCATE_DELAY = 250;
+const uint32 ALLOCATION_STEP_DELAY = 1 * 1000;
+
+const int PHASE_UDP = 0;
+const int PHASE_RELAY = 1;
+const int PHASE_TCP = 2;
+const int PHASE_SSLTCP = 3;
+const int kNumPhases = 4;
+
+const float PREF_LOCAL_UDP = 1.0f;
+const float PREF_LOCAL_STUN = 0.9f;
+const float PREF_LOCAL_TCP = 0.8f;
+const float PREF_RELAY = 0.5f;
+
+const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f; // modifiers of the above constants
+const float RELAY_BACKUP_PREF_MODIFIER = -0.2f;
+
+
+// Returns the phase in which a given local candidate (or rather, the port that
+// gave rise to that local candidate) would have been created.
+int LocalCandidateToPhase(const cricket::Candidate& candidate) {
+ cricket::ProtocolType proto;
+ bool result = cricket::StringToProto(candidate.protocol().c_str(), proto);
+ if (result) {
+ if (candidate.type() == cricket::LOCAL_PORT_TYPE) {
+ switch (proto) {
+ case cricket::PROTO_UDP: return PHASE_UDP;
+ case cricket::PROTO_TCP: return PHASE_TCP;
+ default: assert(false);
+ }
+ } else if (candidate.type() == cricket::STUN_PORT_TYPE) {
+ return PHASE_UDP;
+ } else if (candidate.type() == cricket::RELAY_PORT_TYPE) {
+ switch (proto) {
+ case cricket::PROTO_UDP: return PHASE_RELAY;
+ case cricket::PROTO_TCP: return PHASE_TCP;
+ case cricket::PROTO_SSLTCP: return PHASE_SSLTCP;
+ default: assert(false);
+ }
+ } else {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+ return PHASE_UDP; // reached only with assert failure
+}
+
+const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds
+const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds
+
+int ShakeDelay() {
+ int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
+ return SHAKE_MIN_DELAY + cricket::CreateRandomId() % range;
+}
+
+}
+
+namespace cricket {
+
+// Performs the allocation of ports, in a sequenced (timed) manner, for a given
+// network and IP address.
+class AllocationSequence: public MessageHandler {
+public:
+ AllocationSequence(BasicPortAllocatorSession* session,
+ Network* network,
+ PortConfiguration* config);
+ ~AllocationSequence();
+
+ // Determines whether this sequence is operating on an equivalent network
+ // setup to the one given.
+ bool IsEquivalent(Network* network);
+
+ // Starts and stops the sequence. When started, it will continue allocating
+ // new ports on its own timed schedule.
+ void Start();
+ void Stop();
+
+ // MessageHandler:
+ void OnMessage(Message* msg);
+
+ void EnableProtocol(ProtocolType proto);
+ bool ProtocolEnabled(ProtocolType proto) const;
+
+private:
+ BasicPortAllocatorSession* session_;
+ Network* network_;
+ uint32 ip_;
+ PortConfiguration* config_;
+ bool running_;
+ int step_;
+ int step_of_phase_[kNumPhases];
+
+ typedef std::vector<ProtocolType> ProtocolList;
+ ProtocolList protocols_;
+
+ void CreateUDPPorts();
+ void CreateTCPPorts();
+ void CreateStunPorts();
+ void CreateRelayPorts();
+};
+
+
+// BasicPortAllocator
+
+BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager)
+ : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(NULL), relay_address_(NULL) {
+}
+
+BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager, SocketAddress* stun_address, SocketAddress *relay_address)
+ : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(stun_address), relay_address_(relay_address) {
+}
+
+BasicPortAllocator::~BasicPortAllocator() {
+}
+
+int BasicPortAllocator::best_writable_phase() const {
+ // If we are configured with an HTTP proxy, the best bet is to use the relay
+ if ((best_writable_phase_ == -1)
+ && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) {
+ return PHASE_RELAY;
+ }
+ return best_writable_phase_;
+}
+
+PortAllocatorSession *BasicPortAllocator::CreateSession(const std::string &name) {
+ return new BasicPortAllocatorSession(this, name, stun_address_, relay_address_);
+}
+
+void BasicPortAllocator::AddWritablePhase(int phase) {
+ if ((best_writable_phase_ == -1) || (phase < best_writable_phase_))
+ best_writable_phase_ = phase;
+}
+
+// BasicPortAllocatorSession
+
+BasicPortAllocatorSession::BasicPortAllocatorSession(
+ BasicPortAllocator *allocator,
+ const std::string &name)
+ : allocator_(allocator), name_(name), network_thread_(NULL),
+ config_thread_(NULL), allocation_started_(false), running_(false),
+ stun_address_(NULL), relay_address_(NULL) {
+}
+
+BasicPortAllocatorSession::BasicPortAllocatorSession(
+ BasicPortAllocator *allocator,
+ const std::string &name,
+ SocketAddress *stun_address,
+ SocketAddress *relay_address)
+ : allocator_(allocator), name_(name), network_thread_(NULL),
+ config_thread_(NULL), allocation_started_(false), running_(false),
+ stun_address_(stun_address), relay_address_(relay_address) {
+}
+
+BasicPortAllocatorSession::~BasicPortAllocatorSession() {
+ if (config_thread_ != NULL)
+ config_thread_->Clear(this);
+ if (network_thread_ != NULL)
+ network_thread_->Clear(this);
+
+ std::vector<PortData>::iterator it;
+ for (it = ports_.begin(); it != ports_.end(); it++)
+ delete it->port;
+
+ for (uint32 i = 0; i < configs_.size(); ++i)
+ delete configs_[i];
+
+ for (uint32 i = 0; i < sequences_.size(); ++i)
+ delete sequences_[i];
+}
+
+void BasicPortAllocatorSession::GetInitialPorts() {
+ network_thread_ = Thread::Current();
+ if (!config_thread_)
+ config_thread_ = network_thread_;
+
+ config_thread_->Post(this, MSG_CONFIG_START);
+
+ if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHAKER)
+ network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
+}
+
+void BasicPortAllocatorSession::StartGetAllPorts() {
+ assert(Thread::Current() == network_thread_);
+ running_ = true;
+ if (allocation_started_)
+ network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
+ for (uint32 i = 0; i < sequences_.size(); ++i)
+ sequences_[i]->Start();
+ for (size_t i = 0; i < ports_.size(); ++i)
+ ports_[i].port->Start();
+}
+
+void BasicPortAllocatorSession::StopGetAllPorts() {
+ assert(Thread::Current() == network_thread_);
+ running_ = false;
+ network_thread_->Clear(this, MSG_ALLOCATE);
+ for (uint32 i = 0; i < sequences_.size(); ++i)
+ sequences_[i]->Stop();
+}
+
+void BasicPortAllocatorSession::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CONFIG_START:
+ assert(Thread::Current() == config_thread_);
+ GetPortConfigurations();
+ break;
+
+ case MSG_CONFIG_READY:
+ assert(Thread::Current() == network_thread_);
+ OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
+ break;
+
+ case MSG_ALLOCATE:
+ assert(Thread::Current() == network_thread_);
+ OnAllocate();
+ break;
+
+ case MSG_SHAKE:
+ assert(Thread::Current() == network_thread_);
+ OnShake();
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+void BasicPortAllocatorSession::GetPortConfigurations() {
+ PortConfiguration* config = NULL;
+ if (stun_address_ != NULL)
+ config = new PortConfiguration(*stun_address_,
+ CreateRandomString(16),
+ CreateRandomString(16),
+ "");
+ PortConfiguration::PortList ports;
+ if (relay_address_ != NULL) {
+ ports.push_back(ProtocolAddress(*relay_address_, PROTO_UDP));
+ config->AddRelay(ports, RELAY_PRIMARY_PREF_MODIFIER);
+ }
+
+ ConfigReady(config);
+}
+
+void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
+ network_thread_->Post(this, MSG_CONFIG_READY, config);
+}
+
+// Adds a configuration to the list.
+void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
+ if (config)
+ configs_.push_back(config);
+
+ AllocatePorts();
+}
+
+void BasicPortAllocatorSession::AllocatePorts() {
+ assert(Thread::Current() == network_thread_);
+
+ if (allocator_->proxy().type != PROXY_NONE)
+ Port::set_proxy(allocator_->proxy());
+
+ network_thread_->Post(this, MSG_ALLOCATE);
+}
+
+// For each network, see if we have a sequence that covers it already. If not,
+// create a new sequence to create the appropriate ports.
+void BasicPortAllocatorSession::OnAllocate() {
+ std::vector<Network*> networks;
+ allocator_->network_manager()->GetNetworks(networks);
+
+ for (uint32 i = 0; i < networks.size(); ++i) {
+ if (HasEquivalentSequence(networks[i]))
+ continue;
+
+ PortConfiguration* config = NULL;
+ if (configs_.size() > 0)
+ config = configs_.back();
+
+ AllocationSequence* sequence =
+ new AllocationSequence(this, networks[i], config);
+ if (running_)
+ sequence->Start();
+
+ sequences_.push_back(sequence);
+ }
+
+ allocation_started_ = true;
+ if (running_)
+ network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
+}
+
+bool BasicPortAllocatorSession::HasEquivalentSequence(Network* network) {
+ for (uint32 i = 0; i < sequences_.size(); ++i)
+ if (sequences_[i]->IsEquivalent(network))
+ return true;
+ return false;
+}
+
+void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
+ AllocationSequence * seq,
+ float pref,
+ bool prepare_address) {
+ if (!port)
+ return;
+
+ port->set_name(name_);
+ port->set_preference(pref);
+ port->set_generation(generation());
+ PortData data;
+ data.port = port;
+ data.sequence = seq;
+ data.ready = false;
+ ports_.push_back(data);
+ port->SignalAddressReady.connect(this, &BasicPortAllocatorSession::OnAddressReady);
+ port->SignalConnectionCreated.connect(this, &BasicPortAllocatorSession::OnConnectionCreated);
+ port->SignalDestroyed.connect(this, &BasicPortAllocatorSession::OnPortDestroyed);
+ if (prepare_address)
+ port->PrepareAddress();
+ if (running_)
+ port->Start();
+}
+
+void BasicPortAllocatorSession::OnAddressReady(Port *port) {
+ assert(Thread::Current() == network_thread_);
+ std::vector<PortData>::iterator it = std::find(ports_.begin(), ports_.end(), port);
+ assert(it != ports_.end());
+ assert(!it->ready);
+ it->ready = true;
+ SignalPortReady(this, port);
+
+ // Only accumulate the candidates whose protocol has been enabled
+ std::vector<Candidate> candidates;
+ const std::vector<Candidate>& potentials = port->candidates();
+ for (size_t i=0; i<potentials.size(); ++i) {
+ ProtocolType pvalue;
+ if (!StringToProto(potentials[i].protocol().c_str(), pvalue))
+ continue;
+ if (it->sequence->ProtocolEnabled(pvalue)) {
+ candidates.push_back(potentials[i]);
+ }
+ }
+ if (!candidates.empty()) {
+ SignalCandidatesReady(this, candidates);
+ }
+}
+
+void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto) {
+ std::vector<Candidate> candidates;
+ for (std::vector<PortData>::iterator it = ports_.begin(); it != ports_.end(); ++it) {
+ if (!it->ready || (it->sequence != seq))
+ continue;
+
+ const std::vector<Candidate>& potentials = it->port->candidates();
+ for (size_t i=0; i<potentials.size(); ++i) {
+ ProtocolType pvalue;
+ if (!StringToProto(potentials[i].protocol().c_str(), pvalue))
+ continue;
+ if (pvalue == proto) {
+ candidates.push_back(potentials[i]);
+ }
+ }
+ }
+ if (!candidates.empty()) {
+ SignalCandidatesReady(this, candidates);
+ }
+}
+
+void BasicPortAllocatorSession::OnPortDestroyed(Port* port) {
+ assert(Thread::Current() == network_thread_);
+ std::vector<PortData>::iterator iter =
+ find(ports_.begin(), ports_.end(), port);
+ assert(iter != ports_.end());
+ ports_.erase(iter);
+
+ LOG(INFO) << "Removed port from allocator: "
+ << static_cast<int>(ports_.size()) << " remaining";
+}
+
+void BasicPortAllocatorSession::OnConnectionCreated(Port* port, Connection* conn) {
+ conn->SignalStateChange.connect(this, &BasicPortAllocatorSession::OnConnectionStateChange);
+}
+
+void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) {
+ if (conn->write_state() == Connection::STATE_WRITABLE)
+ allocator_->AddWritablePhase(LocalCandidateToPhase(conn->local_candidate()));
+}
+
+void BasicPortAllocatorSession::OnShake() {
+ LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
+
+ std::vector<Port*> ports;
+ std::vector<Connection*> connections;
+
+ for (size_t i = 0; i < ports_.size(); ++i) {
+ if (ports_[i].ready)
+ ports.push_back(ports_[i].port);
+ }
+
+ for (size_t i = 0; i < ports.size(); ++i) {
+ Port::AddressMap::const_iterator iter;
+ for (iter = ports[i]->connections().begin();
+ iter != ports[i]->connections().end();
+ ++iter) {
+ connections.push_back(iter->second);
+ }
+ }
+
+ LOG(INFO) << ">>>>> Destroying " << (int)ports.size() << " ports and "
+ << (int)connections.size() << " connections";
+
+ for (size_t i = 0; i < connections.size(); ++i)
+ connections[i]->Destroy();
+
+ if (running_ || (ports.size() > 0) || (connections.size() > 0))
+ network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
+}
+
+// AllocationSequence
+
+AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
+ Network* network,
+ PortConfiguration* config)
+ : session_(session), network_(network), ip_(network->ip()), config_(config),
+ running_(false), step_(0) {
+
+ // All of the phases up until the best-writable phase so far run in step 0.
+ // The other phases follow sequentially in the steps after that. If there is
+ // no best-writable so far, then only phase 0 occurs in step 0.
+ int last_phase_in_step_zero =
+ _max(0, session->allocator()->best_writable_phase());
+ for (int phase = 0; phase < kNumPhases; ++phase)
+ step_of_phase_[phase] = _max(0, phase - last_phase_in_step_zero);
+
+ // Immediately perform phase 0.
+ OnMessage(NULL);
+}
+
+AllocationSequence::~AllocationSequence() {
+ session_->network_thread()->Clear(this);
+}
+
+bool AllocationSequence::IsEquivalent(Network* network) {
+ return (network == network_) && (ip_ == network->ip());
+}
+
+void AllocationSequence::Start() {
+ running_ = true;
+ session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
+ this,
+ MSG_ALLOCATION_PHASE);
+}
+
+void AllocationSequence::Stop() {
+ running_ = false;
+ session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
+}
+
+void AllocationSequence::OnMessage(Message* msg) {
+ assert(Thread::Current() == session_->network_thread());
+ if (msg)
+ assert(msg->message_id == MSG_ALLOCATION_PHASE);
+
+ // Perform all of the phases in the current step.
+ for (int phase = 0; phase < kNumPhases; phase++) {
+ if (step_of_phase_[phase] != step_)
+ continue;
+
+ switch (phase) {
+ case PHASE_UDP:
+ LOG(INFO) << "Phase=UDP Step=" << step_;
+ CreateUDPPorts();
+ CreateStunPorts();
+ EnableProtocol(PROTO_UDP);
+ break;
+
+ case PHASE_RELAY:
+ LOG(INFO) << "Phase=RELAY Step=" << step_;
+ CreateRelayPorts();
+ break;
+
+ case PHASE_TCP:
+ LOG(INFO) << "Phase=TCP Step=" << step_;
+ CreateTCPPorts();
+ EnableProtocol(PROTO_TCP);
+ break;
+
+ case PHASE_SSLTCP:
+ LOG(INFO) << "Phase=SSLTCP Step=" << step_;
+ EnableProtocol(PROTO_SSLTCP);
+ break;
+
+ default:
+ // Nothing else we can do.
+ return;
+ }
+ }
+
+ // TODO: use different delays for each stage
+ step_ += 1;
+ if (running_) {
+ session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
+ this,
+ MSG_ALLOCATION_PHASE);
+ }
+}
+
+void AllocationSequence::EnableProtocol(ProtocolType proto) {
+ if (!ProtocolEnabled(proto)) {
+ protocols_.push_back(proto);
+ session_->OnProtocolEnabled(this, proto);
+ }
+}
+
+bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
+ for (ProtocolList::const_iterator it = protocols_.begin(); it != protocols_.end(); ++it) {
+ if (*it == proto)
+ return true;
+ }
+ return false;
+}
+
+void AllocationSequence::CreateUDPPorts() {
+ if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_UDP)
+ return;
+
+ Port* port = new UDPPort(session_->network_thread(), NULL, network_,
+ SocketAddress(ip_, 0));
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP);
+}
+
+void AllocationSequence::CreateTCPPorts() {
+ if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_TCP)
+ return;
+
+ Port* port = new TCPPort(session_->network_thread(), NULL, network_,
+ SocketAddress(ip_, 0));
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP);
+}
+
+void AllocationSequence::CreateStunPorts() {
+ if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_STUN)
+ return;
+
+ if (!config_ || config_->stun_address.IsAny())
+ return;
+
+ Port* port = new StunPort(session_->network_thread(), NULL, network_,
+ SocketAddress(ip_, 0), config_->stun_address);
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN);
+}
+
+void AllocationSequence::CreateRelayPorts() {
+ if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY)
+ return;
+
+ if (!config_)
+ return;
+
+ PortConfiguration::RelayList::const_iterator relay;
+ for (relay = config_->relays.begin();
+ relay != config_->relays.end();
+ ++relay) {
+
+ RelayPort *port = new RelayPort(session_->network_thread(), NULL, network_,
+ SocketAddress(ip_, 0),
+ config_->username, config_->password,
+ config_->magic_cookie);
+ // Note: We must add the allocated port before we add addresses because
+ // the latter will create candidates that need name and preference
+ // settings. However, we also can't prepare the address (normally
+ // done by AddAllocatedPort) until we have these addresses. So we
+ // wait to do that until below.
+ session_->AddAllocatedPort(port, this, PREF_RELAY + relay->pref_modifier, false);
+
+ // Add the addresses of this protocol.
+ PortConfiguration::PortList::const_iterator relay_port;
+ for (relay_port = relay->ports.begin();
+ relay_port != relay->ports.end();
+ ++relay_port) {
+ port->AddServerAddress(*relay_port);
+ port->AddExternalAddress(*relay_port);
+ }
+
+ // Start fetching an address for this port.
+ port->PrepareAddress();
+ }
+}
+
+// PortConfiguration
+
+PortConfiguration::PortConfiguration(const SocketAddress& sa,
+ const std::string& un,
+ const std::string& pw,
+ const std::string& mc)
+ : stun_address(sa), username(un), password(pw), magic_cookie(mc) {
+}
+
+void PortConfiguration::AddRelay(const PortList& ports, float pref_modifier) {
+ RelayServer relay;
+ relay.ports = ports;
+ relay.pref_modifier = pref_modifier;
+ relays.push_back(relay);
+}
+
+bool PortConfiguration::SupportsProtocol(
+ const PortConfiguration::RelayServer& relay, ProtocolType type) {
+ PortConfiguration::PortList::const_iterator relay_port;
+ for (relay_port = relay.ports.begin();
+ relay_port != relay.ports.end();
+ ++relay_port) {
+ if (relay_port->proto == type)
+ return true;
+ }
+ return false;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h
new file mode 100644
index 00000000..0f7b96b4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.h
@@ -0,0 +1,172 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BASICPORTALLOCATOR_H_
+#define _BASICPORTALLOCATOR_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/messagequeue.h"
+#include "talk/base/network.h"
+#include "talk/p2p/base/portallocator.h"
+#include <string>
+#include <vector>
+
+namespace cricket {
+
+class BasicPortAllocator: public PortAllocator {
+public:
+ BasicPortAllocator(NetworkManager* network_manager);
+ BasicPortAllocator(NetworkManager* network_manager, SocketAddress *stun_server, SocketAddress *relay_server);
+ virtual ~BasicPortAllocator();
+
+ NetworkManager* network_manager() { return network_manager_; }
+
+ // Returns the best (highest preference) phase that has produced a port that
+ // produced a writable connection. If no writable connections have been
+ // produced, this returns -1.
+ int best_writable_phase() const;
+
+ virtual PortAllocatorSession *CreateSession(const std::string &name);
+
+ // Called whenever a connection becomes writable with the argument being the
+ // phase that the corresponding port was created in.
+ void AddWritablePhase(int phase);
+
+private:
+ NetworkManager* network_manager_;
+ SocketAddress* stun_address_;
+ SocketAddress* relay_address_;
+ int best_writable_phase_;
+};
+
+struct PortConfiguration;
+class AllocationSequence;
+
+class BasicPortAllocatorSession: public PortAllocatorSession, public MessageHandler {
+public:
+ BasicPortAllocatorSession(BasicPortAllocator *allocator,
+ const std::string &name);
+ BasicPortAllocatorSession(BasicPortAllocator *allocator,
+ const std::string &name,
+ SocketAddress *stun_address,
+ SocketAddress *relay_address);
+ ~BasicPortAllocatorSession();
+
+ BasicPortAllocator* allocator() { return allocator_; }
+ const std::string& name() const { return name_; }
+ Thread* network_thread() { return network_thread_; }
+
+ Thread* config_thread() { return config_thread_; }
+ void set_config_thread(Thread* thread) { config_thread_ = thread; }
+
+ virtual void GetInitialPorts();
+ virtual void StartGetAllPorts();
+ virtual void StopGetAllPorts();
+ virtual bool IsGettingAllPorts() { return running_; }
+
+protected:
+ // Starts the process of getting the port configurations.
+ virtual void GetPortConfigurations();
+
+ // Adds a port configuration that is now ready. Once we have one for each
+ // network (or a timeout occurs), we will start allocating ports.
+ void ConfigReady(PortConfiguration* config);
+
+ // MessageHandler. Can be overriden if message IDs do not conflict.
+ virtual void OnMessage(Message *message);
+
+private:
+ void OnConfigReady(PortConfiguration* config);
+ void OnConfigTimeout();
+ void AllocatePorts();
+ void OnAllocate();
+ bool HasEquivalentSequence(Network* network);
+ void AddAllocatedPort(Port* port, AllocationSequence * seq, float pref, bool prepare_address = true);
+ void OnAddressReady(Port *port);
+ void OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto);
+ void OnPortDestroyed(Port* port);
+ void OnConnectionCreated(Port* port, Connection* conn);
+ void OnConnectionStateChange(Connection* conn);
+ void OnShake();
+
+ BasicPortAllocator *allocator_;
+ std::string name_;
+ Thread* network_thread_;
+ Thread* config_thread_;
+ bool configuration_done_;
+ bool allocation_started_;
+ bool running_; // set when StartGetAllPorts is called
+ std::vector<PortConfiguration*> configs_;
+ std::vector<AllocationSequence*> sequences_;
+ SocketAddress *stun_address_;
+ SocketAddress *relay_address_;
+
+ struct PortData {
+ Port * port;
+ AllocationSequence * sequence;
+ bool ready;
+
+ bool operator==(Port * rhs) const { return (port == rhs); }
+ };
+ std::vector<PortData> ports_;
+
+ friend class AllocationSequence;
+};
+
+// Records configuration information useful in creating ports.
+struct PortConfiguration: public MessageData {
+ SocketAddress stun_address;
+ std::string username;
+ std::string password;
+ std::string magic_cookie;
+
+ typedef std::vector<ProtocolAddress> PortList;
+ struct RelayServer {
+ PortList ports;
+ float pref_modifier; // added to the protocol modifier to get the
+ // preference for this particular server
+ };
+
+ typedef std::vector<RelayServer> RelayList;
+ RelayList relays;
+
+ PortConfiguration(const SocketAddress& stun_address,
+ const std::string& username,
+ const std::string& password,
+ const std::string& magic_cookie);
+
+ // Adds another relay server, with the given ports and modifier, to the list.
+ void AddRelay(const PortList& ports, float pref_modifier);
+
+ // Determines whether the given relay server supports the given protocol.
+ static bool SupportsProtocol(const PortConfiguration::RelayServer& relay,
+ ProtocolType type);
+};
+
+} // namespace cricket
+
+#endif // _BASICPORTALLOCATOR_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc
new file mode 100644
index 00000000..09b38a52
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc
@@ -0,0 +1,545 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/base/logging.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmpp/constants.h"
+#include "talk/xmllite/xmlprinter.h"
+#include <iostream>
+#undef SetPort
+
+namespace {
+
+// We only allow usernames to be this many characters or fewer.
+const size_t kMaxUsernameSize = 16;
+
+}
+
+namespace cricket {
+
+#if 0
+>>>>>>
+<iq from="..." to="..." type="set" id="27">
+ <session xmlns="http://www.google.com/session" type="initiate" id="Dr45JU8A34DF" initiator="...">
+ <description xmlns="http://www.whoever.com/whatever">
+ ...
+ </description>
+ </session>
+</iq>
+
+<<<<<<
+<iq from="..." to="..." type="result" id="27"/>
+
+>>>>>>
+<iq from="..." to="..." type="set" id="28">
+ <session xmlns="http://www.google.com/session" type="candidates" id="Dr45JU8A34DF" initiator="...">
+ <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
+ <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
+ <candidate name="rtp" address="X.X.X.X" port="NNN" username="asdf" password="asdf" preference="1.0" type="udp" network="bleh"/>
+ </session>
+</iq>>
+
+<<<<<<
+<iq from="..." to="..." type="result" id="28"/>
+
+#endif
+
+const std::string NS_GOOGLESESSION("http://www.google.com/session");
+const buzz::QName QN_GOOGLESESSION_SESSION(true, NS_GOOGLESESSION, "session");
+const buzz::QName QN_GOOGLESESSION_CANDIDATE(true, NS_GOOGLESESSION, "candidate");
+const buzz::QName QN_GOOGLESESSION_TARGET(true, NS_GOOGLESESSION, "target");
+const buzz::QName QN_GOOGLESESSION_COOKIE(true, NS_GOOGLESESSION, "cookie");
+const buzz::QName QN_GOOGLESESSION_REGARDING(true, NS_GOOGLESESSION, "regarding");
+
+const buzz::QName QN_TYPE(true, buzz::STR_EMPTY, "type");
+const buzz::QName QN_ID(true, buzz::STR_EMPTY, "id");
+const buzz::QName QN_INITIATOR(true, buzz::STR_EMPTY, "initiator");
+const buzz::QName QN_NAME(true, buzz::STR_EMPTY, "name");
+const buzz::QName QN_PORT(true, buzz::STR_EMPTY, "port");
+const buzz::QName QN_NETWORK(true, buzz::STR_EMPTY, "network");
+const buzz::QName QN_GENERATION(true, buzz::STR_EMPTY, "generation");
+const buzz::QName QN_ADDRESS(true, buzz::STR_EMPTY, "address");
+const buzz::QName QN_USERNAME(true, buzz::STR_EMPTY, "username");
+const buzz::QName QN_PASSWORD(true, buzz::STR_EMPTY, "password");
+const buzz::QName QN_PREFERENCE(true, buzz::STR_EMPTY, "preference");
+const buzz::QName QN_PROTOCOL(true, buzz::STR_EMPTY, "protocol");
+const buzz::QName QN_KEY(true, buzz::STR_EMPTY, "key");
+
+class XmlCookie: public SessionMessage::Cookie {
+public:
+ XmlCookie(const buzz::XmlElement* elem)
+ : elem_(new buzz::XmlElement(*elem)) {
+ }
+
+ virtual ~XmlCookie() {
+ delete elem_;
+ }
+
+ const buzz::XmlElement* elem() const { return elem_; }
+
+ virtual Cookie* Copy() {
+ return new XmlCookie(elem_);
+ }
+
+private:
+ buzz::XmlElement* elem_;
+};
+
+SessionClient::SessionClient(SessionManager *session_manager) {
+ session_manager_ = session_manager;
+ session_manager_->SignalSessionCreate.connect(this, &SessionClient::OnSessionCreateSlot);
+ session_manager_->SignalSessionDestroy.connect(this, &SessionClient::OnSessionDestroySlot);
+}
+
+SessionClient::~SessionClient() {
+}
+
+void SessionClient::OnSessionCreateSlot(Session *session, bool received_initiate) {
+ // Does this session belong to this session client?
+ if (session->name() == GetSessionDescriptionName()) {
+ session->SignalOutgoingMessage.connect(this, &SessionClient::OnOutgoingMessage);
+ OnSessionCreate(session, received_initiate);
+ }
+}
+
+void SessionClient::OnSessionDestroySlot(Session *session) {
+ if (session->name() == GetSessionDescriptionName()) {
+ session->SignalOutgoingMessage.disconnect(this);
+ OnSessionDestroy(session);
+ }
+}
+
+bool SessionClient::IsClientStanza(const buzz::XmlElement *stanza) {
+ // Is it a IQ set stanza?
+ if (stanza->Name() != buzz::QN_IQ)
+ return false;
+ if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET)
+ return false;
+
+ // Make sure it has the right child element
+ const buzz::XmlElement* element
+ = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+ if (element == NULL)
+ return false;
+
+ // Is it one of the allowed types?
+ std::string type;
+ if (element->HasAttr(QN_TYPE)) {
+ type = element->Attr(QN_TYPE);
+ if (type != "initiate" && type != "accept" && type != "modify" &&
+ type != "candidates" && type != "reject" && type != "redirect" &&
+ type != "terminate") {
+ return false;
+ }
+ }
+
+ // Does this client own the session description namespace?
+ buzz::QName qn_session_desc(GetSessionDescriptionName(), "description");
+ const buzz::XmlElement* description = element->FirstNamed(qn_session_desc);
+ if (type == "initiate" || type == "accept" || type == "modify") {
+ if (description == NULL)
+ return false;
+ } else {
+ if (description != NULL)
+ return false;
+ }
+
+ // It's good
+ return true;
+}
+
+void SessionClient::OnIncomingStanza(const buzz::XmlElement *stanza) {
+ SessionMessage message;
+ if (!ParseIncomingMessage(stanza, message))
+ return;
+
+ session_manager_->OnIncomingMessage(message);
+}
+
+void SessionClient::OnFailedSend(const buzz::XmlElement *original_stanza,
+ const buzz::XmlElement *failure_stanza) {
+ SessionMessage message;
+ if (!ParseIncomingMessage(original_stanza, message))
+ return;
+
+ // Note the from/to represents the *original* stanza and not the from/to
+ // on any return path
+ session_manager_->OnIncomingError(message);
+}
+
+bool SessionClient::ParseIncomingMessage(const buzz::XmlElement *stanza,
+ SessionMessage& message) {
+ // Parse stanza into SessionMessage
+ const buzz::XmlElement* element
+ = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+
+ std::string type = element->Attr(QN_TYPE);
+ if (type == "initiate" || type == "accept" || type == "modify") {
+ ParseInitiateAcceptModify(stanza, message);
+ } else if (type == "candidates") {
+ ParseCandidates(stanza, message);
+ } else if (type == "reject" || type == "terminate") {
+ ParseRejectTerminate(stanza, message);
+ } else if (type == "redirect") {
+ ParseRedirect(stanza, message);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void SessionClient::ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message) {
+ if (stanza->HasAttr(buzz::QN_FROM))
+ message.set_from(stanza->Attr(buzz::QN_FROM));
+ if (stanza->HasAttr(buzz::QN_TO))
+ message.set_to(stanza->Attr(buzz::QN_TO));
+
+ const buzz::XmlElement *element
+ = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+ if (element->HasAttr(QN_ID))
+ message.session_id().set_id_str(element->Attr(QN_ID));
+
+ if (element->HasAttr(QN_INITIATOR))
+ message.session_id().set_initiator(element->Attr(QN_INITIATOR));
+
+ std::string type = element->Attr(QN_TYPE);
+ if (type == "initiate") {
+ message.set_type(SessionMessage::TYPE_INITIATE);
+ } else if (type == "accept") {
+ message.set_type(SessionMessage::TYPE_ACCEPT);
+ } else if (type == "modify") {
+ message.set_type(SessionMessage::TYPE_MODIFY);
+ } else if (type == "candidates") {
+ message.set_type(SessionMessage::TYPE_CANDIDATES);
+ } else if (type == "reject") {
+ message.set_type(SessionMessage::TYPE_REJECT);
+ } else if (type == "redirect") {
+ message.set_type(SessionMessage::TYPE_REDIRECT);
+ } else if (type == "terminate") {
+ message.set_type(SessionMessage::TYPE_TERMINATE);
+ } else {
+ assert(false);
+ }
+}
+
+void SessionClient::ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message) {
+ // Pull the standard header pieces out
+ ParseHeader(stanza, message);
+
+ // Parse session description
+ const buzz::XmlElement *session
+ = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+ buzz::QName qn_session_desc(GetSessionDescriptionName(), "description");
+ const buzz::XmlElement* desc_elem = session->FirstNamed(qn_session_desc);
+ const SessionDescription *description = NULL;
+ if (desc_elem)
+ description = CreateSessionDescription(desc_elem);
+ message.set_name(GetSessionDescriptionName());
+ message.set_description(description);
+}
+
+void SessionClient::ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message) {
+ // Pull the standard header pieces out
+ ParseHeader(stanza, message);
+
+ // Parse candidates and session description
+ std::vector<Candidate> candidates;
+ const buzz::XmlElement *element
+ = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+ const buzz::XmlElement *child = element->FirstElement();
+ while (child != NULL) {
+ if (child->Name() == QN_GOOGLESESSION_CANDIDATE) {
+ Candidate candidate;
+ if (ParseCandidate(child, &candidate))
+ candidates.push_back(candidate);
+ }
+ child = child->NextElement();
+ }
+ message.set_name(GetSessionDescriptionName());
+ message.set_candidates(candidates);
+}
+
+void SessionClient::ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message) {
+ // Reject and terminate are very simple
+ ParseHeader(stanza, message);
+}
+
+bool SessionClient::ParseCandidate(const buzz::XmlElement *child,
+ Candidate* candidate) {
+ // Check for all of the required attributes.
+ if (!child->HasAttr(QN_NAME) ||
+ !child->HasAttr(QN_ADDRESS) ||
+ !child->HasAttr(QN_PORT) ||
+ !child->HasAttr(QN_USERNAME) ||
+ !child->HasAttr(QN_PREFERENCE) ||
+ !child->HasAttr(QN_PROTOCOL) ||
+ !child->HasAttr(QN_GENERATION)) {
+ LOG(LERROR) << "Candidate missing required attribute";
+ return false;
+ }
+
+ SocketAddress address;
+ address.SetIP(child->Attr(QN_ADDRESS));
+ std::istringstream ist(child->Attr(QN_PORT));
+ int port;
+ ist >> port;
+ address.SetPort(port);
+
+ if (address.IsAny()) {
+ LOG(LERROR) << "Candidate has address 0";
+ return false;
+ }
+
+ // Always disallow addresses that refer to the local host.
+ if (address.IsLocalIP()) {
+ LOG(LERROR) << "Candidate has local IP address";
+ return false;
+ }
+
+ // Disallow all ports below 1024, except for 80 and 443 on public addresses.
+ if (port < 1024) {
+ if ((port != 80) && (port != 443)) {
+ LOG(LERROR) << "Candidate has port below 1024, not 80 or 443";
+ return false;
+ }
+ if (address.IsPrivateIP()) {
+ LOG(LERROR) << "Candidate has port of 80 or 443 with private IP address";
+ return false;
+ }
+ }
+
+ candidate->set_name(child->Attr(QN_NAME));
+ candidate->set_address(address);
+ candidate->set_username(child->Attr(QN_USERNAME));
+ candidate->set_preference_str(child->Attr(QN_PREFERENCE));
+ candidate->set_protocol(child->Attr(QN_PROTOCOL));
+ candidate->set_generation_str(child->Attr(QN_GENERATION));
+
+ // Check that the username is not too long and does not use any bad chars.
+ if (candidate->username().size() > kMaxUsernameSize) {
+ LOG(LERROR) << "Candidate username is too long";
+ return false;
+ }
+ if (!IsBase64Encoded(candidate->username())) {
+ LOG(LERROR) << "Candidate username has non-base64 encoded characters";
+ return false;
+ }
+
+ // Look for the non-required attributes.
+ if (child->HasAttr(QN_PASSWORD))
+ candidate->set_password(child->Attr(QN_PASSWORD));
+ if (child->HasAttr(QN_TYPE))
+ candidate->set_type(child->Attr(QN_TYPE));
+ if (child->HasAttr(QN_NETWORK))
+ candidate->set_network_name(child->Attr(QN_NETWORK));
+
+ return true;
+}
+
+void SessionClient::ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message) {
+ // Pull the standard header pieces out
+ ParseHeader(stanza, message);
+ const buzz::XmlElement *session = stanza->FirstNamed(QN_GOOGLESESSION_SESSION);
+
+ // Parse the target and cookie.
+
+ const buzz::XmlElement* target = session->FirstNamed(QN_GOOGLESESSION_TARGET);
+ if (target)
+ message.set_redirect_target(target->Attr(QN_NAME));
+
+ const buzz::XmlElement* cookie = session->FirstNamed(QN_GOOGLESESSION_COOKIE);
+ if (cookie)
+ message.set_redirect_cookie(new XmlCookie(cookie));
+}
+
+void SessionClient::OnOutgoingMessage(Session *session, const SessionMessage &message) {
+ // Translate the message into an XMPP stanza
+
+ buzz::XmlElement *result = NULL;
+ switch (message.type()) {
+ case SessionMessage::TYPE_INITIATE:
+ case SessionMessage::TYPE_ACCEPT:
+ case SessionMessage::TYPE_MODIFY:
+ result = TranslateInitiateAcceptModify(message);
+ break;
+
+ case SessionMessage::TYPE_CANDIDATES:
+ result = TranslateCandidates(message);
+ break;
+
+ case SessionMessage::TYPE_REJECT:
+ case SessionMessage::TYPE_TERMINATE:
+ result = TranslateRejectTerminate(message);
+ break;
+
+ case SessionMessage::TYPE_REDIRECT:
+ result = TranslateRedirect(message);
+ break;
+ }
+
+ // Send the stanza. Note that SessionClient is passing on ownership
+ // of result.
+ if (result != NULL) {
+ SignalSendStanza(this, result);
+ }
+}
+
+buzz::XmlElement *SessionClient::TranslateHeader(const SessionMessage &message) {
+ buzz::XmlElement *result = new buzz::XmlElement(buzz::QN_IQ);
+ result->AddAttr(buzz::QN_TO, message.to());
+ result->AddAttr(buzz::QN_TYPE, buzz::STR_SET);
+ buzz::XmlElement *session = new buzz::XmlElement(QN_GOOGLESESSION_SESSION, true);
+ result->AddElement(session);
+ switch (message.type()) {
+ case SessionMessage::TYPE_INITIATE:
+ session->AddAttr(QN_TYPE, "initiate");
+ break;
+ case SessionMessage::TYPE_ACCEPT:
+ session->AddAttr(QN_TYPE, "accept");
+ break;
+ case SessionMessage::TYPE_MODIFY:
+ session->AddAttr(QN_TYPE, "modify");
+ break;
+ case SessionMessage::TYPE_CANDIDATES:
+ session->AddAttr(QN_TYPE, "candidates");
+ break;
+ case SessionMessage::TYPE_REJECT:
+ session->AddAttr(QN_TYPE, "reject");
+ break;
+ case SessionMessage::TYPE_REDIRECT:
+ session->AddAttr(QN_TYPE, "redirect");
+ break;
+ case SessionMessage::TYPE_TERMINATE:
+ session->AddAttr(QN_TYPE, "terminate");
+ break;
+ }
+ session->AddAttr(QN_ID, message.session_id().id_str());
+ session->AddAttr(QN_INITIATOR, message.session_id().initiator());
+ return result;
+}
+
+buzz::XmlElement *SessionClient::TranslateCandidate(const Candidate &candidate) {
+ buzz::XmlElement *result = new buzz::XmlElement(QN_GOOGLESESSION_CANDIDATE);
+ result->AddAttr(QN_NAME, candidate.name());
+ result->AddAttr(QN_ADDRESS, candidate.address().IPAsString());
+ result->AddAttr(QN_PORT, candidate.address().PortAsString());
+ result->AddAttr(QN_USERNAME, candidate.username());
+ result->AddAttr(QN_PASSWORD, candidate.password());
+ result->AddAttr(QN_PREFERENCE, candidate.preference_str());
+ result->AddAttr(QN_PROTOCOL, candidate.protocol());
+ result->AddAttr(QN_TYPE, candidate.type());
+ result->AddAttr(QN_NETWORK, candidate.network_name());
+ result->AddAttr(QN_GENERATION, candidate.generation_str());
+ return result;
+}
+
+buzz::XmlElement *SessionClient::TranslateInitiateAcceptModify(const SessionMessage &message) {
+ // Header info common to all message types
+ buzz::XmlElement *result = TranslateHeader(message);
+ buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
+
+ // Candidates
+ assert(message.candidates().size() == 0);
+
+ // Session Description
+ buzz::XmlElement* description = TranslateSessionDescription(message.description());
+ assert(description->Name().LocalPart() == "description");
+ assert(description->Name().Namespace() == GetSessionDescriptionName());
+ session->AddElement(description);
+
+ if (message.redirect_cookie() != NULL) {
+ const buzz::XmlElement* cookie =
+ reinterpret_cast<XmlCookie*>(message.redirect_cookie())->elem();
+ for (const buzz::XmlElement* elem = cookie->FirstElement(); elem; elem = elem->NextElement())
+ session->AddElement(new buzz::XmlElement(*elem));
+ }
+
+ return result;
+}
+
+buzz::XmlElement *SessionClient::TranslateCandidates(const SessionMessage &message) {
+ // Header info common to all message types
+ buzz::XmlElement *result = TranslateHeader(message);
+ buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
+
+ // Candidates
+ std::vector<Candidate>::const_iterator it;
+ for (it = message.candidates().begin(); it != message.candidates().end(); it++)
+ session->AddElement(TranslateCandidate(*it));
+
+ return result;
+}
+
+buzz::XmlElement *SessionClient::TranslateRejectTerminate(const SessionMessage &message) {
+ // These messages are simple, and only have a header
+ return TranslateHeader(message);
+}
+
+buzz::XmlElement *SessionClient::TranslateRedirect(const SessionMessage &message) {
+ // Header info common to all message types
+ buzz::XmlElement *result = TranslateHeader(message);
+ buzz::XmlElement *session = result->FirstNamed(QN_GOOGLESESSION_SESSION);
+
+ assert(message.candidates().size() == 0);
+ assert(message.description() == NULL);
+
+ assert(message.redirect_target().size() > 0);
+ buzz::XmlElement* target = new buzz::XmlElement(QN_GOOGLESESSION_TARGET);
+ target->AddAttr(QN_NAME, message.redirect_target());
+ session->AddElement(target);
+
+ buzz::XmlElement* cookie = new buzz::XmlElement(QN_GOOGLESESSION_COOKIE);
+ session->AddElement(cookie);
+
+ // If the message does not have a redirect cookie, then this is a redirect
+ // initiated by us. We will automatically add a regarding cookie.
+ if (message.redirect_cookie() == NULL) {
+ buzz::XmlElement* regarding = new buzz::XmlElement(QN_GOOGLESESSION_REGARDING);
+ regarding->AddAttr(QN_NAME, GetJid().BareJid().Str());
+ cookie->AddElement(regarding);
+ } else {
+ const buzz::XmlElement* cookie_elem =
+ reinterpret_cast<const XmlCookie*>(message.redirect_cookie())->elem();
+ const buzz::XmlElement* elem;
+ for (elem = cookie_elem->FirstElement(); elem; elem = elem->NextElement())
+ cookie->AddElement(new buzz::XmlElement(*elem));
+ }
+
+ return result;
+}
+
+SessionManager *SessionClient::session_manager() {
+ return session_manager_;
+}
+
+} // namespace cricket
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h
new file mode 100644
index 00000000..69a18422
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.h
@@ -0,0 +1,104 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SESSIONCLIENT_H_
+#define _SESSIONCLIENT_H_
+
+#include "talk/p2p/base/sessiondescription.h"
+#include "talk/p2p/base/sessionmessage.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/jid.h"
+namespace cricket {
+
+// Generic XMPP session client. This class knows how to translate
+// a SessionMessage to and from XMPP stanzas. The SessionDescription
+// is a custom description implemented by the client.
+
+// This class knows how to talk to the session manager, however the
+// session manager doesn't have knowledge of a particular SessionClient.
+
+class SessionClient : public sigslot::has_slots<> {
+public:
+ SessionClient(SessionManager *psm);
+ virtual ~SessionClient();
+
+ // Call this method to determine if a stanza is for this session client
+ bool IsClientStanza(const buzz::XmlElement *stanza);
+
+ // Call this method to deliver a stanza to this session client
+ void OnIncomingStanza(const buzz::XmlElement *stanza);
+
+ // Call this whenever an error is recieved in response to an outgoing
+ // session IQ. Include the original stanza and any failure stanza. If
+ // the failure is due to a time out, the failure_stanza should be NULL
+ void OnFailedSend(const buzz::XmlElement* original_stanza,
+ const buzz::XmlElement* failure_stanza);
+
+ SessionManager *session_manager();
+
+ // Implement this method for stanza sending
+ sigslot::signal2<SessionClient*, const buzz::XmlElement*> SignalSendStanza;
+
+protected:
+ // Override these to know when sessions belonging to this client create/destroy
+
+ virtual void OnSessionCreate(Session * /*session*/, bool /*received_initiate*/) {}
+ virtual void OnSessionDestroy(Session * /*session*/) {}
+
+ // Implement these methods for a custom session description
+ virtual const SessionDescription *CreateSessionDescription(const buzz::XmlElement *element) = 0;
+ virtual buzz::XmlElement *TranslateSessionDescription(const SessionDescription *description) = 0;
+ virtual const std::string &GetSessionDescriptionName() = 0;
+ virtual const buzz::Jid &GetJid() const = 0;
+
+ SessionManager *session_manager_;
+
+private:
+ void OnSessionCreateSlot(Session *session, bool received_initiate);
+ void OnSessionDestroySlot(Session *session);
+ void OnOutgoingMessage(Session *session, const SessionMessage &message);
+ void ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message);
+ bool ParseCandidate(const buzz::XmlElement *child, Candidate* candidate);
+ bool ParseIncomingMessage(const buzz::XmlElement *stanza,
+ SessionMessage& message);
+ void ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message);
+ void ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message);
+ void ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message);
+ void ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message);
+ buzz::XmlElement *TranslateHeader(const SessionMessage &message);
+ buzz::XmlElement *TranslateCandidate(const Candidate &candidate);
+ buzz::XmlElement *TranslateInitiateAcceptModify(const SessionMessage &message);
+ buzz::XmlElement *TranslateCandidates(const SessionMessage &message);
+ buzz::XmlElement *TranslateRejectTerminate(const SessionMessage &message);
+ buzz::XmlElement *TranslateRedirect(const SessionMessage &message);
+
+};
+
+} // namespace cricket
+
+#endif // _SESSIONCLIENT_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc
new file mode 100644
index 00000000..dd9fa67c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc
@@ -0,0 +1,149 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "socketmonitor.h"
+#include <cassert>
+
+namespace cricket {
+
+const uint32 MSG_MONITOR_POLL = 1;
+const uint32 MSG_MONITOR_START = 2;
+const uint32 MSG_MONITOR_STOP = 3;
+const uint32 MSG_MONITOR_SIGNAL = 4;
+
+SocketMonitor::SocketMonitor(P2PSocket *socket, Thread *monitor_thread) {
+ socket_ = socket;
+ monitoring_thread_ = monitor_thread;
+ monitoring_ = false;
+}
+
+SocketMonitor::~SocketMonitor() {
+ socket_->thread()->Clear(this);
+ monitoring_thread_->Clear(this);
+}
+
+void SocketMonitor::Start(int milliseconds) {
+ rate_ = milliseconds;
+ if (rate_ < 250)
+ rate_ = 250;
+ socket_->thread()->Post(this, MSG_MONITOR_START);
+}
+
+void SocketMonitor::Stop() {
+ socket_->thread()->Post(this, MSG_MONITOR_STOP);
+}
+
+void SocketMonitor::OnMessage(Message *message) {
+ CritScope cs(&crit_);
+
+ switch (message->message_id) {
+ case MSG_MONITOR_START:
+ assert(Thread::Current() == socket_->thread());
+ if (!monitoring_) {
+ monitoring_ = true;
+ socket_->SignalConnectionMonitor.connect(this, &SocketMonitor::OnConnectionMonitor);
+ PollSocket(true);
+ }
+ break;
+
+ case MSG_MONITOR_STOP:
+ assert(Thread::Current() == socket_->thread());
+ if (monitoring_) {
+ monitoring_ = false;
+ socket_->SignalConnectionMonitor.disconnect(this);
+ socket_->thread()->Clear(this);
+ }
+ break;
+
+ case MSG_MONITOR_POLL:
+ assert(Thread::Current() == socket_->thread());
+ PollSocket(true);
+ break;
+
+ case MSG_MONITOR_SIGNAL:
+ {
+ assert(Thread::Current() == monitoring_thread_);
+ std::vector<ConnectionInfo> infos = connection_infos_;
+ crit_.Leave();
+ SignalUpdate(this, infos);
+ crit_.Enter();
+ }
+ break;
+ }
+}
+
+void SocketMonitor::OnConnectionMonitor(P2PSocket *socket) {
+ CritScope cs(&crit_);
+ if (monitoring_)
+ PollSocket(false);
+}
+
+void SocketMonitor::PollSocket(bool poll) {
+ CritScope cs(&crit_);
+ assert(Thread::Current() == socket_->thread());
+
+ // Gather connection infos
+
+ connection_infos_.clear();
+ const std::vector<Connection *> &connections = socket_->connections();
+ std::vector<Connection *>::const_iterator it;
+ for (it = connections.begin(); it != connections.end(); it++) {
+ Connection *connection = *it;
+ ConnectionInfo info;
+ info.best_connection = socket_->best_connection() == connection;
+ info.readable = connection->read_state() == Connection::STATE_READABLE;
+ info.writable = connection->write_state() == Connection::STATE_WRITABLE;
+ info.timeout = connection->write_state() == Connection::STATE_WRITE_TIMEOUT;
+ info.new_connection = false; // connection->new_connection();
+ info.rtt = connection->rtt();
+ info.sent_total_bytes = connection->sent_total_bytes();
+ info.sent_bytes_second = connection->sent_bytes_second();
+ info.recv_total_bytes = connection->recv_total_bytes();
+ info.recv_bytes_second = connection->recv_bytes_second();
+ info.local_candidate = connection->local_candidate();
+ info.remote_candidate = connection->remote_candidate();
+ info.est_quality = connection->port()->network()->quality();
+ info.key = reinterpret_cast<void *>(connection);
+ connection_infos_.push_back(info);
+ }
+
+ // Signal the monitoring thread, start another poll timer
+
+ monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
+ if (poll)
+ socket_->thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL);
+}
+
+P2PSocket *SocketMonitor::socket() {
+ return socket_;
+}
+
+Thread *SocketMonitor::monitor_thread() {
+ return monitoring_thread_;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h
new file mode 100644
index 00000000..549e90b6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.h
@@ -0,0 +1,85 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SOCKETMONITOR_H_
+#define _SOCKETMONITOR_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/criticalsection.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/p2p/base/port.h"
+#include <vector>
+
+namespace cricket {
+
+struct ConnectionInfo {
+ bool best_connection;
+ bool writable;
+ bool readable;
+ bool timeout;
+ bool new_connection;
+ size_t rtt;
+ size_t sent_total_bytes;
+ size_t sent_bytes_second;
+ size_t recv_total_bytes;
+ size_t recv_bytes_second;
+ Candidate local_candidate;
+ Candidate remote_candidate;
+ double est_quality;
+ void *key;
+};
+
+class SocketMonitor : public MessageHandler, public sigslot::has_slots<> {
+public:
+ SocketMonitor(P2PSocket *socket, Thread *monitor_thread);
+ ~SocketMonitor();
+
+ void Start(int cms);
+ void Stop();
+
+ P2PSocket *socket();
+ Thread *monitor_thread();
+
+ sigslot::signal2<SocketMonitor *, const std::vector<ConnectionInfo> &> SignalUpdate;
+
+protected:
+ void OnMessage(Message *message);
+ void OnConnectionMonitor(P2PSocket *socket);
+ void PollSocket(bool poll);
+
+ std::vector<ConnectionInfo> connection_infos_;
+ P2PSocket *socket_;
+ Thread *monitoring_thread_;
+ CriticalSection crit_;
+ uint32 rate_;
+ bool monitoring_;
+};
+
+}
+
+#endif // _SOCKETMONITOR_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am
new file mode 100644
index 00000000..6cfc5b24
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am
@@ -0,0 +1,3 @@
+noinst_HEADERS = receiver.h sessionsendtask.h
+SUBDIRS = phone
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am
new file mode 100644
index 00000000..b2acbf81
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am
@@ -0,0 +1,18 @@
+libcricketsessionphone_la_SOURCES = audiomonitor.cc \
+ channelmanager.cc \
+ voicechannel.cc \
+ call.cc \
+ phonesessionclient.cc \
+ linphonemediaengine.cc
+
+noinst_HEADERS = audiomonitor.h \
+ channelmanager.h \
+ linphonemediaengine.h \
+ mediaengine.h \
+ phonesessionclient.h \
+ voicechannel.h \
+ call.h \
+ mediachannel.h
+
+AM_CPPFLAGS = -DPOSIX $(ORTP_CFLAGS) $(ILBC_CFLAGS) -I$(srcdir)/../../../talk/third_party/mediastreamer -I$(srcdir)/../../.. $(GLIB_CFLAGS) $(SPEEX_CFLAGS)
+noinst_LTLIBRARIES = libcricketsessionphone.la
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc
new file mode 100644
index 00000000..c1b63d1b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc
@@ -0,0 +1,119 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/session/phone/audiomonitor.h"
+#include "talk/session/phone/voicechannel.h"
+#include <cassert>
+
+namespace cricket {
+
+const uint32 MSG_MONITOR_POLL = 1;
+const uint32 MSG_MONITOR_START = 2;
+const uint32 MSG_MONITOR_STOP = 3;
+const uint32 MSG_MONITOR_SIGNAL = 4;
+
+AudioMonitor::AudioMonitor(VoiceChannel *voice_channel, Thread *monitor_thread) {
+ voice_channel_ = voice_channel;
+ monitoring_thread_ = monitor_thread;
+ monitoring_ = false;
+}
+
+AudioMonitor::~AudioMonitor() {
+ voice_channel_->worker_thread()->Clear(this);
+ monitoring_thread_->Clear(this);
+}
+
+void AudioMonitor::Start(int milliseconds) {
+ rate_ = milliseconds;
+ if (rate_ < 100)
+ rate_ = 100;
+ voice_channel_->worker_thread()->Post(this, MSG_MONITOR_START);
+}
+
+void AudioMonitor::Stop() {
+ voice_channel_->worker_thread()->Post(this, MSG_MONITOR_STOP);
+}
+
+void AudioMonitor::OnMessage(Message *message) {
+ CritScope cs(&crit_);
+
+ switch (message->message_id) {
+ case MSG_MONITOR_START:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ if (!monitoring_) {
+ monitoring_ = true;
+ PollVoiceChannel();
+ }
+ break;
+
+ case MSG_MONITOR_STOP:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ if (monitoring_) {
+ monitoring_ = false;
+ voice_channel_->worker_thread()->Clear(this);
+ }
+ break;
+
+ case MSG_MONITOR_POLL:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ PollVoiceChannel();
+ break;
+
+ case MSG_MONITOR_SIGNAL:
+ {
+ assert(Thread::Current() == monitoring_thread_);
+ AudioInfo info = audio_info_;
+ crit_.Leave();
+ SignalUpdate(this, audio_info_);
+ crit_.Enter();
+ }
+ break;
+ }
+}
+
+void AudioMonitor::PollVoiceChannel() {
+ CritScope cs(&crit_);
+ assert(Thread::Current() == voice_channel_->worker_thread());
+
+ // Gather connection infos
+ audio_info_.input_level = voice_channel_->GetInputLevel_w();
+ audio_info_.output_level = voice_channel_->GetOutputLevel_w();
+
+ // Signal the monitoring thread, start another poll timer
+ monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
+ voice_channel_->worker_thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL);
+}
+
+VoiceChannel *AudioMonitor::voice_channel() {
+ return voice_channel_;
+}
+
+Thread *AudioMonitor::monitor_thread() {
+ return monitoring_thread_;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h
new file mode 100644
index 00000000..96b95bd7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CRICKET_PHONE_AUDIOMONITOR_H_
+#define _CRICKET_PHONE_AUDIOMONITOR_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/sigslot.h"
+#include "talk/p2p/base/port.h"
+#include <vector>
+
+namespace cricket {
+
+class VoiceChannel;
+
+
+struct AudioInfo {
+ int input_level;
+ int output_level;
+};
+
+class AudioMonitor : public MessageHandler, public sigslot::has_slots<> {
+public:
+ AudioMonitor(VoiceChannel* voice_channel, Thread *monitor_thread);
+ ~AudioMonitor();
+
+ void Start(int cms);
+ void Stop();
+
+ VoiceChannel* voice_channel();
+ Thread *monitor_thread();
+
+ sigslot::signal2<AudioMonitor*, const AudioInfo&> SignalUpdate;
+
+protected:
+ void OnMessage(Message *message);
+ void PollVoiceChannel();
+
+ AudioInfo audio_info_;
+ VoiceChannel* voice_channel_;
+ Thread* monitoring_thread_;
+ CriticalSection crit_;
+ uint32 rate_;
+ bool monitoring_;
+};
+
+}
+
+#endif // _CRICKET_PHONE_AUDIOMONITOR_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc
new file mode 100644
index 00000000..31b12e92
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc
@@ -0,0 +1,258 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/thread.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/session/phone/call.h"
+
+namespace cricket {
+
+const uint32 MSG_CHECKAUTODESTROY = 1;
+
+Call::Call(PhoneSessionClient *session_client) : muted_(false) {
+ session_client_ = session_client;
+ id_ = CreateRandomId();
+}
+
+Call::~Call() {
+ while (sessions_.begin() != sessions_.end()) {
+ Session *session = sessions_[0];
+ RemoveSession(session);
+ session_client_->session_manager()->DestroySession(session);
+ }
+ Thread::Current()->Clear(this);
+}
+
+Session *Call::InitiateSession(const buzz::Jid &jid) {
+ Session *session = session_client_->CreateSession(this);
+ AddSession(session);
+ session->Initiate(jid.Str(), session_client_->CreateOfferSessionDescription());
+ return session;
+}
+
+void Call::AcceptSession(Session *session) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Accept(session_client_->CreateAcceptSessionDescription(session->remote_description()));
+}
+
+void Call::RedirectSession(Session *session, const buzz::Jid &to) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Redirect(to.Str());
+}
+
+void Call::RejectSession(Session *session) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Reject();
+}
+
+void Call::TerminateSession(Session *session) {
+ assert(std::find(sessions_.begin(), sessions_.end(), session) != sessions_.end());
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ if (it != sessions_.end())
+ (*it)->Terminate();
+}
+
+void Call::Terminate() {
+ // There may be more than one session to terminate
+ std::vector<Session *>::iterator it = sessions_.begin();
+ for (it = sessions_.begin(); it != sessions_.end(); it++)
+ TerminateSession(*it);
+}
+
+void Call::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CHECKAUTODESTROY:
+ // If no more sessions for this call, delete it
+ if (sessions_.size() == 0)
+ session_client_->DestroyCall(this);
+ break;
+ }
+}
+
+const std::vector<Session *> &Call::sessions() {
+ return sessions_;
+}
+
+void Call::AddSession(Session *session) {
+ // Add session to list, create voice channel for this session
+ sessions_.push_back(session);
+ session->SignalState.connect(this, &Call::OnSessionState);
+ session->SignalError.connect(this, &Call::OnSessionError);
+
+ VoiceChannel *channel = session_client_->channel_manager()->CreateVoiceChannel(session);
+ channel_map_[session->id()] = channel;
+
+ // If this call has the focus, enable this channel
+ if (session_client_->GetFocus() == this)
+ channel->Enable(true);
+
+ // Signal client
+ SignalAddSession(this, session);
+}
+
+void Call::RemoveSession(Session *session) {
+ // Remove session from list
+ std::vector<Session *>::iterator it_session;
+ it_session = std::find(sessions_.begin(), sessions_.end(), session);
+ if (it_session == sessions_.end())
+ return;
+ sessions_.erase(it_session);
+
+ // Destroy session channel
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = it_channel->second;
+ channel_map_.erase(it_channel);
+ session_client_->channel_manager()->DestroyVoiceChannel(channel);
+ }
+
+ // Signal client
+ SignalRemoveSession(this, session);
+
+ // The call auto destroys when the lass session is removed
+ Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
+}
+
+VoiceChannel* Call::GetChannel(Session* session) {
+ std::map<SessionID, VoiceChannel *>::iterator it = channel_map_.find(session->id());
+ assert(it != channel_map_.end());
+ return it->second;
+}
+
+void Call::EnableChannels(bool enable) {
+ std::vector<Session *>::iterator it;
+ for (it = sessions_.begin(); it != sessions_.end(); it++) {
+ VoiceChannel *channel = channel_map_[(*it)->id()];
+ if (channel != NULL)
+ channel->Enable(enable);
+ }
+}
+
+void Call::Mute(bool mute) {
+ muted_ = mute;
+ std::vector<Session *>::iterator it;
+ for (it = sessions_.begin(); it != sessions_.end(); it++) {
+ VoiceChannel *channel = channel_map_[(*it)->id()];
+ if (channel != NULL)
+ channel->Mute(mute);
+ }
+}
+
+void Call::Join(Call *call, bool enable) {
+ while (call->sessions_.size() != 0) {
+ // Move session
+ Session *session = call->sessions_[0];
+ call->sessions_.erase(call->sessions_.begin());
+ sessions_.push_back(session);
+ session->SignalState.connect(this, &Call::OnSessionState);
+ session->SignalError.connect(this, &Call::OnSessionError);
+
+ // Move channel
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = call->channel_map_.find(session->id());
+ if (it_channel != call->channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ call->channel_map_.erase(it_channel);
+ channel_map_[session->id()] = channel;
+ channel->Enable(enable);
+ }
+ }
+}
+
+void Call::StartConnectionMonitor(Session *session, int cms) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->SignalConnectionMonitor.connect(this, &Call::OnConnectionMonitor);
+ channel->StartConnectionMonitor(cms);
+ }
+}
+
+void Call::StopConnectionMonitor(Session *session) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->StopConnectionMonitor();
+ channel->SignalConnectionMonitor.disconnect(this);
+ }
+}
+
+void Call::StartAudioMonitor(Session *session, int cms) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
+ channel->StartAudioMonitor(cms);
+ }
+}
+
+void Call::StopAudioMonitor(Session *session) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->StopAudioMonitor();
+ channel->SignalAudioMonitor.disconnect(this);
+ }
+}
+
+
+void Call::OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos) {
+ SignalConnectionMonitor(this, channel->session(), infos);
+}
+
+void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
+ SignalAudioMonitor(this, channel->session(), info);
+}
+
+uint32 Call::id() {
+ return id_;
+}
+
+void Call::OnSessionState(Session *session, Session::State state) {
+ SignalSessionState(this, session, state);
+}
+
+void Call::OnSessionError(Session *session, Session::Error error) {
+ SignalSessionError(this, session, error);
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h
new file mode 100644
index 00000000..209e13c9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h
@@ -0,0 +1,97 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CALL_H_
+#define _CALL_H_
+
+#include "talk/base/messagequeue.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/client/socketmonitor.h"
+#include "talk/xmpp/jid.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/audiomonitor.h"
+
+#include <map>
+#include <vector>
+
+namespace cricket {
+
+class PhoneSessionClient;
+
+class Call : public MessageHandler, public sigslot::has_slots<> {
+public:
+ Call(PhoneSessionClient *session_client);
+ ~Call();
+
+ Session *InitiateSession(const buzz::Jid &jid);
+ void AcceptSession(Session *session);
+ void RedirectSession(Session *session, const buzz::Jid &to);
+ void RejectSession(Session *session);
+ void TerminateSession(Session *session);
+ void Terminate();
+ void StartConnectionMonitor(Session *session, int cms);
+ void StopConnectionMonitor(Session *session);
+ void StartAudioMonitor(Session *session, int cms);
+ void StopAudioMonitor(Session *session);
+ void Mute(bool mute);
+
+ const std::vector<Session *> &sessions();
+ uint32 id();
+ bool muted() const { return muted_; }
+
+ sigslot::signal2<Call *, Session *> SignalAddSession;
+ sigslot::signal2<Call *, Session *> SignalRemoveSession;
+ sigslot::signal3<Call *, Session *, Session::State> SignalSessionState;
+ sigslot::signal3<Call *, Session *, Session::Error> SignalSessionError;
+ sigslot::signal3<Call *, Session *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
+ sigslot::signal3<Call *, Session *, const AudioInfo&> SignalAudioMonitor;
+
+private:
+ void OnMessage(Message *message);
+ void OnSessionState(Session *session, Session::State state);
+ void OnSessionError(Session *session, Session::Error error);
+ void AddSession(Session *session);
+ void RemoveSession(Session *session);
+ void EnableChannels(bool enable);
+ void Join(Call *call, bool enable);
+ void OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos);
+ void OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info);
+ VoiceChannel* GetChannel(Session* session);
+
+ uint32 id_;
+ PhoneSessionClient *session_client_;
+ std::vector<Session *> sessions_;
+ std::map<SessionID, VoiceChannel *> channel_map_;
+ bool muted_;
+
+ friend class PhoneSessionClient;
+};
+
+}
+
+#endif // _CALL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc
new file mode 100644
index 00000000..98634b12
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc
@@ -0,0 +1,203 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_GIPS
+#include "talk/session/phone/gipsmediaengine.h"
+#else
+#include "talk/session/phone/linphonemediaengine.h"
+#endif
+#include "channelmanager.h"
+#include <cassert>
+#include <iostream>
+namespace cricket {
+
+const uint32 MSG_CREATEVOICECHANNEL = 1;
+const uint32 MSG_DESTROYVOICECHANNEL = 2;
+const uint32 MSG_SETAUDIOOPTIONS = 3;
+
+ChannelManager::ChannelManager(Thread *worker_thread) {
+#ifdef HAVE_GIPS
+ media_engine_ = new GipsMediaEngine();
+#else
+ media_engine_ = new LinphoneMediaEngine();
+#endif
+ worker_thread_ = worker_thread;
+ initialized_ = false;
+ Init();
+}
+
+ChannelManager::~ChannelManager() {
+ Exit();
+}
+
+MediaEngine *ChannelManager::media_engine() {
+ return media_engine_;
+}
+
+bool ChannelManager::Init() {
+ initialized_ = media_engine_->Init();
+ return initialized_;
+}
+
+void ChannelManager::Exit() {
+ if (!initialized_)
+ return;
+
+ // Need to destroy the voice channels
+
+ while (true) {
+ crit_.Enter();
+ VoiceChannel *channel = NULL;
+ if (channels_.begin() != channels_.end())
+ channel = channels_[0];
+ crit_.Leave();
+ if (channel == NULL)
+ break;
+ delete channel;
+ }
+ media_engine_->Terminate();
+}
+
+struct CreateParams {
+ Session *session;
+ VoiceChannel *channel;
+};
+
+VoiceChannel *ChannelManager::CreateVoiceChannel(Session *session) {
+ CreateParams params;
+ params.session = session;
+ params.channel = NULL;
+ TypedMessageData<CreateParams *> data(&params);
+ worker_thread_->Send(this, MSG_CREATEVOICECHANNEL, &data);
+ return params.channel;
+}
+
+VoiceChannel *ChannelManager::CreateVoiceChannel_w(Session *session) {
+ CritScope cs(&crit_);
+
+ // This is ok to alloc from a thread other than the worker thread
+ assert(initialized_);
+ MediaChannel *channel = media_engine_->CreateChannel();
+ if (channel == NULL)
+ return NULL;
+
+ VoiceChannel *voice_channel = new VoiceChannel(this, session, channel);
+ channels_.push_back(voice_channel);
+ return voice_channel;
+}
+
+void ChannelManager::DestroyVoiceChannel(VoiceChannel *voice_channel) {
+ TypedMessageData<VoiceChannel *> data(voice_channel);
+ worker_thread_->Send(this, MSG_DESTROYVOICECHANNEL, &data);
+}
+
+void ChannelManager::DestroyVoiceChannel_w(VoiceChannel *voice_channel) {
+ CritScope cs(&crit_);
+ // Destroy voice channel.
+ assert(initialized_);
+ std::vector<VoiceChannel *>::iterator it = std::find(channels_.begin(),
+ channels_.end(), voice_channel);
+ assert(it != channels_.end());
+ if (it == channels_.end())
+ return;
+
+ channels_.erase(it);
+ MediaChannel *channel = voice_channel->channel();
+ delete voice_channel;
+ delete channel;
+}
+
+void ChannelManager::SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device) {
+ AudioOptions options;
+ options.auto_gain_control = auto_gain_control;
+ options.wave_in_device = wave_in_device;
+ options.wave_out_device = wave_out_device;
+ TypedMessageData<AudioOptions> data(options);
+ worker_thread_->Send(this, MSG_SETAUDIOOPTIONS, &data);
+}
+
+void ChannelManager::SetAudioOptions_w(AudioOptions options) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Set auto gain control on
+ if (media_engine_->SetAudioOptions(options.auto_gain_control?MediaEngine::AUTO_GAIN_CONTROL:0) != 0) {
+ // TODO: We need to log these failures.
+ }
+
+ // Set the audio devices
+ // This will fail if audio is already playing. Stop all of the media
+ // start it up again after changing the setting.
+ {
+ CritScope cs(&crit_);
+ for (VoiceChannels::iterator it = channels_.begin();
+ it < channels_.end();
+ ++it) {
+ (*it)->PauseMedia_w();
+ }
+
+ if (media_engine_->SetSoundDevices(options.wave_in_device, options.wave_out_device) == -1) {
+ // TODO: We need to log these failures.
+ }
+
+ for (VoiceChannels::iterator it = channels_.begin();
+ it < channels_.end();
+ ++it) {
+ (*it)->UnpauseMedia_w();
+ }
+ }
+}
+
+Thread *ChannelManager::worker_thread() {
+ return worker_thread_;
+}
+
+void ChannelManager::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CREATEVOICECHANNEL:
+ {
+ TypedMessageData<CreateParams *> *data = static_cast<TypedMessageData<CreateParams *> *>(message->pdata);
+ data->data()->channel = CreateVoiceChannel_w(data->data()->session);
+ }
+ break;
+
+ case MSG_DESTROYVOICECHANNEL:
+ {
+ TypedMessageData<VoiceChannel *> *data = static_cast<TypedMessageData<VoiceChannel *> *>(message->pdata);
+ DestroyVoiceChannel_w(data->data());
+ }
+ break;
+ case MSG_SETAUDIOOPTIONS:
+ {
+ TypedMessageData<AudioOptions> *data = static_cast<TypedMessageData<AudioOptions> *>(message->pdata);
+ SetAudioOptions_w(data->data());
+ }
+ break;
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h
new file mode 100644
index 00000000..7200f75e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h
@@ -0,0 +1,81 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CHANNELMANAGER_H_
+#define _CHANNELMANAGER_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/criticalsection.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/mediaengine.h"
+#include <vector>
+
+namespace cricket {
+
+class VoiceChannel;
+
+class ChannelManager : public MessageHandler {
+public:
+ ChannelManager(Thread *worker_thread);
+ ~ChannelManager();
+
+ VoiceChannel *CreateVoiceChannel(Session *session);
+ void DestroyVoiceChannel(VoiceChannel *voice_channel);
+ void SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device);
+
+ MediaEngine *media_engine();
+ Thread *worker_thread();
+
+private:
+ VoiceChannel *CreateVoiceChannel_w(Session *session);
+ void DestroyVoiceChannel_w(VoiceChannel *voice_channel);
+ void OnMessage(Message *message);
+ bool Init();
+ void Exit();
+
+ struct AudioOptions {
+ bool auto_gain_control;
+ int wave_in_device;
+ int wave_out_device;
+ };
+ void SetAudioOptions_w(AudioOptions options);
+
+ Thread *worker_thread_;
+ MediaEngine *media_engine_;
+ bool initialized_;
+ CriticalSection crit_;
+
+ typedef std::vector<VoiceChannel*> VoiceChannels;
+ VoiceChannels channels_;
+};
+
+}
+
+#endif // _CHANNELMANAGER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
new file mode 100644
index 00000000..7d2305dc
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
@@ -0,0 +1,170 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// LinphoneMediaEngine is a Linphone implementation of MediaEngine
+extern "C" {
+#include "talk/third_party/mediastreamer/mediastream.h"
+#ifdef HAVE_ILBC
+#include "talk/third_party/mediastreamer/msilbcdec.h"
+#endif
+#ifdef HAVE_SPEEX
+#include "talk/third_party/mediastreamer/msspeexdec.h"
+#endif
+}
+#include <ortp/ortp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <iostream>
+#include "talk/session/phone/linphonemediaengine.h"
+
+using namespace cricket;
+
+void *thread_function(void *data)
+{
+ LinphoneMediaChannel *mc =(LinphoneMediaChannel*) data;
+ while (mc->dying() == false) {
+ MediaChannel::NetworkInterface *iface = mc->network_interface();
+ char *buf[2048];
+ int len;
+ len = read(mc->fd(), buf, sizeof(buf));
+ if (iface && (mc->mute()==FALSE))
+ iface->SendPacket(buf, len);
+ }
+}
+
+LinphoneMediaChannel::LinphoneMediaChannel() {
+ pt_ = 102;
+ dying_ = false;
+ pthread_attr_t attr;
+ audio_stream_ = NULL;
+
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+ sockaddr.sin_port = htons(3000);
+ fd_ = socket(PF_INET, SOCK_DGRAM, 0);
+ fcntl(fd_, F_SETFL, 0, O_NONBLOCK);
+ bind (fd_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
+
+ pthread_attr_init(&attr);
+ pthread_create(&thread_, &attr, &thread_function, this);
+}
+
+LinphoneMediaChannel::~LinphoneMediaChannel() {
+ dying_ = true;
+ pthread_join(thread_, NULL);
+ audio_stream_stop(audio_stream_);
+ close(fd_);
+}
+
+void LinphoneMediaChannel::SetCodec(const char *codec) {
+ if (!strcmp(codec, "iLBC"))
+ pt_ = 102;
+ else if (!strcmp(codec, "speex"))
+ pt_ = 110;
+ else
+ pt_ = 0;
+ if (audio_stream_)
+ audio_stream_stop(audio_stream_);
+ audio_stream_ = audio_stream_start(&av_profile, 2000, "127.0.0.1", 3000, pt_, 250);
+}
+
+void LinphoneMediaChannel::OnPacketReceived(const void *data, int len) {
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ struct hostent *host = gethostbyname("localhost");
+ memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
+ sockaddr.sin_port = htons(2000);
+
+ char buf[2048];
+ memcpy(buf, data, len);
+
+ if (buf[1] == pt_) {
+ } else if (buf[1] == 13) {
+ } else if (buf[1] == 102) {
+ SetCodec("iLBC");
+ } else if (buf[1] == 110) {
+ SetCodec("speex");
+ } else if (buf[1] == 0) {
+ SetCodec("PCMU");
+ }
+
+ if (play_ && buf[1] != 13)
+ sendto(fd_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+}
+
+void LinphoneMediaChannel::SetPlayout(bool playout) {
+ play_ = playout;
+}
+
+void LinphoneMediaChannel::SetSend(bool send) {
+ mute_ = !send;
+}
+
+float LinphoneMediaChannel::GetCurrentQuality() {}
+int LinphoneMediaChannel::GetOutputLevel() {}
+
+LinphoneMediaEngine::LinphoneMediaEngine() {}
+LinphoneMediaEngine::~LinphoneMediaEngine() {}
+
+static void null_log_handler(const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data) {
+}
+
+bool LinphoneMediaEngine::Init() {
+ g_log_set_handler("MediaStreamer", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ g_log_set_handler("oRTP", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ g_log_set_handler("oRTP-stats", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ ortp_init();
+ ms_init();
+
+#ifdef HAVE_SPEEX
+ ms_speex_codec_init();
+ rtp_profile_set_payload(&av_profile, 110, &speex_wb);
+ codecs_.push_back(Codec(110, "speex", 8));
+#endif
+
+#ifdef HAVE_ILBC
+ ms_ilbc_codec_init();
+ rtp_profile_set_payload(&av_profile, 102, &payload_type_ilbc);
+ codecs_.push_back(Codec(102, "iLBC", 4));
+#endif
+
+ rtp_profile_set_payload(&av_profile, 0, &pcmu8000);
+ codecs_.push_back(Codec(0, "PCMU", 2));
+
+return true;
+}
+
+void LinphoneMediaEngine::Terminate() {
+
+}
+
+MediaChannel *LinphoneMediaEngine::CreateChannel() {
+ return new LinphoneMediaChannel();
+}
+
+int LinphoneMediaEngine::SetAudioOptions(int options) {}
+int LinphoneMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device) {}
+
+float LinphoneMediaEngine::GetCurrentQuality() {}
+int LinphoneMediaEngine::GetInputLevel() {}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h
new file mode 100644
index 00000000..ee16d2ee
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h
@@ -0,0 +1,75 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// LinphoneMediaEngine is a Linphone implementation of MediaEngine
+
+#ifndef TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
+#define TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
+
+extern "C" {
+#include "talk/third_party/mediastreamer/mediastream.h"
+}
+#include "talk/session/phone/mediaengine.h"
+
+namespace cricket {
+
+class LinphoneMediaChannel : public MediaChannel {
+ public:
+ LinphoneMediaChannel();
+ virtual ~LinphoneMediaChannel();
+ virtual void SetCodec(const char *codec);
+ virtual void OnPacketReceived(const void *data, int len);
+
+ virtual void SetPlayout(bool playout);
+ virtual void SetSend(bool send);
+
+ virtual float GetCurrentQuality();
+ virtual int GetOutputLevel();
+ int fd() {return fd_;}
+ bool mute() {return mute_;}
+ bool dying() {return dying_;}
+ private:
+ AudioStream *audio_stream_;
+ pthread_t thread_;
+ int fd_;
+ int pt_;
+ bool dying_;
+ bool mute_;
+ bool play_;
+};
+
+class LinphoneMediaEngine : public MediaEngine {
+ public:
+ LinphoneMediaEngine();
+ ~LinphoneMediaEngine();
+ virtual bool Init();
+ virtual void Terminate();
+
+ virtual MediaChannel *CreateChannel();
+
+ virtual int SetAudioOptions(int options);
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
+
+ virtual float GetCurrentQuality();
+ virtual int GetInputLevel();
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h
new file mode 100644
index 00000000..db2f9654
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h
@@ -0,0 +1,55 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_
+#define TALK_SESSION_PHONE_MEDIACHANNEL_H_
+
+namespace cricket {
+
+class MediaChannel {
+ public:
+ class NetworkInterface {
+ public:
+ virtual void SendPacket(const void *data, size_t len) = 0;
+ };
+ MediaChannel() {network_interface_ = NULL;}
+ virtual ~MediaChannel() {};
+ void SetInterface(NetworkInterface *iface) {network_interface_ = iface;}
+ virtual void SetCodec(const char *codec) = 0;
+ virtual void OnPacketReceived(const void *data, int len) = 0;
+ virtual void SetPlayout(bool playout) = 0;
+ virtual void SetSend(bool send) = 0;
+ virtual float GetCurrentQuality() = 0;
+ virtual int GetOutputLevel() = 0;
+ NetworkInterface *network_interface() {return network_interface_;}
+ protected:
+ NetworkInterface *network_interface_;
+};
+
+}; // namespace cricket
+
+#endif // TALK_SESSION_PHONE_MEDIACHANNEL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h
new file mode 100644
index 00000000..fa07d2ec
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h
@@ -0,0 +1,95 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// MediaEngine is an abstraction of a media engine which can be subclassed
+// to support different media componentry backends.
+
+#ifndef TALK_SESSION_PHONE_MEDIAENGINE_H_
+#define TALK_SESSION_PHONE_MEDIAENGINE_H_
+
+#include <string>
+#include <vector>
+#include "mediachannel.h"
+
+namespace cricket {
+
+class MediaEngine {
+ public:
+
+ struct Codec {
+ int id;
+ std::string name;
+ int preference;
+ // Creates a codec with the given parameters.
+ Codec(int pt, const std::string& nm, int pr) : id(pt), name(nm), preference(pr) {}
+ // Ranks codecs by their preferences.
+ bool operator <(const Codec& c) const { return preference > c.preference; }
+ };
+
+ // Bitmask flags for options that may be supported by the media engine implementation
+ enum MediaEngineOptions {
+ AUTO_GAIN_CONTROL = 1 << 1,
+ };
+
+ MediaEngine() {}
+
+ // Initialize
+ virtual bool Init() = 0;
+ virtual void Terminate() = 0;
+ virtual MediaChannel *CreateChannel() = 0;
+
+ virtual int SetAudioOptions(int options) = 0;
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device) = 0;
+ virtual int GetInputLevel() = 0;
+
+ std::vector<Codec> &codecs() { return codecs_; }
+
+ bool FindCodec(const char* codec) {
+ for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
+ if ((*i).name == codec)
+ return true;
+ }
+ return false;
+ }
+
+ bool GetCodecPreference (const char *codec, int & preference) {
+ for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
+ if ((*i).name == codec) {
+ preference = (*i).preference;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ std::vector<Codec> codecs_;
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_MEDIAENGINE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
new file mode 100644
index 00000000..d8a31df2
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
@@ -0,0 +1,267 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/logging.h"
+#include "talk/session/receiver.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/xmllite/qname.h"
+namespace {
+
+const std::string NS_PHONE("http://www.google.com/session/phone");
+const std::string NS_EMPTY("");
+
+const buzz::QName QN_PHONE_DESCRIPTION(true, NS_PHONE, "description");
+const buzz::QName QN_PHONE_PAYLOADTYPE(true, NS_PHONE, "payload-type");
+const buzz::QName QN_PHONE_PAYLOADTYPE_ID(true, NS_EMPTY, "id");
+const buzz::QName QN_PHONE_PAYLOADTYPE_NAME(true, NS_EMPTY, "name");
+
+}
+
+namespace cricket {
+
+PhoneSessionClient::PhoneSessionClient(const buzz::Jid& jid,
+ SessionManager *manager) : jid_(jid), SessionClient(manager) {
+
+ // No call to start, and certainly no call with focus
+ focus_call_ = NULL;
+
+ // Start up the channel manager on a worker thread
+ channel_manager_ = new ChannelManager(session_manager_->worker_thread());
+}
+
+PhoneSessionClient::~PhoneSessionClient() {
+ // Destroy all calls
+ std::map<uint32, Call *>::iterator it;
+ while (calls_.begin() != calls_.end()) {
+ std::map<uint32, Call *>::iterator it = calls_.begin();
+ DestroyCall((*it).second);
+ }
+
+ // Delete channel manager. This will wait for the channels to exit
+ delete channel_manager_;
+}
+
+const std::string &PhoneSessionClient::GetSessionDescriptionName() {
+ return NS_PHONE;
+}
+
+PhoneSessionDescription* PhoneSessionClient::CreateOfferSessionDescription() {
+ PhoneSessionDescription* session_desc = new PhoneSessionDescription();
+
+ MediaEngine *me = channel_manager_->media_engine();
+ std::vector<MediaEngine::Codec> codecs = me->codecs();
+ std::vector<MediaEngine::Codec>::iterator i;
+ for (i = codecs.begin(); i < codecs.end(); i++)
+ session_desc->AddCodec(*i);
+
+ session_desc->Sort();
+ return session_desc;
+}
+
+PhoneSessionDescription* PhoneSessionClient::CreateAcceptSessionDescription(const SessionDescription* offer) {
+ const PhoneSessionDescription* offer_desc =
+ static_cast<const PhoneSessionDescription*>(offer);
+ PhoneSessionDescription* accept_desc = new PhoneSessionDescription();
+ std::vector<MediaEngine::Codec> codecs = channel_manager_->media_engine()->codecs();
+ std::vector<MediaEngine::Codec>::iterator iter;
+ for (unsigned int i = 0; i < offer_desc->codecs().size(); ++i) {
+ for (iter = codecs.begin(); iter < codecs.end(); iter++) {
+ if ((*iter).name == offer_desc->codecs()[i].name)
+ accept_desc->AddCodec(*iter);
+ }
+ }
+
+ accept_desc->Sort();
+ return accept_desc;
+}
+
+bool PhoneSessionClient::FindMediaCodec(MediaEngine* me,
+ const PhoneSessionDescription* desc,
+ const char** codec) {
+ for (size_t i = 0; i < desc->codecs().size(); ++i) {
+ if (me->FindCodec(desc->codecs()[i].name.c_str()))
+ *codec = desc->codecs()[i].name.c_str();
+ return true;
+ }
+
+ return false;
+}
+
+const SessionDescription *PhoneSessionClient::CreateSessionDescription(const buzz::XmlElement *element) {
+ PhoneSessionDescription* desc = new PhoneSessionDescription();
+
+ const buzz::XmlElement* payload_type = element->FirstNamed(QN_PHONE_PAYLOADTYPE);
+ int num_payload_types = 0;
+
+ while (payload_type) {
+ if (payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_ID) &&
+ payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_NAME)) {
+ int id = atoi(payload_type->Attr(QN_PHONE_PAYLOADTYPE_ID).c_str());
+ int pref = 0;
+ std::string name = payload_type->Attr(QN_PHONE_PAYLOADTYPE_NAME);
+ desc->AddCodec(MediaEngine::Codec(id, name, 0));
+ }
+
+ payload_type = payload_type->NextNamed(QN_PHONE_PAYLOADTYPE);
+ num_payload_types += 1;
+ }
+
+ // For backward compatability, we can assume the other client is (an old
+ // version of Talk) if it has no payload types at all.
+ if (num_payload_types == 0) {
+ desc->AddCodec(MediaEngine::Codec(103, "ISAC", 1));
+ desc->AddCodec(MediaEngine::Codec(0, "PCMU", 0));
+ }
+
+ return desc;
+}
+
+buzz::XmlElement *PhoneSessionClient::TranslateSessionDescription(const SessionDescription *_session_desc) {
+ const PhoneSessionDescription* session_desc =
+ static_cast<const PhoneSessionDescription*>(_session_desc);
+ buzz::XmlElement* description = new buzz::XmlElement(QN_PHONE_DESCRIPTION, true);
+
+ for (size_t i = 0; i < session_desc->codecs().size(); ++i) {
+ buzz::XmlElement* payload_type = new buzz::XmlElement(QN_PHONE_PAYLOADTYPE, true);
+
+ char buf[32];
+ sprintf(buf, "%d", session_desc->codecs()[i].id);
+ payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_ID, buf);
+
+ payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_NAME,
+ session_desc->codecs()[i].name.c_str());
+
+ description->AddElement(payload_type);
+ }
+
+ return description;
+}
+
+Call *PhoneSessionClient::CreateCall() {
+ Call *call = new Call(this);
+ calls_[call->id()] = call;
+ SignalCallCreate(call);
+ return call;
+}
+
+void PhoneSessionClient::OnSessionCreate(Session *session, bool received_initiate) {
+ if (received_initiate) {
+ session->SignalState.connect(this, &PhoneSessionClient::OnSessionState);
+
+ Call *call = CreateCall();
+ session_map_[session->id()] = call;
+ call->AddSession(session);
+ }
+}
+
+void PhoneSessionClient::OnSessionState(Session *session, Session::State state) {
+ if (state == Session::STATE_RECEIVEDINITIATE) {
+ // If our accept would have no codecs, then we must reject this call.
+ PhoneSessionDescription* accept_desc =
+ CreateAcceptSessionDescription(session->remote_description());
+ if (accept_desc->codecs().size() == 0) {
+ // TODO: include an error description with the rejection.
+ session->Reject();
+ }
+ delete accept_desc;
+ }
+}
+
+void PhoneSessionClient::DestroyCall(Call *call) {
+ // Change focus away, signal destruction
+
+ if (call == focus_call_)
+ SetFocus(NULL);
+ SignalCallDestroy(call);
+
+ // Remove it from calls_ map and delete
+
+ std::map<uint32, Call *>::iterator it = calls_.find(call->id());
+ if (it != calls_.end())
+ calls_.erase(it);
+
+ delete call;
+}
+
+void PhoneSessionClient::OnSessionDestroy(Session *session) {
+ // Find the call this session is in, remove it
+
+ std::map<SessionID, Call *>::iterator it = session_map_.find(session->id());
+ assert(it != session_map_.end());
+ if (it != session_map_.end()) {
+ Call *call = (*it).second;
+ session_map_.erase(it);
+ call->RemoveSession(session);
+ }
+}
+
+Call *PhoneSessionClient::GetFocus() {
+ return focus_call_;
+}
+
+void PhoneSessionClient::SetFocus(Call *call) {
+ Call *old_focus_call = focus_call_;
+ if (focus_call_ != call) {
+ if (focus_call_ != NULL)
+ focus_call_->EnableChannels(false);
+ focus_call_ = call;
+ if (focus_call_ != NULL)
+ focus_call_->EnableChannels(true);
+ SignalFocus(focus_call_, old_focus_call);
+ }
+}
+
+void PhoneSessionClient::JoinCalls(Call *call_to_join, Call *call) {
+ // Move all sessions from call to call_to_join, delete call.
+ // If call_to_join has focus, added sessions should have enabled channels.
+
+ if (focus_call_ == call)
+ SetFocus(NULL);
+ call_to_join->Join(call, focus_call_ == call_to_join);
+ DestroyCall(call);
+}
+
+Session *PhoneSessionClient::CreateSession(Call *call) {
+ Session *session = session_manager_->CreateSession(
+ GetSessionDescriptionName(), jid().Str());
+ session_map_[session->id()] = call;
+ return session;
+}
+
+ChannelManager *PhoneSessionClient::channel_manager() {
+ return channel_manager_;
+}
+
+const buzz::Jid &PhoneSessionClient::jid() const {
+ return jid_;
+}
+
+const buzz::Jid &PhoneSessionClient::GetJid() const {
+ return jid_;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h
new file mode 100644
index 00000000..150bf34b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h
@@ -0,0 +1,122 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PHONESESSIONCLIENT_H_
+#define _PHONESESSIONCLIENT_H_
+
+#include "talk/session/phone/call.h"
+#include "talk/session/phone/channelmanager.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/messagequeue.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessiondescription.h"
+#include "talk/xmpp/xmppclient.h"
+#include <map>
+
+namespace cricket {
+
+class Call;
+class PhoneSessionDescription;
+
+class PhoneSessionClient : public SessionClient {
+public:
+ PhoneSessionClient(const buzz::Jid& jid, SessionManager *manager);
+ ~PhoneSessionClient();
+
+ const buzz::Jid &jid() const;
+
+ Call *CreateCall();
+ void DestroyCall(Call *call);
+
+ Call *GetFocus();
+ void SetFocus(Call *call);
+
+ void JoinCalls(Call *call_to_join, Call *call);
+
+ void SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device) {
+ if (channel_manager_)
+ channel_manager_->SetAudioOptions(auto_gain_control, wave_in_device,
+ wave_out_device);
+ }
+
+ sigslot::signal2<Call *, Call *> SignalFocus;
+ sigslot::signal1<Call *> SignalCallCreate;
+ sigslot::signal1<Call *> SignalCallDestroy;
+
+ PhoneSessionDescription* CreateOfferSessionDescription();
+ PhoneSessionDescription* CreateAcceptSessionDescription(const SessionDescription* offer);
+
+ // Returns our preference for the given codec.
+ static int GetMediaCodecPreference(const char* name);
+
+ // Returns the name of the first codec in the description that
+ // is found. Return value is false if none was found.
+ static bool FindMediaCodec(MediaEngine* gips,
+ const PhoneSessionDescription* desc,
+ const char **codec);
+
+private:
+ void OnSessionCreate(Session *session, bool received_initiate);
+ void OnSessionState(Session *session, Session::State state);
+ void OnSessionDestroy(Session *session);
+ const SessionDescription *CreateSessionDescription(const buzz::XmlElement *element);
+ buzz::XmlElement *TranslateSessionDescription(const SessionDescription *description);
+ const std::string &GetSessionDescriptionName();
+ const buzz::Jid &GetJid() const;
+ Session *CreateSession(Call *call);
+ ChannelManager *channel_manager();
+
+ buzz::Jid jid_;
+ Call *focus_call_;
+ ChannelManager *channel_manager_;
+ std::map<uint32, Call *> calls_;
+ std::map<SessionID, Call *> session_map_;
+
+ friend class Call;
+};
+
+class PhoneSessionDescription: public SessionDescription {
+public:
+ // Returns the list of codecs sorted by our preference.
+ const std::vector<MediaEngine::Codec>& codecs() const { return codecs_; }
+
+ // Adds another codec to the list.
+ void AddCodec(const MediaEngine::Codec& codec) { codecs_.push_back(codec); }
+ // Sorts the list of codecs by preference.
+ void Sort() { /* std::stable_sort(codecs_.begin(), codecs_.end());*/ }
+
+private:
+ std::vector<MediaEngine::Codec> codecs_;
+};
+
+}
+
+#endif // _PHONESESSIONCLIENT_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc
new file mode 100644
index 00000000..b65c9a20
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc
@@ -0,0 +1,331 @@
+#include <portaudio.h>
+#include <ortp/ortp.h>
+#include <speex.h>
+
+// Socket stuff
+#ifndef _WIN32
+#ifdef INET6
+#include <netdb.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#else
+#include <winsock32.h>
+#endif
+
+#include "talk/session/phone/mediaengine.h"
+#include "talk/session/phone/portaudiomediaengine.h"
+
+// Engine settings
+#define ENGINE_BUFFER_SIZE 2048
+
+// PortAudio settings
+#define FRAMES_PER_BUFFER 256
+#define SAMPLE_RATE 1
+
+// Speex settings
+//#define SPEEX_QUALITY 8
+
+// ORTP settings
+#define MAX_RTP_SIZE 1500 // From mediastreamer
+
+
+// -----------------------------------------------------------------------------
+
+static int portAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *channel_p )
+{
+ PortAudioMediaChannel* channel = (PortAudioMediaChannel*) channel_p;
+ channel->readOutput((float*) outputBuffer, framesPerBuffer);
+ channel->writeInput((float*) inputBuffer, framesPerBuffer);
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+PortAudioMediaChannel::PortAudioMediaChannel() : mute_(false), play_(false), stream_(NULL), out_buffer_(NULL), in_buffer_(NULL), speex_frame_(NULL)
+{
+ // Initialize buffers
+ out_buffer_ = new float[ENGINE_BUFFER_SIZE];
+ out_buffer_read_ = out_buffer_write_ = (float*) out_buffer_;
+ out_buffer_end_ = (float*) out_buffer_ + ENGINE_BUFFER_SIZE;
+ in_buffer_ = new float[ENGINE_BUFFER_SIZE];
+ in_buffer_read_ = in_buffer_write_ = (float*) in_buffer_;
+ in_buffer_end_ = (float*) in_buffer_ + ENGINE_BUFFER_SIZE;
+
+ // Initialize PortAudio
+ int err = Pa_OpenDefaultStream(&stream_, 1, 1, paFloat32, SAMPLE_RATE, FRAMES_PER_BUFFER, 0, portAudioCallback, this );
+ if (err != paNoError)
+ fprintf(stderr, "Error creating a PortAudio stream: %s\n", Pa_GetErrorText(err));
+
+ // Initialize Speex
+ speex_bits_init(&speex_bits_);
+ speex_enc_state_ = speex_encoder_init(&speex_nb_mode);
+ speex_dec_state_ = speex_decoder_init(&speex_nb_mode);
+ speex_decoder_ctl(speex_dec_state_, SPEEX_GET_FRAME_SIZE, &speex_frame_size_);
+ speex_frame_ = new float[speex_frame_size_];
+
+ // int quality = SPEEX_QUALITY;
+ // speex_encoder_ctl(state, SPEEX_SET_QUALITY, &quality);
+
+ // Initialize ORTP socket
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+ sockaddr.sin_port = htons(3000);
+ rtp_socket_ = socket(PF_INET, SOCK_DGRAM, 0);
+ fcntl(rtp_socket_, F_SETFL, 0, O_NONBLOCK);
+ bind (rtp_socket_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
+
+ // Initialize ORTP Session
+ rtp_session_ = rtp_session_new(RTP_SESSION_SENDRECV);
+ rtp_session_max_buf_size_set(rtp_session_, MAX_RTP_SIZE);
+ rtp_session_set_profile(rtp_session_, &av_profile);
+ rtp_session_set_local_addr(rtp_session_, "127.0.0.1", 2000);
+ rtp_session_set_remote_addr(rtp_session_, "127.0.0.1", 3000);
+ rtp_session_set_scheduling_mode(rtp_session_, 0);
+ rtp_session_set_blocking_mode(rtp_session_, 0);
+ rtp_session_set_payload_type(rtp_session_, 110);
+ rtp_session_set_jitter_compensation(rtp_session_, 250);
+ rtp_session_enable_adaptive_jitter_compensation(rtp_session_, TRUE);
+ rtp_timestamp_ = 0;
+ //rtp_session_signal_connect(rtp_session_, "telephone-event", (RtpCallback) ortpTelephoneCallback,this);
+}
+
+PortAudioMediaChannel::~PortAudioMediaChannel()
+{
+ if (stream_) {
+ Pa_CloseStream(stream_);
+ }
+
+ // Clean up other allocated pointers
+
+ close(rtp_socket_);
+}
+
+void PortAudioMediaChannel::SetCodec(const char *codec)
+{
+ if (strcmp(codec, "speex"))
+ printf("Unsupported codec: %s\n", codec);
+}
+
+void PortAudioMediaChannel::OnPacketReceived(const void *data, int len)
+{
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ struct hostent *host = gethostbyname("localhost");
+ memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
+ sockaddr.sin_port = htons(2000);
+
+ char buf[2048];
+ memcpy(buf, data, len);
+
+ // Pass packet on to ORTP
+ if (play_) {
+ sendto(rtp_socket_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ }
+}
+
+void PortAudioMediaChannel::SetPlayout(bool playout)
+{
+ if (!stream_)
+ return;
+
+ if (play_ && !playout) {
+ int err = Pa_StopStream(stream_);
+ if (err != paNoError) {
+ fprintf(stderr, "Error stopping PortAudio stream: %s\n", Pa_GetErrorText(err));
+ return;
+ }
+ play_ = false;
+ }
+ else if (!play_ && playout) {
+ int err = Pa_StartStream(stream_);
+ if (err != paNoError) {
+ fprintf(stderr, "Error starting PortAudio stream: %s\n", Pa_GetErrorText(err));
+ return;
+ }
+ play_ = true;
+ }
+}
+
+void PortAudioMediaChannel::SetSend(bool send)
+{
+ mute_ = !send;
+}
+
+
+float PortAudioMediaChannel::GetCurrentQuality()
+{
+ return 0;
+}
+
+int PortAudioMediaChannel::GetOutputLevel()
+{
+ return 0;
+}
+
+void PortAudioMediaChannel::readOutput(float* buf, int len)
+{
+ //readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
+
+ // Receive a packet (if there is one)
+ mblk_t *mp;
+ mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
+ while (mp != NULL) {
+ gint in_len = mp->b_cont->b_wptr-mp->b_cont->b_rptr;
+
+ // Decode speex stream
+ speex_bits_read_from(&speex_bits_,mp->b_cont->b_rptr, in_len);
+ speex_decode(speex_dec_state_, &speex_bits_, speex_frame_);
+ writeBuffer(out_buffer_, out_buffer_read_, &out_buffer_write_, out_buffer_end_, speex_frame_, speex_frame_size_);
+ rtp_timestamp_++;
+ mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
+ }
+
+ // Read output
+ readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
+}
+
+void PortAudioMediaChannel::writeInput(float* buf, int len)
+{
+ //writeBuffer(in_buffer_, in_buffer_read_, &in_buffer_write_, in_buffer_end_, buf, len);
+}
+
+
+void PortAudioMediaChannel::readBuffer(float* buffer, float** buffer_read_p, float*buffer_write, float* buffer_end, float* target_buffer, int target_len)
+{
+ float *end, *tmp, *buffer_read = *buffer_read_p;
+ int remaining;
+
+ // First phase
+ tmp = buffer_read + target_len;
+ if (buffer_write < buffer_read && tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = (tmp > buffer_write ? buffer_write : tmp);
+ remaining = 0;
+ }
+
+ while (buffer_read < end) {
+ *target_buffer++ = *buffer_read++;
+ }
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_read = buffer;
+ tmp = buffer_read + remaining;
+ end = (tmp > buffer_write ? buffer_write : tmp);
+ while (buffer_read < end) {
+ *target_buffer++ = *buffer_read++;
+ }
+ }
+
+ // Finish up
+ *buffer_read_p = buffer_read;
+}
+
+void PortAudioMediaChannel::writeBuffer(float* buffer, float* buffer_read, float**buffer_write_p, float* buffer_end, float* source_buffer, int source_len)
+{
+ float *end, *tmp, *buffer_write = *buffer_write_p;
+ int remaining;
+
+ // First phase
+ tmp = buffer_write + source_len;
+ if (buffer_write > buffer_read) {
+ if (tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+ else {
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s)\n");
+ end = buffer_read;
+ remaining = 0;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+
+ while (buffer_write < end) {
+ *buffer_write++ = *source_buffer++;
+ }
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_write = buffer;
+ tmp = buffer_write + remaining;
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s)\n");
+ end = buffer_read;
+ }
+ else {
+ end = tmp;
+ }
+ while (buffer_write < end) {
+ *buffer_write++ = *source_buffer++;
+ }
+ }
+
+ // Finish up
+ *buffer_write_p = buffer_write;
+}
+
+// -----------------------------------------------------------------------------
+
+PortAudioMediaEngine::PortAudioMediaEngine()
+{
+}
+
+PortAudioMediaEngine::~PortAudioMediaEngine()
+{
+ Pa_Terminate();
+}
+
+bool PortAudioMediaEngine::Init()
+{
+ ortp_init();
+
+ int err = Pa_Initialize();
+ if (err != paNoError) {
+ fprintf(stderr,"Error initializing PortAudio: %s\n",Pa_GetErrorText(err));
+ return false;
+ }
+
+ // Speex
+ rtp_profile_set_payload(&av_profile, 110, &speex_wb);
+ codecs_.push_back(Codec(110, "speex", 8));
+
+ return true;
+}
+
+void PortAudioMediaEngine::Terminate()
+{
+}
+
+
+cricket::MediaChannel* PortAudioMediaEngine::CreateChannel()
+{
+ return new PortAudioMediaChannel();
+}
+
+int PortAudioMediaEngine::SetAudioOptions(int options)
+{
+}
+
+int PortAudioMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device)
+{
+}
+
+int PortAudioMediaEngine::GetInputLevel()
+{
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h
new file mode 100644
index 00000000..95c39a1a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h
@@ -0,0 +1,69 @@
+#ifndef PORTAUDIOMEDIAENGINE_H
+#define PORTAUDIOMEDIAENGINE_H
+
+#include <portaudio.h>
+#include <speex.h>
+#include <ortp/ortp.h>
+
+#include "talk/session/phone/mediaengine.h"
+
+class PortAudioMediaChannel : public cricket::MediaChannel
+{
+public:
+ PortAudioMediaChannel();
+ virtual ~PortAudioMediaChannel();
+ virtual void SetCodec(const char *codec);
+ virtual void OnPacketReceived(const void *data, int len);
+
+ virtual void SetPlayout(bool playout);
+ virtual void SetSend(bool send);
+
+ virtual float GetCurrentQuality();
+ virtual int GetOutputLevel();
+
+ void readOutput(float*, int);
+ void writeInput(float*, int);
+
+protected:
+ void readBuffer(float*, float**, float*, float*, float*, int);
+ void writeBuffer(float*, float*, float**, float*, float*, int);
+
+private:
+ bool mute_;
+ bool play_;
+ PortAudioStream* stream_;
+
+ // Buffers
+ float *out_buffer_, *out_buffer_read_, *out_buffer_write_, *out_buffer_end_;
+ float *in_buffer_, *in_buffer_read_, *in_buffer_write_, *in_buffer_end_;
+
+ // Speex
+ SpeexBits speex_bits_;
+ void *speex_enc_state_, *speex_dec_state_;
+ float *speex_frame_;
+ int speex_frame_size_;
+
+ // ORTP
+ int rtp_socket_;
+ RtpSession* rtp_session_;
+ int rtp_timestamp_;
+};
+
+
+class PortAudioMediaEngine : public cricket::MediaEngine
+{
+public:
+ PortAudioMediaEngine();
+ ~PortAudioMediaEngine();
+ virtual bool Init();
+ virtual void Terminate();
+
+ virtual cricket::MediaChannel *CreateChannel();
+
+ virtual int SetAudioOptions(int options);
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
+
+ virtual int GetInputLevel();
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc
new file mode 100644
index 00000000..58e1db60
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc
@@ -0,0 +1,331 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/channelmanager.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/base/logging.h"
+#include <cassert>
+#undef SetPort
+
+namespace {
+
+// Delay before quality estimate is meaningful.
+uint32 kQualityDelay = 5000; // in ms
+
+}
+
+namespace cricket {
+
+VoiceChannel::VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel) {
+ channel_manager_ = manager;
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ channel_ = channel;
+ session_ = session;
+ socket_monitor_ = NULL;
+ audio_monitor_ = NULL;
+ socket_ = session_->CreateSocket("rtp");
+ socket_->SignalState.connect(this, &VoiceChannel::OnSocketState);
+ socket_->SignalReadPacket.connect(this, &VoiceChannel::OnSocketRead);
+ channel->SetInterface(this);
+ enabled_ = false;
+ paused_ = false;
+ socket_writable_ = false;
+ muted_ = false;
+ LOG(INFO) << "Created voice channel";
+ start_time_ = 0xFFFFFFFF - kQualityDelay;
+
+ session->SignalState.connect(this, &VoiceChannel::OnSessionState);
+ OnSessionState(session, session->state());
+}
+
+VoiceChannel::~VoiceChannel() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ enabled_ = false;
+ ChangeState();
+ delete socket_monitor_;
+ delete audio_monitor_;
+ Thread::Current()->Clear(this);
+ if (socket_ != NULL)
+ session_->DestroySocket(socket_);
+ LOG(INFO) << "Destroyed voice channel";
+}
+
+void VoiceChannel::OnMessage(Message *pmsg) {
+ switch (pmsg->message_id) {
+ case MSG_ENABLE:
+ EnableMedia_w();
+ break;
+
+ case MSG_DISABLE:
+ DisableMedia_w();
+ break;
+
+ case MSG_MUTE:
+ MuteMedia_w();
+ break;
+
+ case MSG_UNMUTE:
+ UnmuteMedia_w();
+ break;
+
+ case MSG_SETSENDCODEC:
+ SetSendCodec_w();
+ break;
+ }
+}
+
+void VoiceChannel::Enable(bool enable) {
+ // Can be called from thread other than worker thread
+ channel_manager_->worker_thread()->Post(this, enable ? MSG_ENABLE : MSG_DISABLE);
+}
+
+void VoiceChannel::Mute(bool mute) {
+ // Can be called from thread other than worker thread
+ channel_manager_->worker_thread()->Post(this, mute ? MSG_MUTE : MSG_UNMUTE);
+}
+
+MediaChannel * VoiceChannel::channel() {
+ return channel_;
+}
+
+void VoiceChannel::OnSessionState(Session* session, Session::State state) {
+ if ((state == Session::STATE_RECEIVEDACCEPT) ||
+ (state == Session::STATE_RECEIVEDINITIATE)) {
+ channel_manager_->worker_thread()->Post(this, MSG_SETSENDCODEC);
+ }
+}
+
+void VoiceChannel::SetSendCodec_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+
+ const PhoneSessionDescription* desc =
+ static_cast<const PhoneSessionDescription*>(session()->remote_description());
+
+ const char *codec = NULL;
+
+ if (desc->codecs().size() > 0)
+ PhoneSessionClient::FindMediaCodec(channel_manager_->media_engine(), desc, &codec);
+
+ // The other client should have returned one of the codecs that we offered.
+ // If they could not, they should have rejected the session. So, if we get
+ // into this state, we're dealing with a bad client, so we may as well just
+ // pick the mostt common format there is: payload type zero.
+ if (codec == NULL)
+ codec = "PCMU";
+
+ channel_->SetCodec(codec);
+}
+
+void VoiceChannel::OnSocketState(P2PSocket *socket, P2PSocket::State state) {
+ switch (state) {
+ case P2PSocket::STATE_WRITABLE:
+ SocketWritable_w();
+ break;
+
+ default:
+ SocketNotWritable_w();
+ break;
+ }
+}
+
+void VoiceChannel::OnSocketRead(P2PSocket *socket, const char *data, size_t len) {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ // OnSocketRead gets called from P2PSocket; now pass data to MediaEngine
+ channel_->OnPacketReceived(data, (int)len);
+}
+
+void VoiceChannel::SendPacket(const void *data, size_t len) {
+ // SendPacket gets called from MediaEngine; send to socket
+ // MediaEngine will call us on a random thread. The Send operation on the socket is
+ // special in that it can handle this.
+ socket_->Send(static_cast<const char *>(data), len);
+}
+
+void VoiceChannel::ChangeState() {
+ if (paused_ || !enabled_ || !socket_writable_) {
+ channel_->SetPlayout(false);
+ channel_->SetSend(false);
+ } else {
+ if (muted_) {
+ channel_->SetSend(false);
+ channel_->SetPlayout(true);
+ } else {
+ channel_->SetSend(true);
+ channel_->SetPlayout(true);
+ }
+ }
+}
+
+void VoiceChannel::PauseMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ assert(!paused_);
+
+ LOG(INFO) << "Voice channel paused";
+ paused_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::UnpauseMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ assert(paused_);
+
+ LOG(INFO) << "Voice channel unpaused";
+ paused_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::EnableMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (enabled_)
+ return;
+
+ LOG(INFO) << "Voice channel enabled";
+ enabled_ = true;
+ start_time_ = Time();
+ ChangeState();
+}
+
+void VoiceChannel::DisableMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!enabled_)
+ return;
+
+ LOG(INFO) << "Voice channel disabled";
+ enabled_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::MuteMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (muted_)
+ return;
+
+ LOG(INFO) << "Voice channel muted";
+ muted_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::UnmuteMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!muted_)
+ return;
+
+ LOG(INFO) << "Voice channel unmuted";
+ muted_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::SocketWritable_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (socket_writable_)
+ return;
+
+ LOG(INFO) << "Voice channel socket writable";
+ socket_writable_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::SocketNotWritable_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!socket_writable_)
+ return;
+
+ LOG(INFO) << "Voice channel socket not writable";
+ socket_writable_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::StartConnectionMonitor(int cms) {
+ delete socket_monitor_;
+ socket_monitor_ = new SocketMonitor(socket_, Thread::Current());
+ socket_monitor_
+ ->SignalUpdate.connect(this, &VoiceChannel::OnConnectionMonitorUpdate);
+ socket_monitor_->Start(cms);
+}
+
+void VoiceChannel::StopConnectionMonitor() {
+ if (socket_monitor_ != NULL) {
+ socket_monitor_->Stop();
+ socket_monitor_->SignalUpdate.disconnect(this);
+ delete socket_monitor_;
+ socket_monitor_ = NULL;
+ }
+}
+
+void VoiceChannel::OnConnectionMonitorUpdate(SocketMonitor *monitor,
+ const std::vector<ConnectionInfo> &infos) {
+ SignalConnectionMonitor(this, infos);
+}
+
+void VoiceChannel::StartAudioMonitor(int cms) {
+ delete audio_monitor_;
+ audio_monitor_ = new AudioMonitor(this, Thread::Current());
+ audio_monitor_
+ ->SignalUpdate.connect(this, &VoiceChannel::OnAudioMonitorUpdate);
+ audio_monitor_->Start(cms);
+}
+
+void VoiceChannel::StopAudioMonitor() {
+ if (audio_monitor_ != NULL) {
+ audio_monitor_ ->Stop();
+ audio_monitor_ ->SignalUpdate.disconnect(this);
+ delete audio_monitor_ ;
+ audio_monitor_ = NULL;
+ }
+}
+
+void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor *monitor,
+ const AudioInfo& info) {
+ SignalAudioMonitor(this, info);
+}
+
+Session *VoiceChannel::session() {
+ return session_;
+}
+
+bool VoiceChannel::HasQuality() {
+ return Time() >= start_time_ + kQualityDelay;
+}
+
+float VoiceChannel::GetCurrentQuality() {
+ return channel_->GetCurrentQuality();
+}
+
+int VoiceChannel::GetInputLevel_w() {
+ return channel_manager_->media_engine()->GetInputLevel();
+}
+
+int VoiceChannel::GetOutputLevel_w() {
+ return channel_->GetOutputLevel();
+}
+
+Thread* VoiceChannel::worker_thread() {
+ return channel_manager_->worker_thread();
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h
new file mode 100644
index 00000000..4cfa0b11
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h
@@ -0,0 +1,129 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VOICECHANNEL_H_
+#define _VOICECHANNEL_H_
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/network.h"
+#include "talk/base/sigslot.h"
+#include "talk/p2p/client/socketmonitor.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/p2p/base/session.h"
+#include "talk/session/phone/audiomonitor.h"
+#include "talk/session/phone/mediaengine.h"
+
+namespace cricket {
+
+const uint32 MSG_ENABLE = 1;
+const uint32 MSG_DISABLE = 2;
+const uint32 MSG_MUTE = 3;
+const uint32 MSG_UNMUTE = 4;
+const uint32 MSG_SETSENDCODEC = 5;
+
+class ChannelManager;
+
+class VoiceChannel
+ : public MessageHandler, public sigslot::has_slots<>,
+ public NetworkSession, public MediaChannel::NetworkInterface {
+ public:
+ VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel);
+ ~VoiceChannel();
+
+ void Enable(bool enable);
+ void Mute(bool mute);
+ MediaChannel *channel();
+ Session *session();
+
+ // Monitoring
+
+ void StartConnectionMonitor(int cms);
+ void StopConnectionMonitor();
+ sigslot::signal2<VoiceChannel *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
+
+ void StartAudioMonitor(int cms);
+ void StopAudioMonitor();
+ sigslot::signal2<VoiceChannel *, const AudioInfo&> SignalAudioMonitor;
+ Thread* worker_thread();
+
+ // Pausing so that the ChannelManager can change the audio devices. These
+ // should only be called from the worker thread
+ void PauseMedia_w();
+ void UnpauseMedia_w();
+
+ int GetInputLevel_w();
+ int GetOutputLevel_w();
+
+ // Gives a quality estimate to the network quality manager.
+ virtual bool HasQuality();
+ virtual float GetCurrentQuality();
+
+ // MediaEngine calls this
+ virtual void SendPacket(const void *data, size_t len);
+
+private:
+ void ChangeState();
+ void EnableMedia_w();
+ void DisableMedia_w();
+ void MuteMedia_w();
+ void UnmuteMedia_w();
+ void SocketWritable_w();
+ void SocketNotWritable_w();
+
+ void OnConnectionMonitorUpdate(SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos);
+ void OnAudioMonitorUpdate(AudioMonitor *monitor, const AudioInfo& info);
+
+ // From MessageHandler
+
+ void OnMessage(Message *pmsg);
+
+ // Setting the send codec based on the remote description.
+ void OnSessionState(Session* session, Session::State state);
+ void SetSendCodec_w();
+
+ // From P2PSocket
+
+ void OnSocketState(P2PSocket *socket, P2PSocket::State state);
+ void OnSocketRead(P2PSocket *socket, const char *data, size_t len);
+
+
+ bool enabled_;
+ bool paused_;
+ bool socket_writable_;
+ bool muted_;
+ MediaChannel *channel_;
+ Session *session_;
+ P2PSocket *socket_;
+ ChannelManager *channel_manager_;
+ SocketMonitor *socket_monitor_;
+ AudioMonitor *audio_monitor_;
+ uint32 start_time_;
+};
+
+}
+
+#endif // _VOICECHANNEL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h
new file mode 100644
index 00000000..a5326893
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h
@@ -0,0 +1,72 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RECEIVER_H_
+#define _RECEIVER_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/p2p/client/sessionclient.h"
+
+namespace cricket {
+
+class Receiver : public buzz::XmppTask {
+public:
+ Receiver(Task *parent, SessionClient *session_client)
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_TYPE) {
+ session_client_ = session_client;
+ }
+
+ virtual int ProcessStart() {
+ const buzz::XmlElement *stanza = NextStanza();
+ if (stanza == NULL)
+ return STATE_BLOCKED;
+ session_client_->OnIncomingStanza(stanza);
+
+ // Respond right away to the sender to let them know that we received
+ // this IQ
+ buzz::XmlElement * result = MakeIqResult(stanza);
+ SendStanza(result);
+
+ return STATE_START;
+ }
+
+protected:
+ virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+ if (!session_client_->IsClientStanza(stanza))
+ return false;
+ QueueStanza(stanza);
+ return true;
+ }
+
+private:
+ SessionClient *session_client_;
+};
+
+}
+
+#endif // _RECEIVER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h
new file mode 100644
index 00000000..9dc5384c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h
@@ -0,0 +1,111 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CRICKET_PHONE_SESSIONSENDTASK_H_
+#define _CRICKET_PHONE_SESSIONSENDTASK_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/p2p/client/sessionclient.h"
+
+namespace cricket {
+
+// The job of this task is to send an IQ stanza out (after stamping it with
+// an ID attribute) and then wait for a response. If not response happens
+// within 5 seconds, it will signal failure on a SessionClient. If an error
+// happens it will also signal failure. If, however, the send succeeds this
+// task will quietly go away.
+
+// It is safe for this to hold on to the session client. In the case where
+// the xmpp client goes away, this task will automatically be aborted. The
+// session_client is guaranteed to outlive the xmpp session.
+class SessionSendTask : public buzz::XmppTask {
+public:
+ SessionSendTask(Task *parent, SessionClient *session_client)
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+ session_client_(session_client),
+ timed_out_(false) {
+ }
+
+ void Send(const buzz::XmlElement* stanza) {
+ assert(stanza_.get() == NULL);
+ stanza_.reset(new buzz::XmlElement(*stanza));
+ stanza_->SetAttr(buzz::QN_ID, task_id());
+ }
+
+protected:
+ // This gets called by the task runner every 500 msec
+ virtual void Poll() {
+ if (ElapsedTime() > (15 * 1000 * 10000)) { // 15 secs
+ timed_out_ = true;
+ Wake();
+ }
+ }
+
+ virtual int ProcessStart() {
+ SendStanza(stanza_.get());
+ return STATE_RESPONSE;
+ }
+
+ virtual int ProcessResponse() {
+ if (timed_out_) {
+ session_client_->OnFailedSend(stanza_.get(), NULL);
+ return STATE_DONE;
+ }
+
+ const buzz::XmlElement* next = NextStanza();
+ if (next == NULL)
+ return STATE_BLOCKED;
+
+ if (next->Attr(buzz::QN_TYPE) == "result") {
+ return STATE_DONE;
+ } else {
+ session_client_->OnFailedSend(stanza_.get(), next);
+ return STATE_DONE;
+ }
+ }
+
+ virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+ if (!MatchResponseIq(stanza, buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id()))
+ return false;
+ if (stanza->Attr(buzz::QN_TYPE) == "result" ||
+ stanza->Attr(buzz::QN_TYPE) == "error") {
+ QueueStanza(stanza);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ SessionClient *session_client_;
+ buzz::scoped_ptr<buzz::XmlElement> stanza_;
+ bool timed_out_;
+};
+
+}
+
+#endif // _CRICKET_PHONE_SESSIONSENDTASK_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am
new file mode 100644
index 00000000..3186245a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=mediastreamer
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am
new file mode 100644
index 00000000..268a52fe
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.am
@@ -0,0 +1,92 @@
+EXTRA_DIST=Makefile.ms
+noinst_LTLIBRARIES = libmediastreamer.la
+libmediastreamer_la_SOURCES=msfilter.c msfilter.h msutils.h waveheader.h\
+ mscodec.c mscodec.h \
+ mssoundread.c mssoundread.h \
+ mssoundwrite.c mssoundwrite.h \
+ msbuffer.c msbuffer.h \
+ msqueue.c msqueue.h \
+ msfifo.c msfifo.h \
+ ms.c ms.h\
+ mssync.c mssync.h \
+ msnosync.c msnosync.h \
+ msread.c msread.h \
+ mswrite.c mswrite.h \
+ mscopy.c mscopy.h \
+ msosswrite.c msosswrite.h \
+ msossread.c msossread.h \
+ msringplayer.c msringplayer.h \
+ msrtprecv.c msrtprecv.h \
+ msrtpsend.c msrtpsend.h \
+ msAlawenc.c msAlawenc.h g711common.h \
+ msAlawdec.c msAlawdec.h g711common.h \
+ msMUlawenc.c msMUlawenc.h g711common.h \
+ msMUlawdec.c msMUlawdec.h g711common.h \
+ mstimer.c mstimer.h \
+ msqdispatcher.c msqdispatcher.h \
+ msfdispatcher.c msfdispatcher.h \
+ sndcard.c sndcard.h \
+ osscard.c osscard.h\
+ hpuxsndcard.c \
+ alsacard.c alsacard.h \
+ jackcard.c jackcard.h \
+ audiostream.c mediastream.h \
+ msspeexenc.c msspeexenc.h msspeexdec.c msspeexdec.h \
+ msilbcdec.c msilbcdec.h msilbcenc.c msilbcenc.h
+
+noinst_HEADERS = affine.h \
+ msAlawenc.h \
+ msfdispatcher.h \
+ msilbcdec.h \
+ msnosync.h \
+ msringplayer.h \
+ msspeexdec.h \
+ msutils.h \
+ waveheader.h \
+ alsacard.h \
+ msavdecoder.h \
+ msfifo.h \
+ msilbcenc.h \
+ msossread.h \
+ msrtprecv.h \
+ msspeexenc.h \
+ msv4l.h \
+ g711common.h \
+ msavencoder.h \
+ msfilter.h \
+ msLPC10decoder.h \
+ msosswrite.h \
+ msrtpsend.h \
+ mssync.h \
+ msvideosource.h \
+ jackcard.h \
+ msbuffer.h \
+ msGSMdecoder.h \
+ msLPC10encoder.h \
+ msqdispatcher.h \
+ mssdlout.h \
+ mstimer.h \
+ mswrite.h \
+ mediastream.h \
+ mscodec.h \
+ msGSMencoder.h \
+ msMUlawdec.h \
+ msqueue.h \
+ mssoundread.h \
+ mstruespeechdecoder.h \
+ osscard.h \
+ msAlawdec.h \
+ mscopy.h \
+ ms.h \
+ msMUlawenc.h \
+ msread.h \
+ mssoundwrite.h \
+ mstruespeechencoder.h \
+ sndcard.h
+
+
+libmediastreamer_la_LIBADD= $(GLIB_LIBS) $(ORTP_LIBS) $(SPEEX_LIBS)
+
+AM_CFLAGS=$(GLIB_CFLAGS) -DG_LOG_DOMAIN=\"MediaStreamer\" $(ORTP_CFLAGS) $(IPV6_CFLAGS) $(ILBC_CFLAGS) $(SPEEX_CFLAGS)
+
+INCLUDES= -I$(srcdir)/../../.. $(ORTP_CFLAGS)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms
new file mode 100644
index 00000000..8b7427c3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/Makefile.ms
@@ -0,0 +1,34 @@
+
+OBJEXT=o
+AR = ar
+RANLIB = ranlib
+DEFS= -DG_LOG_DOMAIN=\"MediaStreamer\"
+INCLUDES=-I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include/ \
+ -I../gsmlib/ -I../lpc10-1.5 -I../oRTP
+COMPILE= gcc $(DEFS) $(INCLUDES)
+LIBTOOL=libtool
+LDFLAGS=-L/usr/local/lib/ -lglib-1.3 -lgthread-1.3 -lpthread
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+
+libmediastreamer_a_OBJECTS = msfilter.$(OBJEXT) msbuffer.$(OBJEXT) \
+msqueue.$(OBJEXT) msfifo.$(OBJEXT) ms.$(OBJEXT) mssync.$(OBJEXT) \
+msnosync.$(OBJEXT) msread.$(OBJEXT) mswrite.$(OBJEXT) mscopy.$(OBJEXT) \
+msv4lsource.$(OBJEXT) msoss.$(OBJEXT) msosswrite.$(OBJEXT) \
+msossread.$(OBJEXT) msringplayer.$(OBJEXT) msGSMencoder.$(OBJEXT) \
+msGSMdecoder.$(OBJEXT) msLPC10encoder.$(OBJEXT) \
+msLPC10decoder.$(OBJEXT)
+
+all: libmediastreamer.a mstest
+
+
+.c.o:
+ $(COMPILE) -c $<
+
+libmediastreamer.a: $(libmediastreamer_a_OBJECTS)
+ -rm -f libmediastreamer.a
+ $(AR) cru libmediastreamer.a $(libmediastreamer_a_OBJECTS)
+ $(RANLIB) libmediastreamer.a
+
+
+mstest: test.o libmediastreamer.a
+ gcc -o mstest test.o libmediastreamer.a $(LDFLAGS) -Wl,-rpath /usr/local/lib
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README
new file mode 100644
index 00000000..1309f534
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/README
@@ -0,0 +1,3 @@
+Mediastreamer is the library that handle all media operations: rtp streaming
+from file, from soundcard, with codec transcoding, and vice-versa;-).
+And also video streaming in the future.
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h
new file mode 100644
index 00000000..620fdc9d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/affine.h
@@ -0,0 +1,43 @@
+/*
+ * affine.h -- Affine Transforms for 2d objects
+ * Copyright (C) 2002 Charles Yates <charles.yates@pandora.be>
+ * Portions Copyright (C) 2003 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _AFFINE_H
+#define _AFFINE_H
+
+#include <math.h>
+
+/** Affine transforms for 2d image manipulation. Current provides shearing and
+ rotating support.
+*/
+
+typedef struct {
+ double matrix[2][2];
+} affine_transform_t;
+
+void affine_transform_init( affine_transform_t *this );
+void affine_transform_rotate( affine_transform_t *this, double angle );
+void affine_transform_shear( affine_transform_t *this, double shear );
+void affine_transform_scale( affine_transform_t *this, double sx, double sy );
+double affine_transform_mapx( affine_transform_t *this, int x, int y );
+double affine_transform_mapy( affine_transform_t *this, int x, int y );
+void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp );
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c
new file mode 100644
index 00000000..c240aa72
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.c
@@ -0,0 +1,640 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "alsacard.h"
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+
+static gchar *over_pcmdev=NULL;
+
+#include "msossread.h"
+#include "msosswrite.h"
+
+#include <signal.h>
+
+int __alsa_card_write(AlsaCard *obj,char *buf,int size);
+
+int alsa_set_params(AlsaCard *obj, int rw, int bits, int stereo, int rate)
+{
+ snd_pcm_hw_params_t *hwparams=NULL;
+ snd_pcm_sw_params_t *swparams=NULL;
+ snd_pcm_t *pcm_handle;
+ gint dir,exact_value;
+ gint channels;
+ gint fsize=0;
+ gint periods=8;
+ gint periodsize=256;
+ gint err;
+ int format;
+
+ if (rw) {
+ pcm_handle=obj->write_handle;
+ }
+ else pcm_handle=obj->read_handle;
+
+ /* Allocate the snd_pcm_hw_params_t structure on the stack. */
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ /* Init hwparams with full configuration space */
+ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
+ g_warning("alsa_set_params: Cannot configure this PCM device.\n");
+ return(-1);
+ }
+
+ if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
+ g_warning("alsa_set_params: Error setting access.\n");
+ return(-1);
+ }
+ /* Set sample format */
+#ifdef WORDS_BIGENDIAN
+ format=SND_PCM_FORMAT_S16_BE;
+#else
+ format=SND_PCM_FORMAT_S16_LE;
+#endif
+ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
+ g_warning("alsa_set_params: Error setting format.\n");
+ return(-1);
+ }
+ /* Set number of channels */
+ if (stereo) channels=2;
+ else channels=1;
+ if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
+ g_warning("alsa_set_params: Error setting channels.\n");
+ return(-1);
+ }
+ /* Set sample rate. If the exact rate is not supported */
+ /* by the hardware, use nearest possible rate. */
+ exact_value=rate;
+ dir=0;
+ if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_value, &dir))<0){
+ g_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));
+ return -1;
+ }
+ if (dir != 0) {
+ g_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "
+ "==> Using %d Hz instead.\n", rate, exact_value);
+ }
+ /* choose greater period size when rate is high */
+ periodsize=periodsize*(rate/8000);
+
+ /* Set buffer size (in frames). The resulting latency is given by */
+ /* latency = periodsize * periods / (rate * bytes_per_frame) */
+ /*
+ fsize=periodsize * periods;
+ exact_value=fsize;
+ if ((err=snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,&exact_value)) < 0) {
+ g_warning("alsa_set_params: Error setting buffer size:%s",snd_strerror(err));
+ return(-1);
+ }
+ if (fsize!= exact_value) {
+ g_warning("alsa_set_params: The buffer size %d is not supported by your hardware.\n "
+ "==> Using %d instead.\n", fsize, exact_value);
+ }
+ */
+ /* set period size */
+ exact_value=periodsize;
+ dir=0;
+ if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
+ g_warning("alsa_set_params: Error setting period size.\n");
+ return(-1);
+ }
+ if (dir != 0) {
+ g_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "
+ "==> Using %d instead.\n", periodsize, exact_value);
+ }
+ periodsize=exact_value;
+ /* Set number of periods. Periods used to be called fragments. */
+ exact_value=periods;
+ dir=0;
+ if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
+ g_warning("alsa_set_params: Error setting periods.\n");
+ return(-1);
+ }
+ if (dir != 0) {
+ g_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "
+ "==> Using %d instead.\n", periods, exact_value);
+ }
+ /* Apply HW parameter settings to */
+ /* PCM device and prepare device */
+ if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
+ g_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));
+ return(-1);
+ }
+ /*prepare sw params */
+ if (rw){
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(pcm_handle, swparams);
+ if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){
+ g_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));
+ return -1;
+ }
+ if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){
+ g_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));
+ return(-1);
+ }
+ }
+ obj->frame_size=channels*(bits/8);
+ SND_CARD(obj)->bsize=periodsize*obj->frame_size;
+ /* //SND_CARD(obj)->bsize=4096; */
+ obj->frames=periodsize;
+ g_message("alsa_set_params: blocksize=%i.",SND_CARD(obj)->bsize);
+ return SND_CARD(obj)->bsize;
+}
+
+int alsa_card_open_r(AlsaCard *obj,int bits,int stereo,int rate)
+{
+ int bsize;
+ int err;
+ snd_pcm_t *pcm_handle;
+ gchar *pcmdev;
+ if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
+ else pcmdev=obj->pcmdev;
+
+ if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {
+ g_warning("alsa_card_open_r: Error opening PCM device %s\n",obj->pcmdev );
+ return -1;
+ }
+ g_return_val_if_fail(pcm_handle!=NULL,-1);
+ obj->read_handle=pcm_handle;
+ if ((bsize=alsa_set_params(obj,0,bits,stereo,rate))<0){
+ snd_pcm_close(pcm_handle);
+ obj->read_handle=NULL;
+ return -1;
+ }
+ obj->readbuf=g_malloc0(bsize);
+
+ err=snd_pcm_start(obj->read_handle);
+ if (err<0){
+ g_warning("Cannot start read pcm: %s", snd_strerror(err));
+ }
+ obj->readpos=0;
+ SND_CARD(obj)->bsize=bsize;
+ SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
+ return 0;
+}
+
+int alsa_card_open_w(AlsaCard *obj,int bits,int stereo,int rate)
+{
+ int err,bsize;
+ snd_pcm_t *pcm_handle;
+ gchar *pcmdev;
+ if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
+ else pcmdev=obj->pcmdev;
+
+ if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
+ g_warning("alsa_card_open_w: Error opening PCM device %s\n", obj->pcmdev);
+ return -1;
+ }
+ obj->write_handle=pcm_handle;
+ if ((bsize=alsa_set_params(obj,1,bits,stereo,rate))<0){
+ snd_pcm_close(pcm_handle);
+ obj->write_handle=NULL;
+ return -1;
+ }
+ obj->writebuf=g_malloc0(bsize);
+
+ obj->writepos=0;
+ SND_CARD(obj)->bsize=bsize;
+ SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
+ return 0;
+}
+
+
+void alsa_card_set_blocking_mode(AlsaCard *obj, gboolean yesno){
+ if (obj->read_handle!=NULL) snd_pcm_nonblock(obj->read_handle,!yesno);
+ if (obj->write_handle!=NULL) snd_pcm_nonblock(obj->write_handle,!yesno);
+}
+
+void alsa_card_close_r(AlsaCard *obj)
+{
+ if (obj->read_handle!=NULL){
+ snd_pcm_close(obj->read_handle);
+ obj->read_handle=NULL;
+ g_free(obj->readbuf);
+ obj->readbuf=NULL;
+ }
+}
+
+void alsa_card_close_w(AlsaCard *obj)
+{
+ if (obj->write_handle!=NULL){
+ snd_pcm_close(obj->write_handle);
+ obj->write_handle=NULL;
+ g_free(obj->writebuf);
+ obj->writebuf=NULL;
+ }
+}
+
+int alsa_card_probe(AlsaCard *obj,int bits,int stereo,int rate)
+{
+ int ret;
+ ret=alsa_card_open_w(obj,bits,stereo,rate);
+ if (ret<0) return -1;
+ ret=SND_CARD(obj)->bsize;
+ alsa_card_close_w(obj);
+ return ret;
+}
+
+
+void alsa_card_destroy(AlsaCard *obj)
+{
+ snd_card_uninit(SND_CARD(obj));
+ g_free(obj->pcmdev);
+ if (obj->readbuf!=0) g_free(obj->readbuf);
+ if (obj->writebuf!=0) g_free(obj->writebuf);
+}
+
+gboolean alsa_card_can_read(AlsaCard *obj)
+{
+ int frames;
+ g_return_val_if_fail(obj->read_handle!=NULL,0);
+ if (obj->readpos!=0) return TRUE;
+ if ( frames=snd_pcm_avail_update(obj->read_handle)>=obj->frames) return 1;
+ /* //g_message("frames=%i",frames); */
+ return 0;
+}
+
+
+
+int __alsa_card_read(AlsaCard *obj,char *buf,int bsize)
+{
+ int err;
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+ err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
+ if (err<0) {
+ if (err!=-EPIPE){
+ g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
+ }
+ snd_pcm_prepare(obj->read_handle);
+ err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
+ if (err<0) g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
+ }
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ return err*obj->frame_size;
+}
+
+int alsa_card_read(AlsaCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+ g_return_val_if_fail(obj->read_handle!=NULL,-1);
+ if (size<bsize){
+ gint canread=MIN(bsize-obj->readpos,size);
+
+ if (obj->readpos==0){
+ err=__alsa_card_read(obj,obj->readbuf,bsize);
+ }
+
+ memcpy(buf,&obj->readbuf[obj->readpos],canread);
+ obj->readpos+=canread;
+ if (obj->readpos>=bsize) obj->readpos=0;
+ return canread;
+ }else{
+ err=__alsa_card_read(obj,buf,size);
+ return err;
+ }
+
+}
+
+int __alsa_card_write(AlsaCard *obj,char *buf,int size)
+{
+ int err;
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+ if ((err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size))<0){
+ if (err!=-EPIPE){
+ g_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));
+ }
+ snd_pcm_prepare(obj->write_handle);
+ err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size);
+ if (err<0) g_warning("alsa_card_write: Error writing sound buffer (size=%i):%s",size,snd_strerror(err));
+
+ }
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ return err;
+}
+
+int alsa_card_write(AlsaCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+ g_return_val_if_fail(obj->write_handle!=NULL,-1);
+ if (size<bsize){
+ gint canwrite;
+
+ canwrite=MIN(bsize-obj->writepos,size);
+ memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
+ obj->writepos+=canwrite;
+ if (obj->writepos>=bsize){
+ err=__alsa_card_write(obj,obj->writebuf,bsize);
+ obj->writepos=0;
+ }
+ return canwrite;
+ }else{
+ return __alsa_card_write(obj,buf,bsize);
+ }
+}
+
+snd_mixer_t *alsa_mixer_open(AlsaCard *obj){
+ snd_mixer_t *mixer=NULL;
+ int err;
+ err=snd_mixer_open(&mixer,0);
+ if (err<0){
+ g_warning("Could not open alsa mixer: %s",snd_strerror(err));
+ return NULL;
+ }
+ if ((err = snd_mixer_attach (mixer, obj->mixdev)) < 0){
+ g_warning("Could not attach mixer to card: %s",snd_strerror(err));
+ snd_mixer_close(mixer);
+ return NULL;
+ }
+ if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){
+ g_warning("snd_mixer_selem_register: %s",snd_strerror(err));
+ snd_mixer_close(mixer);
+ return NULL;
+ }
+ if ((err = snd_mixer_load (mixer)) < 0){
+ g_warning("snd_mixer_load: %s",snd_strerror(err));
+ snd_mixer_close(mixer);
+ return NULL;
+ }
+ obj->mixer=mixer;
+ return mixer;
+}
+
+void alsa_mixer_close(AlsaCard *obj){
+ snd_mixer_close(obj->mixer);
+ obj->mixer=NULL;
+}
+
+typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;
+
+static gint get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){
+ long value=0;
+ const char *elemname;
+ snd_mixer_elem_t *elem;
+ int err;
+ long sndMixerPMin;
+ long sndMixerPMax;
+ long newvol;
+ elem=snd_mixer_first_elem(mixer);
+ while (elem!=NULL){
+ elemname=snd_mixer_selem_get_name(elem);
+ /* //g_message("Found alsa mixer element %s.",elemname); */
+ if (strcmp(elemname,name)==0){
+ switch (action){
+ case CAPTURE:
+ if (snd_mixer_selem_has_capture_volume(elem)){
+ snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
+ err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);
+ newvol-=sndMixerPMin;
+ value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
+ if (err<0) g_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));
+ /* //else g_message("Succesfully get capture level for %s.",elemname); */
+ break;
+ }
+ break;
+ case PLAYBACK:
+ if (snd_mixer_selem_has_playback_volume(elem)){
+ snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
+ err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);
+ newvol-=sndMixerPMin;
+ value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
+ if (err<0) g_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));
+ /* //else g_message("Succesfully get playback level for %s.",elemname); */
+ break;
+ }
+ break;
+ case CAPTURE_SWITCH:
+
+ break;
+ }
+ }
+ elem=snd_mixer_elem_next(elem);
+ }
+
+ return value;
+}
+
+
+static void set_mixer_element(snd_mixer_t *mixer,const char *name, gint level,MixerAction action){
+ const char *elemname;
+ snd_mixer_elem_t *elem;
+ int tmp;
+ long sndMixerPMin;
+ long sndMixerPMax;
+ long newvol;
+
+ elem=snd_mixer_first_elem(mixer);
+
+ while (elem!=NULL){
+ elemname=snd_mixer_selem_get_name(elem);
+ /* //g_message("Found alsa mixer element %s.",elemname); */
+ if (strcmp(elemname,name)==0){
+ switch(action){
+ case CAPTURE:
+ if (snd_mixer_selem_has_capture_volume(elem)){
+ snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
+ newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
+ snd_mixer_selem_set_capture_volume_all(elem,newvol);
+ /* //g_message("Succesfully set capture level for %s.",elemname); */
+ return;
+ }
+ break;
+ case PLAYBACK:
+ if (snd_mixer_selem_has_playback_volume(elem)){
+ snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
+ newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
+ snd_mixer_selem_set_playback_volume_all(elem,newvol);
+ /* //g_message("Succesfully set playback level for %s.",elemname); */
+ return;
+ }
+ break;
+ case CAPTURE_SWITCH:
+ if (snd_mixer_selem_has_capture_switch(elem)){
+ snd_mixer_selem_set_capture_switch_all(elem,level);
+ /* //g_message("Succesfully set capture switch for %s.",elemname); */
+ }
+ break;
+ case PLAYBACK_SWITCH:
+ if (snd_mixer_selem_has_playback_switch(elem)){
+ snd_mixer_selem_set_playback_switch_all(elem,level);
+ /* //g_message("Succesfully set capture switch for %s.",elemname); */
+ }
+ break;
+
+ }
+ }
+ elem=snd_mixer_elem_next(elem);
+ }
+
+ return ;
+}
+
+
+void alsa_card_set_level(AlsaCard *obj,gint way,gint a)
+{
+ snd_mixer_t *mixer;
+ mixer=alsa_mixer_open(obj);
+ if (mixer==NULL) return ;
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ set_mixer_element(mixer,"Master",a,PLAYBACK);
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ set_mixer_element(mixer,"Capture",a,CAPTURE);
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ set_mixer_element(mixer,"PCM",a,PLAYBACK);
+ break;
+ default:
+ g_warning("oss_card_set_level: unsupported command.");
+ }
+ alsa_mixer_close(obj);
+}
+
+gint alsa_card_get_level(AlsaCard *obj,gint way)
+{
+ snd_mixer_t *mixer;
+ gint value;
+ mixer=alsa_mixer_open(obj);
+ if (mixer==NULL) return 0;
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ value=get_mixer_element(mixer,"Master",PLAYBACK);
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ value=get_mixer_element(mixer,"Capture",CAPTURE);
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ value=get_mixer_element(mixer,"PCM",PLAYBACK);
+ break;
+ default:
+ g_warning("oss_card_set_level: unsupported command.");
+ }
+ alsa_mixer_close(obj);
+ return value;
+}
+
+void alsa_card_set_source(AlsaCard *obj,int source)
+{
+ snd_mixer_t *mixer;
+ mixer=alsa_mixer_open(obj);
+ if (mixer==NULL) return;
+ switch (source){
+ case 'm':
+ set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);
+ set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
+ break;
+ case 'l':
+ set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);
+ set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
+ break;
+ }
+}
+
+MSFilter *alsa_card_create_read_filter(AlsaCard *card)
+{
+ MSFilter *f=ms_oss_read_new();
+ ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
+ return f;
+}
+
+MSFilter *alsa_card_create_write_filter(AlsaCard *card)
+{
+ MSFilter *f=ms_oss_write_new();
+ ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
+ return f;
+}
+
+
+SndCard * alsa_card_new(gint devid)
+{
+ AlsaCard * obj;
+ SndCard *base;
+ int err;
+ gchar *name=NULL;
+
+ /* carefull: this is an alsalib call despite its name! */
+ err=snd_card_get_name(devid,&name);
+ if (err<0) {
+ return NULL;
+ }
+ obj= g_new0(AlsaCard,1);
+ base= SND_CARD(obj);
+ snd_card_init(base);
+
+ base->card_name=g_strdup_printf("%s (Advanced Linux Sound Architecture)",name);
+ base->_probe=(SndCardOpenFunc)alsa_card_probe;
+ base->_open_r=(SndCardOpenFunc)alsa_card_open_r;
+ base->_open_w=(SndCardOpenFunc)alsa_card_open_w;
+ base->_can_read=(SndCardPollFunc)alsa_card_can_read;
+ base->_set_blocking_mode=(SndCardSetBlockingModeFunc)alsa_card_set_blocking_mode;
+ base->_read=(SndCardIOFunc)alsa_card_read;
+ base->_write=(SndCardIOFunc)alsa_card_write;
+ base->_close_r=(SndCardCloseFunc)alsa_card_close_r;
+ base->_close_w=(SndCardCloseFunc)alsa_card_close_w;
+ base->_set_rec_source=(SndCardMixerSetRecSourceFunc)alsa_card_set_source;
+ base->_set_level=(SndCardMixerSetLevelFunc)alsa_card_set_level;
+ base->_get_level=(SndCardMixerGetLevelFunc)alsa_card_get_level;
+ base->_destroy=(SndCardDestroyFunc)alsa_card_destroy;
+ base->_create_read_filter=(SndCardCreateFilterFunc)alsa_card_create_read_filter;
+ base->_create_write_filter=(SndCardCreateFilterFunc)alsa_card_create_write_filter;
+
+
+ obj->pcmdev=g_strdup_printf("plughw:%i,0",devid);
+ obj->mixdev=g_strdup_printf("hw:%i",devid);
+ obj->readbuf=NULL;
+ obj->writebuf=NULL;
+ return base;
+}
+
+
+gint alsa_card_manager_init(SndCardManager *m, gint index)
+{
+ gint devindex;
+ gint i;
+ gint found=0;
+ gchar *name=NULL;
+ for(devindex=0;index<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
+ if (snd_card_get_name(devindex,&name)==0){
+ g_message("Found ALSA device: %s",name);
+ m->cards[index]=alsa_card_new(devindex);
+ m->cards[index]->index=index;
+ found++;
+ index++;
+ }
+ }
+ return found;
+}
+
+void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev){
+ if (over_pcmdev!=NULL){
+ g_free(over_pcmdev);
+ }
+ over_pcmdev=g_strdup(pcmdev);
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h
new file mode 100644
index 00000000..df3372fb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/alsacard.h
@@ -0,0 +1,50 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+
+#include "sndcard.h"
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#include <alsa/asoundlib.h>
+struct _AlsaCard
+{
+ SndCard parent;
+ gchar *pcmdev;
+ gchar *mixdev;
+ snd_pcm_t *read_handle;
+ snd_pcm_t *write_handle;
+ gint frame_size;
+ gint frames;
+ gchar *readbuf;
+ gint readpos;
+ gchar *writebuf;
+ gint writepos;
+ snd_mixer_t *mixer;
+};
+
+typedef struct _AlsaCard AlsaCard;
+
+SndCard *alsa_card_new(gint dev_id);
+gint alsa_card_manager_init(SndCardManager *m, gint index);
+void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c
new file mode 100644
index 00000000..f4ff4867
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/audiostream.c
@@ -0,0 +1,343 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "mediastream.h"
+#ifdef INET6
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
+#endif
+
+
+#define MAX_RTP_SIZE 1500
+
+/* this code is not part of the library itself, it is part of the mediastream program */
+void audio_stream_free(AudioStream *stream)
+{
+ RtpSession *s;
+ RtpSession *destroyed=NULL;
+ if (stream->rtprecv!=NULL) {
+ s=ms_rtp_recv_get_session(MS_RTP_RECV(stream->rtprecv));
+ if (s!=NULL){
+ destroyed=s;
+ rtp_session_destroy(s);
+ }
+ ms_filter_destroy(stream->rtprecv);
+ }
+ if (stream->rtpsend!=NULL) {
+ s=ms_rtp_send_get_session(MS_RTP_SEND(stream->rtpsend));
+ if (s!=NULL){
+ if (s!=destroyed)
+ rtp_session_destroy(s);
+ }
+ ms_filter_destroy(stream->rtpsend);
+ }
+ if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
+ if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
+ if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
+ if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
+ if (stream->timer!=NULL) ms_sync_destroy(stream->timer);
+ g_free(stream);
+}
+
+static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
+
+static void on_dtmf_received(RtpSession *s,gint dtmf,gpointer user_data)
+{
+ AudioStream *stream=(AudioStream*)user_data;
+ if (dtmf>15){
+ g_warning("Unsupported telephone-event type.");
+ return;
+ }
+ g_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
+ if (stream!=NULL){
+ if (strcmp(stream->soundwrite->klass->name,"OssWrite")==0)
+ ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf_tab[dtmf]);
+ }
+}
+
+static void on_timestamp_jump(RtpSession *s,guint32* ts, gpointer user_data)
+{
+ g_warning("The remote sip-phone has send data with a future timestamp: %u,"
+ "resynchronising session.",*ts);
+ rtp_session_reset(s);
+}
+
+static const char *ip4local="0.0.0.0";
+static const char *ip6local="::";
+
+const char *get_local_addr_for(const char *remote)
+{
+ const char *ret;
+#ifdef INET6
+ char num[8];
+ struct addrinfo hints, *res0;
+ int err;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ err = getaddrinfo(remote,"8000", &hints, &res0);
+ if (err!=0) {
+ g_warning ("get_local_addr_for: %s", gai_strerror(err));
+ return ip4local;
+ }
+ ret=(res0->ai_addr->sa_family==AF_INET6) ? ip6local : ip4local;
+ freeaddrinfo(res0);
+#else
+ ret=ip4local;
+#endif
+ return ret;
+}
+
+void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport,
+ int payload,int jitt_comp,
+ RtpSession **recvsend){
+ RtpSession *rtpr;
+ rtpr=rtp_session_new(RTP_SESSION_SENDRECV);
+ rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
+ rtp_session_set_profile(rtpr,profile);
+ rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport);
+ if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport);
+ rtp_session_set_scheduling_mode(rtpr,0);
+ rtp_session_set_blocking_mode(rtpr,0);
+ rtp_session_set_payload_type(rtpr,payload);
+ rtp_session_set_jitter_compensation(rtpr,jitt_comp);
+ rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE);
+ /*rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);*/
+ *recvsend=rtpr;
+}
+
+void create_rtp_sessions(RtpProfile *profile, int locport,char *remip,int remport,
+ int payload,int jitt_comp,
+ RtpSession **recv, RtpSession **send){
+ RtpSession *rtps,*rtpr;
+ PayloadType *pt;
+ /* creates two rtp filters to recv send streams (remote part)*/
+
+ rtps=rtp_session_new(RTP_SESSION_SENDONLY);
+ rtp_session_max_buf_size_set(rtps,MAX_RTP_SIZE);
+ rtp_session_set_profile(rtps,profile);
+#ifdef INET6
+ rtp_session_set_local_addr(rtps,"::",locport+2);
+#else
+ rtp_session_set_local_addr(rtps,"0.0.0.0",locport+2);
+#endif
+ rtp_session_set_remote_addr(rtps,remip,remport);
+ rtp_session_set_scheduling_mode(rtps,0);
+ rtp_session_set_blocking_mode(rtps,0);
+ rtp_session_set_payload_type(rtps,payload);
+ rtp_session_set_jitter_compensation(rtps,jitt_comp);
+
+ rtpr=rtp_session_new(RTP_SESSION_RECVONLY);
+ rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
+ rtp_session_set_profile(rtpr,profile);
+#ifdef INET6
+ rtp_session_set_local_addr(rtpr,"::",locport);
+#else
+ rtp_session_set_local_addr(rtpr,"0.0.0.0",locport);
+#endif
+ rtp_session_set_scheduling_mode(rtpr,0);
+ rtp_session_set_blocking_mode(rtpr,0);
+ rtp_session_set_payload_type(rtpr,payload);
+ rtp_session_set_jitter_compensation(rtpr,jitt_comp);
+ rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,NULL);
+ rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);
+ *recv=rtpr;
+ *send=rtps;
+
+}
+
+
+AudioStream * audio_stream_start_full(RtpProfile *profile, int locport,char *remip,int remport,
+ int payload,int jitt_comp, gchar *infile, gchar *outfile, SndCard *playcard, SndCard *captcard)
+{
+ AudioStream *stream=g_new0(AudioStream,1);
+ RtpSession *rtps,*rtpr;
+ PayloadType *pt;
+
+ /* //create_rtp_sessions(profile,locport,remip,remport,payload,jitt_comp,&rtpr,&rtps); */
+
+ create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr);
+ rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,(gpointer)stream);
+ rtps=rtpr;
+
+ stream->recv_session = rtpr;
+ stream->send_session = rtps;
+ stream->rtpsend=ms_rtp_send_new();
+ ms_rtp_send_set_session(MS_RTP_SEND(stream->rtpsend),rtps);
+ stream->rtprecv=ms_rtp_recv_new();
+ ms_rtp_recv_set_session(MS_RTP_RECV(stream->rtprecv),rtpr);
+
+
+ /* creates the local part */
+ if (infile==NULL) stream->soundread=snd_card_create_read_filter(captcard);
+ else stream->soundread=ms_read_new(infile);
+ if (outfile==NULL) stream->soundwrite=snd_card_create_write_filter(playcard);
+ else stream->soundwrite=ms_write_new(outfile);
+
+ /* creates the couple of encoder/decoder */
+ pt=rtp_profile_get_payload(profile,payload);
+ if (pt==NULL){
+ g_error("audiostream.c: undefined payload type.");
+ return NULL;
+ }
+ stream->encoder=ms_encoder_new_with_string_id(pt->mime_type);
+ stream->decoder=ms_decoder_new_with_string_id(pt->mime_type);
+ if ((stream->encoder==NULL) || (stream->decoder==NULL)){
+ /* big problem: we have not a registered codec for this payload...*/
+ audio_stream_free(stream);
+ g_error("mediastream.c: No decoder available for payload %i.",payload);
+ return NULL;
+ }
+ /* give the sound filters some properties */
+ ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
+ ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
+
+ /* give the encoder/decoder some parameters*/
+ ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
+ ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
+ ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
+ ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
+
+ ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->fmtp);
+ ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->fmtp);
+ /* create the synchronisation source */
+ stream->timer=ms_timer_new();
+
+ /* and then connect all */
+ ms_filter_add_link(stream->soundread,stream->encoder);
+ ms_filter_add_link(stream->encoder,stream->rtpsend);
+ ms_filter_add_link(stream->rtprecv,stream->decoder);
+ ms_filter_add_link(stream->decoder,stream->soundwrite);
+
+ ms_sync_attach(stream->timer,stream->soundread);
+ ms_sync_attach(stream->timer,stream->rtprecv);
+
+ /* and start */
+ ms_start(stream->timer);
+
+ return stream;
+}
+
+static int defcard=0;
+
+void audio_stream_set_default_card(int cardindex){
+ defcard=cardindex;
+}
+
+AudioStream * audio_stream_start_with_files(RtpProfile *prof,int locport,char *remip,
+ int remport,int profile,int jitt_comp,gchar *infile, gchar*outfile)
+{
+ return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,infile,outfile,NULL,NULL);
+}
+
+AudioStream * audio_stream_start(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp)
+{
+ SndCard *sndcard;
+ sndcard=snd_card_manager_get_card(snd_card_manager,defcard);
+ return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,sndcard,sndcard);
+}
+
+AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp,SndCard *playcard, SndCard *captcard)
+{
+ g_return_val_if_fail(playcard!=NULL,NULL);
+ g_return_val_if_fail(captcard!=NULL,NULL);
+ return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,playcard,captcard);
+}
+
+void audio_stream_set_rtcp_information(AudioStream *st, const char *cname){
+ if (st->send_session!=NULL){
+ rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL, NULL,"linphone",
+ "This is free software (GPL) !");
+ }
+}
+
+void audio_stream_stop(AudioStream * stream)
+{
+
+ ms_stop(stream->timer);
+ ortp_global_stats_display();
+ ms_sync_detach(stream->timer,stream->soundread);
+ ms_sync_detach(stream->timer,stream->rtprecv);
+
+ ms_filter_remove_links(stream->soundread,stream->encoder);
+ ms_filter_remove_links(stream->encoder,stream->rtpsend);
+ ms_filter_remove_links(stream->rtprecv,stream->decoder);
+ ms_filter_remove_links(stream->decoder,stream->soundwrite);
+
+ audio_stream_free(stream);
+}
+
+RingStream * ring_start(gchar *file,gint interval,SndCard *sndcard)
+{
+ return ring_start_with_cb(file,interval,sndcard,NULL,NULL);
+}
+
+RingStream * ring_start_with_cb(gchar *file,gint interval,SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data)
+{
+ RingStream *stream;
+ int tmp;
+ g_return_val_if_fail(sndcard!=NULL,NULL);
+ stream=g_new0(RingStream,1);
+ stream->source=ms_ring_player_new(file,interval);
+ if (stream->source==NULL) {
+ g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file);
+ return NULL;
+ }
+ if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data);
+ stream->sndwrite=snd_card_create_write_filter(sndcard);
+ ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp);
+ ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp);
+ ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_CHANNELS,&tmp);
+ ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_CHANNELS,&tmp);
+ stream->timer=ms_timer_new();
+ ms_filter_add_link(stream->source,stream->sndwrite);
+ ms_sync_attach(stream->timer,stream->source);
+ ms_start(stream->timer);
+ return stream;
+}
+
+void ring_stop(RingStream *stream)
+{
+ ms_stop(stream->timer);
+ ms_sync_detach(stream->timer,stream->source);
+ ms_sync_destroy(stream->timer);
+ ms_filter_remove_links(stream->source,stream->sndwrite);
+ ms_filter_destroy(stream->source);
+ ms_filter_destroy(stream->sndwrite);
+ g_free(stream);
+}
+
+/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
+gint test_audio_dev(int dev_id)
+{
+ gint err;
+ SndCard *sndcard=snd_card_manager_get_card(snd_card_manager,dev_id);
+ if (sndcard==NULL) return -1;
+ err=snd_card_probe(sndcard,16,0,8000);
+ return err; /* return latency in number of sample */
+}
+
+gint audio_stream_send_dtmf(AudioStream *stream, gchar dtmf)
+{
+ ms_rtp_send_dtmf(MS_RTP_SEND(stream->rtpsend), dtmf);
+ ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h
new file mode 100644
index 00000000..3f5ad16f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/g711common.h
@@ -0,0 +1,171 @@
+/*
+ * PCM - A-Law conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * Wrapper for linphone Codec class by Simon Morlat <simon.morlat@free.fr>
+ */
+
+static inline int val_seg(int val)
+{
+ int r = 0;
+ val >>= 7;
+ if (val & 0xf0) {
+ val >>= 4;
+ r += 4;
+ }
+ if (val & 0x0c) {
+ val >>= 2;
+ r += 2;
+ }
+ if (val & 0x02)
+ r += 1;
+ return r;
+}
+
+/*
+ * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+static inline unsigned char s16_to_alaw(int pcm_val)
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5;
+ } else {
+ mask = 0x55;
+ pcm_val = -pcm_val;
+ if (pcm_val > 0x7fff)
+ pcm_val = 0x7fff;
+ }
+
+ if (pcm_val < 256)
+ aval = pcm_val >> 4;
+ else {
+ /* Convert the scaled magnitude to segment number. */
+ seg = val_seg(pcm_val);
+ aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
+ }
+ return aval ^ mask;
+}
+
+/*
+ * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+static inline int alaw_to_s16(unsigned char a_val)
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+ t = a_val & 0x7f;
+ if (t < 16)
+ t = (t << 4) + 8;
+ else {
+ seg = (t >> 4) & 0x07;
+ t = ((t & 0x0f) << 4) + 0x108;
+ t <<= seg -1;
+ }
+ return ((a_val & 0x80) ? t : -t);
+}
+/*
+ * s16_to_ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ if (pcm_val < 0) {
+ pcm_val = 0x84 - pcm_val;
+ mask = 0x7f;
+ } else {
+ pcm_val += 0x84;
+ mask = 0xff;
+ }
+ if (pcm_val > 0x7fff)
+ pcm_val = 0x7fff;
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = val_seg(pcm_val);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
+ return uval ^ mask;
+}
+
+/*
+ * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+static inline int ulaw_to_s16(unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & 0x0f) << 3) + 0x84;
+ t <<= (u_val & 0x70) >> 4;
+
+ return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c
new file mode 100644
index 00000000..8210e29d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/hpuxsndcard.c
@@ -0,0 +1,301 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "sndcard.h"
+#include "osscard.h"
+
+#ifdef HAVE_SYS_AUDIO_H
+#include <sys/audio.h>
+
+
+#include "msossread.h"
+#include "msosswrite.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+
+int hpuxsnd_open(HpuxSndCard *obj, int bits,int stereo, int rate)
+{
+ int fd;
+ int p=0,cond=0;
+ int i=0;
+ int min_size=0,blocksize=512;
+ /* do a quick non blocking open to be sure that we are not going to be blocked here
+ for the eternity */
+ fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
+ if (fd<0) return -EWOULDBLOCK;
+ close(fd);
+ /* open the device */
+ fd=open(obj->dev_name,O_RDWR);
+
+ g_return_val_if_fail(fd>0,-errno);
+
+ ioctl(fd,AUDIO_RESET,0);
+ ioctl(fd,AUDIO_SET_SAMPLE_RATE,rate);
+ ioctl(fd,AUDIO_SET_CHANNELS,stereo);
+ p=AUDIO_FORMAT_LINEAR16BIT;
+ ioctl(fd,AUDIO_SET_DATA_FORMAT,p);
+ /* ioctl(fd,AUDIO_GET_RXBUFSIZE,&min_size); does not work ? */
+ min_size=2048;
+
+ g_message("dsp blocksize is %i.",min_size);
+ obj->fd=fd;
+ obj->readpos=0;
+ obj->writepos=0;
+ SND_CARD(obj)->bits=bits;
+ SND_CARD(obj)->stereo=stereo;
+ SND_CARD(obj)->rate=rate;
+ SND_CARD(obj)->bsize=min_size;
+ return fd;
+}
+
+int hpux_snd_card_probe(HpuxSndCard *obj,int bits,int stereo,int rate)
+{
+ return 2048;
+}
+
+
+int hpux_snd_card_open(HpuxSndCard *obj,int bits,int stereo,int rate)
+{
+ int fd;
+ obj->ref++;
+ if (obj->fd==0){
+ fd=hpuxsnd_open(obj,bits,stereo,rate);
+ if (fd<0) {
+ obj->fd=0;
+ obj->ref--;
+ return -1;
+ }
+ }
+ SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
+ return 0;
+}
+
+void hpux_snd_card_close(HpuxSndCard *obj)
+{
+ int i;
+ obj->ref--;
+ if (obj->ref==0) {
+ close(obj->fd);
+ obj->fd=0;
+ SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
+
+ }
+}
+
+void hpux_snd_card_destroy(HpuxSndCard *obj)
+{
+ snd_card_uninit(SND_CARD(obj));
+ g_free(obj->dev_name);
+ g_free(obj->mixdev_name);
+}
+
+gboolean hpux_snd_card_can_read(HpuxSndCard *obj)
+{
+ struct timeval tout={0,0};
+ int err;
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ FD_SET(obj->fd,&fdset);
+ err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
+ if (err>0) return TRUE;
+ else return FALSE;
+}
+
+int hpux_snd_card_read(HpuxSndCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+ if (size<bsize){
+ gint canread=MIN(bsize-obj->readpos,size);
+ if (obj->readbuf==NULL) obj->readbuf=g_malloc0(bsize);
+ if (obj->readpos==0){
+ err=read(obj->fd,obj->readbuf,bsize);
+ if (err<0) {
+ g_warning("hpux_snd_card_read: read() failed:%s.",strerror(errno));
+ return -1;
+ }
+ }
+
+ memcpy(buf,&obj->readbuf[obj->readpos],canread);
+ obj->readpos+=canread;
+ if (obj->readpos>=bsize) obj->readpos=0;
+ return canread;
+ }else{
+ err=read(obj->fd,buf,size);
+ if (err<0) {
+ g_warning("hpux_snd_card_read: read-2() failed:%s.",strerror(errno));
+ }
+ return err;
+ }
+
+}
+
+int hpux_snd_card_write(HpuxSndCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+ if (size<bsize){
+ gint canwrite=MIN(bsize-obj->writepos,size);
+ if (obj->writebuf==NULL) obj->writebuf=g_malloc0(bsize);
+
+ memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
+ obj->writepos+=canwrite;
+ if (obj->writepos>=bsize){
+ err=write(obj->fd,obj->writebuf,bsize);
+ }
+ return canwrite;
+ }else{
+ return write(obj->fd,buf,bsize);
+ }
+}
+
+#define SND_CARD_LEVEL_TO_HPUX_LEVEL(a) (((a)*2) - 100)
+#define HPUX_LEVEL_TO_SND_CARD_LEVEL(a) (((a)+200)/2)
+void hpux_snd_card_set_level(HpuxSndCard *obj,gint way,gint a)
+{
+ struct audio_gain gain;
+ int error,mix_fd;
+
+ g_return_if_fail(obj->mixdev_name!=NULL);
+ memset(&gain,0,sizeof(struct audio_gain));
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ gain.cgain[0].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ gain.cgain[1].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ gain.cgain[0].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ gain.cgain[1].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ gain.cgain[0].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ gain.cgain[1].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
+ break;
+ default:
+ g_warning("hpux_snd_card_set_level: unsupported command.");
+ return;
+ }
+ gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
+ mix_fd = open(obj->mixdev_name, O_WRONLY);
+ g_return_if_fail(mix_fd>0);
+ error=ioctl(mix_fd,AUDIO_SET_GAINS,&gain);
+ if (error<0){
+ g_warning("hpux_snd_card_set_level: Could not set gains: %s",strerror(errno));
+ }
+ close(mix_fd);
+}
+
+gint hpux_snd_card_get_level(HpuxSndCard *obj,gint way)
+{
+ struct audio_gain gain;
+ int p=0,mix_fd,error;
+ g_return_if_fail(obj->mixdev_name!=NULL);
+
+ gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
+ mix_fd = open(obj->mixdev_name, O_RDONLY);
+ g_return_if_fail(mix_fd>0);
+ error=ioctl(mix_fd,AUDIO_GET_GAINS,&gain);
+ if (error<0){
+ g_warning("hpux_snd_card_set_level: Could not get gains: %s",strerror(errno));
+ }
+ close(mix_fd);
+
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ p=gain.cgain[0].monitor_gain;
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ p=gain.cgain[0].receive_gain;
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ p=gain.cgain[0].transmit_gain;
+ break;
+ default:
+ g_warning("hpux_snd_card_get_level: unsupported command.");
+ return -1;
+ }
+ return HPUX_LEVEL_TO_SND_CARD_LEVEL(p);
+}
+
+void hpux_snd_card_set_source(HpuxSndCard *obj,int source)
+{
+ gint p=0;
+ gint mix_fd;
+ gint error=0;
+ g_return_if_fail(obj->mixdev_name!=NULL);
+
+ mix_fd=open("/dev/audio",O_WRONLY);
+ g_return_if_fail(mix_fd>0);
+ switch(source){
+ case 'm':
+ error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE);
+ break;
+ case 'l':
+ error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_LINE);
+ break;
+ default:
+ g_warning("hpux_snd_card_set_source: unsupported source.");
+ }
+ close(mix_fd);
+}
+
+MSFilter *hpux_snd_card_create_read_filter(HpuxSndCard *card)
+{
+ MSFilter *f=ms_oss_read_new();
+ ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
+ return f;
+}
+
+MSFilter *hpux_snd_card_create_write_filter(HpuxSndCard *card)
+{
+ MSFilter *f=ms_oss_write_new();
+ ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
+ return f;
+}
+
+
+SndCard * hpux_snd_card_new(char *devname, char *mixdev_name)
+{
+ HpuxSndCard * obj= g_new0(HpuxSndCard,1);
+ SndCard *base= SND_CARD(obj);
+ snd_card_init(base);
+ obj->dev_name=g_strdup(devname);
+ obj->mixdev_name=g_strdup( mixdev_name);
+ base->card_name=g_strdup(devname);
+ base->_probe=(SndCardOpenFunc)hpux_snd_card_probe;
+ base->_open_r=(SndCardOpenFunc)hpux_snd_card_open;
+ base->_open_w=(SndCardOpenFunc)hpux_snd_card_open;
+ base->_can_read=(SndCardPollFunc)hpux_snd_card_can_read;
+ base->_read=(SndCardIOFunc)hpux_snd_card_read;
+ base->_write=(SndCardIOFunc)hpux_snd_card_write;
+ base->_close_r=(SndCardCloseFunc)hpux_snd_card_close;
+ base->_close_w=(SndCardCloseFunc)hpux_snd_card_close;
+ base->_set_rec_source=(SndCardMixerSetRecSourceFunc)hpux_snd_card_set_source;
+ base->_set_level=(SndCardMixerSetLevelFunc)hpux_snd_card_set_level;
+ base->_get_level=(SndCardMixerGetLevelFunc)hpux_snd_card_get_level;
+ base->_destroy=(SndCardDestroyFunc)hpux_snd_card_destroy;
+ base->_create_read_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_read_filter;
+ base->_create_write_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_write_filter;
+ return base;
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c
new file mode 100644
index 00000000..b929cce9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.c
@@ -0,0 +1,574 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ JACK support
+ Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
+*/
+
+#include "jackcard.h"
+
+#ifdef __JACK_ENABLED__
+
+#include "msossread.h"
+#include "msosswrite.h"
+
+#include <signal.h>
+
+#define READBUFFERSIZE 524288
+#define WRITEBUFFERSIZE 524288
+#define BSIZE 512
+
+/**
+ * jack_shutdown:
+ * @arg:
+ *
+ * This is the shutdown callback for this JACK application.
+ * It is called by JACK if the server ever shuts down or
+ * decides to disconnect the client.
+ *
+ */
+void
+jack_shutdown (void *arg)
+{
+ JackCard* obj = (JackCard*) arg;
+
+ obj->jack_running = FALSE;
+ obj->jack_active = FALSE;
+ obj->read.port = NULL;
+ if (obj->read.open)
+ obj->read.init = TRUE;
+ obj->write.port = NULL;
+ if (obj->write.open)
+ obj->write.init = TRUE;
+}
+
+int samplerate(jack_nframes_t rate, void *arg)
+{
+ JackCard* obj = (JackCard*) arg;
+ int error;
+
+ obj->rate = rate;
+ if (obj->read.open) {
+ obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate;
+ obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
+ g_free(obj->read.data.data_in);
+ obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
+ if (obj->read.src_state)
+ if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0)
+ g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
+ }
+ if (obj->write.open) {
+ obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate;
+ obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
+ g_free(obj->write.data.data_out);
+ obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
+ if (obj->write.src_state)
+ if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0)
+ g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
+ }
+ return 0;
+}
+
+/*
+ * The process callback for this JACK application.
+ * It is called by JACK at the appropriate times.
+ * @nframes :
+ * @arg :
+ */
+int
+process (jack_nframes_t nframes, void *arg)
+{
+ JackCard* obj = (JackCard*) arg;
+ sample_t *out;
+ sample_t *in;
+
+ if (obj->clear && !obj->write.can_process) {
+ out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
+ memset (out, 0, nframes * sizeof(sample_t));
+ obj->clear = FALSE;
+ }
+
+ if (!obj->can_process)
+ return 0;
+
+ if(obj->read.can_process) {
+ in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes);
+ jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes);
+ }
+
+ if (obj->write.can_process) {
+ out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
+ memset (out, 0, nframes * sizeof(sample_t));
+ if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) {
+ obj->write.can_process = FALSE;
+ if (!obj->read.open)
+ obj->can_process = FALSE;
+ obj->clear = FALSE;
+ return 0;
+ }
+ jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes);
+ }
+ return 0;
+}
+
+int jack_init(JackCard* obj)
+{
+ char* client_name;
+ int error;
+
+ if (!obj->jack_running) {
+ obj->client = NULL;
+ client_name = g_strdup_printf("linphone-%u", g_random_int());
+ if ((obj->client = jack_client_new (client_name)) == NULL) {
+ g_warning("cannot create jack client");
+ g_free(client_name);
+ return -1;
+ }
+ g_message("Found Jack Daemon");
+ g_free(client_name);
+
+ /* tell the JACK server to call `process()' whenever
+ there is work to be done.
+ */
+ jack_set_process_callback (obj->client, process, obj);
+
+ /* tell the JACK server to call `jack_shutdown()' if
+ it ever shuts down, either entirely, or if it
+ just decides to stop calling us.
+ */
+ jack_on_shutdown (obj->client, jack_shutdown, obj);
+ jack_set_sample_rate_callback (obj->client, samplerate, obj);
+ obj->rate = jack_get_sample_rate (obj->client);
+ if (obj->rate == 0) {
+ g_warning ("rate is 0???");
+ if (jack_client_close(obj->client) != 0)
+ g_warning("could not close client");
+ return -1;
+ }
+ obj->buffer_size = jack_get_buffer_size(obj->client);
+ obj->jack_running = TRUE;
+ }
+
+ if (!obj->jack_active) {
+ if (jack_activate (obj->client)) {
+ g_warning("cannot activate jack client");
+ return -1;
+ } else obj->jack_active = TRUE;
+ }
+
+ if (obj->read.init) {
+ if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) {
+ g_warning("error while trying to register input port");
+ return -1;
+ }
+ if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
+ g_warning("Cannot find any physical capture ports\n");
+ jack_port_unregister(obj->client, obj->read.port);
+ obj->read.port = NULL;
+ return -1;
+ }
+ if (!jack_port_connected(obj->read.port))
+ if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) {
+ g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]);
+ if (error == EEXIST) g_warning("connection already made");
+ else {
+ jack_port_unregister(obj->client, obj->read.port);
+ obj->read.port = NULL;
+ return -1;
+ }
+ }
+ obj->read.init = FALSE;
+ }
+
+ if (obj->write.init) {
+ if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) {
+ g_warning("error while trying to register output port");
+ return -1;
+ }
+ if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
+ g_warning("Cannot find any physical playback ports\n");
+ jack_port_unregister(obj->client, obj->write.port);
+ obj->write.port = NULL;
+ return -1;
+ }
+ if (!jack_port_connected(obj->write.port)) {
+ if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) {
+ g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]);
+ if (error == EEXIST) g_warning("connection already made");
+ else {
+ jack_port_unregister(obj->client, obj->write.port);
+ obj->write.port = NULL;
+ return -1;
+ }
+ }
+ if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) {
+ g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]);
+ if (error == EEXIST) g_warning("connection already made");
+ else {
+ jack_port_unregister(obj->client, obj->write.port);
+ obj->write.port = NULL;
+ return -1;
+ }
+ }
+ }
+ obj->write.init = FALSE;
+ }
+ return 0;
+}
+
+int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate)
+{
+ int channels = stereo + 1, bsize, error;
+ obj->read.init = TRUE;
+ if (jack_init(obj) != 0) return -1;
+
+ obj->read.rate = rate;
+ obj->sample_size = bits / 8;
+ obj->frame_size = channels * obj->sample_size;
+ bsize = BSIZE;
+ obj->read.frames = bsize / 2;
+ SND_CARD(obj)->bsize = bsize;
+ SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
+ obj->read.channels = channels;
+ if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL)
+ g_warning("Error while initializing the samplerate converter: %s", src_strerror(error));
+ obj->read.data.src_ratio = (double)rate / (double)obj->rate;
+ obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
+ obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
+ obj->read.data.data_out = malloc(obj->read.frames*sizeof(float));
+ obj->read.data.end_of_input = 0;
+ if (!obj->read.buffer)
+ obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE);
+ obj->read.can_process = TRUE;
+ obj->can_process = TRUE;
+ obj->read.open = TRUE;
+ obj->read.init = FALSE;
+ return 0;
+}
+
+int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate)
+{
+ int channels = stereo + 1, bsize, err;
+ obj->write.init = TRUE;
+ if (jack_init(obj) != 0) return -1;
+
+ obj->write.rate = rate;
+ obj->sample_size = bits / 8;
+ obj->frame_size = channels * obj->sample_size;
+ bsize = BSIZE;
+ obj->write.frames = bsize / 2;
+ SND_CARD(obj)->bsize = bsize;
+ SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
+ obj->write.channels = channels;
+ if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL)
+ g_warning("Error while initializing the samplerate converter: %s", src_strerror(err));
+ obj->write.data.src_ratio = (double)obj->rate / (double)rate;
+ obj->write.data.data_in = malloc(obj->write.frames*sizeof(float));
+ obj->write.data.end_of_input = 0;
+ obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
+ obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
+ if (!obj->write.buffer)
+ obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE);
+ obj->write.can_process = TRUE;
+ obj->can_process = TRUE;
+ obj->write.open = TRUE;
+ obj->write.init = FALSE;
+ return 0;
+}
+
+void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno)
+{
+}
+
+void jack_card_close_r(JackCard *obj)
+{
+ obj->read.open = FALSE;
+ obj->read.init = FALSE;
+ obj->read.can_process = FALSE;
+ if (!obj->write.open)
+ obj->can_process = FALSE;
+ if (obj->read.src_state)
+ obj->read.src_state = src_delete (obj->read.src_state);
+ g_free(obj->read.data.data_in);
+ g_free(obj->read.data.data_out);
+}
+
+void jack_card_close_w(JackCard *obj)
+{
+ obj->write.open = FALSE;
+ obj->write.init = FALSE;
+ obj->clear = TRUE;
+ if (!obj->jack_running) {
+ obj->write.can_process = FALSE;
+ obj->can_process = FALSE;
+ }
+ if (obj->write.src_state)
+ obj->write.src_state = src_delete (obj->write.src_state);
+ g_free(obj->write.data.data_in);
+ g_free(obj->write.data.data_out);
+}
+
+int jack_card_probe(JackCard *obj,int bits,int stereo,int rate)
+{
+ if (obj->jack_running) return BSIZE;
+ else if (jack_init(obj) == 0) return BSIZE;
+ else return -1;
+}
+
+void jack_card_destroy(JackCard *obj)
+{
+ if (obj->jack_running) jack_client_close (obj->client);
+ snd_card_uninit(SND_CARD(obj));
+ if (obj->read.buffer) {
+ jack_ringbuffer_free(obj->read.buffer);
+ obj->read.buffer = NULL;
+ }
+ if (obj->write.buffer) {
+ jack_ringbuffer_free(obj->write.buffer);
+ obj->write.buffer = NULL;
+ }
+ if (obj->read.phys_ports) {
+ g_free(obj->read.phys_ports);
+ obj->read.phys_ports = NULL;
+ }
+ if (obj->write.phys_ports) {
+ g_free(obj->write.phys_ports);
+ obj->write.phys_ports = NULL;
+ }
+}
+
+gboolean jack_card_can_read(JackCard *obj)
+{
+ g_return_val_if_fail(obj->read.buffer!=NULL,0);
+ if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE;
+ else return FALSE;
+}
+
+int jack_card_read(JackCard *obj,char *buf,int size)
+{
+ size_t bytes, can_read, i;
+ int error;
+ float norm, value;
+
+ g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1);
+ if (jack_init(obj) != 0) return -1;
+ size /= 2;
+ can_read = MIN(size, obj->read.frames);
+ // can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer));
+ can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t);
+ obj->read.can_process = FALSE;
+ bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read);
+ obj->read.can_process = TRUE;
+ obj->read.data.input_frames = bytes / sizeof(sample_t);
+ can_read = MIN(size, obj->read.frames);
+ obj->read.data.output_frames = can_read;
+ if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0)
+ g_warning("error while samplerate conversion. error: %s", src_strerror(error));
+ norm = obj->read.level*obj->level*(float)0x8000;
+ for (i=0; i < obj->read.data.output_frames_gen; i++) {
+ value = obj->read.data.data_out[i]*norm;
+ if (value >= 32767.0)
+ ((short*)buf)[i] = 32767;
+ else if (value <= -32768.0)
+ ((short*)buf)[i] = -32768;
+ else
+ ((short*)buf)[i] = (short)value;
+ }
+ bytes = obj->read.data.output_frames_gen * 2;
+ return bytes;
+}
+
+int jack_card_write(JackCard *obj,char *buf,int size)
+{
+ size_t bytes, can_write, i;
+ int error;
+ float norm;
+
+ g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1);
+ if (jack_init(obj) != 0) return -1;
+ size /= 2;
+ can_write = MIN(size, obj->write.frames);
+ norm = obj->write.level*obj->level/(float)0x8000;
+ for (i=0; i<can_write; i++) {
+ obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm;
+ }
+ obj->write.data.input_frames = can_write;
+ if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0)
+ g_warning("error while samplerate conversion. error: %s", src_strerror(error));
+ obj->write.can_process = FALSE;
+ bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen);
+ obj->write.can_process = TRUE;
+ return bytes;
+}
+
+void jack_card_set_level(JackCard *obj,gint way,gint a)
+{
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ obj->level = (float)a / 100.0;
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ obj->read.level = (float)a / 100.0;
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ obj->write.level = (float)a / 100.0;
+ break;
+ default:
+ g_warning("jack_card_set_level: unsupported command.");
+ }
+}
+
+gint jack_card_get_level(JackCard *obj,gint way)
+{
+ gint value = 0;
+
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ value = (gint)(obj->level*100.0);
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ value = (gint)(obj->read.level*100.0);
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ value = (gint)(obj->write.level*100.0);
+ break;
+ default:
+ g_warning("jack_card_get_level: unsupported command.");
+ }
+ return value;
+}
+
+void jack_card_set_source(JackCard *obj,int source)
+{
+}
+
+MSFilter *jack_card_create_read_filter(JackCard *card)
+{
+ MSFilter *f=ms_oss_read_new();
+ ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
+ return f;
+}
+
+MSFilter *jack_card_create_write_filter(JackCard *card)
+{
+ MSFilter *f=ms_oss_write_new();
+ ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
+ return f;
+}
+SndCard * jack_card_new(jack_client_t *client)
+{
+ JackCard * obj;
+ SndCard *base;
+
+ obj= g_new0(JackCard,1);
+
+ if (!client) return NULL;
+ obj->client = client;
+ obj->jack_running = TRUE;
+ obj->jack_active = FALSE;
+ obj->can_process = FALSE;
+ obj->clear = TRUE;
+ obj->write.can_process = FALSE;
+ obj->write.open = FALSE;
+ obj->write.init = TRUE;
+ obj->write.port = NULL;
+ obj->write.phys_ports = NULL;
+ obj->write.buffer = NULL;
+ obj->read.can_process = FALSE;
+ obj->read.open = FALSE;
+ obj->read.init = TRUE;
+ obj->read.port = NULL;
+ obj->read.phys_ports = NULL;
+ obj->read.buffer = NULL;
+
+ /* tell the JACK server to call `process()' whenever
+ there is work to be done.
+ */
+ jack_set_process_callback (client, process, obj);
+
+ /* tell the JACK server to call `jack_shutdown()' if
+ it ever shuts down, either entirely, or if it
+ just decides to stop calling us.
+ */
+ jack_on_shutdown (client, jack_shutdown, obj);
+
+ jack_set_sample_rate_callback (client, samplerate, obj);
+
+ obj->rate = jack_get_sample_rate (client);
+ obj->buffer_size = jack_get_buffer_size(obj->client);
+
+ jack_init(obj);
+
+ base= SND_CARD(obj);
+ snd_card_init(base);
+
+#ifdef HAVE_GLIB
+ base->card_name=g_strdup_printf("JACK client");
+#else
+ base->card_name=malloc(100);
+ snprintf(base->card_name, 100, "JACK client");
+#endif
+
+ base->_probe=(SndCardOpenFunc)jack_card_probe;
+ base->_open_r=(SndCardOpenFunc)jack_card_open_r;
+ base->_open_w=(SndCardOpenFunc)jack_card_open_w;
+ base->_can_read=(SndCardPollFunc)jack_card_can_read;
+ base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode;
+ base->_read=(SndCardIOFunc)jack_card_read;
+ base->_write=(SndCardIOFunc)jack_card_write;
+ base->_close_r=(SndCardCloseFunc)jack_card_close_r;
+ base->_close_w=(SndCardCloseFunc)jack_card_close_w;
+ base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source;
+ base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level;
+ base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level;
+ base->_destroy=(SndCardDestroyFunc)jack_card_destroy;
+ base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter;
+ base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter;
+
+ obj->read.buffer=NULL;
+ obj->write.buffer=NULL;
+ obj->buffer_size = 0;
+ obj->level = 1.0;
+ obj->write.level = 1.0;
+ obj->read.level = 1.0;
+
+ return base;
+}
+
+
+gint jack_card_manager_init(SndCardManager *m, gint index)
+{
+ jack_client_t *client = NULL;
+ char* client_name;
+
+ client_name=g_strdup_printf("linphone-%u", g_random_int());
+ if ((client = jack_client_new (client_name))!= NULL)
+ {
+ g_message("Found Jack Daemon");
+ g_free(client_name);
+ m->cards[index]=jack_card_new(client);
+ m->cards[index]->index=index;
+ return 1;
+ } else {
+ g_free(client_name);
+ return 0;
+ }
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h
new file mode 100644
index 00000000..33ec46dc
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/jackcard.h
@@ -0,0 +1,81 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ JACK support
+ Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
+*/
+
+#ifndef JACK_CARD_H
+#define JACK_CARD_H
+
+#include <config.h>
+
+#ifdef __JACK_ENABLED__
+
+#include "sndcard.h"
+
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#include <samplerate.h>
+
+typedef jack_default_audio_sample_t sample_t;
+
+typedef struct {
+ jack_port_t *port;
+ const char **phys_ports;
+ float level;
+ jack_ringbuffer_t *buffer;
+ gint channels;
+ gint rate;
+ SRC_STATE* src_state;
+ SRC_DATA data;
+ size_t frames;
+ gboolean can_process;
+ gboolean open;
+ gboolean init;
+} jackcard_mode_t;
+
+struct _JackCard
+{
+ SndCard parent;
+
+ jack_client_t *client;
+ gboolean jack_running;
+ gboolean jack_active;
+ float level;
+ jack_nframes_t buffer_size;
+ gint sample_size;
+ gint frame_size;
+ gint rate;
+ gboolean can_process;
+ gboolean clear;
+
+ jackcard_mode_t read, write;
+};
+
+typedef struct _JackCard JackCard;
+
+SndCard * jack_card_new(jack_client_t *client);
+
+gint jack_card_manager_init(SndCardManager *m, gint index);
+
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h
new file mode 100644
index 00000000..3ccbab69
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mediastream.h
@@ -0,0 +1,130 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MEDIASTREAM_H
+#define MEDIASTREAM_H
+
+#include "msrtprecv.h"
+#include "msrtpsend.h"
+#include "ms.h"
+#include "msosswrite.h"
+#include "msossread.h"
+#include "msread.h"
+#include "mswrite.h"
+#include "mstimer.h"
+#include "mscodec.h"
+#ifdef HAVE_SPEEX
+#include "msspeexdec.h"
+#endif
+#include "msringplayer.h"
+
+
+struct _AudioStream
+{
+ MSSync *timer;
+ RtpSession *send_session;
+ RtpSession *recv_session;
+ MSFilter *soundread;
+ MSFilter *soundwrite;
+ MSFilter *encoder;
+ MSFilter *decoder;
+ MSFilter *rtprecv;
+ MSFilter *rtpsend;
+};
+
+
+typedef struct _AudioStream AudioStream;
+
+struct _RingStream
+{
+ MSSync *timer;
+ MSFilter *source;
+ MSFilter *sndwrite;
+};
+
+typedef struct _RingStream RingStream;
+
+/* start a thread that does sampling->encoding->rtp_sending|rtp_receiving->decoding->playing */
+AudioStream *audio_stream_start (RtpProfile * prof, int locport, char *remip,
+ int remport, int profile, int jitt_comp);
+
+AudioStream *audio_stream_start_with_sndcards(RtpProfile * prof, int locport, char *remip4,
+ int remport, int profile, int jitt_comp, SndCard *playcard, SndCard *captcard);
+
+AudioStream *audio_stream_start_with_files (RtpProfile * prof, int locport,
+ char *remip4, int remport,
+ int profile, int jitt_comp,
+ gchar * infile, gchar * outfile);
+void audio_stream_set_rtcp_information(AudioStream *st, const char *cname);
+
+
+/* stop the above process*/
+void audio_stream_stop (AudioStream * stream);
+
+RingStream *ring_start (gchar * file, gint interval, SndCard *sndcard);
+RingStream *ring_start_with_cb(gchar * file, gint interval, SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data);
+void ring_stop (RingStream * stream);
+
+/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
+gint test_audio_dev (int dev_id);
+
+/* send a dtmf */
+gint audio_stream_send_dtmf (AudioStream * stream, gchar dtmf);
+
+void audio_stream_set_default_card(int cardindex);
+
+
+#ifdef VIDEO_ENABLED
+
+/*****************
+ Video Support
+ *****************/
+
+
+
+struct _VideoStream
+{
+ MSSync *timer;
+ RtpSession *send_session;
+ RtpSession *recv_session;
+ MSFilter *source;
+ MSFilter *output;
+ MSFilter *encoder;
+ MSFilter *decoder;
+ MSFilter *rtprecv;
+ MSFilter *rtpsend;
+ gboolean show_local;
+};
+
+
+typedef struct _VideoStream VideoStream;
+
+VideoStream *video_stream_start(RtpProfile *profile, int locport, char *remip4, int remport,
+ int payload, int jitt_comp, gboolean show_local, const gchar *source, const gchar *device);
+void video_stream_set_rtcp_information(VideoStream *st, const char *cname);
+void video_stream_stop (VideoStream * stream);
+
+VideoStream * video_preview_start(const gchar *source, const gchar *device);
+void video_preview_stop(VideoStream *stream);
+
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c
new file mode 100644
index 00000000..cfcafa33
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.c
@@ -0,0 +1,342 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ms.h"
+#include "sndcard.h"
+#include "mscodec.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef VIDEO_ENABLED
+extern void ms_video_source_register_all();
+#endif
+#ifdef HAVE_ILBC
+extern void ms_ilbc_codec_init();
+#endif
+
+/**
+ * ms_init:
+ *
+ *
+ * Initialize the mediastreamer. This must be the first function called in a program
+ * using the mediastreamer library.
+ *
+ *
+ */
+void ms_init()
+{
+ if (!g_thread_supported()) g_thread_init (NULL);
+#ifdef HAVE_GLIB
+ if (!g_module_supported()){
+ g_error("GModule is not supported.");
+ }
+#endif
+ /* initialize the oss subsystem */
+ snd_card_manager_init(snd_card_manager);
+ /* register the statically linked codecs */
+ ms_codec_register_all();
+#ifdef VIDEO_ENABLED
+ ms_video_source_register_all();
+#endif
+#ifdef HAVE_ILBC
+ ms_ilbc_codec_init();
+#endif
+}
+
+
+static gint compare(gconstpointer a, gconstpointer b)
+{
+ MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b;
+ if (f1->klass<f2->klass) return -1;
+ if (f1->klass==f2->klass) return 0;
+ /* if f1->klass>f2->klass ....*/
+ return 1;
+}
+
+static GList *g_list_append_if_new(GList *l,gpointer data)
+{
+ GList *res=l;
+ if (g_list_find(res,data)==NULL)
+ res=g_list_append(res,data);
+ return(res);
+}
+
+static GList *get_nexts(MSFilter *f,GList *l)
+{
+ int i;
+ MSFifo *fifo;
+ MSQueue *q;
+ GList *res=l;
+
+ /* check fifos*/
+ for (i=0;i <f->klass->max_foutputs;i++)
+ {
+ fifo=f->outfifos[i];
+ if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data);
+ }
+ /* check queues*/
+ for (i=0;i <f->klass->max_qoutputs;i++)
+ {
+ q=f->outqueues[i];
+ if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data);
+ }
+ return(res);
+}
+
+/* compile graphs attached to a sync source*/
+int ms_compile(MSSync *sync)
+{
+ int i;
+ GList *list1=NULL,*list2=NULL,*elem;
+ GList *proc_chain=NULL;
+ MSFilter *f;
+
+ /* first free the old list if we are just updating*/
+ if (sync->execution_list!=NULL) g_list_free(sync->execution_list);
+ /* get the list of filters attached to this sync*/
+ for (i=0;i<sync->filters;i++)
+ {
+ /* //printf("found filter !\n"); */
+ list1=g_list_append(list1,sync->attached_filters[i]);
+ }
+ /* find the processing chain */
+ while (list1!=NULL)
+ {
+ list2=NULL;
+ /* sort the list by types of filter*/
+ list1=g_list_sort(list1,compare);
+ /* save into the processing chain list*/
+ /* //printf("list1 :%i elements\n",g_list_length(list1)); */
+ proc_chain=g_list_concat(proc_chain,list1);
+ /* get all following filters. They are appended to list2*/
+ elem=list1;
+ while (elem!=NULL)
+ {
+ f=(MSFilter*)(elem->data);
+ /* check if filter 's status */
+ if (f->klass->attributes & FILTER_CAN_SYNC)
+ {
+ sync->samples_per_tick=0;
+ }
+ list2=get_nexts(f,list2);
+ elem=g_list_next(elem);
+ }
+ list1=list2;
+ }
+ sync->execution_list=proc_chain;
+ sync->flags&=~MS_SYNC_NEED_UPDATE;
+ ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list));
+ return 0;
+}
+
+/*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/
+void *ms_thread_run(void *sync_ptr)
+{
+ MSSync *sync=(MSSync*) sync_ptr;
+ GList *filter;
+ MSFilter *f;
+
+
+ ms_sync_lock(sync);
+ while(sync->run)
+ {
+ /* //g_message("sync->run=%i",sync->run); */
+ if (sync->samples_per_tick==0) ms_sync_suspend(sync);
+ if (sync->flags & MS_SYNC_NEED_UPDATE){
+ ms_compile(sync);
+ ms_sync_setup(sync);
+ }
+ filter=sync->execution_list;
+ ms_sync_unlock(sync);
+ /* //ms_trace("Calling synchronisation"); */
+ ms_sync_synchronize(sync);
+ while(filter!=NULL)
+ {
+ f=(MSFilter*)filter->data;
+ if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE)
+ {
+ /* execute it once */
+ ms_trace("Running source filter %s.",f->klass->name);
+ ms_filter_process(f);
+ }
+ else
+ {
+ /* make the filter process its input data until it has no more */
+ while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) )
+ {
+ ms_trace("Running filter %s.",f->klass->name);
+ ms_filter_process(f);
+ }
+ }
+ filter=g_list_next(filter);
+ }
+ ms_sync_lock(sync);
+ }
+ g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */
+ ms_sync_unlock(sync);
+ g_message("Mediastreamer processing thread is exiting.");
+ return NULL;
+}
+
+/* stop the processing chain attached to a sync source.*/
+void ms_thread_stop(MSSync *sync)
+{
+ if (sync->thread!=NULL)
+ {
+ if (sync->samples_per_tick==0)
+ {
+ /* to wakeup the thread */
+ /* //g_cond_signal(sync->thread_cond); */
+ }
+ g_mutex_lock(sync->lock);
+ sync->run=0;
+ sync->thread=NULL;
+ g_cond_wait(sync->stop_cond,sync->lock);
+ g_mutex_unlock(sync->lock);
+ }
+ /* //g_message("ms_thread_stop() finished."); */
+}
+
+/**
+ * ms_start:
+ * @sync: A synchronisation source to be started.
+ *
+ * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
+ *
+ *
+ */
+void ms_start(MSSync *sync)
+{
+ if (sync->run==1) return; /*already running*/
+ ms_compile(sync);
+ ms_sync_setup(sync);
+ /* this is to avoid race conditions, for example:
+ ms_start(sync);
+ ms_oss_write_start(ossw);
+ here tge ossw filter need to be compiled to run ms_oss_write_start()
+ */
+ ms_trace("ms_start: creating new thread.");
+ sync->run=1;
+ sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL);
+ if (sync->thread==NULL){
+ g_warning("Could not create thread !");
+ }
+}
+
+/**
+ * ms_stop:
+ * @sync: A synchronisation source to be stopped.
+ *
+ * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
+ * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
+ *
+ *
+ */
+void ms_stop(MSSync *sync)
+{
+ ms_thread_stop(sync);
+ ms_sync_unsetup(sync);
+}
+
+
+gint ms_load_plugin(gchar *path)
+{
+#ifdef HAVE_GLIB
+ g_module_open(path,0);
+#endif
+ return 0;
+}
+
+gchar * ms_proc_get_param(gchar *parameter)
+{
+ gchar *file;
+ int fd;
+ int err,len;
+ gchar *p,*begin,*end;
+ gchar *ret;
+ fd=open("/proc/cpuinfo",O_RDONLY);
+ if (fd<0){
+ g_warning("Could not open /proc/cpuinfo.");
+ return NULL;
+ }
+ file=g_malloc(1024);
+ err=read(fd,file,1024);
+ file[err-1]='\0';
+ /* find the parameter */
+ p=strstr(file,parameter);
+ if (p==NULL){
+ /* parameter not found */
+ g_free(file);
+ return NULL;
+ }
+ /* find the following ':' */
+ p=strchr(p,':');
+ if (p==NULL){
+ g_free(file);
+ return NULL;
+ }
+ /* find the value*/
+ begin=p+2;
+ end=strchr(begin,'\n');
+ if (end==NULL) end=strchr(begin,'\0');
+ len=end-begin+1;
+ ret=g_malloc(len+1);
+ snprintf(ret,len,"%s",begin);
+ /* //printf("%s=%s\n",parameter,ret); */
+ g_free(file);
+ return ret;
+}
+
+gint ms_proc_get_type()
+{
+ static int proc_type=0;
+ gchar *value;
+ if (proc_type==0){
+ value=ms_proc_get_param("cpu family");
+ if (value!=NULL) {
+ proc_type=atoi(value);
+ g_free(value);
+ }else return -1;
+ }
+ return proc_type;
+}
+
+gint ms_proc_get_speed()
+{
+ char *value;
+ static int proc_speed=0;
+ if (proc_speed==0){
+ value=ms_proc_get_param("cpu MHz");
+ if (value!=NULL){
+ proc_speed=atoi(value);
+ g_free(value);
+ }else return -1;
+ }
+ /* //printf("proc_speed=%i\n",proc_speed); */
+ return proc_speed;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h
new file mode 100644
index 00000000..51c69b96
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/ms.h
@@ -0,0 +1,81 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#ifndef MS_H
+#define MS_H
+#include "msfilter.h"
+#include "mssync.h"
+
+
+void ms_init();
+
+/* compile graphs attached to a sync source*/
+int ms_compile(MSSync *source);
+
+
+/* stop the processing chain attached to a sync source.*/
+void ms_thread_stop(MSSync *sync);
+
+
+/**
+ * function_name:ms_thread_run
+ * @sync: The synchronization source for all the set of graphs to run.
+ *
+ * Execute the processing chain attached to a sync source. This function loops indefinitely.
+ * The media streamer programmer can choose to execute this function directly, or to call ms_start(),
+ * that will start a thread for the synchronisation source.
+ *
+ * Returns: no return value.
+ */
+void *ms_thread_run(void *sync);
+
+
+/**
+ * function_name:ms_start
+ * @sync: A synchronisation source to be started.
+ *
+ * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
+ *
+ * Returns: no return value.
+ */
+void ms_start(MSSync *sync);
+
+
+/**
+ * function_name:ms_stop
+ * @sync: A synchronisation source to be stopped.
+ *
+ * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
+ * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
+ *
+ * Returns: no return value.
+ */
+void ms_stop(MSSync *sync);
+
+
+gchar * ms_proc_get_param(gchar *parameter);
+gint ms_proc_get_type();
+gint ms_proc_get_speed();
+
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c
new file mode 100644
index 00000000..70cc906e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.c
@@ -0,0 +1,132 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <msAlawdec.h>
+#include <g711common.h>
+
+extern MSFilter * ms_ALAWencoder_new(void);
+
+MSCodecInfo ALAWinfo={
+ {
+ "ALAW codec",
+ 0,
+ MS_FILTER_AUDIO_CODEC,
+ ms_ALAWencoder_new,
+ "This is the classic A-law codec. Good quality, but only usable with high speed network connections."
+ },
+ ms_ALAWencoder_new,
+ ms_ALAWdecoder_new,
+ 320,
+ 160,
+ 64000,
+ 8000,
+ 8,
+ "PCMA",
+ 1,
+ 1,
+};
+
+static MSALAWDecoderClass *ms_ALAWdecoder_class=NULL;
+
+MSFilter * ms_ALAWdecoder_new(void)
+{
+ MSALAWDecoder *r;
+
+ r=g_new(MSALAWDecoder,1);
+ ms_ALAWdecoder_init(r);
+ if (ms_ALAWdecoder_class==NULL)
+ {
+ ms_ALAWdecoder_class=g_new(MSALAWDecoderClass,1);
+ ms_ALAWdecoder_class_init(ms_ALAWdecoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWdecoder_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_ALAWdecoder_init(MSALAWDecoder *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->r_mingran=ALAW_DECODER_RMAXGRAN;
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
+
+}
+
+void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWDecoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
+ MS_FILTER_CLASS(klass)->max_finputs=MSALAWDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSALAWDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=ALAW_DECODER_RMAXGRAN;
+ MS_FILTER_CLASS(klass)->w_maxgran=ALAW_DECODER_WMAXGRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWdecoder_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWdecoder_process;
+}
+
+void ms_ALAWdecoder_process(MSALAWDecoder *r)
+{
+ MSFifo *fi,*fo;
+ int inlen,outlen;
+ gchar *s,*d;
+ int i;
+ /* process output fifos, but there is only one for this class of filter*/
+
+ /* this is the simplest process function design:
+ the filter declares a r_mingran of ALAW_DECODER_RMAXGRAN, so the mediastreamer's
+ scheduler will call the process function each time there is ALAW_DECODER_RMAXGRAN
+ bytes to read in the input fifo. If there is more, then it will call it several
+ time in order to the fifo to be completetly processed.
+ This is very simple, but not very efficient because of the multiple call function
+ of MSFilterProcessFunc that may happen.
+ The MSAlawEncoder implements another design; see it.
+ */
+
+ fi=r->f_inputs[0];
+ fo=r->f_outputs[0];
+ g_return_if_fail(fi!=NULL);
+ g_return_if_fail(fo!=NULL);
+
+ inlen=ms_fifo_get_read_ptr(fi,ALAW_DECODER_RMAXGRAN,(void**)&s);
+ if (s==NULL) return;
+ outlen=ms_fifo_get_write_ptr(fo,ALAW_DECODER_WMAXGRAN,(void**)&d);
+ if (d!=NULL)
+ {
+ for(i=0;i<ALAW_DECODER_RMAXGRAN;i++)
+ {
+ ((gint16*)d)[i]=alaw_to_s16( (unsigned char) s[i]);
+ }
+ }
+ else g_warning("MSALAWDecoder: Discarding samples !!");
+
+}
+
+
+
+void ms_ALAWdecoder_destroy( MSALAWDecoder *obj)
+{
+ g_free(obj);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h
new file mode 100644
index 00000000..7db4c750
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawdec.h
@@ -0,0 +1,65 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSALAWDECODER_H
+#define MSALAWDECODER_H
+
+#include <msfilter.h>
+#include <mscodec.h>
+
+/*this is the class that implements a ALAWdecoder filter*/
+
+#define MSALAWDECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSALAWDecoder
+{
+ /* the MSALAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWDecoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSALAWDECODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSALAWDECODER_MAX_INPUTS];
+} MSALAWDecoder;
+
+typedef struct _MSALAWDecoderClass
+{
+ /* the MSALAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWDecoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSALAWDecoderClass;
+
+/* PUBLIC */
+#define MS_ALAWDECODER(filter) ((MSALAWDecoder*)(filter))
+#define MS_ALAWDECODER_CLASS(klass) ((MSALAWDecoderClass*)(klass))
+MSFilter * ms_ALAWdecoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_ALAWdecoder_init(MSALAWDecoder *r);
+void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass);
+void ms_ALAWdecoder_destroy( MSALAWDecoder *obj);
+void ms_ALAWdecoder_process(MSALAWDecoder *r);
+
+/* tuning parameters :*/
+#define ALAW_DECODER_WMAXGRAN 320
+#define ALAW_DECODER_RMAXGRAN 160
+
+extern MSCodecInfo ALAWinfo;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c
new file mode 100644
index 00000000..fd1f9abe
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.c
@@ -0,0 +1,124 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msAlawenc.h"
+#include "g711common.h"
+
+extern MSCodecInfo ALAWinfo;
+
+static MSALAWEncoderClass *ms_ALAWencoder_class=NULL;
+
+MSFilter * ms_ALAWencoder_new(void)
+{
+ MSALAWEncoder *r;
+
+ r=g_new(MSALAWEncoder,1);
+ ms_ALAWencoder_init(r);
+ if (ms_ALAWencoder_class==NULL)
+ {
+ ms_ALAWencoder_class=g_new(MSALAWEncoderClass,1);
+ ms_ALAWencoder_class_init(ms_ALAWencoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWencoder_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_ALAWencoder_init(MSALAWEncoder *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->r_mingran=ALAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
+ something to process */
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
+
+}
+
+void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWEncoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
+ MS_FILTER_CLASS(klass)->max_finputs=MSALAWENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSALAWENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=ALAW_ENCODER_RMAXGRAN;
+ MS_FILTER_CLASS(klass)->w_maxgran=ALAW_ENCODER_WMAXGRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWencoder_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWencoder_process;
+}
+
+void ms_ALAWencoder_process(MSALAWEncoder *r)
+{
+ MSFifo *fi,*fo;
+ int inlen,outlen;
+ gchar *s,*d;
+ int i;
+ /* process output fifos, but there is only one for this class of filter*/
+
+ /* this is the sophisticated design of the process function:
+ Here the filter declares that it can be called as soon as there is something
+ to read on the input fifo by setting r_mingran=0.
+ Then it ask for the fifo to get as many data as possible by calling:
+ inlen=ms_fifo_get_read_ptr(fi,0,(void**)&s);
+ This avoid multiple call to the process function to process all data available
+ on the input fifo... but the writing of the process function is a bit
+ more difficult, because althoug ms_fifo_get_read_ptr() returns N bytes,
+ we cannot ask ms_fifo_get_write_ptr to return N bytes if
+ N>MS_FILTER_CLASS(klass)->w_maxgran. This is forbidden by the MSFifo
+ mechanism.
+ This is an open issue.
+ For the moment what is done here is that ms_fifo_get_write_ptr() is called
+ several time with its maximum granularity in order to try to write the output.
+ ...
+ One solution:
+ -create a new function ms_fifo_get_rw_ptr(fifo1,p1, fifo2,p2) to
+ return the number of bytes able to being processed according to the input
+ and output fifo, and their respective data pointers
+ */
+
+
+ fi=r->f_inputs[0];
+ fo=r->f_outputs[0];
+
+ inlen=ms_fifo_get_read_ptr(fi,ALAW_ENCODER_RMAXGRAN,(void**)&s);
+ if (s==NULL) return;
+ outlen=ms_fifo_get_write_ptr(fo,ALAW_ENCODER_WMAXGRAN,(void**)&d);
+ if (d!=NULL)
+ {
+ for(i=0;i<ALAW_ENCODER_WMAXGRAN;i++)
+ {
+ d[i]=s16_to_alaw( *((gint16*)s) );
+ s+=2;
+ }
+ }
+ else g_warning("MSALAWDecoder: Discarding samples !!");
+
+}
+
+
+
+void ms_ALAWencoder_destroy( MSALAWEncoder *obj)
+{
+ g_free(obj);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h
new file mode 100644
index 00000000..608a9884
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msAlawenc.h
@@ -0,0 +1,64 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSALAWENCODER_H
+#define MSALAWENCODER_H
+
+#include "mscodec.h"
+
+
+/*this is the class that implements a ALAWencoder filter*/
+
+#define MSALAWENCODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSALAWEncoder
+{
+ /* the MSALAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWEncoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSALAWENCODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSALAWENCODER_MAX_INPUTS];
+} MSALAWEncoder;
+
+typedef struct _MSALAWEncoderClass
+{
+ /* the MSALAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWEncoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSALAWEncoderClass;
+
+/* PUBLIC */
+#define MS_ALAWENCODER(filter) ((MSALAWEncoder*)(filter))
+#define MS_ALAWENCODER_CLASS(klass) ((MSALAWEncoderClass*)(klass))
+MSFilter * ms_ALAWencoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_ALAWencoder_init(MSALAWEncoder *r);
+void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass);
+void ms_ALAWencoder_destroy( MSALAWEncoder *obj);
+void ms_ALAWencoder_process(MSALAWEncoder *r);
+
+/* tuning parameters :*/
+#define ALAW_ENCODER_WMAXGRAN 160
+#define ALAW_ENCODER_RMAXGRAN 320
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h
new file mode 100644
index 00000000..e73fb332
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMdecoder.h
@@ -0,0 +1,64 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSGSMDECODER_H
+#define MSGSMDECODER_H
+
+#include <msfilter.h>
+#include <mscodec.h>
+#include <gsm.h>
+
+/*this is the class that implements a GSMdecoder filter*/
+
+#define MSGSMDECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSGSMDecoder
+{
+ /* the MSGSMDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMDecoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSGSMDECODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSGSMDECODER_MAX_INPUTS];
+ gsm gsm_handle;
+} MSGSMDecoder;
+
+typedef struct _MSGSMDecoderClass
+{
+ /* the MSGSMDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMDecoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSGSMDecoderClass;
+
+/* PUBLIC */
+#define MS_GSMDECODER(filter) ((MSGSMDecoder*)(filter))
+#define MS_GSMDECODER_CLASS(klass) ((MSGSMDecoderClass*)(klass))
+MSFilter * ms_GSMdecoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_GSMdecoder_init(MSGSMDecoder *r);
+void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass);
+void ms_GSMdecoder_destroy( MSGSMDecoder *obj);
+void ms_GSMdecoder_process(MSGSMDecoder *r);
+
+extern MSCodecInfo GSMinfo;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h
new file mode 100644
index 00000000..2deae387
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msGSMencoder.h
@@ -0,0 +1,61 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSGSMENCODER_H
+#define MSGSMENCODER_H
+
+#include "msfilter.h"
+#include <gsm.h>
+
+/*this is the class that implements a GSMencoder filter*/
+
+#define MSGSMENCODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSGSMEncoder
+{
+ /* the MSGSMEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMEncoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSGSMENCODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSGSMENCODER_MAX_INPUTS];
+ gsm gsm_handle;
+} MSGSMEncoder;
+
+typedef struct _MSGSMEncoderClass
+{
+ /* the MSGSMEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMEncoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSGSMEncoderClass;
+
+/* PUBLIC */
+#define MS_GSMENCODER(filter) ((MSGSMEncoder*)(filter))
+#define MS_GSMENCODER_CLASS(klass) ((MSGSMEncoderClass*)(klass))
+MSFilter * ms_GSMencoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_GSMencoder_init(MSGSMEncoder *r);
+void ms_GSMencoder_class_init(MSGSMEncoderClass *klass);
+void ms_GSMencoder_destroy( MSGSMEncoder *obj);
+void ms_GSMencoder_process(MSGSMEncoder *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h
new file mode 100644
index 00000000..59d9deca
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10decoder.h
@@ -0,0 +1,64 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSLPC10DECODER_H
+#define MSLPC10DECODER_H
+
+#include <msfilter.h>
+#include <mscodec.h>
+#include <lpc10.h>
+
+/*this is the class that implements a LPC10decoder filter*/
+
+#define MSLPC10DECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSLPC10Decoder
+{
+ /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Decoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSLPC10DECODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSLPC10DECODER_MAX_INPUTS];
+ struct lpc10_decoder_state *lpc10_dec;
+} MSLPC10Decoder;
+
+typedef struct _MSLPC10DecoderClass
+{
+ /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Decoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSLPC10DecoderClass;
+
+/* PUBLIC */
+#define MS_LPC10DECODER(filter) ((MSLPC10Decoder*)(filter))
+#define MS_LPC10DECODER_CLASS(klass) ((MSLPC10DecoderClass*)(klass))
+MSFilter * ms_LPC10decoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_LPC10decoder_init(MSLPC10Decoder *r);
+void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass);
+void ms_LPC10decoder_destroy( MSLPC10Decoder *obj);
+void ms_LPC10decoder_process(MSLPC10Decoder *r);
+
+extern MSCodecInfo LPC10info;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h
new file mode 100644
index 00000000..4db16436
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msLPC10encoder.h
@@ -0,0 +1,74 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSLPC10ENCODER_H
+#define MSLPC10ENCODER_H
+
+#include "mscodec.h"
+
+
+int
+read_16bit_samples(gint16 int16samples[], float speech[], int n);
+
+int
+write_16bit_samples(gint16 int16samples[], float speech[], int n);
+
+void
+write_bits(unsigned char *data, gint32 *bits, int len);
+
+int
+read_bits(unsigned char *data, gint32 *bits, int len);
+
+
+/*this is the class that implements a LPC10encoder filter*/
+
+#define MSLPC10ENCODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSLPC10Encoder
+{
+ /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Encoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSLPC10ENCODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSLPC10ENCODER_MAX_INPUTS];
+ struct lpc10_encoder_state *lpc10_enc;
+} MSLPC10Encoder;
+
+typedef struct _MSLPC10EncoderClass
+{
+ /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Encoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSLPC10EncoderClass;
+
+/* PUBLIC */
+#define MS_LPC10ENCODER(filter) ((MSLPC10Encoder*)(filter))
+#define MS_LPC10ENCODER_CLASS(klass) ((MSLPC10EncoderClass*)(klass))
+MSFilter * ms_LPC10encoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_LPC10encoder_init(MSLPC10Encoder *r);
+void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass);
+void ms_LPC10encoder_destroy( MSLPC10Encoder *obj);
+void ms_LPC10encoder_process(MSLPC10Encoder *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c
new file mode 100644
index 00000000..500f2389
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.c
@@ -0,0 +1,130 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <msMUlawdec.h>
+#include <g711common.h>
+
+extern MSFilter * ms_MULAWencoder_new(void);
+
+MSCodecInfo MULAWinfo={
+ {
+ "MULAW codec",
+ 0,
+ MS_FILTER_AUDIO_CODEC,
+ ms_MULAWencoder_new,
+ "This is the classic Mu-law codec. Good quality, but only usable with high speed network connections."
+ },
+ ms_MULAWencoder_new,
+ ms_MULAWdecoder_new,
+ 320,
+ 160,
+ 64000,
+ 8000,
+ 0,
+ "PCMU",
+ 1,
+ 1
+};
+
+static MSMULAWDecoderClass *ms_MULAWdecoder_class=NULL;
+
+MSFilter * ms_MULAWdecoder_new(void)
+{
+ MSMULAWDecoder *r;
+
+ r=g_new(MSMULAWDecoder,1);
+ ms_MULAWdecoder_init(r);
+ if (ms_MULAWdecoder_class==NULL)
+ {
+ ms_MULAWdecoder_class=g_new(MSMULAWDecoderClass,1);
+ ms_MULAWdecoder_class_init(ms_MULAWdecoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWdecoder_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_MULAWdecoder_init(MSMULAWDecoder *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->r_mingran=MULAW_DECODER_RMAXGRAN;
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
+
+}
+
+void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWDecoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
+ MS_FILTER_CLASS(klass)->max_finputs=MSMULAWDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=MULAW_DECODER_RMAXGRAN;
+ MS_FILTER_CLASS(klass)->w_maxgran=MULAW_DECODER_WMAXGRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWdecoder_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWdecoder_process;
+}
+
+void ms_MULAWdecoder_process(MSMULAWDecoder *r)
+{
+ MSFifo *fi,*fo;
+ int inlen,outlen;
+ gchar *s,*d;
+ int i;
+ /* process output fifos, but there is only one for this class of filter*/
+
+ /* this is the simplest process function design:
+ the filter declares a r_mingran of MULAW_DECODER_RMAXGRAN, so the mediastreamer's
+ scheduler will call the process function each time there is MULAW_DECODER_RMAXGRAN
+ bytes to read in the input fifo. If there is more, then it will call it several
+ time in order to the fifo to be completetly processed.
+ This is very simple, but not very efficient because of the multiple call function
+ of MSFilterProcessFunc that may happen.
+ The MSAlawEncoder implements another design; see it.
+ */
+
+ fi=r->f_inputs[0];
+ fo=r->f_outputs[0];
+
+ inlen=ms_fifo_get_read_ptr(fi,MULAW_DECODER_RMAXGRAN,(void**)&s);
+ if (s==NULL) g_error("ms_MULAWdecoder_process: internal error.");
+ outlen=ms_fifo_get_write_ptr(fo,MULAW_DECODER_WMAXGRAN,(void**)&d);
+ if (d!=NULL)
+ {
+ for(i=0;i<MULAW_DECODER_RMAXGRAN;i++)
+ {
+ *((gint16*)d)=ulaw_to_s16( (unsigned char) s[i]);
+ d+=2;
+ }
+ }
+ else g_warning("MSMULAWDecoder: Discarding samples !!");
+}
+
+
+
+void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj)
+{
+ g_free(obj);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h
new file mode 100644
index 00000000..c135d21d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawdec.h
@@ -0,0 +1,66 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSMULAWDECODER_H
+#define MSMULAWDECODER_H
+
+#include <msfilter.h>
+#include <mscodec.h>
+
+/*this is the class that implements a MULAWdecoder filter*/
+
+#define MSMULAWDECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSMULAWDecoder
+{
+ /* the MSMULAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWDecoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSMULAWDECODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSMULAWDECODER_MAX_INPUTS];
+} MSMULAWDecoder;
+
+typedef struct _MSMULAWDecoderClass
+{
+ /* the MSMULAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWDecoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSMULAWDecoderClass;
+
+/* PUBLIC */
+#define MS_MULAWDECODER(filter) ((MSMULAWDecoder*)(filter))
+#define MS_MULAWDECODER_CLASS(klass) ((MSMULAWDecoderClass*)(klass))
+MSFilter * ms_MULAWdecoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_MULAWdecoder_init(MSMULAWDecoder *r);
+void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass);
+void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj);
+void ms_MULAWdecoder_process(MSMULAWDecoder *r);
+
+/* tuning parameters :*/
+#define MULAW_DECODER_WMAXGRAN 320
+#define MULAW_DECODER_RMAXGRAN 160
+
+extern MSCodecInfo MULAWinfo;
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c
new file mode 100644
index 00000000..2f740d89
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.c
@@ -0,0 +1,99 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msMUlawenc.h"
+#include "g711common.h"
+
+extern MSCodecInfo MULAWinfo;
+
+static MSMULAWEncoderClass *ms_MULAWencoder_class=NULL;
+
+MSFilter * ms_MULAWencoder_new(void)
+{
+ MSMULAWEncoder *r;
+
+ r=g_new(MSMULAWEncoder,1);
+ ms_MULAWencoder_init(r);
+ if (ms_MULAWencoder_class==NULL)
+ {
+ ms_MULAWencoder_class=g_new(MSMULAWEncoderClass,1);
+ ms_MULAWencoder_class_init(ms_MULAWencoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWencoder_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_MULAWencoder_init(MSMULAWEncoder *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->r_mingran=MULAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
+ something to process */
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
+
+}
+
+void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWEncoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
+ MS_FILTER_CLASS(klass)->max_finputs=MSMULAWENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=MULAW_ENCODER_RMAXGRAN;
+ MS_FILTER_CLASS(klass)->w_maxgran=MULAW_ENCODER_WMAXGRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWencoder_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWencoder_process;
+}
+
+void ms_MULAWencoder_process(MSMULAWEncoder *r)
+{
+ MSFifo *fi,*fo;
+ int inlen,outlen;
+ gchar *s,*d;
+ int i;
+ /* process output fifos, but there is only one for this class of filter*/
+
+ fi=r->f_inputs[0];
+ fo=r->f_outputs[0];
+ inlen=ms_fifo_get_read_ptr(fi,MULAW_ENCODER_RMAXGRAN,(void**)&s);
+ outlen=ms_fifo_get_write_ptr(fo,MULAW_ENCODER_WMAXGRAN,(void**)&d);
+ if (d!=NULL)
+ {
+ for(i=0;i<MULAW_ENCODER_WMAXGRAN;i++)
+ {
+ d[i]=s16_to_ulaw( *((gint16*)s) );
+ s+=2;
+ }
+ }
+ else g_warning("MSMULAWDecoder: Discarding samples !!");
+}
+
+
+
+void ms_MULAWencoder_destroy( MSMULAWEncoder *obj)
+{
+ g_free(obj);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h
new file mode 100644
index 00000000..52f76661
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msMUlawenc.h
@@ -0,0 +1,63 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSMULAWENCODER_H
+#define MSMULAWENCODER_H
+
+#include "mscodec.h"
+
+
+/*this is the class that implements a MULAWencoder filter*/
+
+#define MSMULAWENCODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSMULAWEncoder
+{
+ /* the MSMULAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWEncoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSMULAWENCODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSMULAWENCODER_MAX_INPUTS];
+} MSMULAWEncoder;
+
+typedef struct _MSMULAWEncoderClass
+{
+ /* the MSMULAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWEncoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSMULAWEncoderClass;
+
+/* PUBLIC */
+#define MS_MULAWENCODER(filter) ((MSMULAWEncoder*)(filter))
+#define MS_MULAWENCODER_CLASS(klass) ((MSMULAWEncoderClass*)(klass))
+MSFilter * ms_MULAWencoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_MULAWencoder_init(MSMULAWEncoder *r);
+void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass);
+void ms_MULAWencoder_destroy( MSMULAWEncoder *obj);
+void ms_MULAWencoder_process(MSMULAWEncoder *r);
+
+/* tuning parameters :*/
+#define MULAW_ENCODER_WMAXGRAN 160
+#define MULAW_ENCODER_RMAXGRAN 320
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h
new file mode 100644
index 00000000..e7c880be
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavdecoder.h
@@ -0,0 +1,87 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSAVDECODER_H
+#define MSAVDECODER_H
+
+#include "msfilter.h"
+
+
+#include <avcodec.h>
+
+/*this is the class that implements a AVdecoder filter*/
+
+#define MSAVDECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+struct _MSAVDecoder
+{
+ /* the MSAVDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVDecoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSQueue *q_inputs[MSAVDECODER_MAX_INPUTS];
+ MSQueue *q_outputs[MSAVDECODER_MAX_INPUTS];
+ AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */
+ AVCodecContext av_context; /* the context of the AVCodec */
+ gint av_opened;
+ int output_pix_fmt;
+ int width;
+ int height;
+ int skip_gob;
+ unsigned char buf_compressed[100000];
+ int buf_size;
+ MSBuffer *obufwrap; /* alternate buffer, when format change is needed*/
+};
+
+typedef struct _MSAVDecoder MSAVDecoder;
+
+struct _MSAVDecoderClass
+{
+ /* the MSAVDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVDecoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSAVDecoderClass MSAVDecoderClass;
+
+/* PUBLIC */
+#define MS_AVDECODER(filter) ((MSAVDecoder*)(filter))
+#define MS_AVDECODER_CLASS(klass) ((MSAVDecoderClass*)(klass))
+
+MSFilter *ms_h263_decoder_new();
+MSFilter *ms_mpeg_decoder_new();
+MSFilter *ms_mpeg4_decoder_new();
+MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id);
+
+gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt);
+void ms_AVdecoder_set_width(MSAVDecoder *av,gint w);
+void ms_AVdecoder_set_height(MSAVDecoder *av,gint h);
+
+/* FOR INTERNAL USE*/
+void ms_AVdecoder_init(MSAVDecoder *r, AVCodec *codec);
+void ms_AVdecoder_uninit(MSAVDecoder *enc);
+void ms_AVdecoder_class_init(MSAVDecoderClass *klass);
+void ms_AVdecoder_destroy( MSAVDecoder *obj);
+void ms_AVdecoder_process(MSAVDecoder *r);
+
+void ms_AVCodec_init();
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h
new file mode 100644
index 00000000..6fe5cad4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msavencoder.h
@@ -0,0 +1,90 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSAVENCODER_H
+#define MSAVENCODER_H
+
+#include "msfilter.h"
+#include "mscodec.h"
+#include <avcodec.h>
+
+/*this is the class that implements a AVencoder filter*/
+
+#define MSAVENCODER_MAX_INPUTS 1 /* max output per filter*/
+#define MSAVENCODER_MAX_OUTPUTS 2
+
+struct _MSAVEncoder
+{
+ /* the MSAVEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVEncoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSQueue *q_inputs[MSAVENCODER_MAX_INPUTS];
+ MSQueue *q_outputs[MSAVENCODER_MAX_OUTPUTS];
+ AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */
+ AVCodecContext av_context; /* the context of the AVCodec */
+ gint input_pix_fmt;
+ gint av_opened;
+ MSBuffer *comp_buf;
+ MSBuffer *yuv_buf;
+};
+
+typedef struct _MSAVEncoder MSAVEncoder;
+/* MSAVEncoder always outputs planar YUV and accept any incoming format you should setup using
+ ms_AVencoder_set_format()
+q_outputs[0] is the compressed video stream output
+q_outputs[1] is a YUV planar buffer of the image it receives in input.
+*/
+
+
+struct _MSAVEncoderClass
+{
+ /* the MSAVEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVEncoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSAVEncoderClass MSAVEncoderClass;
+
+/* PUBLIC */
+#define MS_AVENCODER(filter) ((MSAVEncoder*)(filter))
+#define MS_AVENCODER_CLASS(klass) ((MSAVEncoderClass*)(klass))
+
+MSFilter *ms_h263_encoder_new();
+MSFilter *ms_mpeg_encoder_new();
+MSFilter *ms_mpeg4_encoder_new();
+MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info);
+
+gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt);
+
+#define ms_AVencoder_set_width(av,w) (av)->av_context.width=(w)
+#define ms_AVencoder_set_height(av,h) (av)->av_context.height=(h)
+#define ms_AVencoder_set_bit_rate(av,r) (av)->av_context.bit_rate=(r)
+
+void ms_AVencoder_set_frame_rate(MSAVEncoder *enc, gint frame_rate, gint frame_rate_base);
+
+/* FOR INTERNAL USE*/
+void ms_AVencoder_init(MSAVEncoder *r, AVCodec *codec);
+void ms_AVencoder_uninit(MSAVEncoder *enc);
+void ms_AVencoder_class_init(MSAVEncoderClass *klass);
+void ms_AVencoder_destroy( MSAVEncoder *obj);
+void ms_AVencoder_process(MSAVEncoder *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c
new file mode 100644
index 00000000..4ca3c925
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.c
@@ -0,0 +1,94 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msbuffer.h"
+#include "msutils.h"
+#include <string.h>
+
+
+
+MSBuffer * ms_buffer_new(guint32 size)
+{
+ MSBuffer *buf;
+ buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)+size);
+ buf->ref_count=0;
+ buf->size=size;
+ ms_trace("ms_buffer_new: Allocating buffer of %i bytes.",size);
+ /* allocate the data buffer: there is a lot of optmisation that can be done by using a pool of cached buffers*/
+ buf->buffer=((char*)(buf))+sizeof(MSBuffer); /* to avoid to do two allocations,
+ buffer info and buffer are contigous.*/
+ buf->flags=MS_BUFFER_CONTIGUOUS;
+ return(buf);
+}
+
+MSBuffer *ms_buffer_alloc(gint flags)
+{
+ MSBuffer *buf;
+ buf=(MSBuffer*)g_malloc(sizeof(MSBuffer));
+ buf->ref_count=0;
+ buf->size=0;
+ buf->buffer=NULL;
+ buf->flags=0;
+ return(buf);
+}
+
+
+void ms_buffer_destroy(MSBuffer *buf)
+{
+ if (buf->flags & MS_BUFFER_CONTIGUOUS){
+ g_free(buf);
+ }
+ else {
+ g_free(buf->buffer);
+ g_free(buf);
+ }
+}
+
+MSMessage *ms_message_alloc()
+{
+ MSMessage *m=g_malloc(sizeof(MSMessage));
+ memset(m,0,sizeof(MSMessage));
+ return m;
+}
+
+MSMessage *ms_message_new(gint size)
+{
+ MSMessage *m=ms_message_alloc();
+ MSBuffer *buf=ms_buffer_new(size);
+ ms_message_set_buf(m,buf);
+ return m;
+}
+
+void ms_message_destroy(MSMessage *m)
+{
+ /* the buffer is freed if its ref_count goes to zero */
+ if (m->buffer!=NULL){
+ m->buffer->ref_count--;
+ if (m->buffer->ref_count==0) ms_buffer_destroy(m->buffer);
+ }
+ g_free(m);
+}
+
+MSMessage * ms_message_dup(MSMessage *m)
+{
+ MSMessage *msg=ms_message_alloc();
+ ms_message_set_buf(msg,m->buffer);
+ return msg;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h
new file mode 100644
index 00000000..f96b35a7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msbuffer.h
@@ -0,0 +1,75 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSBUFFER_H
+#define MSBUFFER_H
+#include <config.h>
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#else
+#include <uglib.h>
+#endif
+
+
+#define MS_BUFFER_LARGE 4092
+
+
+typedef struct _MSBuffer
+{
+ gchar *buffer;
+ guint32 size;
+ guint16 ref_count;
+ guint16 flags;
+#define MS_BUFFER_CONTIGUOUS (1)
+}MSBuffer;
+
+MSBuffer * ms_buffer_new(guint32 size);
+void ms_buffer_destroy(MSBuffer *buf);
+
+struct _MSMessage
+{
+ MSBuffer *buffer; /* points to a MSBuffer */
+ void *data; /*points to buffer->buffer */
+ guint32 size; /* the size of the buffer to read in data. It may not be the
+ physical size (I mean buffer->buffer->size */
+ struct _MSMessage *next;
+ struct _MSMessage *prev; /* MSMessage are queued into MSQueues */
+};
+
+typedef struct _MSMessage MSMessage;
+
+
+MSBuffer *ms_buffer_alloc(gint flags);
+MSMessage *ms_message_new(gint size);
+
+#define ms_message_set_buf(m,b) do { (b)->ref_count++; (m)->buffer=(b); (m)->data=(b)->buffer; (m)->size=(b)->size; }while(0)
+#define ms_message_unset_buf(m) do { (m)->buffer->ref_count--; (m)->buffer=NULL; (m)->size=0; (m)->data=NULL; } while(0)
+
+#define ms_message_size(m) (m)->size
+void ms_message_destroy(MSMessage *m);
+
+MSMessage * ms_message_dup(MSMessage *m);
+
+/* allocate a single message without buffer */
+MSMessage *ms_message_alloc();
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c
new file mode 100644
index 00000000..dafa1e87
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.c
@@ -0,0 +1,250 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "mscodec.h"
+#include "msMUlawdec.h"
+
+#ifdef TRUESPEECH
+extern MSCodecInfo TrueSpeechinfo;
+#endif
+
+#ifdef VIDEO_ENABLED
+extern void ms_AVCodec_init();
+#endif
+
+#define UDP_HDR_SZ 8
+#define RTP_HDR_SZ 12
+#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
+
+
+
+
+/* register all statically linked codecs */
+void ms_codec_register_all()
+{
+/*// ms_filter_register(MS_FILTER_INFO(&GSMinfo));
+ // ms_filter_register(MS_FILTER_INFO(&LPC10info));*/
+ ms_filter_register(MS_FILTER_INFO(&MULAWinfo));
+#ifdef TRUESPEECH
+ ms_filter_register(MS_FILTER_INFO(&TrueSpeechinfo));
+#endif
+#ifdef VIDEO_ENABLED
+ ms_AVCodec_init();
+#endif
+
+}
+
+/* returns a list of MSCodecInfo */
+GList * ms_codec_get_all_audio()
+{
+ GList *audio_codecs=NULL;
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if (info->type==MS_FILTER_AUDIO_CODEC){
+ audio_codecs=g_list_append(audio_codecs,info);
+ }
+ elem=g_list_next(elem);
+ }
+ return audio_codecs;
+}
+
+
+MSCodecInfo * ms_audio_codec_info_get(gchar *name)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ( (info->type==MS_FILTER_AUDIO_CODEC) ){
+ MSCodecInfo *codinfo=(MSCodecInfo *)info;
+ if (strcmp(codinfo->description,name)==0){
+ return MS_CODEC_INFO(info);
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSCodecInfo * ms_video_codec_info_get(gchar *name)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ( (info->type==MS_FILTER_VIDEO_CODEC) ){
+ MSCodecInfo *codinfo=(MSCodecInfo *)info;
+ if (strcmp(codinfo->description,name)==0){
+ return MS_CODEC_INFO(info);
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+/* returns a list of MSCodecInfo */
+GList * ms_codec_get_all_video()
+{
+ GList *video_codecs=NULL;
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if (info->type==MS_FILTER_VIDEO_CODEC){
+ video_codecs=g_list_append(video_codecs,info);
+ }
+ elem=g_list_next(elem);
+ }
+ return video_codecs;
+}
+
+MSFilter * ms_encoder_new(gchar *name)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (strcmp(info->name,name)==0){
+ return codinfo->encoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSFilter * ms_decoder_new(gchar *name)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (strcmp(info->name,name)==0){
+ return codinfo->decoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSFilter * ms_encoder_new_with_pt(gint pt)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (codinfo->pt==pt){
+ return codinfo->encoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSFilter * ms_decoder_new_with_pt(gint pt)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (codinfo->pt==pt){
+ return codinfo->decoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSFilter * ms_decoder_new_with_string_id(gchar *id)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (strcasecmp(codinfo->description,id)==0){
+ return codinfo->decoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+
+MSFilter * ms_encoder_new_with_string_id(gchar *id)
+{
+ GList *elem=filter_list;
+ MSFilterInfo *info;
+ while (elem!=NULL)
+ {
+ info=(MSFilterInfo *)elem->data;
+ if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
+ MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
+ if (strcasecmp(codinfo->description,id)==0){
+ return codinfo->encoder();
+ }
+ }
+ elem=g_list_next(elem);
+ }
+ return NULL;
+}
+/* return 0 if codec can be used with bandwidth, -1 else*/
+int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth)
+{
+ double codec_band;
+ double npacket;
+ double packet_size;
+
+ if (((MSFilterInfo*)codec)->type==MS_FILTER_AUDIO_CODEC)
+ {
+ /* calculate the total bandwdith needed by codec (including headers for rtp, udp, ip)*/
+ /* number of packet per second*/
+ npacket=2.0*(double)(codec->rate)/(double)(codec->fr_size);
+ packet_size=(double)(codec->dt_size)+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
+ codec_band=packet_size*8.0*npacket;
+ }
+ else return -1;
+ return(codec_band<bandwidth);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h
new file mode 100644
index 00000000..6c6847d8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscodec.h
@@ -0,0 +1,67 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSCODEC_H
+#define MSCODEC_H
+
+#include "msfilter.h"
+
+struct _MSCodecInfo
+{
+ MSFilterInfo info;
+ MSFilterNewFunc encoder;
+ MSFilterNewFunc decoder;
+ gint fr_size; /* size in char of the uncompressed frame */
+ gint dt_size; /* size in char of the compressed frame */
+ gint bitrate; /* the minimum bit rate in bits/second */
+ gint rate; /*frequency */
+ gint pt; /* the payload type number associated with this codec*/
+ gchar *description; /* a rtpmap field to describe the codec */
+ guint is_usable:1; /* linphone set this flag to remember if it can use this codec considering the total bandwidth*/
+ guint is_selected:1; /* linphone (user) set this flag if he allows this codec to be used*/
+};
+
+typedef struct _MSCodecInfo MSCodecInfo;
+
+MSFilter * ms_encoder_new(gchar *name);
+MSFilter * ms_decoder_new(gchar *name);
+
+MSFilter * ms_encoder_new_with_pt(gint pt);
+MSFilter * ms_decoder_new_with_pt(gint pt);
+
+MSFilter * ms_encoder_new_with_string_id(gchar *id);
+MSFilter * ms_decoder_new_with_string_id(gchar *id);
+
+/* return 0 if codec can be used with bandwidth, -1 else*/
+int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth);
+
+GList * ms_codec_get_all_audio();
+
+GList * ms_codec_get_all_video();
+
+MSCodecInfo * ms_audio_codec_info_get(gchar *name);
+MSCodecInfo * ms_video_codec_info_get(gchar *name);
+
+/* register all statically linked codecs */
+void ms_codec_register_all();
+
+#define MS_CODEC_INFO(codinfo) ((MSCodecInfo*)codinfo)
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c
new file mode 100644
index 00000000..3040b2e2
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.c
@@ -0,0 +1,96 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "mscopy.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+static MSCopyClass *ms_copy_class=NULL;
+
+MSFilter * ms_copy_new(void)
+{
+ MSCopy *r;
+
+ r=g_new(MSCopy,1);
+ ms_copy_init(r);
+ if (ms_copy_class==NULL)
+ {
+ ms_copy_class=g_new(MSCopyClass,1);
+ ms_copy_class_init(ms_copy_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_copy_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_copy_init(MSCopy *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->r_mingran=MSCOPY_DEF_GRAN;
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
+}
+
+void ms_copy_class_init(MSCopyClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"fifocopier");
+ MS_FILTER_CLASS(klass)->max_finputs=MSCOPY_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSCOPY_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=MSCOPY_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->w_maxgran=MSCOPY_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_copy_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_copy_process;
+}
+
+void ms_copy_process(MSCopy *r)
+{
+ MSFifo *fi,*fo;
+ int err1;
+ gint gran=MS_FILTER(r)->klass->r_maxgran;
+ void *s,*d;
+
+ /* process output fifos, but there is only one for this class of filter*/
+
+ fi=r->f_inputs[0];
+ fo=r->f_outputs[0];
+ if (fi!=NULL)
+ {
+ err1=ms_fifo_get_read_ptr(fi,gran,&s);
+ if (err1>0) err1=ms_fifo_get_write_ptr(fo,gran,&d);
+ if (err1>0)
+ {
+ memcpy(d,s,gran);
+ }
+ }
+}
+
+void ms_copy_destroy( MSCopy *obj)
+{
+ g_free(obj);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h
new file mode 100644
index 00000000..2b5749b9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mscopy.h
@@ -0,0 +1,61 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSCOPY_H
+#define MSCOPY_H
+
+#include "msfilter.h"
+
+
+/*this is the class that implements a copy filter*/
+
+#define MSCOPY_MAX_INPUTS 1 /* max output per filter*/
+
+#define MSCOPY_DEF_GRAN 64 /* the default granularity*/
+
+typedef struct _MSCopy
+{
+ /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSCOPY_MAX_INPUTS];
+ MSFifo *f_outputs[MSCOPY_MAX_INPUTS];
+} MSCopy;
+
+typedef struct _MSCopyClass
+{
+ /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSCopyClass;
+
+/* PUBLIC */
+#define MS_COPY(filter) ((MSCopy*)(filter))
+#define MS_COPY_CLASS(klass) ((MSCopyClass*)(klass))
+MSFilter * ms_copy_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_copy_init(MSCopy *r);
+void ms_copy_class_init(MSCopyClass *klass);
+void ms_copy_destroy( MSCopy *obj);
+void ms_copy_process(MSCopy *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c
new file mode 100644
index 00000000..692bbb7b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.c
@@ -0,0 +1,94 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a dispatcher of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msfdispatcher.h"
+
+static MSFdispatcherClass *ms_fdispatcher_class=NULL;
+
+MSFilter * ms_fdispatcher_new(void)
+{
+ MSFdispatcher *obj;
+ obj=g_malloc(sizeof(MSFdispatcher));
+ if (ms_fdispatcher_class==NULL){
+ ms_fdispatcher_class=g_malloc(sizeof(MSFdispatcherClass));
+ ms_fdispatcher_class_init(ms_fdispatcher_class);
+ }
+ MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_fdispatcher_class);
+ ms_fdispatcher_init(obj);
+ return MS_FILTER(obj);
+}
+
+
+void ms_fdispatcher_init(MSFdispatcher *obj)
+{
+ ms_filter_init(MS_FILTER(obj));
+ MS_FILTER(obj)->infifos=obj->f_inputs;
+ MS_FILTER(obj)->outfifos=obj->f_outputs;
+ MS_FILTER(obj)->r_mingran=MS_FDISPATCHER_DEF_GRAN;
+ memset(obj->f_inputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_INPUTS);
+ memset(obj->f_outputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_OUTPUTS);
+}
+
+
+
+void ms_fdispatcher_class_init(MSFdispatcherClass *klass)
+{
+ MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
+ ms_filter_class_init(parent_class);
+ ms_filter_class_set_name(parent_class,"fdispatcher");
+ parent_class->max_finputs=MS_FDISPATCHER_MAX_INPUTS;
+ parent_class->max_foutputs=MS_FDISPATCHER_MAX_OUTPUTS;
+ parent_class->r_maxgran=MS_FDISPATCHER_DEF_GRAN;
+ parent_class->w_maxgran=MS_FDISPATCHER_DEF_GRAN;
+ parent_class->destroy=(MSFilterDestroyFunc)ms_fdispatcher_destroy;
+ parent_class->process=(MSFilterProcessFunc)ms_fdispatcher_process;
+}
+
+
+void ms_fdispatcher_destroy( MSFdispatcher *obj)
+{
+ g_free(obj);
+}
+
+void ms_fdispatcher_process(MSFdispatcher *obj)
+{
+ gint i;
+ MSFifo *inf=obj->f_inputs[0];
+
+
+ if (inf!=NULL){
+ void *s,*d;
+ /* dispatch fifos */
+ while ( ms_fifo_get_read_ptr(inf,MS_FDISPATCHER_DEF_GRAN,&s) >0 ){
+ for (i=0;i<MS_FDISPATCHER_MAX_OUTPUTS;i++){
+ MSFifo *outf=obj->f_outputs[i];
+
+ if (outf!=NULL)
+ {
+ ms_fifo_get_write_ptr(outf,MS_FDISPATCHER_DEF_GRAN,&d);
+ if (d!=NULL) memcpy(d,s,MS_FDISPATCHER_DEF_GRAN);
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h
new file mode 100644
index 00000000..b1b457df
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfdispatcher.h
@@ -0,0 +1,61 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a dispatcher of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSFDISPATCHER_H
+#define MSFDISPATCHER_H
+
+#include "msfilter.h"
+
+
+/*this is the class that implements a fdispatcher filter*/
+
+#define MS_FDISPATCHER_MAX_INPUTS 1
+#define MS_FDISPATCHER_MAX_OUTPUTS 5
+#define MS_FDISPATCHER_DEF_GRAN 64 /* the default granularity*/
+
+typedef struct _MSFdispatcher
+{
+ /* the MSFdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSFdispatcher object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MS_FDISPATCHER_MAX_INPUTS];
+ MSFifo *f_outputs[MS_FDISPATCHER_MAX_OUTPUTS];
+} MSFdispatcher;
+
+typedef struct _MSFdispatcherClass
+{
+ /* the MSFdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSFdispatcher class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSFdispatcherClass;
+
+/* PUBLIC */
+#define MS_FDISPATCHER(filter) ((MSFdispatcher*)(filter))
+#define MS_FDISPATCHER_CLASS(klass) ((MSFdispatcherClass*)(klass))
+MSFilter * ms_fdispatcher_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_fdispatcher_init(MSFdispatcher *r);
+void ms_fdispatcher_class_init(MSFdispatcherClass *klass);
+void ms_fdispatcher_destroy( MSFdispatcher *obj);
+void ms_fdispatcher_process(MSFdispatcher *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c
new file mode 100644
index 00000000..7e783c24
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.c
@@ -0,0 +1,168 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include "msutils.h"
+#include "msfifo.h"
+
+MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset)
+{
+ MSFifo *fifo;
+ gint saved_offset=MAX(r_gran+r_offset,w_offset);
+
+ g_return_val_if_fail(saved_offset<=(buf->size),NULL);
+ fifo=g_malloc(sizeof(MSFifo));
+ fifo->buffer=buf;
+ fifo->r_gran=r_gran;
+ fifo->w_gran=w_gran;
+ fifo->begin=fifo->wr_ptr=fifo->rd_ptr=buf->buffer+saved_offset;
+ fifo->readsize=0;
+ fifo->size=fifo->writesize=buf->size-saved_offset;
+ fifo->saved_offset= saved_offset;
+ fifo->r_end=fifo->w_end=buf->buffer+buf->size;
+ fifo->pre_end=fifo->w_end-saved_offset;
+ buf->ref_count++;
+ fifo->prev_data=NULL;
+ fifo->next_data=NULL;
+ ms_trace("fifo base=%x, begin=%x, end=%x, saved_offset=%i, size=%i"
+ ,fifo->buffer->buffer,fifo->begin,fifo->w_end,fifo->saved_offset,fifo->size);
+ return(fifo);
+}
+
+MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset,
+ gint min_fifo_size)
+{
+ MSFifo *fifo;
+ MSBuffer *buf;
+ gint saved_offset=MAX(r_gran+r_offset,w_offset);
+ gint fifo_size;
+ gint tmp;
+ if (min_fifo_size==0) min_fifo_size=w_gran;
+
+ /* we must allocate a fifo with a size multiple of min_fifo_size,
+ with a saved_offset */
+ if (min_fifo_size>MS_BUFFER_LARGE)
+ fifo_size=(min_fifo_size) + saved_offset;
+ else fifo_size=(6*min_fifo_size) + saved_offset;
+ buf=ms_buffer_new(fifo_size);
+ fifo=ms_fifo_new(buf,r_gran,w_gran,r_offset,w_offset);
+ ms_trace("fifo_size=%i",fifo_size);
+ return(fifo);
+}
+
+void ms_fifo_destroy( MSFifo *fifo)
+{
+ g_free(fifo);
+}
+
+void ms_fifo_destroy_with_buffer(MSFifo *fifo)
+{
+ ms_buffer_destroy(fifo->buffer);
+ ms_fifo_destroy(fifo);
+}
+
+gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
+{
+ gchar *rnext;
+
+ *ret_ptr=NULL;
+ /* //ms_trace("ms_fifo_get_read_ptr: entering.");*/
+ g_return_val_if_fail(bsize<=fifo->r_gran,-EINVAL);
+
+ if (bsize>fifo->readsize)
+ {
+ ms_trace("Not enough data: bsize=%i, readsize=%i",bsize,fifo->readsize);
+ return (-ENODATA);
+ }
+
+ rnext=fifo->rd_ptr+bsize;
+ if (rnext<=fifo->r_end){
+
+ *ret_ptr=fifo->rd_ptr;
+ fifo->rd_ptr=rnext;
+ }else{
+ int unread=fifo->r_end-fifo->rd_ptr;
+ *ret_ptr=fifo->begin-unread;
+ memcpy(fifo->buffer->buffer,fifo->r_end-fifo->saved_offset,fifo->saved_offset);
+ fifo->rd_ptr=(char*)(*ret_ptr) + bsize;
+ fifo->r_end=fifo->w_end; /* this is important ! */
+ ms_trace("moving read ptr to %x",fifo->rd_ptr);
+
+ }
+ /* update write size*/
+ fifo->writesize+=bsize;
+ fifo->readsize-=bsize;
+ return bsize;
+}
+
+
+void ms_fifo_update_write_ptr(MSFifo *fifo, gint written){
+ gint reserved=fifo->wr_ptr-fifo->prev_wr_ptr;
+ gint unwritten;
+ g_return_if_fail(reserved>=0);
+ unwritten=reserved-written;
+ g_return_if_fail(unwritten>=0);
+ /* fix readsize and writesize */
+ fifo->readsize-=unwritten;
+ fifo->writesize+=unwritten;
+ fifo->wr_ptr+=written;
+}
+
+gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
+{
+ gchar *wnext;
+
+ *ret_ptr=NULL;
+ /* //ms_trace("ms_fifo_get_write_ptr: Entering.");*/
+ g_return_val_if_fail(bsize<=fifo->w_gran,-EINVAL);
+ if (bsize>fifo->writesize)
+ {
+ ms_trace("Not enough space: bsize=%i, writesize=%i",bsize,fifo->writesize);
+ *ret_ptr=NULL;
+ return(-ENODATA);
+ }
+ wnext=fifo->wr_ptr+bsize;
+ if (wnext<=fifo->w_end){
+ *ret_ptr=fifo->wr_ptr;
+ fifo->wr_ptr=wnext;
+ }else{
+ *ret_ptr=fifo->begin;
+ fifo->r_end=fifo->wr_ptr;
+ fifo->wr_ptr=fifo->begin+bsize;
+ ms_trace("moving write ptr to %x",fifo->wr_ptr);
+ }
+ fifo->prev_wr_ptr=*ret_ptr;
+ /* update readsize*/
+ fifo->readsize+=bsize;
+ fifo->writesize-=bsize;
+ /* //ms_trace("ms_fifo_get_write_ptr: readsize=%i, writesize=%i",fifo->readsize,fifo->writesize);*/
+ return bsize;
+}
+
+gint ms_fifo_get_rw_ptr(MSFifo *f1,void **p1,gint minsize1,
+ MSFifo *f2,void **p2,gint minsize2)
+{
+ gint rbsize,wbsize;
+
+ rbsize=MIN(f1->readsize,(f1->pre_end-f1->rd_ptr));
+ wbsize=MIN(f2->writesize,(f2->w_end-f2->wr_ptr));
+ return 0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h
new file mode 100644
index 00000000..fde1bece
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfifo.h
@@ -0,0 +1,73 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#else
+#include "glist.h"
+#endif
+#include "msbuffer.h"
+
+typedef struct _MSFifo
+{
+ gint r_gran; /*maximum granularity for reading*/
+ gint w_gran; /*maximum granularity for writing*/
+ gchar * rd_ptr; /* read pointer on the position where there is something to read on the MSBuffer */
+ guint32 readsize;
+ gchar * wr_ptr;
+ gchar * prev_wr_ptr;
+ guint32 writesize; /* write pointer on the position where it is possible to write on the MSBuffer */
+ gchar * begin; /* rd_ptr et wr_ptr must all be >=begin*/
+ guint32 size; /* the length of the fifo, but this may not be equal to buffer->size*/
+ guint32 saved_offset;
+ gchar * pre_end; /* the end of the buffer that is copied at the begginning when we wrap around*/
+ gchar * w_end; /* when a wr ptr is expected to exceed end_offset,
+ it must be wrapped around to go at the beginning of the buffer. This is the end of the buffer*/
+ gchar * r_end; /* this is the last position written at the end of the fifo. If a read ptr is expected to
+ exceed this pointer, it must be put at the begginning of the buffer */
+ void *prev_data; /*user data, usually the writing MSFilter*/
+ void *next_data; /* user data, usually the reading MSFilter */
+ MSBuffer *buffer;
+} MSFifo;
+
+/* constructor*/
+/* r_gran: max granularity for reading (in number of bytes)*/
+/* w_gran: max granularity for writing (in number of bytes)*/
+/* r_offset: number of bytes that are kept available behind read pointer (for recursive filters)*/
+/* w_offset: number of bytes that are kept available behind write pointer (for recursive filters)*/
+/* buf is a MSBuffer that should be compatible with the above parameter*/
+MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset);
+
+/*does the same that ms_fifo_new(), but also allocate a compatible buffer automatically*/
+MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, gint min_buffer_size);
+
+void ms_fifo_destroy( MSFifo *fifo);
+
+void ms_fifo_destroy_with_buffer(MSFifo *fifo);
+
+/* get data to read */
+gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
+
+/* get a buffer to write*/
+gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
+
+/* in case the buffer got by ms_fifo_get_write_ptr() could not be filled completely, you must
+tell it by using this function */
+void ms_fifo_update_write_ptr(MSFifo *fifo, gint written);
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c
new file mode 100644
index 00000000..c67e9f0e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.c
@@ -0,0 +1,537 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <errno.h>
+#include "msfilter.h"
+
+
+
+void ms_filter_init(MSFilter *filter)
+{
+ filter->finputs=0;
+ filter->foutputs=0;
+ filter->qinputs=0;
+ filter->qoutputs=0;
+ filter->infifos=NULL;
+ filter->outfifos=NULL;
+ filter->inqueues=NULL;
+ filter->outqueues=NULL;
+ filter->lock=g_mutex_new();
+ filter->min_fifo_size=0x7fff;
+ filter->notify_event=NULL;
+ filter->userdata=NULL;
+}
+
+void ms_filter_uninit(MSFilter *filter)
+{
+ g_mutex_free(filter->lock);
+}
+
+void ms_filter_class_init(MSFilterClass *filterclass)
+{
+ filterclass->name=NULL;
+ filterclass->max_finputs=0;
+ filterclass->max_foutputs=0;
+ filterclass->max_qinputs=0;
+ filterclass->max_qoutputs=0;
+ filterclass->r_maxgran=0;
+ filterclass->w_maxgran=0;
+ filterclass->r_offset=0;
+ filterclass->w_offset=0;
+ filterclass->set_property=NULL;
+ filterclass->get_property=NULL;
+ filterclass->setup=NULL;
+ filterclass->unsetup=NULL;
+ filterclass->process=NULL;
+ filterclass->destroy=NULL;
+ filterclass->attributes=0;
+ filterclass->ref_count=0;
+}
+
+/* find output queue */
+gint find_oq(MSFilter *m1,MSQueue *oq)
+{
+ gint i;
+
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++){
+ if (m1->outqueues[i]==oq) return i;
+ }
+
+ return -1;
+}
+
+/* find input queue */
+gint find_iq(MSFilter *m1,MSQueue *iq)
+{
+ gint i;
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qinputs;i++){
+ if (m1->inqueues[i]==iq) return i;
+ }
+ return -1;
+}
+
+/* find output fifo */
+gint find_of(MSFilter *m1,MSFifo *of)
+{
+ gint i;
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++){
+ if (m1->outfifos[i]==of) return i;
+ }
+
+ return -1;
+}
+
+/* find input fifo */
+gint find_if(MSFilter *m1,MSFifo *inf)
+{
+ gint i;
+
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_finputs;i++){
+ if (m1->infifos[i]==inf) return i;
+ }
+
+ return -1;
+}
+
+#define find_free_iq(_m1) find_iq(_m1,NULL)
+#define find_free_oq(_m1) find_oq(_m1,NULL)
+#define find_free_if(_m1) find_if(_m1,NULL)
+#define find_free_of(_m1) find_of(_m1,NULL)
+
+int ms_filter_add_link(MSFilter *m1, MSFilter *m2)
+{
+ gint m1_q=-1;
+ gint m1_f=-1;
+ gint m2_q=-1;
+ gint m2_f=-1;
+ /* determine the type of link we can add */
+ m1_q=find_free_oq(m1);
+ m1_f=find_free_of(m1);
+ m2_q=find_free_iq(m2);
+ m2_f=find_free_if(m2);
+ if ((m1_q!=-1) && (m2_q!=-1)){
+ /* link with queues */
+ ms_trace("m1_q=%i , m2_q=%i",m1_q,m2_q);
+ return ms_filter_link(m1,m1_q,m2,m2_q,LINK_QUEUE);
+ }
+ if ((m1_f!=-1) && (m2_f!=-1)){
+ /* link with queues */
+ ms_trace("m1_f=%i , m2_f=%i",m1_f,m2_f);
+ return ms_filter_link(m1,m1_f,m2,m2_f,LINK_FIFO);
+ }
+ g_warning("ms_filter_add_link: could not link.");
+ return -1;
+}
+/**
+ * ms_filter_link:
+ * @m1: A #MSFilter object.
+ * @pin1: The pin number on @m1.
+ * @m2: A #MSFilter object.
+ * @pin2: The pin number on @m2.
+ * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
+ *
+ * This function links two MSFilter object between them. It must be used to make chains of filters.
+ * All data outgoing from pin1 of m1 will go to the input pin2 of m2.
+ * The way to communicate can be fifos or queues, depending of the nature of the filters. Filters can have
+ * multiple queue pins and multiple fifo pins, but most of them have only one queue input/output or only one
+ * fifo input/output. Fifos are usally used by filters doing audio processing, while queues are used by filters doing
+ * video processing.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, int linktype)
+{
+ MSQueue *q;
+ MSFifo *fifo;
+
+ g_message("ms_filter_add_link: %s,%i -> %s,%i",m1->klass->name,pin1,m2->klass->name,pin2);
+ switch(linktype)
+ {
+ case LINK_QUEUE:
+ /* Are filter m1 and m2 able to accept more queues connections ?*/
+ g_return_val_if_fail(m1->qoutputs<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EMLINK);
+ g_return_val_if_fail(m2->qinputs<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EMLINK);
+ /* Are filter m1 and m2 valid with their inputs and outputs ?*/
+ g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
+ g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
+ /* are the requested pins exists ?*/
+ g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
+ g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
+ /* are the requested pins free ?*/
+ g_return_val_if_fail(m1->outqueues[pin1]==NULL,-EBUSY);
+ g_return_val_if_fail(m2->inqueues[pin2]==NULL,-EBUSY);
+
+ q=ms_queue_new();
+ m1->outqueues[pin1]=m2->inqueues[pin2]=q;
+ m1->qoutputs++;
+ m2->qinputs++;
+ q->prev_data=(void*)m1;
+ q->next_data=(void*)m2;
+ break;
+ case LINK_FIFO:
+ /* Are filter m1 and m2 able to accept more fifo connections ?*/
+ g_return_val_if_fail(m1->foutputs<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EMLINK);
+ g_return_val_if_fail(m2->finputs<MS_FILTER_GET_CLASS(m2)->max_finputs,-EMLINK);
+ /* Are filter m1 and m2 valid with their inputs and outputs ?*/
+ g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
+ g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
+ /* are the requested pins exists ?*/
+ g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
+ g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
+ /* are the requested pins free ?*/
+ g_return_val_if_fail(m1->outfifos[pin1]==NULL,-EBUSY);
+ g_return_val_if_fail(m2->infifos[pin2]==NULL,-EBUSY);
+
+ if (MS_FILTER_GET_CLASS(m1)->attributes & FILTER_IS_SOURCE)
+ {
+ /* configure min_fifo_size */
+ fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
+ MS_FILTER_GET_CLASS(m1)->w_maxgran,
+ MS_FILTER_GET_CLASS(m2)->r_offset,
+ MS_FILTER_GET_CLASS(m1)->w_offset,
+ MS_FILTER_GET_CLASS(m1)->w_maxgran);
+ m2->min_fifo_size=MS_FILTER_GET_CLASS(m1)->w_maxgran;
+ }
+ else
+ {
+ gint next_size;
+ ms_trace("ms_filter_add_link: min_fifo_size=%i",m1->min_fifo_size);
+ fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
+ MS_FILTER_GET_CLASS(m1)->w_maxgran,
+ MS_FILTER_GET_CLASS(m2)->r_offset,
+ MS_FILTER_GET_CLASS(m1)->w_offset,
+ m1->min_fifo_size);
+ if (MS_FILTER_GET_CLASS(m2)->r_maxgran>0){
+ next_size=(m1->min_fifo_size*
+ (MS_FILTER_GET_CLASS(m2)->w_maxgran)) /
+ (MS_FILTER_GET_CLASS(m2)->r_maxgran);
+ }else next_size=m1->min_fifo_size;
+ ms_trace("ms_filter_add_link: next_size=%i",next_size);
+ m2->min_fifo_size=next_size;
+ }
+
+
+ m1->outfifos[pin1]=m2->infifos[pin2]=fifo;
+ m1->foutputs++;
+ m2->finputs++;
+ fifo->prev_data=(void*)m1;
+ fifo->next_data=(void*)m2;
+ break;
+ }
+ return 0;
+}
+/**
+ * ms_filter_unlink:
+ * @m1: A #MSFilter object.
+ * @pin1: The pin number on @m1.
+ * @m2: A #MSFilter object.
+ * @pin2: The pin number on @m2.
+ * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
+ *
+ * Unlink @pin1 of filter @m1 from @pin2 of filter @m2. @linktype specifies what type of connection is removed.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype)
+{
+ switch(linktype)
+ {
+ case LINK_QUEUE:
+ /* Are filter m1 and m2 valid with their inputs and outputs ?*/
+ g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
+ g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
+ /* are the requested pins exists ?*/
+ g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
+ g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
+ /* are the requested pins busy ?*/
+ g_return_val_if_fail(m1->outqueues[pin1]!=NULL,-ENOENT);
+ g_return_val_if_fail(m2->inqueues[pin2]!=NULL,-ENOENT);
+ /* are the two pins connected together ?*/
+ g_return_val_if_fail(m1->outqueues[pin1]==m2->inqueues[pin2],-EINVAL);
+
+ ms_queue_destroy(m1->outqueues[pin1]);
+ m1->outqueues[pin1]=m2->inqueues[pin2]=NULL;
+ m1->qoutputs--;
+ m2->qinputs--;
+
+ break;
+ case LINK_FIFO:
+ /* Are filter m1 and m2 valid with their inputs and outputs ?*/
+ g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
+ g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
+ /* are the requested pins exists ?*/
+ g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
+ g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
+ /* are the requested pins busy ?*/
+ g_return_val_if_fail(m1->outfifos[pin1]!=NULL,-ENOENT);
+ g_return_val_if_fail(m2->infifos[pin2]!=NULL,-ENOENT);
+ /* are the two pins connected together ?*/
+ g_return_val_if_fail(m1->outfifos[pin1]==m2->infifos[pin2],-EINVAL);
+ ms_fifo_destroy_with_buffer(m1->outfifos[pin1]);
+ m1->outfifos[pin1]=m2->infifos[pin2]=NULL;
+ m1->foutputs--;
+ m2->finputs--;
+ break;
+ }
+ return 0;
+}
+
+/**
+ *ms_filter_remove_links:
+ *@m1: a filter
+ *@m2: another filter.
+ *
+ * Removes all links between m1 and m2.
+ *
+ *Returns: 0 if one more link have been removed, -1 if not.
+**/
+gint ms_filter_remove_links(MSFilter *m1, MSFilter *m2)
+{
+ int i,j;
+ int removed=-1;
+ MSQueue *qo;
+ MSFifo *fo;
+ /* takes all outputs of m1, and removes the one that goes to m2 */
+ if (m1->outqueues!=NULL){
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++)
+ {
+ qo=m1->outqueues[i];
+ if (qo!=NULL){
+ MSFilter *rmf;
+ /* test if the queue connects to m2 */
+ rmf=(MSFilter*)qo->next_data;
+ if (rmf==m2){
+ j=find_iq(rmf,qo);
+ if (j==-1) g_error("Could not find input queue: impossible case.");
+ ms_filter_unlink(m1,i,m2,j,LINK_QUEUE);
+ removed=0;
+ }
+ }
+ }
+ }
+ if (m1->outfifos!=NULL){
+ for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++)
+ {
+ fo=m1->outfifos[i];
+ if (fo!=NULL){
+ MSFilter *rmf;
+ /* test if the queue connects to m2 */
+ rmf=(MSFilter*)fo->next_data;
+ if (rmf==m2){
+ j=find_if(rmf,fo);
+ if (j==-1) g_error("Could not find input fifo: impossible case.");
+ ms_filter_unlink(m1,i,m2,j,LINK_FIFO);
+ removed=0;
+ }
+ }
+ }
+ }
+ return removed;
+}
+
+/**
+ * ms_filter_fifos_have_data:
+ * @f: a #MSFilter object.
+ *
+ * Tells if the filter has enough data in its input fifos in order to be executed succesfully.
+ *
+ * Returns: 1 if it can be executed, 0 else.
+ */
+gint ms_filter_fifos_have_data(MSFilter *f)
+{
+ gint i,j;
+ gint max_inputs=f->klass->max_finputs;
+ gint con_inputs=f->finputs;
+ MSFifo *fifo;
+ /* test fifos */
+ for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
+ {
+ fifo=f->infifos[i];
+ if (fifo!=NULL)
+ {
+ j++;
+ if (fifo->readsize==0) return 0;
+ if (fifo->readsize>=f->r_mingran) return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ms_filter_queues_have_data:
+ * @f: a #MSFilter object.
+ *
+ * Tells if the filter has enough data in its input queues in order to be executed succesfully.
+ *
+ * Returns: 1 if it can be executed, 0 else.
+ */
+gint ms_filter_queues_have_data(MSFilter *f)
+{
+ gint i,j;
+ gint max_inputs=f->klass->max_qinputs;
+ gint con_inputs=f->qinputs;
+ MSQueue *q;
+ /* test queues */
+ for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
+ {
+ q=f->inqueues[i];
+ if (q!=NULL)
+ {
+ j++;
+ if (ms_queue_can_get(q)) return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+void ms_filter_destroy(MSFilter *f)
+{
+ /* first check if the filter is disconnected from any others */
+ g_return_if_fail(f->finputs==0);
+ g_return_if_fail(f->foutputs==0);
+ g_return_if_fail(f->qinputs==0);
+ g_return_if_fail(f->qoutputs==0);
+ f->klass->destroy(f);
+}
+
+GList *filter_list=NULL;
+
+void ms_filter_register(MSFilterInfo *info)
+{
+ gpointer tmp;
+ tmp=g_list_find(filter_list,info);
+ if (tmp==NULL) filter_list=g_list_append(filter_list,(gpointer)info);
+}
+
+void ms_filter_unregister(MSFilterInfo *info)
+{
+ filter_list=g_list_remove(filter_list,(gpointer)info);
+}
+
+static gint compare_names(gpointer info, gpointer name)
+{
+ MSFilterInfo *i=(MSFilterInfo*) info;
+ return (strcmp(i->name,name));
+}
+
+MSFilterInfo * ms_filter_get_by_name(const gchar *name)
+{
+ GList *elem=g_list_find_custom(filter_list,
+ (gpointer)name,(GCompareFunc)compare_names);
+ if (elem!=NULL){
+ return (MSFilterInfo*)elem->data;
+ }
+ return NULL;
+}
+
+
+
+MSFilter * ms_filter_new_with_name(const gchar *name)
+{
+ MSFilterInfo *info=ms_filter_get_by_name(name);
+ if (info!=NULL) return info->constructor();
+ g_warning("ms_filter_new_with_name: no filter named %s found.",name);
+ return NULL;
+}
+
+
+/* find the first codec in the left part of the stream */
+MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type)
+{
+ MSFilter *tmp=f;
+ MSFilterInfo *info;
+
+ if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)){
+ tmp=(MSFilter*) tmp->infifos[0]->prev_data;
+ while(1){
+ info=MS_FILTER_GET_CLASS(tmp)->info;
+ if (info!=NULL){
+ if ( (info->type==type) ){
+ return tmp;
+ }
+ }
+ if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL))
+ tmp=(MSFilter*) tmp->infifos[0]->prev_data;
+ else break;
+ }
+ }
+ tmp=f;
+ if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)){
+ tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
+ while(1){
+
+ info=MS_FILTER_GET_CLASS(tmp)->info;
+ if (info!=NULL){
+ if ( (info->type==type)){
+ return tmp;
+ }
+ }else g_warning("ms_filter_search_upstream_by_type: filter %s has no info."
+ ,MS_FILTER_GET_CLASS(tmp)->name);
+ if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL))
+ tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
+ else break;
+ }
+ }
+ return NULL;
+}
+
+
+int ms_filter_set_property(MSFilter *f, MSFilterProperty prop,void *value)
+{
+ if (f->klass->set_property!=NULL){
+ return f->klass->set_property(f,prop,value);
+ }
+ return 0;
+}
+
+int ms_filter_get_property(MSFilter *f, MSFilterProperty prop,void *value)
+{
+ if (f->klass->get_property!=NULL){
+ return f->klass->get_property(f,prop,value);
+ }
+ return -1;
+}
+
+void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata)
+{
+ filter->notify_event=func;
+ filter->userdata=userdata;
+}
+
+void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg)
+{
+ if (filter->notify_event!=NULL){
+ filter->notify_event(filter,event,arg,filter->userdata);
+ }
+}
+
+void swap_buffer(gchar *buffer, gint len)
+{
+ int i;
+ gchar tmp;
+ for (i=0;i<len;i+=2){
+ tmp=buffer[i];
+ buffer[i]=buffer[i+1];
+ buffer[i+1]=tmp;
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h
new file mode 100644
index 00000000..71ec81ad
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msfilter.h
@@ -0,0 +1,201 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSFILTER_H
+#define MSFILTER_H
+
+#include <config.h>
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#include <gmodule.h>
+#else
+#undef VERSION
+#undef PACKAGE
+#include <uglib.h>
+#endif
+
+#include <string.h>
+#include "msutils.h"
+#include "msfifo.h"
+#include "msqueue.h"
+
+struct _MSFilter;
+/*this is the abstract object and class for all filter types*/
+typedef gint (*MSFilterNotifyFunc)(struct _MSFilter*, gint event, gpointer arg, gpointer userdata);
+
+struct _MSFilter
+{
+ struct _MSFilterClass *klass;
+ GMutex *lock;
+ guchar finputs; /* number of connected fifo inputs*/
+ guchar foutputs; /* number of connected fifo outputs*/
+ guchar qinputs; /* number of connected queue inputs*/
+ guchar qoutputs; /* number of connected queue outputs*/
+ gint min_fifo_size; /* set when linking*/
+ gint r_mingran; /* read minimum granularity (for fifos).
+ It can be zero so that the filter can accept any size of reading data*/
+ MSFifo **infifos; /*pointer to a table of pointer to input fifos*/
+ MSFifo **outfifos; /*pointer to a table of pointer to output fifos*/
+ MSQueue **inqueues; /*pointer to a table of pointer to input queues*/
+ MSQueue **outqueues; /*pointer to a table of pointer to output queues*/
+ MSFilterNotifyFunc notify_event;
+ gpointer userdata;
+};
+
+typedef struct _MSFilter MSFilter;
+
+typedef enum{
+ MS_FILTER_PROPERTY_FREQ, /* value is int */
+ MS_FILTER_PROPERTY_BITRATE, /*value is int */
+ MS_FILTER_PROPERTY_CHANNELS,/*value is int */
+ MS_FILTER_PROPERTY_FMTP /* value is string */
+}MSFilterProperty;
+
+#define MS_FILTER_PROPERTY_STRING_MAX_SIZE 256
+
+typedef MSFilter * (*MSFilterNewFunc)(void);
+typedef void (*MSFilterProcessFunc)(MSFilter *);
+typedef void (*MSFilterDestroyFunc)(MSFilter *);
+typedef int (*MSFilterPropertyFunc)(MSFilter *,int ,void*);
+typedef void (*MSFilterSetupFunc)(MSFilter *, void *); /*2nd arg is the sync */
+
+typedef struct _MSFilterClass
+{
+ struct _MSFilterInfo *info; /*pointer to a filter_info */
+ gchar *name;
+ guchar max_finputs; /* maximum number of fifo inputs*/
+ guchar max_foutputs; /* maximum number of fifo outputs*/
+ guchar max_qinputs; /* maximum number of queue inputs*/
+ guchar max_qoutputs; /* maximum number of queue outputs*/
+ gint r_maxgran; /* read maximum granularity (for fifos)*/
+ gint w_maxgran; /* write maximum granularity (for fifos)*/
+ gint r_offset; /* size of kept samples behind read pointer (for fifos)*/
+ gint w_offset; /* size of kept samples behind write pointer (for fifos)*/
+ MSFilterPropertyFunc set_property;
+ MSFilterPropertyFunc get_property;
+ MSFilterSetupFunc setup; /* called when attaching to sync */
+ void (*process)(MSFilter *filter);
+ MSFilterSetupFunc unsetup; /* called when detaching from sync */
+ void (*destroy)(MSFilter *filter);
+ guint attributes;
+#define FILTER_HAS_FIFOS (0x0001)
+#define FILTER_HAS_QUEUES (0x0001<<1)
+#define FILTER_IS_SOURCE (0x0001<<2)
+#define FILTER_IS_SINK (0x0001<<3)
+#define FILTER_CAN_SYNC (0x0001<<4)
+ guint ref_count; /*number of object using the class*/
+} MSFilterClass;
+
+
+
+#define MS_FILTER(obj) ((MSFilter*)obj)
+#define MS_FILTER_CLASS(klass) ((MSFilterClass*)klass)
+#define MS_FILTER_GET_CLASS(obj) ((MSFilterClass*)((MS_FILTER(obj)->klass)))
+
+void ms_filter_class_init(MSFilterClass *filterclass);
+void ms_filter_init(MSFilter *filter);
+
+#define ms_filter_class_set_attr(filter,flag) ((filter)->attributes|=(flag))
+#define ms_filter_class_unset_attr(filter,flag) ((filter)->attributes&=~(flag))
+
+#define ms_filter_class_set_name(__klass,__name) (__klass)->name=g_strdup((__name))
+#define ms_filter_class_set_info(_klass,_info) (_klass)->info=(_info)
+/* public*/
+
+#define ms_filter_process(filter) ((filter)->klass->process((filter)))
+
+#define ms_filter_lock(filter) g_mutex_lock((filter)->lock)
+#define ms_filter_unlock(filter) g_mutex_unlock((filter)->lock)
+/* low level connect functions */
+int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, gint linktype);
+int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype);
+
+/* high level connect functions */
+int ms_filter_add_link(MSFilter *m1, MSFilter *m2);
+int ms_filter_remove_links(MSFilter *m1, MSFilter *m2);
+
+void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata);
+void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg);
+
+int ms_filter_set_property(MSFilter *f,MSFilterProperty property, void *value);
+int ms_filter_get_property(MSFilter *f,MSFilterProperty property, void *value);
+
+
+gint ms_filter_fifos_have_data(MSFilter *f);
+gint ms_filter_queues_have_data(MSFilter *f);
+
+void ms_filter_uninit(MSFilter *obj);
+void ms_filter_destroy(MSFilter *f);
+
+#define ms_filter_get_mingran(f) ((f)->r_mingran)
+#define ms_filter_set_mingran(f,gran) ((f)->r_mingran=(gran))
+
+#define LINK_DEFAULT 0
+#define LINK_FIFO 1
+#define LINK_QUEUE 2
+
+
+#define MSFILTER_VERSION(a,b,c) (((a)<<2)|((b)<<1)|(c))
+
+enum _MSFilterType
+{
+ MS_FILTER_DISK_IO,
+ MS_FILTER_AUDIO_CODEC,
+ MS_FILTER_VIDEO_CODEC,
+ MS_FILTER_NET_IO,
+ MS_FILTER_VIDEO_IO,
+ MS_FILTER_AUDIO_IO,
+ MS_FILTER_OTHER
+};
+
+typedef enum _MSFilterType MSFilterType;
+
+
+/* find the first codec in the left part of the stream */
+MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type);
+
+struct _MSFilterInfo
+{
+ gchar *name;
+ gint version;
+ MSFilterType type;
+ MSFilterNewFunc constructor;
+ char *description; /*some textual information*/
+};
+
+typedef struct _MSFilterInfo MSFilterInfo;
+
+void ms_filter_register(MSFilterInfo *finfo);
+void ms_filter_unregister(MSFilterInfo *finfo);
+MSFilterInfo * ms_filter_get_by_name(const gchar *name);
+
+MSFilter * ms_filter_new_with_name(const gchar *name);
+
+
+
+extern GList *filter_list;
+#define MS_FILTER_INFO(obj) ((MSFilterInfo*)obj)
+
+void swap_buffer(gchar *buffer, gint len);
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c
new file mode 100644
index 00000000..b2dfff98
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.c
@@ -0,0 +1,194 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+
+#ifdef HAVE_ILBC
+
+
+#include "msilbcdec.h"
+#include "msilbcenc.h"
+#include "mscodec.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+
+extern MSFilter * ms_ilbc_encoder_new(void);
+
+MSCodecInfo ilbc_info={
+ {
+ "iLBC codec",
+ 0,
+ MS_FILTER_AUDIO_CODEC,
+ ms_ilbc_encoder_new,
+ "A speech codec suitable for robust voice communication over IP"
+ },
+ ms_ilbc_encoder_new,
+ ms_ilbc_decoder_new,
+ 0, /* not applicable, 2 modes */
+ 0, /* not applicable, 2 modes */
+ 15200,
+ 8000,
+ 97,
+ "iLBC",
+ 1,
+ 1,
+};
+
+
+void ms_ilbc_codec_init()
+{
+ ms_filter_register(MS_FILTER_INFO(&ilbc_info));
+}
+
+
+
+static MSILBCDecoderClass *ms_ilbc_decoder_class=NULL;
+
+MSFilter * ms_ilbc_decoder_new(void)
+{
+ MSILBCDecoder *r;
+
+ r=g_new(MSILBCDecoder,1);
+ ms_ilbc_decoder_init(r);
+ if (ms_ilbc_decoder_class==NULL)
+ {
+ ms_ilbc_decoder_class=g_new(MSILBCDecoderClass,1);
+ ms_ilbc_decoder_class_init(ms_ilbc_decoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_decoder_class);
+ return(MS_FILTER(r));
+}
+
+
+int ms_ilbc_decoder_set_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FMTP:
+ if (value == NULL) return 0;
+ if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
+ else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
+ else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
+ break;
+ }
+ return 0;
+}
+int ms_ilbc_decoder_get_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FMTP:
+ if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
+ if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
+ break;
+ }
+ return 0;
+}
+
+void ms_ilbc_decoder_setup(MSILBCDecoder *r)
+{
+ MSFilterClass *klass = NULL;
+ switch (r->ms_per_frame) {
+ case 20:
+ r->samples_per_frame = BLOCKL_20MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
+ break;
+ case 30:
+ r->samples_per_frame = BLOCKL_30MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
+ break;
+ default:
+ g_error("ms_ilbc_decoder_setup: Bad value for ptime (%i)",r->ms_per_frame);
+ }
+ g_message("Using ilbc decoder with %i ms frames mode.",r->ms_per_frame);
+ initDecode(&r->ilbc_dec, r->ms_per_frame /* ms frames */, /* user enhancer */ 0);
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_ilbc_decoder_init(MSILBCDecoder *r)
+{
+ /* default bitrate */
+ r->bitrate = 15200;
+ r->ms_per_frame = 30;
+ r->samples_per_frame = BLOCKL_20MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
+
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->inqueues=r->q_inputs;
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ memset(r->q_inputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
+}
+
+void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCDec");
+ MS_FILTER_CLASS(klass)->max_qinputs=MSILBCDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSILBCDECODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->w_maxgran= ILBC_MAX_SAMPLES_PER_FRAME*2;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_decoder_destroy;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_decoder_set_property;
+ MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_decoder_get_property;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_decoder_setup;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_decoder_process;
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
+}
+
+void ms_ilbc_decoder_process(MSILBCDecoder *r)
+{
+ MSFifo *fo;
+ MSQueue *qi;
+ int err1;
+ void *dst=NULL;
+ float speech[ILBC_MAX_SAMPLES_PER_FRAME];
+ MSMessage *m;
+
+ qi=r->q_inputs[0];
+ fo=r->f_outputs[0];
+ m=ms_queue_get(qi);
+
+ ms_fifo_get_write_ptr(fo, r->samples_per_frame*2, &dst);
+ if (dst!=NULL){
+ if (m->data!=NULL){
+ if (m->size<r->bytes_per_compressed_frame) {
+ g_warning("Invalid ilbc frame ?");
+ }
+ iLBC_decode(speech, m->data, &r->ilbc_dec, /* mode */1);
+ }else{
+ iLBC_decode(speech,NULL, &r->ilbc_dec,0);
+ }
+ ilbc_write_16bit_samples((gint16*)dst, speech, r->samples_per_frame);
+ }
+ ms_message_destroy(m);
+}
+
+void ms_ilbc_decoder_uninit(MSILBCDecoder *obj)
+{
+}
+
+void ms_ilbc_decoder_destroy( MSILBCDecoder *obj)
+{
+ ms_ilbc_decoder_uninit(obj);
+ g_free(obj);
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h
new file mode 100644
index 00000000..c219aabe
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcdec.h
@@ -0,0 +1,72 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSILBCDECODER_H
+#define MSILBCDECODER_H
+
+#include <msfilter.h>
+#include <mscodec.h>
+#include <iLBC_decode.h>
+
+/*this is the class that implements a ILBCdecoder filter*/
+
+#define MSILBCDECODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSILBCDecoder
+{
+ /* the MSILBCDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCDecoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSQueue *q_inputs[MSILBCDECODER_MAX_INPUTS];
+ MSFifo *f_outputs[MSILBCDECODER_MAX_INPUTS];
+ iLBC_Dec_Inst_t ilbc_dec;
+ int bitrate;
+ int ms_per_frame;
+ int samples_per_frame;
+ int bytes_per_compressed_frame;
+} MSILBCDecoder;
+
+typedef struct _MSILBCDecoderClass
+{
+ /* the MSILBCDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCDecoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSILBCDecoderClass;
+
+/* PUBLIC */
+
+/* call this before if don't load the plugin dynamically */
+void ms_ilbc_codec_init();
+
+#define MS_ILBCDECODER(filter) ((MSILBCDecoder*)(filter))
+#define MS_ILBCDECODER_CLASS(klass) ((MSILBCDecoderClass*)(klass))
+MSFilter * ms_ilbc_decoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_ilbc_decoder_init(MSILBCDecoder *r);
+void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass);
+void ms_ilbc_decoder_destroy( MSILBCDecoder *obj);
+void ms_ilbc_decoder_process(MSILBCDecoder *r);
+
+extern MSCodecInfo ilbc_info;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c
new file mode 100644
index 00000000..76d8b648
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.c
@@ -0,0 +1,244 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+
+#ifdef HAVE_ILBC
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "msilbcenc.h"
+
+
+extern MSCodecInfo ilbc_info;
+
+/* The return value of each of these calls is the same as that
+ returned by fread/fwrite, which should be the number of samples
+ successfully read/written, not the number of bytes. */
+
+int
+ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n)
+{
+ int i;
+
+ /* Convert 16 bit integer samples to floating point values in the
+ range [-1,+1]. */
+
+ for (i = 0; i < n; i++) {
+ speech[i] = int16samples[i];
+ }
+
+ return (n);
+}
+
+
+
+int
+ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n)
+{
+ int i;
+ float real_sample;
+
+ /* Convert floating point samples in range [-1,+1] to 16 bit
+ integers. */
+ for (i = 0; i < n; i++) {
+ float dtmp=speech[i];
+ if (dtmp<MIN_SAMPLE)
+ dtmp=MIN_SAMPLE;
+ else if (dtmp>MAX_SAMPLE)
+ dtmp=MAX_SAMPLE;
+ int16samples[i] = (short) dtmp;
+ }
+ return (n);
+}
+
+/*
+
+Write the bits in bits[0] through bits[len-1] to file f, in "packed"
+format.
+
+bits is expected to be an array of len integer values, where each
+integer is 0 to represent a 0 bit, and any other value represents a 1
+bit. This bit string is written to the file f in the form of several
+8 bit characters. If len is not a multiple of 8, then the last
+character is padded with 0 bits -- the padding is in the least
+significant bits of the last byte. The 8 bit characters are "filled"
+in order from most significant bit to least significant.
+
+*/
+
+void
+ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes)
+{
+ memcpy(data, bits, nbytes);
+}
+
+
+
+/*
+
+Read bits from file f into bits[0] through bits[len-1], in "packed"
+format.
+
+*/
+
+int
+ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes)
+{
+
+ memcpy(bits, data, nbytes);
+
+ return (nbytes);
+}
+
+
+
+
+static MSILBCEncoderClass *ms_ilbc_encoder_class=NULL;
+
+MSFilter * ms_ilbc_encoder_new(void)
+{
+ MSILBCEncoder *r;
+
+ r=g_new(MSILBCEncoder,1);
+ ms_ilbc_encoder_init(r);
+ if (ms_ilbc_encoder_class==NULL)
+ {
+ ms_ilbc_encoder_class=g_new(MSILBCEncoderClass,1);
+ ms_ilbc_encoder_class_init(ms_ilbc_encoder_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_encoder_class);
+ return(MS_FILTER(r));
+}
+
+
+int ms_ilbc_encoder_set_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FMTP:
+ if (value == NULL) return 0;
+ if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
+ else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
+ else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
+ break;
+ }
+ return 0;
+}
+
+
+int ms_ilbc_encoder_get_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FMTP:
+ if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
+ if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
+ break;
+ }
+ return 0;
+}
+
+void ms_ilbc_encoder_setup(MSILBCEncoder *r)
+{
+ MSFilterClass *klass = NULL;
+ switch (r->ms_per_frame) {
+ case 20:
+ r->samples_per_frame = BLOCKL_20MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
+ break;
+ case 30:
+ r->samples_per_frame = BLOCKL_30MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
+ break;
+ default:
+ g_error("Bad bitrate value (%i) for ilbc encoder!", r->ms_per_frame);
+ break;
+ }
+ MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
+ g_message("Using ilbc encoder with %i ms frames mode.",r->ms_per_frame);
+ initEncode(&r->ilbc_enc, r->ms_per_frame /* ms frames */);
+}
+
+/* FOR INTERNAL USE*/
+void ms_ilbc_encoder_init(MSILBCEncoder *r)
+{
+ /* default bitrate */
+ r->bitrate = 15200;
+ r->ms_per_frame = 20;
+ r->samples_per_frame = BLOCKL_20MS;
+ r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
+
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->outqueues=r->q_outputs;
+ MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
+ memset(r->q_outputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
+}
+
+void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCEnc");
+ MS_FILTER_CLASS(klass)->max_finputs=MSILBCENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_qoutputs=MSILBCENCODER_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=ILBC_MAX_SAMPLES_PER_FRAME*2;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_encoder_set_property;
+ MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_encoder_get_property;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_encoder_setup;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_encoder_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_encoder_process;
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
+}
+
+void ms_ilbc_encoder_process(MSILBCEncoder *r)
+{
+ MSFifo *fi;
+ MSQueue *qo;
+ MSMessage *m;
+ void *src=NULL;
+ float speech[ILBC_MAX_SAMPLES_PER_FRAME];
+
+ /* process output fifos, but there is only one for this class of filter*/
+
+ qo=r->q_outputs[0];
+ fi=r->f_inputs[0];
+ ms_fifo_get_read_ptr(fi,r->samples_per_frame*2,&src);
+ if (src==NULL) {
+ g_warning( "src=%p\n", src);
+ return;
+ }
+ m=ms_message_new(r->bytes_per_compressed_frame);
+
+ ilbc_read_16bit_samples((gint16*)src, speech, r->samples_per_frame);
+ iLBC_encode((unsigned char *)m->data, speech, &r->ilbc_enc);
+ ms_queue_put(qo,m);
+}
+
+void ms_ilbc_encoder_uninit(MSILBCEncoder *obj)
+{
+}
+
+void ms_ilbc_encoder_destroy( MSILBCEncoder *obj)
+{
+ ms_ilbc_encoder_uninit(obj);
+ g_free(obj);
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h
new file mode 100644
index 00000000..bd8f3bf5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msilbcenc.h
@@ -0,0 +1,84 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSILBCENCODER_H
+#define MSILBCENCODER_H
+
+#include "mscodec.h"
+#include <iLBC_encode.h>
+
+#define ILBC_BITS_IN_COMPRESSED_FRAME 400
+
+int
+ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n);
+
+int
+ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n);
+
+void
+ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes);
+
+int
+ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes);
+
+
+/*this is the class that implements a ILBCencoder filter*/
+
+#define MSILBCENCODER_MAX_INPUTS 1 /* max output per filter*/
+
+
+typedef struct _MSILBCEncoder
+{
+ /* the MSILBCEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCEncoder object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSILBCENCODER_MAX_INPUTS];
+ MSQueue *q_outputs[MSILBCENCODER_MAX_INPUTS];
+ iLBC_Enc_Inst_t ilbc_enc;
+ int ilbc_encoded_bytes;
+ int bitrate;
+ int ms_per_frame;
+ int samples_per_frame;
+ int bytes_per_compressed_frame;
+} MSILBCEncoder;
+
+typedef struct _MSILBCEncoderClass
+{
+ /* the MSILBCEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCEncoder class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSILBCEncoderClass;
+
+/* PUBLIC */
+#define MS_ILBCENCODER(filter) ((MSILBCEncoder*)(filter))
+#define MS_ILBCENCODER_CLASS(klass) ((MSILBCEncoderClass*)(klass))
+MSFilter * ms_ilbc_encoder_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_ilbc_encoder_init(MSILBCEncoder *r);
+void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass);
+void ms_ilbc_encoder_destroy( MSILBCEncoder *obj);
+void ms_ilbc_encoder_process(MSILBCEncoder *r);
+
+#define ILBC_MAX_BYTES_PER_COMPRESSED_FRAME NO_OF_BYTES_30MS
+#define ILBC_MAX_SAMPLES_PER_FRAME BLOCKL_30MS
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c
new file mode 100644
index 00000000..af5141c0
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.c
@@ -0,0 +1,82 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msnosync.h"
+
+static MSNoSyncClass *ms_nosync_class=NULL;
+
+void ms_nosync_init(MSNoSync *sync)
+{
+ ms_sync_init(MS_SYNC(sync));
+ MS_SYNC(sync)->attached_filters=sync->filters;
+ memset(sync->filters,0,MSNOSYNC_MAX_FILTERS*sizeof(MSFilter*));
+ MS_SYNC(sync)->samples_per_tick=160;
+ sync->started=0;
+}
+
+void ms_nosync_class_init(MSNoSyncClass *klass)
+{
+ ms_sync_class_init(MS_SYNC_CLASS(klass));
+ MS_SYNC_CLASS(klass)->max_filters=MSNOSYNC_MAX_FILTERS;
+ MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_nosync_synchronize;
+ MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_nosync_destroy;
+ /* no need to overload these function*/
+ MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
+ MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
+}
+
+void ms_nosync_destroy(MSNoSync *nosync)
+{
+ g_free(nosync);
+}
+
+/* the synchronization function that does nothing*/
+void ms_nosync_synchronize(MSNoSync *nosync)
+{
+ gint32 time;
+ if (nosync->started==0){
+ gettimeofday(&nosync->start,NULL);
+ nosync->started=1;
+ }
+ gettimeofday(&nosync->current,NULL);
+ MS_SYNC(nosync)->ticks++;
+ /* update the time, we are supposed to work at 8000 Hz */
+ time=((nosync->current.tv_sec-nosync->start.tv_sec)*1000) +
+ ((nosync->current.tv_usec-nosync->start.tv_usec)/1000);
+ MS_SYNC(nosync)->time=time;
+ return;
+}
+
+
+MSSync *ms_nosync_new()
+{
+ MSNoSync *nosync;
+
+ nosync=g_malloc(sizeof(MSNoSync));
+ ms_nosync_init(nosync);
+ if (ms_nosync_class==NULL)
+ {
+ ms_nosync_class=g_new(MSNoSyncClass,1);
+ ms_nosync_class_init(ms_nosync_class);
+ }
+ MS_SYNC(nosync)->klass=MS_SYNC_CLASS(ms_nosync_class);
+ return(MS_SYNC(nosync));
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h
new file mode 100644
index 00000000..eef52d45
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msnosync.h
@@ -0,0 +1,60 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "mssync.h"
+
+#include <sys/time.h>
+#define MSNOSYNC_MAX_FILTERS 10
+
+/* MSNoSync derivates from MSSync base class*/
+
+typedef struct _MSNoSync
+{
+ /* the MSSync must be the first field of the object in order to the object mechanism to work*/
+ MSSync sync;
+ MSFilter *filters[MSNOSYNC_MAX_FILTERS];
+ int started;
+ struct timeval start,current;
+} MSNoSync;
+
+
+typedef struct _MSNoSyncClass
+{
+ /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
+ MSSyncClass parent_class;
+} MSNoSyncClass;
+
+
+/*private*/
+
+void ms_nosync_init(MSNoSync *sync);
+void ms_nosync_class_init(MSNoSyncClass *sync);
+
+void ms_nosync_destroy(MSNoSync *nosync);
+void ms_nosync_synchronize(MSNoSync *nosync);
+
+/*public*/
+
+/* casts a MSSync object into a MSNoSync */
+#define MS_NOSYNC(sync) ((MSNoSync*)(sync))
+/* casts a MSSync class into a MSNoSync class */
+#define MS_NOSYNC_CLASS(klass) ((MSNoSyncClass*)(klass))
+
+MSSync *ms_nosync_new();
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c
new file mode 100644
index 00000000..2486c736
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.c
@@ -0,0 +1,148 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msossread.h"
+#include "mssync.h"
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+MSFilterInfo oss_read_info={
+ "OSS read",
+ 0,
+ MS_FILTER_AUDIO_IO,
+ ms_oss_read_new,
+ NULL
+};
+
+static MSOssReadClass *msossreadclass=NULL;
+
+MSFilter * ms_oss_read_new()
+{
+ MSOssRead *w;
+
+ if (msossreadclass==NULL)
+ {
+ msossreadclass=g_new(MSOssReadClass,1);
+ ms_oss_read_class_init( msossreadclass );
+ }
+
+ w=g_new(MSOssRead,1);
+ MS_FILTER(w)->klass=MS_FILTER_CLASS(msossreadclass);
+ ms_oss_read_init(w);
+
+ return(MS_FILTER(w));
+}
+
+/* FOR INTERNAL USE*/
+void ms_oss_read_init(MSOssRead *w)
+{
+ ms_sound_read_init(MS_SOUND_READ(w));
+ MS_FILTER(w)->outfifos=w->f_outputs;
+ MS_FILTER(w)->outfifos[0]=NULL;
+ w->devid=0;
+ w->sndcard=NULL;
+ w->freq=8000;
+}
+
+gint ms_oss_read_set_property(MSOssRead *f,MSFilterProperty prop, void *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ f->freq=((gint*)value)[0];
+ break;
+ }
+ return 0;
+}
+void ms_oss_read_class_init(MSOssReadClass *klass)
+{
+ ms_sound_read_class_init(MS_SOUND_READ_CLASS(klass));
+ MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_oss_read_setup;
+ MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_oss_read_stop;
+ MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_read_process;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_read_set_property;
+ MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_read_destroy;
+ MS_FILTER_CLASS(klass)->w_maxgran=MS_OSS_READ_MAX_GRAN;
+ MS_FILTER_CLASS(klass)->info=&oss_read_info;
+ MS_SOUND_READ_CLASS(klass)->set_device=(gint (*)(MSSoundRead*,gint))ms_oss_read_set_device;
+ MS_SOUND_READ_CLASS(klass)->start=(void (*)(MSSoundRead*))ms_oss_read_start;
+ MS_SOUND_READ_CLASS(klass)->stop=(void (*)(MSSoundRead*))ms_oss_read_stop;
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssRead");
+ /* //ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_CAN_SYNC|FILTER_IS_SOURCE); */
+}
+
+void ms_oss_read_destroy( MSOssRead *obj)
+{
+ g_free(obj);
+}
+
+void ms_oss_read_process(MSOssRead *f)
+{
+ MSFifo *fifo;
+ char *p;
+ fifo=f->f_outputs[0];
+
+ g_return_if_fail(f->sndcard!=NULL);
+ g_return_if_fail(f->gran>0);
+
+ if (snd_card_can_read(f->sndcard)){
+ int got;
+ ms_fifo_get_write_ptr(fifo,f->gran,(void**)&p);
+ g_return_if_fail(p!=NULL);
+ got=snd_card_read(f->sndcard,p,f->gran);
+ if (got>=0 && got!=f->gran) ms_fifo_update_write_ptr(fifo,got);
+ }
+}
+
+
+void ms_oss_read_start(MSOssRead *r)
+{
+ g_return_if_fail(r->devid!=-1);
+ r->sndcard=snd_card_manager_get_card(snd_card_manager,r->devid);
+ g_return_if_fail(r->sndcard!=NULL);
+ /* open the device for an audio telephony signal with minimum latency */
+ snd_card_open_r(r->sndcard,16,0,r->freq);
+ r->gran=(512*r->freq)/8000;
+
+}
+
+void ms_oss_read_stop(MSOssRead *w)
+{
+ g_return_if_fail(w->devid!=-1);
+ g_return_if_fail(w->sndcard!=NULL);
+ snd_card_close_r(w->sndcard);
+ w->sndcard=NULL;
+}
+
+
+void ms_oss_read_setup(MSOssRead *f, MSSync *sync)
+{
+ f->sync=sync;
+ ms_oss_read_start(f);
+}
+
+
+gint ms_oss_read_set_device(MSOssRead *r,gint devid)
+{
+ r->devid=devid;
+ return 0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h
new file mode 100644
index 00000000..89d5a40b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msossread.h
@@ -0,0 +1,77 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSOSSREAD_H
+#define MSOSSREAD_H
+
+#include "mssoundread.h"
+#include "sndcard.h"
+#include "mssync.h"
+
+
+/*this is the class that implements oss writing sink filter*/
+
+#define MS_OSS_READ_MAX_INPUTS 1 /* max output per filter*/
+
+#define MS_OSS_READ_MAX_GRAN (512*2) /* the maximum granularity*/
+
+struct _MSOssRead
+{
+ /* the MSOssRead derivates from MSSoundRead so the MSSoundRead object MUST be the first of the MSOssRead object
+ in order to the object mechanism to work*/
+ MSSoundRead filter;
+ MSFifo *f_outputs[MS_OSS_READ_MAX_INPUTS];
+ MSSync *sync;
+ SndCard *sndcard;
+ gint freq;
+ gint devid; /* the sound device id it depends on*/
+ gint gran;
+ gint flags;
+#define START_REQUESTED 1
+#define STOP_REQUESTED 2
+};
+
+typedef struct _MSOssRead MSOssRead;
+
+struct _MSOssReadClass
+{
+ /* the MSOssRead derivates from MSSoundRead, so the MSSoundRead class MUST be the first of the MSOssRead class
+ in order to the class mechanism to work*/
+ MSSoundReadClass parent_class;
+};
+
+typedef struct _MSOssReadClass MSOssReadClass;
+
+/* PUBLIC */
+#define MS_OSS_READ(filter) ((MSOssRead*)(filter))
+#define MS_OSS_READ_CLASS(klass) ((MSOssReadClass*)(klass))
+MSFilter * ms_oss_read_new(void);
+gint ms_oss_read_set_device(MSOssRead *w,gint devid);
+void ms_oss_read_start(MSOssRead *w);
+void ms_oss_read_stop(MSOssRead *w);
+
+/* FOR INTERNAL USE*/
+void ms_oss_read_init(MSOssRead *r);
+void ms_oss_read_class_init(MSOssReadClass *klass);
+void ms_oss_read_destroy( MSOssRead *obj);
+void ms_oss_read_process(MSOssRead *f);
+void ms_oss_read_setup(MSOssRead *f, MSSync *sync);
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c
new file mode 100644
index 00000000..cc86cd6b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.c
@@ -0,0 +1,247 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msosswrite.h"
+#include "mssync.h"
+#include <unistd.h>
+#include <math.h>
+
+MSFilterInfo oss_write_info={
+ "OSS write",
+ 0,
+ MS_FILTER_OTHER,
+ ms_oss_write_new,
+ NULL
+};
+
+
+static MSOssWriteClass *msosswriteclass=NULL;
+
+MSFilter * ms_oss_write_new()
+{
+ MSOssWrite *w;
+
+ if (msosswriteclass==NULL)
+ {
+ msosswriteclass=g_new(MSOssWriteClass,1);
+ ms_oss_write_class_init( msosswriteclass );
+ }
+ w=g_new(MSOssWrite,1);
+ MS_FILTER(w)->klass=MS_FILTER_CLASS(msosswriteclass);
+ ms_oss_write_init(w);
+ return(MS_FILTER(w));
+}
+
+/* FOR INTERNAL USE*/
+void ms_oss_write_init(MSOssWrite *w)
+{
+ ms_sound_write_init(MS_SOUND_WRITE(w));
+ MS_FILTER(w)->infifos=w->f_inputs;
+ MS_FILTER(w)->infifos[0]=NULL;
+ MS_FILTER(w)->r_mingran=512; /* very few cards can do that...*/
+ w->devid=0;
+ w->sndcard=NULL;
+ w->freq=8000;
+ w->channels=1;
+ w->dtmf_time=-1;
+}
+
+gint ms_oss_write_set_property(MSOssWrite *f,MSFilterProperty prop, void *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ f->freq=((gint*)value)[0];
+ break;
+ case MS_FILTER_PROPERTY_CHANNELS:
+ f->channels=((gint*)value)[0];
+ break;
+ }
+ return 0;
+}
+
+void ms_oss_write_class_init(MSOssWriteClass *klass)
+{
+ ms_sound_write_class_init(MS_SOUND_WRITE_CLASS(klass));
+ MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo input only */
+ MS_FILTER_CLASS(klass)->r_maxgran=MS_OSS_WRITE_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_write_process;
+ MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_write_destroy;
+ MS_FILTER_CLASS(klass)->setup= (MSFilterSetupFunc)ms_oss_write_setup;
+ MS_FILTER_CLASS(klass)->unsetup= (MSFilterSetupFunc)ms_oss_write_stop;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_write_set_property;
+ MS_FILTER_CLASS(klass)->info=&oss_write_info;
+ MS_SOUND_WRITE_CLASS(klass)->set_device=(gint (*)(MSSoundWrite*,gint))ms_oss_write_set_device;
+ MS_SOUND_WRITE_CLASS(klass)->start=(void (*)(MSSoundWrite*))ms_oss_write_start;
+ MS_SOUND_WRITE_CLASS(klass)->stop=(void (*)(MSSoundWrite*))ms_oss_write_stop;
+ MS_SOUND_WRITE_CLASS(klass)->set_level=(void (*)(MSSoundWrite*, gint))ms_oss_write_set_level;
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssWrite");
+}
+
+void ms_oss_write_destroy( MSOssWrite *obj)
+{
+
+ g_free(obj);
+}
+
+void ms_oss_write_process(MSOssWrite *f)
+{
+ MSFifo *fifo;
+ void *p;
+ int i;
+ gint gran=ms_filter_get_mingran(MS_FILTER(f));
+
+ /* always consume something */
+ fifo=f->f_inputs[0];
+ ms_fifo_get_read_ptr(fifo,gran,&p);
+ if (p==NULL) {
+ g_warning("Not enough data: gran=%i.",gran);
+ return;
+ }
+ g_return_if_fail(f->sndcard!=NULL);
+ if (f->dtmf_time!=-1){
+ gint16 *buf=(gint16*)p;
+ /* generate a DTMF*/
+ for(i=0;i<gran/2;i++){
+ buf[i]=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->lowfreq));
+ buf[i]+=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->highfreq));
+ f->dtmf_time++;
+ /* //printf("buf[%i]=%i\n",i,buf[i]); */
+ }
+ if (f->dtmf_time>f->dtmf_duration) f->dtmf_time=-1; /*finished*/
+ }
+ snd_card_write(f->sndcard,p,gran);
+}
+
+void ms_oss_write_start(MSOssWrite *w)
+{
+ gint bsize;
+ g_return_if_fail(w->devid!=-1);
+ w->sndcard=snd_card_manager_get_card(snd_card_manager,w->devid);
+ g_return_if_fail(w->sndcard!=NULL);
+ /* open the device for an audio telephony signal with minimum latency */
+ snd_card_open_w(w->sndcard,16,w->channels==2,w->freq);
+ w->bsize=snd_card_get_bsize(w->sndcard);
+ /* //MS_FILTER(w)->r_mingran=w->bsize; */
+ /* //ms_sync_set_samples_per_tick(MS_FILTER(w)->sync,bsize); */
+}
+
+void ms_oss_write_stop(MSOssWrite *w)
+{
+ g_return_if_fail(w->devid!=-1);
+ g_return_if_fail(w->sndcard!=NULL);
+ snd_card_close_w(w->sndcard);
+ w->sndcard=NULL;
+}
+
+void ms_oss_write_set_level(MSOssWrite *w,gint a)
+{
+
+}
+
+gint ms_oss_write_set_device(MSOssWrite *w, gint devid)
+{
+ w->devid=devid;
+ return 0;
+}
+
+void ms_oss_write_setup(MSOssWrite *r)
+{
+ /* //g_message("starting MSOssWrite.."); */
+ ms_oss_write_start(r);
+}
+
+
+
+void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf){
+
+ w->dtmf_duration=0.1*w->freq;
+ switch(dtmf){
+ case '0':
+ w->lowfreq=941;
+ w->highfreq=1336;
+ break;
+ case '1':
+ w->lowfreq=697;
+ w->highfreq=1209;
+ break;
+ case '2':
+ w->lowfreq=697;
+ w->highfreq=1336;
+ break;
+ case '3':
+ w->lowfreq=697;
+ w->highfreq=1477;
+ break;
+ case '4':
+ w->lowfreq=770;
+ w->highfreq=1209;
+ break;
+ case '5':
+ w->lowfreq=770;
+ w->highfreq=1336;
+ break;
+ case '6':
+ w->lowfreq=770;
+ w->highfreq=1477;
+ break;
+ case '7':
+ w->lowfreq=852;
+ w->highfreq=1209;
+ break;
+ case '8':
+ w->lowfreq=852;
+ w->highfreq=1336;
+ break;
+ case '9':
+ w->lowfreq=852;
+ w->highfreq=1477;
+ break;
+ case '*':
+ w->lowfreq=941;
+ w->highfreq=1209;
+ break;
+ case '#':
+ w->lowfreq=941;
+ w->highfreq=1477;
+ break;
+ case 'A':
+ w->lowfreq=697;
+ w->highfreq=1633;
+ break;
+ case 'B':
+ w->lowfreq=770;
+ w->highfreq=1633;
+ break;
+ case 'C':
+ w->lowfreq=852;
+ w->highfreq=1633;
+ break;
+ case 'D':
+ w->lowfreq=941;
+ w->highfreq=1633;
+ break;
+ default:
+ g_warning("Not a dtmf key.");
+ return;
+ }
+ w->lowfreq=w->lowfreq/w->freq;
+ w->highfreq=w->highfreq/w->freq;
+ w->dtmf_time=0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h
new file mode 100644
index 00000000..d4775341
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msosswrite.h
@@ -0,0 +1,78 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSOSSWRITE_H
+#define MSOSSWRITE_H
+
+#include "mssoundwrite.h"
+#include "sndcard.h"
+
+/*this is the class that implements oss writing sink filter*/
+
+#define MS_OSS_WRITE_MAX_INPUTS 1 /* max output per filter*/
+
+#define MS_OSS_WRITE_DEF_GRAN (512*2) /* the default granularity*/
+
+struct _MSOssWrite
+{
+ /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite object MUST be the first of the MSOssWrite object
+ in order to the object mechanism to work*/
+ MSSoundWrite filter;
+ MSFifo *f_inputs[MS_OSS_WRITE_MAX_INPUTS];
+ gint devid; /* the sound device id it depends on*/
+ SndCard *sndcard;
+ gint bsize;
+ gint freq;
+ gint channels;
+ gdouble lowfreq;
+ gdouble highfreq;
+ gint dtmf_time;
+ gint dtmf_duration;
+};
+
+typedef struct _MSOssWrite MSOssWrite;
+
+struct _MSOssWriteClass
+{
+ /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite class MUST be the first of the MSOssWrite class
+ in order to the class mechanism to work*/
+ MSSoundWriteClass parent_class;
+};
+
+typedef struct _MSOssWriteClass MSOssWriteClass;
+
+/* PUBLIC */
+#define MS_OSS_WRITE(filter) ((MSOssWrite*)(filter))
+#define MS_OSS_WRITE_CLASS(klass) ((MSOssWriteClass*)(klass))
+MSFilter * ms_oss_write_new(void);
+gint ms_oss_write_set_device(MSOssWrite *w,gint devid);
+void ms_oss_write_start(MSOssWrite *w);
+void ms_oss_write_stop(MSOssWrite *w);
+void ms_oss_write_set_level(MSOssWrite *w, gint level);
+void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf);
+
+/* FOR INTERNAL USE*/
+void ms_oss_write_init(MSOssWrite *r);
+void ms_oss_write_setup(MSOssWrite *r);
+void ms_oss_write_class_init(MSOssWriteClass *klass);
+void ms_oss_write_destroy( MSOssWrite *obj);
+void ms_oss_write_process(MSOssWrite *f);
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c
new file mode 100644
index 00000000..6bd073b9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.c
@@ -0,0 +1,91 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a dispatcher of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msqdispatcher.h"
+
+static MSQdispatcherClass *ms_qdispatcher_class=NULL;
+
+MSFilter * ms_qdispatcher_new(void)
+{
+ MSQdispatcher *obj;
+ obj=g_malloc(sizeof(MSQdispatcher));
+ if (ms_qdispatcher_class==NULL){
+ ms_qdispatcher_class=g_malloc0(sizeof(MSQdispatcherClass));
+ ms_qdispatcher_class_init(ms_qdispatcher_class);
+ }
+ MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_qdispatcher_class);
+ ms_qdispatcher_init(obj);
+ return MS_FILTER(obj);
+}
+
+
+void ms_qdispatcher_init(MSQdispatcher *obj)
+{
+ ms_filter_init(MS_FILTER(obj));
+
+ MS_FILTER(obj)->inqueues=obj->q_inputs;
+ MS_FILTER(obj)->outqueues=obj->q_outputs;
+ memset(obj->q_inputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_INPUTS);
+ memset(obj->q_outputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_OUTPUTS);
+}
+
+
+
+void ms_qdispatcher_class_init(MSQdispatcherClass *klass)
+{
+ MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
+ ms_filter_class_init(parent_class);
+ ms_filter_class_set_name(parent_class,"qdispatcher");
+ parent_class->max_qinputs=MS_QDISPATCHER_MAX_INPUTS;
+ parent_class->max_qoutputs=MS_QDISPATCHER_MAX_OUTPUTS;
+
+ parent_class->destroy=(MSFilterDestroyFunc)ms_qdispatcher_destroy;
+ parent_class->process=(MSFilterProcessFunc)ms_qdispatcher_process;
+}
+
+
+void ms_qdispatcher_destroy( MSQdispatcher *obj)
+{
+ g_free(obj);
+}
+
+void ms_qdispatcher_process(MSQdispatcher *obj)
+{
+ gint i;
+ MSQueue *inq=obj->q_inputs[0];
+
+ if (inq!=NULL){
+ MSQueue *outq;
+ MSMessage *m1,*m2;
+ while ( (m1=ms_queue_get(inq))!=NULL){
+ /* dispatch incoming messages to output queues */
+ for (i=0;i<MS_QDISPATCHER_MAX_OUTPUTS;i++){
+ outq=obj->q_outputs[i];
+ if (outq!=NULL){
+ m2=ms_message_dup(m1);
+ ms_queue_put(outq,m2);
+ }
+ }
+ ms_message_destroy(m1);
+ }
+ }
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h
new file mode 100644
index 00000000..3b0c566d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqdispatcher.h
@@ -0,0 +1,60 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a dispatcher of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSQDISPATCHER_H
+#define MSQDISPATCHER_H
+
+#include "msfilter.h"
+
+
+/*this is the class that implements a qdispatcher filter*/
+
+#define MS_QDISPATCHER_MAX_INPUTS 1
+#define MS_QDISPATCHER_MAX_OUTPUTS 5
+
+typedef struct _MSQdispatcher
+{
+ /* the MSQdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSQdispatcher object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSQueue *q_inputs[MS_QDISPATCHER_MAX_INPUTS];
+ MSQueue *q_outputs[MS_QDISPATCHER_MAX_OUTPUTS];
+} MSQdispatcher;
+
+typedef struct _MSQdispatcherClass
+{
+ /* the MSQdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSQdispatcher class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSQdispatcherClass;
+
+/* PUBLIC */
+#define MS_QDISPATCHER(filter) ((MSQdispatcher*)(filter))
+#define MS_QDISPATCHER_CLASS(klass) ((MSQdispatcherClass*)(klass))
+MSFilter * ms_qdispatcher_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_qdispatcher_init(MSQdispatcher *r);
+void ms_qdispatcher_class_init(MSQdispatcherClass *klass);
+void ms_qdispatcher_destroy( MSQdispatcher *obj);
+void ms_qdispatcher_process(MSQdispatcher *r);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c
new file mode 100644
index 00000000..46368956
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.c
@@ -0,0 +1,56 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msqueue.h"
+#include <string.h>
+
+MSQueue * ms_queue_new()
+{
+ MSQueue *q=g_malloc(sizeof(MSQueue));
+ memset(q,0,sizeof(MSQueue));
+ return q;
+}
+
+MSMessage *ms_queue_get(MSQueue *q)
+{
+ MSMessage *b=q->last;
+ if (b==NULL) return NULL;
+ q->last=b->prev;
+ if (b->prev==NULL) q->first=NULL; /* it was the only element of the queue*/
+ q->size--;
+ b->next=b->prev=NULL;
+ return(b);
+}
+
+void ms_queue_put(MSQueue *q, MSMessage *m)
+{
+ MSMessage *mtmp=q->first;
+ g_return_if_fail(m!=NULL);
+ q->first=m;
+ m->next=mtmp;
+ if (mtmp!=NULL)
+ {
+ mtmp->prev=m;
+ }
+ else q->last=m; /* it was the first element of the q */
+ q->size++;
+}
+
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h
new file mode 100644
index 00000000..73ab8d8d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msqueue.h
@@ -0,0 +1,49 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSQUEUE_H
+#define MSQUEUE_H
+
+#include "msbuffer.h"
+
+/* for the moment these are stupid queues limited to one element*/
+
+typedef struct _MSQueue
+{
+ MSMessage *first;
+ MSMessage *last;
+ gint size;
+ void *prev_data; /*user data, usually the writting filter*/
+ void *next_data; /* user data, usually the reading filter*/
+}MSQueue;
+
+
+MSQueue * ms_queue_new();
+
+MSMessage *ms_queue_get(MSQueue *q);
+
+void ms_queue_put(MSQueue *q, MSMessage *m);
+
+#define ms_queue_can_get(q) ( (q)->size!=0 )
+
+#define ms_queue_destroy(q) g_free(q)
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c
new file mode 100644
index 00000000..6f0ec99d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.c
@@ -0,0 +1,182 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msread.h"
+#include "mssync.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+static MSReadClass *ms_read_class=NULL;
+
+MSFilter * ms_read_new(char *name)
+{
+ MSRead *r;
+ int fd=-1;
+
+ r=g_new(MSRead,1);
+ ms_read_init(r);
+ if (ms_read_class==NULL)
+ {
+ ms_read_class=g_new(MSReadClass,1);
+ ms_read_class_init(ms_read_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_read_class);
+ r->fd=-1;
+ if (name!=NULL) ms_read_open(r,name);
+ return(MS_FILTER(r));
+}
+
+
+
+gint ms_read_open(MSRead *r, gchar *name)
+{
+ gint fd;
+ fd=open(name,O_RDONLY);
+ if (fd<0) {
+ r->fd=-1;
+ g_warning("ms_read_new: cannot open %s : %s",name,strerror(errno));
+ return -1;
+ }
+ r->fd=fd;
+ if (strstr(name,".wav")!=NULL){
+ /* skip the header */
+ lseek(fd,20,SEEK_SET);
+#ifdef WORDS_BIGENDIAN
+ r->need_swap=1;
+#else
+ r->need_swap=0;
+#endif
+ }
+ r->state=MS_READ_STATE_STARTED;
+ return 0;
+}
+
+/* FOR INTERNAL USE*/
+void ms_read_init(MSRead *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->outfifos=r->foutputs;
+ MS_FILTER(r)->outqueues=r->qoutputs;
+ memset(r->foutputs,0,sizeof(MSFifo*)*MSREAD_MAX_OUTPUTS);
+ memset(r->qoutputs,0,sizeof(MSQueue*)*MSREAD_MAX_OUTPUTS);
+ r->fd=-1;
+ r->gran=320;
+ r->state=MS_READ_STATE_STOPPED;
+ r->need_swap=0;
+ r->rate=8000;
+}
+
+gint ms_read_set_property(MSRead *f,MSFilterProperty prop, void *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ f->rate=((gint*)value)[0];
+ break;
+ }
+ return 0;
+}
+
+void ms_read_class_init(MSReadClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskreader");
+ ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
+ MS_FILTER_CLASS(klass)->max_foutputs=MSREAD_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->max_qoutputs=MSREAD_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->w_maxgran=MSREAD_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_read_destroy;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_read_setup;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_read_process;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_read_set_property;
+}
+
+void ms_read_process(MSRead *r)
+{
+ MSFifo *f;
+ MSQueue *q;
+ MSMessage *msg=NULL;
+ int err;
+ gint gran=r->gran;
+ void *p;
+
+ f=r->foutputs[0];
+ if ((f!=NULL) && (r->state==MS_READ_STATE_STARTED))
+ {
+ ms_fifo_get_write_ptr(f,gran,&p);
+ if (p!=NULL)
+ {
+ err=read(r->fd,p,gran);
+ if (err<0)
+ {
+ /* temp: */
+ g_warning("ms_read_process: failed to read: %s.\n",strerror(errno));
+ }
+ else if (err<gran){
+ ms_trace("ms_read_process: end of file.");
+ ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
+ r->state=MS_READ_STATE_STOPPED;
+ close(r->fd);
+ r->fd=-1;
+ }
+ if (r->need_swap) swap_buffer(p,gran);
+ }
+ }
+ /* process output queues*/
+ q=r->qoutputs[0];
+ if ((q!=NULL) && (r->fd>0))
+ {
+ msg=ms_message_new(r->gran);
+ err=read(r->fd,msg->data,r->gran);
+ if (err>0){
+ msg->size=err;
+ ms_queue_put(q,msg);
+ if (r->need_swap) swap_buffer(msg->data,r->gran);
+ }else{
+ ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
+ ms_trace("End of file reached.");
+ r->state=MS_READ_STATE_STOPPED;
+ }
+ }
+}
+
+void ms_read_destroy( MSRead *obj)
+{
+ if (obj->fd!=0) close(obj->fd);
+ g_free(obj);
+}
+
+gint ms_read_close(MSRead *obj)
+{
+ if (obj->fd!=0) {
+ close(obj->fd);
+ obj->fd=-1;
+ obj->state=MS_READ_STATE_STOPPED;
+ }
+}
+
+
+void ms_read_setup(MSRead *r, MSSync *sync)
+{
+ r->sync=sync;
+ r->gran=(r->rate*sync->interval/1000)*2;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h
new file mode 100644
index 00000000..93177f38
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msread.h
@@ -0,0 +1,80 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSREAD_H
+#define MSREAD_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+/*this is the class that implements file reading source filter*/
+
+#define MSREAD_MAX_OUTPUTS 1 /* max output per filter*/
+
+#define MSREAD_DEF_GRAN 640 /* the default granularity*/
+
+typedef enum{
+ MS_READ_STATE_STARTED,
+ MS_READ_STATE_STOPPED,
+ MS_READ_STATE_EOF
+}MSReadState;
+
+typedef struct _MSRead
+{
+ /* the MSRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSRead object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *foutputs[MSREAD_MAX_OUTPUTS];
+ MSQueue *qoutputs[MSREAD_MAX_OUTPUTS];
+ MSSync *sync;
+ gint rate;
+ gint fd; /* the file descriptor of the file being read*/
+ gint gran; /*granularity*/ /* for use with queues */
+ gint need_swap;
+ gint state;
+} MSRead;
+
+typedef struct _MSReadClass
+{
+ /* the MSRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSRead class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSReadClass;
+
+/* PUBLIC */
+#define MS_READ(filter) ((MSRead*)(filter))
+#define MS_READ_CLASS(klass) ((MSReadClass*)(klass))
+MSFilter * ms_read_new(char *name);
+/* set the granularity for reading file on disk */
+#define ms_read_set_bufsize(filter,sz) (filter)->gran=(sz)
+
+/* FOR INTERNAL USE*/
+void ms_read_init(MSRead *r);
+void ms_read_class_init(MSReadClass *klass);
+void ms_read_destroy( MSRead *obj);
+void ms_read_process(MSRead *r);
+void ms_read_setup(MSRead *r, MSSync *sync);
+
+typedef enum{
+ MS_READ_EVENT_EOF /* end of file */
+} MSReadEvent;
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c
new file mode 100644
index 00000000..fb2006e8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.c
@@ -0,0 +1,246 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msringplayer.h"
+#include "mssync.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "waveheader.h"
+
+#define WAVE_HEADER_OFFSET sizeof(wave_header_t)
+
+enum { PLAY_RING, PLAY_SILENCE};
+
+static int supported_freq[6]={8000,11025,16000,22050,32000,44100};
+
+gint freq_is_supported(gint freq){
+ int i;
+ for (i=0;i<6;i++){
+ if (abs(supported_freq[i]-freq)<50) return supported_freq[i];
+ }
+ return 0;
+}
+
+static MSRingPlayerClass *ms_ring_player_class=NULL;
+
+/**
+ * ms_ring_player_new:
+ * @name: The path to the 16-bit 8khz raw file to be played as a ring.
+ * @seconds: The number of seconds that separates two rings.
+ *
+ * Allocates a new MSRingPlayer object.
+ *
+ *
+ * Returns: a pointer the the object, NULL if name could not be open.
+ */
+MSFilter * ms_ring_player_new(char *name, gint seconds)
+{
+ MSRingPlayer *r;
+ int fd=-1;
+
+ if ((name!=NULL) && (strlen(name)!=0))
+ {
+ fd=open(name,O_RDONLY);
+ if (fd<0)
+ {
+ g_warning("ms_ring_player_new: failed to open %s.\n",name);
+ return NULL;
+ }
+
+ }else {
+ g_warning("ms_ring_player_new: Bad file name");
+ return NULL;
+ }
+
+ r=g_new(MSRingPlayer,1);
+ ms_ring_player_init(r);
+ if (ms_ring_player_class==NULL)
+ {
+ ms_ring_player_class=g_new(MSRingPlayerClass,1);
+ ms_ring_player_class_init(ms_ring_player_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ring_player_class);
+
+ r->fd=fd;
+ r->silence=seconds;
+ r->freq=8000;
+ if (strstr(name,".wav")!=NULL){
+ wave_header_t header;
+ int freq,freq2;
+ /* read the header */
+ read(fd,&header,sizeof(wave_header_t));
+ freq=wave_header_get_rate(&header);
+ if ((freq2=freq_is_supported(freq))>0){
+ r->freq=freq2;
+ }else {
+ g_warning("Unsupported sampling rate %i",freq);
+ r->freq=8000;
+ }
+ r->channel=wave_header_get_channel(&header);
+ lseek(fd,WAVE_HEADER_OFFSET,SEEK_SET);
+#ifdef WORDS_BIGENDIAN
+ r->need_swap=1;
+#else
+ r->need_swap=0;
+#endif
+ }
+ ms_ring_player_set_property(r, MS_FILTER_PROPERTY_FREQ,&r->freq);
+ r->state=PLAY_RING;
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_ring_player_init(MSRingPlayer *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->outfifos=r->foutputs;
+ MS_FILTER(r)->outqueues=r->qoutputs;
+ memset(r->foutputs,0,sizeof(MSFifo*)*MS_RING_PLAYER_MAX_OUTPUTS);
+ memset(r->qoutputs,0,sizeof(MSQueue*)*MS_RING_PLAYER_MAX_OUTPUTS);
+ r->fd=-1;
+ r->current_pos=0;
+ r->need_swap=0;
+ r->sync=NULL;
+}
+
+gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ f->rate=((gint*)value)[0]*2;
+ f->silence_bytes=f->silence*f->rate;
+ if (f->sync!=NULL)
+ f->gran=(f->rate*f->sync->interval/1000)*2;
+ break;
+ }
+ return 0;
+}
+
+gint ms_ring_player_get_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
+{
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ ((gint*)value)[0]=f->freq;
+
+ break;
+ case MS_FILTER_PROPERTY_CHANNELS:
+ ((gint*)value)[0]=f->channel;
+ break;
+ }
+ return 0;
+}
+
+gint ms_ring_player_get_sample_freq(MSRingPlayer *obj){
+ return obj->freq;
+}
+
+
+void ms_ring_player_class_init(MSRingPlayerClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ringplay");
+ ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
+ MS_FILTER_CLASS(klass)->max_foutputs=MS_RING_PLAYER_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->max_qoutputs=MS_RING_PLAYER_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->w_maxgran=MS_RING_PLAYER_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ring_player_setup;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ring_player_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ring_player_process;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ring_player_set_property;
+ MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ring_player_get_property;
+}
+
+void ms_ring_player_process(MSRingPlayer *r)
+{
+ MSFifo *f;
+ gint err;
+ gint processed=0;
+ gint gran=r->gran;
+ char *p;
+
+ g_return_if_fail(gran>0);
+ /* process output fifos*/
+
+ f=r->foutputs[0];
+ ms_fifo_get_write_ptr(f,gran,(void**)&p);
+ g_return_if_fail(p!=NULL);
+ for (processed=0;processed<gran;){
+ switch(r->state){
+ case PLAY_RING:
+ err=read(r->fd,&p[processed],gran-processed);
+ if (err<0)
+ {
+ memset(&p[processed],0,gran-processed);
+ processed=gran;
+ g_warning("ms_ring_player_process: failed to read: %s.\n",strerror(errno));
+ return;
+ }
+ else if (err<gran)
+ {/* end of file */
+
+ r->current_pos=r->silence_bytes;
+ lseek(r->fd,WAVE_HEADER_OFFSET,SEEK_SET);
+ r->state=PLAY_SILENCE;
+ ms_filter_notify_event(MS_FILTER(r),MS_RING_PLAYER_END_OF_RING_EVENT,NULL);
+ }
+ if (r->need_swap) swap_buffer(&p[processed],err);
+ processed+=err;
+ break;
+ case PLAY_SILENCE:
+ err=gran-processed;
+ if (r->current_pos>err){
+ memset(&p[processed],0,err);
+ r->current_pos-=gran;
+ processed=gran;
+ }else{
+ memset(&p[processed],0,r->current_pos);
+ processed+=r->current_pos;
+ r->state=PLAY_RING;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * ms_ring_player_destroy:
+ * @obj: A valid MSRingPlayer object.
+ *
+ * Destroy a MSRingPlayer object.
+ *
+ *
+ */
+
+void ms_ring_player_destroy( MSRingPlayer *obj)
+{
+ if (obj->fd!=0) close(obj->fd);
+ g_free(obj);
+}
+
+void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync)
+{
+ r->sync=sync;
+ r->gran=(r->rate*r->sync->interval/1000)*r->channel;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h
new file mode 100644
index 00000000..1f5e67da
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msringplayer.h
@@ -0,0 +1,81 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSRINGPLAYER_H
+#define MSRINGPLAYER_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+
+/*this is the class that implements file reading source filter*/
+
+#define MS_RING_PLAYER_MAX_OUTPUTS 1 /* max output per filter*/
+
+#define MS_RING_PLAYER_DEF_GRAN 8192 /* the default granularity*/
+
+#define MS_RING_PLAYER_END_OF_RING_EVENT 1
+
+struct _MSRingPlayer
+{
+ /* the MSRingPlayer derivates from MSFilter, so the MSFilter object MUST be the first of the MSRingPlayer object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *foutputs[MS_RING_PLAYER_MAX_OUTPUTS];
+ MSQueue *qoutputs[MS_RING_PLAYER_MAX_OUTPUTS];\
+ MSSync *sync;
+ gint gran;
+ gint freq;
+ gint rate;
+ gint channel; /* number of interleaved channels */
+ gint silence; /* silence time between each ring, in seconds */
+ gint state;
+ gint fd; /* the file descriptor of the file being read*/
+ gint silence_bytes; /*silence in number of bytes between each ring */
+ gint current_pos;
+ gint need_swap;
+};
+
+typedef struct _MSRingPlayer MSRingPlayer;
+
+struct _MSRingPlayerClass
+{
+ /* the MSRingPlayer derivates from MSFilter, so the MSFilter class MUST be the first of the MSRingPlayer class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSRingPlayerClass MSRingPlayerClass;
+
+/* PUBLIC */
+#define MS_RING_PLAYER(filter) ((MSRingPlayer*)(filter))
+#define MS_RING_PLAYER_CLASS(klass) ((MSRingPlayerClass*)(klass))
+MSFilter * ms_ring_player_new(char *name, gint seconds);
+gint ms_ring_player_get_sample_freq(MSRingPlayer *obj);
+
+
+/* FOR INTERNAL USE*/
+void ms_ring_player_init(MSRingPlayer *r);
+void ms_ring_player_class_init(MSRingPlayerClass *klass);
+void ms_ring_player_destroy( MSRingPlayer *obj);
+void ms_ring_player_process(MSRingPlayer *r);
+#define ms_ring_player_set_bufsize(filter,sz) (filter)->gran=(sz)
+void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync);
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c
new file mode 100644
index 00000000..9b82e939
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.c
@@ -0,0 +1,163 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "msrtprecv.h"
+
+
+/* some utilities to convert mblk_t to MSMessage and vice-versa */
+MSMessage *msgb_2_ms_message(mblk_t* mp){
+ MSMessage *msg;
+ MSBuffer *msbuf;
+ if (mp->b_datap->ref_count!=1) return NULL; /* cannot handle properly non-unique buffers*/
+ /* create a MSBuffer using the mblk_t buffer */
+ msg=ms_message_alloc();
+ msbuf=ms_buffer_alloc(0);
+ msbuf->buffer=mp->b_datap->db_base;
+ msbuf->size=(char*)mp->b_datap->db_lim-(char*)mp->b_datap->db_base;
+ ms_message_set_buf(msg,msbuf);
+ msg->size=mp->b_wptr-mp->b_rptr;
+ msg->data=mp->b_rptr;
+ /* free the mblk_t */
+ g_free(mp->b_datap);
+ g_free(mp);
+ return msg;
+}
+
+
+static MSRtpRecvClass *ms_rtp_recv_class=NULL;
+
+MSFilter * ms_rtp_recv_new(void)
+{
+ MSRtpRecv *r;
+
+ r=g_new(MSRtpRecv,1);
+ ms_rtp_recv_init(r);
+ if (ms_rtp_recv_class==NULL)
+ {
+ ms_rtp_recv_class=g_new0(MSRtpRecvClass,1);
+ ms_rtp_recv_class_init(ms_rtp_recv_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_recv_class);
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_rtp_recv_init(MSRtpRecv *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->outfifos=r->f_outputs;
+ MS_FILTER(r)->outqueues=r->q_outputs;
+ memset(r->f_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
+ memset(r->q_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
+ r->rtpsession=NULL;
+ r->stream_started=0;
+}
+
+void ms_rtp_recv_class_init(MSRtpRecvClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPRecv");
+ MS_FILTER_CLASS(klass)->max_qoutputs=MSRTPRECV_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->max_foutputs=MSRTPRECV_MAX_OUTPUTS;
+ MS_FILTER_CLASS(klass)->w_maxgran=MSRTPRECV_DEF_GRAN;
+ ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_recv_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_recv_process;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_recv_setup;
+}
+
+void ms_rtp_recv_process(MSRtpRecv *r)
+{
+ MSFifo *fo;
+ MSQueue *qo;
+ MSSync *sync= r->sync;
+ void *d;
+ mblk_t *mp;
+ gint len;
+ gint gran=ms_sync_get_samples_per_tick(MS_SYNC(sync));
+
+ if (r->rtpsession==NULL) return;
+ /* process output fifo and output queue*/
+ fo=r->f_outputs[0];
+ if (fo!=NULL)
+ {
+ while( (mp=rtp_session_recvm_with_ts(r->rtpsession,r->prev_ts))!=NULL) {
+ /* try to get rtp packets and paste them to the output fifo */
+ r->stream_started=1;
+ len=mp->b_cont->b_wptr-mp->b_cont->b_rptr;
+ ms_fifo_get_write_ptr(fo,len,&d);
+ if (d!=NULL){
+ memcpy(d,mp->b_cont->b_rptr,len);
+ }else ms_warning("ms_rtp_recv_process: no space on output fifo !");
+ freemsg(mp);
+ }
+ r->prev_ts+=gran;
+
+ }
+ qo=r->q_outputs[0];
+ if (qo!=NULL)
+ {
+ guint32 clock;
+ gint got=0;
+ /* we are connected with queues (surely for video)*/
+ /* use the sync system time to compute a timestamp */
+ PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
+ if (pt==NULL) {
+ ms_warning("ms_rtp_recv_process(): NULL RtpPayload- skipping.");
+ return;
+ }
+ clock=(guint32)(((double)sync->time*(double)pt->clock_rate)/1000.0);
+ /*g_message("Querying packet with timestamp %u",clock);*/
+ /* get rtp packet, and send them through the output queue */
+ while ( (mp=rtp_session_recvm_with_ts(r->rtpsession,clock))!=NULL ){
+ MSMessage *msg;
+ mblk_t *mdata;
+ /*g_message("Got packet with timestamp %u",clock);*/
+ got++;
+ r->stream_started=1;
+ mdata=mp->b_cont;
+ freeb(mp);
+ msg=msgb_2_ms_message(mdata);
+ ms_queue_put(qo,msg);
+ }
+ }
+}
+
+void ms_rtp_recv_destroy( MSRtpRecv *obj)
+{
+ g_free(obj);
+}
+
+RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session)
+{
+ RtpSession *old=obj->rtpsession;
+ obj->rtpsession=session;
+ obj->prev_ts=0;
+ return old;
+}
+
+
+void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync)
+{
+ r->sync=sync;
+ r->stream_started=0;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h
new file mode 100644
index 00000000..8c2c2ed7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h
@@ -0,0 +1,80 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSRTPRECV_H
+#define MSRTPRECV_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+/* because of a conflict between config.h from oRTP and config.h from linphone:*/
+#undef PACKAGE
+#undef VERSION
+#include <ortp/ortp.h>
+
+/*this is the class that implements a copy filter*/
+
+#define MSRTPRECV_MAX_OUTPUTS 1 /* max output per filter*/
+
+#define MSRTPRECV_DEF_GRAN 4096 /* the default granularity*/
+
+struct _MSRtpRecv
+{
+ /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_outputs[MSRTPRECV_MAX_OUTPUTS];
+ MSQueue *q_outputs[MSRTPRECV_MAX_OUTPUTS];
+ MSSync *sync;
+ RtpSession *rtpsession;
+ guint32 prev_ts;
+ gint stream_started;
+};
+
+typedef struct _MSRtpRecv MSRtpRecv;
+
+struct _MSRtpRecvClass
+{
+ /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSRtpRecvClass MSRtpRecvClass;
+
+/* PUBLIC */
+#define MS_RTP_RECV(filter) ((MSRtpRecv*)(filter))
+#define MS_RTP_RECV_CLASS(klass) ((MSRtpRecvClass*)(klass))
+MSFilter * ms_rtp_recv_new(void);
+RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session);
+#define ms_rtp_recv_unset_session(obj) (ms_rtp_recv_set_session((obj),NULL))
+#define ms_rtp_recv_get_session(obj) ((obj)->rtpsession)
+
+
+
+/* FOR INTERNAL USE*/
+void ms_rtp_recv_init(MSRtpRecv *r);
+void ms_rtp_recv_class_init(MSRtpRecvClass *klass);
+void ms_rtp_recv_destroy( MSRtpRecv *obj);
+void ms_rtp_recv_process(MSRtpRecv *r);
+void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c
new file mode 100644
index 00000000..cfcb6b34
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c
@@ -0,0 +1,211 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "msrtpsend.h"
+#include <ortp/telephonyevents.h>
+#include "mssync.h"
+#include "mscodec.h"
+
+
+
+static MSRtpSendClass *ms_rtp_send_class=NULL;
+
+MSFilter * ms_rtp_send_new(void)
+{
+ MSRtpSend *r;
+
+ r=g_new(MSRtpSend,1);
+
+ if (ms_rtp_send_class==NULL)
+ {
+ ms_rtp_send_class=g_new(MSRtpSendClass,1);
+ ms_rtp_send_class_init(ms_rtp_send_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_send_class);
+ ms_rtp_send_init(r);
+ return(MS_FILTER(r));
+}
+
+
+void ms_rtp_send_init(MSRtpSend *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->inqueues=r->q_inputs;
+ MS_FILTER(r)->r_mingran=MSRTPSEND_DEF_GRAN;
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
+ memset(r->q_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
+ r->rtpsession=NULL;
+ r->ts=0;
+ r->ts_inc=0;
+ r->flags=0;
+ r->delay=0;
+}
+
+void ms_rtp_send_class_init(MSRtpSendClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPSend");
+ MS_FILTER_CLASS(klass)->max_qinputs=MSRTPSEND_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_finputs=MSRTPSEND_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=MSRTPSEND_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_send_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_send_process;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_send_setup;
+}
+
+void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size)
+{
+ r->ts_inc=ts_inc;
+ r->packet_size=payload_size;
+ if (r->ts_inc!=0) r->flags|=RTPSEND_CONFIGURED;
+ else r->flags&=~RTPSEND_CONFIGURED;
+ MS_FILTER(r)->r_mingran=payload_size;
+ /*g_message("ms_rtp_send_set_timing: ts_inc=%i",ts_inc);*/
+}
+
+guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime)
+{
+ guint32 clockts;
+ /* use the sync system time to compute a timestamp */
+ PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
+ g_return_val_if_fail(pt!=NULL,0);
+ clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0);
+ ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts);
+ if (r->flags & RTPSEND_CONFIGURED){
+ if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){
+ r->ts=clockts;
+ }
+ else r->ts+=r->ts_inc;
+ }else{
+ r->ts=clockts;
+ }
+ return r->ts;
+}
+
+
+void ms_rtp_send_process(MSRtpSend *r)
+{
+ MSFifo *fi;
+ MSQueue *qi;
+ MSSync *sync= r->sync;
+ int gran=ms_sync_get_samples_per_tick(sync);
+ guint32 ts;
+ void *s;
+ guint skip;
+ guint32 synctime=sync->time;
+
+ g_return_if_fail(gran>0);
+ if (r->rtpsession==NULL) return;
+
+ ms_filter_lock(MS_FILTER(r));
+ skip=r->delay!=0;
+ if (skip) r->delay--;
+ /* process output fifo and output queue*/
+ fi=r->f_inputs[0];
+ if (fi!=NULL)
+ {
+ ts=get_new_timestamp(r,synctime);
+ /* try to read r->packet_size bytes and send them in a rtp packet*/
+ ms_fifo_get_read_ptr(fi,r->packet_size,&s);
+ if (!skip){
+ rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts);
+ ms_trace("len=%i, ts=%i ",r->packet_size,ts);
+ }
+ }
+ qi=r->q_inputs[0];
+ if (qi!=NULL)
+ {
+ MSMessage *msg;
+ /* read a MSMessage and send it through the network*/
+ while ( (msg=ms_queue_get(qi))!=NULL){
+ ts=get_new_timestamp(r,synctime);
+ if (!skip) {
+ /*g_message("Sending packet with ts=%u",ts);*/
+ rtp_session_send_with_ts(r->rtpsession,msg->data,msg->size,ts);
+
+ }
+ ms_message_destroy(msg);
+ }
+ }
+ ms_filter_unlock(MS_FILTER(r));
+}
+
+void ms_rtp_send_destroy( MSRtpSend *obj)
+{
+ g_free(obj);
+}
+
+RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session)
+{
+ RtpSession *old=obj->rtpsession;
+ obj->rtpsession=session;
+ obj->ts=0;
+ obj->ts_inc=0;
+ return old;
+}
+
+void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync)
+{
+ MSFilter *codec;
+ MSCodecInfo *info;
+ r->sync=sync;
+ codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_AUDIO_CODEC);
+ if (codec==NULL) codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_VIDEO_CODEC);
+ if (codec==NULL){
+ g_warning("ms_rtp_send_setup: could not find upstream codec.");
+ return;
+ }
+ info=MS_CODEC_INFO(codec->klass->info);
+ if (info->info.type==MS_FILTER_AUDIO_CODEC){
+ int ts_inc=info->fr_size/2;
+ int psize=info->dt_size;
+ if (ts_inc==0){
+ /* dont'use the normal frame size: this is a variable frame size codec */
+ /* use the MS_FILTER(codec)->r_mingran */
+ ts_inc=MS_FILTER(codec)->r_mingran/2;
+ psize=0;
+ }
+ ms_rtp_send_set_timing(r,ts_inc,psize);
+ }
+}
+
+gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf)
+{
+ gint res;
+
+ if (r->rtpsession==NULL) return -1;
+ if (rtp_session_telephone_events_supported(r->rtpsession)==-1){
+ g_warning("ERROR : telephone events not supported.\n");
+ return -1;
+ }
+
+ ms_filter_lock(MS_FILTER(r));
+ g_message("Sending DTMF.");
+ res=rtp_session_send_dtmf(r->rtpsession, dtmf, r->ts);
+ if (res==0){
+ /* //r->ts+=r->ts_inc; */
+ r->delay+=2;
+ }else g_warning("Could not send dtmf.");
+
+ ms_filter_unlock(MS_FILTER(r));
+
+ return res;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h
new file mode 100644
index 00000000..b70f4e55
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h
@@ -0,0 +1,85 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSRTPSEND_H
+#define MSRTPSEND_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+#undef PACKAGE
+#undef VERSION
+#include <ortp/ortp.h>
+
+
+/*this is the class that implements a sending through rtp filter*/
+
+#define MSRTPSEND_MAX_INPUTS 1 /* max input per filter*/
+
+#define MSRTPSEND_DEF_GRAN 4096/* the default granularity*/
+
+struct _MSRtpSend
+{
+ /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSRTPSEND_MAX_INPUTS];
+ MSQueue *q_inputs[MSRTPSEND_MAX_INPUTS];
+ MSSync *sync;
+ RtpSession *rtpsession;
+ guint32 ts;
+ guint32 ts_inc; /* the timestamp increment */
+ gint packet_size;
+ guint flags;
+ guint delay; /* number of _proccess call which must be skipped */
+#define RTPSEND_CONFIGURED (1)
+};
+
+typedef struct _MSRtpSend MSRtpSend;
+
+struct _MSRtpSendClass
+{
+ /* the MSRtpSend derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSRtpSendClass MSRtpSendClass;
+
+/* PUBLIC */
+#define MS_RTP_SEND(filter) ((MSRtpSend*)(filter))
+#define MS_RTP_SEND_CLASS(klass) ((MSRtpSendClass*)(klass))
+MSFilter * ms_rtp_send_new(void);
+RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session);
+#define ms_rtp_send_unset_session(obj) (ms_rtp_send_set_session((obj),NULL))
+#define ms_rtp_send_get_session(obj) ((obj)->rtpsession)
+void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size);
+gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf);
+
+
+/* FOR INTERNAL USE*/
+void ms_rtp_send_init(MSRtpSend *r);
+void ms_rtp_send_class_init(MSRtpSendClass *klass);
+void ms_rtp_send_destroy( MSRtpSend *obj);
+void ms_rtp_send_process(MSRtpSend *r);
+void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h
new file mode 100644
index 00000000..fd6ec547
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssdlout.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * mssdlout.h
+ *
+ * Mon Jul 11 16:18:55 2005
+ * Copyright 2005 Simon Morlat
+ * Email simon dot morlat at linphone dot org
+ ****************************************************************************/
+
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef mssdlout_h
+#define mssdlout_h
+
+#include "msfilter.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_video.h>
+
+struct _MSSdlOut
+{
+ MSFilter parent;
+ MSQueue *input[2];
+ gint width,height;
+ const gchar *format;
+ SDL_Surface *screen;
+ SDL_Overlay *overlay;
+ MSMessage *oldinm1;
+ gboolean use_yuv;
+};
+
+
+typedef struct _MSSdlOut MSSdlOut;
+
+struct _MSSdlOutClass
+{
+ MSFilterClass parent_class;
+};
+
+typedef struct _MSSdlOutClass MSSdlOutClass;
+
+MSFilter * ms_sdl_out_new(void);
+void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt);
+
+#define MS_SDL_OUT(obj) ((MSSdlOut*)obj)
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c
new file mode 100644
index 00000000..3803b018
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.c
@@ -0,0 +1,39 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation
+
+ */
+
+#include "mssoundread.h"
+
+
+void ms_sound_read_init(MSSoundRead *w)
+{
+ ms_filter_init(MS_FILTER(w));
+
+}
+
+void ms_sound_read_class_init(MSSoundReadClass *klass)
+{
+ int i;
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */
+
+ ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h
new file mode 100644
index 00000000..7f2cab93
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundread.h
@@ -0,0 +1,80 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSSOUNDREAD_H
+#define MSSOUNDREAD_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+
+
+struct _MSSoundRead
+{
+ /* the MSOssRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssRead object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+};
+
+typedef struct _MSSoundRead MSSoundRead;
+
+struct _MSSoundReadClass
+{
+ /* the MSOssRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssRead class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+ gint (*set_device)(MSSoundRead *, gint devid);
+ void (*start)(MSSoundRead *);
+ void (*stop)(MSSoundRead*);
+ void (*set_level)(MSSoundRead *, gint a);
+};
+
+typedef struct _MSSoundReadClass MSSoundReadClass;
+
+/* PUBLIC */
+#define MS_SOUND_READ(filter) ((MSSoundRead*)(filter))
+#define MS_SOUND_READ_CLASS(klass) ((MSSoundReadClass*)(klass))
+
+static inline int ms_sound_read_set_device(MSSoundRead *r,gint devid)
+{
+ return MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
+}
+
+static inline void ms_sound_read_start(MSSoundRead *r)
+{
+ MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->start(r);
+}
+
+static inline void ms_sound_read_stop(MSSoundRead *w)
+{
+ MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->stop(w);
+}
+
+static inline void ms_sound_read_set_level(MSSoundRead *w,gint a)
+{
+ MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
+}
+
+/* FOR INTERNAL USE*/
+void ms_sound_read_init(MSSoundRead *r);
+void ms_sound_read_class_init(MSSoundReadClass *klass);
+
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c
new file mode 100644
index 00000000..9c5879f4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.c
@@ -0,0 +1,39 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation
+
+ */
+
+#include "mssoundwrite.h"
+
+
+void ms_sound_write_init(MSSoundWrite *w)
+{
+ ms_filter_init(MS_FILTER(w));
+
+}
+
+void ms_sound_write_class_init(MSSoundWriteClass *klass)
+{
+ int i;
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo output only */
+
+ ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SINK);
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h
new file mode 100644
index 00000000..e6d79874
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssoundwrite.h
@@ -0,0 +1,80 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSSOUNDWRITE_H
+#define MSSOUNDWRITE_H
+
+#include "msfilter.h"
+#include "mssync.h"
+
+
+
+struct _MSSoundWrite
+{
+ /* the MSOssWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssWrite object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+};
+
+typedef struct _MSSoundWrite MSSoundWrite;
+
+struct _MSSoundWriteClass
+{
+ /* the MSOssWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssWrite class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+ gint (*set_device)(MSSoundWrite *, gint devid);
+ void (*start)(MSSoundWrite *);
+ void (*stop)(MSSoundWrite*);
+ void (*set_level)(MSSoundWrite *, gint a);
+};
+
+typedef struct _MSSoundWriteClass MSSoundWriteClass;
+
+/* PUBLIC */
+#define MS_SOUND_WRITE(filter) ((MSSoundWrite*)(filter))
+#define MS_SOUND_WRITE_CLASS(klass) ((MSSoundWriteClass*)(klass))
+
+static inline int ms_sound_write_set_device(MSSoundWrite *r,gint devid)
+{
+ return MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
+}
+
+static inline void ms_sound_write_start(MSSoundWrite *r)
+{
+ MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->start(r);
+}
+
+static inline void ms_sound_write_stop(MSSoundWrite *w)
+{
+ MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->stop(w);
+}
+
+static inline void ms_sound_write_set_level(MSSoundWrite *w,gint a)
+{
+ MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
+}
+
+/* FOR INTERNAL USE*/
+void ms_sound_write_init(MSSoundWrite *r);
+void ms_sound_write_class_init(MSSoundWriteClass *klass);
+
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c
new file mode 100644
index 00000000..b91ca360
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.c
@@ -0,0 +1,218 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+
+#ifdef HAVE_SPEEX
+
+#include "msspeexdec.h"
+
+#ifdef HAVE_GLIB
+#include <gmodule.h>
+#endif
+
+extern MSFilter * ms_speex_enc_new();
+
+MSCodecInfo speex_info=
+{
+ {
+ "Speex codec",
+ 0,
+ MS_FILTER_AUDIO_CODEC,
+ ms_speex_dec_new,
+ "A high quality variable bit-rate codec from Jean Marc Valin and David Rowe."
+ },
+ ms_speex_enc_new,
+ ms_speex_dec_new,
+ 0, /*frame size */
+ 0,
+ 8000, /*minimal bitrate */
+ -1, /* sampling frequency */
+ 110, /* payload type */
+ "speex",
+ 1,
+ 1
+};
+
+
+
+void ms_speex_codec_init()
+{
+
+ ms_filter_register(MS_FILTER_INFO(&speex_info));
+ /* //ms_filter_register(MS_FILTER_INFO(&speex_lbr_info)); */
+}
+
+#ifdef HAVE_GLIB
+gchar * g_module_check_init(GModule *module)
+{
+ ms_speex_codec_init();
+
+ return NULL;
+}
+#else
+gchar * g_module_check_init()
+{
+ ms_speex_codec_init();
+
+ return NULL;
+}
+#endif
+
+static MSSpeexDecClass * ms_speex_dec_class=NULL;
+/* //static MSSpeexDecClass * ms_speexnb_dec_class=NULL; */
+
+MSFilter * ms_speex_dec_new()
+{
+ MSSpeexDec *obj=g_new(MSSpeexDec,1);
+
+ if (ms_speex_dec_class==NULL){
+ ms_speex_dec_class=g_new(MSSpeexDecClass,1);
+ ms_speex_dec_class_init(ms_speex_dec_class);
+ }
+ MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_dec_class);
+
+ ms_speex_dec_init(obj);
+ return MS_FILTER(obj);
+}
+
+void ms_speex_dec_init(MSSpeexDec *obj)
+{
+ ms_filter_init(MS_FILTER(obj));
+ obj->initialized=0;
+ MS_FILTER(obj)->outfifos=obj->outf;
+ MS_FILTER(obj)->inqueues=obj->inq;
+ obj->outf[0]=NULL;
+ obj->inq[0]=NULL;
+ obj->frequency=8000; /*default value */
+
+}
+
+void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode)
+{
+ int pf=1;
+
+ obj->speex_state=speex_decoder_init(mode);
+ speex_bits_init(&obj->bits);
+ /* enable the perceptual post filter */
+ speex_decoder_ctl(obj->speex_state,SPEEX_SET_PF, &pf);
+
+ speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &obj->frame_size);
+
+ obj->initialized=1;
+}
+
+int ms_speex_dec_set_property(MSSpeexDec *obj, MSFilterProperty prop, int *value)
+{
+ if (obj->initialized){
+ /* we are called when speex is running !! forbid that! */
+ ms_warning("ms_speex_dec_set_property: cannot call this function when running!");
+ return -1;
+ }
+ switch(prop){
+ case MS_FILTER_PROPERTY_FREQ:
+ obj->frequency=value[0];
+ break;
+ }
+ return 0;
+}
+
+void ms_speex_dec_setup(MSSpeexDec *obj)
+{
+ const SpeexMode *mode;
+ g_message("Speex decoder setup: freq=%i",obj->frequency);
+ if ( obj->frequency< 16000) mode=&speex_nb_mode;
+ else mode=&speex_wb_mode;
+ ms_speex_dec_init_core(obj,mode);
+}
+
+void ms_speex_dec_unsetup(MSSpeexDec *obj)
+{
+ ms_speex_dec_uninit_core(obj);
+}
+
+void ms_speex_dec_class_init(MSSpeexDecClass *klass)
+{
+ gint frame_size=0;
+
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ /* use the largest frame size to configure fifos */
+ speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_dec_process;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_dec_setup;
+ MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_dec_unsetup;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_dec_destroy;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_dec_set_property;
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexDecoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
+ MS_FILTER_CLASS(klass)->max_foutputs=1;
+ MS_FILTER_CLASS(klass)->max_qinputs=1;
+ MS_FILTER_CLASS(klass)->w_maxgran=frame_size*2;
+ ms_trace("ms_speex_dec_class_init: w_maxgran is %i.",MS_FILTER_CLASS(klass)->w_maxgran);
+}
+
+void ms_speex_dec_uninit_core(MSSpeexDec *obj)
+{
+ speex_decoder_destroy(obj->speex_state);
+ obj->initialized=0;
+}
+
+void ms_speex_dec_uninit(MSSpeexDec *obj)
+{
+
+}
+
+void ms_speex_dec_destroy(MSSpeexDec *obj)
+{
+ ms_speex_dec_uninit(obj);
+ g_free(obj);
+}
+
+void ms_speex_dec_process(MSSpeexDec *obj)
+{
+ MSFifo *outf=obj->outf[0];
+ MSQueue *inq=obj->inq[0];
+ gint16 *output;
+ gint gran=obj->frame_size*2;
+ gint i;
+ MSMessage *m;
+
+ g_return_if_fail(inq!=NULL);
+ g_return_if_fail(outf!=NULL);
+
+ m=ms_queue_get(inq);
+ g_return_if_fail(m!=NULL);
+ speex_bits_reset(&obj->bits);
+ ms_fifo_get_write_ptr(outf,gran,(void**)&output);
+ g_return_if_fail(output!=NULL);
+ if (m->data!=NULL){
+
+ speex_bits_read_from(&obj->bits,m->data,m->size);
+ /* decode */
+ speex_decode_int(obj->speex_state,&obj->bits,(short*)output);
+ }else{
+ /* we have a missing packet */
+ speex_decode_int(obj->speex_state,NULL,(short*)output);
+ }
+ ms_message_destroy(m);
+
+}
+
+#endif /* HAVE_SPEEX */
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h
new file mode 100644
index 00000000..d4e745fe
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexdec.h
@@ -0,0 +1,69 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSSPEEXDEC_H
+#define MSSPEEXDEC_H
+
+#include <mscodec.h>
+#include <speex.h>
+
+struct _MSSpeexDec
+{
+ MSFilter parent;
+ MSQueue *inq[1]; /* speex has an input q because it can be variable bit rate */
+ MSFifo *outf[1];
+ void *speex_state;
+ SpeexBits bits;
+ int frequency;
+ int frame_size;
+ int initialized;
+};
+
+typedef struct _MSSpeexDec MSSpeexDec;
+
+
+struct _MSSpeexDecClass
+{
+ MSFilterClass parent;
+};
+
+typedef struct _MSSpeexDecClass MSSpeexDecClass;
+
+
+#define MS_SPEEX_DEC(o) ((MSSpeexDec*)(o))
+#define MS_SPEEX_DEC_CLASS(o) ((MSSpeexDecClass*)(o))
+
+/* call this before if don't load the plugin dynamically */
+void ms_speex_codec_init();
+
+/* mediastreamer compliant constructor */
+MSFilter * ms_speex_dec_new();
+
+void ms_speex_dec_init(MSSpeexDec *obj);
+void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode);
+void ms_speex_dec_class_init(MSSpeexDecClass *klass);
+void ms_speex_dec_uninit(MSSpeexDec *obj);
+void ms_speex_dec_uninit_core(MSSpeexDec *obj);
+
+void ms_speex_dec_process(MSSpeexDec *obj);
+void ms_speex_dec_destroy(MSSpeexDec *obj);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c
new file mode 100644
index 00000000..abf976e6
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.c
@@ -0,0 +1,192 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+
+#ifdef HAVE_SPEEX
+
+#include "msspeexenc.h"
+#include "ms.h"
+extern MSCodecInfo speex_info;
+
+static MSSpeexEncClass * ms_speex_enc_class=NULL;
+
+MSFilter * ms_speex_enc_new()
+{
+ MSSpeexEnc *obj=g_new(MSSpeexEnc,1);
+
+ if (ms_speex_enc_class==NULL){
+ ms_speex_enc_class=g_new(MSSpeexEncClass,1);
+ ms_speex_enc_class_init(ms_speex_enc_class);
+ }
+ MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_enc_class);
+ ms_speex_enc_init(MS_SPEEX_ENC(obj));
+ return MS_FILTER(obj);
+}
+
+void ms_speex_enc_init(MSSpeexEnc *obj)
+{
+ ms_filter_init(MS_FILTER(obj));
+ MS_FILTER(obj)->infifos=obj->inf;
+ MS_FILTER(obj)->outqueues=obj->outq;
+ obj->inf[0]=NULL;
+ obj->outq[0]=NULL;
+ obj->frequency=8000;
+ obj->bitrate=30000;
+ obj->initialized=0;
+}
+
+void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint bitrate)
+{
+ int proc_type, proc_speed;
+ gchar *proc_vendor;
+ int tmp;
+ int frame_size;
+
+ obj->speex_state=speex_encoder_init(mode);
+ speex_bits_init(&obj->bits);
+
+ if (bitrate>0) {
+ bitrate++;
+ speex_encoder_ctl(obj->speex_state, SPEEX_SET_BITRATE, &bitrate);
+ g_message("Setting speex output bitrate less or equal than %i",bitrate-1);
+ }
+
+ proc_speed=ms_proc_get_speed();
+ proc_vendor=ms_proc_get_param("vendor_id");
+ if (proc_speed<0 || proc_vendor==NULL){
+ g_warning("Can't guess processor features: setting speex encoder to its lowest complexity.");
+ tmp=1;
+ speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
+ }else if ((proc_speed!=-1) && (proc_speed<200)){
+ g_warning("A cpu speed less than 200 Mhz is not enough: let's reduce the complexity of the speex codec.");
+ tmp=1;
+ speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
+ }else if (proc_vendor!=NULL) {
+ if (strncmp(proc_vendor,"GenuineIntel",strlen("GenuineIntel"))==0){
+ proc_type=ms_proc_get_type();
+ if (proc_type==5){
+ g_warning("A pentium I is not enough fast for speex codec in normal mode: let's reduce its complexity.");
+ tmp=1;
+ speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
+ }
+ }
+ g_free(proc_vendor);
+ }
+ /* guess the used input frame size */
+ speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
+ MS_FILTER(obj)->r_mingran=frame_size*2;
+ ms_trace("ms_speex_init: using frame size of %i.",MS_FILTER(obj)->r_mingran);
+
+ obj->initialized=1;
+}
+
+/* must be called before the encoder is running*/
+int ms_speex_enc_set_property(MSSpeexEnc *obj,int property,int *value)
+{
+ if (obj->initialized){
+ /* we are called when speex is running !! forbid that! */
+ ms_warning("ms_speex_enc_set_property: cannot call this function when running!");
+ return -1;
+ }
+ switch(property){
+ case MS_FILTER_PROPERTY_FREQ:
+ obj->frequency=value[0];
+ break;
+ case MS_FILTER_PROPERTY_BITRATE: /* to specify max bitrate */
+ obj->bitrate=value[0];
+ break;
+ }
+ return 0;
+}
+
+void ms_speex_enc_setup(MSSpeexEnc *obj)
+{
+ const SpeexMode *mode;
+ int quality;
+ g_message("Speex encoder setup: freq=%i",obj->frequency);
+ if ( obj->frequency< 16000) mode=&speex_nb_mode;
+ else mode=&speex_wb_mode;
+ ms_speex_enc_init_core(obj,mode,obj->bitrate);
+
+}
+
+void ms_speex_enc_unsetup(MSSpeexEnc *obj)
+{
+ ms_speex_enc_uninit_core(obj);
+}
+
+void ms_speex_enc_class_init(MSSpeexEncClass *klass)
+{
+ gint frame_size=0;
+
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ /* we take the larger (wb) frame size */
+ speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_enc_process;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_enc_destroy;
+ MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_enc_setup;
+ MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_enc_unsetup;
+ MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_enc_set_property;
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexEncoder");
+ MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
+ MS_FILTER_CLASS(klass)->max_finputs=1;
+ MS_FILTER_CLASS(klass)->max_qoutputs=1;
+ MS_FILTER_CLASS(klass)->r_maxgran=frame_size*2;
+ ms_trace("ms_speex_enc_class_init: r_maxgran is %i.",MS_FILTER_CLASS(klass)->r_maxgran);
+}
+
+void ms_speex_enc_uninit_core(MSSpeexEnc *obj)
+{
+ if (obj->initialized){
+ speex_encoder_destroy(obj->speex_state);
+ obj->initialized=0;
+ }
+}
+
+void ms_speex_enc_destroy(MSSpeexEnc *obj)
+{
+ ms_speex_enc_uninit_core(obj);
+ g_free(obj);
+}
+
+void ms_speex_enc_process(MSSpeexEnc *obj)
+{
+ MSFifo *inf=obj->inf[0];
+ MSQueue *outq=obj->outq[0];
+ gint16 *input;
+ gint gran=MS_FILTER(obj)->r_mingran;
+ gint i;
+ MSMessage *m;
+
+ g_return_if_fail(inf!=NULL);
+ g_return_if_fail(outq!=NULL);
+
+ ms_fifo_get_read_ptr(inf,gran,(void**)&input);
+ g_return_if_fail(input!=NULL);
+ /* encode */
+ speex_bits_reset(&obj->bits);
+ speex_encode_int(obj->speex_state,(short*)input,&obj->bits);
+ m=ms_message_new(speex_bits_nbytes(&obj->bits));
+ m->size=speex_bits_write(&obj->bits,m->data,m->size);
+ ms_queue_put(outq,m);
+}
+
+#endif /* HAVE_SPEEX */
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h
new file mode 100644
index 00000000..41655b9f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msspeexenc.h
@@ -0,0 +1,66 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSSPEEXENC_H
+#define MSSPEEXENC_H
+
+#include <mscodec.h>
+#include <speex.h>
+
+struct _MSSpeexEnc
+{
+ MSFilter parent;
+ MSFifo *inf[1];
+ MSQueue *outq[1]; /* speex has an output q because it can be variable bit rate */
+ void *speex_state;
+ SpeexBits bits;
+ int frequency;
+ int bitrate;
+ int initialized;
+};
+
+typedef struct _MSSpeexEnc MSSpeexEnc;
+
+
+struct _MSSpeexEncClass
+{
+ MSFilterClass parent;
+};
+
+typedef struct _MSSpeexEncClass MSSpeexEncClass;
+
+
+#define MS_SPEEX_ENC(o) ((MSSpeexEnc*)(o))
+#define MS_SPEEX_ENC_CLASS(o) ((MSSpeexEncClass*)(o))
+
+/* generic constructor */
+MSFilter * ms_speex_enc_new();
+
+void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint quality);
+void ms_speex_enc_uninit_core(MSSpeexEnc *obj);
+void ms_speex_enc_init(MSSpeexEnc *obj);
+void ms_speex_enc_class_init(MSSpeexEncClass *klass);
+
+
+void ms_speex_enc_process(MSSpeexEnc *obj);
+void ms_speex_enc_destroy(MSSpeexEnc *obj);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c
new file mode 100644
index 00000000..7656211b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.c
@@ -0,0 +1,193 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "mssync.h"
+#include <errno.h>
+
+/* TODO:
+ -define an uninit function that free the mutex
+*/
+
+/**
+ * function_name:ms_sync_get_bytes_per_tick
+ * @sync: A #MSSync object.
+ *
+ * Returns the number of bytes per tick. This is a usefull information for sources, so
+ * that they can know how much data they must deliver each time they are called.
+ *
+ */
+
+/* private */
+void ms_sync_init(MSSync *sync)
+{
+ sync->klass=NULL;
+ sync->lock=g_mutex_new();
+ sync->thread_cond=g_cond_new();
+ sync->stop_cond=g_cond_new();
+ sync->attached_filters=NULL;
+ sync->execution_list=NULL;
+ sync->filters=0;
+ sync->run=0;
+ sync->flags=0;
+ sync->samples_per_tick=0;
+ sync->ticks=0;
+ sync->time=0;
+ sync->thread=NULL;
+}
+
+void ms_sync_class_init(MSSyncClass *klass)
+{
+ klass->max_filters=0;
+ klass->synchronize=NULL;
+ klass->attach=ms_sync_attach_generic;
+ klass->detach=ms_sync_detach_generic;
+ klass->destroy=NULL;
+}
+
+/* public*/
+
+
+/**
+ * ms_sync_attach:
+ * @sync: A #MSSync object.
+ * @f: A #MSFilter object.
+ *
+ * Attach a chain of filters to a synchronisation source @sync. Filter @f must be the first filter of the processing chain.
+ * In order to be run, each chain of filter must be attached to a synchronisation source, that will be responsible for scheduling
+ * the processing. Multiple chains can be attached to a single synchronisation.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_sync_attach(MSSync *sync,MSFilter *f)
+{
+ gint err;
+ ms_sync_lock(sync);
+ err=sync->klass->attach(sync,f);
+ ms_sync_update(sync);
+ ms_sync_unlock(sync);
+ return(err);
+}
+
+int ms_sync_attach_generic(MSSync *sync,MSFilter *f)
+{
+ int i;
+ /* //printf("attr: %i\n",f->klass->attributes); */
+ g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
+ g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
+
+
+ /* find a free place to attach*/
+ for (i=0;i<sync->klass->max_filters;i++)
+ {
+ if (sync->attached_filters[i]==NULL)
+ {
+ sync->attached_filters[i]=f;
+ sync->filters++;
+ ms_trace("Filter succesfully attached to sync.");
+ return 0;
+ }
+ }
+ g_warning("No more link on sync !");
+ return(-EMLINK);
+}
+
+/**
+ * ms_sync_detach:
+ * @sync: A #MSSync object.
+ * @f: A #MSFilter object.
+ *
+ * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
+ * The processing chain will no more be executed.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_sync_detach(MSSync *sync,MSFilter *f)
+{
+ gint err;
+ ms_sync_lock(sync);
+ err=sync->klass->detach(sync,f);
+ ms_sync_update(sync);
+ ms_sync_unlock(sync);
+ return(err);
+}
+
+int ms_sync_detach_generic(MSSync *sync,MSFilter *f)
+{
+ int i;
+ g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
+ g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
+ for (i=0;i<sync->filters;i++)
+ {
+ if (sync->attached_filters[i]==f)
+ {
+ sync->attached_filters[i]=NULL;
+ sync->filters--;
+ return 0;
+ }
+ }
+ return(-EMLINK);
+}
+
+void ms_sync_set_samples_per_tick(MSSync *sync,gint size)
+{
+ if (sync->samples_per_tick==0)
+ {
+ sync->samples_per_tick=size;
+ g_cond_signal(sync->thread_cond);
+ }
+ else sync->samples_per_tick=size;
+}
+
+/* call the setup func of each filter attached to the graph */
+void ms_sync_setup(MSSync *sync)
+{
+ GList *elem=sync->execution_list;
+ MSFilter *f;
+ while(elem!=NULL){
+ f=(MSFilter*)elem->data;
+ if (f->klass->setup!=NULL){
+ f->klass->setup(f,sync);
+ }
+ elem=g_list_next(elem);
+ }
+}
+
+/* call the unsetup func of each filter attached to the graph */
+void ms_sync_unsetup(MSSync *sync)
+{
+ GList *elem=sync->execution_list;
+ MSFilter *f;
+ while(elem!=NULL){
+ f=(MSFilter*)elem->data;
+ if (f->klass->unsetup!=NULL){
+ f->klass->unsetup(f,sync);
+ }
+ elem=g_list_next(elem);
+ }
+}
+
+
+int ms_sync_uninit(MSSync *sync)
+{
+ g_mutex_free(sync->lock);
+ g_cond_free(sync->thread_cond);
+ g_cond_free(sync->stop_cond);
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h
new file mode 100644
index 00000000..012c068f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mssync.h
@@ -0,0 +1,136 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MS_SYNC_H
+#define MS_SYNC_H
+
+
+#include "msfilter.h"
+
+struct _MSSync
+{
+ struct _MSSyncClass *klass;
+ GMutex *lock;
+ MSFilter **attached_filters; /* pointer to a table of pointer of filters*/
+ GList *execution_list; /* the list of filters to be executed. This is filled with compilation */
+ gint filters; /*number of filters attached to the sync */
+ gint run; /* flag to indicate whether the sync must be run or not */
+ GThread * thread; /* the thread ressource if this sync is run by a thread*/
+ GCond *thread_cond;
+ GCond *stop_cond;
+ guint32 flags;
+ gint interval; /* in miliseconds*/
+#define MS_SYNC_NEED_UPDATE (0x0001) /* a modification has occured in the processing chains
+ attached to this sync; so the execution list has to be updated */
+ guint samples_per_tick; /* number of bytes produced by sources of the processing chains*/
+ guint32 ticks;
+ guint32 time; /* a time since the start of the sync expressed in milisec*/
+};
+
+typedef struct _MSSync MSSync;
+
+typedef void (*MSSyncDestroyFunc)(MSSync*);
+typedef void (*MSSyncSyncFunc)(MSSync*);
+typedef int (*MSSyncAttachFunc)(MSSync*,MSFilter*);
+typedef int (*MSSyncDetachFunc)(MSSync*,MSFilter*);
+
+typedef struct _MSSyncClass
+{
+ gint max_filters; /* the maximum number of filters that can be attached to this sync*/
+ MSSyncSyncFunc synchronize;
+ MSSyncDestroyFunc destroy;
+ MSSyncAttachFunc attach;
+ MSSyncDetachFunc detach;
+} MSSyncClass;
+
+/* private */
+void ms_sync_init(MSSync *sync);
+void ms_sync_class_init(MSSyncClass *klass);
+
+int ms_sync_attach_generic(MSSync *sync,MSFilter *f);
+int ms_sync_detach_generic(MSSync *sync,MSFilter *f);
+
+/* public*/
+
+#define MS_SYNC(sync) ((MSSync*)(sync))
+#define MS_SYNC_CLASS(klass) ((MSSyncClass*)(klass))
+
+#define ms_sync_synchronize(_sync) \
+do \
+{ \
+ MSSync *__sync=_sync; \
+ __sync->ticks++; \
+ ((__sync)->klass->synchronize((__sync))); \
+}while(0)
+
+void ms_sync_setup(MSSync *sync);
+
+void ms_sync_unsetup(MSSync *sync);
+
+#define ms_sync_update(sync) (sync)->flags|=MS_SYNC_NEED_UPDATE
+
+#define ms_sync_get_samples_per_tick(sync) ((sync)->samples_per_tick)
+
+void ms_sync_set_samples_per_tick(MSSync *sync,gint size);
+
+#define ms_sync_get_tick_count(sync) ((sync)->ticks)
+
+#define ms_sync_suspend(sync) g_cond_wait((sync)->thread_cond,(sync)->lock)
+
+#define ms_sync_lock(sync) g_mutex_lock((sync)->lock)
+
+#define ms_sync_unlock(sync) g_mutex_unlock((sync)->lock)
+
+#define ms_sync_trylock(sync) g_mutex_trylock((sync)->lock)
+
+/**
+ * function_name:ms_sync_attach
+ * @sync: A #MSSync object.
+ * @f: A #MSFilter object.
+ *
+ * Attach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_sync_attach(MSSync *sync,MSFilter *f);
+
+/**
+ * ms_sync_detach:
+ * @sync: A #MSSync object.
+ * @f: A #MSFilter object.
+ *
+ * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
+ * The processing chain will no more be executed.
+ *
+ * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
+ */
+int ms_sync_detach(MSSync *sync,MSFilter *f);
+
+int ms_sync_uninit(MSSync *sync);
+
+#define ms_sync_start(sync) ms_start((sync))
+#define ms_sync_stop(sync) ms_stop((sync))
+
+
+/*destroy*/
+#define ms_sync_destroy(sync) (sync)->klass->destroy((sync))
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c
new file mode 100644
index 00000000..29b81d3c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.c
@@ -0,0 +1,114 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "mstimer.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+
+static MSTimerClass *ms_timer_class=NULL;
+
+
+void ms_timer_init(MSTimer *sync)
+{
+ ms_sync_init(MS_SYNC(sync));
+ MS_SYNC(sync)->attached_filters=sync->filters;
+ memset(sync->filters,0,MSTIMER_MAX_FILTERS*sizeof(MSFilter*));
+ MS_SYNC(sync)->samples_per_tick=160;
+ ms_timer_set_interval(sync,20);
+ sync->state=MS_TIMER_STOPPED;
+}
+
+void ms_timer_class_init(MSTimerClass *klass)
+{
+ ms_sync_class_init(MS_SYNC_CLASS(klass));
+ MS_SYNC_CLASS(klass)->max_filters=MSTIMER_MAX_FILTERS;
+ MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_timer_synchronize;
+ MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_timer_destroy;
+ /* no need to overload these function*/
+ MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
+ MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
+}
+
+void ms_timer_destroy(MSTimer *timer)
+{
+ g_free(timer);
+}
+
+
+void ms_timer_synchronize(MSTimer *timer)
+{
+ /* //printf("ticks=%i \n",MS_SYNC(timer)->ticks); */
+ if (timer->state==MS_TIMER_STOPPED){
+ timer->state=MS_TIMER_RUNNING;
+ gettimeofday(&timer->orig,NULL);
+ timer->sync.time=0;
+ }
+ else {
+ gint32 diff,time;
+ struct timeval tv,cur;
+
+ gettimeofday(&cur,NULL);
+ time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
+ if ( (diff=time-timer->sync.time)>50){
+ g_warning("Must catchup %i miliseconds.",diff);
+ }
+ while((diff = timer->sync.time-time) > 0)
+ {
+ tv.tv_sec = diff/1000;
+ tv.tv_usec = (diff%1000)*1000;
+ select(0,NULL,NULL,NULL,&tv);
+ gettimeofday(&cur,NULL);
+ time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
+ }
+ }
+ timer->sync.time+=timer->milisec;
+ return;
+}
+
+
+MSSync *ms_timer_new()
+{
+ MSTimer *timer;
+
+ timer=g_malloc(sizeof(MSTimer));
+ ms_timer_init(timer);
+ if (ms_timer_class==NULL)
+ {
+ ms_timer_class=g_new(MSTimerClass,1);
+ ms_timer_class_init(ms_timer_class);
+ }
+ MS_SYNC(timer)->klass=MS_SYNC_CLASS(ms_timer_class);
+ return(MS_SYNC(timer));
+}
+
+void ms_timer_set_interval(MSTimer *timer, int milisec)
+{
+
+ MS_SYNC(timer)->ticks=0;
+ MS_SYNC(timer)->interval=milisec;
+ timer->interval.tv_sec=milisec/1000;
+ timer->interval.tv_usec=(milisec % 1000)*1000;
+ timer->milisec=milisec;
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h
new file mode 100644
index 00000000..5c7e8ede
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstimer.h
@@ -0,0 +1,68 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSTIMER_H
+#define MSTIMER_H
+
+#include "mssync.h"
+#include <sys/time.h>
+
+#define MSTIMER_MAX_FILTERS 10
+
+/* MSTimer derivates from MSSync base class*/
+
+typedef struct _MSTimer
+{
+ /* the MSSync must be the first field of the object in order to the object mechanism to work*/
+ MSSync sync;
+ MSFilter *filters[MSTIMER_MAX_FILTERS];
+ gint milisec; /* the interval */
+ struct timeval interval;
+ struct timeval orig;
+ gint state;
+} MSTimer;
+
+
+typedef struct _MSTimerClass
+{
+ /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
+ MSSyncClass parent_class;
+} MSTimerClass;
+
+
+/*private*/
+#define MS_TIMER_RUNNING 1
+#define MS_TIMER_STOPPED 0
+void ms_timer_init(MSTimer *sync);
+void ms_timer_class_init(MSTimerClass *sync);
+
+void ms_timer_destroy(MSTimer *timer);
+void ms_timer_synchronize(MSTimer *timer);
+
+/*public*/
+void ms_timer_set_interval(MSTimer *timer, gint milisec);
+
+/* casts a MSSync object into a MSTimer */
+#define MS_TIMER(sync) ((MSTimer*)(sync))
+/* casts a MSSync class into a MSTimer class */
+#define MS_TIMER_CLASS(klass) ((MSTimerClass*)(klass))
+
+MSSync *ms_timer_new();
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h
new file mode 100644
index 00000000..62477436
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechdecoder.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2003 Robert W. Brewer <rbrewer at op.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSTRUESPEECHDECODER_H
+#define MSTRUESPEECHDECODER_H
+
+#include "msfilter.h"
+#include "mstruespeechencoder.h"
+
+
+
+typedef struct _MSTrueSpeechDecoder
+{
+ /* the MSTrueSpeechDecoder derives from MSFilter, so the MSFilter
+ object MUST be the first of the MSTrueSpeechDecoder object
+ in order for the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
+ MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
+ Win32Codec* codec;
+} MSTrueSpeechDecoder;
+
+typedef struct _MSTrueSpeechDecoderClass
+{
+ /* the MSTrueSpeechDecoder derives from MSFilter,
+ so the MSFilter class MUST be the first of the MSTrueSpechDecoder
+ class
+ in order for the class mechanism to work*/
+ MSFilterClass parent_class;
+ Win32CodecDriver* driver;
+} MSTrueSpeechDecoderClass;
+
+/* PUBLIC */
+#define MS_TRUESPEECHDECODER(filter) ((MSTrueSpechMDecoder*)(filter))
+#define MS_TRUESPEECHDECODER_CLASS(klass) ((MSTrueSpeechDecoderClass*)(klass))
+MSFilter * ms_truespeechdecoder_new(void);
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h
new file mode 100644
index 00000000..04e40bb8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mstruespeechencoder.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2003 Robert W. Brewer <rbrewer at op.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef MSTRUESPEECHENCODER_H
+#define MSTRUESPEECHENCODER_H
+
+#include "msfilter.h"
+#include <win32codec.h>
+
+
+#define MS_TRUESPEECH_CODEC_MAX_IN_OUT 1 /* max inputs/outputs per filter*/
+
+#define TRUESPEECH_FORMAT_TAG 0x22
+#define TRUESPEECH_DLL "tssoft32.acm"
+
+typedef struct _MSTrueSpeechEncoder
+{
+ /* the MSTrueSpeechEncoder derives from MSFilter, so the MSFilter
+ object MUST be the first of the MSTrueSpeechEncoder object
+ in order for the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
+ MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
+ Win32Codec* codec;
+} MSTrueSpeechEncoder;
+
+typedef struct _MSTrueSpeechEncoderClass
+{
+ /* the MSTrueSpeechEncoder derives from MSFilter,
+ so the MSFilter class MUST be the first of the MSTrueSpechEncoder
+ class
+ in order for the class mechanism to work*/
+ MSFilterClass parent_class;
+ Win32CodecDriver* driver;
+} MSTrueSpeechEncoderClass;
+
+/* PUBLIC */
+#define MS_TRUESPEECHENCODER(filter) ((MSTrueSpechMEncoder*)(filter))
+#define MS_TRUESPEECHENCODER_CLASS(klass) ((MSTrueSpeechEncoderClass*)(klass))
+MSFilter * ms_truespeechencoder_new(void);
+
+/* for internal use only */
+WAVEFORMATEX* ms_truespeechencoder_wf_create();
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h
new file mode 100644
index 00000000..012b87d8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msutils.h
@@ -0,0 +1,61 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef MSUTILS_H
+#define MSUTILS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#else
+#include <uglib.h>
+#endif
+#include <errno.h>
+
+#ifndef ENODATA
+/* this is for freeBSD .*/
+#define ENODATA EWOULDBLOCK
+#endif
+
+#ifdef MS_DEBUG
+
+#define ms_trace g_message
+
+#else
+
+#define ms_trace(...)
+#endif
+
+#define ms_warning g_warning
+#define ms_error g_error
+
+#define VIDEO_SIZE_CIF_W 352
+#define VIDEO_SIZE_CIF_H 288
+#define VIDEO_SIZE_QCIF_W 176
+#define VIDEO_SIZE_QCIF_H 144
+#define VIDEO_SIZE_4CIF_W 704
+#define VIDEO_SIZE_4CIF_H 576
+#define VIDEO_SIZE_MAX_W VIDEO_SIZE_4CIF_W
+#define VIDEO_SIZE_MAX_H VIDEO_SIZE_4CIF_H
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h
new file mode 100644
index 00000000..e19ac9ea
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msv4l.h
@@ -0,0 +1,96 @@
+ /*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSV4L_H
+#define MSV4L_H
+
+#include <msvideosource.h>
+#include <sys/types.h>
+#include <linux/videodev.h>
+
+struct _MSV4l
+{
+ MSVideoSource parent;
+ int fd;
+ char *device;
+ struct video_capability cap;
+ struct video_channel channel;
+ struct video_window win;
+ struct video_picture pict;
+ struct video_mmap vmap;
+ struct video_mbuf vmbuf;
+ struct video_capture vcap;
+ gint bsize;
+ gint use_mmap;
+ gint frame;
+ guint query_frame;
+ gchar *mmapdbuf; /* the mmap'd buffer */
+ MSBuffer img[VIDEO_MAX_FRAME]; /* the buffer wrappers used for mmaps */
+ gint width; /* the capture image size - can be cropped to output size */
+ gint height;
+ MSBuffer *allocdbuf; /* the buffer allocated for read() and mire */
+ gint count;
+ MSBuffer *image_grabbed;
+ GCond *cond;
+ GCond *stopcond;
+ GThread *v4lthread;
+ gboolean grab_image;
+ gboolean thread_run;
+ gboolean thread_exited;
+};
+
+typedef struct _MSV4l MSV4l;
+
+
+struct _MSV4lClass
+{
+ MSVideoSourceClass parent_class;
+
+};
+
+typedef struct _MSV4lClass MSV4lClass;
+
+
+/* PUBLIC API */
+#define MS_V4L(v) ((MSV4l*)(v))
+#define MS_V4L_CLASS(k) ((MSV4lClass*)(k))
+MSFilter * ms_v4l_new();
+
+void ms_v4l_start(MSV4l *obj);
+void ms_v4l_stop(MSV4l *obj);
+int ms_v4l_set_device(MSV4l *f, const gchar *device);
+gint ms_v4l_get_width(MSV4l *v4l);
+gint ms_v4l_get_height(MSV4l *v4l);
+void ms_v4l_set_size(MSV4l *v4l, gint w, gint h);
+
+/* PRIVATE API */
+void ms_v4l_init(MSV4l *obj);
+void ms_v4l_class_init(MSV4lClass *klass);
+int v4l_configure(MSV4l *f);
+
+void v4l_process(MSV4l *obj);
+
+void ms_v4l_uninit(MSV4l *obj);
+
+void ms_v4l_destroy(MSV4l *obj);
+
+extern MSFilterInfo v4l_info;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h
new file mode 100644
index 00000000..9a27f836
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msvideosource.h
@@ -0,0 +1,74 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSVIDEOSOURCE_H
+#define MSVIDEOSOURCE_H
+
+
+#include "msfilter.h"
+
+/* this is the video input abstract class */
+
+#define MSVIDEOSOURCE_MAX_OUTPUTS 1 /* max output per filter*/
+
+typedef struct _MSVideoSource
+{
+ /* the MSVideoSource derivates from MSFilter, so the MSFilter object MUST be the first of the MSVideoSource object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSQueue *outputs[MSVIDEOSOURCE_MAX_OUTPUTS];
+ gchar *dev_name;
+ gint width, height;
+ gchar *format;
+ gint frame_rate;
+ gint frame_rate_base;
+} MSVideoSource;
+
+typedef struct _MSVideoSourceClass
+{
+ /* the MSVideoSource derivates from MSFilter, so the MSFilter class MUST be the first of the MSVideoSource class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+ gint (*set_device)(MSVideoSource *s, const gchar *name);
+ void (*start)(MSVideoSource *s);
+ void (*stop)(MSVideoSource *s);
+ void (*set_size)(MSVideoSource *s, gint width, gint height);
+ void (*set_frame_rate)(MSVideoSource *s, gint frame_rate, gint frame_rate_base);
+} MSVideoSourceClass;
+
+/* PUBLIC */
+void ms_video_source_register_all();
+int ms_video_source_set_device(MSVideoSource *f, const gchar *device);
+gchar* ms_video_source_get_device_name(MSVideoSource *f);
+void ms_video_source_start(MSVideoSource *f);
+void ms_video_source_stop(MSVideoSource *f);
+void ms_video_source_set_size(MSVideoSource *f, gint width, gint height);
+void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base);
+gchar* ms_video_source_get_format(MSVideoSource *f);
+
+#define MS_VIDEO_SOURCE(obj) ((MSVideoSource*)(obj))
+#define MS_VIDEO_SOURCE_CLASS(klass) ((MSVideoSourceClass*)(klass))
+
+
+/* FOR INTERNAL USE*/
+void ms_video_source_init(MSVideoSource *f);
+void ms_video_source_class_init(MSVideoSourceClass *klass);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c
new file mode 100644
index 00000000..178e294c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.c
@@ -0,0 +1,121 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "mswrite.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+static MSWriteClass *ms_write_class=NULL;
+
+MSFilter * ms_write_new(char *name)
+{
+ MSWrite *r;
+ int fd=-1;
+
+ r=g_new(MSWrite,1);
+ ms_write_init(r);
+ if (ms_write_class==NULL)
+ {
+ ms_write_class=g_new(MSWriteClass,1);
+ ms_write_class_init(ms_write_class);
+ }
+ MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_write_class);
+ if ((name!=NULL) && (strlen(name)!=0))
+ {
+ fd=open(name,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd<0) g_error("ms_write_new: failed to open %s.\n",name);
+ }
+ r->fd=fd;
+ return(MS_FILTER(r));
+}
+
+
+/* FOR INTERNAL USE*/
+void ms_write_init(MSWrite *r)
+{
+ ms_filter_init(MS_FILTER(r));
+ MS_FILTER(r)->infifos=r->f_inputs;
+ MS_FILTER(r)->inqueues=r->q_inputs;
+ MS_FILTER(r)->r_mingran=MSWRITE_MIN_GRAN;
+ memset(r->f_inputs,0,sizeof(MSFifo*)*MSWRITE_MAX_INPUTS);
+ memset(r->q_inputs,0,sizeof(MSQueue*)*MSWRITE_MAX_INPUTS);
+ r->fd=-1;
+}
+
+void ms_write_class_init(MSWriteClass *klass)
+{
+ ms_filter_class_init(MS_FILTER_CLASS(klass));
+ ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskwriter");
+ MS_FILTER_CLASS(klass)->max_finputs=MSWRITE_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->max_qinputs=MSWRITE_MAX_INPUTS;
+ MS_FILTER_CLASS(klass)->r_maxgran=MSWRITE_DEF_GRAN;
+ MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_write_destroy;
+ MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_write_process;
+}
+
+void ms_write_process(MSWrite *r)
+{
+ MSFifo *f;
+ MSQueue *q;
+ MSMessage *buf=NULL;
+ int i,j,err1,err2;
+ gint gran=ms_filter_get_mingran(MS_FILTER(r));
+ void *p;
+
+ /* process output fifos*/
+ for (i=0,j=0;(i<MS_FILTER(r)->klass->max_finputs)&&(j<MS_FILTER(r)->finputs);i++)
+ {
+ f=r->f_inputs[i];
+ if (f!=NULL)
+ {
+ if ( (err1=ms_fifo_get_read_ptr(f,gran,&p))>0 )
+ {
+
+ err2=write(r->fd,p,gran);
+ if (err2<0) g_warning("ms_write_process: failed to write: %s.\n",strerror(errno));
+ }
+ j++;
+ }
+ }
+ /* process output queues*/
+ for (i=0,j=0;(i<MS_FILTER(r)->klass->max_qinputs)&&(j<MS_FILTER(r)->qinputs);i++)
+ {
+ q=r->q_inputs[i];
+ if (q!=NULL)
+ {
+ while ( (buf=ms_queue_get(q))!=NULL ){
+ write(r->fd,buf->data,buf->size);
+ j++;
+ ms_message_destroy(buf);
+ }
+ }
+ }
+}
+
+void ms_write_destroy( MSWrite *obj)
+{
+ if (obj->fd!=0) close(obj->fd);
+ g_free(obj);
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h
new file mode 100644
index 00000000..cd766d10
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/mswrite.h
@@ -0,0 +1,63 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MSWRITE_H
+#define MSWRITE_H
+
+#include "msfilter.h"
+
+
+/*this is the class that implements writing reading sink filter*/
+
+#define MSWRITE_MAX_INPUTS 1 /* max output per filter*/
+
+#define MSWRITE_DEF_GRAN 512 /* the default granularity*/
+#define MSWRITE_MIN_GRAN 64
+
+typedef struct _MSWrite
+{
+ /* the MSWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSWrite object
+ in order to the object mechanism to work*/
+ MSFilter filter;
+ MSFifo *f_inputs[MSWRITE_MAX_INPUTS];
+ MSQueue *q_inputs[MSWRITE_MAX_INPUTS];
+ gint fd; /* the file descriptor of the file being written*/
+} MSWrite;
+
+typedef struct _MSWriteClass
+{
+ /* the MSWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSWrite class
+ in order to the class mechanism to work*/
+ MSFilterClass parent_class;
+} MSWriteClass;
+
+/* PUBLIC */
+#define MS_WRITE(filter) ((MSWrite*)(filter))
+#define MS_WRITE_CLASS(klass) ((MSWriteClass*)(klass))
+MSFilter * ms_write_new(char *name);
+
+/* FOR INTERNAL USE*/
+void ms_write_init(MSWrite *r);
+void ms_write_class_init(MSWriteClass *klass);
+void ms_write_destroy( MSWrite *obj);
+void ms_write_process(MSWrite *r);
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c
new file mode 100644
index 00000000..636c5792
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.c
@@ -0,0 +1,495 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "osscard.h"
+
+#include "msossread.h"
+#include "msosswrite.h"
+
+#ifdef HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#if 0
+void * oss_thread(OssCard *obj)
+{
+ gint i;
+ gint err;
+ g_message("oss_thread: starting **********");
+ while(1){
+ for(i=0;i<OSS_CARD_BUFFERS;i++){
+ g_mutex_lock(obj->lock);
+ if (obj->ref==0){
+ g_cond_signal(obj->cond);
+ g_mutex_unlock(obj->lock);
+ g_thread_exit(NULL);
+ }
+ g_mutex_unlock(obj->lock);
+ obj->readindex=i;
+
+ err=read(obj->fd,obj->readbuf[i],SND_CARD(obj)->bsize);
+ if (err<0) g_warning("oss_thread: read() error:%s.",strerror(errno));
+ obj->writeindex=i;
+ write(obj->fd,obj->writebuf[i],SND_CARD(obj)->bsize);
+ memset(obj->writebuf[i],0,SND_CARD(obj)->bsize);
+ }
+ }
+}
+#endif
+int oss_open(OssCard *obj, int bits,int stereo, int rate)
+{
+ int fd;
+ int p=0,cond=0;
+ int i=0;
+ int min_size=0,blocksize=512;
+ int err;
+
+ //g_message("opening sound device");
+ fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
+ if (fd<0) return -EWOULDBLOCK;
+ /* unset nonblocking mode */
+ /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK);
+
+ /* reset is maybe not needed but takes time*/
+ /*ioctl(fd, SNDCTL_DSP_RESET, 0); */
+
+
+#ifdef WORDS_BIGENDIAN
+ p=AFMT_U16_BE;
+#else
+ p=AFMT_U16_LE;
+#endif
+
+ err=ioctl(fd,SNDCTL_DSP_SETFMT,&p);
+ if (err<0){
+ g_warning("oss_open: can't set sample format:%s.",strerror(errno));
+ }
+
+
+ p = bits; /* 16 bits */
+ err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
+ if (err<0){
+ g_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno));
+ }
+
+ p = rate; /* rate in khz*/
+ err=ioctl(fd, SNDCTL_DSP_SPEED, &p);
+ if (err<0){
+ g_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno));
+ }
+
+ p = stereo; /* stereo or not */
+ err=ioctl(fd, SNDCTL_DSP_STEREO, &p);
+ if (err<0){
+ g_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno));
+ }
+
+ if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */
+ else blocksize=blocksize*(rate/8000);
+ ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
+
+ /* try to subdivide BLKSIZE to reach blocksize if necessary */
+ if (min_size>blocksize)
+ {
+ cond=1;
+ p=min_size/blocksize;
+ while(cond)
+ {
+ i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
+ //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
+ if ((i==0) || (p==1)) cond=0;
+ else p=p/2;
+ }
+ }
+ ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
+ if (min_size>blocksize)
+ {
+ g_warning("dsp block size set to %i.",min_size);
+ }else{
+ /* no need to access the card with less latency than needed*/
+ min_size=blocksize;
+ }
+
+ g_message("dsp blocksize is %i.",min_size);
+
+ /* start recording !!! Alex */
+ {
+ int fl,res;
+
+ fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT;
+ res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl);
+ if (res<0) g_warning("OSS_TRIGGER: %s",strerror(errno));
+ }
+
+ obj->fd=fd;
+ obj->readpos=0;
+ obj->writepos=0;
+ SND_CARD(obj)->bits=bits;
+ SND_CARD(obj)->stereo=stereo;
+ SND_CARD(obj)->rate=rate;
+ SND_CARD(obj)->bsize=min_size;
+ return fd;
+}
+
+int oss_card_probe(OssCard *obj,int bits,int stereo,int rate)
+{
+
+ int fd;
+ int p=0,cond=0;
+ int i=0;
+ int min_size=0,blocksize=512;
+
+ if (obj->fd>0) return SND_CARD(obj)->bsize;
+ fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
+ if (fd<0) {
+ g_warning("oss_card_probe: can't open %s: %s.",obj->dev_name,strerror(errno));
+ return -1;
+ }
+ ioctl(fd, SNDCTL_DSP_RESET, 0);
+
+ p = bits; /* 16 bits */
+ ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
+
+ p = stereo; /* number of channels */
+ ioctl(fd, SNDCTL_DSP_CHANNELS, &p);
+
+ p = rate; /* rate in khz*/
+ ioctl(fd, SNDCTL_DSP_SPEED, &p);
+
+ ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
+
+ /* try to subdivide BLKSIZE to reach blocksize if necessary */
+ if (min_size>blocksize)
+ {
+ cond=1;
+ p=min_size/blocksize;
+ while(cond)
+ {
+ i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
+ //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
+ if ((i==0) || (p==1)) cond=0;
+ else p=p/2;
+ }
+ }
+ ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
+ if (min_size>blocksize)
+ {
+ g_warning("dsp block size set to %i.",min_size);
+ }else{
+ /* no need to access the card with less latency than needed*/
+ min_size=blocksize;
+ }
+ close(fd);
+ return min_size;
+}
+
+
+int oss_card_open(OssCard *obj,int bits,int stereo,int rate)
+{
+ int fd;
+ obj->ref++;
+ if (obj->fd==0){
+ fd=oss_open(obj,bits,stereo,rate);
+ if (fd<0) {
+ obj->fd=0;
+ obj->ref--;
+ return -1;
+ }
+ }
+
+ obj->readbuf=g_malloc0(SND_CARD(obj)->bsize);
+ obj->writebuf=g_malloc0(SND_CARD(obj)->bsize);
+
+ SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
+ return 0;
+}
+
+void oss_card_close(OssCard *obj)
+{
+ int i;
+ obj->ref--;
+ if (obj->ref==0) {
+ close(obj->fd);
+ obj->fd=0;
+ SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
+ g_free(obj->readbuf);
+ obj->readbuf=NULL;
+ g_free(obj->writebuf);
+ obj->writebuf=NULL;
+
+ }
+}
+
+void oss_card_destroy(OssCard *obj)
+{
+ snd_card_uninit(SND_CARD(obj));
+ g_free(obj->dev_name);
+ g_free(obj->mixdev_name);
+ if (obj->readbuf!=NULL) g_free(obj->readbuf);
+ if (obj->writebuf!=NULL) g_free(obj->writebuf);
+}
+
+gboolean oss_card_can_read(OssCard *obj)
+{
+ struct timeval tout={0,0};
+ int err;
+ fd_set fdset;
+ if (obj->readpos!=0) return TRUE;
+ FD_ZERO(&fdset);
+ FD_SET(obj->fd,&fdset);
+ err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
+ if (err>0) return TRUE;
+ else return FALSE;
+}
+
+int oss_card_read(OssCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+ if (size<bsize){
+ gint canread=MIN(bsize-obj->readpos,size);
+ if (obj->readpos==0){
+ err=read(obj->fd,obj->readbuf,bsize);
+ if (err<0) {
+ g_warning("oss_card_read: read() failed:%s.",strerror(errno));
+ return -1;
+ }
+ }
+
+ memcpy(buf,&obj->readbuf[obj->readpos],canread);
+ obj->readpos+=canread;
+ if (obj->readpos>=bsize) obj->readpos=0;
+ return canread;
+ }else{
+ err=read(obj->fd,buf,size);
+ if (err<0) {
+ g_warning("oss_card_read: read-2() failed:%s.",strerror(errno));
+ }
+ return err;
+ }
+
+}
+
+int oss_card_write(OssCard *obj,char *buf,int size)
+{
+ int err;
+ gint bsize=SND_CARD(obj)->bsize;
+
+ if (size<bsize){
+ gint canwrite;
+ canwrite=MIN(bsize-obj->writepos,size);
+ memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
+ obj->writepos+=canwrite;
+ if (obj->writepos>=bsize){
+ err=write(obj->fd,obj->writebuf,bsize);
+ obj->writepos=0;
+ }
+ return canwrite;
+ }else{
+ return write(obj->fd,buf,bsize);
+ }
+}
+
+void oss_card_set_level(OssCard *obj,gint way,gint a)
+{
+ int p,mix_fd;
+ int osscmd;
+ g_return_if_fail(obj->mixdev_name!=NULL);
+#ifdef HAVE_SYS_SOUNDCARD_H
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ osscmd=SOUND_MIXER_VOLUME;
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ osscmd=SOUND_MIXER_IGAIN;
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ osscmd=SOUND_MIXER_PCM;
+ break;
+ default:
+ g_warning("oss_card_set_level: unsupported command.");
+ return;
+ }
+ p=(((int)a)<<8 | (int)a);
+ mix_fd = open(obj->mixdev_name, O_WRONLY);
+ ioctl(mix_fd,MIXER_WRITE(osscmd), &p);
+ close(mix_fd);
+#endif
+}
+
+gint oss_card_get_level(OssCard *obj,gint way)
+{
+ int p=0,mix_fd;
+ int osscmd;
+ g_return_if_fail(obj->mixdev_name!=NULL);
+#ifdef HAVE_SYS_SOUNDCARD_H
+ switch(way){
+ case SND_CARD_LEVEL_GENERAL:
+ osscmd=SOUND_MIXER_VOLUME;
+ break;
+ case SND_CARD_LEVEL_INPUT:
+ osscmd=SOUND_MIXER_IGAIN;
+ break;
+ case SND_CARD_LEVEL_OUTPUT:
+ osscmd=SOUND_MIXER_PCM;
+ break;
+ default:
+ g_warning("oss_card_get_level: unsupported command.");
+ return -1;
+ }
+ mix_fd = open(obj->mixdev_name, O_RDONLY);
+ ioctl(mix_fd,MIXER_READ(SOUND_MIXER_VOLUME), &p);
+ close(mix_fd);
+#endif
+ return p>>8;
+}
+
+void oss_card_set_source(OssCard *obj,int source)
+{
+ gint p=0;
+ gint mix_fd;
+ g_return_if_fail(obj->mixdev_name!=NULL);
+#ifdef HAVE_SYS_SOUNDCARD_H
+ if (source == 'c')
+ p = 1 << SOUND_MIXER_CD;
+ if (source == 'l')
+ p = 1 << SOUND_MIXER_LINE;
+ if (source == 'm')
+ p = 1 << SOUND_MIXER_MIC;
+
+
+ mix_fd = open(obj->mixdev_name, O_WRONLY);
+ ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p);
+ close(mix_fd);
+#endif
+}
+
+MSFilter *oss_card_create_read_filter(OssCard *card)
+{
+ MSFilter *f=ms_oss_read_new();
+ ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
+ return f;
+}
+
+MSFilter *oss_card_create_write_filter(OssCard *card)
+{
+ MSFilter *f=ms_oss_write_new();
+ ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
+ return f;
+}
+
+
+SndCard * oss_card_new(char *devname, char *mixdev_name)
+{
+ OssCard * obj= g_new0(OssCard,1);
+ SndCard *base= SND_CARD(obj);
+ snd_card_init(base);
+ obj->dev_name=g_strdup(devname);
+ obj->mixdev_name=g_strdup( mixdev_name);
+#ifdef HAVE_GLIB
+ base->card_name=g_strdup_printf("%s (Open Sound System)",devname);
+#else
+ base->card_name=malloc(100);
+ snprintf(base->card_name, 100, "%s (Open Sound System)",devname);
+#endif
+ base->_probe=(SndCardOpenFunc)oss_card_probe;
+ base->_open_r=(SndCardOpenFunc)oss_card_open;
+ base->_open_w=(SndCardOpenFunc)oss_card_open;
+ base->_can_read=(SndCardPollFunc)oss_card_can_read;
+ base->_read=(SndCardIOFunc)oss_card_read;
+ base->_write=(SndCardIOFunc)oss_card_write;
+ base->_close_r=(SndCardCloseFunc)oss_card_close;
+ base->_close_w=(SndCardCloseFunc)oss_card_close;
+ base->_set_rec_source=(SndCardMixerSetRecSourceFunc)oss_card_set_source;
+ base->_set_level=(SndCardMixerSetLevelFunc)oss_card_set_level;
+ base->_get_level=(SndCardMixerGetLevelFunc)oss_card_get_level;
+ base->_destroy=(SndCardDestroyFunc)oss_card_destroy;
+ base->_create_read_filter=(SndCardCreateFilterFunc)oss_card_create_read_filter;
+ base->_create_write_filter=(SndCardCreateFilterFunc)oss_card_create_write_filter;
+ return base;
+}
+
+#define DSP_NAME "/dev/dsp"
+#define MIXER_NAME "/dev/mixer"
+
+gint oss_card_manager_init(SndCardManager *manager, gint tabindex)
+{
+ gchar *devname;
+ gchar *mixername;
+ gint devindex=0;
+ gint found=0;
+
+ /* search for /dev/dsp and /dev/mixer */
+#ifdef HAVE_GLIB
+ if (g_file_test(DSP_NAME,G_FILE_TEST_EXISTS)){
+ tabindex++;
+ devindex++;
+ manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
+ manager->cards[0]->index=0;
+ found++;
+ g_message("Found /dev/dsp.");
+ }
+ for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
+ devname=g_strdup_printf("%s%i",DSP_NAME,devindex);
+ mixername=g_strdup_printf("%s%i",MIXER_NAME,devindex);
+ if (g_file_test(devname,G_FILE_TEST_EXISTS)){
+ manager->cards[tabindex]=oss_card_new(devname,mixername);
+ manager->cards[tabindex]->index=tabindex;
+ tabindex++;
+ found++;
+ }
+ g_free(devname);
+ g_free(mixername);
+ }
+#else
+ if (access(DSP_NAME,F_OK)==0){
+ tabindex++;
+ devindex++;
+ manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
+ manager->cards[0]->index=0;
+ found++;
+ g_message("Found /dev/dsp.");
+ }
+ for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
+ devname=malloc(100);
+ snprintf(devname, 100, "%s%i",DSP_NAME,devindex);
+ mixername=malloc(100);
+ snprintf(mixername, 100, "%s%i",MIXER_NAME,devindex);
+
+ if (access(devname,F_OK)==0){
+ manager->cards[tabindex]=oss_card_new(devname,mixername);
+ manager->cards[tabindex]->index=tabindex;
+ tabindex++;
+ found++;
+ }
+ g_free(devname);
+ g_free(mixername);
+ }
+#endif
+ if (tabindex==0) g_warning("No sound cards found !");
+ return found;
+}
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h
new file mode 100644
index 00000000..30b96c23
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/osscard.h
@@ -0,0 +1,47 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/* An implementation of SndCard : the OssCard */
+
+#ifndef OSS_CARD_H
+#define OSS_CARD_H
+
+#include "sndcard.h"
+
+#define OSS_CARD_BUFFERS 3
+struct _OssCard
+{
+ SndCard parent;
+ gchar *dev_name; /* /dev/dsp0 for example */
+ gchar *mixdev_name; /* /dev/mixer0 for example */
+ gint fd; /* the file descriptor of the open soundcard, 0 if not open*/
+ gint ref;
+ gchar *readbuf;
+ gint readpos;
+ gchar *writebuf;
+ gint writepos;
+};
+
+typedef struct _OssCard OssCard;
+
+SndCard * oss_card_new(char *devname, char *mixdev_name);
+
+typedef OssCard HpuxSndCard;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c
new file mode 100644
index 00000000..9570b905
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.c
@@ -0,0 +1,315 @@
+/*
+ Copyright (C) 2005 Remko Troncon
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <portaudio.h>
+#include <stdlib.h>
+
+#include "portaudiocard.h"
+#include "msossread.h"
+#include "msosswrite.h"
+
+// Settings
+#define BUFFER_SIZE 2048
+
+// PortAudio settings
+#define FRAMES_PER_BUFFER 256
+
+
+// -----------------------------------------------------------------------------
+
+int readBuffer(char* buffer, char** buffer_read_p, char*buffer_write, char* buffer_end, char* target_buffer, int target_len)
+{
+ char *end, *tmp, *buffer_read = *buffer_read_p;
+ size_t remaining, len;
+ int read = 0;
+
+ // First phase
+ tmp = buffer_read + target_len;
+ if (buffer_write < buffer_read) {
+ if (tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+ else {
+ end = (tmp >= buffer_write ? buffer_write : tmp);
+ remaining = 0;
+ }
+ //printf("end: %p\n",end);
+
+ // Copy the data
+ len = end - buffer_read;
+ memcpy(target_buffer, buffer_read, len);
+ buffer_read += len;
+ target_buffer += len;
+ read += len;
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_read = buffer;
+ tmp = buffer_read + remaining;
+ len = (tmp > buffer_write ? buffer_write : tmp) - buffer_read;
+ memcpy(target_buffer, buffer_read, len);
+ buffer_read += len;
+ read += len;
+ }
+
+ // Finish up
+ *buffer_read_p = buffer_read;
+
+ return read;
+}
+
+int writeBuffer(char* buffer, char* buffer_read, char** buffer_write_p, char* buffer_end, char* source_buffer, int source_len)
+{
+ char *end, *tmp, *buffer_write = *buffer_write_p;
+ size_t remaining, len;
+ int written = 0;
+
+ // First phase
+ tmp = buffer_write + source_len;
+ if (buffer_write >= buffer_read) {
+ if (tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+ else {
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s) %p %p\n", tmp, buffer_read);
+ end = buffer_read;
+ remaining = 0;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+
+ len = end - buffer_write;
+ memcpy(buffer_write, source_buffer, len);
+ buffer_write += len;
+ source_buffer += len;
+ written += len;
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_write = buffer;
+ tmp = buffer_write + remaining;
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s) %p %p\n", tmp, buffer_read);
+ end = buffer_read;
+ }
+ else {
+ end = tmp;
+ }
+
+ len = end - buffer_write;
+ memcpy(buffer_write, source_buffer, len);
+ buffer_write += len;
+ written += len;
+ }
+
+ // Finish up
+ *buffer_write_p = buffer_write;
+ return written;
+}
+
+// -----------------------------------------------------------------------------
+
+static int portAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *card_p )
+{
+ PortAudioCard* card = (PortAudioCard*) card_p;
+
+ size_t len = framesPerBuffer * Pa_GetSampleSize(paInt16);
+ //printf("PA::readBuffer begin %p %p %p %p %d\n",card->out_buffer,card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, len);
+ readBuffer(card->out_buffer,&card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, outputBuffer, len);
+ //printf("PA::readBuffer end %p %p %p %p %d\n",card->out_buffer,card->out_buffer_read,card->out_buffer_write,card->out_buffer_end, len);
+ writeBuffer(card->in_buffer,card->in_buffer_read,&card->in_buffer_write,card->in_buffer_end, inputBuffer, len);
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+int portaudio_card_probe(PortAudioCard *obj, int bits, int stereo, int rate)
+{
+ return FRAMES_PER_BUFFER * (SND_CARD(obj)->stereo ? 2 : 1) * Pa_GetSampleSize(paInt16);
+}
+
+
+int portaudio_card_open_r(PortAudioCard *obj,int bits,int stereo,int rate)
+{
+ fprintf(stderr,"Opening PortAudio card\n");
+
+ int err;
+ err = Pa_OpenDefaultStream(&obj->stream, 1, 1, paInt16, rate, FRAMES_PER_BUFFER, 0, portAudioCallback, obj);
+ if (err != paNoError) {
+ fprintf(stderr, "Error creating a PortAudio stream: %s\n", Pa_GetErrorText(err));
+ return -1;
+ }
+
+ err = Pa_StartStream(obj->stream);
+ if (err != paNoError) {
+ fprintf(stderr, "Error starting PortAudio stream: %s\n", Pa_GetErrorText(err));
+ Pa_CloseStream(obj->stream);
+ obj->stream = NULL;
+ return -1;
+ }
+
+ SND_CARD(obj)->bits = 16;
+ SND_CARD(obj)->stereo = 0;
+ SND_CARD(obj)->rate = rate;
+ // Should this be multiplied by Pa_GetMinNumBuffers(FRAMES_PER_BUFFER,sampleRate) ?
+ SND_CARD(obj)->bsize = FRAMES_PER_BUFFER * (SND_CARD(obj)->stereo ? 2 : 1) * Pa_GetSampleSize(paInt16);
+
+ return 0;
+
+}
+
+void portaudio_card_close_r(PortAudioCard *obj)
+{
+ fprintf(stderr, "Closing PortAudio card\n");
+ if (obj->stream) {
+ Pa_StopStream(obj->stream);
+ Pa_CloseStream(obj->stream);
+ obj->stream = NULL;
+ }
+}
+
+int portaudio_card_open_w(PortAudioCard *obj,int bits,int stereo,int rate)
+{
+}
+
+void portaudio_card_close_w(PortAudioCard *obj)
+{
+}
+
+void portaudio_card_destroy(PortAudioCard *obj)
+{
+ snd_card_uninit(SND_CARD(obj));
+ free(obj->in_buffer);
+ free(obj->out_buffer);
+}
+
+gboolean portaudio_card_can_read(PortAudioCard *obj)
+{
+ return obj->in_buffer_read != obj->in_buffer_write;
+}
+
+int portaudio_card_read(PortAudioCard *obj,char *buf,int size)
+{
+ //printf("read begin %p %p %p %p %d\n",obj->in_buffer,obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, size);
+ return readBuffer(obj->in_buffer,&obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, buf, size);
+ //printf("read end %p %p %p %p %d\n",obj->in_buffer,obj->in_buffer_read,obj->in_buffer_write,obj->in_buffer_end, size);
+}
+
+int portaudio_card_write(PortAudioCard *obj,char *buf,int size)
+{
+ //printf("writeBuffer begin %p %p %p %p %d\n",obj->out_buffer,obj->out_buffer_read,obj->out_buffer_write,obj->out_buffer_end, size);
+ return writeBuffer(obj->out_buffer,obj->out_buffer_read,&obj->out_buffer_write,obj->out_buffer_end, buf, size);
+ //printf("writeBuffer end %p %p %p %p %d\n",obj->out_buffer,obj->out_buffer_read,obj->out_buffer_write,obj->out_buffer_end, size);
+}
+
+void portaudio_card_set_level(PortAudioCard *obj,gint way,gint a)
+{
+}
+
+gint portaudio_card_get_level(PortAudioCard *obj,gint way)
+{
+ return 0;
+}
+
+void portaudio_card_set_source(PortAudioCard *obj,int source)
+{
+}
+
+MSFilter *portaudio_card_create_read_filter(PortAudioCard *card)
+{
+ MSFilter *f=ms_oss_read_new();
+ ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
+ return f;
+}
+
+MSFilter *portaudio_card_create_write_filter(PortAudioCard *card)
+{
+ MSFilter *f=ms_oss_write_new();
+ ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
+ return f;
+}
+
+
+SndCard* portaudio_card_new()
+{
+ // Basic stuff
+ PortAudioCard* obj= g_new0(PortAudioCard,1);
+ SndCard* base= SND_CARD(obj);
+ snd_card_init(base);
+ base->card_name=g_strdup_printf("PortAudio Card");
+ base->_probe=(SndCardOpenFunc)portaudio_card_probe;
+ base->_open_r=(SndCardOpenFunc)portaudio_card_open_r;
+ base->_open_w=(SndCardOpenFunc)portaudio_card_open_w;
+ base->_can_read=(SndCardPollFunc)portaudio_card_can_read;
+ base->_read=(SndCardIOFunc)portaudio_card_read;
+ base->_write=(SndCardIOFunc)portaudio_card_write;
+ base->_close_r=(SndCardCloseFunc)portaudio_card_close_r;
+ base->_close_w=(SndCardCloseFunc)portaudio_card_close_w;
+ base->_set_rec_source=(SndCardMixerSetRecSourceFunc)portaudio_card_set_source;
+ base->_set_level=(SndCardMixerSetLevelFunc)portaudio_card_set_level;
+ base->_get_level=(SndCardMixerGetLevelFunc)portaudio_card_get_level;
+ base->_destroy=(SndCardDestroyFunc)portaudio_card_destroy;
+ base->_create_read_filter=(SndCardCreateFilterFunc)portaudio_card_create_read_filter;
+ base->_create_write_filter=(SndCardCreateFilterFunc)portaudio_card_create_write_filter;
+
+ // Initialize stream
+ obj->stream = NULL;
+
+ // Initialize buffers
+ obj->out_buffer = (char*) malloc(sizeof(char)*BUFFER_SIZE);
+ obj->out_buffer_read = obj->out_buffer_write = obj->out_buffer;
+ obj->out_buffer_end = obj->out_buffer + BUFFER_SIZE;
+ obj->in_buffer = (char*) malloc(sizeof(char)*BUFFER_SIZE);
+ obj->in_buffer_read = obj->in_buffer_write = obj->in_buffer;
+ obj->in_buffer_end = obj->in_buffer + BUFFER_SIZE;
+
+ return base;
+}
+
+gint portaudio_card_manager_init(SndCardManager *manager, gint tabindex)
+{
+ // Initialize portaudio lib
+ int err = Pa_Initialize();
+ if (err != paNoError) {
+ fprintf(stderr,"Error initializing PortAudio: %s\n",Pa_GetErrorText(err));
+ return 0;
+ }
+
+ // Create new card
+ manager->cards[0]=portaudio_card_new();
+ manager->cards[0]->index=0;
+
+ return 1;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h
new file mode 100644
index 00000000..cbaa7982
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/portaudiocard.h
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2005 Remko Troncon
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/* An implementation of SndCard : the OssCard */
+
+#ifndef PORTAUDIO_CARD_H
+#define PORTAUDIO_CARD_H
+
+#include "sndcard.h"
+
+typedef struct _PortAudioCard
+{
+ SndCard parent;
+ PortAudioStream* stream;
+ char *out_buffer, *out_buffer_read, *out_buffer_write, *out_buffer_end;
+ char *in_buffer, *in_buffer_read, *in_buffer_write, *in_buffer_end;
+} PortAudioCard;
+
+gint portaudio_card_manager_init(SndCardManager *manager, gint tabindex);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c
new file mode 100644
index 00000000..3a0f5d9a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.c
@@ -0,0 +1,209 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "sndcard.h"
+#include "msfilter.h"
+
+void snd_card_init(SndCard *obj)
+{
+ memset(obj,0,sizeof(SndCard));
+}
+
+void snd_card_uninit(SndCard *obj)
+{
+ if (obj->card_name!=NULL) g_free(obj->card_name);
+}
+
+const gchar *snd_card_get_identifier(SndCard *obj)
+{
+ return obj->card_name;
+}
+
+int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate)
+{
+ g_return_val_if_fail(obj->_open_r!=NULL,-1);
+ g_message("Opening sound card [%s] in capture mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
+ return obj->_open_r(obj,bits,stereo,rate);
+}
+int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate)
+{
+ g_return_val_if_fail(obj->_open_w!=NULL,-1);
+ g_message("Opening sound card [%s] in playback mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
+ return obj->_open_w(obj,bits,stereo,rate);
+}
+
+gboolean snd_card_can_read(SndCard *obj){
+ g_return_val_if_fail(obj->_can_read!=NULL,-1);
+ return obj->_can_read(obj);
+}
+
+void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno){
+ g_return_if_fail(obj->_set_blocking_mode!=NULL);
+ obj->_set_blocking_mode(obj,yesno);
+}
+
+int snd_card_read(SndCard *obj,char *buffer,int size)
+{
+ g_return_val_if_fail(obj->_read!=NULL,-1);
+ return obj->_read(obj,buffer,size);
+}
+int snd_card_write(SndCard *obj,char *buffer,int size)
+{
+ g_return_val_if_fail(obj->_write!=NULL,-1);
+ return obj->_write(obj,buffer,size);
+}
+
+int snd_card_get_bsize(SndCard *obj)
+{
+ if (obj->flags & SND_CARD_FLAGS_OPENED){
+ return obj->bsize;
+ }
+ return -1;
+}
+
+void snd_card_close_r(SndCard *obj)
+{
+ g_return_if_fail(obj->_close_r!=NULL);
+ g_message("Closing reading channel of soundcard.");
+ obj->_close_r(obj);
+}
+
+void snd_card_close_w(SndCard *obj)
+{
+ g_return_if_fail(obj->_close_w!=NULL);
+ g_message("Closing writing channel of soundcard.");
+ obj->_close_w(obj);
+}
+
+gint snd_card_probe(SndCard *obj,int bits, int stereo, int rate)
+{
+ g_return_val_if_fail(obj->_probe!=NULL,-1);
+ return obj->_probe(obj,bits,stereo,rate);
+}
+
+void snd_card_set_rec_source(SndCard *obj, int source)
+{
+ g_return_if_fail(obj->_set_rec_source!=NULL);
+ obj->_set_rec_source(obj,source);
+}
+
+void snd_card_set_level(SndCard *obj, int way, int level)
+{
+ g_return_if_fail(obj->_set_level!=NULL);
+ obj->_set_level(obj,way,level);
+}
+
+gint snd_card_get_level(SndCard *obj,int way)
+{
+ g_return_val_if_fail(obj->_get_level!=NULL,-1);
+ return obj->_get_level(obj,way);
+}
+
+
+MSFilter * snd_card_create_read_filter(SndCard *obj)
+{
+ g_return_val_if_fail(obj->_create_read_filter!=NULL,NULL);
+ return obj->_create_read_filter(obj);
+}
+MSFilter * snd_card_create_write_filter(SndCard *obj)
+{
+ g_return_val_if_fail(obj->_create_write_filter!=NULL,NULL);
+ return obj->_create_write_filter(obj);
+}
+
+
+#ifdef HAVE_SYS_AUDIO_H
+gint sys_audio_manager_init(SndCardManager *manager, gint index)
+{
+ /* this is a quick shortcut, as multiple soundcards on HPUX does not happen
+ very often... */
+ manager->cards[index]=hpux_snd_card_new("/dev/audio","/dev/audio");
+ return 1;
+}
+
+#endif
+
+#include "osscard.h"
+#include "alsacard.h"
+#include "jackcard.h"
+
+void snd_card_manager_init(SndCardManager *manager)
+{
+ gint index=0;
+ gint tmp=0;
+ memset(manager,0,sizeof(SndCardManager));
+ #ifdef HAVE_SYS_SOUNDCARD_H
+ tmp=oss_card_manager_init(manager,index);
+ index+=tmp;
+ if (index>=MAX_SND_CARDS) return;
+ #endif
+ #ifdef __ALSA_ENABLED__
+ tmp=alsa_card_manager_init(manager,index);
+ index+=tmp;
+ if (index>=MAX_SND_CARDS) return;
+ #endif
+ #ifdef __JACK_ENABLED__
+ tmp=jack_card_manager_init(manager,index);
+ index+=tmp;
+ if (index>=MAX_SND_CARDS) return;
+ #endif
+ #ifdef HAVE_PORTAUDIO
+ tmp=portaudio_card_manager_init(manager,index);
+ index+=tmp;
+ if (index>=MAX_SND_CARDS) return;
+ #endif
+ #ifdef HAVE_SYS_AUDIO_H
+ tmp=sys_audio_manager_init(manager,index);
+ index+=tmp;
+ #endif
+}
+
+
+
+
+
+SndCard * snd_card_manager_get_card(SndCardManager *manager,int index)
+{
+ g_return_val_if_fail(index>=0,NULL);
+ g_return_val_if_fail(index<MAX_SND_CARDS,NULL);
+ if (index>MAX_SND_CARDS) return NULL;
+ return manager->cards[index];
+}
+
+SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index)
+{
+ int i;
+ for (i=0;i<MAX_SND_CARDS;i++){
+ gchar *card_name;
+ if (manager->cards[i]==NULL) continue;
+ card_name=manager->cards[i]->card_name;
+ if (card_name==NULL) continue;
+ if (strcmp(card_name,cardname)==0){
+ *index=i;
+ return manager->cards[i];
+ }
+ }
+ g_warning("No card %s found.",cardname);
+ return NULL;
+}
+
+SndCardManager _snd_card_manager;
+SndCardManager *snd_card_manager=&_snd_card_manager;
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h
new file mode 100644
index 00000000..d84757fd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/sndcard.h
@@ -0,0 +1,143 @@
+/*
+ The mediastreamer library aims at providing modular media processing and I/O
+ for linphone, but also for any telephony application.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#ifndef SNDCARD_H
+#define SNDCARD_H
+
+#undef PACKAGE
+#undef VERSION
+#include <config.h>
+#undef PACKAGE
+#undef VERSION
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#else
+#include <uglib.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* the base class for all soundcards: SndCard */
+struct _SndCard;
+
+typedef int (*SndCardOpenFunc)(struct _SndCard*,int, int, int);
+typedef void (*SndCardSetBlockingModeFunc)(struct _SndCard*, gboolean );
+typedef void (*SndCardCloseFunc)(struct _SndCard*);
+typedef gint (*SndCardIOFunc)(struct _SndCard*,char *,int);
+typedef void (*SndCardDestroyFunc)(struct _SndCard*);
+typedef gboolean (*SndCardPollFunc)(struct _SndCard*);
+typedef gint (*SndCardMixerGetLevelFunc)(struct _SndCard*,gint);
+typedef void (*SndCardMixerSetRecSourceFunc)(struct _SndCard*,gint);
+typedef void (*SndCardMixerSetLevelFunc)(struct _SndCard*,gint ,gint);
+typedef struct _MSFilter * (*SndCardCreateFilterFunc)(struct _SndCard *);
+
+struct _SndCard
+{
+ gchar *card_name; /* SB16 PCI for example */
+ gint index;
+ gint bsize;
+ gint rate;
+ gint stereo;
+ gint bits;
+ gint flags;
+#define SND_CARD_FLAGS_OPENED 1
+ SndCardOpenFunc _probe;
+ SndCardOpenFunc _open_r;
+ SndCardOpenFunc _open_w;
+ SndCardSetBlockingModeFunc _set_blocking_mode;
+ SndCardPollFunc _can_read;
+ SndCardIOFunc _read;
+ SndCardIOFunc _write;
+ SndCardCloseFunc _close_r;
+ SndCardCloseFunc _close_w;
+ SndCardMixerGetLevelFunc _get_level;
+ SndCardMixerSetLevelFunc _set_level;
+ SndCardMixerSetRecSourceFunc _set_rec_source;
+ SndCardCreateFilterFunc _create_read_filter;
+ SndCardCreateFilterFunc _create_write_filter;
+ SndCardDestroyFunc _destroy;
+};
+
+
+typedef struct _SndCard SndCard;
+
+void snd_card_init(SndCard *obj);
+void snd_card_uninit(SndCard *obj);
+gint snd_card_probe(SndCard *obj, int bits, int stereo, int rate);
+int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate);
+int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate);
+int snd_card_get_bsize(SndCard *obj);
+gboolean snd_card_can_read(SndCard *obj);
+int snd_card_read(SndCard *obj,char *buffer,int size);
+int snd_card_write(SndCard *obj,char *buffer,int size);
+void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno);
+void snd_card_close_r(SndCard *obj);
+void snd_card_close_w(SndCard *obj);
+
+void snd_card_set_rec_source(SndCard *obj, int source); /* source='l' or 'm'*/
+void snd_card_set_level(SndCard *obj, int way, int level);
+gint snd_card_get_level(SndCard *obj,int way);
+
+const gchar *snd_card_get_identifier(SndCard *obj);
+
+struct _MSFilter * snd_card_create_read_filter(SndCard *sndcard);
+struct _MSFilter * snd_card_create_write_filter(SndCard *sndcard);
+
+
+#define SND_CARD_LEVEL_GENERAL 1
+#define SND_CARD_LEVEL_INPUT 2
+#define SND_CARD_LEVEL_OUTPUT 3
+
+
+int snd_card_destroy(SndCard *obj);
+
+#define SND_CARD(obj) ((SndCard*)(obj))
+
+
+
+
+/* SndCardManager */
+
+#define MAX_SND_CARDS 20
+
+
+struct _SndCardManager
+{
+ SndCard *cards[MAX_SND_CARDS];
+};
+
+typedef struct _SndCardManager SndCardManager;
+
+void snd_card_manager_init(SndCardManager *manager);
+SndCard * snd_card_manager_get_card(SndCardManager *manager,int index);
+SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index);
+
+extern SndCardManager *snd_card_manager;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h
new file mode 100644
index 00000000..6768d8f8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/waveheader.h
@@ -0,0 +1,111 @@
+/*
+linphone
+Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* the following code was taken from a free software utility that I don't remember the name. */
+/* sorry */
+
+
+
+#include <ms.h>
+#ifndef waveheader_h
+#define waveheader_h
+
+typedef struct uint16scheme
+{
+ unsigned char lo_byte;
+ unsigned char hi_byte;
+} uint16scheme_t;
+
+typedef struct uint32scheme
+{
+ guint16 lo_int;
+ guint16 hi_int;
+} uint32scheme_t;
+
+
+/* all integer in wav header must be read in least endian order */
+inline guint16 _readuint16(guint16 a)
+{
+ guint16 res;
+ uint16scheme_t *tmp1=(uint16scheme_t*)&a;
+
+ ((uint16scheme_t *)(&res))->lo_byte=tmp1->hi_byte;
+ ((uint16scheme_t *)(&res))->hi_byte=tmp1->lo_byte;
+ return res;
+}
+
+inline guint32 _readuint32(guint32 a)
+{
+ guint32 res;
+ uint32scheme_t *tmp1=(uint32scheme_t*)&a;
+
+ ((uint32scheme_t *)(&res))->lo_int=_readuint16(tmp1->hi_int);
+ ((uint32scheme_t *)(&res))->hi_int=_readuint16(tmp1->lo_int);
+ return res;
+}
+
+#ifdef WORDS_BIGENDIAN
+#define le_uint32(a) (_readuint32((a)))
+#define le_uint16(a) (_readuint16((a)))
+#define le_int16(a) ( (gint16) _readuint16((guint16)((a))) )
+#else
+#define le_uint32(a) (a)
+#define le_uint16(a) (a)
+#define le_int16(a) (a)
+#endif
+
+typedef struct _riff_t {
+ char riff[4] ; /* "RIFF" (ASCII characters) */
+ guint32 len ; /* Length of package (binary, little endian) */
+ char wave[4] ; /* "WAVE" (ASCII characters) */
+} riff_t;
+
+/* The FORMAT chunk */
+
+typedef struct _format_t {
+ char fmt[4] ; /* "fmt_" (ASCII characters) */
+ guint32 len ; /* length of FORMAT chunk (always 0x10) */
+ guint16 que ; /* Always 0x01 */
+ guint16 channel ; /* Channel numbers (0x01 = mono, 0x02 = stereo) */
+ guint32 rate ; /* Sample rate (binary, in Hz) */
+ guint32 bps ; /* Bytes Per Second */
+ guint16 bpsmpl ; /* bytes per sample: 1 = 8 bit Mono,
+ 2 = 8 bit Stereo/16 bit Mono,
+ 4 = 16 bit Stereo */
+ guint16 bitpspl ; /* bits per sample */
+} format_t;
+
+/* The DATA chunk */
+
+typedef struct _data_t {
+ char data[4] ; /* "data" (ASCII characters) */
+ int len ; /* length of data */
+} data_t;
+
+typedef struct _wave_header_t
+{
+ riff_t riff_chunk;
+ format_t format_chunk;
+ data_t data_chunk;
+} wave_header_t;
+
+#define wave_header_get_rate(header) le_uint32((header)->format_chunk.rate)
+#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel)
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am
new file mode 100644
index 00000000..1e7abcfd
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am
@@ -0,0 +1,18 @@
+libcricketxmllite_la_SOURCES = qname.cc \
+ xmlbuilder.cc \
+ xmlconstants.cc \
+ xmlelement.cc \
+ xmlnsstack.cc \
+ xmlparser.cc \
+ xmlprinter.cc
+
+noinst_HEADERS = qname.h \
+ xmlbuilder.h \
+ xmlconstants.h \
+ xmlelement.h \
+ xmlnsstack.h \
+ xmlparser.h \
+ xmlprinter.h
+AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../..
+
+noinst_LTLIBRARIES = libcricketxmllite.la
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc
new file mode 100644
index 00000000..626cfa96
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc
@@ -0,0 +1,167 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlconstants.h"
+
+//#define new TRACK_NEW
+
+namespace buzz {
+
+static int QName_Hash(const std::string & ns, const char * local) {
+ int result = ns.size() * 101;
+ while (*local) {
+ result *= 19;
+ result += *local;
+ local += 1;
+ }
+ return result;
+}
+
+static const int bits = 9;
+static QName::Data * get_qname_table() {
+ static QName::Data qname_table[1 << bits];
+ return qname_table;
+}
+
+static QName::Data *
+AllocateOrFind(const std::string & ns, const char * local) {
+ int index = QName_Hash(ns, local);
+ int increment = index >> (bits - 1) | 1;
+ QName::Data * qname_table = get_qname_table();
+ for (;;) {
+ index &= ((1 << bits) - 1);
+ if (!qname_table[index].Occupied()) {
+ return new QName::Data(ns, local);
+ }
+ if (qname_table[index].localPart_ == local &&
+ qname_table[index].namespace_ == ns) {
+ qname_table[index].AddRef();
+ return qname_table + index;
+ }
+ index += increment;
+ }
+}
+
+static QName::Data *
+Add(const std::string & ns, const char * local) {
+ int index = QName_Hash(ns, local);
+ int increment = index >> (bits - 1) | 1;
+ QName::Data * qname_table = get_qname_table();
+ for (;;) {
+ index &= ((1 << bits) - 1);
+ if (!qname_table[index].Occupied()) {
+ qname_table[index].namespace_ = ns;
+ qname_table[index].localPart_ = local;
+ qname_table[index].AddRef(); // AddRef twice so it's never deleted
+ qname_table[index].AddRef();
+ return qname_table + index;
+ }
+ if (qname_table[index].localPart_ == local &&
+ qname_table[index].namespace_ == ns) {
+ qname_table[index].AddRef();
+ return qname_table + index;
+ }
+ index += increment;
+ }
+}
+
+QName::~QName() {
+ data_->Release();
+}
+
+QName::QName() : data_(QN_EMPTY.data_) {
+ data_->AddRef();
+}
+
+QName::QName(bool add, const std::string & ns, const char * local) :
+ data_(add ? Add(ns, local) : AllocateOrFind(ns, local)) {}
+
+QName::QName(bool add, const std::string & ns, const std::string & local) :
+ data_(add ? Add(ns, local.c_str()) : AllocateOrFind(ns, local.c_str())) {}
+
+QName::QName(const std::string & ns, const char * local) :
+ data_(AllocateOrFind(ns, local)) {}
+
+static std::string
+QName_LocalPart(const std::string & name) {
+ size_t i = name.rfind(':');
+ if (i == std::string::npos)
+ return name;
+ return name.substr(i + 1);
+}
+
+static std::string
+QName_Namespace(const std::string & name) {
+ size_t i = name.rfind(':');
+ if (i == std::string::npos)
+ return STR_EMPTY;
+ return name.substr(0, i);
+}
+
+QName::QName(const std::string & mergedOrLocal) :
+ data_(AllocateOrFind(QName_Namespace(mergedOrLocal),
+ QName_LocalPart(mergedOrLocal).c_str())) {}
+
+std::string
+QName::Merged() const {
+ if (data_->namespace_ == STR_EMPTY)
+ return data_->localPart_;
+
+ std::string result(data_->namespace_);
+ result.reserve(result.length() + 1 + data_->localPart_.length());
+ result += ':';
+ result += data_->localPart_;
+ return result;
+}
+
+bool
+QName::operator==(const QName & other) const {
+ return other.data_ == data_ ||
+ data_->localPart_ == other.data_->localPart_ &&
+ data_->namespace_ == other.data_->namespace_;
+}
+
+int
+QName::Compare(const QName & other) const {
+ if (data_ == other.data_)
+ return 0;
+
+ int result = data_->localPart_.compare(other.data_->localPart_);
+ if (result)
+ return result;
+
+ return data_->namespace_.compare(other.data_->namespace_);
+}
+
+}
+
+
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h
new file mode 100644
index 00000000..b1bcec61
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h
@@ -0,0 +1,87 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _qname_h_
+#define _qname_h_
+
+#include <string>
+
+namespace buzz {
+
+
+class QName
+{
+public:
+ explicit QName();
+ QName(const QName & qname) : data_(qname.data_) { data_->AddRef(); }
+ explicit QName(bool add, const std::string & ns, const char * local);
+ explicit QName(bool add, const std::string & ns, const std::string & local);
+ explicit QName(const std::string & ns, const char * local);
+ explicit QName(const std::string & mergedOrLocal);
+ QName & operator=(const QName & qn) {
+ qn.data_->AddRef();
+ data_->Release();
+ data_ = qn.data_;
+ return *this;
+ }
+ ~QName();
+
+ const std::string & Namespace() const { return data_->namespace_; }
+ const std::string & LocalPart() const { return data_->localPart_; }
+ std::string Merged() const;
+ int Compare(const QName & other) const;
+ bool operator==(const QName & other) const;
+ bool operator!=(const QName & other) const { return !operator==(other); }
+ bool operator<(const QName & other) const { return Compare(other) < 0; }
+
+ class Data {
+ public:
+ Data(const std::string & ns, const std::string & local) :
+ refcount_(1),
+ namespace_(ns),
+ localPart_(local) {}
+
+ Data() : refcount_(0) {}
+
+ std::string namespace_;
+ std::string localPart_;
+ void AddRef() { refcount_++; }
+ void Release() { if (!--refcount_) { delete this; } }
+ bool Occupied() { return !!refcount_; }
+
+ private:
+ int refcount_;
+ };
+
+private:
+ Data * data_;
+};
+
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc
new file mode 100644
index 00000000..313c4013
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc
@@ -0,0 +1,151 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/stl_decl.h"
+#include <vector>
+#include <set>
+#include <expat.h>
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlbuilder.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+XmlBuilder::XmlBuilder() :
+ pelCurrent_(NULL),
+ pelRoot_(NULL),
+ pvParents_(new std::vector<XmlElement *>()) {
+}
+
+void
+XmlBuilder::Reset() {
+ pelRoot_.reset();
+ pelCurrent_ = NULL;
+ pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::BuildElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) {
+ QName tagName(pctx->ResolveQName(name, false));
+ if (tagName == QN_EMPTY)
+ return NULL;
+
+ XmlElement * pelNew = new XmlElement(tagName);
+
+ if (!*atts)
+ return pelNew;
+
+ std::set<QName> seenNonlocalAtts;
+
+ while (*atts) {
+ QName attName(pctx->ResolveQName(*atts, true));
+ if (attName == QN_EMPTY) {
+ delete pelNew;
+ return NULL;
+ }
+
+ // verify that namespaced names are unique
+ if (!attName.Namespace().empty()) {
+ if (seenNonlocalAtts.count(attName)) {
+ delete pelNew;
+ return NULL;
+ }
+ seenNonlocalAtts.insert(attName);
+ }
+
+ pelNew->AddAttr(attName, std::string(*(atts + 1)));
+ atts += 2;
+ }
+
+ return pelNew;
+}
+
+void
+XmlBuilder::StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) {
+ XmlElement * pelNew = BuildElement(pctx, name, atts);
+ if (pelNew == NULL) {
+ pctx->RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (!pelCurrent_) {
+ pelCurrent_ = pelNew;
+ pelRoot_.reset(pelNew);
+ pvParents_->push_back(NULL);
+ } else {
+ pelCurrent_->AddElement(pelNew);
+ pvParents_->push_back(pelCurrent_);
+ pelCurrent_ = pelNew;
+ }
+}
+
+void
+XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
+ UNUSED(pctx);
+ UNUSED(name);
+ pelCurrent_ = pvParents_->back();
+ pvParents_->pop_back();
+}
+
+void
+XmlBuilder::CharacterData(XmlParseContext * pctx,
+ const char * text, int len) {
+ UNUSED(pctx);
+ if (pelCurrent_) {
+ pelCurrent_->AddParsedText(text, len);
+ }
+}
+
+void
+XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
+ UNUSED(pctx);
+ UNUSED(err);
+ pelRoot_.reset(NULL);
+ pelCurrent_ = NULL;
+ pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::CreateElement() {
+ return pelRoot_.release();
+}
+
+XmlElement *
+XmlBuilder::BuiltElement() {
+ return pelRoot_.get();
+}
+
+XmlBuilder::~XmlBuilder() {
+}
+
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h
new file mode 100644
index 00000000..b5b1be59
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h
@@ -0,0 +1,79 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmlbuilder_h_
+#define _xmlbuilder_h_
+
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stl_decl.h"
+#include "talk/xmllite/xmlparser.h"
+
+#ifdef OSX
+#include "talk/third_party/expat/expat.h"
+#else
+#include <expat.h>
+#endif
+
+namespace buzz {
+
+class XmlElement;
+class XmlParseContext;
+
+
+class XmlBuilder : public XmlParseHandler {
+public:
+ XmlBuilder();
+
+ static XmlElement * BuildElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ virtual void EndElement(XmlParseContext * pctx, const char * name);
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len);
+ virtual void Error(XmlParseContext * pctx, XML_Error);
+ virtual ~XmlBuilder();
+
+ void Reset();
+
+ // Take ownership of the built element; second call returns NULL
+ XmlElement * CreateElement();
+
+ // Peek at the built element without taking ownership
+ XmlElement * BuiltElement();
+
+private:
+ XmlElement * pelCurrent_;
+ scoped_ptr<XmlElement> pelRoot_;
+ scoped_ptr<std::vector<XmlElement *, std::allocator<XmlElement *> > >
+ pvParents_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc
new file mode 100644
index 00000000..503f832f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc
@@ -0,0 +1,65 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xmlconstants.h"
+
+using namespace buzz;
+
+const std::string & XmlConstants::str_empty() {
+ static const std::string str_empty_;
+ return str_empty_;
+}
+
+const std::string & XmlConstants::ns_xml() {
+ static const std::string ns_xml_("http://www.w3.org/XML/1998/namespace");
+ return ns_xml_;
+}
+
+const std::string & XmlConstants::ns_xmlns() {
+ static const std::string ns_xmlns_("http://www.w3.org/2000/xmlns/");
+ return ns_xmlns_;
+}
+
+const std::string & XmlConstants::str_xmlns() {
+ static const std::string str_xmlns_("xmlns");
+ return str_xmlns_;
+}
+
+const std::string & XmlConstants::str_xml() {
+ static const std::string str_xml_("xml");
+ return str_xml_;
+}
+
+const std::string & XmlConstants::str_version() {
+ static const std::string str_version_("version");
+ return str_version_;
+}
+
+const std::string & XmlConstants::str_encoding() {
+ static const std::string str_encoding_("encoding");
+ return str_encoding_;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h
new file mode 100644
index 00000000..8514d6f4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h
@@ -0,0 +1,61 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Because global constant initialization order is undefined
+// globals cannot depend on other objects to be instantiated.
+// This class creates string objects within static methods
+// such that globals may refer to these constants by the
+// accessor function and they are guaranteed to be initialized.
+
+#ifndef TALK_XMLLITE_CONSTANTS_H_
+#define TALK_XMLLITE_CONSTANTS_H_
+
+#include <string>
+
+#define STR_EMPTY XmlConstants::str_empty()
+#define NS_XML XmlConstants::ns_xml()
+#define NS_XMLNS XmlConstants::ns_xmlns()
+#define STR_XMLNS XmlConstants::str_xmlns()
+#define STR_XML XmlConstants::str_xml()
+#define STR_VERSION XmlConstants::str_version()
+#define STR_ENCODING XmlConstants::str_encoding()
+namespace buzz {
+
+class XmlConstants {
+ public:
+ static const std::string & str_empty();
+ static const std::string & ns_xml();
+ static const std::string & ns_xmlns();
+ static const std::string & str_xmlns();
+ static const std::string & str_xml();
+ static const std::string & str_version();
+ static const std::string & str_encoding();
+};
+
+}
+
+#endif // TALK_XMLLITE_CONSTANTS_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc
new file mode 100644
index 00000000..d3619a92
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc
@@ -0,0 +1,491 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlparser.h"
+#include "talk/xmllite/xmlbuilder.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmllite/xmlconstants.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+const QName QN_EMPTY(true, STR_EMPTY, STR_EMPTY);
+const QName QN_XMLNS(true, STR_EMPTY, STR_XMLNS);
+
+
+XmlChild::~XmlChild() {
+}
+
+bool
+XmlText::IsTextImpl() const {
+ return true;
+}
+
+XmlElement *
+XmlText::AsElementImpl() const {
+ return NULL;
+}
+
+XmlText *
+XmlText::AsTextImpl() const {
+ return const_cast<XmlText *>(this);
+}
+
+void
+XmlText::SetText(const std::string & text) {
+ text_ = text;
+}
+
+void
+XmlText::AddParsedText(const char * buf, int len) {
+ text_.append(buf, len);
+}
+
+void
+XmlText::AddText(const std::string & text) {
+ text_ += text;
+}
+
+XmlText::~XmlText() {
+}
+
+XmlElement::XmlElement(const QName & name) :
+ name_(name),
+ pFirstAttr_(NULL),
+ pLastAttr_(NULL),
+ pFirstChild_(NULL),
+ pLastChild_(NULL) {
+}
+
+XmlElement::XmlElement(const XmlElement & elt) :
+ XmlChild(),
+ name_(elt.name_),
+ pFirstAttr_(NULL),
+ pLastAttr_(NULL),
+ pFirstChild_(NULL),
+ pLastChild_(NULL) {
+
+ // copy attributes
+ XmlAttr * pAttr;
+ XmlAttr ** ppLastAttr = &pFirstAttr_;
+ XmlAttr * newAttr = NULL;
+ for (pAttr = elt.pFirstAttr_; pAttr; pAttr = pAttr->NextAttr()) {
+ newAttr = new XmlAttr(*pAttr);
+ *ppLastAttr = newAttr;
+ ppLastAttr = &(newAttr->pNextAttr_);
+ }
+ pLastAttr_ = newAttr;
+
+ // copy children
+ XmlChild * pChild;
+ XmlChild ** ppLast = &pFirstChild_;
+ XmlChild * newChild = NULL;
+
+ for (pChild = elt.pFirstChild_; pChild; pChild = pChild->NextChild()) {
+ if (pChild->IsText()) {
+ newChild = new XmlText(*(pChild->AsText()));
+ } else {
+ newChild = new XmlElement(*(pChild->AsElement()));
+ }
+ *ppLast = newChild;
+ ppLast = &(newChild->pNextChild_);
+ }
+ pLastChild_ = newChild;
+
+}
+
+XmlElement::XmlElement(const QName & name, bool useDefaultNs) :
+ name_(name),
+ pFirstAttr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
+ pLastAttr_(pFirstAttr_),
+ pFirstChild_(NULL),
+ pLastChild_(NULL) {
+}
+
+bool
+XmlElement::IsTextImpl() const {
+ return false;
+}
+
+XmlElement *
+XmlElement::AsElementImpl() const {
+ return const_cast<XmlElement *>(this);
+}
+
+XmlText *
+XmlElement::AsTextImpl() const {
+ return NULL;
+}
+
+const std::string &
+XmlElement::BodyText() const {
+ if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
+ return pFirstChild_->AsText()->Text();
+ }
+
+ return STR_EMPTY;
+}
+
+void
+XmlElement::SetBodyText(const std::string & text) {
+ if (text == STR_EMPTY) {
+ ClearChildren();
+ } else if (pFirstChild_ == NULL) {
+ AddText(text);
+ } else if (pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
+ pFirstChild_->AsText()->SetText(text);
+ } else {
+ ClearChildren();
+ AddText(text);
+ }
+}
+
+const QName &
+XmlElement::FirstElementName() const {
+ const XmlElement * element = FirstElement();
+ if (element == NULL)
+ return QN_EMPTY;
+ return element->Name();
+}
+
+XmlAttr *
+XmlElement::FirstAttr() {
+ return pFirstAttr_;
+}
+
+const std::string &
+XmlElement::Attr(const QName & name) const {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ return pattr->value_;
+ }
+ return STR_EMPTY;
+}
+
+bool
+XmlElement::HasAttr(const QName & name) const {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ return true;
+ }
+ return false;
+}
+
+void
+XmlElement::SetAttr(const QName & name, const std::string & value) {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ break;
+ }
+ if (!pattr) {
+ pattr = new XmlAttr(name, value);
+ if (pLastAttr_)
+ pLastAttr_->pNextAttr_ = pattr;
+ else
+ pFirstAttr_ = pattr;
+ pLastAttr_ = pattr;
+ return;
+ }
+ pattr->value_ = value;
+}
+
+void
+XmlElement::ClearAttr(const QName & name) {
+ XmlAttr * pattr;
+ XmlAttr *pLastAttr = NULL;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ break;
+ pLastAttr = pattr;
+ }
+ if (!pattr)
+ return;
+ if (!pLastAttr)
+ pFirstAttr_ = pattr->pNextAttr_;
+ else
+ pLastAttr->pNextAttr_ = pattr->pNextAttr_;
+ if (pLastAttr_ == pattr)
+ pLastAttr_ = pLastAttr;
+ delete pattr;
+}
+
+XmlChild *
+XmlElement::FirstChild() {
+ return pFirstChild_;
+}
+
+XmlElement *
+XmlElement::FirstElement() {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText())
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextElement() {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText())
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::FirstWithNamespace(const std::string & ns) {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextWithNamespace(const std::string & ns) {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::FirstNamed(const QName & name) {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextNamed(const QName & name) {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+const std::string &
+XmlElement::TextNamed(const QName & name) const {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement()->BodyText();
+ }
+ return STR_EMPTY;
+}
+
+void
+XmlElement::InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNext) {
+ if (pPredecessor == NULL) {
+ pNext->pNextChild_ = pFirstChild_;
+ pFirstChild_ = pNext;
+ }
+ else {
+ pNext->pNextChild_ = pPredecessor->pNextChild_;
+ pPredecessor->pNextChild_ = pNext;
+ }
+}
+
+void
+XmlElement::RemoveChildAfter(XmlChild * pPredecessor) {
+ XmlChild * pNext;
+
+ if (pPredecessor == NULL) {
+ pNext = pFirstChild_;
+ pFirstChild_ = pNext->pNextChild_;
+ }
+ else {
+ pNext = pPredecessor->pNextChild_;
+ pPredecessor->pNextChild_ = pNext->pNextChild_;
+ }
+
+ if (pLastChild_ == pNext)
+ pLastChild_ = pPredecessor;
+
+ delete pNext;
+}
+
+void
+XmlElement::AddAttr(const QName & name, const std::string & value) {
+ ASSERT(!HasAttr(name));
+
+ XmlAttr ** pprev = pLastAttr_ ? &(pLastAttr_->pNextAttr_) : &pFirstAttr_;
+ pLastAttr_ = (*pprev = new XmlAttr(name, value));
+}
+
+void
+XmlElement::AddAttr(const QName & name, const std::string & value,
+ int depth) {
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddAttr(name, value);
+}
+
+void
+XmlElement::AddParsedText(const char * cstr, int len) {
+ if (len == 0)
+ return;
+
+ if (pLastChild_ && pLastChild_->IsText()) {
+ pLastChild_->AsText()->AddParsedText(cstr, len);
+ return;
+ }
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = new XmlText(cstr, len);
+}
+
+void
+XmlElement::AddText(const std::string & text) {
+ if (text == STR_EMPTY)
+ return;
+
+ if (pLastChild_ && pLastChild_->IsText()) {
+ pLastChild_->AsText()->AddText(text);
+ return;
+ }
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = new XmlText(text);
+}
+
+void
+XmlElement::AddText(const std::string & text, int depth) {
+ // note: the first syntax is ambigious for msvc 6
+ // XmlElement * pel(this);
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddText(text);
+}
+
+void
+XmlElement::AddElement(XmlElement *pelChild) {
+ if (pelChild == NULL)
+ return;
+
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = pelChild;
+ pelChild->pNextChild_ = NULL;
+}
+
+void
+XmlElement::AddElement(XmlElement *pelChild, int depth) {
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddElement(pelChild);
+}
+
+void
+XmlElement::ClearNamedChildren(const QName & name) {
+ XmlChild * prev_child = NULL;
+ XmlChild * next_child;
+ XmlChild * child;
+ for (child = FirstChild(); child; child = next_child) {
+ next_child = child->NextChild();
+ if (!child->IsText() && child->AsElement()->Name() == name)
+ {
+ RemoveChildAfter(prev_child);
+ continue;
+ }
+ prev_child = child;
+ }
+}
+
+void
+XmlElement::ClearChildren() {
+ XmlChild * pchild;
+ for (pchild = pFirstChild_; pchild; ) {
+ XmlChild * pToDelete = pchild;
+ pchild = pchild->pNextChild_;
+ delete pToDelete;
+ }
+ pFirstChild_ = pLastChild_ = NULL;
+}
+
+std::string
+XmlElement::Str() const {
+ std::stringstream ss;
+ Print(&ss, NULL, 0);
+ return ss.str();
+}
+
+XmlElement *
+XmlElement::ForStr(const std::string & str) {
+ XmlBuilder builder;
+ XmlParser::ParseXml(&builder, str);
+ return builder.CreateElement();
+}
+
+void
+XmlElement::Print(
+ std::ostream * pout, std::string xmlns[], int xmlnsCount) const {
+ XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount);
+}
+
+XmlElement::~XmlElement() {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; ) {
+ XmlAttr * pToDelete = pattr;
+ pattr = pattr->pNextAttr_;
+ delete pToDelete;
+ }
+
+ XmlChild * pchild;
+ for (pchild = pFirstChild_; pchild; ) {
+ XmlChild * pToDelete = pchild;
+ pchild = pchild->pNextChild_;
+ delete pToDelete;
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h
new file mode 100644
index 00000000..06545d89
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h
@@ -0,0 +1,231 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmlelement_h_
+#define _xmlelement_h_
+
+#include <iosfwd>
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmllite/qname.h"
+
+namespace buzz {
+
+extern const QName QN_EMPTY;
+extern const QName QN_XMLNS;
+
+
+class XmlChild;
+class XmlText;
+class XmlElement;
+class XmlAttr;
+
+class XmlChild {
+friend class XmlElement;
+
+public:
+
+ XmlChild * NextChild() { return pNextChild_; }
+ const XmlChild * NextChild() const { return pNextChild_; }
+
+ bool IsText() const { return IsTextImpl(); }
+
+ XmlElement * AsElement() { return AsElementImpl(); }
+ const XmlElement * AsElement() const { return AsElementImpl(); }
+
+ XmlText * AsText() { return AsTextImpl(); }
+ const XmlText * AsText() const { return AsTextImpl(); }
+
+
+protected:
+
+ XmlChild() :
+ pNextChild_(NULL) {
+ }
+
+ virtual bool IsTextImpl() const = 0;
+ virtual XmlElement * AsElementImpl() const = 0;
+ virtual XmlText * AsTextImpl() const = 0;
+
+
+ virtual ~XmlChild();
+
+private:
+ XmlChild(const XmlChild & noimpl);
+
+ XmlChild * pNextChild_;
+
+};
+
+class XmlText : public XmlChild {
+public:
+ explicit XmlText(const std::string & text) :
+ XmlChild(),
+ text_(text) {
+ }
+ explicit XmlText(const XmlText & t) :
+ XmlChild(),
+ text_(t.text_) {
+ }
+ explicit XmlText(const char * cstr, size_t len) :
+ XmlChild(),
+ text_(cstr, len) {
+ }
+ virtual ~XmlText();
+
+ const std::string & Text() const { return text_; }
+ void SetText(const std::string & text);
+ void AddParsedText(const char * buf, int len);
+ void AddText(const std::string & text);
+
+protected:
+ virtual bool IsTextImpl() const;
+ virtual XmlElement * AsElementImpl() const;
+ virtual XmlText * AsTextImpl() const;
+
+private:
+ std::string text_;
+};
+
+class XmlAttr {
+friend class XmlElement;
+
+public:
+ XmlAttr * NextAttr() const { return pNextAttr_; }
+ const QName & Name() const { return name_; }
+ const std::string & Value() const { return value_; }
+
+private:
+ explicit XmlAttr(const QName & name, const std::string & value) :
+ pNextAttr_(NULL),
+ name_(name),
+ value_(value) {
+ }
+ explicit XmlAttr(const XmlAttr & att) :
+ pNextAttr_(NULL),
+ name_(att.name_),
+ value_(att.value_) {
+ }
+
+ XmlAttr * pNextAttr_;
+ QName name_;
+ std::string value_;
+};
+
+class XmlElement : public XmlChild {
+public:
+ explicit XmlElement(const QName & name);
+ explicit XmlElement(const QName & name, bool useDefaultNs);
+ explicit XmlElement(const XmlElement & elt);
+
+ virtual ~XmlElement();
+
+ const QName & Name() const { return name_; }
+
+ const std::string & BodyText() const;
+ void SetBodyText(const std::string & text);
+
+ const QName & FirstElementName() const;
+
+ XmlAttr * FirstAttr();
+ const XmlAttr * FirstAttr() const
+ { return const_cast<XmlElement *>(this)->FirstAttr(); }
+
+ //! Attr will return STR_EMPTY if the attribute isn't there:
+ //! use HasAttr to test presence of an attribute.
+ const std::string & Attr(const QName & name) const;
+ bool HasAttr(const QName & name) const;
+ void SetAttr(const QName & name, const std::string & value);
+ void ClearAttr(const QName & name);
+
+ XmlChild * FirstChild();
+ const XmlChild * FirstChild() const
+ { return const_cast<XmlElement *>(this)->FirstChild(); }
+
+ XmlElement * FirstElement();
+ const XmlElement * FirstElement() const
+ { return const_cast<XmlElement *>(this)->FirstElement(); }
+
+ XmlElement * NextElement();
+ const XmlElement * NextElement() const
+ { return const_cast<XmlElement *>(this)->NextElement(); }
+
+ XmlElement * FirstWithNamespace(const std::string & ns);
+ const XmlElement * FirstWithNamespace(const std::string & ns) const
+ { return const_cast<XmlElement *>(this)->FirstWithNamespace(ns); }
+
+ XmlElement * NextWithNamespace(const std::string & ns);
+ const XmlElement * NextWithNamespace(const std::string & ns) const
+ { return const_cast<XmlElement *>(this)->NextWithNamespace(ns); }
+
+ XmlElement * FirstNamed(const QName & name);
+ const XmlElement * FirstNamed(const QName & name) const
+ { return const_cast<XmlElement *>(this)->FirstNamed(name); }
+
+ XmlElement * NextNamed(const QName & name);
+ const XmlElement * NextNamed(const QName & name) const
+ { return const_cast<XmlElement *>(this)->NextNamed(name); }
+
+ const std::string & TextNamed(const QName & name) const;
+
+ void InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNewChild);
+ void RemoveChildAfter(XmlChild * pPredecessor);
+
+ void AddParsedText(const char * buf, int len);
+ void AddText(const std::string & text);
+ void AddText(const std::string & text, int depth);
+ void AddElement(XmlElement * pelChild);
+ void AddElement(XmlElement * pelChild, int depth);
+ void AddAttr(const QName & name, const std::string & value);
+ void AddAttr(const QName & name, const std::string & value, int depth);
+ void ClearNamedChildren(const QName & name);
+ void ClearChildren();
+
+ static XmlElement * ForStr(const std::string & str);
+ std::string Str() const;
+
+ void Print(std::ostream * pout, std::string xmlns[], int xmlnsCount) const;
+
+protected:
+ virtual bool IsTextImpl() const;
+ virtual XmlElement * AsElementImpl() const;
+ virtual XmlText * AsTextImpl() const;
+
+private:
+ QName name_;
+ XmlAttr * pFirstAttr_;
+ XmlAttr * pLastAttr_;
+ XmlChild * pFirstChild_;
+ XmlChild * pLastChild_;
+
+};
+
+
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc
new file mode 100644
index 00000000..4dcb6490
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc
@@ -0,0 +1,205 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/stl_decl.h"
+#include <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+XmlnsStack::XmlnsStack() :
+ pxmlnsStack_(new std::vector<std::string>),
+ pxmlnsDepthStack_(new std::vector<size_t>) {
+}
+
+XmlnsStack::~XmlnsStack() {}
+
+void
+XmlnsStack::PushFrame() {
+ pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
+}
+
+void
+XmlnsStack::PopFrame() {
+ size_t prev_size = pxmlnsDepthStack_->back();
+ pxmlnsDepthStack_->pop_back();
+ if (prev_size < pxmlnsStack_->size()) {
+ pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
+ pxmlnsStack_->end());
+ }
+}
+const std::pair<std::string, bool> NS_NOT_FOUND(STR_EMPTY, false);
+const std::pair<std::string, bool> EMPTY_NS_FOUND(STR_EMPTY, true);
+const std::pair<std::string, bool> XMLNS_DEFINITION_FOUND(NS_XMLNS, true);
+
+const std::string *
+XmlnsStack::NsForPrefix(const std::string & prefix) {
+ if (prefix.length() >= 3 &&
+ (prefix[0] == 'x' || prefix[0] == 'X') &&
+ (prefix[1] == 'm' || prefix[1] == 'M') &&
+ (prefix[2] == 'l' || prefix[2] == 'L')) {
+ if (prefix == "xml")
+ return &(NS_XML);
+ if (prefix == "xmlns")
+ return &(NS_XMLNS);
+ return NULL;
+ }
+
+ std::vector<std::string>::iterator pos;
+ for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+ pos -= 2;
+ if (*pos == prefix)
+ return &(*(pos + 1));
+ }
+
+ if (prefix == STR_EMPTY)
+ return &(STR_EMPTY); // default namespace
+
+ return NULL; // none found
+}
+
+bool
+XmlnsStack::PrefixMatchesNs(const std::string & prefix, const std::string & ns) {
+ const std::string * match = NsForPrefix(prefix);
+ if (match == NULL)
+ return false;
+ return (*match == ns);
+}
+
+std::pair<std::string, bool>
+XmlnsStack::PrefixForNs(const std::string & ns, bool isattr) {
+ if (ns == NS_XML)
+ return std::make_pair(std::string("xml"), true);
+ if (ns == NS_XMLNS)
+ return std::make_pair(std::string("xmlns"), true);
+ if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
+ return std::make_pair(STR_EMPTY, true);
+
+ std::vector<std::string>::iterator pos;
+ for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+ pos -= 2;
+ if (*(pos + 1) == ns &&
+ (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
+ return std::make_pair(*pos, true);
+ }
+
+ return std::make_pair(STR_EMPTY, false); // none found
+}
+
+std::string
+XmlnsStack::FormatQName(const QName & name, bool isAttr) {
+ std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
+ if (prefix == STR_EMPTY)
+ return name.LocalPart();
+ else
+ return prefix + ':' + name.LocalPart();
+}
+
+void
+XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
+ pxmlnsStack_->push_back(prefix);
+ pxmlnsStack_->push_back(ns);
+}
+
+void
+XmlnsStack::RemoveXmlns() {
+ pxmlnsStack_->pop_back();
+ pxmlnsStack_->pop_back();
+}
+
+static bool IsAsciiLetter(char ch) {
+ return ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z'));
+}
+
+static std::string AsciiLower(const std::string & s) {
+ std::string result(s);
+ size_t i;
+ for (i = 0; i < result.length(); i++) {
+ if (result[i] >= 'A' && result[i] <= 'Z')
+ result[i] += 'a' - 'A';
+ }
+ return result;
+}
+
+static std::string SuggestPrefix(const std::string & ns) {
+ size_t len = ns.length();
+ size_t i = ns.find_last_of('.');
+ if (i != std::string::npos && len - i <= 4 + 1)
+ len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
+ size_t last = len;
+ while (last > 0) {
+ last -= 1;
+ if (IsAsciiLetter(ns[last])) {
+ size_t first = last;
+ last += 1;
+ while (first > 0) {
+ if (!IsAsciiLetter(ns[first - 1]))
+ break;
+ first -= 1;
+ }
+ if (last - first > 4)
+ last = first + 3;
+ std::string candidate(AsciiLower(ns.substr(first, last - first)));
+ if (candidate.find("xml") != 0)
+ return candidate;
+ break;
+ }
+ }
+ return "ns";
+}
+
+
+std::pair<std::string, bool>
+XmlnsStack::AddNewPrefix(const std::string & ns, bool isAttr) {
+ if (PrefixForNs(ns, isAttr).second)
+ return std::make_pair(STR_EMPTY, false);
+
+ std::string base(SuggestPrefix(ns));
+ std::string result(base);
+ int i = 2;
+ while (NsForPrefix(result) != NULL) {
+ std::stringstream ss;
+ ss << base;
+ ss << (i++);
+ ss >> result;
+ }
+ AddXmlns(result, ns);
+ return std::make_pair(result, true);
+}
+
+void XmlnsStack::Reset() {
+ pxmlnsStack_->clear();
+ pxmlnsDepthStack_->clear();
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h
new file mode 100644
index 00000000..299ec1ce
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h
@@ -0,0 +1,62 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmlnsstack_h_
+#define _xmlnsstack_h_
+
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stl_decl.h"
+#include "talk/xmllite/qname.h"
+
+namespace buzz {
+
+class XmlnsStack {
+public:
+ XmlnsStack();
+ ~XmlnsStack();
+
+ void AddXmlns(const std::string & prefix, const std::string & ns);
+ void RemoveXmlns();
+ void PushFrame();
+ void PopFrame();
+ void Reset();
+
+ const std::string * NsForPrefix(const std::string & prefix);
+ bool PrefixMatchesNs(const std::string & prefix, const std::string & ns);
+ std::pair<std::string, bool> PrefixForNs(const std::string & ns, bool isAttr);
+ std::pair<std::string, bool> AddNewPrefix(const std::string & ns, bool isAttr);
+ std::string FormatQName(const QName & name, bool isAttr);
+
+private:
+
+ scoped_ptr<std::vector<std::string, std::allocator<std::string> > > pxmlnsStack_;
+ scoped_ptr<std::vector<size_t, std::allocator<size_t> > > pxmlnsDepthStack_;
+};
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc
new file mode 100644
index 00000000..f2b56778
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc
@@ -0,0 +1,250 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/stl_decl.h"
+#include <string>
+#include <vector>
+#include <iostream>
+#include <expat.h>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlparser.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlconstants.h"
+
+#include <expat.h>
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+
+static void
+StartElementCallback(void * userData, const char *name, const char **atts) {
+ (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
+}
+
+static void
+EndElementCallback(void * userData, const char *name) {
+ (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
+}
+
+static void
+CharacterDataCallback(void * userData, const char *text, int len) {
+ (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
+}
+
+static void
+XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
+ (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
+}
+
+XmlParser::XmlParser(XmlParseHandler *pxph) :
+ context_(this), pxph_(pxph), sentError_(false) {
+ expat_ = XML_ParserCreate(NULL);
+ XML_SetUserData(expat_, this);
+ XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+ XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+ XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+}
+
+void
+XmlParser::Reset() {
+ if (!XML_ParserReset(expat_, NULL)) {
+ XML_ParserFree(expat_);
+ expat_ = XML_ParserCreate(NULL);
+ }
+ XML_SetUserData(expat_, this);
+ XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+ XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+ XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+ context_.Reset();
+ sentError_ = false;
+}
+
+static bool
+XmlParser_StartsWithXmlns(const char *name) {
+ return name[0] == 'x' &&
+ name[1] == 'm' &&
+ name[2] == 'l' &&
+ name[3] == 'n' &&
+ name[4] == 's';
+}
+
+void
+XmlParser::ExpatStartElement(const char *name, const char **atts) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ const char **att;
+ context_.StartElement();
+ for (att = atts; *att; att += 2) {
+ if (XmlParser_StartsWithXmlns(*att)) {
+ if ((*att)[5] == '\0') {
+ context_.StartNamespace("", *(att + 1));
+ }
+ else if ((*att)[5] == ':') {
+ if (**(att + 1) == '\0') {
+ // In XML 1.0 empty namespace illegal with prefix (not in 1.1)
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+ context_.StartNamespace((*att) + 6, *(att + 1));
+ }
+ }
+ }
+ pxph_->StartElement(&context_, name, atts);
+}
+
+void
+XmlParser::ExpatEndElement(const char *name) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ context_.EndElement();
+ pxph_->EndElement(&context_, name);
+}
+
+void
+XmlParser::ExpatCharacterData(const char *text, int len) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ pxph_->CharacterData(&context_, text, len);
+}
+
+void
+XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+
+ if (ver && std::string("1.0") != ver) {
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (standalone == 0) {
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
+ (enc[1] == 'T' || enc[1] == 't') &&
+ (enc[2] == 'F' || enc[2] == 'f') &&
+ enc[3] == '-' && enc[4] =='8')) {
+ context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
+ return;
+ }
+
+}
+
+bool
+XmlParser::Parse(const char *data, size_t len, bool isFinal) {
+ if (sentError_)
+ return false;
+
+ if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) != XML_STATUS_OK)
+ context_.RaiseError(XML_GetErrorCode(expat_));
+
+ if (context_.RaisedError() != XML_ERROR_NONE) {
+ sentError_ = true;
+ pxph_->Error(&context_, context_.RaisedError());
+ return false;
+ }
+
+ return true;
+}
+
+XmlParser::~XmlParser() {
+ XML_ParserFree(expat_);
+}
+
+void
+XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
+ XmlParser parser(pxph);
+ parser.Parse(text.c_str(), text.length(), true);
+}
+
+XmlParser::ParseContext::ParseContext(XmlParser *parser) :
+ parser_(parser),
+ xmlnsstack_(),
+ raised_(XML_ERROR_NONE) {
+}
+
+void
+XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
+ xmlnsstack_.AddXmlns(
+ *prefix ? std::string(prefix) : STR_EMPTY,
+// ns == NS_CLIENT ? NS_CLIENT :
+// ns == NS_ROSTER ? NS_ROSTER :
+// ns == NS_GR ? NS_GR :
+ std::string(ns));
+}
+
+void
+XmlParser::ParseContext::StartElement() {
+ xmlnsstack_.PushFrame();
+}
+
+void
+XmlParser::ParseContext::EndElement() {
+ xmlnsstack_.PopFrame();
+}
+
+QName
+XmlParser::ParseContext::ResolveQName(const char *qname, bool isAttr) {
+ const char *c;
+ for (c = qname; *c; ++c) {
+ if (*c == ':') {
+ const std::string * result;
+ result = xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
+ if (result == NULL)
+ return QN_EMPTY;
+ const char * localname = c + 1;
+ return QName(*result, localname);
+ }
+ }
+ if (isAttr) {
+ return QName(STR_EMPTY, qname);
+ }
+
+ const std::string * result;
+ result = xmlnsstack_.NsForPrefix(STR_EMPTY);
+ if (result == NULL)
+ return QN_EMPTY;
+
+ return QName(*result, qname);
+}
+
+void
+XmlParser::ParseContext::Reset() {
+ xmlnsstack_.Reset();
+ raised_ = XML_ERROR_NONE;
+}
+
+XmlParser::ParseContext::~ParseContext() {
+}
+
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h
new file mode 100644
index 00000000..760802e4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h
@@ -0,0 +1,108 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmlparser_h_
+#define _xmlparser_h_
+
+#include <string>
+#include "talk/xmllite/xmlnsstack.h"
+#include <expat.h>
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct * XML_Parser;
+
+namespace buzz {
+
+class XmlParseHandler;
+class XmlParseContext;
+class XmlParser;
+
+class XmlParseContext {
+public:
+ virtual QName ResolveQName(const char * qname, bool isAttr) = 0;
+ virtual void RaiseError(XML_Error err) = 0;
+};
+
+class XmlParseHandler {
+public:
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) = 0;
+ virtual void EndElement(XmlParseContext * pctx,
+ const char * name) = 0;
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len) = 0;
+ virtual void Error(XmlParseContext * pctx,
+ XML_Error errorCode) = 0;
+};
+
+class XmlParser {
+public:
+ static void ParseXml(XmlParseHandler * pxph, std::string text);
+
+ explicit XmlParser(XmlParseHandler * pxph);
+ bool Parse(const char * data, size_t len, bool isFinal);
+ void Reset();
+ virtual ~XmlParser();
+
+ // expat callbacks
+ void ExpatStartElement(const char * name, const char ** atts);
+ void ExpatEndElement(const char * name);
+ void ExpatCharacterData(const char * text, int len);
+ void ExpatXmlDecl(const char * ver, const char * enc, int standalone);
+
+private:
+
+ class ParseContext : public XmlParseContext {
+ public:
+ ParseContext(XmlParser * parser);
+ virtual ~ParseContext();
+ virtual QName ResolveQName(const char * qname, bool isAttr);
+ virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
+ XML_Error RaisedError() { return raised_; }
+ void Reset();
+
+ void StartElement();
+ void EndElement();
+ void StartNamespace(const char * prefix, const char * ns);
+
+ private:
+ const XmlParser * parser_;
+ XmlnsStack xmlnsstack_;
+ XML_Error raised_;
+ };
+
+ ParseContext context_;
+ XML_Parser expat_;
+ XmlParseHandler * pxph_;
+ bool sentError_;
+
+
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc
new file mode 100644
index 00000000..892e2ebb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc
@@ -0,0 +1,190 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/stl_decl.h"
+#include <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+class XmlPrinterImpl {
+public:
+ XmlPrinterImpl(std::ostream * pout,
+ const std::string * const xmlns, int xmlnsCount);
+ void PrintElement(const XmlElement * element);
+ void PrintQuotedValue(const std::string & text);
+ void PrintBodyText(const std::string & text);
+
+private:
+ std::ostream *pout_;
+ XmlnsStack xmlnsStack_;
+};
+
+void
+XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element) {
+ PrintXml(pout, element, NULL, 0);
+}
+
+void
+XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element,
+ const std::string * const xmlns, int xmlnsCount) {
+ XmlPrinterImpl printer(pout, xmlns, xmlnsCount);
+ printer.PrintElement(element);
+}
+
+XmlPrinterImpl::XmlPrinterImpl(std::ostream * pout,
+ const std::string * const xmlns, int xmlnsCount) :
+ pout_(pout),
+ xmlnsStack_() {
+ int i;
+ for (i = 0; i < xmlnsCount; i += 2) {
+ xmlnsStack_.AddXmlns(xmlns[i], xmlns[i + 1]);
+ }
+}
+
+void
+XmlPrinterImpl::PrintElement(const XmlElement * element) {
+ xmlnsStack_.PushFrame();
+
+ // first go through attrs of pel to add xmlns definitions
+ const XmlAttr * pattr;
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ if (pattr->Name() == QN_XMLNS)
+ xmlnsStack_.AddXmlns(STR_EMPTY, pattr->Value());
+ else if (pattr->Name().Namespace() == NS_XMLNS)
+ xmlnsStack_.AddXmlns(pattr->Name().LocalPart(),
+ pattr->Value());
+ }
+
+ // then go through qnames to make sure needed xmlns definitons are added
+ std::vector<std::string> newXmlns;
+ std::pair<std::string, bool> prefix;
+ prefix = xmlnsStack_.AddNewPrefix(element->Name().Namespace(), false);
+ if (prefix.second) {
+ newXmlns.push_back(prefix.first);
+ newXmlns.push_back(element->Name().Namespace());
+ }
+
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ prefix = xmlnsStack_.AddNewPrefix(pattr->Name().Namespace(), true);
+ if (prefix.second) {
+ newXmlns.push_back(prefix.first);
+ newXmlns.push_back(element->Name().Namespace());
+ }
+ }
+
+ // print the element name
+ *pout_ << '<' << xmlnsStack_.FormatQName(element->Name(), false);
+
+ // and the attributes
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ *pout_ << ' ' << xmlnsStack_.FormatQName(pattr->Name(), true) << "=\"";
+ PrintQuotedValue(pattr->Value());
+ *pout_ << '"';
+ }
+
+ // and the extra xmlns declarations
+ std::vector<std::string>::iterator i(newXmlns.begin());
+ while (i < newXmlns.end()) {
+ if (*i == STR_EMPTY)
+ *pout_ << " xmlns=\"" << *(i + 1) << '"';
+ else
+ *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
+ i += 2;
+ }
+
+ // now the children
+ const XmlChild * pchild = element->FirstChild();
+
+ if (pchild == NULL)
+ *pout_ << "/>";
+ else {
+ *pout_ << '>';
+ while (pchild) {
+ if (pchild->IsText())
+ PrintBodyText(pchild->AsText()->Text());
+ else
+ PrintElement(pchild->AsElement());
+ pchild = pchild->NextChild();
+ }
+ *pout_ << "</" << xmlnsStack_.FormatQName(element->Name(), false) << '>';
+ }
+
+ xmlnsStack_.PopFrame();
+}
+
+void
+XmlPrinterImpl::PrintQuotedValue(const std::string & text) {
+ size_t safe = 0;
+ for (;;) {
+ size_t unsafe = text.find_first_of("<>&\"", safe);
+ if (unsafe == std::string::npos)
+ unsafe = text.length();
+ *pout_ << text.substr(safe, unsafe - safe);
+ if (unsafe == text.length())
+ return;
+ switch (text[unsafe]) {
+ case '<': *pout_ << "&lt;"; break;
+ case '>': *pout_ << "&gt;"; break;
+ case '&': *pout_ << "&amp;"; break;
+ case '"': *pout_ << "&quot;"; break;
+ }
+ safe = unsafe + 1;
+ if (safe == text.length())
+ return;
+ }
+}
+
+void
+XmlPrinterImpl::PrintBodyText(const std::string & text) {
+ size_t safe = 0;
+ for (;;) {
+ size_t unsafe = text.find_first_of("<>&", safe);
+ if (unsafe == std::string::npos)
+ unsafe = text.length();
+ *pout_ << text.substr(safe, unsafe - safe);
+ if (unsafe == text.length())
+ return;
+ switch (text[unsafe]) {
+ case '<': *pout_ << "&lt;"; break;
+ case '>': *pout_ << "&gt;"; break;
+ case '&': *pout_ << "&amp;"; break;
+ }
+ safe = unsafe + 1;
+ if (safe == text.length())
+ return;
+ }
+}
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h
new file mode 100644
index 00000000..96900d0d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h
@@ -0,0 +1,49 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmlprinter_h_
+#define _xmlprinter_h_
+
+#include <iosfwd>
+#include <string>
+#include "talk/base/scoped_ptr.h"
+
+namespace buzz {
+
+class XmlElement;
+
+class XmlPrinter {
+public:
+ static void PrintXml(std::ostream * pout, const XmlElement * pelt);
+
+ static void PrintXml(std::ostream * pout, const XmlElement * pelt,
+ const std::string * const xmlns, int xmlnsCount);
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am
new file mode 100644
index 00000000..527f7053
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am
@@ -0,0 +1,34 @@
+## Does not compile with final
+KDE_OPTIONS = nofinal
+
+libcricketxmpp_la_SOURCES = constants.cc \
+ jid.cc \
+ saslmechanism.cc \
+ xmppclient.cc \
+ xmppengineimpl.cc \
+ xmppengineimpl_iq.cc \
+ xmpplogintask.cc \
+ xmppstanzaparser.cc \
+ xmpptask.cc
+
+noinst_HEADERS = asyncsocket.h \
+ prexmppauth.h \
+ saslhandler.h \
+ xmpplogintask.h \
+ jid.h \
+ saslmechanism.h \
+ xmppclient.h \
+ xmpppassword.h \
+ constants.h \
+ saslplainmechanism.h \
+ xmppclientsettings.h \
+ xmppstanzaparser.h \
+ xmppengine.h \
+ xmpptask.h \
+ plainsaslhandler.h \
+ saslcookiemechanism.h \
+ xmppengineimpl.h
+
+
+AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../..
+noinst_LTLIBRARIES = libcricketxmpp.la
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h
new file mode 100644
index 00000000..fd91929b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h
@@ -0,0 +1,85 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASYNCSOCKET_H_
+#define _ASYNCSOCKET_H_
+
+#include "talk/base/sigslot.h"
+
+namespace cricket {
+ class SocketAddress;
+}
+
+namespace buzz {
+
+class AsyncSocket {
+public:
+ enum State {
+ STATE_CLOSED = 0, //!< Socket is not open.
+ STATE_CLOSING, //!< Socket is closing but can have buffered data
+ STATE_CONNECTING, //!< In the process of
+ STATE_OPEN, //!< Socket is connected
+#if defined(FEATURE_ENABLE_SSL)
+ STATE_TLS_CONNECTING, //!< Establishing TLS connection
+ STATE_TLS_OPEN, //!< TLS connected
+#endif
+ };
+
+ enum Error {
+ ERROR_NONE = 0, //!< No error
+ ERROR_WINSOCK, //!< Winsock error
+ ERROR_DNS, //!< Couldn't resolve host name
+ ERROR_WRONGSTATE, //!< Call made while socket is in the wrong state
+#if defined(FEATURE_ENABLE_SSL)
+ ERROR_SSL, //!< Something went wrong with OpenSSL
+#endif
+ };
+
+ virtual ~AsyncSocket() {}
+ virtual State state() = 0;
+ virtual Error error() = 0;
+
+ virtual bool Connect(const cricket::SocketAddress& addr) = 0;
+ virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
+ virtual bool Write(const char * data, size_t len) = 0;
+ virtual bool Close() = 0;
+#if defined(FEATURE_ENABLE_SSL)
+ // We allow matching any passed domain.
+ // If both names are passed as empty, we do not require a match.
+ virtual bool StartTls(const std::string & domainname) = 0;
+#endif
+
+ sigslot::signal0<> SignalConnected;
+ sigslot::signal0<> SignalSSLConnected;
+ sigslot::signal0<> SignalClosed;
+ sigslot::signal0<> SignalRead;
+ sigslot::signal0<> SignalError;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc
new file mode 100644
index 00000000..b2c833f7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc
@@ -0,0 +1,331 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include "talk/base/basicdefs.h"
+#include "talk/xmllite/xmlconstants.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/constants.h"
+namespace buzz {
+
+const Jid JID_EMPTY(STR_EMPTY);
+
+const std::string & Constants::ns_client() {
+ static const std::string ns_client_("jabber:client");
+ return ns_client_;
+}
+
+const std::string & Constants::ns_server() {
+ static const std::string ns_server_("jabber:server");
+ return ns_server_;
+}
+
+const std::string & Constants::ns_stream() {
+ static const std::string ns_stream_("http://etherx.jabber.org/streams");
+ return ns_stream_;
+}
+
+const std::string & Constants::ns_xstream() {
+ static const std::string ns_xstream_("urn:ietf:params:xml:ns:xmpp-streams");
+ return ns_xstream_;
+}
+
+const std::string & Constants::ns_tls() {
+ static const std::string ns_tls_("urn:ietf:params:xml:ns:xmpp-tls");
+ return ns_tls_;
+}
+
+const std::string & Constants::ns_sasl() {
+ static const std::string ns_sasl_("urn:ietf:params:xml:ns:xmpp-sasl");
+ return ns_sasl_;
+}
+
+const std::string & Constants::ns_bind() {
+ static const std::string ns_bind_("urn:ietf:params:xml:ns:xmpp-bind");
+ return ns_bind_;
+}
+
+const std::string & Constants::ns_dialback() {
+ static const std::string ns_dialback_("jabber:server:dialback");
+ return ns_dialback_;
+}
+
+const std::string & Constants::ns_session() {
+ static const std::string ns_session_("urn:ietf:params:xml:ns:xmpp-session");
+ return ns_session_;
+}
+
+const std::string & Constants::ns_stanza() {
+ static const std::string ns_stanza_("urn:ietf:params:xml:ns:xmpp-stanzas");
+ return ns_stanza_;
+}
+
+const std::string & Constants::ns_privacy() {
+ static const std::string ns_privacy_("jabber:iq:privacy");
+ return ns_privacy_;
+}
+
+const std::string & Constants::ns_roster() {
+ static const std::string ns_roster_("jabber:iq:roster");
+ return ns_roster_;
+}
+
+const std::string & Constants::ns_vcard() {
+ static const std::string ns_vcard_("vcard-temp");
+ return ns_vcard_;
+}
+
+const std::string & Constants::str_client() {
+ static const std::string str_client_("client");
+ return str_client_;
+}
+
+const std::string & Constants::str_server() {
+ static const std::string str_server_("server");
+ return str_server_;
+}
+
+const std::string & Constants::str_stream() {
+ static const std::string str_stream_("stream");
+ return str_stream_;
+}
+
+const std::string STR_GET("get");
+const std::string STR_SET("set");
+const std::string STR_RESULT("result");
+const std::string STR_ERROR("error");
+
+const std::string STR_FROM("from");
+const std::string STR_TO("to");
+const std::string STR_BOTH("both");
+const std::string STR_REMOVE("remove");
+
+const std::string STR_UNAVAILABLE("unavailable");
+const std::string STR_INVISIBLE("invisible");
+
+const std::string STR_GOOGLE_COM("google.com");
+const std::string STR_GMAIL_COM("gmail.com");
+const std::string STR_GOOGLEMAIL_COM("googlemail.com");
+const std::string STR_DEFAULT_DOMAIN("default.talk.google.com");
+const std::string STR_X("x");
+
+const QName QN_STREAM_STREAM(true, NS_STREAM, STR_STREAM);
+const QName QN_STREAM_FEATURES(true, NS_STREAM, "features");
+const QName QN_STREAM_ERROR(true, NS_STREAM, "error");
+
+const QName QN_XSTREAM_BAD_FORMAT(true, NS_XSTREAM, "bad-format");
+const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX(true, NS_XSTREAM, "bad-namespace-prefix");
+const QName QN_XSTREAM_CONFLICT(true, NS_XSTREAM, "conflict");
+const QName QN_XSTREAM_CONNECTION_TIMEOUT(true, NS_XSTREAM, "connection-timeout");
+const QName QN_XSTREAM_HOST_GONE(true, NS_XSTREAM, "host-gone");
+const QName QN_XSTREAM_HOST_UNKNOWN(true, NS_XSTREAM, "host-unknown");
+const QName QN_XSTREAM_IMPROPER_ADDRESSIING(true, NS_XSTREAM, "improper-addressing");
+const QName QN_XSTREAM_INTERNAL_SERVER_ERROR(true, NS_XSTREAM, "internal-server-error");
+const QName QN_XSTREAM_INVALID_FROM(true, NS_XSTREAM, "invalid-from");
+const QName QN_XSTREAM_INVALID_ID(true, NS_XSTREAM, "invalid-id");
+const QName QN_XSTREAM_INVALID_NAMESPACE(true, NS_XSTREAM, "invalid-namespace");
+const QName QN_XSTREAM_INVALID_XML(true, NS_XSTREAM, "invalid-xml");
+const QName QN_XSTREAM_NOT_AUTHORIZED(true, NS_XSTREAM, "not-authorized");
+const QName QN_XSTREAM_POLICY_VIOLATION(true, NS_XSTREAM, "policy-violation");
+const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED(true, NS_XSTREAM, "remote-connection-failed");
+const QName QN_XSTREAM_RESOURCE_CONSTRAINT(true, NS_XSTREAM, "resource-constraint");
+const QName QN_XSTREAM_RESTRICTED_XML(true, NS_XSTREAM, "restricted-xml");
+const QName QN_XSTREAM_SEE_OTHER_HOST(true, NS_XSTREAM, "see-other-host");
+const QName QN_XSTREAM_SYSTEM_SHUTDOWN(true, NS_XSTREAM, "system-shutdown");
+const QName QN_XSTREAM_UNDEFINED_CONDITION(true, NS_XSTREAM, "undefined-condition");
+const QName QN_XSTREAM_UNSUPPORTED_ENCODING(true, NS_XSTREAM, "unsupported-encoding");
+const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE(true, NS_XSTREAM, "unsupported-stanza-type");
+const QName QN_XSTREAM_UNSUPPORTED_VERSION(true, NS_XSTREAM, "unsupported-version");
+const QName QN_XSTREAM_XML_NOT_WELL_FORMED(true, NS_XSTREAM, "xml-not-well-formed");
+const QName QN_XSTREAM_TEXT(true, NS_XSTREAM, "text");
+
+const QName QN_TLS_STARTTLS(true, NS_TLS, "starttls");
+const QName QN_TLS_REQUIRED(true, NS_TLS, "required");
+const QName QN_TLS_PROCEED(true, NS_TLS, "proceed");
+const QName QN_TLS_FAILURE(true, NS_TLS, "failure");
+
+const QName QN_SASL_MECHANISMS(true, NS_SASL, "mechanisms");
+const QName QN_SASL_MECHANISM(true, NS_SASL, "mechanism");
+const QName QN_SASL_AUTH(true, NS_SASL, "auth");
+const QName QN_SASL_CHALLENGE(true, NS_SASL, "challenge");
+const QName QN_SASL_RESPONSE(true, NS_SASL, "response");
+const QName QN_SASL_ABORT(true, NS_SASL, "abort");
+const QName QN_SASL_SUCCESS(true, NS_SASL, "success");
+const QName QN_SASL_FAILURE(true, NS_SASL, "failure");
+const QName QN_SASL_ABORTED(true, NS_SASL, "aborted");
+const QName QN_SASL_INCORRECT_ENCODING(true, NS_SASL, "incorrect-encoding");
+const QName QN_SASL_INVALID_AUTHZID(true, NS_SASL, "invalid-authzid");
+const QName QN_SASL_INVALID_MECHANISM(true, NS_SASL, "invalid-mechanism");
+const QName QN_SASL_MECHANISM_TOO_WEAK(true, NS_SASL, "mechanism-too-weak");
+const QName QN_SASL_NOT_AUTHORIZED(true, NS_SASL, "not-authorized");
+const QName QN_SASL_TEMPORARY_AUTH_FAILURE(true, NS_SASL, "temporary-auth-failure");
+
+const QName QN_DIALBACK_RESULT(true, NS_DIALBACK, "result");
+const QName QN_DIALBACK_VERIFY(true, NS_DIALBACK, "verify");
+
+const QName QN_STANZA_BAD_REQUEST(true, NS_STANZA, "bad-request");
+const QName QN_STANZA_CONFLICT(true, NS_STANZA, "conflict");
+const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED(true, NS_STANZA, "feature-not-implemented");
+const QName QN_STANZA_FORBIDDEN(true, NS_STANZA, "forbidden");
+const QName QN_STANZA_GONE(true, NS_STANZA, "gone");
+const QName QN_STANZA_INTERNAL_SERVER_ERROR(true, NS_STANZA, "internal-server-error");
+const QName QN_STANZA_ITEM_NOT_FOUND(true, NS_STANZA, "item-not-found");
+const QName QN_STANZA_JID_MALFORMED(true, NS_STANZA, "jid-malformed");
+const QName QN_STANZA_NOT_ACCEPTABLE(true, NS_STANZA, "not-acceptable");
+const QName QN_STANZA_NOT_ALLOWED(true, NS_STANZA, "not-allowed");
+const QName QN_STANZA_PAYMENT_REQUIRED(true, NS_STANZA, "payment-required");
+const QName QN_STANZA_RECIPIENT_UNAVAILABLE(true, NS_STANZA, "recipient-unavailable");
+const QName QN_STANZA_REDIRECT(true, NS_STANZA, "redirect");
+const QName QN_STANZA_REGISTRATION_REQUIRED(true, NS_STANZA, "registration-required");
+const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND(true, NS_STANZA, "remote-server-not-found");
+const QName QN_STANZA_REMOTE_SERVER_TIMEOUT(true, NS_STANZA, "remote-server-timeout");
+const QName QN_STANZA_RESOURCE_CONSTRAINT(true, NS_STANZA, "resource-constraint");
+const QName QN_STANZA_SERVICE_UNAVAILABLE(true, NS_STANZA, "service-unavailable");
+const QName QN_STANZA_SUBSCRIPTION_REQUIRED(true, NS_STANZA, "subscription-required");
+const QName QN_STANZA_UNDEFINED_CONDITION(true, NS_STANZA, "undefined-condition");
+const QName QN_STANZA_UNEXPECTED_REQUEST(true, NS_STANZA, "unexpected-request");
+const QName QN_STANZA_TEXT(true, NS_STANZA, "text");
+
+const QName QN_BIND_BIND(true, NS_BIND, "bind");
+const QName QN_BIND_RESOURCE(true, NS_BIND, "resource");
+const QName QN_BIND_JID(true, NS_BIND, "jid");
+
+const QName QN_MESSAGE(true, NS_CLIENT, "message");
+const QName QN_BODY(true, NS_CLIENT, "body");
+const QName QN_SUBJECT(true, NS_CLIENT, "subject");
+const QName QN_THREAD(true, NS_CLIENT, "thread");
+const QName QN_PRESENCE(true, NS_CLIENT, "presence");
+const QName QN_SHOW(true, NS_CLIENT, "show");
+const QName QN_STATUS(true, NS_CLIENT, "status");
+const QName QN_LANG(true, NS_CLIENT, "lang");
+const QName QN_PRIORITY(true, NS_CLIENT, "priority");
+const QName QN_IQ(true, NS_CLIENT, "iq");
+const QName QN_ERROR(true, NS_CLIENT, "error");
+
+const QName QN_SERVER_MESSAGE(true, NS_SERVER, "message");
+const QName QN_SERVER_BODY(true, NS_SERVER, "body");
+const QName QN_SERVER_SUBJECT(true, NS_SERVER, "subject");
+const QName QN_SERVER_THREAD(true, NS_SERVER, "thread");
+const QName QN_SERVER_PRESENCE(true, NS_SERVER, "presence");
+const QName QN_SERVER_SHOW(true, NS_SERVER, "show");
+const QName QN_SERVER_STATUS(true, NS_SERVER, "status");
+const QName QN_SERVER_LANG(true, NS_SERVER, "lang");
+const QName QN_SERVER_PRIORITY(true, NS_SERVER, "priority");
+const QName QN_SERVER_IQ(true, NS_SERVER, "iq");
+const QName QN_SERVER_ERROR(true, NS_SERVER, "error");
+
+const QName QN_SESSION_SESSION(true, NS_SESSION, "session");
+
+const QName QN_PRIVACY_QUERY(true, NS_PRIVACY, "query");
+const QName QN_PRIVACY_ACTIVE(true, NS_PRIVACY, "active");
+const QName QN_PRIVACY_DEFAULT(true, NS_PRIVACY, "default");
+const QName QN_PRIVACY_LIST(true, NS_PRIVACY, "list");
+const QName QN_PRIVACY_ITEM(true, NS_PRIVACY, "item");
+const QName QN_PRIVACY_IQ(true, NS_PRIVACY, "iq");
+const QName QN_PRIVACY_MESSAGE(true, NS_PRIVACY, "message");
+const QName QN_PRIVACY_PRESENCE_IN(true, NS_PRIVACY, "presence-in");
+const QName QN_PRIVACY_PRESENCE_OUT(true, NS_PRIVACY, "presence-out");
+
+const QName QN_ROSTER_QUERY(true, NS_ROSTER, "query");
+const QName QN_ROSTER_ITEM(true, NS_ROSTER, "item");
+const QName QN_ROSTER_GROUP(true, NS_ROSTER, "group");
+
+const QName QN_VCARD_QUERY(true, NS_VCARD, "vCard");
+const QName QN_VCARD_FN(true, NS_VCARD, "FN");
+
+const QName QN_XML_LANG(true, NS_XML, "lang");
+
+const std::string STR_TYPE("type");
+const std::string STR_ID("id");
+const std::string STR_NAME("name");
+const std::string STR_JID("jid");
+const std::string STR_SUBSCRIPTION("subscription");
+const std::string STR_ASK("ask");
+
+const QName QN_ENCODING(true, STR_EMPTY, STR_ENCODING);
+const QName QN_VERSION(true, STR_EMPTY, STR_VERSION);
+const QName QN_TO(true, STR_EMPTY, "to");
+const QName QN_FROM(true, STR_EMPTY, "from");
+const QName QN_TYPE(true, STR_EMPTY, "type");
+const QName QN_ID(true, STR_EMPTY, "id");
+const QName QN_CODE(true, STR_EMPTY, "code");
+const QName QN_NAME(true, STR_EMPTY, "name");
+const QName QN_VALUE(true, STR_EMPTY, "value");
+const QName QN_ACTION(true, STR_EMPTY, "action");
+const QName QN_ORDER(true, STR_EMPTY, "order");
+const QName QN_MECHANISM(true, STR_EMPTY, "mechanism");
+const QName QN_ASK(true, STR_EMPTY, "ask");
+const QName QN_JID(true, STR_EMPTY, "jid");
+const QName QN_SUBSCRIPTION(true, STR_EMPTY, "subscription");
+const QName QN_SOURCE(true, STR_EMPTY, "source");
+
+const QName QN_XMLNS_CLIENT(true, NS_XMLNS, STR_CLIENT);
+const QName QN_XMLNS_SERVER(true, NS_XMLNS, STR_SERVER);
+const QName QN_XMLNS_STREAM(true, NS_XMLNS, STR_STREAM);
+
+// Presence
+const std::string STR_SHOW_AWAY("away");
+const std::string STR_SHOW_CHAT("chat");
+const std::string STR_SHOW_DND("dnd");
+const std::string STR_SHOW_XA("xa");
+
+// Subscription
+const std::string STR_SUBSCRIBE("subscribe");
+const std::string STR_SUBSCRIBED("subscribed");
+const std::string STR_UNSUBSCRIBE("unsubscribe");
+const std::string STR_UNSUBSCRIBED("unsubscribed");
+
+
+// JEP 0030
+const QName QN_NODE(true, STR_EMPTY, "node");
+const QName QN_CATEGORY(true, STR_EMPTY, "category");
+const QName QN_VAR(true, STR_EMPTY, "var");
+const std::string NS_DISCO_INFO("http://jabber.org/protocol/disco#info");
+const std::string NS_DISCO_ITEMS("http://jabber.org/protocol/disco#items");
+const QName QN_DISCO_INFO_QUERY(true, NS_DISCO_INFO, "query");
+const QName QN_DISCO_IDENTITY(true, NS_DISCO_INFO, "identity");
+const QName QN_DISCO_FEATURE(true, NS_DISCO_INFO, "feature");
+
+const QName QN_DISCO_ITEMS_QUERY(true, NS_DISCO_ITEMS, "query");
+const QName QN_DISCO_ITEM(true, NS_DISCO_ITEMS, "item");
+
+
+// JEP 0115
+const std::string NS_CAPS("http://jabber.org/protocol/caps");
+const QName QN_CAPS_C(true, NS_CAPS, "c");
+const QName QN_VER(true, STR_EMPTY, "ver");
+const QName QN_EXT(true, STR_EMPTY, "ext");
+
+// JEP 0091 Delayed Delivery
+const std::string kNSDelay("jabber:x:delay");
+const QName kQnDelayX(true, kNSDelay, "x");
+const QName kQnStamp(true, STR_EMPTY, "stamp");
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h
new file mode 100644
index 00000000..b05af965
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h
@@ -0,0 +1,300 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
+#define _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
+
+#include <string>
+#include "talk/xmllite/qname.h"
+#include "talk/xmpp/jid.h"
+
+
+#define NS_CLIENT Constants::ns_client()
+#define NS_SERVER Constants::ns_server()
+#define NS_STREAM Constants::ns_stream()
+#define NS_XSTREAM Constants::ns_xstream()
+#define NS_TLS Constants::ns_tls()
+#define NS_SASL Constants::ns_sasl()
+#define NS_BIND Constants::ns_bind()
+#define NS_DIALBACK Constants::ns_dialback()
+#define NS_SESSION Constants::ns_session()
+#define NS_STANZA Constants::ns_stanza()
+#define NS_PRIVACY Constants::ns_privacy()
+#define NS_ROSTER Constants::ns_roster()
+#define NS_VCARD Constants::ns_vcard()
+#define STR_CLIENT Constants::str_client()
+#define STR_SERVER Constants::str_server()
+#define STR_STREAM Constants::str_stream()
+
+namespace buzz {
+
+extern const Jid JID_EMPTY;
+
+class Constants {
+ public:
+ static const std::string & ns_client();
+ static const std::string & ns_server();
+ static const std::string & ns_stream();
+ static const std::string & ns_xstream();
+ static const std::string & ns_tls();
+ static const std::string & ns_sasl();
+ static const std::string & ns_bind();
+ static const std::string & ns_dialback();
+ static const std::string & ns_session();
+ static const std::string & ns_stanza();
+ static const std::string & ns_privacy();
+ static const std::string & ns_roster();
+ static const std::string & ns_vcard();
+
+ static const std::string & str_client();
+ static const std::string & str_server();
+ static const std::string & str_stream();
+};
+
+extern const std::string STR_GET;
+extern const std::string STR_SET;
+extern const std::string STR_RESULT;
+extern const std::string STR_ERROR;
+
+extern const std::string STR_FROM;
+extern const std::string STR_TO;
+extern const std::string STR_BOTH;
+extern const std::string STR_REMOVE;
+
+extern const std::string STR_MESSAGE;
+extern const std::string STR_BODY;
+extern const std::string STR_PRESENCE;
+extern const std::string STR_STATUS;
+extern const std::string STR_SHOW;
+extern const std::string STR_PRIOIRTY;
+extern const std::string STR_IQ;
+
+extern const std::string STR_TYPE;
+extern const std::string STR_NAME;
+extern const std::string STR_ID;
+extern const std::string STR_JID;
+extern const std::string STR_SUBSCRIPTION;
+extern const std::string STR_ASK;
+extern const std::string STR_X;
+extern const std::string STR_GOOGLE_COM;
+extern const std::string STR_GMAIL_COM;
+extern const std::string STR_GOOGLEMAIL_COM;
+extern const std::string STR_DEFAULT_DOMAIN;
+
+extern const std::string STR_UNAVAILABLE;
+extern const std::string STR_INVISIBLE;
+
+extern const QName QN_STREAM_STREAM;
+extern const QName QN_STREAM_FEATURES;
+extern const QName QN_STREAM_ERROR;
+
+extern const QName QN_XSTREAM_BAD_FORMAT;
+extern const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
+extern const QName QN_XSTREAM_CONFLICT;
+extern const QName QN_XSTREAM_CONNECTION_TIMEOUT;
+extern const QName QN_XSTREAM_HOST_GONE;
+extern const QName QN_XSTREAM_HOST_UNKNOWN;
+extern const QName QN_XSTREAM_IMPROPER_ADDRESSIING;
+extern const QName QN_XSTREAM_INTERNAL_SERVER_ERROR;
+extern const QName QN_XSTREAM_INVALID_FROM;
+extern const QName QN_XSTREAM_INVALID_ID;
+extern const QName QN_XSTREAM_INVALID_NAMESPACE;
+extern const QName QN_XSTREAM_INVALID_XML;
+extern const QName QN_XSTREAM_NOT_AUTHORIZED;
+extern const QName QN_XSTREAM_POLICY_VIOLATION;
+extern const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
+extern const QName QN_XSTREAM_RESOURCE_CONSTRAINT;
+extern const QName QN_XSTREAM_RESTRICTED_XML;
+extern const QName QN_XSTREAM_SEE_OTHER_HOST;
+extern const QName QN_XSTREAM_SYSTEM_SHUTDOWN;
+extern const QName QN_XSTREAM_UNDEFINED_CONDITION;
+extern const QName QN_XSTREAM_UNSUPPORTED_ENCODING;
+extern const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
+extern const QName QN_XSTREAM_UNSUPPORTED_VERSION;
+extern const QName QN_XSTREAM_XML_NOT_WELL_FORMED;
+extern const QName QN_XSTREAM_TEXT;
+
+extern const QName QN_TLS_STARTTLS;
+extern const QName QN_TLS_REQUIRED;
+extern const QName QN_TLS_PROCEED;
+extern const QName QN_TLS_FAILURE;
+
+extern const QName QN_SASL_MECHANISMS;
+extern const QName QN_SASL_MECHANISM;
+extern const QName QN_SASL_AUTH;
+extern const QName QN_SASL_CHALLENGE;
+extern const QName QN_SASL_RESPONSE;
+extern const QName QN_SASL_ABORT;
+extern const QName QN_SASL_SUCCESS;
+extern const QName QN_SASL_FAILURE;
+extern const QName QN_SASL_ABORTED;
+extern const QName QN_SASL_INCORRECT_ENCODING;
+extern const QName QN_SASL_INVALID_AUTHZID;
+extern const QName QN_SASL_INVALID_MECHANISM;
+extern const QName QN_SASL_MECHANISM_TOO_WEAK;
+extern const QName QN_SASL_NOT_AUTHORIZED;
+extern const QName QN_SASL_TEMPORARY_AUTH_FAILURE;
+
+extern const QName QN_DIALBACK_RESULT;
+extern const QName QN_DIALBACK_VERIFY;
+
+extern const QName QN_STANZA_BAD_REQUEST;
+extern const QName QN_STANZA_CONFLICT;
+extern const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
+extern const QName QN_STANZA_FORBIDDEN;
+extern const QName QN_STANZA_GONE;
+extern const QName QN_STANZA_INTERNAL_SERVER_ERROR;
+extern const QName QN_STANZA_ITEM_NOT_FOUND;
+extern const QName QN_STANZA_JID_MALFORMED;
+extern const QName QN_STANZA_NOT_ACCEPTABLE;
+extern const QName QN_STANZA_NOT_ALLOWED;
+extern const QName QN_STANZA_PAYMENT_REQUIRED;
+extern const QName QN_STANZA_RECIPIENT_UNAVAILABLE;
+extern const QName QN_STANZA_REDIRECT;
+extern const QName QN_STANZA_REGISTRATION_REQUIRED;
+extern const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
+extern const QName QN_STANZA_REMOTE_SERVER_TIMEOUT;
+extern const QName QN_STANZA_RESOURCE_CONSTRAINT;
+extern const QName QN_STANZA_SERVICE_UNAVAILABLE;
+extern const QName QN_STANZA_SUBSCRIPTION_REQUIRED;
+extern const QName QN_STANZA_UNDEFINED_CONDITION;
+extern const QName QN_STANZA_UNEXPECTED_REQUEST;
+extern const QName QN_STANZA_TEXT;
+
+extern const QName QN_BIND_BIND;
+extern const QName QN_BIND_RESOURCE;
+extern const QName QN_BIND_JID;
+
+extern const QName QN_MESSAGE;
+extern const QName QN_BODY;
+extern const QName QN_SUBJECT;
+extern const QName QN_THREAD;
+extern const QName QN_PRESENCE;
+extern const QName QN_SHOW;
+extern const QName QN_STATUS;
+extern const QName QN_LANG;
+extern const QName QN_PRIORITY;
+extern const QName QN_IQ;
+extern const QName QN_ERROR;
+
+extern const QName QN_SERVER_MESSAGE;
+extern const QName QN_SERVER_BODY;
+extern const QName QN_SERVER_SUBJECT;
+extern const QName QN_SERVER_THREAD;
+extern const QName QN_SERVER_PRESENCE;
+extern const QName QN_SERVER_SHOW;
+extern const QName QN_SERVER_STATUS;
+extern const QName QN_SERVER_LANG;
+extern const QName QN_SERVER_PRIORITY;
+extern const QName QN_SERVER_IQ;
+extern const QName QN_SERVER_ERROR;
+
+extern const QName QN_SESSION_SESSION;
+
+extern const QName QN_PRIVACY_QUERY;
+extern const QName QN_PRIVACY_ACTIVE;
+extern const QName QN_PRIVACY_DEFAULT;
+extern const QName QN_PRIVACY_LIST;
+extern const QName QN_PRIVACY_ITEM;
+extern const QName QN_PRIVACY_IQ;
+extern const QName QN_PRIVACY_MESSAGE;
+extern const QName QN_PRIVACY_PRESENCE_IN;
+extern const QName QN_PRIVACY_PRESENCE_OUT;
+
+extern const QName QN_ROSTER_QUERY;
+extern const QName QN_ROSTER_ITEM;
+extern const QName QN_ROSTER_GROUP;
+
+extern const QName QN_VCARD_QUERY;
+extern const QName QN_VCARD_FN;
+
+extern const QName QN_XML_LANG;
+
+extern const QName QN_ENCODING;
+extern const QName QN_VERSION;
+extern const QName QN_TO;
+extern const QName QN_FROM;
+extern const QName QN_TYPE;
+extern const QName QN_ID;
+extern const QName QN_CODE;
+extern const QName QN_NAME;
+extern const QName QN_VALUE;
+extern const QName QN_ACTION;
+extern const QName QN_ORDER;
+extern const QName QN_MECHANISM;
+extern const QName QN_ASK;
+extern const QName QN_JID;
+extern const QName QN_SUBSCRIPTION;
+
+
+extern const QName QN_XMLNS_CLIENT;
+extern const QName QN_XMLNS_SERVER;
+extern const QName QN_XMLNS_STREAM;
+
+// Presence
+extern const std::string STR_SHOW_AWAY;
+extern const std::string STR_SHOW_CHAT;
+extern const std::string STR_SHOW_DND;
+extern const std::string STR_SHOW_XA;
+
+// Subscription
+extern const std::string STR_SUBSCRIBE;
+extern const std::string STR_SUBSCRIBED;
+extern const std::string STR_UNSUBSCRIBE;
+extern const std::string STR_UNSUBSCRIBED;
+
+
+// JEP 0030
+extern const QName QN_NODE;
+extern const QName QN_CATEGORY;
+extern const QName QN_VAR;
+extern const std::string NS_DISCO_INFO;
+extern const std::string NS_DISCO_ITEMS;
+
+extern const QName QN_DISCO_INFO_QUERY;
+extern const QName QN_DISCO_IDENTITY;
+extern const QName QN_DISCO_FEATURE;
+
+extern const QName QN_DISCO_ITEMS_QUERY;
+extern const QName QN_DISCO_ITEM;
+
+
+// JEP 0115
+extern const std::string NS_CAPS;
+extern const QName QN_CAPS_C;
+extern const QName QN_VER;
+extern const QName QN_EXT;
+
+
+// JEP 0091 Delayed Delivery
+extern const std::string kNSDelay;
+extern const QName kQnDelayX;
+extern const QName kQnStamp;
+
+}
+
+#endif // _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc
new file mode 100644
index 00000000..b742e03a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc
@@ -0,0 +1,477 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+extern "C" {
+#include <ctype.h>
+}
+#include <string>
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/constants.h"
+#include "talk/base/common.h"
+#include <algorithm>
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+static int AsciiToLower(int x) {
+ return (x <= 'Z' && x >= 'A') ? (x + ('a' - 'A')) : x;
+}
+
+Jid::Jid() : data_(NULL) {
+}
+
+Jid::Jid(bool is_special, const std::string & special) {
+ data_ = is_special ? new Data(special, STR_EMPTY, STR_EMPTY) : NULL;
+}
+
+Jid::Jid(const std::string & jid_string) {
+ if (jid_string == STR_EMPTY) {
+ data_ = NULL;
+ return;
+ }
+
+ // First find the slash and slice of that part
+ size_t slash = jid_string.find('/');
+ std::string resource_name = (slash == std::string::npos ? STR_EMPTY :
+ jid_string.substr(slash + 1));
+
+ // Now look for the node
+ std::string node_name;
+ size_t at = jid_string.find('@');
+ size_t domain_begin;
+ if (at < slash && at != std::string::npos) {
+ node_name = jid_string.substr(0, at);
+ domain_begin = at + 1;
+ } else {
+ domain_begin = 0;
+ }
+
+ // Now take what is left as the domain
+ size_t domain_length =
+ ( slash == std::string::npos
+ ? jid_string.length() - domain_begin
+ : slash - domain_begin);
+
+ // avoid allocating these constants repeatedly
+ std::string domain_name;
+
+ if (domain_length == 9 && jid_string.find("gmail.com", domain_begin) == domain_begin) {
+ domain_name = STR_GMAIL_COM;
+ }
+ else if (domain_length == 14 && jid_string.find("googlemail.com", domain_begin) == domain_begin) {
+ domain_name = STR_GOOGLEMAIL_COM;
+ }
+ else if (domain_length == 10 && jid_string.find("google.com", domain_begin) == domain_begin) {
+ domain_name = STR_GOOGLE_COM;
+ }
+ else {
+ domain_name = jid_string.substr(domain_begin, domain_length);
+ }
+
+ // If the domain is empty we have a non-valid jid and we should empty
+ // everything else out
+ if (domain_name.empty()) {
+ data_ = NULL;
+ return;
+ }
+
+ bool valid_node;
+ std::string validated_node = prepNode(node_name,
+ node_name.begin(), node_name.end(), &valid_node);
+ bool valid_domain;
+ std::string validated_domain = prepDomain(domain_name,
+ domain_name.begin(), domain_name.end(), &valid_domain);
+ bool valid_resource;
+ std::string validated_resource = prepResource(resource_name,
+ resource_name.begin(), resource_name.end(), &valid_resource);
+
+ if (!valid_node || !valid_domain || !valid_resource) {
+ data_ = NULL;
+ return;
+ }
+
+ data_ = new Data(validated_node, validated_domain, validated_resource);
+}
+
+Jid::Jid(const std::string & node_name,
+ const std::string & domain_name,
+ const std::string & resource_name) {
+ if (domain_name.empty()) {
+ data_ = NULL;
+ return;
+ }
+
+ bool valid_node;
+ std::string validated_node = prepNode(node_name,
+ node_name.begin(), node_name.end(), &valid_node);
+ bool valid_domain;
+ std::string validated_domain = prepDomain(domain_name,
+ domain_name.begin(), domain_name.end(), &valid_domain);
+ bool valid_resource;
+ std::string validated_resource = prepResource(resource_name,
+ resource_name.begin(), resource_name.end(), &valid_resource);
+
+ if (!valid_node || !valid_domain || !valid_resource) {
+ data_ = NULL;
+ return;
+ }
+
+ data_ = new Data(validated_node, validated_domain, validated_resource);
+}
+
+std::string Jid::Str() const {
+ if (!IsValid())
+ return STR_EMPTY;
+
+ std::string ret;
+
+ if (!data_->node_name_.empty())
+ ret = data_->node_name_ + "@";
+
+ ASSERT(data_->domain_name_ != STR_EMPTY);
+ ret += data_->domain_name_;
+
+ if (!data_->resource_name_.empty())
+ ret += "/" + data_->resource_name_;
+
+ return ret;
+}
+
+bool
+Jid::IsValid() const {
+ return data_ != NULL && !data_->domain_name_.empty();
+}
+
+bool
+Jid::IsBare() const {
+ return IsValid() &&
+ data_->resource_name_.empty();
+}
+
+bool
+Jid::IsFull() const {
+ return IsValid() &&
+ !data_->resource_name_.empty();
+}
+
+Jid
+Jid::BareJid() const {
+ if (!IsValid())
+ return Jid();
+ if (!IsFull())
+ return *this;
+ return Jid(data_->node_name_, data_->domain_name_, STR_EMPTY);
+}
+
+#if 0
+void
+Jid::set_node(const std::string & node_name) {
+ data_->node_name_ = node_name;
+}
+void
+Jid::set_domain(const std::string & domain_name) {
+ data_->domain_name_ = domain_name;
+}
+void
+Jid::set_resource(const std::string & res_name) {
+ data_->resource_name_ = res_name;
+}
+#endif
+
+bool
+Jid::BareEquals(const Jid & other) const {
+ return (other.data_ == data_ ||
+ data_ != NULL &&
+ other.data_ != NULL &&
+ other.data_->node_name_ == data_->node_name_ &&
+ other.data_->domain_name_ == data_->domain_name_);
+}
+
+bool
+Jid::operator==(const Jid & other) const {
+ return (other.data_ == data_ ||
+ data_ != NULL &&
+ other.data_ != NULL &&
+ other.data_->node_name_ == data_->node_name_ &&
+ other.data_->domain_name_ == data_->domain_name_ &&
+ other.data_->resource_name_ == data_->resource_name_);
+}
+
+int
+Jid::Compare(const Jid & other) const {
+ if (other.data_ == data_)
+ return 0;
+ if (data_ == NULL)
+ return -1;
+ if (other.data_ == NULL)
+ return 1;
+
+ int compare_result;
+ compare_result = data_->node_name_.compare(other.data_->node_name_);
+ if (0 != compare_result)
+ return compare_result;
+ compare_result = data_->domain_name_.compare(other.data_->domain_name_);
+ if (0 != compare_result)
+ return compare_result;
+ compare_result = data_->resource_name_.compare(other.data_->resource_name_);
+ return compare_result;
+}
+
+
+// --- JID parsing code: ---
+
+// Checks and normalizes the node part of a JID.
+std::string
+Jid::prepNode(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ char ch = *i;
+ if (ch <= 0x7F) {
+ result += prepNodeAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement the correct stringprep protocol for these
+ result += tolower(ch);
+ }
+ if (!char_valid) {
+ return STR_EMPTY;
+ }
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a node.
+char
+Jid::prepNodeAscii(char ch, bool *valid) {
+ *valid = true;
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ return (char)(ch + ('a' - 'A'));
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
+ case '\"': case '\'':
+ case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+
+// Checks and normalizes the resource part of a JID.
+std::string
+Jid::prepResource(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ char ch = *i;
+ if (ch <= 0x7F) {
+ result += prepResourceAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement the correct stringprep protocol for these
+ result += ch;
+ }
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+// Returns the appropriate mapping for an ASCII character in a resource.
+char
+Jid::prepResourceAscii(char ch, bool *valid) {
+ *valid = true;
+ switch (ch) {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+// Checks and normalizes the domain part of a JID.
+std::string
+Jid::prepDomain(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ // TODO: if the domain contains a ':', then we should parse it
+ // as an IPv6 address rather than giving an error about illegal domain.
+ prepDomain(str, start, end, &result, valid);
+ if (!*valid) {
+ return STR_EMPTY;
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+
+// Checks and normalizes an IDNA domain.
+void
+Jid::prepDomain(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, std::string *buf, bool *valid) {
+ *valid = false;
+ std::string::const_iterator last = start;
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool label_valid = true;
+ char ch = *i;
+ switch (ch) {
+ case 0x002E:
+#if 0 // FIX: This isn't UTF-8-aware.
+ case 0x3002:
+ case 0xFF0E:
+ case 0xFF61:
+#endif
+ prepDomainLabel(str, last, i, buf, &label_valid);
+ *buf += '.';
+ last = i + 1;
+ break;
+ }
+ if (!label_valid) {
+ return;
+ }
+ }
+ prepDomainLabel(str, last, end, buf, valid);
+}
+
+// Checks and normalizes a domain label.
+void
+Jid::prepDomainLabel(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, std::string *buf, bool *valid) {
+ *valid = false;
+
+ int startLen = buf->length();
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ char ch = *i;
+ if (ch <= 0x7F) {
+ *buf += prepDomainLabelAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement ToASCII for these
+ *buf += ch;
+ }
+ if (!char_valid) {
+ return;
+ }
+ }
+
+ int count = buf->length() - startLen;
+ if (count == 0) {
+ return;
+ }
+ else if (count > 63) {
+ return;
+ }
+
+ // Is this check needed? See comment in prepDomainLabelAscii.
+ if ((*buf)[startLen] == '-') {
+ return;
+ }
+ if ((*buf)[buf->length() - 1] == '-') {
+ return;
+ }
+ *valid = true;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a domain label.
+char
+Jid::prepDomainLabelAscii(char ch, bool *valid) {
+ *valid = true;
+ // TODO: A literal reading of the spec seems to say that we do
+ // not need to check for these illegal characters (an "internationalized
+ // domain label" runs ToASCII with UseSTD3... set to false). But that
+ // can't be right. We should at least be checking that there are no '/'
+ // or '@' characters in the domain. Perhaps we should see what others
+ // do in this case.
+
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ return (char)(ch + ('a' - 'A'));
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
+ case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
+ case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
+ case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
+ case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
+ case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h
new file mode 100644
index 00000000..ae7944bf
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h
@@ -0,0 +1,144 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _jid_h_
+#define _jid_h_
+
+#include <string>
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+//! The Jid class encapsulates and provides parsing help for Jids
+//! A Jid consists of three parts. The node, the domain and the resource.
+//!
+//! node@domain/resource
+//!
+//! The node and resource are both optional. A valid jid is defined to have
+//! a domain. A bare jid is defined to not have a resource and a full jid
+//! *does* have a resource.
+class Jid {
+public:
+ explicit Jid();
+ explicit Jid(const std::string & jid_string);
+ explicit Jid(const std::string & node_name,
+ const std::string & domain_name,
+ const std::string & resource_name);
+ explicit Jid(bool special, const std::string & special_string);
+ Jid(const Jid & jid) : data_(jid.data_) {
+ if (data_ != NULL) {
+ data_->AddRef();
+ }
+ }
+ Jid & operator=(const Jid & jid) {
+ if (jid.data_ != NULL) {
+ jid.data_->AddRef();
+ }
+ if (data_ != NULL) {
+ data_->Release();
+ }
+ data_ = jid.data_;
+ return *this;
+ }
+ ~Jid() {
+ if (data_ != NULL) {
+ data_->Release();
+ }
+ }
+
+
+ const std::string & node() const { return !data_ ? STR_EMPTY : data_->node_name_; }
+ // void set_node(const std::string & node_name);
+ const std::string & domain() const { return !data_ ? STR_EMPTY : data_->domain_name_; }
+ // void set_domain(const std::string & domain_name);
+ const std::string & resource() const { return !data_ ? STR_EMPTY : data_->resource_name_; }
+ // void set_resource(const std::string & res_name);
+
+ std::string Str() const;
+ Jid BareJid() const;
+
+ bool IsValid() const;
+ bool IsBare() const;
+ bool IsFull() const;
+
+ bool BareEquals(const Jid & other) const;
+
+ bool operator==(const Jid & other) const;
+ bool operator!=(const Jid & other) const { return !operator==(other); }
+
+ bool operator<(const Jid & other) const { return Compare(other) < 0; };
+ bool operator>(const Jid & other) const { return Compare(other) > 0; };
+
+ int Compare(const Jid & other) const;
+
+
+private:
+
+ static std::string prepNode(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static char prepNodeAscii(char ch, bool *valid);
+ static std::string prepResource(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static char prepResourceAscii(char ch, bool *valid);
+ static std::string prepDomain(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static void prepDomain(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ std::string *buf, bool *valid);
+ static void prepDomainLabel(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ std::string *buf, bool *valid);
+ static char prepDomainLabelAscii(char ch, bool *valid);
+
+ class Data {
+ public:
+ Data() : refcount_(1) {}
+ Data(const std::string & node, const std::string &domain, const std::string & resource) :
+ node_name_(node),
+ domain_name_(domain),
+ resource_name_(resource),
+ refcount_(1) {}
+ const std::string node_name_;
+ const std::string domain_name_;
+ const std::string resource_name_;
+
+ void AddRef() { refcount_++; }
+ void Release() { if (!--refcount_) delete this; }
+ private:
+ int refcount_;
+ };
+
+ Data * data_;
+};
+
+}
+
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h
new file mode 100644
index 00000000..659820f5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h
@@ -0,0 +1,80 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PLAINSASLHANDLER_H_
+#define _PLAINSASLHANDLER_H_
+
+#include "talk/xmpp/saslhandler.h"
+#include <algorithm>
+
+namespace buzz {
+
+class PlainSaslHandler : public SaslHandler {
+public:
+ PlainSaslHandler(const Jid & jid, const XmppPassword & password) :
+ jid_(jid), password_(password) {}
+
+ virtual ~PlainSaslHandler() {}
+
+ // Should pick the best method according to this handler
+ // returns the empty string if none are suitable
+ virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+
+ // Do not send @google.com passwords unencrypted
+ if (!encrypted && jid_.domain() == "google.com") {
+ return "";
+ }
+
+ std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
+ if (it == mechanisms.end()) {
+ return "";
+ }
+ else {
+ return "PLAIN";
+ }
+ }
+
+ // Creates a SaslMechanism for the given mechanism name (you own it
+ // once you get it). If not handled, return NULL.
+ virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
+ if (mechanism == "PLAIN") {
+ return new SaslPlainMechanism(jid_, password_);
+ }
+ return NULL;
+ }
+
+private:
+ Jid jid_;
+ XmppPassword password_;
+
+};
+
+
+}
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h
new file mode 100644
index 00000000..8d2aa9d4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h
@@ -0,0 +1,85 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PREXMPPAUTH_H_
+#define _PREXMPPAUTH_H_
+
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/saslhandler.h"
+#include "talk/xmpp/xmpppassword.h"
+
+namespace cricket {
+ class SocketAddress;
+}
+
+namespace buzz {
+
+class Jid;
+class SaslMechanism;
+
+class CaptchaChallenge {
+ public:
+ CaptchaChallenge() : captcha_needed_(false) {}
+ CaptchaChallenge(const std::string& token, const std::string& url)
+ : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
+ }
+
+ bool captcha_needed() const { return captcha_needed_; }
+ const std::string& captcha_token() const { return captcha_token_; }
+
+ // This url is relative to the gaia server. Once we have better tools
+ // for cracking URLs, we should probably make this a full URL
+ const std::string& captcha_image_url() const { return captcha_image_url_; }
+
+ private:
+ bool captcha_needed_;
+ std::string captcha_token_;
+ std::string captcha_image_url_;
+};
+
+class PreXmppAuth : public SaslHandler {
+public:
+ virtual ~PreXmppAuth() {}
+
+ virtual void StartPreXmppAuth(
+ const Jid & jid,
+ const cricket::SocketAddress & server,
+ const XmppPassword & pass,
+ const std::string & auth_cookie) = 0;
+
+ sigslot::signal0<> SignalAuthDone;
+
+ virtual bool IsAuthDone() = 0;
+ virtual bool IsAuthorized() = 0;
+ virtual bool HadError() = 0;
+ virtual CaptchaChallenge GetCaptchaChallenge() = 0;
+ virtual std::string GetAuthCookie() = 0;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h
new file mode 100644
index 00000000..a6630d90
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h
@@ -0,0 +1,67 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SASLCOOKIEMECHANISM_H_
+#define _SASLCOOKIEMECHANISM_H_
+
+#include "talk/xmpp/saslmechanism.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/constants.h"
+
+namespace buzz {
+
+class SaslCookieMechanism : public SaslMechanism {
+
+public:
+ SaslCookieMechanism(const std::string & mechanism, const std::string & username, const std::string & cookie) :
+ mechanism_(mechanism), username_(username), cookie_(cookie) {}
+
+ virtual std::string GetMechanismName() { return mechanism_; }
+
+ virtual XmlElement * StartSaslAuth() {
+ // send initial request
+ XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+ el->AddAttr(QN_MECHANISM, mechanism_);
+
+ std::string credential;
+ credential.append("\0", 1);
+ credential.append(username_);
+ credential.append("\0", 1);
+ credential.append(cookie_);
+ el->AddText(Base64Encode(credential));
+ return el;
+ }
+
+private:
+ std::string mechanism_;
+ std::string username_;
+ std::string cookie_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h
new file mode 100644
index 00000000..b57d3baf
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h
@@ -0,0 +1,59 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SASLHANDLER_H_
+#define _SASLHANDLER_H_
+
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+class SaslMechanism;
+
+// Creates mechanisms to deal with a given mechanism
+class SaslHandler {
+
+public:
+
+ // Intended to be subclassed
+ virtual ~SaslHandler() {}
+
+ // Should pick the best method according to this handler
+ // returns the empty string if none are suitable
+ virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
+
+ // Creates a SaslMechanism for the given mechanism name (you own it
+ // once you get it).
+ // If not handled, return NULL.
+ virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
+};
+
+}
+
+#endif
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc
new file mode 100644
index 00000000..092df104
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc
@@ -0,0 +1,68 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/base64.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/constants.h"
+#include "talk/xmpp/saslmechanism.h"
+
+namespace buzz {
+
+XmlElement *
+SaslMechanism::StartSaslAuth() {
+ return new XmlElement(QN_SASL_AUTH, true);
+}
+
+XmlElement *
+SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
+ return new XmlElement(QN_SASL_ABORT, true);
+}
+
+void
+SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
+}
+
+void
+SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
+}
+
+std::string
+SaslMechanism::Base64Encode(const std::string & plain) {
+ return Base64::encode(plain);
+}
+
+std::string
+SaslMechanism::Base64Decode(const std::string & encoded) {
+ return Base64::decode(encoded);
+}
+
+std::string
+SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
+ return Base64::encodeFromArray(plain, length);
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h
new file mode 100644
index 00000000..f2e5adce
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h
@@ -0,0 +1,74 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SASLMECHANISM_H_
+#define _SASLMECHANISM_H_
+
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+
+
+// Defines a mechnanism to do SASL authentication.
+// Subclass instances should have a self-contained way to present
+// credentials.
+class SaslMechanism {
+
+public:
+
+ // Intended to be subclassed
+ virtual ~SaslMechanism() {}
+
+ // Should return the name of the SASL mechanism, e.g., "PLAIN"
+ virtual std::string GetMechanismName() = 0;
+
+ // Should generate the initial "auth" request. Default is just <auth/>.
+ virtual XmlElement * StartSaslAuth();
+
+ // Should respond to a SASL "<challenge>" request. Default is
+ // to abort (for mechanisms that do not do challenge-response)
+ virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
+
+ // Notification of a SASL "<success>". Sometimes information
+ // is passed on success.
+ virtual void HandleSaslSuccess(const XmlElement * success);
+
+ // Notification of a SASL "<failure>". Sometimes information
+ // for the user is passed on failure.
+ virtual void HandleSaslFailure(const XmlElement * failure);
+
+protected:
+ static std::string Base64Encode(const std::string & plain);
+ static std::string Base64Decode(const std::string & encoded);
+ static std::string Base64EncodeFromArray(const char * plain, size_t length);
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h
new file mode 100644
index 00000000..7e0b0562
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h
@@ -0,0 +1,65 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SASLPLAINMECHANISM_H_
+#define _SASLPLAINMECHANISM_H_
+
+#include "talk/xmpp/saslmechanism.h"
+#include "talk/xmpp/xmpppassword.h"
+
+namespace buzz {
+
+class SaslPlainMechanism : public SaslMechanism {
+
+public:
+ SaslPlainMechanism(const buzz::Jid user_jid, const XmppPassword & password) :
+ user_jid_(user_jid), password_(password) {}
+
+ virtual std::string GetMechanismName() { return "PLAIN"; }
+
+ virtual XmlElement * StartSaslAuth() {
+ // send initial request
+ XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+ el->AddAttr(QN_MECHANISM, "PLAIN");
+
+ FormatXmppPassword credential;
+ credential.Append("\0", 1);
+ credential.Append(user_jid_.Str());
+ credential.Append("\0", 1);
+ credential.Append(&password_);
+ el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
+ return el;
+ }
+
+private:
+ Jid user_jid_;
+ XmppPassword password_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc
new file mode 100644
index 00000000..959b6f88
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc
@@ -0,0 +1,372 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xmppclient.h"
+#include "xmpptask.h"
+#include "talk/xmpp/constants.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/saslplainmechanism.h"
+#include "talk/xmpp/prexmppauth.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmpp/plainsaslhandler.h"
+
+namespace buzz {
+
+Task *
+XmppClient::GetParent(int code) {
+ if (code == XMPP_CLIENT_TASK_CODE)
+ return this;
+ else
+ return Task::GetParent(code);
+}
+
+class XmppClient::Private :
+ public sigslot::has_slots<>,
+ public XmppSessionHandler,
+ public XmppOutputHandler {
+public:
+
+ Private(XmppClient * client) :
+ client_(client),
+ socket_(NULL),
+ engine_(NULL),
+ proxy_port_(0),
+ pre_engine_error_(XmppEngine::ERROR_NONE),
+ signal_closed_(false) {}
+
+ // the owner
+ XmppClient * const client_;
+
+ // the two main objects
+ scoped_ptr<AsyncSocket> socket_;
+ scoped_ptr<XmppEngine> engine_;
+ scoped_ptr<PreXmppAuth> pre_auth_;
+ XmppPassword pass_;
+ std::string auth_cookie_;
+ cricket::SocketAddress server_;
+ std::string proxy_host_;
+ int proxy_port_;
+ XmppEngine::Error pre_engine_error_;
+ CaptchaChallenge captcha_challenge_;
+ bool signal_closed_;
+
+ // implementations of interfaces
+ void OnStateChange(int state);
+ void WriteOutput(const char * bytes, size_t len);
+ void StartTls(const std::string & domainname);
+ void CloseConnection();
+
+ // slots for socket signals
+ void OnSocketConnected();
+ void OnSocketRead();
+ void OnSocketClosed();
+};
+
+XmppReturnStatus
+XmppClient::Connect(const XmppClientSettings & settings, AsyncSocket * socket, PreXmppAuth * pre_auth) {
+ if (socket == NULL)
+ return XMPP_RETURN_BADARGUMENT;
+ if (d_->socket_.get() != NULL)
+ return XMPP_RETURN_BADSTATE;
+
+ d_->socket_.reset(socket);
+
+ d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
+ d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
+ d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
+
+ d_->engine_.reset(XmppEngine::Create());
+ d_->engine_->SetSessionHandler(d_.get());
+ d_->engine_->SetOutputHandler(d_.get());
+ d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
+ if (!settings.resource().empty()) {
+ d_->engine_->SetRequestedResource(settings.resource());
+ }
+ d_->engine_->SetUseTls(settings.use_tls());
+
+
+ d_->pass_ = settings.pass();
+ d_->auth_cookie_ = settings.auth_cookie();
+ d_->server_ = settings.server();
+ d_->proxy_host_ = settings.proxy_host();
+ d_->proxy_port_ = settings.proxy_port();
+ d_->pre_auth_.reset(pre_auth);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppEngine::State
+XmppClient::GetState() {
+ if (d_->engine_.get() == NULL)
+ return XmppEngine::STATE_NONE;
+ return d_->engine_->GetState();
+}
+
+XmppEngine::Error
+XmppClient::GetError() {
+ if (d_->engine_.get() == NULL)
+ return XmppEngine::ERROR_NONE;
+ if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE)
+ return d_->pre_engine_error_;
+ return d_->engine_->GetError();
+}
+
+CaptchaChallenge XmppClient::GetCaptchaChallenge() {
+ if (d_->engine_.get() == NULL)
+ return CaptchaChallenge();
+ return d_->captcha_challenge_;
+}
+
+std::string
+XmppClient::GetAuthCookie() {
+ if (d_->engine_.get() == NULL)
+ return "";
+ return d_->auth_cookie_;
+}
+
+static void
+ForgetPassword(std::string & to_erase) {
+ size_t len = to_erase.size();
+ for (size_t i = 0; i < len; i++) {
+ // get rid of characters
+ to_erase[i] = 'x';
+ }
+ // get rid of length
+ to_erase.erase();
+}
+
+int
+XmppClient::ProcessStart() {
+ if (d_->pre_auth_.get()) {
+ d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
+ d_->pre_auth_->StartPreXmppAuth(
+ d_->engine_->GetUser(), d_->server_, d_->pass_, d_->auth_cookie_);
+ d_->pass_.Clear(); // done with this;
+ return STATE_PRE_XMPP_LOGIN;
+ }
+ else {
+ d_->engine_->SetSaslHandler(new PlainSaslHandler(
+ d_->engine_->GetUser(), d_->pass_));
+ d_->pass_.Clear(); // done with this;
+ return STATE_START_XMPP_LOGIN;
+ }
+}
+
+void
+XmppClient::OnAuthDone() {
+ Wake();
+}
+
+int
+XmppClient::ProcessCookieLogin() {
+ // Don't know how this could happen, but crash reports show it as NULL
+ if (!d_->pre_auth_.get()) {
+ d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ // Wait until pre authentication is done is done
+ if (!d_->pre_auth_->IsAuthDone())
+ return STATE_BLOCKED;
+
+ if (!d_->pre_auth_->IsAuthorized()) {
+ // maybe split out a case when gaia is down?
+ if (d_->pre_auth_->HadError()) {
+ d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+ }
+ else {
+ d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
+ d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
+ }
+ d_->pre_auth_.reset(NULL); // done with this
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ // Save auth cookie as a result
+ d_->auth_cookie_ = d_->pre_auth_->GetAuthCookie();
+
+ // transfer ownership of pre_auth_ to engine
+ d_->engine_->SetSaslHandler(d_->pre_auth_.release());
+
+ return STATE_START_XMPP_LOGIN;
+}
+
+int
+XmppClient::ProcessStartXmppLogin() {
+ // Done with pre-connect tasks - connect!
+ if (!d_->socket_->Connect(d_->server_)) {
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ return STATE_RESPONSE;
+}
+
+int
+XmppClient::ProcessResponse() {
+ // Hang around while we are connected.
+ if (!delivering_signal_ && (d_->engine_.get() == NULL ||
+ d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
+ return STATE_DONE;
+ return STATE_BLOCKED;
+}
+
+XmppReturnStatus
+XmppClient::Disconnect() {
+ if (d_->socket_.get() == NULL)
+ return XMPP_RETURN_BADSTATE;
+ d_->engine_->Disconnect();
+ return XMPP_RETURN_OK;
+}
+
+XmppClient::XmppClient(Task * parent) : Task(parent),
+ delivering_signal_(false) {
+ d_.reset(new Private(this));
+}
+
+XmppClient::~XmppClient() {}
+
+const Jid &
+XmppClient::jid() {
+ return d_->engine_->FullJid();
+}
+
+
+std::string
+XmppClient::NextId() {
+ return d_->engine_->NextId();
+}
+
+XmppReturnStatus
+XmppClient::SendStanza(const XmlElement * stanza) {
+ return d_->engine_->SendStanza(stanza);
+}
+
+XmppReturnStatus
+XmppClient::SendStanzaError(const XmlElement * old_stanza, XmppStanzaError xse, const std::string & message) {
+ return d_->engine_->SendStanzaError(old_stanza, xse, message);
+}
+
+XmppReturnStatus
+XmppClient::SendRaw(const std::string & text) {
+ return d_->engine_->SendRaw(text);
+}
+
+XmppEngine*
+XmppClient::engine() {
+ return d_->engine_.get();
+}
+
+void
+XmppClient::Private::OnSocketConnected() {
+ engine_->Connect();
+}
+
+void
+XmppClient::Private::OnSocketRead() {
+ char bytes[4096];
+ size_t bytes_read;
+ for (;;) {
+ if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
+ // TODO: deal with error information
+ return;
+ }
+
+ if (bytes_read == 0)
+ return;
+
+//#ifdef _DEBUG
+ client_->SignalLogInput(bytes, bytes_read);
+//#endif
+
+ engine_->HandleInput(bytes, bytes_read);
+ }
+}
+
+void
+XmppClient::Private::OnSocketClosed() {
+ engine_->ConnectionClosed();
+}
+
+void
+XmppClient::Private::OnStateChange(int state) {
+ if (state == XmppEngine::STATE_CLOSED) {
+ client_->EnsureClosed();
+ }
+ else {
+ client_->SignalStateChange((XmppEngine::State)state);
+ }
+ client_->Wake();
+}
+
+void
+XmppClient::Private::WriteOutput(const char * bytes, size_t len) {
+
+//#ifdef _DEBUG
+ client_->SignalLogOutput(bytes, len);
+//#endif
+
+ socket_->Write(bytes, len);
+ // TODO: deal with error information
+}
+
+void
+XmppClient::Private::StartTls(const std::string & domain) {
+#if defined(FEATURE_ENABLE_SSL)
+ socket_->StartTls(domain);
+#endif
+}
+
+void
+XmppClient::Private::CloseConnection() {
+ socket_->Close();
+}
+
+void
+XmppClient::AddXmppTask(XmppTask * task, XmppEngine::HandlerLevel level) {
+ d_->engine_->AddStanzaHandler(task, level);
+}
+
+void
+XmppClient::RemoveXmppTask(XmppTask * task) {
+ d_->engine_->RemoveStanzaHandler(task);
+}
+
+void
+XmppClient::EnsureClosed() {
+ if (!d_->signal_closed_) {
+ d_->signal_closed_ = true;
+ delivering_signal_ = true;
+ SignalStateChange(XmppEngine::STATE_CLOSED);
+ delivering_signal_ = false;
+ }
+}
+
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h
new file mode 100644
index 00000000..f8b4798c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h
@@ -0,0 +1,157 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPCLIENT_H_
+#define _XMPPCLIENT_H_
+
+#include <string>
+#include "talk/base/basicdefs.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/asyncsocket.h"
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/base/task.h"
+
+namespace buzz {
+
+class XmppTask;
+class PreXmppAuth;
+class CaptchaChallenge;
+
+// Just some non-colliding number. Could have picked "1".
+#define XMPP_CLIENT_TASK_CODE 0x366c1e47
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPCLIENT
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task first. XmppClient is a parent task for XmppTasks.
+//
+// XmppClient is a task which is designed to be the parent task for
+// all tasks that depend on a single Xmpp connection. If you want to,
+// for example, listen for subscription requests forever, then your
+// listener should be a task that is a child of the XmppClient that owns
+// the connection you are using. XmppClient has all the utility methods
+// that basically drill through to XmppEngine.
+//
+// XmppClient is just a wrapper for XmppEngine, and if I were writing it
+// all over again, I would make XmppClient == XmppEngine. Why?
+// XmppEngine needs tasks too, for example it has an XmppLoginTask which
+// should just be the same kind of Task instead of an XmppEngine specific
+// thing. It would help do certain things like GAIA auth cleaner.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient : public Task, public sigslot::has_slots<>
+{
+public:
+ XmppClient(Task * parent);
+ ~XmppClient();
+
+ XmppReturnStatus Connect(const XmppClientSettings & settings,
+ AsyncSocket * socket,
+ PreXmppAuth * preauth);
+
+ virtual Task * GetParent(int code);
+ virtual int ProcessStart();
+ virtual int ProcessResponse();
+ XmppReturnStatus Disconnect();
+ const Jid & jid();
+
+ sigslot::signal1<XmppEngine::State> SignalStateChange;
+ XmppEngine::State GetState();
+ XmppEngine::Error GetError();
+
+ // When there is an authentication error, we may have captcha info
+ // that the user can use to unlock their account
+ CaptchaChallenge GetCaptchaChallenge();
+
+ // When authentication is successful, this returns the service cookie
+ // (if we used GAIA authentication)
+ std::string GetAuthCookie();
+
+ std::string NextId();
+ XmppReturnStatus SendStanza(const XmlElement *stanza);
+ XmppReturnStatus SendRaw(const std::string & text);
+ XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text);
+
+ XmppEngine* engine();
+
+ sigslot::signal2<const char *, int> SignalLogInput;
+ sigslot::signal2<const char *, int> SignalLogOutput;
+
+private:
+ friend class XmppTask;
+
+ void OnAuthDone();
+
+ // managed tasks and dispatching
+ void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
+ void RemoveXmppTask(XmppTask *);
+
+ sigslot::signal0<> SignalDisconnected;
+
+private:
+ // Internal state management
+ enum {
+ STATE_PRE_XMPP_LOGIN = STATE_NEXT,
+ STATE_START_XMPP_LOGIN = STATE_NEXT + 1,
+ };
+ int Process(int state) {
+ switch (state) {
+ case STATE_PRE_XMPP_LOGIN: return ProcessCookieLogin();
+ case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
+ default: return Task::Process(state);
+ }
+ }
+
+ std::string GetStateName(int state) const {
+ switch (state) {
+ case STATE_PRE_XMPP_LOGIN: return "PRE_XMPP_LOGIN";
+ case STATE_START_XMPP_LOGIN: return "START_XMPP_LOGIN";
+ default: return Task::GetStateName(state);
+ }
+ }
+
+ int ProcessCookieLogin();
+ int ProcessStartXmppLogin();
+ void EnsureClosed();
+
+ class Private;
+ friend class Private;
+ scoped_ptr<Private> d_;
+
+ bool delivering_signal_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h
new file mode 100644
index 00000000..9795682b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h
@@ -0,0 +1,94 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPCLIENTSETTINGS_H_
+#define _XMPPCLIENTSETTINGS_H_
+
+#include "talk/p2p/base/port.h"
+#include "talk/xmpp/xmpppassword.h"
+
+namespace buzz {
+
+class XmppClientSettings {
+public:
+ XmppClientSettings() :
+ use_tls_(false), use_cookie_auth_(false), protocol_(cricket::PROTO_TCP),
+ proxy_(cricket::PROXY_NONE), proxy_port_(80), use_proxy_auth_(false) {}
+
+ void set_user(const std::string & user) { user_ = user; }
+ void set_host(const std::string & host) { host_ = host; }
+ void set_pass(const XmppPassword & pass) { pass_ = pass; }
+ void set_auth_cookie(const std::string & cookie) { auth_cookie_ = cookie; }
+ void set_resource(const std::string & resource) { resource_ = resource; }
+ void set_use_tls(bool use_tls) { use_tls_ = use_tls; }
+ void set_server(const cricket::SocketAddress & server) {
+ server_ = server;
+ }
+ void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
+ void set_proxy(cricket::ProxyType f) { proxy_ = f; }
+ void set_proxy_host(const std::string & host) { proxy_host_ = host; }
+ void set_proxy_port(int port) { proxy_port_ = port; };
+ void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
+ void set_proxy_user(const std::string & user) { proxy_user_ = user; }
+ void set_proxy_pass(const XmppPassword & pass) { proxy_pass_ = pass; }
+
+ const std::string & user() const { return user_; }
+ const std::string & host() const { return host_; }
+ const XmppPassword & pass() const { return pass_; }
+ const std::string & auth_cookie() const { return auth_cookie_; }
+ const std::string & resource() const { return resource_; }
+ bool use_tls() const { return use_tls_; }
+ const cricket::SocketAddress & server() const { return server_; }
+ cricket::ProtocolType protocol() const { return protocol_; }
+ cricket::ProxyType proxy() const { return proxy_; }
+ const std::string & proxy_host() const { return proxy_host_; }
+ int proxy_port() const { return proxy_port_; }
+ bool use_proxy_auth() const { return use_proxy_auth_; }
+ const std::string & proxy_user() const { return proxy_user_; }
+ const XmppPassword & proxy_pass() const { return proxy_pass_; }
+
+private:
+ std::string user_;
+ std::string host_;
+ XmppPassword pass_;
+ std::string auth_cookie_;
+ std::string resource_;
+ bool use_tls_;
+ bool use_cookie_auth_;
+ cricket::SocketAddress server_;
+ cricket::ProtocolType protocol_;
+ cricket::ProxyType proxy_;
+ std::string proxy_host_;
+ int proxy_port_;
+ bool use_proxy_auth_;
+ std::string proxy_user_;
+ XmppPassword proxy_pass_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h
new file mode 100644
index 00000000..ef8f2ea8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h
@@ -0,0 +1,332 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmppengine_h_
+#define _xmppengine_h_
+
+// also part of the API
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlelement.h"
+
+
+namespace buzz {
+
+class XmppEngine;
+class SaslHandler;
+typedef void * XmppIqCookie;
+
+//! XMPP stanza error codes.
+//! Used in XmppEngine.SendStanzaError().
+enum XmppStanzaError {
+ XSE_BAD_REQUEST,
+ XSE_CONFLICT,
+ XSE_FEATURE_NOT_IMPLEMENTED,
+ XSE_FORBIDDEN,
+ XSE_GONE,
+ XSE_INTERNAL_SERVER_ERROR,
+ XSE_ITEM_NOT_FOUND,
+ XSE_JID_MALFORMED,
+ XSE_NOT_ACCEPTABLE,
+ XSE_NOT_ALLOWED,
+ XSE_PAYMENT_REQUIRED,
+ XSE_RECIPIENT_UNAVAILABLE,
+ XSE_REDIRECT,
+ XSE_REGISTRATION_REQUIRED,
+ XSE_SERVER_NOT_FOUND,
+ XSE_SERVER_TIMEOUT,
+ XSE_RESOURCE_CONSTRAINT,
+ XSE_SERVICE_UNAVAILABLE,
+ XSE_SUBSCRIPTION_REQUIRED,
+ XSE_UNDEFINED_CONDITION,
+ XSE_UNEXPECTED_REQUEST,
+};
+
+// XmppReturnStatus
+// This is used by API functions to synchronously return status.
+enum XmppReturnStatus {
+ XMPP_RETURN_OK,
+ XMPP_RETURN_BADARGUMENT,
+ XMPP_RETURN_BADSTATE,
+ XMPP_RETURN_PENDING,
+ XMPP_RETURN_UNEXPECTED,
+ XMPP_RETURN_NOTYETIMPLEMENTED,
+};
+
+//! Callback for socket output for an XmppEngine connection.
+//! Register via XmppEngine.SetOutputHandler. An XmppEngine
+//! can call back to this handler while it is processing
+//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
+class XmppOutputHandler {
+public:
+
+ //! Deliver the specified bytes to the XMPP socket.
+ virtual void WriteOutput(const char * bytes, size_t len) = 0;
+
+ //! Initiate TLS encryption on the socket.
+ //! The implementation must verify that the SSL
+ //! certificate matches the given domainname.
+ virtual void StartTls(const std::string & domainname) = 0;
+
+ //! Called when engine wants the connecton closed.
+ virtual void CloseConnection() = 0;
+};
+
+//! Callback to deliver engine state change notifications
+//! to the object managing the engine.
+class XmppSessionHandler {
+public:
+ //! Called when engine changes state. Argument is new state.
+ virtual void OnStateChange(int state) = 0;
+};
+
+//! Callback to deliver stanzas to an Xmpp application module.
+//! Register via XmppEngine.SetDefaultSessionHandler or via
+//! XmppEngine.AddSessionHAndler.
+class XmppStanzaHandler {
+public:
+
+ //! Process the given stanza.
+ //! The handler must return true if it has handled the stanza.
+ //! A false return value causes the stanza to be passed on to
+ //! the next registered handler.
+ virtual bool HandleStanza(const XmlElement * stanza) = 0;
+};
+
+//! Callback to deliver iq responses (results and errors).
+//! Register while sending an iq via XmppEngine.SendIq.
+//! Iq responses are routed to matching XmppIqHandlers in preference
+//! to sending to any registered SessionHandlers.
+class XmppIqHandler {
+public:
+ //! Called to handle the iq response.
+ //! The response may be either a result or an error, and will have
+ //! an 'id' that matches the request and a 'from' that matches the
+ //! 'to' of the request. Called no more than once; once this is
+ //! called, the handler is automatically unregistered.
+ virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
+};
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput. Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngine {
+public:
+ static XmppEngine * Create();
+ virtual ~XmppEngine() {}
+
+ //! Error codes. See GetError().
+ enum Error {
+ ERROR_NONE = 0, //!< No error
+ ERROR_XML, //!< Malformed XML or encoding error
+ ERROR_STREAM, //!< XMPP stream error - see GetStreamError()
+ ERROR_VERSION, //!< XMPP version error
+ ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials)
+ ERROR_TLS, //!< TLS could not be negotiated
+ ERROR_AUTH, //!< Authentication could not be negotiated
+ ERROR_BIND, //!< Resource or session binding could not be negotiated
+ ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
+ ERROR_DOCUMENT_CLOSED, //!< Closed by </stream:stream>
+ ERROR_SOCKET, //!< Socket error
+ };
+
+ //! States. See GetState().
+ enum State {
+ STATE_NONE = 0, //!< Nonexistent state
+ STATE_START, //!< Initial state.
+ STATE_OPENING, //!< Exchanging stream headers, authenticating and so on.
+ STATE_OPEN, //!< Authenticated and bound.
+ STATE_CLOSED, //!< Session closed, possibly due to error.
+ };
+
+ // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+ //! Registers the handler for socket output
+ virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
+
+ //! Provides socket input to the engine
+ virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
+
+ //! Advises the engine that the socket has closed
+ virtual XmppReturnStatus ConnectionClosed() = 0;
+
+ // SESSION SETUP ---------------------------------------------------------
+
+ //! Indicates the (bare) JID for the user to use.
+ virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
+
+ //! Get the login (bare) JID.
+ virtual const Jid & GetUser() = 0;
+
+ //! Provides different methods for credentials for login.
+ //! Takes ownership of this object; deletes when login is done
+ virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
+
+ //! Sets whether TLS will be used within the connection (default true).
+ virtual XmppReturnStatus SetUseTls(bool useTls) = 0;
+
+ //! Sets an alternate domain from which we allows TLS certificates.
+ //! This is for use in the case where a we want to allow a proxy to
+ //! serve up its own certificate rather than one owned by the underlying
+ //! domain.
+ virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain) = 0;
+
+ //! Gets whether TLS will be used within the connection.
+ virtual bool GetUseTls() = 0;
+
+ //! Sets the request resource name, if any (optional).
+ //! Note that the resource name may be overridden by the server; after
+ //! binding, the actual resource name is available as part of FullJid().
+ virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
+
+ //! Gets the request resource name.
+ virtual const std::string & GetRequestedResource() = 0;
+
+ // SESSION MANAGEMENT ---------------------------------------------------
+
+ //! Set callback for state changes.
+ virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
+
+ //! Initiates the XMPP connection.
+ //! After supplying connection settings, call this once to initiate,
+ //! (optionally) encrypt, authenticate, and bind the connection.
+ virtual XmppReturnStatus Connect() = 0;
+
+ //! The current engine state.
+ virtual State GetState() = 0;
+
+ //! Returns true if the connection is encrypted (under TLS)
+ virtual bool IsEncrypted() = 0;
+
+ //! The error code.
+ //! Consult this after XmppOutputHandler.OnClose().
+ virtual Error GetError() = 0;
+
+ //! The stream:error stanza, when the error is XMPP_ERROR_STREAM.
+ //! Notice the stanza returned is owned by the XmppEngine and
+ //! is deleted when the engine is destroyed.
+ virtual const XmlElement * GetStreamError() = 0;
+
+ //! Closes down the connection.
+ //! Sends CloseConnection to output, and disconnects and registered
+ //! session handlers. After Disconnect completes, it is guaranteed
+ //! that no further callbacks will be made.
+ virtual XmppReturnStatus Disconnect() = 0;
+
+ // APPLICATION USE -------------------------------------------------------
+
+ enum HandlerLevel {
+ HL_NONE = 0,
+ HL_PEEK, //!< Sees messages before all other processing; cannot abort
+ HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
+ HL_SENDER, //!< Watches for a type of message from a specific sender
+ HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs
+ HL_ALL, //!< Watches all messages - gets last shot
+ HL_COUNT, //!< Count of handler levels
+ };
+
+ //! Adds a listener for session events.
+ //! Stanza delivery is chained to session handlers; the first to
+ //! return 'true' is the last to get each stanza.
+ virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
+
+ //! Removes a listener for session events.
+ virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
+
+ //! Sends a stanza to the server.
+ virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
+
+ //! Sends raw text to the server
+ virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
+
+ //! Sends an iq to the server, and registers a callback for the result.
+ //! Returns the cookie passed to the result handler.
+ virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+ XmppIqHandler* iq_handler,
+ XmppIqCookie* cookie) = 0;
+
+ //! Unregisters an iq callback handler given its cookie.
+ //! No callback will come to this handler after it's unregistered.
+ virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler** iq_handler) = 0;
+
+
+ //! Forms and sends an error in response to the given stanza.
+ //! Swaps to and from, sets type to "error", and adds error information
+ //! based on the passed code. Text is optional and may be STR_EMPTY.
+ virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text) = 0;
+
+ //! The fullly bound JID.
+ //! This JID is only valid after binding has succeeded. If the value
+ //! is JID_NULL, the binding has not succeeded.
+ virtual const Jid & FullJid() = 0;
+
+ //! The next unused iq id for this connection.
+ //! Call this when building iq stanzas, to ensure that each iq
+ //! gets its own unique id.
+ virtual std::string NextId() = 0;
+
+};
+
+}
+
+
+// Move these to a better location
+
+#define XMPP_FAILED(x) \
+ ( (x) == buzz::XMPP_RETURN_OK ? false : true) \
+
+
+#define XMPP_SUCCEEDED(x) \
+ ( (x) == buzz::XMPP_RETURN_OK ? true : false) \
+
+#define IFR(x) \
+ do { \
+ xmpp_status = (x); \
+ if (XMPP_FAILED(xmpp_status)) { \
+ return xmpp_status; \
+ } \
+ } while (false) \
+
+
+#define IFC(x) \
+ do { \
+ xmpp_status = (x); \
+ if (XMPP_FAILED(xmpp_status)) { \
+ goto Cleanup; \
+ } \
+ } while (false) \
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc
new file mode 100644
index 00000000..173d711b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc
@@ -0,0 +1,480 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TRACK_ARRAY_ALLOC_PROBLEM
+
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/xmpplogintask.h"
+#include "talk/xmpp/constants.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmpp/saslhandler.h"
+// #include "buzz/saslmechanism.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+static const std::string XMPP_CLIENT_NAMESPACES[] = {
+ "stream", "http://etherx.jabber.org/streams",
+ "", "jabber:client",
+};
+
+static const size_t XMPP_CLIENT_NAMESPACES_LEN = 4;
+
+XmppEngine * XmppEngine::Create() {
+ return new XmppEngineImpl();
+}
+
+
+XmppEngineImpl::XmppEngineImpl() :
+ stanzaParseHandler_(this),
+ stanzaParser_(&stanzaParseHandler_),
+ engine_entered_(0),
+ user_jid_(JID_EMPTY),
+ password_(),
+ requested_resource_(STR_EMPTY),
+ tls_needed_(true),
+ login_task_(new XmppLoginTask(this)),
+ next_id_(0),
+ bound_jid_(JID_EMPTY),
+ state_(STATE_START),
+ encrypted_(false),
+ error_code_(ERROR_NONE),
+ stream_error_(NULL),
+ raised_reset_(false),
+ output_handler_(NULL),
+ session_handler_(NULL),
+ iq_entries_(new IqEntryVector()),
+ output_(new std::stringstream()),
+ sasl_handler_(NULL) {
+ for (int i = 0; i < HL_COUNT; i+= 1) {
+ stanza_handlers_[i].reset(new StanzaHandlerVector());
+ }
+}
+
+XmppEngineImpl::~XmppEngineImpl() {
+ DeleteIqCookies();
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetOutputHandler(XmppOutputHandler* output_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ output_handler_ = output_handler;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetSessionHandler(XmppSessionHandler* session_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ session_handler_ = session_handler;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::HandleInput(const char * bytes, size_t len) {
+ if (state_ < STATE_OPENING || state_ > STATE_OPEN)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ stanzaParser_.Parse(bytes, len, false);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::ConnectionClosed() {
+ if (state_ != STATE_CLOSED) {
+ EnterExit ee(this);
+ // If told that connection closed and not already closed,
+ // then connection was unpexectedly dropped.
+ SignalError(ERROR_CONNECTION_CLOSED);
+ }
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetUseTls(bool useTls) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ tls_needed_ = useTls;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetTlsServerDomain(const std::string & tls_server_domain) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ tls_server_domain_= tls_server_domain;
+
+ return XMPP_RETURN_OK;
+}
+
+bool
+XmppEngineImpl::GetUseTls() {
+ return tls_needed_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetUser(const Jid & jid) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ user_jid_ = jid;
+
+ return XMPP_RETURN_OK;
+}
+
+const Jid &
+XmppEngineImpl::GetUser() {
+ return user_jid_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetSaslHandler(SaslHandler * sasl_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ sasl_handler_.reset(sasl_handler);
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetRequestedResource(const std::string & resource) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ requested_resource_ = resource;
+
+ return XMPP_RETURN_OK;
+}
+
+const std::string &
+XmppEngineImpl::GetRequestedResource() {
+ return requested_resource_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::AddStanzaHandler(XmppStanzaHandler * stanza_handler,
+ XmppEngine::HandlerLevel level) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ stanza_handlers_[level]->push_back(stanza_handler);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::RemoveStanzaHandler(XmppStanzaHandler * stanza_handler) {
+
+ bool found = false;
+
+ for (int level = 0; level < HL_COUNT; level += 1) {
+ StanzaHandlerVector::iterator new_end =
+ std::remove(stanza_handlers_[level]->begin(),
+ stanza_handlers_[level]->end(),
+ stanza_handler);
+
+ if (new_end != stanza_handlers_[level]->end()) {
+ stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return XMPP_RETURN_BADARGUMENT;
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::Connect() {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ // get the login task started
+ state_ = STATE_OPENING;
+ if (login_task_.get()) {
+ login_task_->IncomingStanza(NULL, false);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SendStanza(const XmlElement * element) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ if (login_task_.get()) {
+ // still handshaking - then outbound stanzas are queued
+ login_task_->OutgoingStanza(element);
+ } else {
+ // handshake done - send straight through
+ InternalSendStanza(element);
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SendRaw(const std::string & text) {
+ if (state_ == STATE_CLOSED || login_task_.get())
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ (*output_) << text;
+
+ return XMPP_RETURN_OK;
+}
+
+std::string
+XmppEngineImpl::NextId() {
+ std::stringstream ss;
+ ss << next_id_++;
+ return ss.str();
+}
+
+XmppReturnStatus
+XmppEngineImpl::Disconnect() {
+
+ if (state_ != STATE_CLOSED) {
+ EnterExit ee(this);
+ if (state_ == STATE_OPEN)
+ *output_ << "</stream:stream>";
+ state_ = STATE_CLOSED;
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::IncomingStart(const XmlElement * pelStart) {
+ if (HasError() || raised_reset_)
+ return;
+
+ if (login_task_.get()) {
+ // start-stream should go to login task
+ login_task_->IncomingStanza(pelStart, true);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ }
+ else {
+ // if not logging in, it's an error to see a start
+ SignalError(ERROR_XML);
+ }
+}
+
+void
+XmppEngineImpl::IncomingStanza(const XmlElement * stanza) {
+ if (HasError() || raised_reset_)
+ return;
+
+ if (stanza->Name() == QN_STREAM_ERROR) {
+ // Explicit XMPP stream error
+ SignalStreamError(stanza);
+ } else if (login_task_.get()) {
+ // Handle login handshake
+ login_task_->IncomingStanza(stanza, false);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ } else if (HandleIqResponse(stanza)) {
+ // iq is handled by above call
+ } else {
+ // give every "peek" handler a shot at all stanzas
+ for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
+ (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
+ }
+
+ // give other handlers a shot in precedence order, stopping after handled
+ for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
+ for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
+ if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
+ goto Handled;
+ }
+ }
+
+ // If nobody wants to handle a stanza then send back an error.
+ // Only do this for IQ stanzas as messages should probably just be dropped
+ // and presence stanzas should certainly be dropped.
+ std::string type = stanza->Attr(QN_TYPE);
+ if (stanza->Name() == QN_IQ &&
+ !(type == "error" || type == "result")) {
+ SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
+ }
+ }
+ Handled:
+ ; // handled - we're done
+}
+
+void
+XmppEngineImpl::IncomingEnd(bool isError) {
+ if (HasError() || raised_reset_)
+ return;
+
+ SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED);
+}
+
+void
+XmppEngineImpl::InternalSendStart(const std::string & to) {
+ // send stream-beginning
+ // note, we put a \r\n at tne end fo the first line to cause non-XMPP
+ // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
+ *output_ << "<stream:stream to=\"" << to << "\" version=\"1.0\" "
+ "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+ "xmlns=\"jabber:client\">\r\n";
+}
+
+void
+XmppEngineImpl::InternalSendStanza(const XmlElement * element) {
+ // It should really never be necessary to set a FROM attribute on a stanza.
+ // It is implied by the bind on the stream and if you get it wrong
+ // (by flipping from/to on a message?) the server will close the stream.
+ ASSERT(!element->HasAttr(QN_FROM));
+
+ // TODO: consider caching the XmlPrinter
+ XmlPrinter::PrintXml(output_.get(), element,
+ XMPP_CLIENT_NAMESPACES, XMPP_CLIENT_NAMESPACES_LEN);
+}
+
+std::string
+XmppEngineImpl::ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+ return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
+}
+
+SaslMechanism *
+XmppEngineImpl::GetSaslMechanism(const std::string & name) {
+ return sasl_handler_->CreateSaslMechanism(name);
+}
+
+void
+XmppEngineImpl::SignalBound(const Jid & fullJid) {
+ if (state_ == STATE_OPENING) {
+ bound_jid_ = fullJid;
+ state_ = STATE_OPEN;
+ }
+}
+
+void
+XmppEngineImpl::SignalStreamError(const XmlElement * pelStreamError) {
+ if (state_ != STATE_CLOSED) {
+ stream_error_.reset(new XmlElement(*pelStreamError));
+ SignalError(ERROR_STREAM);
+ }
+}
+
+void
+XmppEngineImpl::SignalError(Error errorCode) {
+ if (state_ != STATE_CLOSED) {
+ error_code_ = errorCode;
+ state_ = STATE_CLOSED;
+ }
+}
+
+bool
+XmppEngineImpl::HasError() {
+ return error_code_ != ERROR_NONE;
+}
+
+void
+XmppEngineImpl::StartTls(const std::string & domain) {
+ if (output_handler_) {
+ output_handler_->StartTls(
+ tls_server_domain_.empty() ? domain : tls_server_domain_);
+ encrypted_ = true;
+ }
+}
+
+XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
+ : engine_(engine),
+ state_(engine->state_),
+ error_(engine->error_code_) {
+ engine->engine_entered_ += 1;
+}
+
+XmppEngineImpl::EnterExit::~EnterExit() {
+ XmppEngineImpl* engine = engine_;
+
+ engine->engine_entered_ -= 1;
+
+ bool closing = (engine->state_ != state_ &&
+ engine->state_ == STATE_CLOSED);
+ bool flushing = closing || (engine->engine_entered_ == 0);
+
+ if (engine->output_handler_ && flushing) {
+ std::string output = engine->output_->str();
+ if (output.length() > 0)
+ engine->output_handler_->WriteOutput(output.c_str(), output.length());
+ engine->output_->str("");
+
+ if (closing) {
+ engine->output_handler_->CloseConnection();
+ engine->output_handler_ = 0;
+ }
+ }
+
+ if (engine->engine_entered_)
+ return;
+
+ if (engine->raised_reset_) {
+ engine->stanzaParser_.Reset();
+ engine->raised_reset_ = false;
+ }
+
+ if (engine->session_handler_) {
+ if (engine->state_ != state_)
+ engine->session_handler_->OnStateChange(engine->state_);
+ // Note: Handling of OnStateChange(CLOSED) should allow for the
+ // deletion of the engine, so no members should be accessed
+ // after this line.
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h
new file mode 100644
index 00000000..c36f168c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h
@@ -0,0 +1,262 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmppengineimpl_h_
+#define _xmppengineimpl_h_
+
+#include <sstream>
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmppstanzaparser.h"
+
+namespace buzz {
+
+class XmppLoginTask;
+class XmppEngine;
+class XmppIqEntry;
+class SaslHandler;
+class SaslMechanism;
+
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput. Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngineImpl : public XmppEngine {
+public:
+ XmppEngineImpl();
+ virtual ~XmppEngineImpl();
+
+ // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+ //! Registers the handler for socket output
+ virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
+
+ //! Provides socket input to the engine
+ virtual XmppReturnStatus HandleInput(const char * bytes, size_t len);
+
+ //! Advises the engine that the socket has closed
+ virtual XmppReturnStatus ConnectionClosed();
+
+ // SESSION SETUP ---------------------------------------------------------
+
+ //! Indicates the (bare) JID for the user to use.
+ virtual XmppReturnStatus SetUser(const Jid & jid);
+
+ //! Get the login (bare) JID.
+ virtual const Jid & GetUser();
+
+ //! Indicates the autentication to use. Takes ownership of the object.
+ virtual XmppReturnStatus SetSaslHandler(SaslHandler * sasl_handler);
+
+ //! Sets whether TLS will be used within the connection (default true).
+ virtual XmppReturnStatus SetUseTls(bool useTls);
+
+ //! Sets an alternate domain from which we allows TLS certificates.
+ //! This is for use in the case where a we want to allow a proxy to
+ //! serve up its own certificate rather than one owned by the underlying
+ //! domain.
+ virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain);
+
+ //! Gets whether TLS will be used within the connection.
+ virtual bool GetUseTls();
+
+ //! Sets the request resource name, if any (optional).
+ //! Note that the resource name may be overridden by the server; after
+ //! binding, the actual resource name is available as part of FullJid().
+ virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
+
+ //! Gets the request resource name.
+ virtual const std::string & GetRequestedResource();
+
+ // SESSION MANAGEMENT ---------------------------------------------------
+
+ //! Set callback for state changes.
+ virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
+
+ //! Initiates the XMPP connection.
+ //! After supplying connection settings, call this once to initiate,
+ //! (optionally) encrypt, authenticate, and bind the connection.
+ virtual XmppReturnStatus Connect();
+
+ //! The current engine state.
+ virtual State GetState() { return state_; }
+
+ //! Returns true if the connection is encrypted (under TLS)
+ virtual bool IsEncrypted() { return encrypted_; }
+
+ //! The error code.
+ //! Consult this after XmppOutputHandler.OnClose().
+ virtual Error GetError() { return error_code_; }
+
+ //! The stream:error stanza, when the error is XMPP_ERROR_STREAM.
+ //! Notice the stanza returned is owned by the XmppEngine and
+ //! is deleted when the engine is destroyed.
+ virtual const XmlElement * GetStreamError() { return stream_error_.get(); }
+
+ //! Closes down the connection.
+ //! Sends CloseConnection to output, and disconnects and registered
+ //! session handlers. After Disconnect completes, it is guaranteed
+ //! that no further callbacks will be made.
+ virtual XmppReturnStatus Disconnect();
+
+ // APPLICATION USE -------------------------------------------------------
+
+ //! Adds a listener for session events.
+ //! Stanza delivery is chained to session handlers; the first to
+ //! return 'true' is the last to get each stanza.
+ virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
+ XmppEngine::HandlerLevel level);
+
+ //! Removes a listener for session events.
+ virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
+
+ //! Sends a stanza to the server.
+ virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza);
+
+ //! Sends raw text to the server
+ virtual XmppReturnStatus SendRaw(const std::string & text);
+
+ //! Sends an iq to the server, and registers a callback for the result.
+ //! Returns the cookie passed to the result handler.
+ virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+ XmppIqHandler* iq_handler,
+ XmppIqCookie* cookie);
+
+ //! Unregisters an iq callback handler given its cookie.
+ //! No callback will come to this handler after it's unregistered.
+ virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler** iq_handler);
+
+ //! Forms and sends an error in response to the given stanza.
+ //! Swaps to and from, sets type to "error", and adds error information
+ //! based on the passed code. Text is optional and may be STR_EMPTY.
+ virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text);
+
+ //! The fullly bound JID.
+ //! This JID is only valid after binding has succeeded. If the value
+ //! is JID_NULL, the binding has not succeeded.
+ virtual const Jid & FullJid() { return bound_jid_; }
+
+ //! The next unused iq id for this connection.
+ //! Call this when building iq stanzas, to ensure that each iq
+ //! gets its own unique id.
+ virtual std::string NextId();
+
+private:
+ friend class XmppLoginTask;
+ friend class XmppIqEntry;
+
+ void IncomingStanza(const XmlElement *pelStanza);
+ void IncomingStart(const XmlElement *pelStanza);
+ void IncomingEnd(bool isError);
+
+ void InternalSendStart(const std::string & domainName);
+ void InternalSendStanza(const XmlElement * pelStanza);
+ std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted);
+ SaslMechanism * GetSaslMechanism(const std::string & name);
+ void SignalBound(const Jid & fullJid);
+ void SignalStreamError(const XmlElement * pelStreamError);
+ void SignalError(Error errorCode);
+ bool HasError();
+ void DeleteIqCookies();
+ bool HandleIqResponse(const XmlElement * element);
+ void StartTls(const std::string & domain);
+ void RaiseReset() { raised_reset_ = true; }
+
+ class StanzaParseHandler : public XmppStanzaParseHandler {
+ public:
+ StanzaParseHandler(XmppEngineImpl * outer) : outer_(outer) {}
+ virtual void StartStream(const XmlElement * pelStream)
+ { outer_->IncomingStart(pelStream); }
+ virtual void Stanza(const XmlElement * pelStanza)
+ { outer_->IncomingStanza(pelStanza); }
+ virtual void EndStream()
+ { outer_->IncomingEnd(false); }
+ virtual void XmlError()
+ { outer_->IncomingEnd(true); }
+ private:
+ XmppEngineImpl * const outer_;
+ };
+
+ class EnterExit {
+ public:
+ EnterExit(XmppEngineImpl* engine);
+ ~EnterExit();
+ private:
+ XmppEngineImpl* engine_;
+ State state_;
+ Error error_;
+
+ };
+
+ friend class StanzaParseHandler;
+ friend class EnterExit;
+
+ StanzaParseHandler stanzaParseHandler_;
+ XmppStanzaParser stanzaParser_;
+
+
+ // state
+ int engine_entered_;
+ Jid user_jid_;
+ std::string password_;
+ std::string requested_resource_;
+ bool tls_needed_;
+ std::string tls_server_domain_;
+ scoped_ptr<XmppLoginTask> login_task_;
+
+ int next_id_;
+ Jid bound_jid_;
+ State state_;
+ bool encrypted_;
+ Error error_code_;
+ scoped_ptr<XmlElement> stream_error_;
+ bool raised_reset_;
+ XmppOutputHandler* output_handler_;
+ XmppSessionHandler* session_handler_;
+
+ typedef STD_VECTOR(XmppStanzaHandler*) StanzaHandlerVector;
+ scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
+
+ typedef STD_VECTOR(XmppIqEntry*) IqEntryVector;
+ scoped_ptr<IqEntryVector> iq_entries_;
+
+ scoped_ptr<SaslHandler> sasl_handler_;
+
+ scoped_ptr<std::stringstream> output_;
+};
+
+}
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc
new file mode 100644
index 00000000..eb623ed9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc
@@ -0,0 +1,279 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <vector>
+#include <algorithm>
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/constants.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+class XmppIqEntry {
+ XmppIqEntry(const std::string & id, const std::string & to,
+ XmppEngine * pxce, XmppIqHandler * iq_handler) :
+ id_(id),
+ to_(to),
+ engine_(pxce),
+ iq_handler_(iq_handler) {
+ }
+
+private:
+ friend class XmppEngineImpl;
+
+ const std::string id_;
+ const std::string to_;
+ XmppEngine * const engine_;
+ XmppIqHandler * const iq_handler_;
+};
+
+
+XmppReturnStatus
+XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler,
+ XmppIqCookie* cookie) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+ if (NULL == iq_handler)
+ return XMPP_RETURN_BADARGUMENT;
+ if (!element || element->Name() != QN_IQ)
+ return XMPP_RETURN_BADARGUMENT;
+
+ const std::string& type = element->Attr(QN_TYPE);
+ if (type != "get" && type != "set")
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!element->HasAttr(QN_ID))
+ return XMPP_RETURN_BADARGUMENT;
+ const std::string& id = element->Attr(QN_ID);
+
+ XmppIqEntry * iq_entry = new XmppIqEntry(id,
+ element->Attr(QN_TO),
+ this, iq_handler);
+ iq_entries_->push_back(iq_entry);
+ SendStanza(element);
+
+ if (cookie)
+ *cookie = iq_entry;
+
+ return XMPP_RETURN_OK;
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler ** iq_handler) {
+
+ std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos;
+
+ pos = std::find(iq_entries_->begin(),
+ iq_entries_->end(),
+ reinterpret_cast<XmppIqEntry*>(cookie));
+
+ if (pos == iq_entries_->end())
+ return XMPP_RETURN_BADARGUMENT;
+
+ XmppIqEntry* entry = *pos;
+ iq_entries_->erase(pos);
+ if (iq_handler)
+ *iq_handler = entry->iq_handler_;
+ delete entry;
+
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::DeleteIqCookies() {
+ for (size_t i = 0; i < iq_entries_->size(); i += 1) {
+ XmppIqEntry * iq_entry_ = (*iq_entries_)[i];
+ (*iq_entries_)[i] = NULL;
+ delete iq_entry_;
+ }
+ iq_entries_->clear();
+}
+
+static void
+AecImpl(XmlElement * error_element, const QName & name,
+ const char * type, const char * code) {
+ error_element->AddElement(new XmlElement(QN_ERROR));
+ error_element->AddAttr(QN_CODE, code, 1);
+ error_element->AddAttr(QN_TYPE, type, 1);
+ error_element->AddElement(new XmlElement(name, true), 1);
+}
+
+
+static void
+AddErrorCode(XmlElement * error_element, XmppStanzaError code) {
+ switch (code) {
+ case XSE_BAD_REQUEST:
+ AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400");
+ break;
+ case XSE_CONFLICT:
+ AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409");
+ break;
+ case XSE_FEATURE_NOT_IMPLEMENTED:
+ AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED,
+ "cancel", "501");
+ break;
+ case XSE_FORBIDDEN:
+ AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403");
+ break;
+ case XSE_GONE:
+ AecImpl(error_element, QN_STANZA_GONE, "modify", "302");
+ break;
+ case XSE_INTERNAL_SERVER_ERROR:
+ AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500");
+ break;
+ case XSE_ITEM_NOT_FOUND:
+ AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404");
+ break;
+ case XSE_JID_MALFORMED:
+ AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400");
+ break;
+ case XSE_NOT_ACCEPTABLE:
+ AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406");
+ break;
+ case XSE_NOT_ALLOWED:
+ AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405");
+ break;
+ case XSE_PAYMENT_REQUIRED:
+ AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402");
+ break;
+ case XSE_RECIPIENT_UNAVAILABLE:
+ AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404");
+ break;
+ case XSE_REDIRECT:
+ AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302");
+ break;
+ case XSE_REGISTRATION_REQUIRED:
+ AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407");
+ break;
+ case XSE_SERVER_NOT_FOUND:
+ AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND,
+ "cancel", "404");
+ break;
+ case XSE_SERVER_TIMEOUT:
+ AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502");
+ break;
+ case XSE_RESOURCE_CONSTRAINT:
+ AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500");
+ break;
+ case XSE_SERVICE_UNAVAILABLE:
+ AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503");
+ break;
+ case XSE_SUBSCRIPTION_REQUIRED:
+ AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407");
+ break;
+ case XSE_UNDEFINED_CONDITION:
+ AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500");
+ break;
+ case XSE_UNEXPECTED_REQUEST:
+ AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400");
+ break;
+ }
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::SendStanzaError(const XmlElement * element_original,
+ XmppStanzaError code,
+ const std::string & text) {
+
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement error_element(element_original->Name());
+ error_element.AddAttr(QN_TYPE, "error");
+
+ // copy attrs, copy 'from' to 'to' and strip 'from'
+ for (const XmlAttr * attribute = element_original->FirstAttr();
+ attribute; attribute = attribute->NextAttr()) {
+ QName name = attribute->Name();
+ if (name == QN_TO)
+ continue; // no need to put a from attr. Server will stamp stanza
+ else if (name == QN_FROM)
+ name = QN_TO;
+ else if (name == QN_TYPE)
+ continue;
+ error_element.AddAttr(name, attribute->Value());
+ }
+
+ // copy children
+ for (const XmlChild * child = element_original->FirstChild();
+ child;
+ child = child->NextChild()) {
+ if (child->IsText()) {
+ error_element.AddText(child->AsText()->Text());
+ } else {
+ error_element.AddElement(new XmlElement(*(child->AsElement())));
+ }
+ }
+
+ // add error information
+ AddErrorCode(&error_element, code);
+ if (text != STR_EMPTY) {
+ XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true);
+ text_element->AddText(text);
+ error_element.AddElement(text_element);
+ }
+
+ SendStanza(&error_element);
+
+ return XMPP_RETURN_OK;
+}
+
+
+bool
+XmppEngineImpl::HandleIqResponse(const XmlElement * element) {
+ if (iq_entries_->empty())
+ return false;
+ if (element->Name() != QN_IQ)
+ return false;
+ std::string type = element->Attr(QN_TYPE);
+ if (type != "result" && type != "error")
+ return false;
+ if (!element->HasAttr(QN_ID))
+ return false;
+ std::string id = element->Attr(QN_ID);
+ std::string from = element->Attr(QN_FROM);
+
+ for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin();
+ it != iq_entries_->end(); it += 1) {
+ XmppIqEntry * iq_entry = *it;
+ if (iq_entry->id_ == id && iq_entry->to_ == from) {
+ iq_entries_->erase(it);
+ iq_entry->iq_handler_->IqResponse(iq_entry, element);
+ delete iq_entry;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc
new file mode 100644
index 00000000..470c2dc2
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc
@@ -0,0 +1,357 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/constants.h"
+#include "talk/base/base64.h"
+#include "talk/xmpp/xmpplogintask.h"
+#include "talk/xmpp/saslmechanism.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
+ pctx_(pctx),
+ authNeeded_(true),
+ state_(LOGINSTATE_INIT),
+ pelStanza_(NULL),
+ isStart_(false),
+ iqId_(STR_EMPTY),
+ pelFeatures_(NULL),
+ fullJid_(STR_EMPTY),
+ streamId_(STR_EMPTY),
+ pvecQueuedStanzas_(new std::vector<XmlElement *>()),
+ sasl_mech_(NULL) {
+}
+
+XmppLoginTask::~XmppLoginTask() {
+ for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
+ delete (*pvecQueuedStanzas_)[i];
+}
+
+void
+XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
+ pelStanza_ = element;
+ isStart_ = isStart;
+ Advance();
+ pelStanza_ = NULL;
+ isStart_ = false;
+}
+
+const XmlElement *
+XmppLoginTask::NextStanza() {
+ const XmlElement * result = pelStanza_;
+ pelStanza_ = NULL;
+ return result;
+}
+
+bool
+XmppLoginTask::Advance() {
+
+ for (;;) {
+
+ const XmlElement * element = NULL;
+
+ switch (state_) {
+
+ case LOGINSTATE_INIT: {
+ pctx_->RaiseReset();
+ pelFeatures_.reset(NULL);
+
+ pctx_->InternalSendStart(pctx_->user_jid_.domain());
+ state_ = LOGINSTATE_STREAMSTART_SENT;
+ break;
+ }
+
+ case LOGINSTATE_STREAMSTART_SENT: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (!isStart_ || !HandleStartStream(element))
+ return Failure(XmppEngine::ERROR_VERSION);
+
+ state_ = LOGINSTATE_STARTED_XMPP;
+ return true;
+ }
+
+ case LOGINSTATE_STARTED_XMPP: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (!HandleFeatures(element))
+ return Failure(XmppEngine::ERROR_VERSION);
+
+ if (pctx_->tls_needed_) {
+ state_ = LOGINSTATE_TLS_INIT;
+ continue;
+ }
+
+ if (authNeeded_) {
+ state_ = LOGINSTATE_AUTH_INIT;
+ continue;
+ }
+
+ state_ = LOGINSTATE_BIND_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_TLS_INIT: {
+ const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
+ if (!pelTls)
+ return Failure(XmppEngine::ERROR_TLS);
+
+ XmlElement el(QN_TLS_STARTTLS, true);
+ pctx_->InternalSendStanza(&el);
+ state_ = LOGINSTATE_TLS_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_TLS_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name() != QN_TLS_PROCEED)
+ return Failure(XmppEngine::ERROR_TLS);
+
+ // The proper domain to verify against is the real underlying
+ // domain - i.e., the domain that owns the JID. Our XmppEngineImpl
+ // also allows matching against a proxy domain instead, if it is told
+ // to do so - see the implementation of XmppEngineImpl::StartTls and
+ // XmppEngine::SetTlsServerDomain to see how you can use that feature
+ pctx_->StartTls(pctx_->user_jid_.domain());
+ pctx_->tls_needed_ = false;
+ state_ = LOGINSTATE_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_AUTH_INIT: {
+ const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
+ if (!pelSaslAuth) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // Collect together the SASL auth mechanisms presented by the server
+ std::vector<std::string> mechanisms;
+ for (const XmlElement * pelMech =
+ pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
+ pelMech;
+ pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
+
+ mechanisms.push_back(pelMech->BodyText());
+ }
+
+ // Given all the mechanisms, choose the best
+ std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
+ if (choice.empty()) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // No recognized auth mechanism - that's an error
+ sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
+ if (sasl_mech_.get() == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // OK, let's start it.
+ XmlElement * auth = sasl_mech_->StartSaslAuth();
+ if (auth == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ pctx_->InternalSendStanza(auth);
+ delete auth;
+ state_ = LOGINSTATE_SASL_RUNNING;
+ continue;
+ }
+
+ case LOGINSTATE_SASL_RUNNING: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name().Namespace() != NS_SASL)
+ return Failure(XmppEngine::ERROR_AUTH);
+ if (element->Name() == QN_SASL_CHALLENGE) {
+ XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
+ if (response == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+ pctx_->InternalSendStanza(response);
+ delete response;
+ state_ = LOGINSTATE_SASL_RUNNING;
+ continue;
+ }
+ if (element->Name() != QN_SASL_SUCCESS) {
+ return Failure(XmppEngine::ERROR_UNAUTHORIZED);
+ }
+
+ // Authenticated!
+ authNeeded_ = false;
+ state_ = LOGINSTATE_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_BIND_INIT: {
+ const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
+ const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
+ if (!pelBindFeature || !pelSessionFeature)
+ return Failure(XmppEngine::ERROR_BIND);
+
+ XmlElement iq(QN_IQ);
+ iq.AddAttr(QN_TYPE, "set");
+
+ iqId_ = pctx_->NextId();
+ iq.AddAttr(QN_ID, iqId_);
+ iq.AddElement(new XmlElement(QN_BIND_BIND, true));
+
+ if (pctx_->requested_resource_ != STR_EMPTY) {
+ iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
+ iq.AddText(pctx_->requested_resource_, 2);
+ }
+ pctx_->InternalSendStanza(&iq);
+ state_ = LOGINSTATE_BIND_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_BIND_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+ element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+ return true;
+
+ if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
+ element->FirstElement()->Name() != QN_BIND_BIND)
+ return Failure(XmppEngine::ERROR_BIND);
+
+ fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
+ if (!fullJid_.IsFull()) {
+ return Failure(XmppEngine::ERROR_BIND);
+ }
+
+ if (pctx_->user_jid_.domain() != STR_DEFAULT_DOMAIN &&
+ fullJid_.BareJid() != pctx_->user_jid_) {
+ return Failure(XmppEngine::ERROR_BIND);
+ }
+
+ // now request session
+ XmlElement iq(QN_IQ);
+ iq.AddAttr(QN_TYPE, "set");
+
+ iqId_ = pctx_->NextId();
+ iq.AddAttr(QN_ID, iqId_);
+ iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
+ pctx_->InternalSendStanza(&iq);
+
+ state_ = LOGINSTATE_SESSION_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_SESSION_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+ element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+ return false;
+
+ if (element->Attr(QN_TYPE) != "result")
+ return Failure(XmppEngine::ERROR_BIND);
+
+ pctx_->SignalBound(fullJid_);
+ FlushQueuedStanzas();
+ state_ = LOGINSTATE_DONE;
+ return true;
+ }
+
+ case LOGINSTATE_DONE:
+ return false;
+ }
+ }
+}
+
+bool
+XmppLoginTask::HandleStartStream(const XmlElement *element) {
+
+ if (element->Name() != QN_STREAM_STREAM)
+ return false;
+
+ if (element->Attr(QN_XMLNS) != "jabber:client")
+ return false;
+
+ if (element->Attr(QN_VERSION) != "1.0")
+ return false;
+
+ if (!element->HasAttr(QN_ID))
+ return false;
+
+ streamId_ = element->Attr(QN_ID);
+
+ return true;
+}
+
+bool
+XmppLoginTask::HandleFeatures(const XmlElement *element) {
+ if (element->Name() != QN_STREAM_FEATURES)
+ return false;
+
+ pelFeatures_.reset(new XmlElement(*element));
+ return true;
+}
+
+const XmlElement *
+XmppLoginTask::GetFeature(const QName & name) {
+ return pelFeatures_->FirstNamed(name);
+}
+
+bool
+XmppLoginTask::Failure(XmppEngine::Error reason) {
+ state_ = LOGINSTATE_DONE;
+ pctx_->SignalError(reason);
+ return false;
+}
+
+void
+XmppLoginTask::OutgoingStanza(const XmlElement * element) {
+ XmlElement * pelCopy = new XmlElement(*element);
+ pvecQueuedStanzas_->push_back(pelCopy);
+}
+
+void
+XmppLoginTask::FlushQueuedStanzas() {
+ for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
+ pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
+ delete (*pvecQueuedStanzas_)[i];
+ }
+ pvecQueuedStanzas_->clear();
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h
new file mode 100644
index 00000000..7f321a30
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h
@@ -0,0 +1,95 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _logintask_h_
+#define _logintask_h_
+
+#include <string>
+#include "talk/xmpp/jid.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/base/stl_decl.h"
+
+namespace buzz {
+
+class XmlElement;
+class XmppEngineImpl;
+class SaslMechanism;
+
+
+class XmppLoginTask {
+
+public:
+ XmppLoginTask(XmppEngineImpl *pctx);
+ ~XmppLoginTask();
+
+ bool IsDone()
+ { return state_ == LOGINSTATE_DONE; }
+ void IncomingStanza(const XmlElement * element, bool isStart);
+ void OutgoingStanza(const XmlElement *element);
+
+private:
+ enum LoginTaskState {
+ LOGINSTATE_INIT = 0,
+ LOGINSTATE_STREAMSTART_SENT,
+ LOGINSTATE_STARTED_XMPP,
+ LOGINSTATE_TLS_INIT,
+ LOGINSTATE_AUTH_INIT,
+ LOGINSTATE_BIND_INIT,
+ LOGINSTATE_TLS_REQUESTED,
+ LOGINSTATE_SASL_RUNNING,
+ LOGINSTATE_BIND_REQUESTED,
+ LOGINSTATE_SESSION_REQUESTED,
+ LOGINSTATE_DONE,
+ };
+
+ const XmlElement * NextStanza();
+ bool Advance();
+ bool HandleStartStream(const XmlElement * element);
+ bool HandleFeatures(const XmlElement * element);
+ const XmlElement * GetFeature(const QName & name);
+ bool Failure(XmppEngine::Error reason);
+ void FlushQueuedStanzas();
+
+ XmppEngineImpl * pctx_;
+ bool authNeeded_;
+ LoginTaskState state_;
+ const XmlElement * pelStanza_;
+ bool isStart_;
+ std::string iqId_;
+ scoped_ptr<XmlElement> pelFeatures_;
+ Jid fullJid_;
+ std::string streamId_;
+ scoped_ptr<std::vector<XmlElement *,
+ std::allocator<XmlElement *> > > pvecQueuedStanzas_;
+
+ scoped_ptr<SaslMechanism> sasl_mech_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h
new file mode 100644
index 00000000..f431b4e5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h
@@ -0,0 +1,163 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPPASSWORD_H_
+#define _XMPPPASSWORD_H_
+
+#include "talk/base/linked_ptr.h"
+#include "talk/base/scoped_ptr.h"
+
+namespace buzz {
+
+class XmppPasswordImpl {
+public:
+ virtual ~XmppPasswordImpl() {}
+ virtual size_t GetLength() const = 0;
+ virtual void CopyTo(char * dest, bool nullterminate) const = 0;
+ virtual std::string UrlEncode() const = 0;
+ virtual XmppPasswordImpl * Copy() const = 0;
+};
+
+class EmptyXmppPasswordImpl : public XmppPasswordImpl {
+public:
+ virtual ~EmptyXmppPasswordImpl() {}
+ virtual size_t GetLength() const { return 0; }
+ virtual void CopyTo(char * dest, bool nullterminate) const {
+ if (nullterminate) {
+ *dest = '\0';
+ }
+ }
+ virtual std::string UrlEncode() const { return ""; }
+ virtual XmppPasswordImpl * Copy() const { return new EmptyXmppPasswordImpl(); }
+};
+
+class XmppPassword {
+public:
+ XmppPassword() : impl_(new EmptyXmppPasswordImpl()) {}
+ size_t GetLength() const { return impl_->GetLength(); }
+ void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
+ XmppPassword(const XmppPassword & other) : impl_(other.impl_->Copy()) {}
+ explicit XmppPassword(const XmppPasswordImpl & impl) : impl_(impl.Copy()) {}
+ XmppPassword & operator=(const XmppPassword & other) {
+ if (this != &other) {
+ impl_.reset(other.impl_->Copy());
+ }
+ return *this;
+ }
+ void Clear() { impl_.reset(new EmptyXmppPasswordImpl()); }
+ std::string UrlEncode() const { return impl_->UrlEncode(); }
+
+private:
+ scoped_ptr<const XmppPasswordImpl> impl_;
+};
+
+
+// Used for constructing strings where a password is involved and we
+// need to ensure that we zero memory afterwards
+class FormatXmppPassword {
+public:
+ FormatXmppPassword() {
+ storage_ = new char[32];
+ capacity_ = 32;
+ length_ = 0;
+ storage_[0] = 0;
+ }
+
+ void Append(const std::string & text) {
+ Append(text.data(), text.length());
+ }
+
+ void Append(const char * data, size_t length) {
+ EnsureStorage(length_ + length + 1);
+ memcpy(storage_ + length_, data, length);
+ length_ += length;
+ storage_[length_] = '\0';
+ }
+
+ void Append(const XmppPassword * password) {
+ size_t len = password->GetLength();
+ EnsureStorage(length_ + len + 1);
+ password->CopyTo(storage_ + length_, true);
+ length_ += len;
+ }
+
+ size_t GetLength() {
+ return length_;
+ }
+
+ const char * GetData() {
+ return storage_;
+ }
+
+
+ // Ensures storage of at least n bytes
+ void EnsureStorage(size_t n) {
+ if (capacity_ >= n) {
+ return;
+ }
+
+ size_t old_capacity = capacity_;
+ char * old_storage = storage_;
+
+ for (;;) {
+ capacity_ *= 2;
+ if (capacity_ >= n)
+ break;
+ }
+
+ storage_ = new char[capacity_];
+
+ if (old_capacity) {
+ memcpy(storage_, old_storage, length_);
+
+ // zero memory in a way that an optimizer won't optimize it out
+ old_storage[0] = 0;
+ for (size_t i = 1; i < old_capacity; i++) {
+ old_storage[i] = old_storage[i - 1];
+ }
+ delete[] old_storage;
+ }
+ }
+
+ ~FormatXmppPassword() {
+ if (capacity_) {
+ storage_[0] = 0;
+ for (size_t i = 1; i < capacity_; i++) {
+ storage_[i] = storage_[i - 1];
+ }
+ }
+ delete[] storage_;
+ }
+private:
+ char * storage_;
+ size_t capacity_;
+ size_t length_;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc
new file mode 100644
index 00000000..66ed44fb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc
@@ -0,0 +1,104 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <expat.h>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppstanzaparser.h"
+#include "talk/xmpp/constants.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) :
+ psph_(psph),
+ innerHandler_(this),
+ parser_(&innerHandler_),
+ depth_(0),
+ builder_() {
+}
+
+void
+XmppStanzaParser::Reset() {
+ parser_.Reset();
+ depth_ = 0;
+ builder_.Reset();
+}
+
+void
+XmppStanzaParser::IncomingStartElement(
+ XmlParseContext * pctx, const char * name, const char ** atts) {
+ if (depth_++ == 0) {
+ XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts);
+ if (pelStream == NULL) {
+ pctx->RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+ psph_->StartStream(pelStream);
+ delete pelStream;
+ return;
+ }
+
+ builder_.StartElement(pctx, name, atts);
+}
+
+void
+XmppStanzaParser::IncomingCharacterData(
+ XmlParseContext * pctx, const char * text, int len) {
+ if (depth_ > 1) {
+ builder_.CharacterData(pctx, text, len);
+ }
+}
+
+void
+XmppStanzaParser::IncomingEndElement(
+ XmlParseContext * pctx, const char * name) {
+ if (--depth_ == 0) {
+ psph_->EndStream();
+ return;
+ }
+
+ builder_.EndElement(pctx, name);
+
+ if (depth_ == 1) {
+ XmlElement *element = builder_.CreateElement();
+ psph_->Stanza(element);
+ delete element;
+ }
+}
+
+void
+XmppStanzaParser::IncomingError(
+ XmlParseContext * pctx, XML_Error errCode) {
+ UNUSED(pctx);
+ UNUSED(errCode);
+ psph_->XmlError();
+}
+
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h
new file mode 100644
index 00000000..1e109a3d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h
@@ -0,0 +1,96 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _xmppstanzaparser_h_
+#define _xmppstanzaparser_h_
+
+#include "talk/xmllite/xmlparser.h"
+#include "talk/xmllite/xmlbuilder.h"
+
+
+namespace buzz {
+
+class XmlElement;
+
+class XmppStanzaParseHandler {
+public:
+ virtual void StartStream(const XmlElement * pelStream) = 0;
+ virtual void Stanza(const XmlElement * pelStanza) = 0;
+ virtual void EndStream() = 0;
+ virtual void XmlError() = 0;
+};
+
+class XmppStanzaParser {
+public:
+ XmppStanzaParser(XmppStanzaParseHandler *psph);
+ bool Parse(const char * data, size_t len, bool isFinal)
+ { return parser_.Parse(data, len, isFinal); }
+ void Reset();
+
+private:
+ class ParseHandler : public XmlParseHandler {
+ public:
+ ParseHandler(XmppStanzaParser * outer) : outer_(outer) {}
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts)
+ { outer_->IncomingStartElement(pctx, name, atts); }
+ virtual void EndElement(XmlParseContext * pctx,
+ const char * name)
+ { outer_->IncomingEndElement(pctx, name); }
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len)
+ { outer_->IncomingCharacterData(pctx, text, len); }
+ virtual void Error(XmlParseContext * pctx,
+ XML_Error errCode)
+ { outer_->IncomingError(pctx, errCode); }
+ private:
+ XmppStanzaParser * const outer_;
+ };
+
+ friend class ParseHandler;
+
+ void IncomingStartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ void IncomingEndElement(XmlParseContext * pctx,
+ const char * name);
+ void IncomingCharacterData(XmlParseContext * pctx,
+ const char * text, int len);
+ void IncomingError(XmlParseContext * pctx,
+ XML_Error errCode);
+
+ XmppStanzaParseHandler * psph_;
+ ParseHandler innerHandler_;
+ XmlParser parser_;
+ int depth_;
+ XmlBuilder builder_;
+
+ };
+
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc
new file mode 100644
index 00000000..82207f3b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc
@@ -0,0 +1,168 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/xmpp/xmpptask.h"
+#include "talk/xmpp/xmppclient.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/constants.h"
+
+namespace buzz {
+
+XmppTask::XmppTask(Task * parent, XmppEngine::HandlerLevel level)
+ : Task(parent), client_(NULL) {
+ XmppClient * client = (XmppClient*)parent->GetParent(XMPP_CLIENT_TASK_CODE);
+ client_ = client;
+ id_ = client->NextId();
+ client->AddXmppTask(this, level);
+ client->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
+}
+
+XmppTask::~XmppTask() {
+ StopImpl();
+}
+
+void
+XmppTask::StopImpl() {
+ while (NextStanza() != NULL) {}
+ if (client_) {
+ client_->RemoveXmppTask(this);
+ client_->SignalDisconnected.disconnect(this);
+ client_ = NULL;
+ }
+}
+
+XmppReturnStatus
+XmppTask::SendStanza(const XmlElement * stanza) {
+ if (client_ == NULL)
+ return XMPP_RETURN_BADSTATE;
+ return client_->SendStanza(stanza);
+}
+
+XmppReturnStatus
+XmppTask::SendStanzaError(const XmlElement * element_original,
+ XmppStanzaError code,
+ const std::string & text) {
+ if (client_ == NULL)
+ return XMPP_RETURN_BADSTATE;
+ return client_->SendStanzaError(element_original, code, text);
+}
+
+void
+XmppTask::Stop() {
+ StopImpl();
+ Task::Stop();
+}
+
+void
+XmppTask::OnDisconnect() {
+ Error();
+}
+
+void
+XmppTask::QueueStanza(const XmlElement * stanza) {
+ stanza_queue_.push_back(new XmlElement(*stanza));
+ Wake();
+}
+
+const XmlElement *
+XmppTask::NextStanza() {
+ XmlElement * result = NULL;
+ if (!stanza_queue_.empty()) {
+ result = stanza_queue_.front();
+ stanza_queue_.pop_front();
+ }
+ next_stanza_.reset(result);
+ return result;
+}
+
+XmlElement *
+XmppTask::MakeIq(const std::string & type,
+ const buzz::Jid & to, const std::string id) {
+ XmlElement * result = new XmlElement(QN_IQ);
+ if (!type.empty())
+ result->AddAttr(QN_TYPE, type);
+ if (to != JID_EMPTY)
+ result->AddAttr(QN_TO, to.Str());
+ if (!id.empty())
+ result->AddAttr(QN_ID, id);
+ return result;
+}
+
+XmlElement *
+XmppTask::MakeIqResult(const XmlElement * query) {
+ XmlElement * result = new XmlElement(QN_IQ);
+ result->AddAttr(QN_TYPE, STR_RESULT);
+ if (query->HasAttr(QN_FROM)) {
+ result->AddAttr(QN_TO, query->Attr(QN_FROM));
+ }
+ result->AddAttr(QN_ID, query->Attr(QN_ID));
+ return result;
+}
+
+bool
+XmppTask::MatchResponseIq(const XmlElement * stanza,
+ const Jid & to, const std::string & id) {
+ if (stanza->Name() != QN_IQ)
+ return false;
+
+ if (stanza->Attr(QN_ID) != id)
+ return false;
+
+ Jid from(stanza->Attr(QN_FROM));
+ if (from != to) {
+ Jid me = client_->jid();
+ // we address the server as "", but it is legal for the server
+ // to identify itself with "domain" or "myself@domain"
+ if (to != JID_EMPTY) {
+ return false;
+ }
+
+ if (from != Jid(me.domain()) && from != me.BareJid()) {
+ return false;
+ }
+ }
+
+
+ return true;
+}
+
+bool
+XmppTask::MatchRequestIq(const XmlElement * stanza,
+ const std::string & type, const QName & qn) {
+ if (stanza->Name() != QN_IQ)
+ return false;
+
+ if (stanza->Attr(QN_TYPE) != type)
+ return false;
+
+ if (stanza->FirstNamed(qn) == NULL)
+ return false;
+
+ return true;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h
new file mode 100644
index 00000000..3b56a1c9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h
@@ -0,0 +1,113 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XMPPTASK_H_
+#define _XMPPTASK_H_
+
+#include <string>
+#include <deque>
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/base/task.h"
+
+namespace buzz {
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPTASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task and XmppClient first.
+//
+// XmppTask is a task that is designed to go underneath XmppClient and be
+// useful there. It has a way of finding its XmppClient parent so you
+// can have it nested arbitrarily deep under an XmppClient and it can
+// still find the XMPP services.
+//
+// Tasks register themselves to listen to particular kinds of stanzas
+// that are sent out by the client. Rather than processing stanzas
+// right away, they should decide if they own the sent stanza,
+// and if so, queue it and Wake() the task, or if a stanza does not belong
+// to you, return false right away so the next XmppTask can take a crack.
+// This technique (synchronous recognize, but asynchronous processing)
+// allows you to have arbitrary logic for recognizing stanzas yet still,
+// for example, disconnect a client while processing a stanza -
+// without reentrancy problems.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient;
+
+class XmppTask :
+ public Task,
+ public XmppStanzaHandler,
+ public sigslot::has_slots<>
+{
+public:
+ XmppTask(Task * parent, XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
+ virtual ~XmppTask();
+
+ virtual XmppClient * GetClient() const { return client_; }
+ std::string task_id() const { return id_; }
+
+protected:
+ friend class XmppClient;
+
+ XmppReturnStatus SendStanza(const XmlElement * stanza);
+ XmppReturnStatus SetResult(const std::string & code);
+ XmppReturnStatus SendStanzaError(const XmlElement * element_original,
+ XmppStanzaError code,
+ const std::string & text);
+
+ virtual void Stop();
+ virtual bool HandleStanza(const XmlElement * stanza) { return false; }
+ virtual void OnDisconnect();
+ virtual int ProcessReponse() { return STATE_DONE; }
+
+ void QueueStanza(const XmlElement * stanza);
+ const XmlElement * NextStanza();
+
+ bool MatchResponseIq(const XmlElement * stanza, const Jid & to, const std::string & task_id);
+ bool MatchRequestIq(const XmlElement * stanza, const std::string & type, const QName & qn);
+ XmlElement *MakeIqResult(const XmlElement * query);
+ XmlElement *MakeIq(const std::string & type,
+ const Jid & to, const std::string task_id);
+
+private:
+ void StopImpl();
+
+ XmppClient * client_;
+ std::deque<XmlElement *> stanza_queue_;
+ scoped_ptr<XmlElement> next_stanza_;
+ std::string id_;
+
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/voicecaller.h b/kopete/protocols/jabber/jingle/voicecaller.h
new file mode 100644
index 00000000..0f0d18bb
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/voicecaller.h
@@ -0,0 +1,96 @@
+#define PsiAccount JabberAccount
+class PsiAccount;
+
+#ifndef VOICECALLER_H
+#define VOICECALLER_H
+
+#include "im.h"
+
+
+
+
+using namespace XMPP;
+
+/**
+ * \brief An abstract class for a voice call implementation.
+ */
+class VoiceCaller : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * \brief Base constructor.
+ *
+ * \param account the account to which this voice caller belongs
+ */
+ VoiceCaller(PsiAccount* account) : account_(account) { };
+
+ /**
+ * \brief Retrieves the account to which this voice caller belongs.
+ */
+ PsiAccount* account() { return account_; }
+
+ /**
+ * \brief Initializes the voice caller.
+ * This should be called when the connection is open.
+ */
+ virtual void initialize() = 0;
+
+ /**
+ * \brief De-initializes the voice caller.
+ * This should be called when the connection is about to be closed.
+ */
+ virtual void deinitialize() = 0;
+
+ /**
+ * \brief Call the given JID.
+ */
+ virtual void call(const Jid&) = 0;
+
+ /**
+ * \brief Accept a call from the given JID.
+ */
+ virtual void accept(const Jid&) = 0;
+
+ /**
+ * \brief Reject the call from the given JID.
+ */
+ virtual void reject(const Jid&) = 0;
+
+ /**
+ * \brief Terminate the call from the given JID.
+ */
+ virtual void terminate(const Jid&) = 0;
+
+signals:
+ /**
+ * \brief Incoming call from the given JID.
+ */
+ void incoming(const Jid&);
+
+ /**
+ * \brief Contact accepted an incoming call.
+ */
+ void accepted(const Jid&);
+
+ /**
+ * \brief Contact rejected an incoming call.
+ */
+ void rejected(const Jid&);
+
+ /**
+ * \brief Call with given JID is in progress.
+ */
+ void in_progress(const Jid&);
+
+ /**
+ * \brief Call with given JID is terminated.
+ */
+ void terminated(const Jid&);
+
+private:
+ PsiAccount* account_;
+};
+
+#endif