source: qutecom-2.2/wifo/phapi/phapi-old.c @ 425:f1929a89802a

Last change on this file since 425:f1929a89802a was 425:f1929a89802a, checked in by vadim@…, 4 years ago

fixes for enchanced fmtp support

File size: 103.8 KB
Line 
1/*
2* phapi   phone api
3*
4* Copyright (C) 2006        WENGO SAS
5* Copyright (C) 2004        Vadim Lebedev <vadim@mbdsys.com>
6*
7* This is free software; you can redistribute it and/or modify
8* it under the terms of the GNU General Public License as
9* published by the Free Software F undation; either version 2,
10* or (at your option) any later version.
11*
12* This is distributed in the hope that it will be useful, but
13* WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15* GNU General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with dpkg; if not, write to the Free Software
19* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/**
23* @file phapi.c
24* @brief softphone  API
25*
26* phapi is a library providing simplified api to create VOIP sessions
27* using eXosip library oSIP stack and oRTP stcak
28* <P>
29*/
30#ifdef WIN32
31#include <winsock2.h>
32#endif /* WIN32 */
33#include <eXosip/eXosip.h>
34#include <phapi-old.h>
35#include <phglobal.h>
36#include <phvline.h>
37#include <phevents.h>
38#include <phrpc.h>
39#include <phmedia.h>
40#include <phcall.h>
41
42#include <phlog.h>
43
44#include <owpl_log.h>
45#include <owpl_plugin.h>
46#include <svoip_phapi.h>
47
48#include <../src/eXosip2.h>
49
50#include <phapi-util/util.h>
51#include "phcodec.h"
52
53#include <pthread.h>
54
55/*
56#define G711_ONLY
57*/
58
59#define SKIP(x)
60
61#ifdef PHAPI_VIDEO_SUPPORT
62#include <avcodec.h>
63#include <webcam/webcam.h>
64#endif
65
66#include <osip2/osip_mt.h>
67#include <osipparser2/headers/osip_from.h>
68#include <eXosip/eXosip.h>
69#include <eXosip/eXosip_cfg.h>
70
71
72#ifdef OS_WINDOWS
73#include <winsock2.h>
74#endif
75#include <stdio.h>
76#include <string.h>
77#include <stdlib.h>
78#include <sys/stat.h>
79#include <sys/types.h>
80#include <errno.h>
81#include <limits.h>
82#include <ctype.h>
83#include <assert.h>
84#include <time.h>
85
86#ifndef OS_WINDOWS
87//#include "config.h"
88#include <sys/wait.h>
89#include <unistd.h>
90#include <dirent.h>
91#ifndef OS_MACOSX
92#include <sys/soundcard.h>
93#endif
94#include <sys/ioctl.h>
95#include <fcntl.h>
96#else  /* WIN32 */
97#define snprintf _snprintf
98#define strncasecmp strnicmp
99#define strcasecmp stricmp
100#define usleep(usecs) Sleep((usecs)/1000)
101#endif
102
103
104void ph_wegot_dtmf(void  *ctx, int dtmfEvent);
105static int ph_event_get();
106
107/**
108 * Processes an event from eXosip as an SDP event
109 *
110 * @param       je      an eXosip event
111 * @return      0 on success; negative value on failure
112 */
113static int ph_process_call_event_default(eXosip_event_t * je);
114
115#define MEDIA_SUSPEND
116
117#ifndef PH_STREAM_AUDIO
118#define PH_STREAM_AUDIO (1 << 0)
119#define PH_STREAM_VIDEO_RX (1 << 1)
120#define PH_STREAM_VIDEO_TX (1 << 2)
121#endif
122
123#define PH_STREAM_CNG (1 << 30)
124
125static int ph_call_retrieve_payloads(phcall_t *ca, eXosip_event_t *je, int flags);
126static int ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int resumeflag);
127static void ph_call_media_stop(phcall_t * ca);
128static int ph_call_media_suspend(phcall_t *ca, int localhold);
129void ph_release_call(phcall_t *ca);
130int ph_call_hasaudio(phcall_t *ca);
131
132int phWaitTimeout = 500;
133
134static void  _get_local_video_sdp_port(char buf[]);
135static void  _get_local_audio_sdp_port(char buf[]);
136
137void ph_message_progress(eXosip_event_t *je);
138static void ph_keep_refreshing();
139/*static*/ void  ph_call_requestfailure(eXosip_event_t *je);
140
141static void ph_frame_display_cbk(void *ctx, void *event);
142
143#define nonempty(x)  ((x) && (x)[0])
144
145static void
146ph_build_cname(char *buf, int n, phVLine *vl);
147
148
149//int phvlRegister(int vlid);
150//static phVLine *vline_alloc();
151//static void vline_free(phVLine *vl);
152//#define PHM_IGNORE_PORT 1
153//#define PHM_IGNORE_HOST 2
154//static phVLine *ph_find_matching_vline(const char *userid, int ignore);
155//static phVLine *ph_find_matching_vline2(const char *username, const char* host, int ignore);
156//static phVLine *ph_find_matching_vline3(const char *username, const char* host, int port, int ignore);
157//static phVLine *ph_find_vline_by_rid(int rid);
158
159static char *ph_get_proxy(const char *from);
160static int   ph_get_vline_id(const char *userid, const char *altid);
161
162// mutex for ph_release_call
163pthread_mutex_t  ph_media_stop_mutex;
164#define PH_MSESSION_STOP_LOCK() pthread_mutex_lock(&ph_media_stop_mutex)
165#define PH_MSESSION_STOP_UNLOCK() pthread_mutex_unlock(&ph_media_stop_mutex)
166////
167
168int getPublicPort(char *local_voice_port, char *local_video_port, char *public_voice_port, char *public_video_port);
169
170#define clear(x) memset(&x, 0, sizeof(x))
171
172phCallbacks_t *phcb;
173int phIsInitialized;
174int phDebugLevel = 0;
175char *phLogFileName = 0;
176
177unsigned short phCallBackPort = PH_CALLBACK_PORT;
178unsigned short phServerPort = PH_SERVER_PORT;
179
180static FILE *ph_log_file;
181
182#define ph_printf printf
183void * ph_api_thread(void *arg);
184
185static void ph_update_media_payloads_packetization_info(
186                osip_list_t *local_format_modifiers, struct ph_mstream_params_s* msp, 
187                int in_call_ptime)
188{
189        int payloadIndex;
190        int fmtpModifIndex;
191        char* format_modifier = NULL;
192        char payload_id[10];
193       
194        if (!msp)
195        {
196                return;
197        }
198       
199        for (payloadIndex = 0; payloadIndex < PH_MSTREAM_PARAMS_MAX_PAYLOADS; payloadIndex++)
200        {
201                if (msp->opayloads[payloadIndex].string[0] != '\0')
202                {
203                        memset(payload_id, 0, 10);
204                        snprintf(payload_id, 10, "%d", msp->opayloads[payloadIndex].number);
205                       
206                        if (local_format_modifiers)
207                        {
208                                for (fmtpModifIndex = 0; 
209                                                !osip_list_eol(local_format_modifiers, fmtpModifIndex); fmtpModifIndex++)
210                                {
211                                        format_modifier = (char*)osip_list_get(local_format_modifiers, fmtpModifIndex);
212                                       
213                                        if ( (strstr(format_modifier, payload_id) == format_modifier) && 
214                                                        (format_modifier[strlen(payload_id)] == ' ') )
215                                        {
216                                                msp->opayloads[payloadIndex].fmtp = osip_strdup(format_modifier);
217                                                msp->ipayloads[payloadIndex].fmtp = osip_strdup(format_modifier);
218                                               
219                                                break;
220                                        }
221                                }
222                        }
223                       
224                        if (msp->ptime != 0)
225                        {
226                                msp->opayloads[payloadIndex].ptime = msp->ptime;
227                                msp->ipayloads[payloadIndex].ptime = in_call_ptime;
228                        }
229                }
230        }
231}
232
233static const char* skip_payload_nr(const char *fmtp)
234{
235  while(*fmtp && isdigit(*fmtp))
236    *fmtp++;
237
238  while(*fmtp && *fmtp != ' ')
239    *fmtp++;
240
241  return fmtp;
242}
243
244
245#define name(x) #x
246
247static char *evtnames[] =
248{
249        name(EXOSIP_REGISTRATION_NEW),              /* announce new registration.       */
250        name(EXOSIP_REGISTRATION_SUCCESS),          /* user is successfully registred.  */
251        name(EXOSIP_REGISTRATION_FAILURE),          /* user is not registred.           */
252        name(EXOSIP_REGISTRATION_REFRESHED),        /* registration has been refreshed. */
253        name(EXOSIP_REGISTRATION_TERMINATED),       /* UA is not registred any more.    */
254
255        /* for UAC events */
256        name(EXOSIP_CALL_NOANSWER),        /* announce no answer within the phWaitTimeout */
257        name(EXOSIP_CALL_PROCEEDING),      /* announce processing by a remote app   */
258        name(EXOSIP_CALL_RINGING),         /* announce ringback                     */
259        name(EXOSIP_CALL_ANSWERED),        /* announce start of call                */
260        name(EXOSIP_CALL_REDIRECTED),      /* announce a redirection                */
261        name(EXOSIP_CALL_REQUESTFAILURE),  /* announce a request failure            */
262        name(EXOSIP_CALL_SERVERFAILURE),   /* announce a server failure             */
263        name(EXOSIP_CALL_GLOBALFAILURE),   /* announce a global failure             */
264
265        /* for UAS events */
266        name(EXOSIP_CALL_NEW),             /* announce a new call                   */
267        name(EXOSIP_CALL_ACK),             /* ACK received for 200ok to INVITE      */
268        name(EXOSIP_CALL_CANCELLED),       /* announce that call has been cancelled */
269        name(EXOSIP_CALL_TIMEOUT),         /* announce that call has failed         */
270        name(EXOSIP_CALL_HOLD),            /* audio must be stopped                 */
271        name(EXOSIP_CALL_OFFHOLD),         /* audio must be restarted               */
272        name(EXOSIP_CALL_CLOSED),          /* a BYE was received for this call      */
273
274        /* for both UAS & UAC events */
275        name(EXOSIP_CALL_STARTAUDIO),         /* audio must be established           */
276        name(EXOSIP_CALL_RELEASED),           /* call context is cleared.            */
277
278        /* for UAC events */
279        name(EXOSIP_OPTIONS_NOANSWER),        /* announce no answer within the phWaitTimeout */
280        name(EXOSIP_OPTIONS_PROCEEDING),      /* announce processing by a remote app   */
281        name(EXOSIP_OPTIONS_ANSWERED),        /* announce a 200ok                      */
282        name(EXOSIP_OPTIONS_REDIRECTED),      /* announce a redirection                */
283        name(EXOSIP_OPTIONS_REQUESTFAILURE),  /* announce a request failure            */
284        name(EXOSIP_OPTIONS_SERVERFAILURE),   /* announce a server failure             */
285        name(EXOSIP_OPTIONS_GLOBALFAILURE),   /* announce a global failure             */
286
287        name(EXOSIP_INFO_NOANSWER),        /* announce no answer within the phWaitTimeout */
288        name(EXOSIP_INFO_PROCEEDING),      /* announce processing by a remote app   */
289        name(EXOSIP_INFO_ANSWERED),        /* announce a 200ok                      */
290        name(EXOSIP_INFO_REDIRECTED),      /* announce a redirection                */
291        name(EXOSIP_INFO_REQUESTFAILURE),  /* announce a request failure            */
292        name(EXOSIP_INFO_SERVERFAILURE),   /* announce a server failure             */
293        name(EXOSIP_INFO_GLOBALFAILURE),   /* announce a global failure             */
294
295        /* for UAS events */
296        name(EXOSIP_OPTIONS_NEW),             /* announce a new options method         */
297        name(EXOSIP_INFO_NEW),               /* new info request received           */
298
299        name(EXOSIP_MESSAGE_NEW),            /* announce new incoming MESSAGE. */
300        name(EXOSIP_MESSAGE_SUCCESS),        /* announce a 200ok to a previous sent */
301        name(EXOSIP_MESSAGE_FAILURE),        /* announce a failure. */
302
303
304        /* Presence and Instant Messaging */
305        name(EXOSIP_SUBSCRIPTION_NEW),          /* announce new incoming SUBSCRIBE.  */
306        name(EXOSIP_SUBSCRIPTION_UPDATE),       /* announce incoming SUBSCRIBE.      */
307        name(EXOSIP_SUBSCRIPTION_CLOSED),       /* announce end of subscription.     */
308
309        name(EXOSIP_SUBSCRIPTION_NOANSWER),        /* announce no answer              */
310        name(EXOSIP_SUBSCRIPTION_PROCEEDING),      /* announce a 1xx                  */
311        name(EXOSIP_SUBSCRIPTION_ANSWERED),        /* announce a 200ok                */
312        name(EXOSIP_SUBSCRIPTION_REDIRECTED),      /* announce a redirection          */
313        name(EXOSIP_SUBSCRIPTION_REQUESTFAILURE),  /* announce a request failure      */
314        name(EXOSIP_SUBSCRIPTION_SERVERFAILURE),   /* announce a server failure       */
315        name(EXOSIP_SUBSCRIPTION_GLOBALFAILURE),   /* announce a global failure       */
316        name(EXOSIP_SUBSCRIPTION_NOTIFY),          /* announce new NOTIFY request     */
317
318        name(EXOSIP_SUBSCRIPTION_RELEASED),        /* call context is cleared.        */
319
320        name(EXOSIP_IN_SUBSCRIPTION_NEW),          /* announce new incoming SUBSCRIBE.*/
321        name(EXOSIP_IN_SUBSCRIPTION_RELEASED),     /* announce end of subscription.   */
322
323        name(EXOSIP_CALL_REFERED),              /* announce incoming REFER           */
324        name(EXOSIP_CALL_REFER_STATUS),         /* announce incoming NOTIFY          */
325        name(EXOSIP_CALL_REFER_FAILURE),         /* announce error during refer */
326
327        name(EXOSIP_CALL_REPLACES)         /* announce incoming INVITE with Rpelaces    */
328
329};
330
331#undef name
332
333
334
335phcall_t ph_calls[PH_MAX_CALLS];
336
337
338/*
339//#define FORCE_VAD   1
340#define FORCE_CNG   1
341*/
342
343
344
345
346phConfig_t *phGetConfig()
347{
348        return &phcfg;
349}
350
351
352
353
354
355
356#ifdef EMBED
357phConfig_t phcfg = {"10600", "",
358/* sipport  */ 5060,5062,5061,
359/* identity */ "",
360/* codecs */   "" ,
3610 ,0 ,
362/* audio_dev */   "" ,
363/* softboost */ 0,0,0,
364/* vad */ 0,0,0,
3650,0,0,
3660
367};
368#else
369phConfig_t phcfg = {
370        /* rtp, rtcp ports */ "10600", "", "10700", "",
371        /* identity */ "",
372        /* codecs */ "" ,"",
373        /* asyncmode */ 0,
374        /* audio_dev */ "",
375        /* softboost */ 0, 0, 0,
376        /* vad */ 0, 0, 0, 0, 0,
377        0, 0, 0,
378#ifdef WIN32
379        /* videoHandle */ 0,
380#endif
381        /* video_config */ {0, 0, 0, 0, 0, 0, 0, 0, ""},
382        /* plugin_path */ ""
383};
384
385#endif
386
387static int _is_video_enabled(int streams)
388{
389        return (streams & (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX));
390}
391
392
393static int _is_audio_enabled(int streams)
394{
395        return (streams & PH_STREAM_AUDIO);
396}
397
398
399static int
400ph_port_inuse(int port)
401{
402        int i;
403        phcall_t *ca;
404
405        /* scan all active calls and check that the given port is inuse */
406        for(i=0; i<PH_MAX_CALLS;  i++)
407        {
408                ca = &ph_calls[i];
409                if (ca->cid != -1)
410                {
411                        /* active call */
412                        if(ca->local_sdp_audio_port == port || port == ca->local_sdp_video_port)
413                        {
414                                return 1;
415                        }
416                }
417        }
418
419        return 0;
420}
421
422static void
423_get_local_audio_sdp_port(char buf[])
424{
425
426        /* <MINHPQ>
427        * To get arround the problem of connect in winsock ( connect returns
428        * an error: 10048: Address already in use connect is called an the local address is in used
429        * within the last 2 or 4 minutes), we should not bind the rtp socket to a specific local port. Hence,
430        * we should return "0" here to let the system choose a random port number.
431        */
432
433        /* base port number*/
434        int port = atoi(phcfg.local_rtp_port);
435
436        buf[0] = 0;
437
438        while(1)
439        {
440                if (!ph_port_inuse(port))
441                {
442                        sprintf(buf, "%d", port);
443                        return;
444                }
445                else
446                {
447                        port += 2;    /* try next pair */
448                }
449        }
450}
451
452static void
453_get_local_video_sdp_port(char buf[])
454{
455        int port = atoi(phcfg.local_video_rtp_port) + 2;
456
457        buf[0] = 0;
458
459        while(1)
460        {
461                if (!ph_port_inuse(port))
462                {
463                        sprintf(buf, "%d", port);
464                        return;
465                }
466                else
467                {
468                        port += 2;    /* try next pair */
469                }
470        }
471}
472
473
474phcall_t *
475ph_locate_call_by_cid(int cid)
476{
477        phcall_t *ca;
478
479
480        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
481        {
482                if (ca->cid == cid)
483                {
484                        return ca;
485                }
486        }
487
488        return 0;
489}
490
491#if 0
492void phReleaseTerminatedCalls()
493{
494        phcall_t *ca;
495        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
496        {
497                if ((ca->cid != -1) && (ph_media_is_stream_stopped(ca) == 1))
498                {
499                        ph_release_call(ca);
500                }
501        }
502}
503#endif
504
505phcall_t *
506ph_locate_call_by_rcid(int cid)
507{
508        phcall_t *ca;
509
510
511        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
512        {
513                if (ca->rcid == cid)
514                {
515                        return ca;
516                }
517        }
518
519        return 0;
520}
521
522phcall_t *
523ph_locate_call_by_rdid(int did)
524{
525        phcall_t *ca;
526
527
528        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
529        {
530                if (ca->rdid == did)
531                {
532                        return ca;
533                }
534        }
535
536        return 0;
537}
538
539
540phcall_t *
541ph_allocate_call(int cid)
542{
543        phcall_t *ca = ph_locate_call_by_cid(-1);
544
545        if (!ca)
546        {
547                return 0;
548        }
549
550        ca->redirs = 0;
551        ca->cid = cid;
552        return ca;
553}
554
555
556
557phcall_t *
558ph_locate_call(eXosip_event_t *je, int creatit)
559{
560        phcall_t *ca, *found = 0, *newca = 0;
561
562        /* lookup matching call descriptor */
563        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
564        {
565                // locate first non-used pre-allocated phcall_t
566                if (ca->cid == -1 && !newca)
567                {
568                        newca = ca;
569                }
570
571                if (ca->extern_cid == je->cid)
572                {
573                        found  = ca;
574                        break;
575                }
576        }
577
578        ca = found;
579
580        if (!ca)   /* we didn't find a matching call descriptor */
581        {
582                if (creatit)
583                {
584                        /* allocate a new one */
585                        if (!newca)
586                        {
587                                return 0; /* !!! BUG !!! */
588                        }
589                        ca = newca;
590                        memset(ca, 0, sizeof(*ca));
591                        ca->cid = getNextCallId();
592                        ca->extern_cid = je->cid;
593                        ca->did = je->did;
594                        ca->vlid = ph_vline2vlid(ph_find_vline_by_rid(je->rid));
595                }
596        }
597
598        if (!ca)
599        {
600                return 0;
601        }
602
603        if (je->remote_sdp_audio_ip[0])
604        {
605                strncpy(ca->remote_sdp_audio_ip, je->remote_sdp_audio_ip, sizeof(ca->remote_sdp_audio_ip));
606                ca->remote_sdp_audio_port = je->remote_sdp_audio_port;
607                strncpy(ca->audio_payload_name, je->payload_name, sizeof(ca->audio_payload_name));
608                ca->audio_payload = je->payload;
609        }
610
611        if (je->remote_sdp_video_ip[0])
612        {
613                strncpy(ca->remote_sdp_video_ip, je->remote_sdp_video_ip, sizeof(ca->remote_sdp_video_ip));
614                ca->remote_sdp_video_port = je->remote_sdp_video_port;
615                strncpy(ca->video_payload_name, je->video_payload_name, sizeof(ca->video_payload_name));
616                ca->video_payload = je->video_payload;
617        }
618
619        return ca;
620}
621
622phcall_t *
623ph_locate_call_by_remote_uri(char *remote_uri)
624{
625        phcall_t *ca;
626
627        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
628        {
629                if(ca->remote_uri)
630                {
631                        if (!strncmp(ca->remote_uri, remote_uri, strlen(remote_uri)))
632                        {
633                                return ca;
634                        }
635                }
636        }
637
638        return 0;
639}
640
641
642void ph_release_call(phcall_t *ca)
643{
644        DBG_SIP_NEGO("SIP_NEGO: ph_release_call start\n");
645        PH_MSESSION_STOP_LOCK();
646
647        ph_call_media_stop(ca);
648        ph_clear_msession_streams_fmtps(ca->mses);
649
650        if (ca->remote_uri) {
651                free(ca->remote_uri);
652        }
653        memset(ca, 0, sizeof(phcall_t));
654        ca->cid = -1;
655        ca->extern_cid = -1;
656        PH_MSESSION_STOP_UNLOCK();
657}
658
659// <ncouturier>
660/**
661* Releases a SIP call (notion of audio is here inexistant)
662*/
663void ph_release_call2(phcall_t *ca){
664        DBG_SIP_NEGO("SIP_NEGO: ph_release_call2 start\n");
665
666        memset(ca, 0, sizeof(phcall_t));
667        ca->cid = -1;
668        ca->extern_cid = -1;
669}
670// </ncouturier>
671
672int ph_has_active_calls()
673{
674        phcall_t *ca;
675        int count = 0;
676
677        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
678        {
679                if (ca->cid != -1 && ca->extern_cid != -1 && ph_call_hasaudio(ca))
680                {
681                        if (!ca->remotehold && !ca->localhold)
682                        {
683                                count++;
684                        }
685                }
686        }
687        return count;
688}
689
690/**
691* @brief does the call have an active audio session stream ?
692*/
693int ph_call_hasaudio(phcall_t *ca)
694{
695        if (ca->mses && (ca->mses->activestreams & (1 << PH_MSTREAM_AUDIO1)))
696        {
697                return 1;
698        }
699        return 0;
700}
701
702void ph_stream_ended(void *ctx, int event)
703{
704        phcall_t *ca = (phcall_t *)ctx;
705
706        ca->closereq = 1;
707}
708
709void ph_wegot_dtmf(void *ctx, int dtmfEvent)
710{
711        phCallStateInfo_t info;
712        phcall_t *ca = (phcall_t *)ctx;
713
714        clear(info);
715
716        info.event = phDTMF;
717        info.u.dtmfDigit = dtmfEvent;
718        info.vlid = ca->vlid;
719        if (phcb->callProgress) {
720                phcb->callProgress(ca->cid, &info);
721        }
722
723        owplFireCallEvent2(ca->cid,
724                CALLSTATE_AUDIO_EVENT,
725                CALLSTATE_AUDIO_DTMF,
726                ca->remote_uri,
727                dtmfEvent,
728                0, /* No additional data */
729                0  /* no associated call*/
730                );
731
732
733}
734
735void ph_frame_display_cbk(void *ctx, void *event)
736{
737        phcall_t *ca = (phcall_t *) ctx;
738
739        if (phcb->onFrameReady) {
740                phcb->onFrameReady(ca->cid, (phVideoFrameReceivedEvent_t*)event);
741        }
742        owplFireCallEvent2(ca->cid,
743                CALLSTATE_VIDEO_EVENT,
744                CALLSTATE_VIDEO_FRAME_RCV,
745                ca->remote_uri,
746                0,
747                event,
748                0
749                );
750}
751
752
753
754
755
756int ph_same_str(const char *str1, const char *str2)
757{
758        if (str1 == 0)
759        {
760                return str2 == 0;
761        }
762
763        if (str2 == 0)
764        {
765                return str1 == 0;
766        }
767
768        return (0 == strcasecmp(str1, str2));
769}
770
771int ph_same_uri(const char *uristr1, const char *uristr2)
772{
773        osip_contact_t *uri1, *uri2;
774        int ret;
775
776        osip_contact_init(&uri1);
777        osip_contact_init(&uri2);
778
779        osip_contact_parse(uri1, uristr1);
780        osip_contact_parse(uri2, uristr2);
781
782        /* if we've got and invalid URI return TRUE */
783        if (!uri1 || !uri2 || !uri1->url || !uri2->url)
784        {
785                ret = 1;
786        }
787        else
788        {
789                ret = ph_same_str(uri1->url->username, uri2->url->username) &&
790                        ph_same_str(uri1->url->host, uri2->url->host) &&
791                        ph_same_str(uri1->url->port, uri2->url->port);
792        }
793
794        osip_contact_free(uri1);
795        osip_contact_free(uri2);
796
797        return ret;
798}
799
800int ph_from_user_domain(char *buf, int bufsize, const char * uri )
801{
802        osip_from_t * uri_struct ;
803
804        if (uri == NULL)
805        {
806                return 0 ;
807        }
808
809        if (osip_from_init (& uri_struct))
810        {
811                return 0 ;
812        }
813
814        if (osip_from_parse (uri_struct, uri))
815        {
816                osip_from_free (uri_struct) ;
817                return 0 ;
818        }
819        snprintf(buf, bufsize, "sip:%s@%s", uri_struct->url->username, uri_struct->url->host);
820        return 1;
821}
822
823int
824phGetVersion()
825{
826        static char version[] = PHAPI_VERSION;
827        char *subv = strstr(version, ".");
828        int v,s,r;
829
830        v = atoi(version);
831        s = atoi(subv+1);
832        r = atoi(strstr(subv+1, ".")+1);
833
834        return (v << 16) | (s << 8) | r;
835}
836#undef stringize
837
838
839int
840phGetAudioVersion()
841{
842#if !defined(WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__)
843        int fd, ret=-1;
844#ifndef EMBED
845        fd = open("/dev/dsp", O_RDWR, O_NONBLOCK);
846#else
847        fd = open("/dev/sound/mixer0", O_RDWR, O_NONBLOCK);
848#endif
849        if (fd>=0)
850        {
851#if defined(EMBED)
852                if(0>ioctl(fd, SOUND_MIXER_PRIVATE5, &ret))
853#else
854                if(0>ioctl(fd, OSS_GETVERSION, &ret))
855#endif
856                {
857                        ret = -1;
858                }
859                close(fd);
860        }
861        return ret;
862#else
863        return 0;
864#endif
865}
866
867static void
868ph_build_cname(char *buf, int n, phVLine *vl)
869{
870        char * vl_un, * vl_s, * un, * s;
871        assert(buf);
872        assert(vl);
873
874        vl_un = owsip_account_user_get (vl->sipAccount) ;
875        vl_s = owsip_account_domain_get (vl->sipAccount) ;
876        un = nonempty(vl_un) ? vl_un : "unknown";
877        s = nonempty(vl_s) ? vl_s : "localhost";
878
879        snprintf(buf, n, "%s@%s", un, s);
880}
881
882#define optional(x) (x[0] ? x : 0)
883
884int
885phLinePlaceCall_withCa(int vlid, const char *uri, void *userdata, int rcid, int streams, phcall_t *ca0)
886{
887        int i;
888        osip_message_t *invite;
889        phcall_t *ca = 0;
890        char *proxy ;
891        phVLine *vl;
892        char from[512];
893        char  local_voice_port[16];
894        char  local_video_port[16];
895
896        //streams = PH_STREAM_AUDIO;
897        DBG_SIP_NEGO("phLinePlaceCall_withCa start\n");
898
899        local_video_port[0] = 0;
900        local_voice_port[0] = 0;
901
902        if (!nonempty(uri))
903        {
904                return -PH_BADARG;
905        }
906
907        vl = ph_valid_vlid(vlid);
908
909        if (!vl)
910        {
911                return -PH_BADVLID;
912        }
913
914        if (rcid) {
915                ca = ph_locate_call_by_cid(rcid);
916                if (!ca)
917                {
918                        return -PH_BADCID;
919                }
920        }
921
922        ph_vline_get_from(from, sizeof(from), vl);
923
924        proxy = owsip_account_proxy_get (vl->sipAccount) ;
925
926        i = eXosip_build_initial_invite(&invite,
927                (char *) uri,
928                from,
929                proxy,
930                "");
931        if (i!=0)
932        {
933                return -1;
934        }
935
936        if (_is_video_enabled(streams))
937        {
938                _get_local_video_sdp_port(local_video_port);
939        }
940
941        _get_local_audio_sdp_port(local_voice_port);
942
943        eXosip_lock();
944        DBG_SIP_NEGO("NO STUN ports (a.local=%s, a.public=%s) (v.local=%s, v.public=%s)\n",local_voice_port,0,local_video_port,0);
945        i = eXosip_initiate_call(vl->sipAccount, invite, userdata, NULL, local_voice_port, optional(local_video_port),  0, 0);
946
947        if (!ca0) {
948                int newCallId = getNextCallId();
949                ca0 = ph_allocate_call(newCallId);
950                ca0->extern_cid = i;
951        }
952        else {
953                if (ca0->cid < 0) {
954                        ca0->cid = getNextCallId();
955                }
956                ca0->extern_cid = i;
957        }
958
959
960        ca0->local_sdp_audio_port = atoi(local_voice_port);
961        if (_is_video_enabled(streams))
962        {
963                ca0->local_sdp_video_port = atoi(local_video_port);
964        }
965
966        ca0->waitaccept = 1;
967
968        ca0->user_mflags = streams;
969        ca0->nego_mflags = ca0->user_mflags;
970
971        if (rcid)
972        {
973                ca0->rcid = rcid;
974        }
975
976        ca0->vlid = ph_vline2vlid(vl);
977        ca0->remote_uri = strdup(uri);
978
979        eXosip_unlock();
980
981        owplFireCallEvent(ca0->cid,
982                CALLSTATE_REMOTE_OFFERING,
983                CALLSTATE_REMOTE_OFFERING_NORMAL,
984                uri,
985                0);
986
987        return ca0->cid;
988}
989
990
991int
992phLinePlaceCall(int vlid, const char *uri, void *userdata, int rcid)
993{
994        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, PH_STREAM_AUDIO, 0);
995}
996
997int
998phLinePlaceCall2(int vlid, const char *uri, void *userdata, int rcid, int streams)
999{
1000        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0);
1001}
1002
1003#if 0 // not used
1004int
1005phLineSendMessage(int vlid, const char *uri, const char *buff, const char *mime)
1006{
1007        int i;
1008        phVLine *vl;
1009        char from[512];
1010
1011        vl = ph_valid_vlid(vlid);
1012        if (!vl)
1013        {
1014                return -PH_BADVLID;
1015        }
1016
1017        ph_vline_get_from(from, sizeof(from), vl);
1018
1019        if ( !nonempty(uri))
1020        {
1021                return -PH_BADARG;
1022        }
1023
1024        eXosip_lock();
1025        i = eXosip_message((char *)uri, from, vl->proxy, (char *)buff, (char *)mime);
1026        eXosip_unlock();
1027        return i;
1028}
1029
1030int
1031phSendMessage(const char *from, const char *uri,
1032                          const char *buff, const char *mime)
1033{
1034        int i;
1035
1036        if (!nonempty(from) || !nonempty(uri))
1037        {
1038                return -PH_BADARG;
1039        }
1040
1041        eXosip_lock();
1042        i = eXosip_message((char *)uri, (char*) from, ph_get_proxy(from),
1043                (char *)buff, (char *)mime);
1044        eXosip_unlock();
1045        return i;
1046}
1047
1048
1049int
1050phLineSubscribe(int vlid, const char *uri, const int winfo)
1051{
1052        int i;
1053        phVLine *vl;
1054        char from[512];
1055
1056
1057        vl = ph_valid_vlid(vlid);
1058
1059        if (!vl)
1060        {
1061                return -PH_BADVLID;
1062        }
1063
1064        ph_vline_get_from(from, sizeof(from), vl);
1065
1066
1067        if ( !nonempty(uri))
1068        {
1069                return -PH_BADARG;
1070        }
1071
1072
1073        eXosip_lock();
1074        i = eXosip_subscribe(vl->sipAccount, (char *)uri, from, vl->proxy, winfo);
1075        eXosip_unlock();
1076        if (i < 0) {
1077                return -1;
1078        }
1079        return 0;
1080}
1081
1082int
1083phSubscribe(const char *from, const char *to, const int winfo)
1084{
1085        int i;
1086
1087        if (!nonempty(to) || !nonempty(from))
1088        {
1089                return -PH_BADARG;
1090        }
1091
1092        eXosip_lock();
1093        /* TODO: get account */
1094        i = eXosip_subscribe(0, (char *)to, (char *)from, ph_get_proxy(from), winfo);
1095        eXosip_unlock();
1096        if (i < 0) {
1097                return -1;
1098        }
1099        return 0;
1100}
1101
1102int
1103phLinePublish(int vlid, const char *uri, const int winfo, const char * content_type, const char * content)
1104{
1105        int i;
1106        phVLine *vl;
1107        char from[512];
1108
1109
1110        vl = ph_valid_vlid(vlid);
1111
1112        if (!vl)
1113        {
1114                return -PH_BADVLID;
1115        }
1116
1117        ph_vline_get_from(from, sizeof(from), vl);
1118
1119
1120        if ( !nonempty(uri))
1121        {
1122                return -PH_BADARG;
1123        }
1124
1125
1126        eXosip_lock();
1127        i = eXosip_publish((char *)uri, from, vl->proxy, winfo, content_type,content);
1128        eXosip_unlock();
1129        return i;
1130}
1131
1132
1133int
1134phPublish(const char *from, const char *to, const int winfo, const char * content_type, const char * content)
1135{
1136        int i;
1137
1138        if (!nonempty(to) || !nonempty(from) || !nonempty(content_type) || !nonempty(content))
1139        {
1140                return -PH_BADARG;
1141        }
1142
1143
1144        i = eXosip_publish((char *)to, (char *)from, ph_get_proxy(from), winfo, content_type,content);
1145        eXosip_unlock();
1146        return i;
1147}
1148#endif // not used
1149
1150void
1151phRefresh()
1152{
1153        if (!phIsInitialized)
1154        {
1155                return;
1156        }
1157        eXosip_lock();
1158        eXosip_update();
1159        eXosip_unlock();
1160}
1161
1162
1163int
1164phLineSendOptions(int vlid, const char *to)
1165{
1166        int i;
1167        phVLine *vl;
1168        char from[512];
1169
1170        if (!nonempty(to))
1171        {
1172                return -PH_BADARG;
1173        }
1174
1175        vl = ph_valid_vlid(vlid);
1176        if (!vl)
1177        {
1178                return -PH_BADVLID;
1179        }
1180
1181        ph_vline_get_from(from, sizeof(from), vl);
1182
1183        eXosip_lock();
1184        i = eXosip_options(vl->sipAccount, (char *)to, from, owsip_account_proxy_get (vl->sipAccount));
1185        eXosip_unlock();
1186        return i;
1187}
1188
1189int
1190phSendOptions(int vlid, const char *from, const char *uri)
1191{
1192        int i;
1193        phVLine *vl;
1194
1195        if (!nonempty(from) || !nonempty(uri))
1196        {
1197                return -PH_BADARG;
1198        }
1199
1200        vl = ph_valid_vlid(vlid);
1201        if (!vl)
1202        {
1203                return -PH_BADVLID;
1204        }
1205
1206        eXosip_lock();
1207        i = eXosip_options(vl->sipAccount, (char *)uri, (char*) from, owsip_account_proxy_get (vl->sipAccount));
1208        eXosip_unlock();
1209        return i;
1210}
1211
1212
1213int
1214phAcceptCall2(int cid, void *userData)
1215{
1216        return phAcceptCall3(cid, userData, PH_STREAM_AUDIO);
1217}
1218
1219
1220int
1221phAcceptCall3(int cid, void *userData, int streams)
1222{
1223        int i;
1224        phcall_t *ca = ph_locate_call_by_cid(cid);
1225        phCallStateInfo_t info;
1226        char *remoteUri = 0;
1227        char  local_video_port[16];
1228        char  local_voice_port[16];
1229
1230        local_video_port[0] = 0;
1231        local_voice_port[0] = 0;
1232
1233        //streams = PH_STREAM_AUDIO;
1234        DBG_SIP_NEGO("SIP NEGO: phAcceptCall3\n");
1235        if (!ca) {
1236                return -PH_BADCID;
1237        }
1238
1239        ca->user_mflags = streams; // trace of what the user decided
1240        ca->nego_mflags = ca->user_mflags; // current negociated media flags
1241
1242        if (_is_video_enabled(streams))
1243        {
1244                _get_local_video_sdp_port(local_video_port);
1245        }
1246
1247        _get_local_audio_sdp_port(local_voice_port);
1248
1249    eXosip_lock();
1250    DBG_SIP_NEGO("NO STUN ports (a.local=%s, a.public=%s) (v.local=%s, v.public=%s)\n",local_voice_port,0,local_video_port,0);
1251    i = eXosip_answer_call(ca->did, 200, local_voice_port, optional(local_video_port), 0, 0, NULL);
1252
1253        if (i == 0)
1254        {
1255                i = ph_call_retrieve_payloads(ca, NULL, streams | PH_STREAM_CNG );
1256
1257                ca->local_sdp_audio_port = atoi(local_voice_port);
1258                if (_is_video_enabled(streams))
1259                {
1260                        ca->local_sdp_video_port = atoi(local_video_port);
1261                }
1262
1263        }
1264
1265        eXosip_unlock();
1266
1267        if (!i)
1268        {
1269                i = ph_call_media_start(ca, NULL, 0);
1270        }
1271
1272        if (i)
1273        {
1274                return i;
1275        }
1276
1277
1278
1279        eXosip_lock();
1280        eXosip_retrieve_from(ca->did, &remoteUri);
1281        eXosip_unlock();
1282
1283        clear(info);
1284
1285        info.u.remoteUri = remoteUri;
1286        info.event = phCALLOK;
1287
1288        if (phcb->callProgress) {
1289                phcb->callProgress(cid, &info);
1290        }
1291
1292        // Fire the call connected event
1293        owplFireCallEvent(cid,
1294                CALLSTATE_CONNECTED,
1295                CALLSTATE_CONNECTED_ACTIVE,
1296                remoteUri,
1297                0);
1298
1299        if (remoteUri)
1300        {
1301                osip_free(remoteUri);
1302        }
1303
1304        return 0;
1305}
1306
1307
1308int
1309ph_answer_request_with_contact(int did, int reason, char* answer_contact)
1310{
1311        int i;
1312
1313        eXosip_lock();
1314        i = eXosip_answer_call(did, reason, 0, 0, 0, 0, answer_contact);
1315        eXosip_unlock();
1316
1317        return i;
1318}
1319
1320
1321int
1322ph_answer_request(int did, int reason)
1323{
1324        return ph_answer_request_with_contact(did, reason, NULL);
1325}
1326
1327
1328int
1329phRejectCall(int cid, int reason)
1330{
1331        int i;
1332        phcall_t *ca = ph_locate_call_by_cid(cid);
1333        phCallStateInfo_t info;
1334
1335        if (!ca)
1336        {
1337                return -PH_BADCID;
1338        }
1339
1340        i = ph_answer_request(ca->did, reason);
1341
1342        clear(info);
1343        info.event = phCALLCLOSED;
1344        if (phcb->callProgress) {
1345                phcb->callProgress(cid, &info);
1346        }
1347        owplFireCallEvent(cid,
1348                CALLSTATE_DISCONNECTED,
1349                CALLSTATE_DISCONNECTED_NORMAL,
1350                ca->remote_uri,
1351                0);
1352
1353        DBG_SIP_NEGO("release calls");
1354        ph_release_call(ca);
1355
1356        return i;
1357
1358}
1359
1360
1361int
1362phRingingCall(int cid)
1363{
1364        int i;
1365        phcall_t *ca = ph_locate_call_by_cid(cid);
1366
1367        if (!ca)
1368        {
1369                return -PH_BADCID;
1370        }
1371
1372        i = ph_answer_request(ca->did, 180);
1373
1374        owplFireCallEvent(cid,
1375                CALLSTATE_ALERTING,
1376                CALLSTATE_ALERTING_NORMAL,
1377                ca->remote_uri,
1378                0);
1379
1380        return i;
1381
1382}
1383
1384
1385
1386int
1387phCloseCall(int cid)
1388{
1389        int i;
1390        phcall_t *ca = ph_locate_call_by_cid(cid);
1391        phCallStateInfo_t info;
1392        int did;
1393        int extern_cid = -1;
1394
1395        DBG_SIP_NEGO("phCloseCall %d\n", cid);
1396        clear(info);
1397        info.event = phCALLCLOSED;
1398
1399        if (!ca)
1400        {
1401                return -PH_BADCID;
1402        }
1403
1404        if (ca->isringing)
1405        {
1406                info.event = phCALLCLOSEDandSTOPRING;
1407                ca->isringing = 0;
1408        }
1409
1410
1411        info.vlid = ca->vlid;
1412        did = ca->did;
1413        extern_cid = ca->extern_cid;
1414
1415        eXosip_lock();
1416        i = eXosip_terminate_call(extern_cid, did);
1417        eXosip_unlock();
1418
1419        if (i)
1420        {
1421                return i;
1422        }
1423
1424        info.userData = 0;
1425
1426        info.u.errorCode = 0;
1427        if (phcb->callProgress) {
1428                phcb->callProgress(cid, &info);
1429        }
1430
1431        owplFireCallEvent(cid,
1432                CALLSTATE_DISCONNECTED,
1433                CALLSTATE_DISCONNECTED_NORMAL,
1434                ca->remote_uri,
1435                0);
1436
1437        DBG_SIP_NEGO("release calls");
1438        ph_release_call(ca);
1439
1440        return i;
1441}
1442
1443int
1444phBlindTransferCall(int cid, const char *uri)
1445{
1446        int i;
1447        phcall_t *ca = ph_locate_call_by_cid(cid);
1448
1449        if (!ca)
1450        {
1451                return -PH_BADCID;
1452        }
1453
1454        if (!nonempty(uri))
1455        {
1456                return -PH_BADARG;
1457        }
1458
1459        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
1460        {
1461                return -PH_REDIRLOOP;
1462        }
1463
1464
1465        ca->localrefer = 1;
1466        phHoldCall(cid);
1467
1468        eXosip_lock();
1469        i = eXosip_transfer_call(ca->did, (char *)uri);
1470        eXosip_unlock();
1471
1472        return i;
1473
1474}
1475
1476
1477int
1478phAcceptSubscribe(int vlid, int did, int reason, int online, const char* note)
1479{
1480        int i;
1481        int ss_status = EXOSIP_SUBCRSTATE_ACTIVE;
1482        int ss_reason = 0;
1483
1484        if (!(reason < 300 && reason >= 200))
1485          {
1486            ss_status = EXOSIP_SUBCRSTATE_TERMINATED;
1487            ss_reason = REJECTED;
1488          }
1489
1490
1491        eXosip_lock();
1492        i = eXosip_notify_accept_subscribe(did, reason);
1493        eXosip_unlock();
1494        if (i)
1495          return i;
1496
1497        usleep(50*1000); /* FIXME: hack to provoke thread switch to allow eXosip_execute to send out 200 ok */
1498        if (ss_status == EXOSIP_SUBCRSTATE_ACTIVE)
1499          {
1500           
1501            owplPresenceNotify(vlid, did, online, note, 0);
1502#if 0
1503            eXosip_lock();
1504            i = eXosip_notify(did, ss_status, ss_reason);
1505            eXosip_unlock();
1506#endif
1507          }
1508        return i;
1509
1510}
1511
1512
1513#if 0 /* not used */
1514int
1515phTransferCall(int cid, int tcid)
1516{
1517        phcall_t *ca = ph_locate_call_by_cid(cid);
1518        phcall_t *txca = ph_locate_call_by_cid(tcid);
1519        int i;
1520
1521
1522        if (!ca || !txca)
1523        {
1524                return -PH_BADCID;
1525        }
1526
1527        ca->localrefer = 1;
1528        ca->txcid = tcid;
1529
1530        eXosip_lock();
1531        i = eXosip_transfer_call_to(ca->did, txca->did);
1532        eXosip_unlock();
1533
1534
1535        return i;
1536}
1537
1538int
1539phSetContact(int vlid, const char *uri)
1540{
1541        phVLine *vl;
1542
1543
1544        if (!vlid)
1545        {
1546                /* set contact for all VL */
1547                strncpy(vcontact, uri, sizeof(vcontact));
1548                return 0;
1549        }
1550
1551
1552        vl = ph_valid_vlid(vlid);
1553
1554        if (!vl)
1555        {
1556                return -PH_BADVLID;
1557        }
1558
1559        return 0;
1560}
1561#endif /* not used */
1562
1563int
1564phConf(int cid1, int cid2)
1565{
1566        phcall_t *ca1 = ph_locate_call_by_cid(cid1);
1567        phcall_t *ca2 = ph_locate_call_by_cid(cid2);
1568
1569        if(!ca1 || !ca2)
1570        {
1571                return -PH_BADCFID;
1572        }
1573
1574        if (0 > ph_msession_conf_start(ca1->mses, ca2->mses, phcfg.audio_dev))
1575        {
1576                return PH_NORESOURCES;
1577        }
1578        else
1579        {
1580                return 0;
1581        }
1582}
1583
1584int
1585phStopConf(int cid1, int cid2)
1586{
1587        phcall_t *ca1 = ph_locate_call_by_cid(cid1);
1588        phcall_t *ca2 = ph_locate_call_by_cid(cid2);
1589
1590        if(!ca1 || !ca2)
1591        {
1592                return -PH_BADCFID;
1593        }
1594
1595        if( 0 > ph_msession_conf_stop(ca1->mses, ca2->mses))
1596        {
1597                return PH_NORESOURCES;
1598        }
1599        else
1600        {
1601                return 0;
1602        }
1603}
1604
1605#define CONF_MODE 1
1606
1607
1608int
1609phResumeCall(int cid)
1610{
1611        phcall_t *ca = ph_locate_call_by_cid(cid);
1612        int i;
1613
1614        DBG_SIP_NEGO("phResumeCall:begin for callId: %d\n", cid);
1615   
1616        if (!ca)
1617        {
1618                return -PH_BADCID;
1619        }
1620
1621        // a call that is not held locally cannot be resumed locally
1622        if (!ca->localhold)
1623        {
1624                return -PH_HOLDERR;
1625        }
1626
1627#ifndef CONF_MODE
1628        if (ph_has_active_calls())
1629        {
1630                return -PH_NORESOURCES;
1631        }
1632#endif
1633
1634        ca->localhold = 0;
1635    // the local peer starts a resume process on the call
1636        ca->localresume = 1;
1637
1638        eXosip_lock();
1639        i = eXosip_off_hold_call(ca->did, 0, 0);
1640        eXosip_unlock();
1641
1642        // if eXosip failed to put the call off hold, revert the changes on the call
1643        if(i != 0) {
1644                ca->localhold = 1;
1645                ca->localresume = 0;
1646        }
1647
1648        DBG_SIP_NEGO("phResumeCall:end for callId: %d, local.(hold,resume,refer)=(%d, %d, %d)\n", cid, ca->localhold, ca->localresume, ca->localrefer);
1649        return i;
1650}
1651
1652
1653int
1654phHoldCall(int cid)
1655{
1656        phcall_t *ca = ph_locate_call_by_cid(cid);
1657        int i;
1658
1659        DBG_SIP_NEGO("SIP_NEGO: phHoldCall\n");
1660
1661        // call does not exist
1662        if (!ca)
1663        {
1664                return -PH_BADCID;
1665        }
1666
1667        // call hold is already in progress
1668        if (ca->localhold)
1669        {
1670                return -PH_HOLDERR;
1671        }
1672
1673        // the local peer starts a call hold process on the call
1674        ca->localhold = 1;
1675
1676        // SPIKE_EXOSIP: hold a call
1677        eXosip_lock();
1678        i = eXosip_on_hold_call(ca->did);
1679        eXosip_unlock();
1680
1681        // if eXosip failed to put the call on hold, revert the change on the call
1682        if(i != 0) {
1683                ca->localhold = 0;
1684        }
1685
1686        return i;
1687
1688}
1689
1690
1691int
1692phLineSetFollowMe(int vlid, const char *uri)
1693{
1694        phVLine *vl = ph_valid_vlid(vlid);
1695
1696        if (!vl)
1697        {
1698                return -PH_BADVLID;
1699        }
1700
1701        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
1702        {
1703                return -PH_REDIRLOOP;
1704        }
1705
1706        if (vl->followme)
1707        {
1708                osip_free(vl->followme);
1709        }
1710
1711        vl->followme = osip_strdup(uri);
1712
1713        return 0;
1714}
1715
1716
1717int
1718phLineSetBusy(int vlid, int busyFlag)
1719{
1720        phVLine *vl = ph_valid_vlid(vlid);
1721
1722
1723        if (!vl)
1724        {
1725                return -PH_BADVLID;
1726        }
1727
1728        vl->busy = busyFlag;
1729        return 0;
1730}
1731
1732
1733int
1734phAddAuthInfo(const char *username, const char *userid,
1735                          const char *passwd, const char *ha1,
1736                          const char *realm)
1737{
1738        int ret;
1739
1740        if (!username)
1741        {
1742                return -PH_BADARG;
1743        }
1744
1745        if (!userid)
1746        {
1747                return -PH_BADARG;
1748        }
1749
1750        if (!passwd)
1751        {
1752                return -PH_BADARG;
1753        }
1754
1755        if (!realm)
1756        {
1757                return -PH_BADARG;
1758        }
1759
1760        eXosip_lock();
1761
1762        ret = eXosip_add_authentication_info(username, userid, passwd, ha1, realm);
1763
1764        eXosip_unlock();
1765
1766        return ret;
1767}
1768
1769
1770int
1771phSendDtmf(int cid, int dtmfEvent, int mode)
1772{
1773        phcall_t *ca = ph_locate_call_by_cid(cid);
1774
1775        if (!ca)
1776        {
1777                return -PH_BADCID;
1778        }
1779
1780        if (!ph_call_hasaudio(ca))
1781        {
1782                return -PH_NOMEDIA;
1783        }
1784
1785
1786        return ph_msession_send_dtmf(ca->mses, dtmfEvent, mode);
1787
1788}
1789
1790
1791
1792
1793
1794int
1795phPlaySoundFile(const char *fileName , int loop)
1796{
1797        return -1;
1798}
1799
1800
1801
1802int
1803phSendSoundFile(int cid, const char *fileName)
1804{
1805        phcall_t *ca = ph_locate_call_by_cid(cid);
1806
1807        if (!ca)
1808        {
1809                return -PH_BADCID;
1810        }
1811
1812        if (!ph_call_hasaudio(ca))
1813        {
1814                return -PH_NOMEDIA;
1815        }
1816
1817
1818        return ph_msession_send_sound_file(ca->mses, fileName);
1819
1820
1821}
1822
1823
1824
1825
1826int
1827phStopSoundFile()
1828{
1829        return -1;
1830}
1831
1832
1833int
1834phSetSpeakerVolume(int cid,  int volume)
1835{
1836#if 0
1837        phcall_t *ca = ph_locate_call_by_cid(cid);
1838
1839        if (!ca)
1840        {
1841                return -PH_BADCID;
1842        }
1843
1844        return(ph_media_set_spkvol(ca, volume));
1845#else
1846        return 0;
1847#endif
1848}
1849
1850
1851int
1852phSetRecLevel(int cid,  int level)
1853{
1854#if 0
1855        phcall_t *ca = ph_locate_call_by_cid(cid);
1856
1857        if (!ca)
1858        {
1859                return -PH_BADCID;
1860        }
1861
1862        return(ph_media_set_recvol(ca, level));
1863#else
1864        return 0;
1865#endif
1866}
1867
1868int
1869phAddVline(const char* username, const char *server, const char*  proxy, OWPL_TRANSPORT_PROTOCOL transport, int regTimeout)
1870{
1871        return phAddVline2(NULL, username, server, proxy, transport, regTimeout);
1872}
1873
1874/*
1875scrap the :port part from the host uri
1876*/
1877static char *
1878ph_scrap_port(char *buf, int bufsize, const char *host, int *port)
1879{
1880
1881        assert(buf != 0);
1882        assert(port != 0);
1883
1884        *port = 0;
1885
1886        if (!host)
1887        {
1888                return 0;
1889        }
1890
1891        if (!strchr(host, ':'))
1892        {
1893                return (char *)host;
1894        }
1895
1896        strncpy(buf, host, bufsize);
1897        host = strchr(buf, ':');
1898        if (host)
1899        {
1900                *( char *) host = 0;
1901                *port = atoi(host+1);
1902        }
1903
1904        return buf;
1905
1906}
1907
1908static const char emptystr[] = { 0 };
1909#define nonull(x) ((x) ? (x) : emptystr)
1910
1911int
1912phAddVline2(const char *displayname, const char* username, const char *server, const char*  proxy, OWPL_TRANSPORT_PROTOCOL transport, int regTimeout)
1913{
1914        phVLine *vl;
1915        int oldTimeout = 0;
1916        char srvbuf[256];
1917        char *srv2;
1918        int port;
1919        TransportProtocol sip_transport ;
1920
1921        DBG_SIP_NEGO("AddVline2(dn = %s, un=%s, srv=%s pxy=%s regT=%d)\n", nonull(displayname),
1922                nonull(username), nonull(server), nonull(proxy), regTimeout);
1923
1924        srv2 = ph_split_host_port(srvbuf, sizeof(srvbuf), server, &port);
1925
1926        if (!port)
1927        {
1928                port = 5060;
1929        }
1930
1931        if (!username)
1932        {
1933                username = "";
1934        }
1935
1936        if (0 < regTimeout && regTimeout < 200)
1937        {
1938                regTimeout = 200;
1939        }
1940
1941        vl = vline_alloc();
1942        if (!vl)
1943        {
1944                return -PH_NORESOURCES;
1945        }
1946
1947        switch (transport)
1948        {
1949                case OWPL_TRANSPORT_UDP :
1950                        sip_transport = TRANSPORT_UDP ;
1951                        break ;
1952                case OWPL_TRANSPORT_TCP :
1953                        sip_transport = TRANSPORT_TCP ;
1954                        break ;
1955                case OWPL_TRANSPORT_TLS :
1956                        sip_transport = TRANSPORT_TLS ;
1957                        break ;
1958                default :
1959                        sip_transport = TRANSPORT_UNKNOWN ;
1960        }
1961        vl->sipAccount = owsip_account_new
1962        (
1963                displayname,
1964                username,
1965                srv2,
1966                sip_transport,
1967                proxy,
1968                port
1969        ) ;
1970        if (vl->sipAccount < 0)
1971        {
1972                return -PH_NORESOURCES;
1973        }
1974
1975        if (owsip_account_idle_time_max_set (vl->sipAccount, 75))
1976        {
1977                return -PH_ERROR ;
1978        }
1979
1980        vl->regTimeout = regTimeout;
1981
1982        vl->LineState = LINESTATE_PROVISIONED;
1983
1984        if (nonempty(srv2) && (oldTimeout > 0 || regTimeout > 0))
1985        {
1986                phvlRegister(ph_vline2vlid(vl));
1987        }
1988
1989        return ph_vline2vlid(vl);
1990}
1991
1992int
1993phDelVline(int vlid, int regTimeout)
1994{
1995        return phDelVline2(vlid, regTimeout, 0);
1996}
1997
1998int
1999phDelVline2(int vlid, int regTimeout, int skipUnregister)
2000{
2001        phVLine *vl;
2002        phcall_t *ca;
2003
2004        if (!(vl = ph_valid_vlid(vlid)))
2005        {
2006                return -PH_BADVLID;
2007        }
2008
2009#if 0
2010        if (vl->LineState == LINESTATE_DELETING) {
2011                return 0;
2012        }
2013#endif
2014
2015        /* forbid deletion of the lines which have pending calls */
2016        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS]; ca++)
2017        {
2018                if (ca->vlid == vlid && ca->cid > 0)
2019                {
2020                        return -PH_VLBUSY;
2021                }
2022        }
2023
2024        if (regTimeout >= 0)
2025        {
2026                vl->regTimeout = regTimeout;
2027        }
2028
2029        if (vl->LineState == LINESTATE_REGISTERED && !skipUnregister)
2030        {
2031                phvlUnregister(ph_vline2vlid(vl));
2032                vl->LineState == LINESTATE_DELETING;
2033        }
2034        else
2035        {
2036                if (owsip_account_free (vl->sipAccount))
2037                {
2038                        return -1 ;
2039                }
2040                vline_free(vl);
2041        }
2042
2043        //vl->LineState = LINESTATE_DELETING;
2044
2045        return 0;
2046}
2047
2048
2049int phChangeAudioDevices(const char *devstr)
2050{
2051        char *forcedDeviceId;
2052        /*
2053        Audio device selection:
2054        if we have PH_FORCE_AUDIO_DEVICE env var it overrides everything else
2055        otherwise we try to use the device specified by the UI....
2056        if UI didn't specify anything we try to use content of PH_AUDIO_DEVICE env var (if it is nonempty)
2057        and in the last resort we use PortAudio default device
2058        */
2059        forcedDeviceId = getenv("PH_FORCE_AUDIO_DEVICE");
2060
2061        if (forcedDeviceId && forcedDeviceId[0])
2062        {
2063                strncpy(phcfg.audio_dev, forcedDeviceId, sizeof(phcfg.audio_dev));
2064        }
2065        else if (devstr && devstr[0])
2066        {
2067                strncpy(phcfg.audio_dev, devstr, sizeof(phcfg.audio_dev));
2068        }
2069        else
2070        {
2071                forcedDeviceId = getenv("PH_AUDIO_DEVICE");
2072                if (forcedDeviceId && forcedDeviceId[0])
2073                {
2074                        strncpy(phcfg.audio_dev, forcedDeviceId, sizeof(phcfg.audio_dev));
2075                }
2076                else
2077                {
2078#if defined(OS_MACOSX)
2079                        strncpy(phcfg.audio_dev, "ca:", sizeof(phcfg.audio_dev));
2080#else
2081                        strncpy(phcfg.audio_dev, "pa:", sizeof(phcfg.audio_dev));
2082#endif
2083                }
2084        }
2085
2086        return 0;
2087}
2088
2089/*
2090scan call marked for close and close them while delivering phCALLCLOSED to phApi client
2091*/
2092static void
2093ph_scan_calls()
2094{
2095        int i;
2096        phcall_t *ca;
2097
2098        ca = ph_calls;
2099        for (i = PH_MAX_CALLS; i; i--, ca++)
2100        {
2101                if (ca->cid > 0 && ca->closereq)
2102                {
2103                        phCallStateInfo_t info;
2104                        int cid = ca->cid;
2105
2106                        memset(&info, 0, sizeof(info));
2107                        info.vlid = ca->vlid;
2108                        info.event = phCALLCLOSED;
2109
2110                        if (phcb->callProgress) {
2111                                phcb->callProgress(cid, &info);
2112                        }
2113                        owplFireCallEvent(cid,
2114                                CALLSTATE_DISCONNECTED,
2115                                CALLSTATE_DISCONNECTED_NORMAL,
2116                                ca->remote_uri,
2117                                0);
2118
2119                        DBG_SIP_NEGO("release calls");
2120                        ph_release_call(ca);
2121                }
2122        }
2123}
2124
2125#if 0 /* not used */
2126static char *
2127ph_get_proxy(const char *userid)
2128{
2129        phVLine *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
2130
2131        if (!vl)
2132        {
2133                return "";
2134        }
2135
2136        return vl->proxy ? vl->proxy : "";
2137}
2138#endif /* not used */
2139
2140static int
2141ph_get_vline_id(const char *userid, const char *altid)
2142{
2143
2144        phVLine *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
2145
2146        if (vl)
2147        {
2148                return ph_vline2vlid(vl);
2149        }
2150
2151        if (nonempty(altid))
2152        {
2153                vl = ph_find_matching_vline(altid, PHM_IGNORE_PORT);
2154                if (vl)
2155                {
2156                        return ph_vline2vlid(vl);
2157                }
2158        }
2159
2160        vl = ph_find_matching_vline(userid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
2161        if (vl)
2162        {
2163                return ph_vline2vlid(vl);
2164        }
2165
2166
2167        if (nonempty(altid))
2168        {
2169                vl = ph_find_matching_vline(altid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
2170                if (vl)
2171                {
2172                        return ph_vline2vlid(vl);
2173                }
2174        }
2175
2176        return 0;
2177
2178}
2179
2180static void setup_payload(const char *ptstring)
2181{
2182        char  tmp[64];
2183        char  num[8];
2184        ph_media_payload_t  pt;
2185        int g722hack = 0;
2186
2187        DBG_CODEC_LOOKUP("trying to setup codec in eXosip: %s\n", ptstring);
2188        if(!strncasecmp(ptstring, "G722", 4))
2189          {
2190            g722hack = 1;
2191            ptstring = "G722/16000";
2192          }
2193
2194        if (ph_media_supported_payload(&pt, ptstring))
2195        {
2196                if (g722hack)
2197                    pt.rate = 8000;
2198                DBG_CODEC_LOOKUP("...setup accepted : %d - %s/%d\n", pt.number, pt.string, pt.rate);
2199                snprintf(num, sizeof(num), "%d", pt.number);
2200                snprintf(tmp, sizeof(tmp), "%d %s/%d/1", pt.number, pt.string, pt.rate);
2201
2202                eXosip_sdp_negotiation_add_codec(
2203                        osip_strdup(num),
2204                        NULL,
2205                        osip_strdup("RTP/AVP"),
2206                        NULL, NULL, NULL,
2207                        NULL,NULL,
2208                        osip_strdup(tmp));
2209                return;
2210        }
2211        DBG_CODEC_LOOKUP("...setup refused - not found in ortp profile");
2212
2213}
2214
2215
2216
2217static void setup_video_payload(const char *ptsring)
2218{
2219        char  tmp[64];
2220        char  num[8];
2221        ph_media_payload_t  pt;
2222
2223        if (ph_media_supported_payload(&pt, ptsring))
2224        {
2225                snprintf(num, sizeof(num), "%d", pt.number);
2226                snprintf(tmp, sizeof(tmp), "%d %s/%d/1", pt.number, pt.string, pt.rate);
2227
2228                eXosip_sdp_negotiation_add_videocodec(osip_strdup(num),
2229                        NULL,
2230                        osip_strdup("RTP/AVP"),
2231                        NULL, NULL, NULL,
2232                        NULL,NULL,
2233                        osip_strdup(tmp));
2234        }
2235        else
2236        {
2237                DBG_CODEC_LOOKUP("unsupported payload");
2238        }
2239}
2240
2241#ifdef OS_WIN32
2242
2243static int
2244wsock_init()
2245{
2246        WORD wVersionRequested;
2247        WSADATA wsaData;
2248        int i;
2249
2250        wVersionRequested = MAKEWORD(1,1);
2251        if(i = WSAStartup(wVersionRequested,  &wsaData))
2252        {
2253                return -1;
2254        }
2255        return 0;
2256}
2257#else
2258#define wsock_init() 0
2259#endif
2260
2261
2262static int
2263ph_debug_init()
2264{
2265        const char *dbgstr;
2266
2267        dbgstr = getenv("PH_DEBUG_LEVEL");
2268        if (dbgstr)
2269        {
2270                phDebugLevel = atoi(dbgstr);
2271        }
2272
2273        if (phDebugLevel > 0)
2274        {
2275                if (!phLogFileName)
2276                {
2277                        phLogFileName = getenv("PH_LOG_FILENAME");
2278                }
2279
2280                ph_log_file = phLogFileName ? fopen (phLogFileName, "w+") : stdout;
2281
2282                if (!ph_log_file)
2283                {
2284                        perror ("phapi: log file");
2285                        return -1;
2286                }
2287                TRACE_INITIALIZE (phDebugLevel, ph_log_file);
2288        }
2289
2290        return 0;
2291}
2292
2293
2294void
2295ph_avcodec_init()
2296{
2297#ifdef PHAPI_VIDEO_SUPPORT
2298        avcodec_init();
2299        avcodec_register_all();
2300        //phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_128KBPS;
2301#endif
2302}
2303
2304
2305void
2306ph_calls_init()
2307{
2308        int i;
2309
2310        for( i = 0; i < PH_MAX_CALLS; i++)
2311        {
2312                ph_calls[i].cid = -1;
2313                ph_calls[i].extern_cid = -1;
2314        }
2315}
2316
2317/**
2318* @brief initialize the payload/codecs that are allowed to be handled by the SIP stack
2319*/
2320void
2321ph_payloads_init()
2322{
2323        /* reset all payload to fit application capabilities */
2324        eXosip_sdp_negotiation_remove_audio_payloads();
2325        eXosip_sdp_negotiation_remove_video_payloads();
2326
2327        // init payload/codecs for VIDEO
2328
2329#ifdef PHAPI_VIDEO_SUPPORT
2330        //setup_video_payload(CODEC_H263P_MIME_STRING"/90000");
2331        setup_video_payload(CODEC_H263_MIME_STRING"/90000");
2332        setup_video_payload(CODEC_FLV1_MIME_STRING"/90000");
2333#if 0
2334        if (!phcfg.video_codecs[0])
2335        {
2336                setup_video_payload(CODEC_H263_MIME_STRING"/90000");
2337                setup_video_payload(CODEC_H264_MIME_STRING"/90000");
2338        }
2339        else
2340        {
2341                char tmp[32];
2342                char *tok = strtok(phcfg.video_codecs, ",");
2343
2344                while(tok) {
2345                        snprintf(tmp, sizeof(tmp), "%s/90000", tok);
2346                        setup_video_payload(tmp);
2347                        DBG_CODEC_LOOKUP("phapi: added video codec: %s\n",tmp);
2348                        tok = strtok(0, ",");
2349                }
2350        }
2351#endif
2352#endif
2353
2354        // init payload/codecs for AUDIO
2355
2356        // add codecs out of an ENV var
2357        {
2358                char *aclist = getenv("PH_AUDIO_CODECS");
2359                if (aclist)
2360                {
2361                        strncpy(phcfg.audio_codecs, aclist, sizeof(phcfg.audio_codecs));
2362                }
2363
2364        }
2365
2366
2367        // limit codecs to G711 codecs according to compile time DEFINE
2368#ifdef G711_ONLY
2369        strcpy(phcfg.audio_codecs, "PCMU/8000,PCMA/8000");
2370#endif
2371
2372        // if at this stage, no codecs are required, fix a default list
2373        if (!phcfg.audio_codecs[0])
2374        {
2375                setup_payload("PCMU/8000");
2376                setup_payload("PCMA/8000");
2377                setup_payload("GSM/8000");
2378#ifdef ENABLE_ILBC
2379                setup_payload("ILBC/8000");
2380#endif
2381                setup_payload("SPEEX/16000");
2382                setup_payload("SPEEX/8000");
2383#ifdef ENABLE_AMR
2384                setup_payload("AMR/8000");
2385#endif
2386
2387#ifdef ENABLE_AMR_WB
2388                setup_payload("AMR-WB/16000");
2389#endif
2390                setup_payload("G722/8000");
2391                setup_payload("G726-32/8000");
2392        }
2393        // phapi.h client has required a specific list of codecs
2394        else
2395        {
2396                /*
2397                The list is "," separated
2398                some hacks are present to allow for :
2399                - payload usurpation
2400                - default /8000 clockrate when not specified
2401                - ... look at the code
2402                */
2403
2404                char tmp[32];
2405                char *acodecs_bak;
2406                char *tok;
2407               
2408                acodecs_bak = strdup(phcfg.audio_codecs);
2409                tok = strtok(phcfg.audio_codecs, ",");
2410
2411                while(tok)
2412                {
2413                        if(!strcasecmp(tok, "G722/8000"))
2414                             strcpy(tmp, "G722/16000");
2415                        else if(!strcmp(tok, "AMR-WB"))
2416                        {
2417#ifdef AMR_OVER_G729_HACK
2418                                snprintf(tmp, sizeof(tmp), "G729/8000");
2419#else
2420                                snprintf(tmp, sizeof(tmp), "%s/16000", tok);
2421#endif
2422                        }
2423#ifdef SPEEX_OVER_G729_HACK
2424                        else if(!strcmp(tok, "SPEEX/16000"))
2425                        {
2426                                snprintf(tmp, sizeof(tmp), "G729/8000");
2427                        }
2428#endif
2429                        else if (strchr(tok, '/'))
2430                        {
2431                                strncpy(tmp, tok, sizeof(tmp));
2432                        }
2433                        else
2434                        {
2435                                snprintf(tmp, sizeof(tmp), "%s/8000", tok);
2436                        }
2437
2438                        if (ph_media_can_handle_payload(tmp))
2439                        {
2440                                setup_payload(tmp);
2441                        }
2442
2443                        tok = strtok(0, ",");
2444                }
2445
2446                if (acodecs_bak)
2447                {
2448                        strncpy(phcfg.audio_codecs, acodecs_bak, sizeof(phcfg.audio_codecs));
2449                        free(acodecs_bak);
2450                }
2451        }
2452
2453        // set codec in sip stack for CNG (confort noise generator=
2454        if(phcfg.cng)
2455        {
2456                setup_payload("CN/8000");
2457        }
2458
2459        // set codec in sip stack for DTMF
2460        setup_payload("telephone-event/8000");
2461}
2462
2463void DEBUGTRACE(const char * mess)
2464{
2465        if(phcb && phcb->debugTrace)
2466        {
2467                phcb->debugTrace(mess);
2468        }
2469        owplLogDebug(mess);
2470}
2471
2472// SPIKE_SRTP: enable / disable cipher mode using environnment variable
2473/**
2474 * @brief enable / disable cipher mode using environnment variable
2475 */
2476static void
2477ph_cipher_init()
2478{
2479  char *cipherMode_str = getenv("SVOIP_PHAPI_CIPHERMODE");
2480
2481  fprintf(stdout,"sVoIP cipherMode_str = %s\n", cipherMode_str);
2482  if (cipherMode_str == NULL)
2483    {
2484      sVoIP_phapi_setCipherMode(0);
2485    }
2486  else
2487    {
2488      if (!strcmp(cipherMode_str, "NULL"))
2489        {
2490          fprintf(stdout,"sVoIP will not ciphered\n");
2491          sVoIP_phapi_setCipherMode(0);
2492        }
2493      if (!strcmp(cipherMode_str, "SRTP"))
2494        {
2495          fprintf(stdout,"sVoIP uses SRTP\n");
2496          sVoIP_phapi_setCipherMode(1);
2497        }
2498    }
2499}
2500
2501/**
2502* terminate ph api
2503*/
2504void
2505phTerminate()
2506{
2507        int i;
2508
2509        DBG_SIP_NEGO("SIP NEGO: phTerminate\n");
2510        if (!phIsInitialized)
2511        {
2512                return;
2513        }
2514
2515        for(i = 0; i < PH_MAX_CALLS; i++)
2516                if (ph_calls[i].cid != -1 && ph_calls[i].extern_cid != -1)
2517                {
2518                        DBG_SIP_NEGO("release calls");
2519                        ph_release_call(&ph_calls[i]);
2520                }
2521
2522                for(i = 0; i < PH_MAX_VLINES; i++)
2523                {
2524                        phDelVline(i+1, -1);
2525                }
2526
2527                usleep(200000);
2528
2529                phPoll();
2530
2531                phIsInitialized = 0;
2532
2533                eXosip_quit();
2534
2535                ph_media_cleanup();
2536
2537                if (phLogFileName && phDebugLevel > 0)
2538                {
2539                        fclose(ph_log_file);
2540                }
2541                if (phDebugLevel > 0)
2542                {
2543                        for (i = 0; i <= phDebugLevel && i < END_TRACE_LEVEL; ++i)
2544                        {
2545                                TRACE_DISABLE_LEVEL(i);
2546                        }
2547                }
2548}
2549
2550
2551/**
2552* poll for phApi events.c
2553*/
2554int
2555phPoll()
2556{
2557        if (!phIsInitialized)
2558        {
2559                return -1;
2560        }
2561
2562        if (!phcfg.asyncmode)
2563        {
2564                if (ph_event_get() == -2)
2565                {
2566                        return -2;
2567                }
2568
2569                ph_keep_refreshing();
2570        }
2571        return 0;
2572}
2573
2574void ph_refer_notify(int did, int status, const char* msg, int final)
2575{
2576        char  statusmsg[128];
2577
2578        snprintf(statusmsg, sizeof(statusmsg), "SIP/2.0 %d %s", status, msg);
2579
2580        eXosip_lock();
2581
2582        eXosip_transfer_send_notify(did, final ? EXOSIP_SUBCRSTATE_TERMINATED : EXOSIP_SUBCRSTATE_ACTIVE,
2583                statusmsg);
2584
2585        eXosip_unlock();
2586
2587}
2588
2589static int
2590ph_call_retrieve_payloads(phcall_t *ca, eXosip_event_t *je, int flags)
2591{
2592        int  i = 0;
2593
2594        DBG_SIP_NEGO("looking for payloads...\n");
2595        DBG_SIP_NEGO("audio...\n");
2596        if (_is_audio_enabled(flags))
2597        {
2598                i = eXosip_retrieve_negotiated_audio_payload(ca->did, &ca->audio_payload, ca->audio_payload_name, sizeof(ca->audio_payload_name));
2599                DBG_SIP_NEGO("remote_audio=%s payload=%s(%d)\n", ca->remote_sdp_audio_ip, ca->audio_payload_name, ca->audio_payload);
2600        }
2601
2602        DBG_SIP_NEGO("video...\n");
2603        ca->video_payload = 0;
2604        if (ca->remote_sdp_video_ip[0] && (_is_video_enabled(flags)))
2605        {
2606                i = eXosip_retrieve_negotiated_video_payload(ca->did, &ca->video_payload, ca->video_payload_name, sizeof(ca->video_payload_name));
2607                DBG_SIP_NEGO("remote_video=%s payload=%s(%d)\n", ca->remote_sdp_video_ip, ca->video_payload_name, ca->video_payload);
2608        }
2609
2610        DBG_SIP_NEGO("cng...\n");
2611        if(!i && phcfg.cng && (flags & PH_STREAM_CNG)) {
2612                ca->cng = !eXosip_retrieve_negotiated_specific_payload(ca->did, PH_MEDIA_CN_PT_STR, strlen(PH_MEDIA_CN_PT_STR));
2613                DBG_SIP_NEGO("cng: %d", ca->cng);
2614        }
2615
2616        return i;
2617}
2618
2619
2620int phCallGetCodecs(int cid, char *audioCodecBuf, int aBufLen, char *videoCodecBuf, int vBufLen)
2621{
2622        phcall_t *ca = ph_locate_call_by_cid(cid);
2623
2624        if (!ca)
2625        {
2626                return -PH_BADCID;
2627        }
2628
2629        if (audioCodecBuf)
2630        {
2631                strncpy(audioCodecBuf, ca->audio_payload_name, aBufLen);
2632        }
2633
2634        if (videoCodecBuf)
2635        {
2636                strncpy(videoCodecBuf, ca->video_payload_name, vBufLen);
2637        }
2638
2639        return 0;
2640}
2641
2642static void
2643ph_parse_payload_mime(struct ph_media_payload_s *pt, const char *mime, int rate, int chans)
2644{
2645        const char *rp;
2646        const char *cp;
2647
2648        rp = strchr(mime, '/');
2649        strncpy(pt->string, mime, sizeof(pt->string));
2650        pt->rate = rate;
2651        pt->chans = chans;
2652
2653        if (!rp)
2654        {
2655                return;
2656        }
2657
2658        rp++;
2659        if (!*rp)
2660        {
2661                return;
2662        }
2663
2664        pt->rate = atol(rp);
2665
2666        cp = strchr(rp, '/');
2667        if (!cp)
2668        {
2669                return;
2670        }
2671
2672        cp++;
2673        if (!*cp)
2674        {
2675                return;
2676        }
2677
2678        pt->chans = atol(cp);
2679}
2680
2681
2682
2683static void
2684ph_call_media_stop(phcall_t *ca)
2685{
2686        DBG_SIP_NEGO("ph_call_media_stop\n");
2687
2688        if (ca->mses)
2689        {
2690                ph_msession_stop(ca->mses, phcfg.audio_dev);
2691                ph_clear_msession_streams_fmtps(ca->mses);
2692
2693                // cf allocation sequence for the ph_msession_s in phmedia.h
2694                pthread_mutex_destroy(&ca->mses->critsec_mstream_init);
2695                free(ca->mses);
2696
2697                ca->mses = 0;
2698        }
2699}
2700
2701static int
2702ph_call_media_suspend(phcall_t *ca, int localhold)
2703{
2704        if (ca->mses)
2705        {
2706                ph_msession_suspend(ca->mses, PH_MSTREAM_TRAFFIC_IO, phcfg.audio_dev);
2707        }
2708        return 0;
2709}
2710
2711
2712static int
2713ph_call_media_resume(phcall_t *ca, int localhold)
2714{
2715        if (ca->mses)
2716        {
2717                ph_msession_resume(ca->mses, PH_MSTREAM_TRAFFIC_IO, phcfg.audio_dev);
2718        }
2719
2720        return 0;
2721}
2722
2723
2724void ph_copy_media_payload(ph_media_payload_t* orig_payload, ph_media_payload_t* dest_payload, int is_full_copy)
2725{
2726        if ( (orig_payload == NULL) || (dest_payload == NULL) )
2727        {
2728                return;
2729        }
2730       
2731        dest_payload->number = orig_payload->number;
2732        strcpy(dest_payload->string, orig_payload->string);
2733        dest_payload->rate = orig_payload->rate;
2734        dest_payload->chans = orig_payload->chans;
2735        dest_payload->ptime = orig_payload->ptime;
2736        dest_payload->psize = orig_payload->psize;
2737        dest_payload->mode = orig_payload->mode;
2738       
2739        if (!is_full_copy)
2740        {
2741                return;
2742        }
2743       
2744        if (orig_payload->fmtp != NULL)
2745        {
2746                dest_payload->fmtp = osip_strdup(orig_payload->fmtp);
2747        }
2748}
2749
2750
2751/**
2752* @brief used to start/restart the media engine
2753* this function is used everytime it is necessary to start media sessions
2754* @param ca phcall_t call that is concerned. will express the needed sessions
2755* @param je last exosip event that justified the invocation of the function
2756* @param resumeflag 0/1 is this a resume operation ?
2757*
2758* @return 0 - OK / PH_NOMEDIA
2759*/
2760static int
2761ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int resumeflag)
2762{
2763        int i = 0;
2764        struct ph_msession_s *s = NULL, *olds = NULL;
2765        const char* ptime = getenv("EXOSIP_FORCE_PTIME");
2766        int bIsCallAccepted = 0;
2767
2768
2769        // cases when the invocation is ignored
2770        if (phcfg.nomedia || ca->localhold || ca->remotehold)
2771        {
2772                return 0;
2773        }
2774
2775        // we will work on the media sessions of the given phcall_t
2776        s = ca->mses;
2777
2778        // init the ph_msession_s for the call if the call doesn't have one yet
2779        if (!s)
2780        {
2781                s = ca->mses = (struct ph_msession_s *)calloc(sizeof(struct ph_msession_s), 1);
2782                if (!s)
2783                {
2784                        return -PH_NORESOURCES;
2785                }
2786                pthread_mutex_init(&s->critsec_mstream_init, NULL);
2787        }
2788
2789        s->cbkInfo = ca;
2790
2791        // we need to understand what is required from the function call
2792        // by default, nothing to do
2793        s->newstreams = 0;
2794
2795        if ( // user accepts video and network accepts video
2796                (_is_video_enabled(ca->user_mflags))
2797                && ca->video_payload
2798                && ca->remote_sdp_video_ip[0]
2799        )
2800        {
2801                // negociated flags (user+SDP) need to be IO
2802                ca->nego_mflags = ca->nego_mflags | PH_STREAM_VIDEO_RX;
2803                ca->nego_mflags = ca->nego_mflags | PH_STREAM_VIDEO_TX;
2804
2805                DBG_SIP_NEGO("will have video stream ip: %s payload=%d\n", ca->remote_sdp_video_ip, ca->video_payload);
2806                DBG_SIP_NEGO("media flags may have changed: user= %d nego=%d\n", ca->user_mflags, ca->nego_mflags);
2807        }
2808        else
2809        {
2810                // video is not negociated
2811                // it is necessary to remove VIDEO IO flags
2812                ca->nego_mflags = ca->nego_mflags & ~PH_STREAM_VIDEO_RX;
2813                ca->nego_mflags = ca->nego_mflags & ~PH_STREAM_VIDEO_TX;
2814
2815                DBG_SIP_NEGO("media flags may have changed: user= %d nego=%d\n", ca->user_mflags, ca->nego_mflags);
2816        }
2817
2818        if ( _is_video_enabled(ca->nego_mflags) )
2819        {
2820                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_VIDEO1];
2821                int ttype;
2822
2823                // program activation of VIDEO1
2824                s->newstreams |= (1 << PH_MSTREAM_VIDEO1);
2825
2826                // define the traffic type of the stream
2827                ttype = _is_video_enabled(ca->user_mflags);
2828                if (ttype == (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX))
2829                {
2830                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
2831                }
2832                else if (ttype == PH_STREAM_VIDEO_RX)
2833                {
2834                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
2835                }
2836                else if (ttype == PH_STREAM_VIDEO_TX)
2837                {
2838                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
2839                }
2840
2841                msp->localport = ca->local_sdp_video_port;
2842                msp->remoteport = ca->remote_sdp_video_port;
2843                if (je)
2844                {
2845                        strncpy(msp->remoteaddr,
2846                                je->remote_sdp_video_ip,
2847                                sizeof(msp->remoteaddr));
2848                }
2849                else
2850                {
2851                        strncpy(msp->remoteaddr,
2852                                ca->remote_sdp_video_ip,
2853                                sizeof(msp->remoteaddr));
2854                }
2855
2856                // define the negociated codec payload on the stream
2857                msp->opayloads[0].number = ca->video_payload;
2858                ph_parse_payload_mime(&msp->opayloads[0], ca->video_payload_name, 90000, 1);
2859                ph_copy_media_payload(&msp->opayloads[0], &msp->ipayloads[0], FALSE);
2860
2861                // define the video callback
2862                s->frameDisplayCbk =  ph_frame_display_cbk;
2863
2864                // additional configuration for video
2865                msp->videoconfig = phcfg.video_config.video_line_configuration;
2866        }       //if ( _is_video_enabled(ca->nego_mflags) )
2867
2868
2869        if ( // audio is enabled
2870                _is_audio_enabled(ca->nego_mflags)
2871                && (!je || je->remote_sdp_audio_ip[0])
2872                )
2873        {
2874                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
2875
2876                int in_call_ptime = 0;
2877                int out_call_ptime = 0;
2878               
2879                // Set to this stream the correct ptime negociated in the SDP.
2880                // If there is no ptime negociated, use the default value (20 ms).
2881                if ( (!je) && (ca->did > 0) )
2882                {
2883                        // We are accepting a call. On this case "je == NULL", so
2884                        // we need to retrive the ptime value if any from the original
2885                        // SDP package.
2886                        in_call_ptime = eXosip_get_audio_ptime_from_call(je, ca->did, 0, 1);
2887                        out_call_ptime = eXosip_get_audio_ptime_from_call(je, ca->did, 1, 1);
2888                       
2889                        msp->ptime = (out_call_ptime > 0 ? out_call_ptime : atoi(DEFAULT_PTIME_VALUE));
2890                       
2891                        bIsCallAccepted = 1;
2892                }
2893                else
2894                {
2895                        in_call_ptime = eXosip_get_audio_ptime_from_call(je, ca->did, 0, 0);
2896                        out_call_ptime = eXosip_get_audio_ptime_from_call(je, ca->did, 1, 0);
2897                       
2898                        msp->ptime = (out_call_ptime > 0 ? out_call_ptime : atoi(DEFAULT_PTIME_VALUE));
2899                }
2900               
2901                // Override "in_call_ptime" with packetization informed through
2902                // environment variable.
2903                if (ptime != NULL)
2904                {
2905                        if(!strncmp(ca->audio_payload_name, "GSM", 3))
2906                        {
2907                                if(30 == atoi(ptime))
2908                                {
2909                                        // for GSM reset ptime to 20ms
2910                                        ptime = DEFAULT_PTIME_VALUE;
2911                                }
2912                        }
2913                       
2914                        in_call_ptime = atoi(ptime);
2915                }
2916
2917                // program activation of AUDIO1
2918                s->newstreams |= (1 << PH_MSTREAM_AUDIO1);
2919
2920                s->dtmfCallback = ph_wegot_dtmf;
2921                s->endCallback = ph_stream_ended;
2922
2923                if (phcfg.vad & 0x80000000)
2924                {
2925                        msp->flags |= PH_MSTREAM_FLAG_VAD;
2926                        msp->vadthreshold = phcfg.vad & 0x7fff;
2927                }
2928
2929                if (phcfg.cng)
2930                {
2931                        msp->flags |= PH_MSTREAM_FLAG_CNG;
2932                }
2933
2934                msp->jitter = phcfg.jitterdepth;
2935
2936                if (!phcfg.noaec)
2937                {
2938                        msp->flags |= PH_MSTREAM_FLAG_AEC;
2939                }
2940
2941                msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
2942
2943                msp->localport = ca->local_sdp_audio_port;
2944                msp->remoteport = ca->remote_sdp_audio_port;
2945                if (je)
2946                {
2947                        strncpy(msp->remoteaddr,
2948                                je->remote_sdp_audio_ip,
2949                                sizeof(msp->remoteaddr));
2950                }
2951                else
2952                {
2953                        strncpy(msp->remoteaddr,
2954                                ca->remote_sdp_audio_ip,
2955                                sizeof(msp->remoteaddr));
2956                }
2957
2958                // SPIKE_HDX
2959                if (phcfg.hdxmode == PH_HDX_MODE_MIC)
2960                {
2961                        msp->flags |= PH_MSTREAM_FLAG_MICHDX;
2962                        msp->vadthreshold = phcfg.vad & 0x7fff;
2963                }
2964
2965                if (phcfg.hdxmode == PH_HDX_MODE_SPK)
2966                {
2967                        msp->flags |= PH_MSTREAM_FLAG_SPKHDX;
2968                        msp->vadthreshold = phcfg.vad & 0x7fff;
2969                }
2970
2971                ph_clear_msession_streams_fmtps(s);
2972
2973                msp->opayloads[0].number = ca->audio_payload;
2974                ph_parse_payload_mime(&msp->opayloads[0], ca->audio_payload_name, 8000, 1);
2975                if (!strcasecmp(msp->opayloads[0].string, "g722"))
2976                  msp->opayloads[0].rate = 16000;
2977                ph_copy_media_payload(&msp->opayloads[0], &msp->ipayloads[0], FALSE);
2978
2979                {
2980                        osip_list_t local_format_modifiers;
2981                        int pos = 0;
2982                        char *format_modifier = NULL;
2983                       
2984                        osip_list_init(&local_format_modifiers);
2985                       
2986                        eXosip_get_media_formats_from_call(je, 
2987                                        ca->did, 0, bIsCallAccepted, &local_format_modifiers);
2988                       
2989                        ph_update_media_payloads_packetization_info(
2990                                        &local_format_modifiers, msp, in_call_ptime);
2991                       
2992                        while (!osip_list_eol(&local_format_modifiers, pos))
2993                        {
2994                          format_modifier = (char*)osip_list_get(&local_format_modifiers, pos);
2995                          osip_list_remove(&local_format_modifiers, pos);
2996                        }
2997                }
2998
2999        } // end        if ( // audio is enabled
3000
3001        // take action depending on the streaming configuration
3002        if (s->newstreams | s->activestreams)
3003        {
3004                if (resumeflag)
3005                {
3006                        if (ph_msession_resume(s, PH_MSTREAM_TRAFFIC_IO, phcfg.audio_dev))
3007                        {
3008                                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_resume\n");
3009                                i = -PH_NOMEDIA;
3010                        }
3011                }
3012                else if (ph_msession_start(s, phcfg.audio_dev))
3013                {
3014                        DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_start\n");
3015                        i = -PH_NOMEDIA;
3016                }
3017        }
3018        else
3019        {
3020                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: nothing to start\n");
3021                i = -PH_NOMEDIA;
3022        }
3023
3024        return i;
3025}
3026
3027void
3028ph_call_new(eXosip_event_t *je)
3029{
3030        phCallStateInfo_t info;
3031        phcall_t *ca;
3032        phVLine *vl;
3033        char own[512];
3034        char remote[512];
3035
3036        clear(info);
3037#if 0 /* not used */
3038        if (ph_busyFlag)
3039        {
3040                ph_answer_request(je->did, 486);
3041                return;
3042        }
3043
3044        if (ph_follow_me_addr[0])
3045        {
3046                ph_answer_request_with_contact(je->did, 302, ph_follow_me_addr);
3047                return;
3048        }
3049#endif /* not used */
3050
3051        info.vlid = ph_get_vline_id(je->local_uri, je->req_uri);
3052
3053        if (!info.vlid)
3054        {
3055                ph_answer_request(je->did, 404);
3056                return;
3057        }
3058
3059        vl = ph_vlid2vline(info.vlid);
3060
3061        assert(vl);
3062
3063        if (vl->busy)
3064        {
3065                ph_answer_request(je->did, 486);
3066                return;
3067        }
3068       
3069        DBG_SIP_NEGO("LOC:%s, REM:%s, REQ:%s\n", je->local_uri, je->remote_uri, je->req_uri);
3070        ph_vline_get_user_domain(own, sizeof(own), vl);
3071
3072        if(ph_from_user_domain(remote, sizeof(remote),je->remote_uri))
3073        {
3074                DBG_SIP_NEGO("Own:%s Remote:%s\n", own, remote);
3075                if(!strncmp(own, remote, strlen(remote)))
3076                {
3077                        ca = ph_locate_call_by_remote_uri(remote);
3078                        if(ca)
3079                        {
3080                                if(ca->waitaccept)
3081                                {
3082                                        /*
3083                                         *      Return BUSY if called by itself
3084                                         */
3085                                        ph_answer_request(je->did, 486);
3086                                        return;
3087                                }
3088                        }
3089                        DBG_SIP_NEGO("Accept call from own number");
3090                }
3091        }
3092
3093        if (vl->followme && vl->followme[0])
3094        {
3095                ph_answer_request_with_contact(je->did, 302, vl->followme);
3096                return;
3097        }
3098
3099        ca = ph_locate_call(je, 1);
3100
3101        if (ca)
3102        {
3103                ca->vlid = info.vlid;
3104                ca->remote_uri = strdup(je->remote_uri);
3105                ph_build_cname(ca->cname, sizeof(ca->cname), ph_vlid2vline(ca->vlid));
3106
3107                info.userData = je->external_reference;
3108                info.event = phINCALL;
3109                info.u.remoteUri = je->remote_uri;
3110                info.localUri = je->local_uri;
3111                info.streams = PH_STREAM_AUDIO;
3112                if (ca->video_payload)
3113                {
3114                        info.streams |= PH_STREAM_VIDEO_RX;
3115                }
3116
3117                if (phcb->callProgress) {
3118                        phcb->callProgress(ca->cid, &info);
3119                }
3120                owplFireCallEvent(ca->cid,
3121                        CALLSTATE_OFFERING,
3122                        CALLSTATE_OFFERING_ACTIVE,
3123                        je->remote_uri,
3124                        0);
3125        }
3126        else
3127        {
3128                ph_answer_request(je->did, 500);
3129        }
3130}
3131
3132void
3133ph_call_replaces(eXosip_event_t *je)
3134{
3135        phCallStateInfo_t info;
3136        phcall_t *ca, *oldca;
3137
3138        DBG_SIP_NEGO("SIP_NEGO: ph_call_replaces\n");
3139
3140        clear(info);
3141
3142        ca = ph_locate_call(je, 1);
3143
3144        if (ca)
3145        {
3146                oldca = ph_locate_call_by_cid(je->replacedcid);
3147
3148                if (oldca)
3149                {
3150                        info.userData = je->external_reference;
3151                        info.event = phCALLREPLACED;
3152                        info.u.remoteUri = je->remote_uri;
3153                        info.localUri = je->local_uri;
3154                        info.newcid = ca->cid;
3155
3156                        info.vlid = oldca->vlid;
3157
3158                        if (!ca->vlid)
3159                        {
3160                                ca->vlid = info.vlid;
3161                        }
3162
3163                        if (phcb->callProgress) {
3164                                phcb->callProgress(oldca->cid, &info);
3165                        }
3166
3167                        //TODO: Find an appropriate event to raise here for the new owpl API
3168
3169                        ph_call_media_stop(oldca);
3170
3171                        phAcceptCall(ca->cid);
3172                }
3173        }
3174}
3175
3176
3177/**
3178 * @brief function called upon reception of a 200 OK to a previously sent INVITATION
3179 *
3180 * This function needs to handle several cases depending on why the INVITATION was locally sent in the first place
3181 */
3182void
3183ph_call_answered(eXosip_event_t *je)
3184{
3185        phCallStateInfo_t info;
3186        phcall_t *ca, *rca=0;
3187
3188        clear(info);
3189
3190        ca = ph_locate_call(je, 1);
3191        DBG_SIP_NEGO("ph_call_answered remotely cid=%d, local.(hold, resume, refer) = (%d, %d, %d)\n", ca->cid, ca->localhold, ca->localresume, ca->localrefer);
3192   
3193        if (ca)
3194        {
3195                rca = ph_locate_call_by_cid(ca->rcid);
3196        }
3197
3198        ca->waitaccept = 0;
3199        ca->did = je->did;
3200
3201        if (!ca->localhold)
3202        {
3203                ph_call_retrieve_payloads(ca, je, -1);
3204                ph_call_media_start(ca, je, ca->localresume);
3205        }
3206
3207        if (ca->localhold && ph_call_hasaudio(ca))
3208        {
3209#ifndef MEDIA_SUSPEND
3210                ph_call_media_stop(ca);
3211#else
3212                ph_call_media_suspend(ca, 1);
3213#endif
3214        }
3215
3216        info.localUri = je->local_uri;
3217        info.userData = je->external_reference;
3218        info.u.remoteUri = je->remote_uri;
3219        info.vlid = ca->vlid;
3220        info.streams = PH_STREAM_AUDIO;
3221        if (ca->video_payload)
3222        {
3223                info.streams |= PH_STREAM_VIDEO_RX;
3224        }
3225        if (ca->localhold)
3226        {
3227                info.event = phHOLDOK;
3228                DBG_SIP_NEGO("phHOLDOK, cid=%d\n", ca->cid);
3229                if (!ca->localrefer)
3230                {
3231                        owplFireCallEvent(ca->cid,
3232                                CALLSTATE_HOLD,
3233                                CALLSTATE_HOLD_STARTED,
3234                                ca->remote_uri,
3235                                0);
3236                }
3237        }
3238        else if (ca->localresume)
3239        {
3240                info.event = phRESUMEOK;
3241                DBG_SIP_NEGO("phRESUMEOK, cid=%d\n", ca->cid);
3242                ca->localresume = 0;
3243                if (!ca->localrefer)
3244                {
3245                        owplFireCallEvent(ca->cid,
3246                                CALLSTATE_HOLD,
3247                                CALLSTATE_HOLD_RESUMED,
3248                                ca->remote_uri,
3249                                0);
3250                }
3251        }
3252        else {
3253                info.event = phCALLOK;
3254                DBG_SIP_NEGO("phCALLOK, cid=%d\n", ca->cid);
3255                if (!ca->localrefer)
3256                {
3257                        owplFireCallEvent(ca->cid,
3258                                CALLSTATE_CONNECTED,
3259                                CALLSTATE_CONNECTED_ACTIVE,
3260                                ca->remote_uri,
3261                                0);
3262                }
3263        }
3264
3265        if (!ca->localrefer)
3266        {
3267                if (phcb->callProgress) {
3268                        phcb->callProgress(ca->cid, &info);
3269                }
3270        }
3271
3272        if (rca)
3273        {
3274                ph_refer_notify(rca->rdid, je->status_code, "Answered", 1);
3275        }
3276}
3277
3278
3279void
3280ph_call_proceeding(eXosip_event_t *je)
3281{
3282        phCallStateInfo_t info;
3283        phcall_t *ca, *rca=0;
3284        int cng = 0;
3285
3286        DBG_SIP_NEGO("SIP NEGO: ph_call_proceeding\n");
3287        clear(info);
3288
3289        ca = ph_locate_call(je, 1);
3290        if (ca)
3291        {
3292                rca = ph_locate_call_by_cid(ca->rcid);
3293        }
3294
3295        if ((!ca->localrefer)&&(!ca->localresume))
3296        {
3297                ph_call_retrieve_payloads(ca, je, PH_STREAM_CNG);
3298                ph_call_media_start(ca, je, 0);
3299
3300                info.userData = je->external_reference;
3301                info.event = phDIALING;
3302                info.u.remoteUri = je->remote_uri;
3303                info.vlid = ca->vlid;
3304
3305                info.streams = ca->nego_mflags;
3306
3307                if (phcb->callProgress) {
3308                        phcb->callProgress(ca->cid, &info);
3309                }
3310
3311                owplFireCallEvent(ca->cid,
3312                        CALLSTATE_REMOTE_OFFERING,
3313                        CALLSTATE_REMOTE_OFFERING_NORMAL,
3314                        ca->remote_uri,
3315                        0);
3316        }
3317
3318        if (rca)
3319        {
3320                ph_refer_notify(rca->rdid, je->status_code, "Proceeding", 0);
3321        }
3322}
3323
3324void
3325ph_call_redirected(eXosip_event_t *je)
3326{
3327        phCallStateInfo_t info;
3328        phcall_t *ca;
3329        int validUris;
3330
3331
3332        ca = ph_locate_call(je, 1);
3333
3334        if (!ca)
3335        {
3336                return;
3337        }
3338
3339        validUris = nonempty(je->remote_contact) && nonempty(je->remote_uri);
3340
3341        if ((ca->redirs > 8) || !validUris || ph_find_matching_vline(je->remote_contact, PHM_IGNORE_PORT) || ph_same_uri(je->remote_contact, je->remote_uri))
3342        {
3343                ph_call_requestfailure(je);
3344                return;
3345        }
3346
3347
3348        clear(info);
3349
3350
3351        info.localUri = je->local_uri;
3352        info.userData = je->external_reference;
3353        info.event = phCALLREDIRECTED;
3354        info.u.remoteUri = je->remote_contact;
3355        info.vlid = ca->vlid;
3356        info.newcid = 0;
3357
3358        if (phcfg.autoredir)
3359        {
3360                phcall_t *newca;
3361
3362                newca = ph_allocate_call(-2);
3363                newca->redirs = ca->redirs + 1;
3364                info.newcid = phLinePlaceCall_withCa(info.vlid, je->remote_contact, 0, 0, ca->user_mflags, newca);
3365        }
3366
3367        if(phcb->callProgress) {
3368                phcb->callProgress(ca->cid, &info);
3369        }
3370
3371        owplFireCallEvent(ca->cid,
3372                CALLSTATE_REDIRECTED,
3373                CALLSTATE_REDIRECTED_NORMAL,
3374                je->remote_contact,
3375                0);
3376
3377        DBG_SIP_NEGO("release calls");
3378        ph_release_call(ca);
3379}
3380
3381
3382void ph_callStopRinging(eXosip_event_t *je)
3383{
3384        phCallStateInfo_t info;
3385        phcall_t *ca;
3386
3387        clear(info);
3388
3389        ca = ph_locate_call(je, 1);
3390        if (ca->isringing)
3391        {
3392                ca->isringing = 0;
3393                info.event = phRINGandSTOP;
3394
3395                info.localUri = je->local_uri;
3396                info.userData = je->external_reference;
3397
3398                info.u.remoteUri = je->remote_uri;
3399                info.vlid = ca->vlid;
3400
3401                if(phcb->callProgress) {
3402                        phcb->callProgress(ca->cid, &info);
3403                }
3404
3405                //TODO: Find an appropriate event to raise here for the new owpl API
3406        }
3407}
3408
3409void
3410ph_call_ringing(eXosip_event_t *je)
3411{
3412        int ret = 0;
3413        phCallStateInfo_t info;
3414        phcall_t *ca, *rca=0;
3415        int cng=0;
3416
3417        DBG_SIP_NEGO("SIP NEGO: ph_call_ringing\n");
3418
3419        clear(info);
3420
3421        ca = ph_locate_call(je, 1);
3422        if (ca)
3423        {
3424                rca = ph_locate_call_by_cid(ca->rcid);
3425        }
3426
3427        ph_call_retrieve_payloads(ca, je, PH_STREAM_CNG);
3428
3429        ret = ph_call_media_start(ca, je, 0);
3430
3431        info.event = phRINGING;
3432
3433        if (ret == -PH_NOMEDIA && !ph_call_hasaudio(ca) && !ca->isringing) /*  no audio and softPhone is now not ringing and has no sound */
3434        {
3435                ca->isringing = 1;
3436                info.event = phRINGandSTART;
3437        }
3438        else if (ca->isringing )
3439        {
3440                ca->isringing = 0;
3441                info.event = phRINGandSTOP;
3442        }
3443
3444
3445        info.localUri = je->local_uri;
3446        info.userData = je->external_reference;
3447
3448        info.u.remoteUri = je->remote_uri;
3449        info.vlid = ca->vlid;
3450
3451        info.streams = ca->nego_mflags;
3452
3453        if(phcb->callProgress) {
3454                phcb->callProgress(ca->cid, &info);
3455        }
3456
3457        if(info.event == phRINGandSTART)
3458        {
3459                owplFireCallEvent(ca->cid, CALLSTATE_REMOTE_ALERTING,
3460                                                                        CALLSTATE_REMOTE_ALERTING_MEDIA_START,
3461                                                                        ca->remote_uri, 0);
3462        }
3463        else if(info.event == phRINGandSTOP)
3464        {
3465                owplFireCallEvent(ca->cid, CALLSTATE_REMOTE_ALERTING,
3466                                                                        CALLSTATE_REMOTE_ALERTING_MEDIA_STOP,
3467                                                                        ca->remote_uri, 0);
3468        }
3469        else
3470                owplFireCallEvent(ca->cid, CALLSTATE_REMOTE_ALERTING,
3471                                                                        CALLSTATE_REMOTE_ALERTING_NORMAL,
3472                                                                        ca->remote_uri, 0);
3473
3474        if (rca)
3475        {
3476                ph_refer_notify(rca->rdid, 180, "Ringing", 0);
3477        }
3478}
3479
3480
3481/*static*/ void
3482ph_call_requestfailure(eXosip_event_t *je)
3483{
3484        phCallStateInfo_t info;
3485        phcall_t *ca, *rca=0;
3486
3487        clear(info);
3488
3489        ca = ph_locate_call(je, 0);
3490        if (!ca)
3491        {
3492                return;
3493        }
3494
3495        rca = ph_locate_call_by_cid(ca->rcid);
3496        info.vlid = ca->vlid;
3497
3498        info.localUri = je->local_uri;
3499        info.userData = je->external_reference;
3500        if (je->status_code == 486)
3501        {
3502                info.event = phCALLBUSY;
3503                info.u.remoteUri = je->remote_uri;
3504
3505                owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_BUSY, ca->remote_uri, 0);
3506        }
3507        else
3508        {
3509                info.event = phCALLERROR;
3510                info.u.errorCode = je->status_code;
3511
3512                owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_UNKNOWN, ca->remote_uri, 0);
3513        }
3514
3515        if (phcb->callProgress) {
3516                phcb->callProgress(ca->cid, &info);
3517        }
3518
3519        if (rca)
3520        {
3521                ph_refer_notify(rca->rdid, je->status_code, je->status_code == 486 ? "Busy" : "Request failure", 1);
3522        }
3523        DBG_SIP_NEGO("release calls");
3524        ph_release_call(ca);
3525}
3526
3527
3528void
3529ph_call_serverfailure(eXosip_event_t *je)
3530{
3531        phCallStateInfo_t info;
3532        phcall_t *ca, *rca=0;
3533
3534        clear(info);
3535
3536        ca = ph_locate_call(je, 0);
3537
3538        if (!ca) {
3539                return;
3540        }
3541
3542        rca = ph_locate_call_by_cid(ca->rcid);
3543        info.vlid = ca->vlid;
3544        info.localUri = je->local_uri;
3545        info.userData = je->external_reference;
3546        info.event = phCALLERROR;
3547        info.u.errorCode = je->status_code;
3548
3549
3550        if (phcb->callProgress) {
3551                phcb->callProgress(ca->cid, &info);
3552        }
3553
3554        owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_NETWORK, ca->remote_uri, 0);
3555
3556        if (rca)
3557        {
3558                ph_refer_notify(rca->rdid, je->status_code, "Server failure", 1);
3559        }
3560
3561        DBG_SIP_NEGO("release calls");
3562        ph_release_call(ca);
3563}
3564
3565void
3566ph_call_globalfailure(eXosip_event_t *je)
3567{
3568        phCallStateInfo_t info;
3569        phcall_t *ca, *rca=0;
3570
3571        clear(info);
3572
3573        ca = ph_locate_call(je, 0);
3574        if (!ca) {
3575                return;
3576        }
3577       
3578        rca = ph_locate_call_by_cid(ca->rcid);
3579        info.vlid = ca->vlid;
3580        info.userData = je->external_reference;
3581        info.localUri = je->local_uri;
3582
3583        if (je->status_code == 600)
3584        {
3585                info.event = phCALLBUSY;
3586                info.u.remoteUri = je->remote_uri;
3587
3588                owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_BUSY, ca->remote_uri, 0);
3589        }
3590        else
3591        {
3592                info.event = phCALLERROR;
3593                info.u.errorCode = je->status_code;
3594
3595                owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_NETWORK, ca->remote_uri, 0);
3596        }
3597
3598        if (phcb->callProgress) {
3599                phcb->callProgress(ca->cid, &info);
3600        }
3601
3602        if (rca)
3603        {
3604                ph_refer_notify(rca->rdid, je->status_code, "Global failure", 1);
3605        }
3606
3607        DBG_SIP_NEGO("release calls");
3608        ph_release_call(ca);
3609}
3610
3611void
3612ph_call_noanswer(eXosip_event_t *je)
3613{
3614        phCallStateInfo_t info;
3615        phcall_t *ca, *rca=0;
3616
3617        clear(info);
3618
3619        ca = ph_locate_call(je, 1);
3620
3621        if (!ca)
3622        {
3623                return;
3624        }
3625        rca = ph_locate_call_by_cid(ca->rcid);
3626        info.vlid = ca->vlid;
3627        info.userData = je->external_reference;
3628        info.event = phNOANSWER;
3629        info.u.remoteUri = je->remote_uri;
3630        info.localUri = je->local_uri;
3631
3632        if (phcb->callProgress) {
3633                phcb->callProgress(ca->cid, &info);
3634        }
3635
3636        owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_NO_RESPONSE, ca->remote_uri, 0);
3637
3638        if (rca)
3639        {
3640                ph_refer_notify(rca->rdid, je->status_code, "No answer", 1);
3641        }
3642
3643        DBG_SIP_NEGO("release calls");
3644        ph_release_call(ca);
3645}
3646
3647
3648
3649void
3650ph_call_closed(eXosip_event_t *je)
3651{
3652        phCallStateInfo_t info;
3653        phcall_t *ca, *rca=0;
3654
3655        clear(info);
3656
3657        ca = ph_locate_call(je, 0);
3658        if (!ca)
3659        {
3660                return;
3661        }
3662
3663        rca = ph_locate_call_by_cid(ca->rcid);
3664        info.vlid = ca->vlid;
3665        DBG_SIP_NEGO("release calls");
3666       
3667        info.userData = je->external_reference;
3668        info.event = phCALLCLOSED;
3669        info.u.errorCode = 0;
3670        if (phcb->callProgress) {
3671                phcb->callProgress(ca->cid, &info);
3672        }
3673        owplFireCallEvent(ca->cid, CALLSTATE_DISCONNECTED, CALLSTATE_DISCONNECTED_NORMAL, ca->remote_uri, 0);
3674
3675        if (rca)
3676        {
3677                ph_refer_notify(rca->rdid, je->status_code, "Closed", 1);
3678        }
3679        ph_release_call(ca);
3680}
3681
3682/**
3683* @brief callback called by the exosip layer when a call is on hold
3684*/
3685void
3686ph_call_onhold(eXosip_event_t *je)
3687{
3688        phCallStateInfo_t info;
3689        phcall_t *ca;
3690
3691        DBG_SIP_NEGO("SIP_NEGO: ph_call_onhold\n");
3692        clear(info);
3693
3694        // locate the corresponding call for this event
3695        ca = ph_locate_call(je, 0);
3696        if (!ca)
3697        {
3698                return;
3699        }
3700
3701        info.vlid = ca->vlid;
3702        if (ph_call_hasaudio(ca))
3703        {
3704#ifndef MEDIA_SUSPEND
3705                ph_call_media_stop(ca);
3706#else
3707                ph_call_media_suspend(ca, 0);
3708#endif
3709        }
3710
3711        ca->remotehold = 1;
3712        info.userData = je->external_reference;
3713        info.event = phCALLHELD;
3714
3715        if (phcb->callProgress) {
3716                phcb->callProgress(ca->cid, &info);
3717        }
3718
3719        owplFireCallEvent(ca->cid, CALLSTATE_HOLD, CALLSTATE_HOLD_STARTED, ca->remote_uri, 0);
3720}
3721
3722void
3723ph_call_offhold(eXosip_event_t *je)
3724{
3725        phCallStateInfo_t info;
3726        phcall_t *ca;
3727        int cng=0;
3728        int remhold;
3729
3730        DBG_SIP_NEGO("SIP NEGO: ph_call_offhold\n");
3731
3732        ca = ph_locate_call(je, 0);
3733        if (!ca)
3734        {
3735                return;
3736        }
3737
3738        clear(info);
3739
3740        info.vlid = ca->vlid;
3741        // ph_media_resume(ca);
3742
3743        //  if (ph_call_hasaudio(ca))
3744        //      ph_media_stop(ca);
3745
3746        remhold = ca->remotehold;
3747        ca->remotehold = 0;
3748
3749        ph_call_retrieve_payloads(ca, je, -1);
3750        ph_call_media_start(ca, je, remhold);
3751
3752        if (remhold)
3753        {
3754                info.userData = je->external_reference;
3755                info.event = phCALLRESUMED;
3756                info.streams = ca->nego_mflags;
3757
3758                if (phcb->callProgress) {
3759                        phcb->callProgress(ca->cid, &info);
3760                }
3761                owplFireCallEvent(ca->cid, CALLSTATE_HOLD, CALLSTATE_HOLD_RESUMED, ca->remote_uri, 0);
3762        }
3763
3764        ca->remotehold = 0;
3765}
3766
3767 static char *remove_brackets(char *uri)
3768 {
3769   char *lb = strchr(uri, '<');
3770   char *rb;
3771
3772   if (!lb)
3773     return uri;
3774   lb++;
3775   rb = strchr(lb, '>');
3776   if (rb)
3777     *rb = 0;
3778   return lb;
3779}
3780
3781
3782/*
3783 * scan list of Contact headers, find a contact which matches given virtual line
3784 * and update the registration expiration timeout from the value of "expires" parameter
3785 * of the contact header
3786 */
3787static void ph_update_expiration_for_contact(phVLine *vl,  osip_list_t *ctcts)
3788{
3789  char vlcontact[256], *vlc;
3790  osip_contact_t *ct;
3791  int i;
3792  char *uristr = 0;
3793
3794  owsip_account_contact_get(vl->sipAccount, vlcontact, sizeof(vlcontact));
3795  vlc = remove_brackets(vlcontact);
3796  i = 0;
3797  while((ct = (osip_contact_t*) osip_list_get(ctcts, i++)))
3798    {
3799      osip_uri_t *cturi = osip_contact_get_url(ct);
3800      if (cturi)
3801        {
3802
3803          osip_uri_to_str(cturi, &uristr);
3804          if (!strcmp(vlc, uristr))
3805            {
3806              osip_uri_param_t *param;
3807
3808              if (!osip_contact_param_get_byname(ct, "expires", &param))
3809                vl->regTimeout = atoi(param->gvalue);
3810
3811              break;
3812            }
3813          osip_free(uristr);
3814          uristr = 0;
3815        }
3816    }
3817
3818  if (uristr)
3819    {
3820      osip_free(uristr);
3821    }
3822
3823}
3824
3825
3826
3827 
3828void ph_reg_progress(eXosip_event_t *je)
3829{
3830        int i;
3831        phVLine *vl = 0;
3832        int vlid;
3833        int mask = 0;
3834
3835        vl =  ph_find_vline_by_rid(je->rid);
3836
3837        if (!vl)
3838        {
3839                return;
3840        }
3841
3842        if (vl->LineState == LINESTATE_UNREGISTERING || 
3843                        vl->LineState == LINESTATE_DELETING)
3844        {
3845                mask = PH_UNREG_MASK;
3846        }
3847        vlid = ph_vline2vlid(vl);
3848
3849        DBG_SIP_NEGO("REGPROGRESS reg=%d for vlid=%d\n", je->rid, vlid);
3850
3851        if (je->type == EXOSIP_REGISTRATION_SUCCESS)
3852        {
3853                if (vl->LineState == LINESTATE_UNREGISTERING
3854                                 || vl->LineState == LINESTATE_UNREGISTER_FAILED
3855                                 || vl->LineState == LINESTATE_DELETING)
3856                {
3857                        _owplLineSetState(vlid, LINESTATE_UNREGISTERED, LINESTATE_CAUSE_NORMAL);
3858                }
3859                else {
3860                        if (je->expires) {
3861                                vl->regTimeout = je->expires;
3862                        }
3863                        else
3864                          {
3865                            osip_message_t *ans;
3866                            if (!eXosip_register_answer_get(je->rid, &ans))
3867                              ph_update_expiration_for_contact(vl, &ans->contacts);
3868                          }
3869                        _owplLineSetState(vlid, LINESTATE_REGISTERED, LINESTATE_CAUSE_NORMAL);
3870                }
3871
3872                if (phcb->regProgress) {
3873                        phcb->regProgress(vlid, 0 | mask);
3874                }
3875
3876                //if (vl->used == VL_DELETING)
3877                if (vl->LineState == LINESTATE_DELETING)
3878                {
3879                        if (owsip_account_free (vl->sipAccount))
3880                        {
3881                                return -1 ;
3882                        }
3883                        vline_free(vl);
3884                }
3885        }
3886        else if (je->type == EXOSIP_REGISTRATION_FAILURE)
3887        {
3888                int newtimeout = -1;
3889                OWPL_LINESTATE_EVENT reg_event = LINESTATE_REGISTER_FAILED;
3890
3891                if (mask & PH_UNREG_MASK) {
3892                        reg_event = LINESTATE_UNREGISTER_FAILED;
3893                }
3894
3895                if (je->status_code == 423)  /* Interval to brief */
3896                {
3897                        if (je->minexpires)
3898                        {
3899                                vl->regTimeout = newtimeout = je->minexpires;
3900                        }
3901                }
3902
3903                if (je->status_code == 401 || je->status_code == 407 || (newtimeout > 0))
3904                {
3905                        eXosip_lock();
3906                        i = eXosip_register(je->rid, newtimeout);
3907                        eXosip_unlock();
3908
3909                        SKIP(printf("Retrying reg=%d for vlid=%d i=%d t=%d\n", je->rid, vlid, i, newtimeout))
3910                                if (i == 0)
3911                                {
3912                                        return;
3913                                }
3914                }
3915
3916                if (phcb->regProgress) {
3917                        phcb->regProgress(vlid, mask | (je->status_code ? je->status_code : 500) );
3918                }
3919
3920                switch(je->status_code) {
3921                        case 403:
3922                        case 407: /* 407 is Proxy Authentication Required (returned by some Nortel server) */
3923                                _owplLineSetState(vlid, reg_event , LINESTATE_CAUSE_NOT_AUTHORIZED);
3924                                break;
3925                        case 404:
3926                                _owplLineSetState(vlid, reg_event , LINESTATE_CAUSE_NOT_FOUND );
3927                                break;
3928                        case 408:
3929                                _owplLineSetState(vlid, reg_event , LINESTATE_CAUSE_TIMEOUT);
3930                                break;
3931                        default:
3932                                _owplLineSetState(vlid, reg_event , LINESTATE_CAUSE_COULD_NOT_CONNECT);
3933                                break;
3934                }
3935
3936                if (vl->LineState == LINESTATE_DELETING)
3937                {
3938                        if (owsip_account_free (vl->sipAccount))
3939                        {
3940                                return -1 ;
3941                        }
3942                        vline_free(vl);
3943                }
3944        }
3945}
3946
3947static int str2lower(char *str)
3948{
3949        if (str == NULL || *str == '\0')
3950        {
3951                return -1;
3952        }
3953
3954        while (str && *str)
3955        {
3956                if (*str >= 'A' && *str <= 'Z')
3957                {
3958                        *str = (char) tolower((int) *str);
3959                }
3960                str++;
3961        }
3962
3963        return 0;
3964}
3965
3966void ph_notify_handler(eXosip_event_t *je)
3967{
3968        char status[16];
3969
3970        // TODO REFACTOR REMOVE
3971        if (phcb->onNotify)
3972        {
3973                phcb->onNotify(je->sip_event, je->remote_uri, je->msg_body);
3974        }
3975
3976        str2lower(je->msg_body);
3977
3978        if (strcmp(je->sip_event, "presence") == 0) {
3979                if(owplNotificationPresenceGetStatus(je->msg_body, status, sizeof(status)) == OWPL_RESULT_SUCCESS) {
3980                        if(strcmp(status, "open") == 0) {
3981                                owplFireNotificationEvent(NOTIFICATION_PRESENCE, NOTIFICATION_PRESENCE_ONLINE, je->msg_body, je->remote_uri);
3982                        } else if(strcmp(status, "closed") == 0){
3983                                owplFireNotificationEvent(NOTIFICATION_PRESENCE, NOTIFICATION_PRESENCE_OFFLINE, je->msg_body, je->remote_uri);
3984                        } else {
3985                                owplFireNotificationEvent(NOTIFICATION_UNKNOWN, NOTIFICATION_PARSE_ERROR, je->msg_body, je->remote_uri);
3986                        }
3987                }
3988        } else if (strcmp(je->sip_event, "presence.winfo") == 0) {
3989                owplFireNotificationEvent(NOTIFICATION_PRESENCE, NOTIFICATION_PRESENCE_WATCHER, je->msg_body, je->remote_uri);
3990        } else if (strcmp(je->sip_event, "message-summary") == 0) {
3991                owplFireNotificationEvent(NOTIFICATION_MWI, NOTIFICATION_CAUSE_UNKNOWN, je->msg_body, je->remote_uri);
3992        } else {
3993                owplFireNotificationEvent(NOTIFICATION_UNKNOWN, NOTIFICATION_CAUSE_UNKNOWN, je->msg_body, je->remote_uri);
3994        }
3995}
3996
3997
3998void ph_call_refered(eXosip_event_t *je)
3999{
4000        phcall_t *ca;
4001        phCallStateInfo_t info;
4002        phVLine *vl = 0;
4003
4004        DBG_SIP_NEGO("SIP_NEGO: ph_call_refered\n");
4005
4006        //ca = ph_locate_call_by_cid(je->cid);
4007        ca = ph_locate_call(je, 0);
4008
4009        if (ca)
4010        {
4011                vl = ph_valid_vlid(ca->vlid);
4012        }
4013
4014        /*
4015        we're rejecting the requests refering unxisting calls, vlines and
4016        if we detect URI loop
4017        */
4018        if (!ca || !vl || ph_find_matching_vline(je->refer_to, 0))
4019        {
4020                eXosip_lock();
4021                eXosip_answer_refer(je->did, (!ca) ? 481 : 488);
4022                eXosip_unlock();
4023                return;
4024        }
4025
4026        eXosip_lock();
4027        eXosip_answer_refer(je->did, 202);
4028        eXosip_unlock();
4029
4030        clear(info);
4031        ca->rdid = je->did;
4032
4033        ph_call_media_stop(ca);
4034
4035        info.newcid = phLinePlaceCall2(ca->vlid, je->refer_to,  0, ca->cid, ca->user_mflags);
4036
4037        info.event = phXFERREQ;
4038        info.u.remoteUri = je->refer_to;
4039        info.vlid = ca->vlid;
4040
4041        if (phcb->callProgress) {
4042                phcb->callProgress(ca->cid, &info);
4043        }
4044
4045        owplFireCallEvent(ca->cid,
4046                CALLSTATE_TRANSFER,
4047                CALLSTATE_TRANSFER_INITIATED,
4048                je->remote_contact,
4049                0);
4050}
4051
4052
4053void ph_call_refer_status(eXosip_event_t *je)
4054{
4055        phcall_t *ca;
4056        phCallStateInfo_t info;
4057        int cheat = 0;
4058        const char *resultstr;
4059        int status = 0;
4060        int txcid;
4061
4062        //ca = ph_locate_call_by_cid(je->cid);
4063        ca = ph_locate_call(je, 0);
4064
4065        if (!ca)
4066        {
4067                return;
4068        }
4069
4070        clear(info);
4071
4072        if (je->type == EXOSIP_CALL_REFER_STATUS)
4073        {
4074                DBG_SIP_NEGO("refer_status sdp=%s\n", je->msg_body);
4075
4076                if (je->ss_status == EXOSIP_SUBCRSTATE_TERMINATED)
4077                {
4078                        /* cheat and suppose that the transfer succeeded */
4079                        cheat  = 200;
4080                }
4081
4082                resultstr = strchr(je->msg_body, ' ');
4083
4084                if (resultstr)
4085                {
4086                        status = atoi(resultstr);
4087                }
4088        }
4089        else
4090        {
4091                status = je->status_code;
4092        }
4093
4094        if (!status)
4095        {
4096                if (!cheat)
4097                {
4098                        return;
4099                }
4100
4101                status = cheat;
4102        }
4103
4104        if ((status < 200) && cheat)
4105        {
4106                status = cheat;
4107        }
4108
4109        info.u.errorCode = status;
4110        info.vlid = ca->vlid;
4111
4112        if (!ca->txcid && status == 180)
4113        {
4114                /* blind transfer:  RINGING is good enough for us */
4115                info.event = phXFEROK;
4116
4117                owplFireCallEvent(ca->cid,
4118                CALLSTATE_TRANSFER,
4119                CALLSTATE_TRANSFER_ACCEPTED,
4120                je->remote_contact,
4121                0);
4122        }
4123        else if (status < 200 && status >= 100)
4124        {
4125                info.event = phXFERPROGRESS;
4126
4127                owplFireCallEvent(ca->cid,
4128                CALLSTATE_TRANSFER,
4129                CALLSTATE_TRANSFER_TRYING,
4130                je->remote_contact,
4131                0);
4132        }
4133        else if (status >= 200 && status < 300)
4134        {
4135                info.event = phXFEROK;
4136
4137                owplFireCallEvent(ca->cid,
4138                CALLSTATE_TRANSFER,
4139                CALLSTATE_TRANSFER_ACCEPTED,
4140                je->remote_contact,
4141                0);
4142        }
4143        else
4144        {
4145                info.event = phXFERFAIL;
4146
4147                owplFireCallEvent(ca->cid,
4148                CALLSTATE_TRANSFER,
4149                CALLSTATE_TRANSFER_FAILURE,
4150                je->remote_contact,
4151                0);
4152        }
4153
4154        txcid = ca->txcid;
4155
4156        if(phcb->callProgress) {
4157                phcb->callProgress(ca->cid, &info);
4158        }
4159
4160        if (info.event == phXFEROK || info.event == phXFERFAIL)
4161        {
4162                if (txcid > 0)          /* assisted transfer, close both calls  */
4163                {
4164                        phCloseCall(txcid);
4165                }
4166                if (ca->cid > 0)        /* assisted or blind transfer, close call  */
4167                {
4168                        phCloseCall(ca->cid);
4169                }
4170        }
4171}
4172
4173void ph_message_progress(eXosip_event_t *je)
4174{
4175        phMsgStateInfo_t info;
4176
4177        if(je != NULL) {
4178                memset(&info, 0, sizeof(info));
4179
4180                if (je->type == EXOSIP_MESSAGE_NEW)
4181                {
4182                        info.event = phMsgNew;
4183                        info.content = je->msg_body;
4184                        info.ctype = je->i_ctt->type;
4185                        info.subtype = je->i_ctt->subtype;
4186                        info.to = je->local_uri;
4187                        info.from = je->remote_uri;
4188                        if (phcb->msgProgress != NULL)
4189                        {
4190                                phcb->msgProgress(0, &info);
4191                        }
4192                        owplFireMessageEvent(MESSAGE_NEW,
4193                                MESSAGE_NEW_NORMAL,
4194                                je->mid,
4195                                ph_vline_get_id_from_event(je),
4196                                je->msg_body,
4197                                je->local_uri,
4198                                je->remote_uri,
4199                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4200                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4201                }
4202                else if (je->type == EXOSIP_MESSAGE_SUCCESS)
4203                {
4204                        info.event = phMsgOk;
4205                        info.to = je->local_uri;
4206                        info.from = je->remote_uri;
4207                        if (phcb->msgProgress != NULL)
4208                        {
4209                                phcb->msgProgress(je->mid, &info);
4210                        }
4211                        owplFireMessageEvent(MESSAGE_SUCCESS,
4212                                MESSAGE_SUCCESS_NORMAL,
4213                                je->mid,
4214                                ph_vline_get_id_from_event(je),
4215                                je->msg_body,
4216                                je->local_uri,
4217                                je->remote_uri,
4218                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4219                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4220                }
4221                else if (je->type == EXOSIP_MESSAGE_FAILURE)
4222                {
4223                        info.to = je->local_uri;
4224                        info.from = je->remote_uri;
4225                        info.event = phMsgError;
4226                        if (phcb->msgProgress != NULL)
4227                        {
4228                                phcb->msgProgress(je->mid, &info);
4229                        }
4230                        owplFireMessageEvent(MESSAGE_FAILURE,
4231                                MESSAGE_FAILURE_UNKNOWN,
4232                                je->mid,
4233                                ph_vline_get_id_from_event(je),
4234                                je->msg_body,
4235                                je->local_uri,
4236                                je->remote_uri,
4237                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4238                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4239                }
4240        }
4241}
4242
4243/*
4244TODO for future use ?
4245void ph_message_progress(eXosip_event_t *je)
4246{
4247        phMsgStateInfo_t info;
4248
4249        if(je != NULL) {
4250                memset(&info, 0, sizeof(info));
4251
4252                if (je->type == EXOSIP_MESSAGE_NEW)
4253                {
4254                        info.event = phMsgNew;
4255                        info.content = je->msg_body;
4256                        info.ctype = je->i_ctt->type;
4257                        info.subtype = je->i_ctt->subtype;
4258                        info.to = je->local_uri;
4259                        info.from = je->remote_uri;
4260                        if (phcb->msgProgress != NULL)
4261                        {
4262                                phcb->msgProgress(0, &info);
4263                        }
4264
4265                        if(je->i_ctt != NULL && strcmp(je->i_ctt->type, "typingstate") == 0) {
4266                                if(strcmp(je->i_ctt->subtype, "typing") == 0) {
4267                                        owplFireMessageEvent(MESSAGE_NEW,
4268                                                MESSAGE_NEW_TYPING,
4269                                                je->mid,
4270                                                ph_vline_get_id_from_event(je),
4271                                                je->msg_body,
4272                                                je->local_uri,
4273                                                je->remote_uri,
4274                                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4275                                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4276                                } else if(strcmp(je->i_ctt->subtype, "stoptyping") == 0) {
4277                                        owplFireMessageEvent(MESSAGE_NEW,
4278                                                MESSAGE_NEW_STOP_TYPING,
4279                                                je->mid,
4280                                                ph_vline_get_id_from_event(je),
4281                                                je->msg_body,
4282                                                je->local_uri,
4283                                                je->remote_uri,
4284                                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4285                                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4286                                } else {
4287                                        owplFireMessageEvent(MESSAGE_NEW,
4288                                                MESSAGE_NEW_NOT_TYPING,
4289                                                je->mid,
4290                                                ph_vline_get_id_from_event(je),
4291                                                je->msg_body,
4292                                                je->local_uri,
4293                                                je->remote_uri,
4294                                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4295                                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4296                                }
4297                        } else if(je->i_ctt != NULL && strcmp(je->i_ctt->type, "buddyicon") == 0) {
4298                                owplFireMessageEvent(MESSAGE_NEW,
4299                                        MESSAGE_NEW_BUDDY_ICON,
4300                                        je->mid,
4301                                        ph_vline_get_id_from_event(je),
4302                                        je->msg_body,
4303                                        je->local_uri,
4304                                        je->remote_uri,
4305                                        (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4306                                        (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4307                        } else {
4308                                owplFireMessageEvent(MESSAGE_NEW,
4309                                        MESSAGE_NEW_NORMAL,
4310                                        je->mid,
4311                                        ph_vline_get_id_from_event(je),
4312                                        je->msg_body,
4313                                        je->local_uri,
4314                                        je->remote_uri,
4315                                        (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4316                                        (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4317                        }
4318                }
4319                else if (je->type == EXOSIP_MESSAGE_SUCCESS)
4320                {
4321                        info.event = phMsgOk;
4322                        info.to = je->local_uri;
4323                        info.from = je->remote_uri;
4324                        if (phcb->msgProgress != NULL)
4325                        {
4326                                phcb->msgProgress(je->mid, &info);
4327                        }
4328
4329                        owplFireMessageEvent(MESSAGE_SUCCESS,
4330                                MESSAGE_SUCCESS_NORMAL,
4331                                NULL,
4332                                je->mid,
4333                                ph_vline_get_id_from_event(je),
4334                                je->local_uri,
4335                                je->remote_uri,
4336                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4337                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4338                }
4339                else if (je->type == EXOSIP_MESSAGE_FAILURE)
4340                {
4341                        info.to = je->local_uri;
4342                        info.from = je->remote_uri;
4343                        info.event = phMsgError;
4344                        if (phcb->msgProgress != NULL)
4345                        {
4346                                phcb->msgProgress(je->mid, &info);
4347                        }
4348
4349                        owplFireMessageEvent(MESSAGE_FAILURE,
4350                                MESSAGE_FAILURE_COULD_NOT_SEND,
4351                                NULL,
4352                                je->mid,
4353                                ph_vline_get_id_from_event(je),
4354                                je->local_uri,
4355                                je->remote_uri,
4356                                (je->i_ctt != NULL) ? je->i_ctt->type : NULL,
4357                                (je->i_ctt != NULL) ? je->i_ctt->subtype : NULL);
4358                }
4359        }
4360}
4361*/
4362
4363
4364void ph_subscription_progress(eXosip_event_t *je)
4365{
4366        phSubscriptionStateInfo_t info;
4367
4368        memset(&info, 0, sizeof(info));
4369
4370        if (je->type == EXOSIP_SUBSCRIPTION_ANSWERED)
4371        {
4372                info.event = phSubscriptionOk;
4373                info.from = je->local_uri;
4374                info.to = je->remote_uri;
4375
4376                if (phcb->subscriptionProgress != NULL)
4377                {
4378                        phcb->subscriptionProgress (je->sid, &info);
4379                }
4380
4381                owplFireSubscriptionEvent(je->sid, OWPL_SUBSCRIPTION_ACTIVE, SUBSCRIPTION_CAUSE_NORMAL, je->remote_uri, 0);
4382        }
4383        else if (je->type == EXOSIP_SUBSCRIPTION_REQUESTFAILURE)
4384        {
4385                if (je->status_code == 481) {
4386                    char proxyBuf[256];
4387                    int n = sizeof(proxyBuf);
4388
4389                    owplLineGetProxy(ph_vline_get_id_from_event(je), proxyBuf, &n);
4390                    eXosip_lock();
4391                    eXosip_subscribe_retry(je->sid, proxyBuf);
4392                    eXosip_unlock();
4393                    return;
4394                }
4395                info.event = phSubscriptionError;
4396                if (je->status_code == 404) {
4397                        info.event = phSubscriptionErrNotFound;
4398                }
4399
4400                info.from = je->local_uri;
4401                info.to = je->remote_uri;
4402                if (phcb->subscriptionProgress != NULL)
4403                {
4404                        phcb->subscriptionProgress (je->sid, &info);
4405                }
4406
4407                owplFireSubscriptionEvent(je->sid, OWPL_SUBSCRIPTION_FAILED, SUBSCRIPTION_CAUSE_UNKNOWN, je->remote_uri, 0);
4408        }
4409}
4410
4411
4412void ph_incoming_subscribe(eXosip_event_t *je)
4413{
4414  phSubscriptionStateInfo_t info;
4415  OWPL_SUBSCRIPTION_STATE state;
4416  OWPL_SUBSCRIPTION_CAUSE cause;
4417
4418  info.event = phSubscriptionOk;
4419
4420  info.from = je->remote_uri;
4421  info.to = je->local_uri;
4422  info.evtType = je->sip_event;
4423  info.timeout = je->expires;
4424
4425  switch(je->type)
4426    {
4427    case EXOSIP_IN_SUBSCRIPTION_NEW:
4428      info.event = phSubscriptionIn;
4429      state = OWPL_INSUBSCRIPTION_NEW;
4430      cause = SUBSCRIPTION_CAUSE_NORMAL;
4431      break;
4432
4433    case EXOSIP_IN_SUBSCRIPTION_RELEASED:
4434      info.event = phSubscriptionInClosed;
4435      state = OWPL_INSUBSCRIPTION_CLOSE;
4436      cause = SUBSCRIPTION_CAUSE_NORMAL;
4437      break;
4438
4439    default:
4440      break;
4441    } 
4442   
4443  if ((info.event != phSubscriptionOk))
4444    {
4445      if (phcb->subscriptionProgress)
4446        phcb->subscriptionProgress (je->did, &info);
4447     
4448      owplFireSubscriptionEvent(je->did, state, cause, je->remote_uri, info.evtType);
4449    }
4450}
4451
4452
4453static int ph_process_call_event_default(eXosip_event_t * je) {
4454
4455        switch(je->type) {
4456                case EXOSIP_CALL_NEW:
4457                        ph_call_new(je);
4458                        break;
4459
4460                case EXOSIP_CALL_ANSWERED:
4461                        ph_callStopRinging(je);
4462                        ph_call_answered(je);
4463                        break;
4464
4465                case EXOSIP_CALL_PROCEEDING:
4466                        ph_call_proceeding(je);
4467                        break;
4468
4469                case EXOSIP_CALL_RINGING:
4470                        ph_call_ringing(je);
4471                        break;
4472
4473                case EXOSIP_CALL_REDIRECTED:
4474                        ph_call_redirected(je);
4475                        break;
4476
4477                case EXOSIP_CALL_REPLACES:
4478                        ph_call_replaces(je);
4479                        break;
4480
4481                case EXOSIP_CALL_REQUESTFAILURE:
4482                        ph_call_requestfailure(je);
4483                        break;
4484
4485                case EXOSIP_CALL_SERVERFAILURE:
4486                        ph_call_serverfailure(je);
4487                        break;
4488
4489                case EXOSIP_CALL_GLOBALFAILURE:
4490                        ph_call_globalfailure(je);
4491                        break;
4492
4493                case EXOSIP_CALL_NOANSWER:
4494                        ph_call_noanswer(je);
4495                        break;
4496
4497                case EXOSIP_CALL_CLOSED:
4498                        ph_call_closed(je);
4499                        break;
4500
4501                case EXOSIP_CALL_HOLD:
4502                        ph_call_onhold(je);
4503                        break;
4504
4505                case EXOSIP_CALL_OFFHOLD:
4506                        ph_call_offhold(je);
4507                        break;
4508
4509                case EXOSIP_REGISTRATION_SUCCESS:
4510                        ph_reg_progress(je);
4511                        break;
4512
4513                case EXOSIP_REGISTRATION_FAILURE:
4514                        ph_reg_progress(je);
4515                        break;
4516
4517                case EXOSIP_CALL_REFERED:
4518                        ph_call_refered(je);
4519                        break;
4520
4521                case EXOSIP_CALL_REFER_STATUS:
4522                case EXOSIP_CALL_REFER_FAILURE:
4523                        ph_call_refer_status(je);
4524                        break;
4525
4526
4527                case EXOSIP_MESSAGE_NEW:
4528                case EXOSIP_MESSAGE_SUCCESS:            /* announce a 200ok to a previous sent */
4529                case EXOSIP_MESSAGE_FAILURE:
4530                        ph_message_progress(je);
4531                        break;
4532
4533
4534                case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:
4535                case EXOSIP_SUBSCRIPTION_ANSWERED:
4536                        ph_subscription_progress(je);
4537                        break;
4538
4539                case EXOSIP_SUBSCRIPTION_NOTIFY:
4540                        ph_notify_handler(je);
4541                        break;
4542
4543                case EXOSIP_OPTIONS_NOANSWER:
4544                        return -2;
4545
4546                case EXOSIP_ENGINE_STOPPED:
4547                        return -2;
4548
4549                default:
4550                        if(phDebugLevel > 0) {
4551                                DBG_SIP_NEGO("event(%i %i %i %i) text=%s\n", je->cid, je->sid, je->nid, je->did, je->textinfo);
4552                        }
4553                        break;
4554        }
4555
4556        return 0;
4557}
4558
4559
4560/**
4561* Tests if an event is a call event.
4562*
4563* @param        [in]    je : an eXosip event
4564* @return       TRUE if it is a call event; FALSE else
4565*/
4566static unsigned int isCallEvent(eXosip_event_t * je){
4567        if(je->type == EXOSIP_CALL_NEW ||
4568                je->type == EXOSIP_CALL_ANSWERED ||
4569                je->type == EXOSIP_CALL_PROCEEDING ||
4570                je->type == EXOSIP_CALL_RINGING ||
4571                je->type == EXOSIP_CALL_REDIRECTED ||
4572                je->type == EXOSIP_CALL_REPLACES ||
4573                je->type == EXOSIP_CALL_REQUESTFAILURE ||
4574                je->type == EXOSIP_CALL_SERVERFAILURE ||
4575                je->type == EXOSIP_CALL_GLOBALFAILURE ||
4576                je->type == EXOSIP_CALL_NOANSWER ||
4577                je->type == EXOSIP_CALL_CLOSED ||
4578                je->type == EXOSIP_CALL_HOLD ||
4579                je->type == EXOSIP_CALL_OFFHOLD ||
4580                je->type == EXOSIP_CALL_REFERED ||
4581                je->type == EXOSIP_CALL_REFER_STATUS ||
4582                je->type == EXOSIP_CALL_REFER_FAILURE)
4583        {
4584                return TRUE;
4585        }
4586        return FALSE;
4587}
4588
4589static void ph_update_callstate_by_event(eXosip_event_t * je)
4590{
4591        phcall_t * rca;
4592        phcall_t * ca = ph_locate_call(je, 0);
4593        if (!ca) {
4594                return;
4595        }
4596        rca = ph_locate_call_by_rcid(ca->rcid);
4597
4598        switch(je->type){
4599                        case EXOSIP_CALL_NEW:
4600                                break;
4601
4602                        case EXOSIP_CALL_ANSWERED:
4603                                ca->did = je->did;
4604                                if(rca){
4605                                        ph_refer_notify(rca->rdid, je->status_code, "Answered", 1);
4606                                }
4607                                break;
4608
4609                        case EXOSIP_CALL_PROCEEDING:
4610                                if(rca){
4611                                        ph_refer_notify(rca->rdid, je->status_code, "Proceeding", 0);
4612                                }
4613                                break;
4614
4615                        case EXOSIP_CALL_RINGING:
4616                                if (rca){
4617                                        ph_refer_notify(rca->rdid, 180, "Ringing", 0);
4618                                }
4619                                break;
4620
4621                        case EXOSIP_CALL_REDIRECTED:
4622                                break;
4623
4624                        case EXOSIP_CALL_REPLACES:
4625                                break;
4626
4627                        case EXOSIP_CALL_REQUESTFAILURE:
4628                                if(rca) {
4629                                        ph_refer_notify(rca->rdid, je->status_code, je->status_code == 486 ? "Busy" : "Request failure", 1);
4630                                }
4631                                DBG_SIP_NEGO("release calls");
4632                                ph_release_call(ca);
4633                                break;
4634
4635                        case EXOSIP_CALL_SERVERFAILURE:
4636                                if(rca) {
4637                                        ph_refer_notify(rca->rdid, je->status_code, "Server failure", 1);
4638                                }
4639                                DBG_SIP_NEGO("release calls");
4640                                ph_release_call(ca);
4641                                break;
4642
4643                        case EXOSIP_CALL_GLOBALFAILURE:                         
4644                                if(rca) {
4645                                        ph_refer_notify(rca->rdid, je->status_code, "Global failure", 1);
4646                                }
4647                                DBG_SIP_NEGO("release calls");
4648                                ph_release_call(ca);
4649                                break;
4650
4651                        case EXOSIP_CALL_NOANSWER:
4652                                if(rca) {
4653                                        ph_refer_notify(rca->rdid, je->status_code, "No answer", 1);
4654                                }
4655                                DBG_SIP_NEGO("release calls");
4656                                ph_release_call(ca);
4657                                break;
4658
4659                        case EXOSIP_CALL_CLOSED:
4660                                if(rca) {
4661                                        ph_refer_notify(rca->rdid, je->status_code, "Closed", 1);
4662                                }
4663                                DBG_SIP_NEGO("release calls");
4664                                ph_release_call(ca);
4665                                break;
4666
4667                        case EXOSIP_CALL_HOLD:
4668                                break;
4669
4670                        case EXOSIP_CALL_OFFHOLD:
4671                                break;
4672
4673                        case EXOSIP_CALL_REFERED:
4674                                break;
4675
4676                        case EXOSIP_CALL_REFER_STATUS:
4677                                break;
4678
4679                        case EXOSIP_CALL_REFER_FAILURE:
4680                                break;
4681
4682                        default:
4683                                break;
4684        }
4685}
4686
4687/**
4688* Retrieves eXosip events
4689*
4690* @return       0 if there has been events; -1 if there were no events
4691*/
4692static int ph_event_get(){
4693        int counter =0;
4694        /* use events to print some info */
4695        eXosip_event_t *je;
4696        /*variables to handle OWPL plugin framework*/
4697        OWPL_PLUGIN *owplPlugin;
4698        char buf[101];
4699        phcall_t * ca = NULL;
4700
4701        for (;;) {
4702                je = eXosip_event_wait(0,phWaitTimeout);
4703                if(je==NULL) {
4704                        break;
4705                }
4706                counter++;
4707
4708                if(phDebugLevel > 0) {
4709                        ph_printf("\n<- %s (%i %i) [%i %s] %s requri=%s\n",
4710                                evtnames[je->type], je->cid, je->did,
4711                                je->status_code,
4712                                je->reason_phrase,
4713                                je->remote_uri,
4714                                je->req_uri);
4715                }
4716
4717                // get the plugin corresponding to that content-type
4718                if(isCallEvent(je)) {
4719                        if((ca = ph_locate_call(je, je->type == EXOSIP_CALL_NEW ? 1 : 0)) == NULL) {
4720                                return -1;
4721                        }
4722
4723                        if( ca && (ca->owplPlugin == 0)) {
4724                                if(je->i_ctt && je->i_ctt->type) {
4725                                        strncpy(buf, je->i_ctt->type, sizeof(buf)-1);
4726                                        if (je->i_ctt->subtype) {
4727                                                strncat(buf, "/", sizeof(buf) - strlen(buf) -1);
4728                                                strncat(buf,je->i_ctt->subtype, sizeof(buf) - strlen(buf) - 1);
4729                                        }
4730                                        owplPlugin = owplGetPlugin4ContentType(buf);
4731                                        if (owplPlugin) {
4732                                                ca->owplPlugin = owplPlugin;
4733                                        }
4734                                }
4735                        }
4736
4737                        if(ca->owplPlugin == NULL) {
4738                                ph_process_call_event_default(je);
4739                        } else {
4740                                owplFireExosipCallEvent(je);
4741                        }
4742
4743            // beware here to the fact that events have already been fired to the top-level-program.
4744            // If the TLP is highly "stimulus-response" reactive (fast to react), this may lead to problems
4745            // The problem was identified once for the 3-way conference mechanism when the phResume was called
4746            // as soon as the phHoldOK had been sent. cf REV 10978 for a bugfix example (jwa)
4747                        ph_update_callstate_by_event(je);
4748           
4749           
4750                }else{
4751                        switch(je->type){
4752                                case EXOSIP_REGISTRATION_SUCCESS:
4753                                        ph_reg_progress(je);
4754                                        break;
4755
4756                                case EXOSIP_REGISTRATION_FAILURE:
4757                                        ph_reg_progress(je);
4758                                        break;
4759
4760                                case EXOSIP_MESSAGE_NEW:
4761                                case EXOSIP_MESSAGE_SUCCESS:        /* announce a 200ok to a previous sent */
4762                                case EXOSIP_MESSAGE_FAILURE:
4763                                        ph_message_progress(je);
4764                                        break;
4765
4766                                case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:
4767                                case EXOSIP_SUBSCRIPTION_ANSWERED:
4768                                        ph_subscription_progress(je);
4769                                        break;
4770
4771                                case EXOSIP_SUBSCRIPTION_NOTIFY:
4772                                        ph_notify_handler(je);
4773                                        break;
4774
4775
4776                                case EXOSIP_IN_SUBSCRIPTION_NEW:
4777                                case EXOSIP_IN_SUBSCRIPTION_RELEASED:
4778                                        ph_incoming_subscribe(je);
4779                                        break;
4780
4781
4782                                case EXOSIP_OPTIONS_NOANSWER:
4783                                        return -2;
4784
4785                                case EXOSIP_ENGINE_STOPPED:
4786                                        return -2;
4787
4788                                default:
4789                                        if(phDebugLevel > 0) {
4790                                                ph_printf("event(%i %i %i %i) text=%s\n", je->cid, je->sid, je->nid, je->did, je->textinfo);
4791                                        }
4792                                        break;
4793                        }
4794                }
4795
4796                eXosip_event_free(je);
4797        }
4798
4799        ph_refresh_vlines();
4800        ph_scan_calls();
4801
4802        if (counter>0) {
4803                return 0;
4804        }
4805        return -1;
4806}
4807
4808static void
4809ph_keep_refreshing()
4810{
4811        time_t now;
4812        static time_t last_refresh;
4813
4814        time(&now);
4815        if (now - last_refresh > PH_REFRESH_INTERVAL)
4816        {
4817                phRefresh();
4818                last_refresh = now;
4819        }
4820        owplLinesCheck () ;
4821}
4822
4823
4824
4825/**
4826* eXosip event reader thread
4827*/
4828void *
4829ph_api_thread(void *arg)
4830{
4831        time_t t1 = 0;
4832        phIsInitialized = 1;
4833
4834#ifdef PHAPI_VIDEO_SUPPORT
4835        webcam_api_initialize();
4836#endif
4837
4838        time(&t1);
4839        while(1)
4840        {
4841#ifdef WIN32
4842                Sleep(100);
4843#endif
4844                if (!phIsInitialized)
4845                {
4846                        return 0;
4847                }
4848
4849                ph_keep_refreshing();
4850
4851                if (ph_event_get() == -2)
4852                {
4853                        if (phcb->regProgress) {
4854                                phcb->regProgress(0, -1);
4855                        }
4856                        /* TODO: line should be specified */
4857                        owplFireLineEvent(0, LINESTATE_REGISTER_FAILED, LINESTATE_CAUSE_COULD_NOT_CONNECT, 0);
4858                        //phTerminate();
4859                        break;
4860                }
4861        }
4862
4863#ifdef PHAPI_VIDEO_SUPPORT
4864        webcam_api_uninitialize();
4865#endif
4866
4867        return 0;
4868}
4869
4870#ifdef QOS_DEBUG_ENABLE
4871void phrtcp_QoS_enable_rtcp_report(int ToF)
4872{
4873        ortcp_enable_rtcp_report(ToF);
4874}
4875void phrtcp_report_set_cb(jt_rtcpCallbacks_t *cbk)
4876{
4877        ortcp_report_set_cb(cbk);
4878}
4879int phrtcp_report_begin()
4880{
4881        phrtcp_QoS_enable_rtcp_report(1);
4882        ortcp_report_begin();
4883}
4884int phrtcp_report_end()
4885{
4886        ortcp_report_end();
4887}
4888#endif /* end of QOS_DEBUG_ENABLE */
4889
4890int phLineGetSipAddress(int vlid, char buf[], int bufsize)
4891{
4892        phVLine *vl;
4893
4894        vl = ph_valid_vlid(vlid);
4895
4896        if (!vl)
4897        {
4898                return PH_BADVLID;
4899        }
4900
4901        ph_vline_get_from(buf, bufsize, vl);
4902        return 0;
4903}
4904
4905int phCrash()
4906{
4907        *(int *)0 = 0;
4908        return 1;
4909}
4910
4911void phSetDebugLevel(int level)
4912{
4913        phDebugLevel = level;
4914}
4915
4916// <ncouturier>
4917// ----- GENERIC WRAPPERS FOR PLUGINS -----
4918
4919/**
4920* Gets the local username
4921*
4922* @param        [in]    vlid : a virtual line id
4923* @return       the local username
4924*/
4925char * ph_get_username(int vlid){
4926        phVLine *vl;
4927
4928        if (!(vl = ph_valid_vlid(vlid)))
4929        {
4930                return NULL;
4931        }
4932
4933        return owsip_account_user_get (vl->sipAccount) ;
4934}
4935
4936
4937/**
4938* Gets the virtual line id associated to a user_id
4939*
4940* @param        [in]    user_id : ?
4941* @param        [in]    alt_id : ?
4942* @return       the virtual line id
4943*/
4944int ph_get_vlid(const char * user_id, const char * alt_id){
4945        return ph_get_vline_id(user_id, alt_id);
4946}
4947
4948/**
4949* Generic PhApi service. Sends an invite with a custom body
4950*
4951* @param        [in]    vlid : a virtual line id
4952* @param        [in]    userdata : ?
4953* @param        [in]    uri : the destination uri (ex : "<sip:user@domain>")
4954* @param        [in]    bodytype : the type of body message (ex : "type/subtype")
4955* @param        [in]    body : the custom message body
4956* @param        [in]    call_id : the call id
4957* @return       TRUE if succeeds; FALSE else
4958*/
4959int phInvite(int vlid, void *userdata, char * uri, const char * bodytype, const char * body, int * call_id){
4960        int i;
4961        osip_message_t *invite;
4962        char *proxy ;
4963        phVLine *vl;
4964        char from[512];
4965        phcall_t *ca = NULL; // forced to use it, even though it mixes the notion of SIP and SDP call
4966
4967        DBG_SIP_NEGO("phLineSendFile: a new file transfer is being processed\n");
4968
4969
4970        // TODO verif des arguments
4971        if (!nonempty(uri))
4972        {
4973                return -PH_BADARG;
4974        }
4975
4976        if (!(vl = ph_valid_vlid(vlid)))
4977        {
4978                return -PH_BADVLID;
4979        }
4980
4981        ph_vline_get_from(from, sizeof(from), vl);
4982
4983        proxy = owsip_account_proxy_get (vl->sipAccount) ;
4984
4985        if((i = eXosip_build_initial_invite(&invite, uri, from, proxy, "")) != 0)
4986        {
4987                return -1;
4988        }
4989
4990        eXosip_lock();
4991        i = eXosip_initiate_call_with_body(vl->sipAccount, invite, bodytype, body, userdata);
4992
4993        ca = ph_allocate_call(i);
4994        ca->vlid = ph_vline2vlid(vl);
4995
4996        eXosip_unlock();
4997
4998        if(ca != NULL && call_id != NULL)
4999        {
5000                *call_id = ca->cid;
5001
5002        }
5003
5004        owplFireCallEvent(ca->cid,
5005                                                CALLSTATE_REMOTE_OFFERING,
5006                                                CALLSTATE_REMOTE_OFFERING_NORMAL,
5007                                                uri,
5008                                                0);
5009
5010        return i;
5011}
5012
5013/** DEPRECATED, use owplCallAnswerWithBody
5014* Generic PhApi service. Sends a 200OK with a custom body
5015*
5016* @param        [in]    cid : the call id
5017* @param        [in]    bodytype : the type of body message (ex : "type/subtype")
5018* @param        [in]    body : the custom message body
5019* @return       TRUE if succeeds; FALSE else
5020*/
5021int phAccept(int cid, const char * bodytype, const char * body){
5022        int i;
5023        phcall_t *ca = ph_locate_call_by_cid(cid);
5024
5025        DBG_SIP_NEGO("SIP NEGO: phAccept\n");
5026        if (!ca)
5027        {
5028                return -PH_BADCID;
5029        }
5030
5031        eXosip_lock();
5032        i = eXosip_answer_call_with_body(ca->did, 200, bodytype, body); // returns 0 on succes
5033        eXosip_unlock();
5034
5035        if(i != 0)
5036        {
5037                return -1;
5038        }
5039
5040        return 0;
5041}
5042
5043int phReject(int cid) {
5044        int i;
5045        phcall_t *ca = ph_locate_call_by_cid(cid);
5046
5047        DBG_SIP_NEGO("SIP NEGO: phReject\n");
5048        if (!ca)
5049        {
5050                return -PH_BADCID;
5051        }
5052
5053        eXosip_lock();
5054        i = eXosip_answer_call(ca->did, 486, 0, 0, 0, 0, NULL);
5055        eXosip_unlock();
5056
5057        DBG_SIP_NEGO("release calls");
5058        ph_release_call(ca);
5059
5060        return i;
5061
5062}
5063
5064/** DEPRECATED, no replacement
5065* Generic PhApi service. Creates a new call in PhApi.
5066*
5067* @param        [in]    cid : a call id
5068* @param        [in]    did : a dialog id
5069* @param        [in]    local_uri : ?
5070* @param        [in]    req_uri : ?
5071* @return       TRUE if succeeds; FALSE else
5072*/
5073int phNewCall(int cid, int did, const char * local_uri, const char * req_uri){
5074        phcall_t *ca;
5075        phVLine *vl;
5076        int vlid;
5077
5078        vlid = ph_get_vline_id(local_uri, req_uri);
5079
5080        if (!vlid)
5081        {
5082                ph_answer_request(did, 404);
5083                return FALSE;
5084        }
5085
5086        vl = ph_vlid2vline(vlid);
5087
5088        assert(vl);
5089
5090        if (vl->busy)
5091        {
5092                ph_answer_request(did, 486);
5093                return FALSE;
5094        }
5095
5096        if (vl->followme && vl->followme[0])
5097        {
5098                ph_answer_request_with_contact(did, 302, vl->followme);
5099                return FALSE;
5100        }
5101
5102        // ca = ph_locate_call(je, 1);
5103        if((ca = ph_locate_call_by_cid(cid)) == NULL)
5104        {
5105                if((ca = ph_allocate_call(cid)) == NULL)
5106                {
5107                        return FALSE;
5108                }
5109                ca->did = did;
5110        }
5111
5112        if (ca)
5113        {
5114                ca->vlid = vlid;
5115                ph_build_cname(ca->cname, sizeof(ca->cname), ph_vlid2vline(ca->vlid));
5116        }
5117        else
5118        {
5119                ph_answer_request(did, 500);
5120                return FALSE;
5121        }
5122
5123        return ca->cid;
5124}
5125
5126/** DEPRECATED, this function will be deleted and there is no replacement
5127* Generic PhApi service. Stops the state ringing of a call.
5128*
5129* @param        [in]    call_id : a call id
5130* @return       TRUE if succeeds; FALSE else
5131*/
5132int phStopRinging(int call_id){
5133        phcall_t *ca = NULL;
5134
5135        ca = ph_locate_call_by_cid(call_id);
5136        if(ca && ca->isringing)
5137        {
5138                ca->isringing = 0;
5139                return TRUE;
5140        }
5141        return FALSE;
5142}
5143
5144/** *DEPRECATED* , use owplCallDisconnect instead!
5145
5146* Generic PhApi service. Sends a CANCEL, DECLINE or a BYE that must be sent
5147*
5148* @param        [in]    call_id : the call id
5149* @return       TRUE if succeeds; FALSE else
5150*/
5151int phBye(int call_id){
5152        int i;
5153        phcall_t *ca = ph_locate_call_by_cid(call_id);
5154        int did;
5155        int extern_cid = -1;
5156
5157        DBG_SIP_NEGO("phCloseSipCall %d\n", call_id);
5158
5159        if(!ca)
5160        {
5161                return -PH_BADCID;
5162        }
5163
5164        if(ca->isringing)
5165        {
5166                ca->isringing = 0;
5167        }
5168
5169        did = ca->did;
5170        extern_cid = ca->extern_cid;
5171
5172        ph_release_call2(ca);
5173
5174        eXosip_lock();
5175        i = eXosip_terminate_call(extern_cid, did);
5176        eXosip_unlock();
5177
5178        if(i)
5179        {
5180                return i;
5181        }
5182
5183        return i;
5184}
5185
5186/**
5187* Generic PhApi service. Is the same as a phBye, because the function eXosip_terminate_call() used inside decides
5188* wether it is a CANCEL, DECLINE or a BYE that must be sent
5189*
5190* @param        [in]    call_id : the call id
5191* @return       TRUE if succeeds; FALSE else
5192*/
5193int phCancel(int call_id){
5194        int i;
5195        phcall_t *ca = ph_locate_call_by_cid(call_id);
5196        int did;
5197        int extern_cid = -1;
5198
5199        DBG_SIP_NEGO("phCloseSipCall %d\n", call_id);
5200
5201        if(!ca)
5202        {
5203                return -PH_BADCID;
5204        }
5205
5206        if(ca->isringing)
5207        {
5208                ca->isringing = 0;
5209        }
5210
5211        did = ca->did;
5212        extern_cid = ca->extern_cid;
5213
5214        ph_release_call2(ca);
5215
5216        eXosip_lock();
5217        i = eXosip_terminate_call(extern_cid, did);
5218        eXosip_unlock();
5219
5220        if(i)
5221        {
5222                return i;
5223        }
5224
5225        return i;
5226}
5227
5228/**
5229* Generic PhApi service.
5230*
5231* @param        [in]
5232* @return       TRUE if succeeds; FALSE else
5233*/
5234int phEndCall(int call_id, int status_code){
5235        phcall_t *ca, *rca=0;
5236
5237        ca = ph_locate_call_by_cid(call_id);
5238        if(ca)
5239        {
5240                rca = ph_locate_call_by_cid(ca->rcid);
5241                DBG_SIP_NEGO("release calls");
5242                ph_release_call(ca);
5243        }
5244        else
5245        {
5246                return FALSE;
5247        }
5248
5249        if (rca)
5250        {
5251                ph_refer_notify(rca->rdid, status_code, "Closed", 1);
5252        }
5253
5254        return TRUE;
5255}
5256/**
5257* Generic PhApi service.
5258*
5259* @param        [in]    call_id : the call id
5260* @param        [in]    status_code : the status code of the originating eXosip event
5261* @return       TRUE if succeeds; FALSE else
5262*/
5263int phRequestFailure(int call_id, int status_code){
5264        phcall_t *ca, *rca=0;
5265
5266        ca = ph_locate_call_by_cid(call_id);
5267        if(!ca)
5268        {
5269                return FALSE;
5270        }
5271
5272        rca = ph_locate_call_by_cid(ca->rcid); 
5273
5274        if (rca)
5275        {
5276                ph_refer_notify(rca->rdid, status_code, status_code == 486 ? "Busy" : "Request failure", 1);
5277        }
5278
5279        DBG_SIP_NEGO("release calls");
5280        ph_release_call(ca);
5281
5282        return TRUE;
5283}
5284
5285/**
5286* Generic PhApi service.
5287*
5288* @param        [in]    call_id : the call id
5289* @param        [in]    status_code : the status code of the originating eXosip event
5290* @return       TRUE if succeeds; FALSE else
5291*/
5292int phServerFailure(int call_id, int status_code){
5293        phcall_t *ca, *rca=0;
5294
5295        ca = ph_locate_call_by_cid(call_id);
5296        if(ca)
5297        {
5298                rca = ph_locate_call_by_cid(ca->rcid);
5299                DBG_SIP_NEGO("release calls");
5300                ph_release_call(ca);
5301        }
5302        else
5303        {
5304                return FALSE;
5305        }
5306
5307        if(rca)
5308        {
5309                ph_refer_notify(rca->rdid, status_code, "Server failure", 1);
5310        }
5311
5312        return TRUE;
5313}
5314
5315/**
5316* Generic PhApi service.
5317*
5318* @param        [in]    call_id : the call id
5319* @param        [in]    status_code : the status code of the originating eXosip event
5320* @return       TRUE if succeeds; FALSE else
5321*/
5322int phGlobalFailure(int call_id, int status_code){
5323        phcall_t *ca, *rca=0;
5324
5325        ca = ph_locate_call_by_cid(call_id);
5326        if(!ca)
5327        {
5328                return FALSE;
5329        }
5330               
5331        rca = ph_locate_call_by_cid(ca->rcid);
5332        if(rca)
5333        {
5334                ph_refer_notify(rca->rdid, status_code, "Global failure", 1);
5335        }
5336
5337        DBG_SIP_NEGO("release calls");
5338        ph_release_call(ca);
5339
5340        return TRUE;
5341}
5342
5343/**
5344* Generic PhApi service.
5345*
5346* @param        [in]    call_id : the call id
5347* @param        [in]    status_code : the status code of the originating eXosip event
5348* @return       TRUE if succeeds; FALSE else
5349*/
5350int phNoAnswer(int call_id, int status_code){
5351        phcall_t *ca, *rca=0;
5352
5353        ca = ph_locate_call_by_cid(call_id);
5354        if (!ca)
5355        {
5356                return FALSE;
5357        }
5358        rca = ph_locate_call_by_cid(ca->rcid);
5359        if (rca)
5360        {
5361                ph_refer_notify(rca->rdid, status_code, "No answer", 1);
5362        }
5363
5364        DBG_SIP_NEGO("release calls");
5365        ph_release_call(ca);
5366        //ca->owplPlugin = 0;
5367
5368        return TRUE;
5369}
5370
5371int phHoldOn(int call_id, const char * bodytype){
5372        phcall_t *ca = ph_locate_call_by_cid(call_id);
5373        int i;
5374
5375        DBG_SIP_NEGO("SIP_NEGO: phHoldOn\n");
5376
5377        if (!ca)
5378        {
5379                return -PH_BADCID;
5380        }
5381
5382        eXosip_lock();
5383        i = eXosip_on_hold_call_with_body(ca->did, bodytype, "holdon");
5384        eXosip_unlock();
5385
5386        if(i==0)
5387        {
5388                if (ca->localhold)
5389                {
5390                        return -PH_HOLDERR;
5391                }
5392
5393                ca->localhold = 1;
5394                return TRUE;
5395        }
5396        return FALSE;
5397}
5398
5399int phHoldOff(int call_id, const char * bodytype){
5400        phcall_t *ca = ph_locate_call_by_cid(call_id);
5401        int i;
5402
5403        DBG_SIP_NEGO("SIP_NEGO: phHoldOff\n");
5404
5405        if (!ca)
5406        {
5407                return -PH_BADCID;
5408        }
5409
5410        eXosip_lock();
5411        i = eXosip_off_hold_call_with_body(ca->did, bodytype, "holdoff");
5412        eXosip_unlock();
5413
5414        if(i==0)
5415        {
5416                if (ca->localhold != 1)
5417                {
5418                        return -PH_HOLDERR;
5419                }
5420
5421                ca->localhold = 0;
5422                return TRUE;
5423        }
5424        return FALSE;
5425}
5426
5427// -----
5428// </ncouturier>
Note: See TracBrowser for help on using the repository browser.