source: qutecom-2.2/libs/sipwrapper/src/phapi/PhApiWrapper.cpp @ 439:5018eafe9395

Last change on this file since 439:5018eafe9395 was 439:5018eafe9395, checked in by Laurent Tarrisse <laurent@…>, 4 years ago

Use contact display name on chat window

File size: 32.5 KB
Line 
1/*
2 * WengoPhone, a voice over Internet phone
3 * Copyright (C) 2004-2007  Wengo
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#include "PhApiWrapper.h"
21
22#include "PhApiCodecList.h"
23
24#include "PhApiSFPWrapper.h"
25
26#include <imwrapper/IMChatSession.h>
27#include <imwrapper/IMContact.h>
28
29#include <cutil/global.h>
30#include <thread/Thread.h>
31#include <thread/Timer.h>
32#include <util/File.h>
33#include <util/Logger.h>
34#include <util/StringList.h>
35
36#include <string>
37
38#include <cstdio>
39
40#include <owpl_log.h>
41
42using namespace std;
43
44const std::string PhApiWrapper::PresenceStateOnline = "online";
45const std::string PhApiWrapper::PresenceStateAway = "away";
46const std::string PhApiWrapper::PresenceStateDoNotDisturb = "do not disturb";
47const std::string PhApiWrapper::PresenceStateBusy = "busy";
48
49PhApiWrapper * PhApiWrapper::PhApiWrapperHack = NULL;
50
51
52#ifdef ENABLE_VIDEO
53static const int VIDEO_FLAGS = OWPL_STREAM_AUDIO | OWPL_STREAM_VIDEO_RX | OWPL_STREAM_VIDEO_TX;
54static const int VIDEO_RX_ONLY_FLAGS = OWPL_STREAM_AUDIO | OWPL_STREAM_VIDEO_RX;
55#else
56static const int VIDEO_FLAGS = OWPL_STREAM_AUDIO;
57static const int VIDEO_RX_ONLY_FLAGS = OWPL_STREAM_AUDIO;
58#endif
59
60#ifdef CC_MSVC
61#define strcasecmp stricmp
62#define strncasecmp strnicmp
63#endif
64
65struct traits_nocase : std::char_traits<char>
66{
67  static bool eq( const char& c1, const char& c2 )
68  { return toupper(c1) == toupper(c2) ; }
69  static bool lt( const char& c1, const char& c2 )
70  { return toupper(c1) < toupper(c2) ; }
71  static int compare( const char* s1, const char* s2, size_t N )
72  {
73    return strncasecmp( s1, s2, N ) ; // posix
74    // mirosoft C++ - use _strnicmp instead
75  }
76  static const char* find( const char* s, size_t N, const char& a )
77  {
78    for( size_t i=0 ; i<N ; ++i )
79      if( toupper(s[i]) == toupper(a) ) return s+i ;
80    return 0 ;
81  }
82  static bool eq_int_type ( const int_type& c1, const int_type& c2 )
83  { return toupper(c1) == toupper(c2) ; }
84};
85
86// string preserves case; comparisons are case insensitive
87typedef std::basic_string< char, traits_nocase > string_nocase ;
88
89
90static void phapiLogFunction(OWPL_LOG_LEVEL level, const char* message) {
91        static const char* component = "PhApi";
92        Logger* logger = Logger::getInstance();
93        switch (level) {
94        case OWPL_LOG_LEVEL_DEBUG:
95                logger->debug(component, "", message);
96                break;
97        case OWPL_LOG_LEVEL_INFO:
98                logger->info(component, "", message);
99                break;
100        case OWPL_LOG_LEVEL_WARN:
101                logger->warn(component, "", message);
102                break;
103        case OWPL_LOG_LEVEL_ERROR:
104                logger->error(component, "", message);
105                break;
106        }
107}
108
109PhApiWrapper::PhApiWrapper(PhApiCallbacks & callbacks)
110        : _phApiSFPWrapper(PhApiSFPWrapper::getInstance()) {
111        _callbacks = &callbacks;
112        _wengoVline = -1;
113        _isInitialized = false;
114        _tunnelNeeded = false;
115        _tunnelPort = 0;
116        _tunnelSSL = false;
117        _natType = EnumNatType::NatTypeUnknown;
118        _sipServerPort = 0;
119        _sipLocalPort = 0;
120        PhApiWrapperHack = this;
121        _registered = false;
122        _mustReinitNetwork = false;
123
124        //FIXME ugly hack for conference
125        phoneCallStateChangedEvent +=
126                boost::bind(&PhApiWrapper::phoneCallStateChangedEventHandler, this, _1, _2, _3, _4);
127
128        owplSetLogFunction(phapiLogFunction);
129
130        sipOptions.sip_register_timeout = 49*60;
131        sipOptions.sip_publish_timeout = 5*60;
132        sipOptions.sip_use_options_request = true;
133        sipOptions.sip_p2p_presence = false;
134        sipOptions.sip_use_typing_state = false;
135
136        const char *sc;
137        if ((sc = getenv("SIP_REGISTER_TIMEOUT")))     
138          sipOptions.sip_register_timeout = atoi(sc);
139
140        if ((sc = getenv("SIP_PUBLISH_TIMEOUT")))     
141          sipOptions.sip_publish_timeout = atoi(sc);
142
143        if ((sc = getenv("SIP_USE_OPTIONS")))     
144          sipOptions.sip_use_options_request = (0 != atoi(sc));
145
146
147        if ((sc = getenv("SIP_USE_TYPING_STATE")))     
148          sipOptions.sip_use_typing_state = (0 != atoi(sc));
149
150        if ((sc = getenv("SIP_P2P_PRESENCE")))     
151          sipOptions.sip_p2p_presence = (0 != atoi(sc));
152
153       
154        if (sipOptions.sip_register_timeout  <= 0)
155          sipOptions.sip_register_timeout = 49 * 60;
156
157        if (sipOptions.sip_publish_timeout <= 0) 
158          sipOptions.sip_publish_timeout = 5 * 60;
159 
160
161        isOnline = false;
162
163}
164
165PhApiWrapper::~PhApiWrapper() {
166        terminate();
167}
168
169void PhApiWrapper::terminate() {
170        if (_isInitialized) {
171                LOG_DEBUG("terminating phapi");
172                owplShutdown();
173                _isInitialized = false;
174        }
175}
176
177
178void PhApiWrapper::setSipOptions(const std::string& opt,  const std::string& value)
179{
180#define NC (string_nocase&)
181
182    if (NC opt == "sip.register_timeout")
183    {
184        sipOptions.sip_register_timeout = atoi(value.c_str());
185        if (sipOptions.sip_register_timeout  <= 0)
186            sipOptions.sip_register_timeout = 49 * 60;
187    }
188    else if (NC opt == "sip.publish_timeout")
189    {
190        sipOptions.sip_publish_timeout = atoi(value.c_str());
191        if (sipOptions.sip_publish_timeout  <= 0)
192            sipOptions.sip_publish_timeout = 5*60;
193    }
194    else if (NC opt == "sip.use_options_request")
195      {
196        sipOptions.sip_use_options_request = (NC value == "true");
197      }
198    else if (NC opt == "sip.use_typing_state")
199      {
200        sipOptions.sip_use_typing_state = (NC value == "true");
201      }
202    else if (NC opt == "sip.p2p_presence")
203      {
204        sipOptions.sip_p2p_presence = (NC value == "true");
205      }
206#undef NC
207}
208
209
210void PhApiWrapper::setNetworkParameter() {
211#if 0 /* phAPI refactoring */
212        int natRefreshTime = 25;
213
214        if (_tunnelNeeded) {
215                if(owplConfigSetLocalHttpProxy(_proxyServer.c_str(), _proxyPort, _proxyLogin.c_str(), _proxyPassword.c_str()) != OWPL_RESULT_SUCCESS) {
216                        // TODO what? throw an exception? exit?
217                }
218                // activate SSL for HTTP tunnel
219                int mask = OWPL_TUNNEL_USE;
220                if(_tunnelSSL) {
221                        mask = mask | OWPL_TUNNEL_SSL;
222                }
223                if(owplConfigSetTunnel(_tunnelServer.c_str(), _tunnelPort, mask) != OWPL_RESULT_SUCCESS) {
224                        // TODO what? throw an exception? exit?
225                }
226
227                owplConfigSetNat(OWPL_NAT_TYPE_FCONE, natRefreshTime);
228
229        } else {
230                switch(_natType) {
231                case EnumNatType::NatTypeOpen:
232                        owplConfigSetNat(OWPL_NAT_TYPE_NONE, 0);
233                        break;
234
235                case EnumNatType::NatTypeFullCone:
236                        owplConfigSetNat(OWPL_NAT_TYPE_FCONE, natRefreshTime);
237                        break;
238
239                case EnumNatType::NatTypeRestrictedCone:
240                        owplConfigSetNat(OWPL_NAT_TYPE_RCONE, natRefreshTime);
241                        break;
242
243                case EnumNatType::NatTypePortRestrictedCone:
244                        owplConfigSetNat(OWPL_NAT_TYPE_PRCONE, natRefreshTime);
245                        break;
246
247                case EnumNatType::NatTypeSymmetric:
248                case EnumNatType::NatTypeSymmetricFirewall:
249                case EnumNatType::NatTypeBlocked:
250                case EnumNatType::NatTypeFailure:
251                case EnumNatType::NatTypeUnknown:
252                        owplConfigSetNat(OWPL_NAT_TYPE_SYMETRIC, natRefreshTime);
253                        break;
254
255                default:
256                        owplConfigSetNat(OWPL_NAT_TYPE_AUTO, natRefreshTime);
257                        LOG_FATAL("unknown NAT type");
258                }
259
260                // in case of change after first initialization
261                owplConfigSetTunnel(NULL, 0, OWPL_TUNNEL_NOT_USED);
262        }
263#endif /* phAPI refactoring */
264
265        if (_tunnelNeeded) {
266                if (owplConfigSetLocalHttpProxy(_proxyServer.c_str(), _proxyPort,
267                        _proxyLogin.c_str(), _proxyPassword.c_str()) != OWPL_RESULT_SUCCESS) {
268                        // TODO what? throw an exception? exit?
269                }
270               
271                owplConfigSetHttpTunnel(_tunnelServer.c_str(), _tunnelPort, 5);
272                owplConfigEnableHttpTunnel(1, _tunnelSSL);
273
274        } else {
275                // in case of change after first initialization
276                owplConfigEnableHttpTunnel(0, 0);
277        }
278}
279
280int PhApiWrapper::addVirtualLine(const std::string & displayName,
281        const std::string & username,
282        const std::string & identity,
283        const std::string & password,
284        const std::string & realm,
285        const std::string & proxyServer,
286        const std::string & registerServer) {
287
288        const int REGISTER_TIMEOUT = sipOptions.sip_register_timeout;
289        OWPL_LINE hLine = -1;
290
291        if (_isInitialized) {
292                std::string tmp = proxyServer;
293                tmp += ":" + String::fromNumber(_sipServerPort);
294
295                if (_mustReinitNetwork) {
296                        owplNetworkReinit(_sipLocalPort, _sipLocalPort, _sipLocalPort + 1);
297                        _mustReinitNetwork = false;
298                }
299
300                if (owplLineAdd(displayName.c_str(), identity.c_str(), registerServer.c_str(), tmp.c_str(), OWPL_TRANSPORT_UDP, REGISTER_TIMEOUT, &hLine) != OWPL_RESULT_SUCCESS) {
301                        LOG_ERROR("owplLineAdd failed");
302                        return SipWrapper::VirtualLineIdError;
303                }
304
305                 
306                if (owplLineAddCredential(hLine, identity.c_str(), password.c_str(), realm.c_str()) != OWPL_RESULT_SUCCESS) {
307                        LOG_ERROR("owplLineAddCredential failed");
308                        return -1; // TODO ?
309                }
310
311                _wengoVline = hLine;
312                _wengoSipAddress = "sip:" + identity + "@" + realm;
313                _wengoRealm = realm;
314
315                //owplLineSetAdapter(hLine, "nortel", NULL, &_wengoVline);
316                if (!sipOptions.sip_use_options_request)
317                       owplLineSetAutoKeepAlive(hLine, 0, 0);
318                else
319                  owplLineSetAutoKeepAlive(hLine, 1, 30);
320        }
321
322        return hLine;
323}
324
325#if _MSC_VER
326#define sleep(s) Sleep(s*1000)
327#endif
328
329int PhApiWrapper::registerVirtualLine(int lineId) {
330        phoneLineStateChangedEvent(*this, lineId, EnumPhoneLineState::PhoneLineStateProgress);
331        int result = owplLineRegister(lineId, 1);
332        if (result != 0) {
333                LOG_ERROR("owplLineRegister failed");
334        }
335        return result;
336}
337
338void PhApiWrapper::removeVirtualLine(int lineId, bool force) {
339        _mustReinitNetwork = force;
340
341        if (_isInitialized) {
342                // Unsubscribre to presence of all contacts
343                std::set<std::string>::iterator it;
344                for (it = getSubscribedContacts().begin();
345                        it != getSubscribedContacts().end();
346                        it = getSubscribedContacts().begin()) {
347                        unsubscribeToPresenceOf(*it);
348                }
349
350                publishOffline(String::null);
351                sleep(2);
352                owplLineDelete(lineId, force);
353
354                //setRegistered(false);
355                //phoneLineStateChangedEvent(*this, lineId, EnumPhoneLineState::PhoneLineStateClosed);
356        }
357       
358        setRegistered(false);
359        phoneLineStateChangedEvent(*this, lineId, EnumPhoneLineState::PhoneLineStateClosed);
360}
361
362int PhApiWrapper::makeCall(int lineId, const std::string & sipAddress, bool enableVideo) {
363        OWPL_CALL hCall;
364
365        LOG_DEBUG("call=" + sipAddress);
366        int mediaFlags = VIDEO_RX_ONLY_FLAGS;
367        if (enableVideo) {
368                mediaFlags = VIDEO_FLAGS;
369        }
370
371        sendMyIcon(sipAddress, _iconFilename);
372
373        if(owplCallCreate(lineId, &hCall) != OWPL_RESULT_SUCCESS) {
374                return -1;
375        }
376        if(owplCallConnect(hCall, sipAddress.c_str(), mediaFlags) != OWPL_RESULT_SUCCESS) {
377                return -1;
378        }
379
380        return hCall;
381}
382
383void PhApiWrapper::sendRingingNotification(int callId, bool enableVideo) {
384        int mediaFlags = VIDEO_RX_ONLY_FLAGS;
385        if (enableVideo) {
386                mediaFlags = VIDEO_FLAGS;
387        }
388
389        owplCallAccept(callId, mediaFlags);
390}
391
392void PhApiWrapper::acceptCall(int callId, bool enableVideo) {
393        int mediaFlags = VIDEO_RX_ONLY_FLAGS;
394        if (enableVideo) {
395                mediaFlags = VIDEO_FLAGS;
396        }
397
398        owplCallAnswer(callId, mediaFlags);
399}
400
401void PhApiWrapper::rejectCall(int callId) {
402        owplCallReject(callId, 486, NULL);
403}
404
405void PhApiWrapper::closeCall(int callId) {
406        if (owplCallDisconnect(callId) != OWPL_RESULT_SUCCESS) {
407                LOG_ERROR("cannot close this PhoneCall");
408        }
409}
410
411void PhApiWrapper::holdCall(int callId) {
412        owplCallHold(callId);
413}
414
415void PhApiWrapper::resumeCall(int callId) {
416        owplCallUnhold(callId);
417}
418
419void PhApiWrapper::blindTransfer(int callId, const std::string & sipAddress) {
420        phBlindTransferCall(callId, sipAddress.c_str());
421}
422
423void PhApiWrapper::playDtmf(int callId, char dtmf) {
424        phSendDtmf(callId, dtmf, 3);
425}
426
427void PhApiWrapper::playSoundFile(int callId, const std::string & soundFile) {
428        phSendSoundFile(callId, soundFile.c_str());
429}
430
431CodecList::AudioCodec PhApiWrapper::getAudioCodecUsed(int callId) {
432        static const int LENGTH = 255;
433        static char audioCodec[LENGTH];
434        static char videoCodec[LENGTH];
435
436        phCallGetCodecs(callId, audioCodec, LENGTH, videoCodec, LENGTH);
437        String tmp(audioCodec);
438        if (tmp.contains(PhApiCodecList::AUDIO_CODEC_PCMU)) {
439                return CodecList::AudioCodecPCMU;
440        }
441        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_PCMA)) {
442                return CodecList::AudioCodecPCMA;
443        }
444        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_G722)) {
445                return CodecList::AudioCodecG722;
446        }
447    else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_G726)) {
448                return CodecList::AudioCodecG726;
449        }
450        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_ILBC)) {
451                return CodecList::AudioCodecILBC;
452        }
453        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_GSM)) {
454                return CodecList::AudioCodecGSM;
455        }
456        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_AMRNB)) {
457                return CodecList::AudioCodecAMRNB;
458        }
459        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_AMRWB)) {
460                return CodecList::AudioCodecAMRWB;
461        }
462        else if (tmp.contains(PhApiCodecList::AUDIO_CODEC_SPEEXWB)) {
463                return CodecList::AudioCodecSPEEXWB;
464        }
465        else if (tmp.empty()) {
466                return CodecList::AudioCodecError;
467        }
468        else {
469                LOG_WARN("unknown codec=" + tmp);
470                return CodecList::AudioCodecError;
471        }
472}
473
474CodecList::VideoCodec PhApiWrapper::getVideoCodecUsed(int callId) {
475        static const int LENGTH = 255;
476        static char audioCodec[LENGTH];
477        static char videoCodec[LENGTH];
478
479        phCallGetCodecs(callId, audioCodec, LENGTH, videoCodec, LENGTH);
480        String tmp(videoCodec);
481        if (tmp.contains(PhApiCodecList::VIDEO_CODEC_H263)) {
482                return CodecList::VideoCodecH263;
483        }
484        else if (tmp.contains(PhApiCodecList::VIDEO_CODEC_H264)) {
485                return CodecList::VideoCodecH264;
486        }
487        else if (tmp.contains(PhApiCodecList::VIDEO_CODEC_MPEG4)) {
488                return CodecList::VideoCodecMPEG4;
489        }
490        else if (tmp.empty()) {
491                return CodecList::VideoCodecError;
492        }
493        else {
494                LOG_WARN("unknown codec=" + tmp);
495                return CodecList::VideoCodecError;
496        }
497}
498
499bool PhApiWrapper::setCallInputAudioDevice(const AudioDevice & device) {
500        _inputAudioDevice = device;
501        return setAudioDevices();
502}
503
504bool PhApiWrapper::setRingerOutputAudioDevice(const AudioDevice & device) {
505        return false;
506}
507
508bool PhApiWrapper::setCallOutputAudioDevice(const AudioDevice & device) {
509        _outputAudioDevice = device;
510        return setAudioDevices();
511}
512
513bool PhApiWrapper::setAudioDevices() {
514        static const std::string OUTPUT_DEVICE_TAG  = "OUT=";
515        std::string devices;
516
517#ifdef OS_MACOSX
518        static const std::string INPUT_DEVICE_TAG = "ca:IN=";
519        devices = INPUT_DEVICE_TAG
520                + _inputAudioDevice.getData().toString(":")
521                + std::string(" ") + OUTPUT_DEVICE_TAG
522                + _outputAudioDevice.getData().toString(":");
523#else
524#if defined(OWSOUND_PORTAUDIO_SUPPORT)
525        static const std::string INPUT_DEVICE_TAG = "pa:IN=";
526        devices = INPUT_DEVICE_TAG
527                + _inputAudioDevice.getData()[1]
528                + std::string(" ") + OUTPUT_DEVICE_TAG
529                + _outputAudioDevice.getData()[1];
530#else
531        static const std::string INPUT_DEVICE_TAG = "alsa:IN=";
532        devices = INPUT_DEVICE_TAG
533                + _inputAudioDevice.getData()[1]
534                + std::string(" ") + OUTPUT_DEVICE_TAG
535                + _outputAudioDevice.getData()[1];
536#endif
537#endif
538
539        int ret = phChangeAudioDevices(devices.c_str());
540        if (ret == 0) {
541                //Ok
542                return true;
543        }
544        return false;
545}
546
547void PhApiWrapper::enableAEC(bool enable) {
548        if (enable) {
549                phcfg.noaec = 0;
550                LOG_DEBUG("AEC enabled");
551        } else {
552                phcfg.noaec = 1;
553                LOG_DEBUG("AEC disabled");
554        }
555}
556
557void PhApiWrapper::enableHalfDuplex(bool enable) {
558        if (enable) {
559                //Half duplex (mode where speaker signal has priority over microphone signal)
560                phcfg.hdxmode = PH_HDX_MODE_SPK;
561                LOG_DEBUG("half-duplex enabled");
562        } else {
563                phcfg.hdxmode = 0;
564                LOG_DEBUG("half-duplex disabled");
565        }
566}
567
568void PhApiWrapper::enablePIM(bool enable) {
569        owplConfigEnablePIM(enable);
570}
571
572/*
573 * IM API implementation
574 */
575
576void PhApiWrapper::connect() {
577        if (isRegistered())
578                connectedEvent(*this);
579}
580
581void PhApiWrapper::disconnect(bool force) {
582        removeVirtualLine(_wengoVline, force);
583        disconnectedEvent(*this, false, String::null);
584}
585
586void PhApiWrapper::sendMessage(IMChatSession & chatSession, const std::string & message) {
587        const IMContactSet & buddies = chatSession.getIMContactSet();
588        IMContactSet::const_iterator it;
589        int messageId = -1;
590
591        for (it = buddies.begin(); it != buddies.end(); it++) {
592                std::string sipAddress = makeSipAddress((*it).getContactId());
593
594                owplMessageSend(_wengoVline,
595                                        sipAddress.c_str(),
596                                        message.c_str(),
597                                        "text/html; charset=utf-8",
598                                        &messageId);
599        }
600}
601
602void PhApiWrapper::changeTypingState(IMChatSession & chatSession, IMChat::TypingState state) {
603        const IMContactSet & buddies = chatSession.getIMContactSet();
604        IMContactSet::const_iterator it;
605        int messageId = -1;
606
607        if (!sipOptions.sip_use_typing_state)
608          return;
609
610        for (it = buddies.begin(); it != buddies.end(); it++) {
611                std::string sipAddress = makeSipAddress((*it).getContactId());
612
613                switch (state) {
614                        case IMChat::TypingStateTyping :
615                                owplMessageSendTypingState(_wengoVline,
616                                        sipAddress.c_str(),
617                                        OWPL_TYPING_STATE_TYPING,
618                                        &messageId);
619                                break;
620
621                        case IMChat::TypingStateStopTyping :
622                                owplMessageSendTypingState(_wengoVline,
623                                        sipAddress.c_str(),
624                                        OWPL_TYPING_STATE_STOP_TYPING,
625                                        &messageId);
626                                break;
627
628                        default :
629                                owplMessageSendTypingState(_wengoVline,
630                                        sipAddress.c_str(),
631                                        OWPL_TYPING_STATE_NOT_TYPING,
632                                        &messageId);
633                                break;
634                }
635        }
636}
637
638void PhApiWrapper::createSession(IMChat & imChat, const IMContactSet & imContactSet) {
639        Mutex::ScopedLock lock(_mutex);
640
641        // PhApi supports only one person per chat session
642        if (imContactSet.size() == 1) {
643                IMChatSession *imChatSession = NULL;
644                // Check if a session already exists with the given contact
645                const IMContact & imContact = *imContactSet.begin();
646                if (_contactChatMap.find(imContact.getContactId()) != _contactChatMap.end()) {
647                        //A Session with this contact already exists
648                        imChatSession = _contactChatMap[imContact.getContactId()];
649                } else {
650                        imChatSession = new IMChatSession(imChat, true);
651                        addContact(*imChatSession, (*imContactSet.begin()).getContactId(),"");
652                }
653
654                newIMChatSessionCreatedEvent(*this, *imChatSession);
655                sendMyIcon((*imContactSet.begin()).getContactId(), _iconFilename);
656        } else {
657                LOG_ERROR("More than one peer in IMContactSet");
658        }
659}
660
661void PhApiWrapper::closeSession(IMChatSession & sender) {
662        Mutex::ScopedLock lock(_mutex);
663
664        std::map<const std::string, IMChatSession *>::iterator it =
665                _contactChatMap.find((*sender.getIMContactSet().begin()).getContactId());
666
667        if (it != _contactChatMap.end()) {
668                _contactChatMap.erase(it);
669        } else {
670                LOG_ERROR("Session not registered");
671        }
672}
673
674void PhApiWrapper::addContact(IMChatSession & chatSession, const std::string & contactId,  const std::string & alias) {
675        // PhApi supports only one person per chat session
676        _contactChatMap[contactId] = &chatSession;
677        contactAddedEvent(*this, chatSession, contactId, alias);
678}
679
680void PhApiWrapper::removeContact(IMChatSession & chatSession, const std::string & contactId) {
681        contactRemovedEvent(*this, chatSession, contactId);
682}
683
684void PhApiWrapper::changeMyPresence(EnumPresenceState::PresenceState state, const std::string & note) {
685        switch(state) {
686        case EnumPresenceState::PresenceStateOnline:
687                publishOnline(PresenceStateOnline);
688                break;
689
690        case EnumPresenceState::PresenceStateAway:
691                publishOnline(PresenceStateAway);
692                break;
693
694        case EnumPresenceState::PresenceStateDoNotDisturb:
695                publishOnline(PresenceStateDoNotDisturb);
696                break;
697
698        case EnumPresenceState::PresenceStateUserDefined:
699                if (!sipOptions.sip_p2p_presence)
700                  publishOnline(note);
701                break;
702
703        case EnumPresenceState::PresenceStateInvisible:
704        case EnumPresenceState::PresenceStateOffline:
705                publishOffline(note);
706                break;
707
708        case EnumPresenceState::PresenceStateUnknown:
709                myPresenceStatusEvent(*this, EnumPresenceState::MyPresenceStatusError, note);
710                break;
711
712        default:
713                LOG_FATAL("unknown presence state=" + String::fromNumber(state));
714        }
715}
716
717void PhApiWrapper::sendMyIcon(const std::string & contactId, const std::string & iconFilename) {
718        int messageId = -1;
719
720        if (iconFilename.empty()) {
721                return;
722        }
723
724        std::string sipAddress = makeSipAddress(contactId);
725        owplMessageSendIcon(_wengoVline,
726                sipAddress.c_str(),
727                iconFilename.c_str(),
728                &messageId);
729}
730
731void PhApiWrapper::publishOnline(const std::string & note) {
732        if (_isInitialized) {
733                publishPresence(true, note);
734        }
735}
736
737void PhApiWrapper::publishOffline(const std::string & note) {
738        if (_isInitialized) {
739                publishPresence(false, note);
740        }
741}
742
743void PhApiWrapper::publishPresence(bool online, const std::string & note) {
744        static const std::string contentType = "application/pidf+xml";
745
746        if (_isInitialized) {
747          isOnline = online;
748          presence_note = note;
749
750          if (sipOptions.sip_p2p_presence)
751            {
752              for (InSubIter isub = _incomingSubscriptions.begin(); isub != _incomingSubscriptions.end(); isub++)
753                if (isub->second.state == SUBCONFIRMED)
754                  owplPresenceNotify(_wengoVline, isub->first, (online)?1:0, note.c_str(), 0);
755             
756              myPresenceStatusEvent(*this, EnumPresenceState::MyPresenceStatusOk, note);
757
758            }
759          else  if(owplPresencePublish(_wengoVline, (online)?1:0, note.c_str(), NULL) != OWPL_RESULT_SUCCESS) {
760                        myPresenceStatusEvent(*this, EnumPresenceState::MyPresenceStatusError, note);
761                } else {
762                        myPresenceStatusEvent(*this, EnumPresenceState::MyPresenceStatusOk, note);
763                }
764        }
765}
766
767void PhApiWrapper::handleIncomingSubscribe(int sid, const char* from, const char* evtType)
768{
769
770  if (from)
771    {
772      std::string ctct = parseFromHeader(from);
773
774      InSub sub = { SUBPENDING, ctct, evtType ? evtType : "" };
775      {
776        Mutex::ScopedLock lock(_mutex);
777
778        _incomingSubscriptions[sid] = sub;
779
780        if (_subscribedContacts.find(ctct) != _subscribedContacts.end())
781          subscribeToPresenceOf(ctct);
782           
783      }
784     
785
786      incomingSubscribeEvent(*this, sid, sub.from, sub.evt);
787    }
788
789}
790
791void PhApiWrapper::terminateIncomingSubscribe(int sid)
792{
793   Mutex::ScopedLock lock(_mutex);
794
795  _incomingSubscriptions.erase(sid);
796
797}
798
799void PhApiWrapper::acceptSubscription(int sid)
800{
801  {
802   Mutex::ScopedLock lock(_mutex);
803
804   _incomingSubscriptions[sid].state = SUBCONFIRMED;
805  }
806
807  // FIXME:  will not work in multiline mode
808  owplSubscribeAccept(_wengoVline, sid, 202, (int) isOnline , presence_note.c_str());
809
810 
811}
812
813void PhApiWrapper::rejectSubscription(int sid)
814{
815  // FIXME:  will not work in multiline mode
816  owplSubscribeReject(_wengoVline, sid, 480);
817  terminateIncomingSubscribe(sid);
818
819}
820
821
822
823
824void PhApiWrapper::subscribeToPresenceOf(const std::string & contactId) {
825        OWPL_SUB hSub;
826        std::string sipAddress = makeSipAddress(contactId);
827
828        if(owplPresenceSubscribe(_wengoVline, sipAddress.c_str(), 0, &hSub) != OWPL_RESULT_SUCCESS) {
829                subscribeStatusEvent(*this, sipAddress, IMPresence::SubscribeStatusError);
830        } else {
831                getSubscribedContacts().insert(contactId);
832                subscribeStatusEvent(*this, sipAddress, IMPresence::SubscribeStatusOk);
833        }
834}
835
836void PhApiWrapper::unsubscribeToPresenceOf(const std::string & contactId) {
837        std::string sipAddress = makeSipAddress(contactId);
838
839        owplPresenceUnsubscribeFromUri(_wengoVline, sipAddress.c_str());
840       
841        std::set<std::string>::iterator it;
842        it = getSubscribedContacts().find(contactId);
843        if (it != getSubscribedContacts().end()) {
844                getSubscribedContacts().erase(it);
845        }
846}
847
848void PhApiWrapper::allowWatcher(const std::string & watcher) {
849        /*
850        static const int winfo = 1;     //Publish with event = presence.winfo
851        static const std::string contentType = "application/watcherinfo+xml";
852
853        std::string winfoAllow = "<?xml version=\"1.0\"?>\n";
854        winfoAllow += "<watcherinfo>\n";
855        winfoAllow += "<watcher-list>\n";
856        winfoAllow += "<watcher status=\"active\">";
857        winfoAllow += watcher;
858        winfoAllow += "</watcher>\n";
859        winfoAllow += "</watcher-list>\n";
860        winfoAllow += "</watcherinfo>\n";
861
862        phLinePublish(_wengoVline, _wengoSipAddress.c_str(), winfo, contentType.c_str(), winfoAllow.c_str());
863        */
864        // TODO REFACTOR
865        // owplPresencePublishAllowed(...);
866}
867
868void PhApiWrapper::forbidWatcher(const std::string & watcher) {
869        /*
870        static const int winfo = 1;     //Publish with event = presence.winfo
871        static const std::string contentType = "application/watcherinfo+xml";
872
873        std::string winfoForbid = "<?xml version=\"1.0\"?>\n";
874        winfoForbid += "<watcherinfo>\n";
875        winfoForbid += "<watcher-list>\n";
876        winfoForbid += "<watcher status=\"pending\">";
877        winfoForbid += watcher;
878        winfoForbid += "</watcher>\n";
879        winfoForbid += "</watcher-list>\n";
880        winfoForbid += "</watcherinfo>\n";
881
882        phLinePublish(_wengoVline, _wengoSipAddress.c_str(), winfo, contentType.c_str(), winfoForbid.c_str());
883        */
884        // TODO REFACTOR
885        // owplPresencePublishAllowed(...);
886}
887
888void PhApiWrapper::blockContact(const std::string & contactId) {
889        std::string sipAddress = makeSipAddress(contactId);
890        allowWatcher(sipAddress);
891}
892
893void PhApiWrapper::unblockContact(const std::string & contactId) {
894        std::string sipAddress = makeSipAddress(contactId);
895        allowWatcher(sipAddress);
896}
897
898void PhApiWrapper::setProxy(const std::string & address, unsigned port,
899        const std::string & login, const std::string & password) {
900
901        _proxyServer = address;
902        _proxyPort = port;
903        _proxyLogin = login;
904        _proxyPassword = password;
905}
906
907void PhApiWrapper::setTunnel(const std::string & address, unsigned port, bool ssl) {
908        _tunnelNeeded = true;
909        _tunnelServer = address;
910        _tunnelPort = port;
911        _tunnelSSL = ssl;
912}
913
914void PhApiWrapper::setNatType(EnumNatType::NatType natType) {
915        _natType = natType;
916}
917
918void PhApiWrapper::setVideoQuality(EnumVideoQuality::VideoQuality videoQuality) {
919#ifdef ENABLE_VIDEO
920        phVideoControlSetWebcamCaptureResolution(320, 240);
921#endif
922
923        switch(videoQuality) {
924        case EnumVideoQuality::VideoQualityNormal:
925                phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_128KBPS;
926                break;
927
928        case EnumVideoQuality::VideoQualityGood:
929                phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_256KBPS;
930                break;
931
932        case EnumVideoQuality::VideoQualityVeryGood:
933                phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_512KBPS;
934                break;
935
936        case EnumVideoQuality::VideoQualityExcellent:
937                phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_1024KBPS;
938                break;
939
940        default:
941                LOG_FATAL("unknown video quality=" + String::fromNumber(videoQuality));
942        }
943}
944
945void PhApiWrapper::setSIP(const string & server, unsigned serverPort, unsigned localPort) {
946        _sipServer = server;
947        _sipServerPort = serverPort;
948        _sipLocalPort = localPort;
949}
950
951
952/*
953** Conference Algorithm **
954
955int callId1 = placeCall();
956//wait for CALLOK on callId1
957phHold(callId1);
958int callId2 = placeCall();
959//wait for CALLOK on callId2
960phHold(callId2);
961phConf(callId1, callId2);
962phResume(callId1);
963phResume(callId2);
964phStopConf(callId1, callId2);
965
966*/
967
968static int callId1 = SipWrapper::CallIdError;
969static int callId2 = SipWrapper::CallIdError;
970
971int PhApiWrapper::createConference() {
972        //FIXME return phConfCreate();
973
974        return 1;
975}
976
977void PhApiWrapper::phoneCallStateChangedEventHandler(SipWrapper & sender, int callId,
978        EnumPhoneCallState::PhoneCallState state, const std::string & from) {
979
980        if (callId == callId1 &&
981                (state == EnumPhoneCallState::PhoneCallStateClosed ||
982                state == EnumPhoneCallState::PhoneCallStateError)) {
983
984                callId1 = SipWrapper::CallIdError;
985        }
986
987        else if (callId == callId2 &&
988                (state == EnumPhoneCallState::PhoneCallStateClosed ||
989                state == EnumPhoneCallState::PhoneCallStateError)) {
990
991                callId2 = SipWrapper::CallIdError;
992        }
993}
994
995void PhApiWrapper::joinConference(int confId, int callId) {
996        //FIXME phConfAddMember(confId, callId);
997
998        if (callId1 == SipWrapper::CallIdError) {
999                callId1 = callId;
1000        }
1001
1002        else if (callId2 == SipWrapper::CallIdError) {
1003                callId2 = callId;
1004        }
1005
1006        if (callId1 != SipWrapper::CallIdError && callId2 != SipWrapper::CallIdError) {
1007                //Thread::sleep(5);
1008                phConf(callId1, callId2);
1009                LOG_DEBUG("conference call started");
1010                resumeCall(callId1);
1011                resumeCall(callId2);
1012        }
1013}
1014
1015void PhApiWrapper::splitConference(int confId, int callId) {
1016        //FIXME phConfRemoveMember(confId, callId);
1017
1018        //FIXME phConfClose(confId);
1019        if (callId1 != SipWrapper::CallIdError && callId2 != SipWrapper::CallIdError) {
1020                phStopConf(callId1, callId2);
1021                callId1 = SipWrapper::CallIdError;
1022                callId2 = SipWrapper::CallIdError;
1023                LOG_DEBUG("conference call destroyed");
1024        }
1025}
1026
1027void PhApiWrapper::setAudioCodecList(const StringList & audioCodecList) {
1028        owplConfigSetAudioCodecs(audioCodecList.toString(",").c_str());
1029}
1030
1031void PhApiWrapper::init() {
1032        setNetworkParameter();
1033
1034        //Plugin path
1035        strncpy(phcfg.plugin_path, _pluginPath.c_str(), sizeof(phcfg.plugin_path));
1036
1037        /* Codec list *
1038        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_SPEEXWB.c_str());
1039        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_ILBC.c_str());
1040        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_AMRWB.c_str());
1041        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_PCMU.c_str());
1042        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_G722.c_str());
1043    owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_G726.c_str());
1044        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_PCMA.c_str());
1045        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_AMRNB.c_str());
1046        owplConfigAddAudioCodecByName(PhApiCodecList::AUDIO_CODEC_GSM.c_str());
1047        owplConfigAddVideoCodecByName(PhApiCodecList::VIDEO_CODEC_H263.c_str());
1048        */
1049
1050#ifdef ENABLE_VIDEO
1051        // default webcam capture size must be initialized to avoid a 0x0 size
1052        phVideoControlSetWebcamCaptureResolution(320, 240);
1053        owplConfigAddVideoCodecByName(PhApiCodecList::VIDEO_CODEC_H263.c_str());
1054#endif
1055
1056        _callbacks->startListeningPhApiEvents();
1057
1058        if(owplInit(1, _sipLocalPort, _sipLocalPort, _sipLocalPort + 1, NULL, 0) == OWPL_RESULT_SUCCESS) {
1059                _isInitialized = true;
1060                LOG_DEBUG("phApi successfully initialized");
1061        } else {
1062                _isInitialized = false;
1063                LOG_ERROR("cannot initialize phApi");
1064        }
1065}
1066
1067void PhApiWrapper::setPluginPath(const string & path) {
1068        _pluginPath = path;
1069}
1070
1071std::string PhApiWrapper::phapiCallStateToString(enum phCallStateEvent event) {
1072        std::string toReturn;
1073        switch(event) {
1074        case phDIALING:
1075                toReturn = "phDIALING";
1076                break;
1077        case phRINGING:
1078                toReturn = "phRINGING";
1079                break;
1080        case phNOANSWER:
1081                toReturn = "phNOANSWER";
1082                break;
1083        case phCALLBUSY:
1084                toReturn = "phCALLBUSY";
1085                break;
1086        case phCALLREDIRECTED:
1087                toReturn = "phCALLREDIRECTED";
1088                break;
1089        case phCALLOK:
1090                toReturn = "phCALLOK";
1091                break;
1092        case phCALLHELD:
1093                toReturn = "phCALLHELD";
1094                break;
1095        case phCALLRESUMED:
1096                toReturn = "phCALLRESUMED";
1097                break;
1098        case phHOLDOK:
1099                toReturn = "phHOLDOK";
1100                break;
1101        case phRESUMEOK:
1102                toReturn = "phRESUMEOK";
1103                break;
1104        case phINCALL:
1105                toReturn = "phINCALL";
1106                break;
1107        case phCALLCLOSED:
1108                toReturn = "phCALLCLOSED";
1109                break;
1110        case phCALLERROR:
1111                toReturn = "phCALLERROR";
1112                break;
1113        case phDTMF:
1114                toReturn = "phDTMF";
1115                break;
1116        case phXFERPROGRESS:
1117                toReturn = "phXFERPROGRESS";
1118                break;
1119        case phXFEROK:
1120                toReturn = "phXFEROK";
1121                break;
1122        case phXFERFAIL:
1123                toReturn = "phXFERFAIL";
1124                break;
1125        case phXFERREQ:
1126                toReturn = "phXFERREQ";
1127                break;
1128        case phCALLREPLACED:
1129                toReturn = "phCALLREPLACED";
1130                break;
1131        case phRINGandSTART:
1132                toReturn = "phRINGandSTART";
1133                break;
1134        case phRINGandSTOP:
1135                toReturn = "phRINGandSTOP";
1136                break;
1137        case phCALLCLOSEDandSTOPRING:
1138                toReturn = "phCALLCLOSEDandSTOPRING";
1139                break;
1140        default:
1141                LOG_FATAL("unknown phapi state=" + String::fromNumber(event));
1142        }
1143        return toReturn;
1144}
1145
1146void PhApiWrapper::setVideoDevice(const std::string & deviceName) {
1147        strncpy(phcfg.video_config.video_device, deviceName.c_str(), sizeof(phcfg.video_config.video_device));
1148}
1149
1150void PhApiWrapper::flipVideoImage(bool flip) {
1151#ifdef ENABLE_VIDEO
1152        phVideoControlSetCameraFlip((int)flip);
1153#endif
1154}
1155
1156std::string PhApiWrapper::makeSipAddress(const std::string & contactId) {
1157        std::string sipAddress;
1158        const string_nocase& ncid = (const string_nocase& ) contactId;
1159
1160        if (ncid.compare(0, 4, "sip:") != 0) {
1161                sipAddress = "sip:" + contactId;
1162        } else {
1163                sipAddress = contactId;
1164        }
1165
1166        if (ncid.find('@') == ncid.npos) {
1167                sipAddress += "@" + _wengoRealm;
1168        }
1169
1170        return sipAddress;
1171}
1172
1173void PhApiWrapper::setCallsEncryption(bool enable) {
1174        owplConfigSetEncryptionMode((int)enable);
1175}
1176
1177bool PhApiWrapper::isCallEncrypted(int callId) {
1178        int result;
1179        owplCallGetEncryptionMode(callId, &result);
1180        LOG_DEBUG("Call with callId " + String::fromNumber(callId)
1181                + " has encryption mode " + String::fromNumber(result));
1182
1183        return result == 0 ? false : true ;
1184}
1185
1186bool PhApiWrapper::isInitialized() {
1187        return _isInitialized;
1188}
1189
1190std::string PhApiWrapper::parseFromHeader(const std::string & sipFrom) {
1191  const string_nocase& uri = (const string_nocase&) sipFrom;
1192  int beginOfSipUri = uri.find("<sip:") + 5;
1193  int endOfSipUri = uri.find(">");
1194  string_nocase from = uri.substr(beginOfSipUri, endOfSipUri - beginOfSipUri);
1195
1196  return (std::string &)from;
1197}
1198
1199std::string PhApiWrapper::getDisplayNameFromHeader(const std::string & sipFrom) {
1200        const string_nocase& uri = (const string_nocase&) sipFrom;
1201        int beginOfSipUri = uri.find("\"") + 1;
1202        int endOfSipUri = uri.find("\" <");
1203        string_nocase display_name = uri.substr(beginOfSipUri, endOfSipUri - beginOfSipUri);
1204       
1205        return (std::string &)display_name;
1206}
1207
1208IMChatSession *PhApiWrapper::getIMChatSession(const std::string & from) const {
1209        Mutex::ScopedLock lock(_mutex);
1210
1211        IMChatSession *result = NULL;
1212
1213        std::map<const std::string, IMChatSession *>::const_iterator it = _contactChatMap.find(from);
1214        if (it != _contactChatMap.end()) {
1215                result = (*it).second;
1216        }
1217
1218        return result;
1219}
Note: See TracBrowser for help on using the repository browser.