source: verona/phapi/phapi.c @ 279:844eb81f5228

Last change on this file since 279:844eb81f5228 was 279:844eb81f5228, checked in by Vadim Lebedev <vadim@…>, 21 months ago

Fix handling of mobility flags

File size: 142.8 KB
Line 
1/*
2 * phapi   phone api
3 *
4 * Copyright (C) 2004        Vadim Lebedev <vadim@mbdsys.com>
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as
8 * published by the Free Software F undation; either version 2,
9 * or (at your option) any later version.
10 *
11 * This is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with dpkg; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/**
22 * @file phapi.c
23 * @brief softphone  API
24 *
25 * phapi is a library providing simplified api to create VOIP sessions
26 * using eXosip library oSIP stack and oRTP stack
27 * <P>
28 */
29
30#include "phglobal.h"
31#ifdef OS_WIN32
32#include <winsock2.h>
33#include <windows.h>
34#endif
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <errno.h>
41#include <limits.h>
42#include <ctype.h>
43#include <assert.h>
44#include <time.h>
45
46#if !defined(OS_WIN32) && !defined(_WIN32_WCE)
47//#include "config.h"
48#include <sys/wait.h>
49#include <unistd.h>
50#include <dirent.h>
51#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
52#include <sys/soundcard.h>
53#endif
54#include <sys/ioctl.h>
55#include <fcntl.h>
56#else  /* WIN32 */
57#define snprintf _snprintf
58#ifndef _WIN32_WCE
59#define strncasecmp strnicmp
60#endif /* !_WIN32_WCE */
61# if !defined(strcasecmp)
62#  define strcasecmp stricmp
63# endif
64#define usleep(usecs) Sleep((usecs)/1000)
65#define random rand
66#define osip_free_func osip_free
67#endif
68
69#ifdef HAVE_NETINET_IN_H
70#include <netinet/in.h>
71#endif
72#include <osipparser2/osip_list.h>
73#include <osipparser2/osip_port.h>
74#include <osip2/osip_dialog.h>
75#include <osip2/osip_mt.h>
76#include <osip2/osip.h>
77#include <eXosip2/eXosip.h>
78#include <ortp/stun.h>
79#include <ortp/ortp.h>
80#include <ortp/payloadtype.h>
81
82#include "phapi-config.h"
83
84#include "phdebug.h"
85#include "phapi.h"
86#include "phcall.h"
87#include "phrpc.h"
88
89#include "phms.h"
90#include "phms_audiostream.h"
91#include "sdphandler.h"
92
93#ifdef USE_HTTP_TUNNEL
94#include "httptunnel.h"
95#endif
96
97#if  1
98
99#ifdef PHAPI_VIDEO_SUPPORT
100#include <libavcodec/avcodec.h>
101#include "phms_videostream.h"
102#endif
103
104#ifdef USE_UPNP
105#include <miniupnpc/upnpcommands.h>
106#include <miniupnpc/miniupnpc.h>
107
108static struct UPNPUrls ph_upnp_urls;
109static struct IGDdatas ph_upnp_data;
110
111#endif
112
113static struct osip_thread *phapithread = NULL;
114
115phcall_t *ph_locate_call(eXosip_event_t *je, int creatit);
116phcall_t *ph_allocate_call(int cid);
117phcall_t *ph_locate_call_for_refer(eXosip_event_t *je);
118
119void ph_wegot_dtmf(void  *ctx, int dtmfEvent);
120static int ph_event_get();
121
122
123static char *ph_get_call_contact(phcall_t *ca);
124static void set_customized_header(osip_message_t *req, const char *h, const char *v);
125
126#define MEDIA_SUSPEND
127
128#ifndef PH_STREAM_AUDIO
129#define PH_STREAM_AUDIO (1 << 0)
130#define PH_STREAM_VIDEO_RX (1 << 1)
131#define PH_STREAM_VIDEO_TX (1 << 2)
132#endif
133
134#define PH_STREAM_CNG (1 << 30)
135
136
137static int ph_call_retrieve_payloads(phcall_t *ca, int flags);
138static int ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag);
139static char *ph_ipv4tostr(char *buf, const StunAddress4 addr);
140
141
142void ph_release_call(phcall_t *ca);
143static  int timeout = 10000;
144
145static int ph_resend_offset = 30;
146
147#define PORT_STRING_LEN 16
148static char ph_nat_router_addr[32];
149static char ph_nat_port_str[PORT_STRING_LEN];
150
151#ifdef PHAPI_VIDEO_SUPPORT
152static char ph_nat_video_port_str[16];
153#endif
154
155static char ph_nat_sip_port_str[16];
156
157static char vcontact[256];
158
159typedef enum phNatType
160{
161        OPEN,
162        UPNP,
163        STUN,
164        TUNNEL
165}phNatType;
166
167static phNatType ph_nat_type = OPEN;
168static NatType ph_stun_nat_type = StunTypeOpen;
169
170static char * _get_local_sip_port();
171static void  _get_local_video_sdp_port(char buf[]);
172static void  _get_local_audio_sdp_port(char buf[]);
173
174static char*  _get_public_sip_port();
175
176static void ph_connection_lost(const char *host, int port);
177static int ph_is_connection_lost;
178
179void ph_message_progress(eXosip_event_t *je);
180static void ph_keep_refreshing();
181static void  ph_call_requestfailure(eXosip_event_t *je);
182
183static void ph_frame_display_cbk(void *ctx, void *event);
184
185static int ph_call_media_stop(phcall_t * ca);
186static int ph_call_media_suspend(phcall_t *ca, int localhold);
187
188#define nonempty(x)  ((x) && (x)[0])
189
190
191#define USE_VLINES 1
192#ifndef PH_MAX_VLINES
193#define PH_MAX_VLINES 16
194#endif
195
196
197struct vline
198{
199        char  *displayname;
200        char  *username;
201        char  *server;
202        int    port;
203        char  *proxy;
204        char  *contact;
205        time_t   regTimeout;
206        time_t   lastRegTime;
207        int   rid;
208#define VL_USED 1
209#define VL_DELETING 2
210        int   used;
211        int   busy;
212        char  *followme;
213        int    mobility;
214        struct
215        {
216                time_t  timeout;
217                time_t  last;
218                char    *etag;
219                char    *uri;
220                char    *evt;
221                char    *ctt;
222                char    *body;
223        } pub;
224};
225
226
227struct vline ph_vlines[PH_MAX_VLINES];
228
229static int
230ph_build_cname(char *buf, int n, struct vline *vl);
231
232
233static int 
234ph_req_set_body(osip_message_t *msg, const char *body, const char *mime);
235static char *
236ph_req_get_body(osip_message_t *msg);
237
238
239static 
240void ph_msession_free(struct ph_msession_s *s);
241static 
242void ph_msession_use(struct ph_msession_s *s);
243
244static struct vline *vline_alloc();
245static void vline_free(struct vline *vl);
246#define PHM_IGNORE_PORT 1
247#define PHM_IGNORE_HOST 2
248static struct vline *ph_find_matching_vline(const char *userid, int ignore);
249static struct vline *ph_find_matching_vline2(const char *username, const char* host, int ignore);
250static struct vline *ph_find_matching_vline3(const char *username, const char* host, int port, int ignore); 
251static struct vline *ph_find_vline_by_rid(int rid);
252
253static char *ph_get_proxy(const char *from);
254static int   ph_get_vline_id(const char *userid, const char *altid);
255static enum phNatType ph_get_nat_type() 
256{
257        return ph_nat_type;
258}
259
260int getPublicPort(char *local_voice_port, char *local_video_port, char *public_voice_port, char *public_video_port);
261
262
263
264#define ph_vlid2vline(vlid) (ph_vlines + (vlid) - 1)
265#define ph_vline2vlid(vl) ((vl) - ph_vlines + 1)
266
267#define clear(x) memset(&x, 0, sizeof(x))
268
269static struct vline *
270ph_valid_vlid(int vlid)
271{
272        struct vline *vl = 0;
273
274        if (vlid > 0 && vlid <= PH_MAX_VLINES)
275        {
276                vl = ph_vlid2vline(vlid);
277                if (!vl->used || vl->used == VL_DELETING)
278                        vl = 0;
279        }
280        return vl;
281}
282
283PHAPI_EXPORT phCallbacks_t *phcb;
284
285PHAPI_EXPORT int phIsInitialized;
286
287PHAPI_EXPORT int phDebugLevel = 0;
288PHAPI_EXPORT char *phLogFileName = 0;
289
290static char ph_follow_me_addr[256];
291
292unsigned short phCallBackPort = PH_CALLBACK_PORT; 
293PHAPI_EXPORT  unsigned short phServerPort = PH_SERVER_PORT;
294
295static int ph_busyFlag;
296
297
298static FILE *ph_log_file;
299
300void *
301ph_api_thread(void *arg);
302
303// mutex for ph_start_call
304ph_mutex_t  *ph_media_start_mutex;
305
306// mutex for ph_release_call
307ph_mutex_t  *ph_media_stop_mutex;
308
309ph_mutex_t *ph_custom_mutex;
310
311osip_list_t ph_custom_headers;
312int  ph_custom_idx;
313
314#define ph_custom_lock() osip_mutex_lock(ph_custom_mutex)
315#define ph_custom_unlock() osip_mutex_unlock(ph_custom_mutex)
316static void ph_apply_header_monitor(osip_message_t* msg,  struct ph_hdr_list *hlist);
317
318
319ph_mutex_t *ph_hdrmon_mutex;
320int ph_hdrmon_idx;
321osip_list_t ph_hdrmon_list;
322
323#define ph_hdrmon_lock() osip_mutex_lock(ph_hdrmon_mutex)
324#define ph_hdrmon_unlock() osip_mutex_unlock(ph_hdrmon_mutex)
325
326
327
328struct ph_custom_hdr
329{
330        char     *matchrequests;
331        char  *hdrname;
332        char  *hdrvalue;
333        int   idx;
334        int   enabled;
335
336};
337
338
339
340static char *presencenames[] =
341{
342                "presence",
343                "presence.winfo",
344                "presence.list",
345                "conflist",
346                "sipprofile",
347                "addressbook.query"
348};
349
350#define name(x) #x
351
352static char *evtnames[] =
353{
354                name(EXOSIP_REGISTRATION_NEW),           /**< announce new registration.       */
355                name(EXOSIP_REGISTRATION_SUCCESS),       /**< user is successfully registred.  */
356                name(EXOSIP_REGISTRATION_FAILURE),       /**< user is not registred.           */
357                name(EXOSIP_REGISTRATION_REFRESHED),     /**< registration has been refreshed. */
358                name(EXOSIP_REGISTRATION_TERMINATED),    /**< UA is not registred any more.    */
359
360                /* INVITE related events within calls */
361                name(EXOSIP_CALL_INVITE),            /**< announce a new call                   */
362                name(EXOSIP_CALL_REINVITE),          /**< announce a new INVITE within call     */
363
364                name(EXOSIP_CALL_NOANSWER),          /**< announce no answer within the timeout */
365                name(EXOSIP_CALL_PROCEEDING),        /**< announce processing by a remote app   */
366                name(EXOSIP_CALL_RINGING),           /**< announce ringback                     */
367                name(EXOSIP_CALL_ANSWERED),          /**< announce start of call                */
368                name(EXOSIP_CALL_REDIRECTED),        /**< announce a redirection                */
369                name(EXOSIP_CALL_REQUESTFAILURE),    /**< announce a request failure            */
370                name(EXOSIP_CALL_SERVERFAILURE),     /**< announce a server failure             */
371                name(EXOSIP_CALL_GLOBALFAILURE),     /**< announce a global failure             */
372                name(EXOSIP_CALL_ACK),               /**< ACK received for 200ok to INVITE      */
373
374                name(EXOSIP_CALL_CANCELLED),         /**< announce that call has been cancelled */
375                name(EXOSIP_CALL_TIMEOUT),           /**< announce that call has failed         */
376
377                /* request related events within calls (except INVITE) */
378                name(EXOSIP_CALL_MESSAGE_NEW),              /**< announce new incoming request. */
379                name(EXOSIP_CALL_MESSAGE_PROCEEDING),       /**< announce a 1xx for request. */
380                name(EXOSIP_CALL_MESSAGE_ANSWERED),         /**< announce a 200ok  */
381                name(EXOSIP_CALL_MESSAGE_REDIRECTED),       /**< announce a failure. */
382                name(EXOSIP_CALL_MESSAGE_REQUESTFAILURE),   /**< announce a failure. */
383                name(EXOSIP_CALL_MESSAGE_SERVERFAILURE),    /**< announce a failure. */
384                name(EXOSIP_CALL_MESSAGE_GLOBALFAILURE),    /**< announce a failure. */
385
386                name(EXOSIP_CALL_CLOSED),            /**< a BYE was received for this call      */
387
388                /* for both UAS & UAC events */
389                name(EXOSIP_CALL_RELEASED),             /**< call context is cleared.            */
390
391                /* response received for request outside calls */
392                name(EXOSIP_MESSAGE_NEW),              /**< announce new incoming request. */
393                name(EXOSIP_MESSAGE_PROCEEDING),       /**< announce a 1xx for request. */
394                name(EXOSIP_MESSAGE_ANSWERED),         /**< announce a 200ok  */
395                name(EXOSIP_MESSAGE_REDIRECTED),       /**< announce a failure. */
396                name(EXOSIP_MESSAGE_REQUESTFAILURE),   /**< announce a failure. */
397                name(EXOSIP_MESSAGE_SERVERFAILURE),    /**< announce a failure. */
398                name(EXOSIP_MESSAGE_GLOBALFAILURE),    /**< announce a failure. */
399
400                /* Presence and Instant Messaging */
401                name(EXOSIP_SUBSCRIPTION_UPDATE),         /**< announce incoming SUBSCRIBE.      */
402                name(EXOSIP_SUBSCRIPTION_CLOSED),         /**< announce end of subscription.     */
403
404                name(EXOSIP_SUBSCRIPTION_NOANSWER),          /**< announce no answer              */
405                name(EXOSIP_SUBSCRIPTION_PROCEEDING),        /**< announce a 1xx                  */
406                name(EXOSIP_SUBSCRIPTION_ANSWERED),          /**< announce a 200ok                */
407                name(EXOSIP_SUBSCRIPTION_REDIRECTED),        /**< announce a redirection          */
408                name(EXOSIP_SUBSCRIPTION_REQUESTFAILURE),    /**< announce a request failure      */
409                name(EXOSIP_SUBSCRIPTION_SERVERFAILURE),     /**< announce a server failure       */
410                name(EXOSIP_SUBSCRIPTION_GLOBALFAILURE),     /**< announce a global failure       */
411                name(EXOSIP_SUBSCRIPTION_NOTIFY),            /**< announce new NOTIFY request     */
412
413                name(EXOSIP_SUBSCRIPTION_RELEASED),          /**< call context is cleared.        */
414
415                name(EXOSIP_IN_SUBSCRIPTION_NEW),            /**< announce new incoming SUBSCRIBE.*/
416                name(EXOSIP_IN_SUBSCRIPTION_RELEASED),       /**< announce end of subscription.   */
417
418                name(EXOSIP_NOTIFICATION_NOANSWER),          /**< announce no answer              */
419                name(EXOSIP_NOTIFICATION_PROCEEDING),        /**< announce a 1xx                  */
420                name(EXOSIP_NOTIFICATION_ANSWERED),          /**< announce a 200ok                */
421                name(EXOSIP_NOTIFICATION_REDIRECTED),        /**< announce a redirection          */
422                name(EXOSIP_NOTIFICATION_REQUESTFAILURE),    /**< announce a request failure      */
423                name(EXOSIP_NOTIFICATION_SERVERFAILURE),     /**< announce a server failure       */
424                name(EXOSIP_NOTIFICATION_GLOBALFAILURE)     /**< announce a global failure       */
425
426};
427
428#undef name
429
430
431
432phcall_t ph_calls[PH_MAX_CALLS];
433
434/*
435//#define FORCE_VAD   1
436#define FORCE_CNG   1
437 */
438static struct osip_list ph_audio_payloads;
439static struct osip_list ph_video_payloads;
440
441
442ph_config_t phcfg = {
443                /* public ip addr */ "",
444                /* local ip addr */ "",
445                /* local audio rtp port */"10600",
446                /* local audio rtcp port */ "10900",
447                /* local audio rtp port */"10700",
448                /* local audio rtcp port */ "11000",
449                /* local video rtp port */ "10800",
450                /* local video rtcp port */ "11100",
451                /* sipport  */ "5060",
452                /* public sip port */ "",
453                /* sip transport */ IPPROTO_UDP,
454                /* nattype */  "" ,
455                /* codecs */   "" ,"",
456                /* asyncmode */ 0,
457                /* audio_dev_in */   "" ,
458                /* audio_dev_out */   "" ,
459                /* softboost */ 0,
460                /* no media */ 0,
461                /* no aec */ 0,
462                /* vad */ 0,
463                /* cng */ 0,
464                /* hdx mode */ 0,
465                /* nat_refresh_udp_time */ 0,
466                /* nat_refresh_tcp_time */ 0,
467                /* nat_refresh_time_shift */ 0,
468                /* ptime */ 0,
469                /* jitterdepth */0,
470                /* stream_timeout */0,
471                /* nodefaultline */0,
472                /* autoredir */0,
473                /* stunserver */  "80.118.132.74",
474                0
475};
476
477static const char *
478ph_get_event_type_str(int winfo)
479{
480        if (winfo > sizeof(presencenames))
481                return NULL;
482        return presencenames[winfo];
483} 
484
485PHAPI_EXPORT ph_config_t *ph_get_config()
486{
487        return &phcfg;
488}
489
490static int _is_video_enabled(int streams) 
491{
492        return (streams & (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX));
493}
494
495
496static int _is_audio_enabled(int streams) 
497{
498        return (streams & PH_STREAM_AUDIO);
499}
500
501static char *ph_ipv4tostr(char *buf, const StunAddress4 addr)
502{
503        uint32_t ip = addr.addr;
504
505        sprintf(buf, "%d.%d.%d.%d", (ip >> 24) & 255,  (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
506
507        return buf;
508
509}
510
511static int 
512ph_port_inuse(int port)
513{
514        int i;
515        phcall_t *ca;
516
517        /* scan all active calls and check that the given port is inuse */
518        for(i=0; i<PH_MAX_CALLS;  i++)
519        {
520                ca = &ph_calls[i];
521                if (ca->cid != -1)
522                {
523                        /* active call */
524                        if(ca->local_sdp_audio_port == port || port == ca->local_sdp_video_port)
525                                return 1;
526                }
527        }
528
529        return 0;
530}
531
532static void 
533_get_local_audio_sdp_port(char buf[])
534{
535
536        /* <MINHPQ>
537         * To get arround the problem of connect in winsock ( connect returns
538         * an error: 10048: Address already in use connect is called an the local address is in used
539         * within the last 2 or 4 minutes), we should not bind the rtp socket to a specific local port. Hence,
540         * we should return "0" here to let the system choose a random port number.
541         */
542
543        /* base port number*/
544        int port = atoi(phcfg.local_audio_rtp_port);
545
546        buf[0] = 0;
547
548        if (port <= 0)
549                port = 10600 + random() % 4096;
550
551        while(1)
552        {
553                if (!ph_port_inuse(port))
554                {
555                        sprintf(buf, "%d", port);
556                        return;
557                }
558                else
559                        port += 2;    /* try next pair */
560        }
561}
562
563static void 
564_get_local_video_sdp_port(char buf[]) 
565{
566        int port = atoi(phcfg.local_video_rtp_port);
567
568        buf[0] = 0;
569
570        if (port <= 0)
571                port = 10600 + random() % 4096;
572        else
573                port += 2;
574
575        while(1)
576        {
577                if (!ph_port_inuse(port))
578                {
579                        sprintf(buf, "%d", port);
580                        return;
581                }
582                else
583                        port += 2;    /* try next pair */
584        }
585}
586
587
588
589static char *
590_get_local_sip_port()
591{
592        return phcfg.sipport;
593}
594
595static char *
596_get_public_sip_port()
597{
598        if (ph_nat_sip_port_str[0])
599                return ph_nat_sip_port_str;
600        return _get_local_sip_port();
601}
602
603phcall_t *
604ph_locate_call_by_cid(int cid)
605{
606        phcall_t *ca;
607
608        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
609        {
610                if (ca->cid == cid)
611                        return ca;
612        }
613        return 0;
614}
615
616#if 0
617void phReleaseTerminatedCalls()
618{
619        phcall_t *ca;
620        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
621        {
622                if ((ca->cid != -1) && (ph_media_is_stream_stopped(ca) == 1))
623                        ph_release_call(ca);
624        }
625}
626#endif
627
628
629phcall_t *
630ph_locate_call_by_rcid(int cid)
631{
632        phcall_t *ca;
633
634
635        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
636        {
637                if (ca->rcid == cid)
638                        return ca;
639        }
640
641        return 0;
642}
643
644phcall_t *
645ph_locate_call_by_rdid(int did)
646{
647        phcall_t *ca;
648
649
650        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
651        {
652                if (ca->rdid == did)
653                        return ca;
654        }
655
656        return 0;
657}
658
659
660phcall_t *
661ph_allocate_call(int cid)
662{
663        phcall_t *ca = ph_locate_call_by_cid(-1);
664
665        if (!ca)
666                return 0;
667
668        ca->redirs = 0;
669        ca->cid = cid;
670        osip_list_init(&ca->audio_payloads);
671        osip_list_clone(&ph_audio_payloads, &ca->audio_payloads, sdp_payload_clone);
672        osip_list_init(&ca->video_payloads);
673        osip_list_clone(&ph_video_payloads, &ca->video_payloads, sdp_payload_clone);
674        return ca;
675}
676
677
678phcall_t *
679ph_locate_call(eXosip_event_t *je, int creatit)
680{
681        phcall_t *ca, *found = 0, *newca = 0;
682        osip_header_t *hdr = 0;
683
684
685        /* lookup matching call descriptor */
686        for (ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS]; ca++)
687        {
688                if (ca->cid == -1 && !newca)
689                        newca = ca;
690
691                if (ca->cid == je->cid)
692                {
693                        found = ca;
694                        break;
695                }
696        }
697
698        ca = found;
699
700        if (!ca) /* we didn't find a matching call descriptor */
701        {
702                if (creatit)
703                {
704                        /* allocate a new one */
705                        if (!newca)
706                                return 0; /* !!! BUG !!! */
707                        ca = newca;
708                        memset(ca, 0, sizeof(*ca));
709                        ca->cid = -2;
710                }
711        }
712
713        if (!ca)
714                return 0;
715
716
717        /* update the call information */
718
719        if (!ca->localrefer)
720        {
721                ca->cid = je->cid;
722                ca->did = je->did;
723                ca->tid = je->tid;
724        }
725
726        if (je->response)
727        {
728                osip_message_header_get_byname(je->response, "Accept-Contact", 0, &hdr);
729                if (hdr && !strcmp(hdr->hvalue, "*;+g.oma.sip-im"))
730                        ca->nego_mflags = PH_STREAM_DATA;
731        }
732
733        if (creatit)
734        {
735                if (osip_list_size(&ca->audio_payloads) == 0) {
736                        osip_list_init(&ca->audio_payloads);
737                        osip_list_clone(&ph_audio_payloads, &ca->audio_payloads, sdp_payload_clone);
738                }
739                if (osip_list_size(&ca->video_payloads) == 0) {
740                        osip_list_init(&ca->video_payloads);
741                        osip_list_clone(&ph_video_payloads, &ca->video_payloads, sdp_payload_clone);
742                }
743                osip_list_init(&ca->result_audio_payloads);
744                osip_list_init(&ca->result_video_payloads);
745
746                if (je->request && MSG_IS_INVITE(je->request) && !ca->remote_sdp && !ca->state == PH_CALLER)
747                {
748                        char *sdp = ph_req_get_body(je->request);
749
750                        if (sdp)
751                        {
752                                sdp_message_init(&ca->remote_sdp);
753                                sdp_message_parse(ca->remote_sdp, sdp);
754                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "audio"))
755                                        ca->nego_mflags |= PH_STREAM_AUDIO;
756                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "video"))
757                                        ca->nego_mflags |= PH_STREAM_VIDEO;
758                                osip_free(sdp);
759                        }
760                }
761
762                if (je->response && MSG_IS_INVITE(je->response) && !ca->remote_sdp)
763                {
764                        char *sdp = ph_req_get_body(je->response);
765
766                        if (sdp)
767                        {
768                                sdp_message_init(&ca->remote_sdp);
769                                sdp_message_parse(ca->remote_sdp, sdp);
770                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "audio"))
771                                        ca->nego_mflags |= PH_STREAM_AUDIO;
772                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "video"))
773                                        ca->nego_mflags |= PH_STREAM_VIDEO;
774                                osip_free(sdp);
775                        }
776                }
777        }
778        return ca;
779}
780
781static void 
782ph_free_stream(struct ph_stream_params *sp)
783{
784        int i;
785
786        if (sp->streamtype)
787                free((void *) sp->streamtype);
788        if (sp->payloads)
789                free((void *) sp->payloads);
790        if (sp->streamaddr)
791                free((void *) sp->streamaddr);
792
793        for(i = 0; (i < PH_STREAM_MAX_ATTRS) && sp->attrs[i]; i++)
794                free((void *) sp->attrs[i]);
795        free(sp);
796}
797
798
799static void 
800ph_copy_stream(struct ph_stream_params *dp, const struct ph_stream_params *sp)
801{
802        int i;
803
804        *dp = *sp;
805        if (dp->streamtype)
806                dp->streamtype = strdup(dp->streamtype);
807        if (dp->payloads)
808                dp->payloads = strdup(dp->payloads);
809        if (dp->streamaddr)
810                dp->streamaddr = strdup(dp->streamaddr);
811
812        for(i = 0; (i < PH_STREAM_MAX_ATTRS) && dp->attrs[i]; i++)
813                dp->attrs[i] = strdup(dp->attrs[i]);
814
815}
816
817static void 
818ph_deep_copy_streams(struct ph_stream_params **dp, struct ph_stream_params **sp)
819{
820        int i;
821
822        for( i = 0; i < PH_MAX_STREAMS && sp[i]; i++)
823        {
824                dp[i] = malloc(sizeof(*sp[i]));
825                ph_copy_stream(dp[i], sp[i]);
826        }
827
828        if (i < PH_MAX_STREAMS)
829                dp[i] = 0;
830}
831
832
833static void 
834ph_free_all_streams(struct ph_stream_params *sp[])
835{
836        int i;
837
838        for( i = 0; i < PH_MAX_STREAMS && sp[i]; i++)
839        {
840                ph_free_stream(sp[i]);
841        }
842}
843
844static int ph_call_hasaudio(phcall_t *ca)
845{
846        if (ca->mses && (ca->mses->activestreams & (1 << PH_MSTREAM_AUDIO1)))
847                return 1;
848        return 0;
849}
850
851static int ph_call_hasvideo(phcall_t *ca)
852{
853        if (ca->mses && (ca->mses->activestreams & (1 << PH_MSTREAM_VIDEO1)))
854                return 1;
855        return 0;
856}
857
858static int ph_call_stream_alive(phcall_t *ca)
859{
860        if (!ph_call_hasaudio(ca) && !ph_call_hasvideo(ca))
861                return 0;
862        if (phcfg.stream_timeout <= 0)
863                return 1;
864        return ph_msession_is_stream_alive(ca->mses, phcfg.stream_timeout);
865}
866
867
868static struct ph_stream_params *
869ph_find_stream(struct ph_stream_params  **streams, const char *strtype, int maxstrs);
870
871void ph_release_call(phcall_t *ca)
872{
873
874        DBG_SIP_NEGO("SIP_NEGO: ph_release_call\n");
875
876        if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca))
877        {
878                ph_call_media_stop(ca);
879        }
880
881
882        if (ca->audiodev_in != phcfg.audio_dev_in)
883                if (ca->audiodev_in)
884                        osip_free(ca->audiodev_in);
885       
886        if (ca->audiodev_out != phcfg.audio_dev_out)
887                if (ca->audiodev_out)
888                        osip_free(ca->audiodev_out);
889
890        ph_free_all_streams(ca->streams);
891        if (ca->sdpctx)
892                sdp_context_free(ca->sdpctx);
893
894        osip_list_special_free(&ca->audio_payloads, sdp_payload_free);
895        osip_list_special_free(&ca->result_audio_payloads, sdp_payload_free);
896        osip_list_special_free(&ca->result_video_payloads, sdp_payload_free);
897
898        osip_list_special_free(&ca->video_payloads, sdp_payload_free);
899
900        memset(ca, 0, sizeof(phcall_t));
901        ca->cid = -1;
902}
903
904int ph_has_active_calls()
905{
906        phcall_t *ca;
907        int count = 0;
908
909        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
910        {
911                if (ca->cid != -1 && (ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) )
912                {
913                        if (!ca->remotehold && !ca->localhold)
914                                count++;
915                }
916        }
917
918        return count;
919}
920
921void ph_stream_ended(void *ctx, int event)
922{
923        phcall_t *ca = (phcall_t *)ctx;
924
925        ca->closereq = 1;
926}
927
928void ph_wegot_dtmf(void *ctx, int dtmfEvent)
929{
930        phCallStateInfo_t info;
931        phcall_t *ca = (phcall_t *)ctx;
932
933        clear(info);
934
935        info.event = phDTMF;
936        info.dtmfDigit = dtmfEvent;
937        info.vlid = ca->vlid;
938        phcb->callProgress(ca->cid, &info);
939
940}
941
942void ph_frame_display_cbk(void *ctx, void *event)
943{
944        phcall_t *ca = (phcall_t *) ctx;
945
946        phcb->onFrameReady(ca->cid, event);
947}
948
949int ph_same_str(const char *str1, const char *str2)
950{
951        if (str1 == 0)
952                return str2 == 0;
953
954        if (str2 == 0)
955                return str1 == 0;
956
957        return (0 == strcasecmp(str1, str2));
958}
959
960int ph_same_uri(const char *uristr1, const char *uristr2)
961{
962        osip_contact_t *uri1, *uri2;
963        int ret;
964
965        osip_contact_init(&uri1);
966        osip_contact_init(&uri2);
967
968        osip_contact_parse(uri1, uristr1);
969        osip_contact_parse(uri2, uristr2);
970
971        /* if we've got and invalid URI return TRUE */
972        if (!uri1 || !uri2 || !uri1->url || !uri2->url)
973                ret = 1;
974        else
975                ret = ph_same_str(uri1->url->username, uri2->url->username) &&
976                ph_same_str(uri1->url->host, uri2->url->host) &&
977                ph_same_str(uri1->url->port, uri2->url->port);
978
979        osip_contact_free(uri1);
980        osip_contact_free(uri2);
981
982        return ret;
983}
984
985
986
987static int 
988ph_req_set_body(osip_message_t *msg, const char *body, const char *mime)
989{
990        char clen[10];
991
992        snprintf(clen, 10, "%li", strlen(body));
993        if (mime)
994                osip_message_set_content_type(msg, mime);
995        osip_message_set_body(msg, body, strlen(body));
996        osip_message_set_content_length(msg, clen);
997
998        return 0;
999}
1000
1001static sdp_payload_t *
1002ph_call_support_payload(const struct osip_list *codec_list, const sdp_payload_t *payload)
1003{
1004        sdp_payload_t *cur_payload;
1005
1006        int pos = 0;
1007
1008        while (!osip_list_eol(codec_list, pos))
1009        {
1010                cur_payload = (sdp_payload_t *) osip_list_get (codec_list, pos);
1011
1012                if (sdp_equal_payload(cur_payload, payload) == 0)
1013                {
1014                        return cur_payload;
1015                }
1016                pos++;
1017        }
1018        return NULL;
1019}
1020
1021int ph_accept_audio_offer(sdp_context_t *ctx, sdp_payload_t *payload)
1022{
1023        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1024        struct ph_stream_params *si;
1025        sdp_payload_t *new_payload, *ca_payload;
1026        struct vline *vl;
1027
1028        if (!_is_audio_enabled(ca->user_mflags) ||
1029                        !(ca_payload = ph_call_support_payload(&ca->audio_payloads, payload)))
1030        {
1031                DBG_CODEC_LOOKUP("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap);
1032                return -1;
1033        }
1034
1035        if (!ca->remote_sdp_audio_port)
1036        {
1037                ca->remote_sdp_audio_port = payload->remoteport;
1038                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1039                strncpy(ca->remote_sdp_audio_ip, payload->c_addr, sizeof(ca->remote_sdp_audio_ip));
1040        }
1041
1042        //maybe si->streamport is useless
1043        {
1044                si  = ph_find_stream(ca->streams, "audio", 16);
1045                if (!si->streamaddr && si->streamport == -1)
1046                {
1047                        si->streamport = ca->local_sdp_audio_port;
1048                }
1049        }
1050
1051        vl = ph_valid_vlid(ca->vlid);
1052
1053        payload->localport = ca->local_sdp_audio_port;
1054    payload->localrtcpport = ca->local_sdp_audio_rtcp_port;
1055
1056        sdp_payload_clone(payload, (void **)&new_payload);
1057        if (new_payload->a_rtpmap)
1058                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1059
1060        //we replace external payload number by local number
1061        new_payload->pt = ca_payload->pt;
1062        if (vl->mobility & PH_NORTCP_ATTR)
1063                new_payload->localrtcpport = 0;
1064
1065        osip_list_add(&ca->result_audio_payloads, new_payload, 0);
1066
1067        return 0;
1068}
1069
1070int ph_accept_video_offer(sdp_context_t *ctx, sdp_payload_t *payload)
1071{
1072        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1073        struct ph_stream_params *si;
1074        sdp_payload_t *new_payload, *ca_payload;
1075        struct vline* vl;
1076
1077        if (!_is_video_enabled(ca->user_mflags))
1078        {
1079                DBG_CODEC_LOOKUP("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap);
1080                return -1;
1081        }
1082
1083        if (!(ca_payload = ph_call_support_payload(&ca->video_payloads, payload)))
1084        {
1085                DBG_CODEC_LOOKUP("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap);
1086                return -1;
1087        }
1088
1089        if (!ca->remote_sdp_video_port)
1090        {
1091                ca->remote_sdp_video_port = payload->remoteport;
1092                ca->remote_sdp_video_rtcp_port = payload->remotertcpport;
1093                strncpy(ca->remote_sdp_video_ip, payload->c_addr, sizeof(ca->remote_sdp_video_ip));
1094        }
1095
1096        //maybe si->streamport is useless ?
1097        {
1098                si  = ph_find_stream(ca->streams, "video", 16);
1099                if (!si->streamaddr && si->streamport == -1)
1100                {
1101                        si->streamport = ca->local_sdp_video_port;
1102                }
1103        }
1104
1105        payload->localport = ca->local_sdp_video_port;
1106        payload->localrtcpport = ca->local_sdp_video_rtcp_port;
1107
1108        sdp_payload_clone(payload, (void**) &new_payload);
1109        if (new_payload->a_rtpmap)
1110                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1111
1112        //we replace external payload number by local number
1113        new_payload->pt = ca_payload->pt;
1114
1115        vl = ph_valid_vlid(ca->vlid);
1116        if (vl->mobility & PH_NORTCP_ATTR)
1117                new_payload->localrtcpport = 0;
1118
1119        osip_list_add(&ca->result_video_payloads, new_payload, 0);
1120
1121        return 0;
1122}
1123
1124int ph_set_audio_offer(sdp_context_t *ctx)
1125{
1126        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1127
1128        RtpProfile *profile = &av_profile;
1129        sdp_payload_t *cur_payload;
1130        //sdp_payload_t payload;
1131        struct vline* vl;
1132
1133        int pos = 0;
1134
1135        if (!_is_audio_enabled(ca->nego_mflags))
1136                return 0;
1137
1138        vl = ph_valid_vlid(ca->vlid);
1139        while (!osip_list_eol(&ca->audio_payloads, pos))
1140        {
1141                cur_payload = (sdp_payload_t *) osip_list_get (&ca->audio_payloads, pos);
1142                cur_payload->localport = ca->local_sdp_audio_port;
1143                cur_payload->localrtcpport = ca->local_sdp_audio_rtcp_port;
1144
1145                if (strncasecmp(cur_payload->a_rtpmap, "iLBC",4)==0)
1146                {
1147                        /* prefer the 30 ms mode */
1148                        cur_payload->a_fmtp="ptime=30";
1149                }
1150
1151                if (vl->mobility & PH_NORTCP_ATTR)
1152                        cur_payload->localrtcpport = 0;
1153
1154                sdp_context_add_audio_payload(ctx, cur_payload, phcfg.ptime);
1155                pos++;
1156        }
1157
1158        /* add telephone-event payload*/
1159        /*      sdp_payload_init(&payload);
1160        payload.pt=rtp_profile_get_payload_number_from_mime(profile,"telephone-event");
1161        payload.a_rtpmap="telephone-event/8000";
1162        payload.a_fmtp="0-11";
1163
1164        sdp_context_add_audio_payload(ctx, &payload, 0);*/
1165
1166        return 0;
1167}
1168
1169int ph_set_video_offer(sdp_context_t *ctx)
1170{
1171        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1172        sdp_payload_t *cur_payload;
1173        int pos = 0;
1174        struct vline* vl;
1175
1176        if (!_is_video_enabled(ca->nego_mflags))
1177                return 0;
1178
1179        vl = ph_valid_vlid(ca->vlid);
1180        while (!osip_list_eol(&ca->video_payloads, pos))
1181        {
1182                cur_payload = (sdp_payload_t *) osip_list_get (&ca->video_payloads, pos);
1183                cur_payload->localport=ca->local_sdp_video_port;
1184                cur_payload->localrtcpport = ca->local_sdp_video_rtcp_port;
1185                if (vl->mobility & PH_NORTCP_ATTR)
1186                        cur_payload->localrtcpport = 0;
1187
1188                sdp_context_add_video_payload(ctx, cur_payload);
1189                pos++;
1190        }
1191
1192        return 0;
1193}
1194
1195
1196int ph_read_audio_answer(sdp_context_t *ctx, sdp_payload_t *payload)
1197{
1198        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1199        sdp_payload_t *new_payload, *ca_payload;
1200
1201        if (!(ca_payload = ph_call_support_payload(&ca->audio_payloads, payload)))
1202        {
1203                DBG_CODEC_LOOKUP("Refusing audio codec answered %i (%s)",payload->pt,payload->a_rtpmap);
1204                return -1;
1205        }
1206
1207        sdp_payload_clone(payload, (void**) &new_payload);
1208        if (new_payload->a_rtpmap)
1209                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1210
1211        //we replace external payload number by local number
1212        new_payload->pt = ca_payload->pt;
1213        osip_list_add(&ca->result_audio_payloads, new_payload, 0);
1214
1215        if (!ca->remote_sdp_audio_port) {
1216                strncpy(ca->remote_sdp_audio_ip, payload->c_addr, sizeof(ca->remote_sdp_audio_ip));
1217                ca->remote_sdp_audio_port = payload->remoteport;
1218                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1219        }
1220        return 0;
1221}
1222
1223int ph_read_video_answer(sdp_context_t *ctx, sdp_payload_t *payload)
1224{
1225        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1226        sdp_payload_t *new_payload, *ca_payload;
1227
1228        if (!(ca_payload = ph_call_support_payload(&ca->video_payloads, payload)))
1229        {
1230                DBG_CODEC_LOOKUP("Refusing video codec answered %i (%s)",payload->pt,payload->a_rtpmap);
1231                return -1;
1232        }
1233
1234        sdp_payload_clone(payload, (void**) &new_payload);
1235        if (new_payload->a_rtpmap)
1236                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1237
1238        //we replace external payload number by local number
1239        new_payload->pt = ca_payload->pt;
1240
1241        osip_list_add(&ca->result_video_payloads, new_payload, 0);
1242
1243        if (!ca->remote_sdp_video_port) {
1244                strncpy(ca->remote_sdp_video_ip, payload->c_addr, sizeof(ca->remote_sdp_video_ip));
1245                ca->remote_sdp_video_port = payload->remoteport;
1246                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1247        }
1248        return 0;
1249}
1250
1251
1252sdp_handler_t ph_sdp_handler={
1253                ph_accept_audio_offer,   /*from remote sdp */
1254                ph_accept_video_offer,   /*from remote sdp */
1255                ph_set_audio_offer,     /*to local sdp */
1256                ph_set_video_offer,     /*to local sdp */
1257                ph_read_audio_answer,   /*from incoming answer  */
1258                ph_read_video_answer    /*from incoming answer  */
1259};
1260
1261int
1262phGetVersion()
1263{
1264        static char version[] = PHAPI_VERSION_STRING;
1265        char *subv = strstr(version, ".");
1266        int v,s,r;
1267
1268        v = atoi(version);
1269        s = atoi(subv+1);
1270        r = atoi(strstr(subv+1, ".")+1);
1271
1272        return (v << 16) | (s << 8) | r;
1273}
1274#undef stringize
1275
1276const char *
1277phGetRevision()
1278{
1279#ifdef PHAPI_REVISION
1280        return PHAPI_REVISION;
1281#else  /*!PHAPI_REVISION */
1282        return "";
1283#endif /*!PHAPI_REVISION */
1284}
1285
1286
1287
1288/*
1289
1290PHAPI_EXPORT int
1291phGetAudioVersion()
1292{
1293  int fd, ret=-1;
1294#if !defined(WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__)
1295#ifndef EMBED
1296  fd = open("/dev/dsp", O_RDWR, O_NONBLOCK);
1297#else
1298  fd = open("/dev/sound/mixer0", O_RDWR, O_NONBLOCK);
1299#endif
1300  if (fd>=0)
1301    {
1302#if defined(EMBED)
1303    if(0>ioctl(fd, SOUND_MIXER_PRIVATE5, &ret))
1304#else
1305      if(0>ioctl(fd, OSS_GETVERSION, &ret))
1306#endif
1307        ret = -1;
1308    close(fd);
1309    }
1310  return ret;
1311#else
1312  return 0;
1313#endif
1314} */
1315
1316PHAPI_EXPORT int
1317phGetNatInfo(char *ntstr, int ntlen, char *fwip, int fwiplen)
1318{
1319        assert(ntstr!=NULL);
1320        assert(fwip!=NULL);
1321
1322        //strncpy(ntstr, ph_get_nat_type(), ntlen);
1323        strncpy(fwip, ph_nat_router_addr, fwiplen);
1324        return 0;
1325}
1326
1327
1328
1329
1330PHAPI_EXPORT int
1331phSetUaString(const char *uastr)
1332{
1333        eXosip_set_user_agent(uastr);
1334        return 0;
1335}
1336
1337#define FROM_DISPLAYNAME 1
1338#define FROM_PORT 2
1339#define FROM_FORCEPORT 4
1340
1341static void
1342ph_build_from2(char *buf, int n, struct vline *vl, int flags)
1343{
1344        char *un, *s;
1345        char port[32]={0};
1346        const char *uphone = "";
1347
1348        assert(buf != NULL);
1349        assert(vl != NULL);
1350
1351        if (checkmobility(vl->mobility,PH_LINE_MOBILITY_PHONE))
1352                uphone=";user=phone";
1353
1354
1355
1356        un = nonempty(vl->username) ? vl->username : "unknown";
1357        s = nonempty(vl->server) ? vl->server : "localhost";
1358        if ((vl->port >= 0 && vl->port != 5060 && (flags & FROM_PORT)) || (vl->port == 5060 && (flags & FROM_FORCEPORT)))
1359                snprintf(port, sizeof(port), ":%d", vl->port);
1360
1361
1362        if ((flags & FROM_DISPLAYNAME) && nonempty(vl->displayname))
1363        {
1364                if (!strchr(vl->displayname, ' '))
1365                {
1366                        snprintf(buf, n, "%s <sip:%s@%s%s%s>", vl->displayname, un, s, port, uphone);
1367                }
1368                else
1369                {
1370                        snprintf(buf, n, "\"%s\" <sip:%s@%s%s%s>", vl->displayname, un, s, port, uphone);
1371                }
1372
1373        }
1374        else
1375        {
1376                snprintf(buf, n, "<sip:%s@%s%s%s>", un, s, port, uphone);
1377        }
1378}
1379
1380
1381static void
1382ph_build_from(char *buf, int n, struct vline *vl)
1383{
1384        ph_build_from2(buf, n, vl, FROM_DISPLAYNAME);
1385}
1386
1387
1388static void
1389ph_build_contact(char *buf, int n, struct vline *vl)
1390{
1391        char fbuf[512];
1392        char *ctct;
1393
1394        ph_build_from2(fbuf, 512, vl, 0);
1395        if (!eXosip_build_contact_str(fbuf, 0, &ctct))
1396        {
1397                strncpy(buf, ctct, n);
1398                osip_free(ctct);
1399                return;
1400        }
1401        strncpy(buf, fbuf, n);
1402
1403
1404}
1405
1406
1407static int
1408ph_build_cname(char *buf, int n, struct vline *vl)
1409{
1410        char *un, *s;
1411        int res;
1412        assert(buf!=NULL);
1413        assert(vl!=NULL);
1414
1415        un = nonempty(vl->username) ? vl->username : "unknown";
1416        s = nonempty(vl->server) ? vl->server : "localhost";
1417
1418        res = snprintf(buf, n, "%s@%s", un, s);
1419        return res < 0 ? 1 : res >= n;
1420}
1421
1422//
1423
1424static int 
1425ph_retrieve_from(int did, char **from)
1426{
1427        osip_dialog_t *dlg = eXosip_call_get_osip_dialog(did);
1428
1429        if (did)
1430                return -1;
1431
1432        return osip_from_to_str(dlg->remote_uri, from);
1433
1434}
1435
1436#define optional(x) (x[0] ? x : 0)
1437
1438static void
1439ph_replace_contact(osip_message_t *msg, const char *ctct)
1440{
1441        osip_list_special_free(&msg->contacts, (void (*)(void *)) &osip_contact_free);
1442        osip_message_set_contact(msg, ctct);
1443}
1444
1445int
1446phLinePlaceCall_withCa(int vlid, const char *uri, void *userdata, int rcid, int streams, phcall_t *ca0, const char *adev, const char *audio_addr, const char *video_addr)
1447{
1448        int i;
1449        osip_message_t *invite;
1450        phcall_t *ca = 0;
1451        char *proxy = 0;
1452        struct vline *vl;
1453        char from[512];
1454        char  local_voice_port[16];
1455        char  local_video_port[16];
1456        char  local_ip[16];
1457
1458        DBG_SIP_NEGO("phLinePlaceCall_withCa: a new call has been placed\n");
1459
1460        local_video_port[0] = 0;
1461        local_voice_port[0] = 0;
1462
1463        if (!phIsInitialized)
1464                return -PH_NOTINIT;
1465
1466        if (!nonempty(uri))
1467                return -PH_BADARG;
1468
1469        vl = ph_valid_vlid(vlid);
1470
1471        if (!vl)
1472                return -PH_BADVLID;
1473
1474        if (rcid)
1475        {
1476                ca = ph_locate_call_by_cid(rcid);
1477                if (!ca)
1478                        return -PH_BADCID;
1479        }
1480
1481        eXosip_lock();
1482        if (!ca0)
1483                ca0 = ph_allocate_call(-2);
1484        else
1485                ca0->cid = -2;
1486        eXosip_unlock();
1487
1488        if (!ca0)
1489                return -PH_NORESOURCES;
1490
1491        if (adev)
1492                ca0->audiodev_in = osip_strdup(adev);
1493        else 
1494        {
1495                if (phcfg.audio_dev_in) {
1496                        ca0->audiodev_in = osip_strdup(phcfg.audio_dev_in);
1497                }
1498                if (phcfg.audio_dev_out) {
1499                        ca0->audiodev_out = osip_strdup(phcfg.audio_dev_out);
1500                }
1501        }
1502
1503        ca0->user_mflags = streams;
1504        ca0->nego_mflags = streams;
1505
1506        if (rcid)
1507                ca0->rcid = rcid;
1508
1509        if (audio_addr == NULL)
1510        {
1511                if (phcfg.local_ip_addr[0] == 0)
1512                {
1513                        eXosip_guess_localip(AF_INET, local_ip, 16);
1514                }
1515                else
1516                {
1517                        strcpy(local_ip, phcfg.local_ip_addr);
1518                }
1519        }
1520        else
1521                strcpy(local_ip, audio_addr);
1522
1523        ca0->vlid = ph_vline2vlid(vl);
1524        ca0->state = PH_CALLER;
1525
1526        if (streams & PH_ANONYMOUS_CALL)
1527                strcpy(from, "<sip:anonymous@anonymous.invalid>");
1528        else
1529                ph_build_from2(from, sizeof(from), vl, FROM_DISPLAYNAME & FROM_PORT);
1530
1531        proxy = vl->proxy;
1532
1533        eXosip_lock();
1534        i = eXosip_call_build_initial_invite(&invite,
1535                        uri,
1536                        from,
1537                        proxy,
1538                        "PHAPI CALL");
1539        eXosip_unlock();
1540        if (i!=0)
1541                return -1;
1542
1543        osip_message_set_allow(invite, "INVITE, ACK, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, REGISTER");
1544
1545        ph_apply_customizations(invite, NULL, NULL);
1546        if (streams & PH_ANONYMOUS_CALL) {
1547                osip_message_set_header(invite, "Privacy", "id");
1548                ph_replace_contact(invite, vl->contact);
1549        }
1550
1551
1552        if (_is_audio_enabled(streams))
1553        {
1554                _get_local_audio_sdp_port(local_voice_port);
1555                ca0->local_sdp_audio_port = atoi(local_voice_port);
1556                ca0->local_sdp_audio_rtcp_port = ca0->local_sdp_audio_port + 1;
1557        }
1558
1559        if (_is_video_enabled(streams))
1560        {
1561                _get_local_video_sdp_port(local_video_port);
1562                ca0->local_sdp_video_port = atoi(local_video_port);
1563                ca0->local_sdp_video_rtcp_port = ca0->local_sdp_video_port + 1;
1564        }
1565
1566
1567        if (streams == PH_STREAM_DATA)
1568        {
1569                osip_message_set_header(invite, "Accept-Contact", "*;g.oma.sip-im");
1570                eXosip_lock();
1571                i = eXosip_call_send_initial_invite(invite); //  userdata, NULL, 0,  0,  0, 0, 0, 0);
1572        }
1573        else
1574        {
1575                if (!ca0->sdpctx) {
1576                        ca0->sdpctx = sdp_handler_create_context(&ph_sdp_handler, local_ip, vl->username, 0);
1577                        ca0->cfg =  &phcfg;
1578                        sdp_context_set_user_pointer(ca0->sdpctx, ca0);
1579                }
1580
1581
1582                sdp_context_build_offer(ca0->sdpctx);
1583                ca0->local_sdp = ca0->sdpctx->offer;
1584
1585                ph_req_set_body(invite, ca0->sdpctx->offerstr, "application/sdp");
1586
1587                eXosip_lock();
1588                i = eXosip_call_send_initial_invite(invite);
1589        }
1590
1591        eXosip_call_set_reference(i, userdata);
1592        ca0->cid = i;
1593        ca0->state = PH_CALLER;
1594        eXosip_unlock();
1595        return i;
1596
1597}
1598
1599PHAPI_EXPORT int
1600phLinePlaceCall2(int vlid, const char *uri, void *userdata, int rcid, int streams)
1601{
1602        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, 0, 0, 0);
1603}
1604
1605
1606PHAPI_EXPORT int
1607phLinePlaceCall3(int vlid, const char *uri, void *userdata, int rcid, int streams, const char *adev)
1608{
1609        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, adev, 0, 0);
1610}
1611
1612PHAPI_EXPORT int
1613phLinePlaceCall4(int vlid, const char *uri, void *userdata, int rcid, int streams, const char *adev, const char *audio_addr, const char *video_addr)
1614{
1615        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, adev, audio_addr, video_addr);
1616}
1617
1618PHAPI_EXPORT int
1619phLinePlaceMcCall(int vlid, const char *uri, void *userdata, int streams, const char *adev)
1620{
1621        if (!streams)
1622                streams = PH_STREAM_AUDIO;
1623
1624        return phLinePlaceCall_withCa(vlid, uri, userdata, 0,
1625                        streams|PH_STREAM_MCRECV, 0, adev, 0, 0);
1626}
1627
1628PHAPI_EXPORT int
1629phLinePlaceCall(int vlid, const char *uri, void *userdata, int rcid)
1630{
1631        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, PH_STREAM_AUDIO, 0, 0, 0, 0);
1632}
1633
1634PHAPI_EXPORT int
1635phLineSendMessage(int vlid, const char *uri, const char *buff, const char *mime)
1636{
1637        return phLineSendMessage2(vlid, uri, uri, buff, mime, 0);
1638}
1639
1640
1641PHAPI_EXPORT int
1642phLineSendMessage2(int vlid, const char *target, const char *uri,
1643                const char *buff, const char *mime, const char *sipcid)
1644{
1645        int i;
1646        struct vline *vl;
1647        char from[512];
1648        osip_message_t *msg;
1649
1650        if (!phIsInitialized)
1651                return -PH_NOTINIT;
1652
1653        vl = ph_valid_vlid(vlid);
1654        if (!vl) {
1655                return -PH_BADVLID;
1656        }
1657
1658        if ( !nonempty(uri)) {
1659                return -PH_BADARG;
1660        }
1661
1662        ph_build_from(from, sizeof(from), vl);
1663
1664        eXosip_lock();
1665        i = eXosip_message_build_request(&msg, "MESSAGE", (char *)uri,
1666                        from, vl->proxy);
1667
1668
1669        ph_req_set_body(msg, buff, mime);
1670        osip_message_set_contact(msg, vl->contact);
1671
1672        if (sipcid)
1673                osip_message_set_call_id(msg, sipcid);
1674
1675        ph_apply_customizations(msg, NULL, NULL);
1676        i = eXosip_message_send_request(msg);
1677
1678        eXosip_unlock();
1679        return i;
1680}
1681
1682PHAPI_EXPORT int
1683phCallSendMessage(int cid, const char *buff, const char *mime)
1684{
1685        int i;
1686        phcall_t *ca;
1687        osip_message_t *msg;
1688
1689        if (!phIsInitialized)
1690                return -PH_NOTINIT;
1691
1692        ca = ph_locate_call_by_cid(cid);
1693
1694        if (!ca)
1695                return -PH_BADCID;
1696
1697        eXosip_lock();
1698
1699        i = eXosip_call_build_request(ca->did, "MESSAGE", &msg);
1700        ph_req_set_body(msg, buff, mime);
1701        osip_message_set_contact(msg, ph_get_call_contact(ca));
1702        i = eXosip_call_send_request(ca->did, msg);
1703
1704        eXosip_unlock();
1705
1706        return i;
1707}
1708
1709
1710
1711
1712PHAPI_EXPORT int
1713phSendMessage(const char *from, const char *uri,
1714                const char *buff, const char *mime)
1715{
1716        int i;
1717        osip_message_t *msg;
1718
1719        if (!phIsInitialized)
1720                return -PH_NOTINIT;
1721
1722        if (!nonempty(from) || !nonempty(uri))
1723                return -PH_BADARG;
1724
1725        eXosip_lock();
1726        i = eXosip_message_build_request(&msg, "MESSAGE", uri, from, ph_get_proxy(from));
1727        ph_req_set_body(msg, buff, mime);
1728        ph_apply_customizations(msg, NULL, NULL);
1729        i = eXosip_message_send_request(msg);
1730        eXosip_unlock();
1731        return i;
1732}
1733
1734PHAPI_EXPORT int
1735phLineSubscribe(int vlid, const char *uri, const int winfo)
1736{
1737        return phLineSubscribe2(vlid, uri, winfo, NULL, 1, 600);
1738}
1739
1740PHAPI_EXPORT int
1741phLineSubscribe2(int vlid, const char *uri, const int winfo, char *data, int use_proxy, int expire)
1742{
1743        int i;
1744        struct vline *vl;
1745        char from[512];
1746        osip_message_t *msg;
1747
1748        if (!phIsInitialized)
1749                return -PH_NOTINIT;
1750
1751        vl = ph_valid_vlid(vlid);
1752
1753        if (!vl)
1754                return -PH_BADVLID;
1755
1756        ph_build_from(from, sizeof(from), vl);
1757
1758
1759        if ( !nonempty(uri))
1760                return -PH_BADARG;
1761
1762
1763        eXosip_lock();
1764        if (use_proxy)
1765                i = eXosip_subscribe_build_initial_request(&msg, uri, from, vl->proxy, ph_get_event_type_str(winfo), expire);
1766        else
1767                i = eXosip_subscribe_build_initial_request(&msg, uri, from, uri, ph_get_event_type_str(winfo), expire);
1768
1769        if (!i)
1770        {
1771                if (data)
1772                {               
1773                        osip_header_t *data_header;
1774
1775                        osip_header_init(&data_header);
1776                        osip_header_set_name(data_header, osip_strdup("X-Addressbook"));
1777                        osip_header_set_value(data_header, osip_strdup(data));
1778                        osip_list_add(&msg->headers, data_header, 0);
1779                }
1780                ph_apply_customizations(msg, NULL, NULL);
1781                i = eXosip_subscribe_send_initial_request(msg);
1782        }
1783        eXosip_unlock();
1784        return i;
1785}
1786
1787
1788PHAPI_EXPORT int
1789phLineUnsubscribe(int sid, int winfo)
1790{
1791        int i = 0;
1792        osip_message_t *sub;
1793
1794        if (!phIsInitialized)
1795                return -PH_NOTINIT;
1796
1797        eXosip_lock();
1798        if ((i = eXosip_subscribe_build_refresh_request(sid,&sub)) < 0) {
1799                eXosip_unlock();
1800                return i;
1801        }
1802        osip_message_set_expires(sub, strdup("0"));
1803        osip_message_set_header(sub, "Event", ph_get_event_type_str(winfo));
1804        ph_apply_customizations(sub, NULL, NULL);
1805        if ((i = eXosip_subscribe_send_refresh_request(sid,sub)) < 0) {
1806                eXosip_unlock();
1807                return i;
1808        }
1809        eXosip_unlock();
1810        return 0;
1811}
1812
1813
1814PHAPI_EXPORT int
1815phSubscribe(const char *from, const char *to, const int winfo)
1816{
1817        int sid;
1818        osip_message_t *msg;
1819
1820        if (!phIsInitialized)
1821                return -PH_NOTINIT;
1822
1823        if (!nonempty(to) || !nonempty(from))
1824                return -PH_BADARG;
1825
1826        eXosip_lock();
1827        sid = eXosip_subscribe_build_initial_request(&msg, to, from, ph_get_proxy(from), ph_get_event_type_str(winfo), 600);
1828        if (!sid) {
1829                ph_apply_customizations(msg, NULL, NULL);
1830                sid = eXosip_subscribe_send_initial_request(msg);
1831        }
1832        eXosip_unlock();
1833        return sid;
1834}
1835
1836
1837
1838PHAPI_EXPORT int
1839phLinePublish(int vlid, const char *uri, int winfo, const char * content_type, const char * content)
1840{
1841        return phLinePublish2(vlid, uri, ph_get_event_type_str(winfo), content_type, content, 600);
1842}
1843
1844
1845
1846PHAPI_EXPORT int
1847phLinePublish2(int vlid, const char *uri, const char *evt, const char *ctt, const char *body, int expires)
1848{
1849        int i;
1850        struct vline *vl;
1851        char from[512];
1852        char expstr[16];
1853        osip_message_t *publish;
1854
1855        if (!phIsInitialized)
1856                return -PH_NOTINIT;
1857
1858        if ( !nonempty(uri))
1859                return -PH_BADARG;
1860
1861        vl = ph_valid_vlid(vlid);
1862
1863        if (!vl)
1864                return -PH_BADVLID;
1865
1866        ph_build_from(from, sizeof(from), vl);
1867
1868        snprintf(expstr, sizeof(expstr), "%d", expires);
1869
1870        eXosip_lock();
1871        i = eXosip_build_publish(&publish,  uri, from,  vl->proxy, evt, expstr, ctt, body);
1872        if (!i) {
1873                ph_apply_customizations(publish, NULL, NULL);
1874                i = eXosip_publish(publish, uri);
1875        }
1876        eXosip_unlock();
1877
1878
1879        if (i)
1880                return -PH_ERROR;
1881
1882        return i;
1883}
1884
1885
1886
1887
1888static const char  *ph_get_expires_str()
1889{
1890        // FIXME:
1891        return "1200";
1892} 
1893
1894PHAPI_EXPORT int
1895phPublish(const char *from, const char *to, const int winfo, const char * content_type, const char * content)
1896{
1897        int i;
1898        osip_message_t *msg;
1899
1900        if (!phIsInitialized)
1901                return -PH_NOTINIT;
1902
1903        if (!nonempty(to) || !nonempty(from) || !nonempty(content_type) || !nonempty(content))
1904                return -PH_BADARG;
1905
1906
1907        eXosip_lock();
1908        i = eXosip_build_publish(&msg, to, from, ph_get_proxy(from), ph_get_event_type_str(winfo), ph_get_expires_str(), content_type, content);
1909        if (!i) {
1910                ph_apply_customizations(msg, NULL, NULL);
1911                i = eXosip_publish(msg, to);
1912        }
1913
1914        eXosip_unlock();
1915        return i;
1916}
1917
1918extern void eXosip_update();
1919
1920PHAPI_EXPORT void
1921phRefresh()
1922{
1923        if (!phIsInitialized)
1924                return;
1925        eXosip_lock();
1926        eXosip_update();
1927        eXosip_unlock();
1928}
1929
1930
1931PHAPI_EXPORT int
1932phLineSendOptions(int vlid, const char *to)
1933{
1934        int i;
1935        struct vline *vl;
1936        char from[512];
1937        osip_message_t *msg;
1938
1939        if (!phIsInitialized)
1940                return -PH_NOTINIT;
1941
1942        vl = ph_valid_vlid(vlid);
1943
1944        if (!vl)
1945                return -PH_BADVLID;
1946
1947        ph_build_from(from, sizeof(from), vl);
1948
1949
1950        if (!nonempty(to))
1951                return -PH_BADARG;
1952
1953
1954        eXosip_lock();
1955        i = eXosip_options_build_request(&msg, to, from, vl->proxy);
1956        if (!i) {
1957                ph_apply_customizations(msg, NULL, NULL);
1958                i = eXosip_options_send_request(msg);
1959        }
1960
1961        eXosip_unlock();
1962
1963        if (i && (msg!=0))
1964                osip_message_free(msg);
1965
1966        return i ? PH_ERROR : i;
1967
1968}
1969
1970
1971
1972PHAPI_EXPORT int
1973phSendOptions(const char *from, const char *uri)
1974{
1975        int i;
1976        osip_message_t *req = 0;
1977
1978        if (!phIsInitialized)
1979                return -PH_NOTINIT;
1980
1981        if (!nonempty(from) || !nonempty(uri))
1982                return -PH_BADARG;
1983
1984        eXosip_lock();
1985        i = eXosip_options_build_request(&req, (char *)uri, (char*) from, ph_get_proxy(from));
1986        if (!i) {
1987                ph_apply_customizations(req, NULL, NULL);
1988                i = eXosip_options_send_request(req);
1989        }
1990        eXosip_unlock();
1991
1992        if (i && (req!=0))
1993                osip_message_free(req);
1994
1995
1996        return i ? PH_ERROR : i;
1997}
1998
1999
2000PHAPI_EXPORT int
2001phAcceptCall2(int cid, void *userData)
2002{
2003        return phAcceptCall3(cid, userData, PH_STREAM_AUDIO);
2004}
2005
2006PHAPI_EXPORT int
2007phAcceptCall3(int cid, void *userData, int streams)
2008{
2009        return phAcceptCall4(cid, userData, streams, 0, 0);
2010}
2011
2012
2013static int 
2014ph_answer_call(int cid, int tid, int status, const char *laport, const char *ctct,
2015                const char *lvport, const char  *paport, const char *pvport,
2016                const char *audio_addr, const char *video_addr, const char *uri)
2017{
2018        int i;
2019        osip_message_t *msg = 0;
2020
2021        phcall_t *ca = ph_locate_call_by_cid(cid);
2022
2023        if (!ca)
2024                return -PH_BADCID;
2025
2026        i = eXosip_call_build_answer(tid, status, &msg);
2027        if (!i) {
2028                if (ctct)
2029                        osip_message_set_contact(msg, ctct);
2030
2031                i = eXosip_call_send_answer(tid, status, msg);
2032        }
2033
2034        return i;
2035}
2036
2037
2038PHAPI_EXPORT int
2039phAcceptCall4(int cid, void *userData, int streams, const char *audio_addr, const char *video_addr)
2040{
2041        int i;
2042        phcall_t *ca;
2043        char  local_video_port[16] = "0";
2044        char  local_voice_port[16] = "0";
2045
2046        phCallStateInfo_t info;
2047        osip_message_t *msg = 0;
2048        struct vline *vl;
2049        char local_ip[16];
2050        char *remoteUri = 0;
2051
2052        DBG_SIP_NEGO("SIP NEGO: phAcceptCall4\n");
2053
2054        if (!phIsInitialized)
2055                return -PH_NOTINIT;
2056
2057        ca = ph_locate_call_by_cid(cid);
2058
2059        if (!ca)
2060                return -PH_BADCID;
2061
2062        vl = ph_valid_vlid(ca->vlid);
2063
2064        if (!vl)
2065                return -PH_BADVLID;
2066
2067        if (audio_addr == NULL)
2068        {
2069                if (phcfg.local_ip_addr[0] == 0)
2070                {
2071                        eXosip_guess_localip(AF_INET, local_ip, 16);
2072                }
2073                else
2074                {
2075                        strcpy(local_ip, phcfg.local_ip_addr);
2076                }
2077        }
2078        else
2079                strcpy(local_ip, audio_addr);
2080
2081        ca->user_mflags = streams; // trace of what the user decided
2082        ca->nego_mflags = ca->user_mflags; // current negociated media flags
2083        ca->state = PH_CALLEE_ACCEPTED;
2084
2085        //listening ports are already set by allocatePorts
2086        if (_is_video_enabled(streams))
2087        {
2088                _get_local_video_sdp_port(local_video_port);
2089                ca->local_sdp_video_port = atoi(local_video_port);
2090                ca->local_sdp_video_rtcp_port = ca->local_sdp_video_port + 1;
2091        }
2092
2093        if (_is_audio_enabled(streams))
2094        {
2095                _get_local_audio_sdp_port(local_voice_port);
2096                ca->local_sdp_audio_port = atoi(local_voice_port);
2097                ca->local_sdp_audio_rtcp_port = ca->local_sdp_audio_port + 1;
2098        }
2099
2100
2101        eXosip_lock();
2102        ph_retrieve_from(ca->did, &remoteUri);
2103        eXosip_unlock();
2104
2105        if (streams == PH_STREAM_DATA)
2106        {
2107                eXosip_lock();
2108                i = ph_answer_call(ca->cid, ca->tid, 200, 0, 0, 0, 0, 0, 0, 0, 0);
2109        }
2110        else
2111        {
2112                eXosip_lock();
2113
2114                i = eXosip_call_build_answer(ca->tid, 200, &msg);
2115                if (i < 0)
2116                {
2117                        eXosip_unlock();
2118                        return -1;
2119                }
2120
2121                if (!ca->sdpctx) {
2122                        ca->sdpctx = sdp_handler_create_context(&ph_sdp_handler, local_ip, vl->username, 0);
2123                        ca->cfg =  &phcfg;
2124                        sdp_context_set_user_pointer(ca->sdpctx, ca);
2125                        ca->sdpctx->offer = ca->remote_sdp;
2126                }
2127                if (sdp_context_build_answer(ca->sdpctx, ca->remote_sdp, phcfg.ptime) == NULL)
2128                {
2129                        eXosip_call_send_answer(ca->tid, 606, NULL); //error, no matching payload
2130                        eXosip_unlock();
2131                        return -1;
2132                }
2133
2134                ca->local_sdp = ca->sdpctx->answer;
2135                ph_req_set_body(msg, ca->sdpctx->answerstr, "application/sdp");
2136                i = eXosip_call_send_answer(ca->tid, 200, msg);
2137        }
2138
2139        if (i == 0 && streams != PH_STREAM_DATA)
2140        {
2141                i = ph_call_retrieve_payloads(ca, streams | PH_STREAM_CNG );
2142        }
2143
2144        eXosip_unlock();
2145
2146        if (!i && streams != PH_STREAM_DATA)
2147                i = ph_call_media_start(ca, NULL, streams, 0);
2148
2149        if (i)
2150                return i;
2151
2152        clear(info);
2153
2154        info.remoteUri = remoteUri;
2155        info.event = phCALLOK;
2156        phcb->callProgress(cid, &info);
2157
2158        if (remoteUri)
2159                osip_free(remoteUri);
2160
2161        return 0;
2162}
2163
2164PHAPI_EXPORT int
2165phAcceptMcCall(int cid, const char *adev_in, const char *adev_out, const char *audioaddr, int port)
2166{
2167        phcall_t *ca;
2168        char  local_voice_port[16] = "0";
2169        int streams = PH_STREAM_AUDIO;
2170        phCallStateInfo_t info;
2171        int i;
2172        char *remoteUri;
2173
2174        if (!phIsInitialized)
2175                return -PH_NOTINIT;
2176
2177        ca = ph_locate_call_by_cid(cid);
2178
2179        if (!ca)
2180                return -PH_BADCID;
2181
2182        snprintf(local_voice_port,16, "%d", port);
2183        eXosip_lock();
2184
2185        i = ph_answer_call(ca->cid, ca->did, 200, local_voice_port, ph_get_call_contact(ca),
2186                        NULL,NULL,NULL,
2187                        audioaddr, NULL, 0);
2188
2189        if (i == 0)
2190        {
2191                char tmp[16];
2192
2193                i = ph_call_retrieve_payloads(ca, streams);
2194
2195                _get_local_audio_sdp_port(tmp);
2196                ca->local_sdp_audio_port = atoi(tmp);
2197                ca->remote_sdp_audio_port = port;
2198                strncpy(ca->remote_sdp_audio_ip, audioaddr, sizeof(ca->remote_sdp_audio_ip));
2199
2200        }
2201
2202        eXosip_unlock();
2203
2204        if (adev_in)
2205        {
2206                if (ca->audiodev_in) 
2207                        osip_free(ca->audiodev_in);
2208                ca->audiodev_in = osip_strdup(adev_in);
2209        }
2210       
2211        if (adev_out)
2212        {
2213                if (ca->audiodev_out) 
2214                        osip_free(ca->audiodev_out);
2215                ca->audiodev_out = osip_strdup(adev_out);
2216        }
2217
2218        ph_call_media_start(ca, NULL, streams|PH_STREAM_MCSEND, 0);
2219
2220        eXosip_lock();
2221        ph_retrieve_from(ca->did, &remoteUri);
2222        eXosip_unlock();
2223
2224        clear(info);
2225
2226        info.remoteUri = remoteUri;
2227        info.event = phCALLOK;
2228        phcb->callProgress(cid, &info);
2229
2230        if (remoteUri)
2231                osip_free(remoteUri);
2232
2233        return 0;
2234}
2235
2236PHAPI_EXPORT int
2237phAcceptMcCall2(int cid, int mcid)
2238{
2239        phcall_t *ca;
2240        phcall_t *mca;
2241        char  local_voice_port[16] = "0";
2242        int streams = PH_STREAM_AUDIO;
2243        phCallStateInfo_t info;
2244        int i;
2245        char *remoteUri;
2246
2247        if (!phIsInitialized)
2248                return -PH_NOTINIT;
2249
2250        ca = ph_locate_call_by_cid(cid);
2251        mca = ph_locate_call_by_cid(mcid);
2252
2253        if (!ca || !mca)
2254                return -PH_BADCID;
2255
2256        i = ph_call_retrieve_payloads(ca, streams);
2257
2258        ca->local_sdp_audio_port = mca->local_sdp_audio_port;
2259        ca->remote_sdp_audio_port =  mca->remote_sdp_audio_port;
2260        strncpy(ca->remote_sdp_audio_ip, mca->remote_sdp_audio_ip, sizeof(ca->remote_sdp_audio_ip));
2261        if (mca->audiodev_in)
2262                ca->audiodev_in = osip_strdup(mca->audiodev_in);
2263        if (mca->audiodev_out)
2264                ca->audiodev_out = osip_strdup(mca->audiodev_out);
2265
2266
2267        ph_msession_use(mca->mses);
2268        ca->mses = mca->mses;
2269
2270        ca->user_mflags = mca->user_mflags;
2271        ca->nego_mflags = mca->nego_mflags;
2272
2273        snprintf(local_voice_port,16, "%d", ca->remote_sdp_audio_port);
2274
2275
2276
2277        eXosip_lock();
2278        i = ph_answer_call(ca->cid, ca->did, 200, local_voice_port, ph_get_call_contact(ca),
2279                        NULL,NULL,NULL,
2280                        ca->remote_sdp_audio_ip, NULL, NULL);
2281
2282        ph_retrieve_from(ca->did, &remoteUri);
2283
2284        eXosip_unlock();
2285
2286
2287
2288        clear(info);
2289
2290        info.remoteUri = remoteUri;
2291        info.event = phCALLOK;
2292        phcb->callProgress(cid, &info);
2293
2294        if (remoteUri)
2295                osip_free(remoteUri);
2296
2297        return 0;
2298}
2299
2300
2301static void 
2302add_contact_param(struct vline *vl,  const char *param, const char *value, int inside)
2303{
2304        osip_contact_t *ctct;
2305
2306
2307        if (!vl->contact)
2308                return;
2309
2310        osip_contact_init(&ctct);
2311
2312        osip_contact_parse(ctct, vl->contact);
2313        if (inside)
2314                osip_uri_param_add(&ctct->url->url_params, osip_strdup(param), osip_strdup(value));
2315        else
2316                osip_contact_param_add(ctct, osip_strdup(param), osip_strdup(value));
2317
2318        osip_free(vl->contact);
2319        osip_contact_to_str(ctct, &vl->contact);
2320        osip_contact_free(ctct);
2321}
2322
2323
2324PHAPI_EXPORT int
2325phLineGetMobility(int vlid)
2326{
2327        struct vline *vl;
2328
2329        if (!phIsInitialized)
2330                return -PH_NOTINIT;
2331
2332        vl = ph_valid_vlid(vlid);
2333
2334        if (!vl)
2335                return -PH_BADVLID;
2336
2337        return vl->mobility;
2338
2339}
2340
2341
2342/*
2343  find and return a  stream of the given type in the 'streams'.
2344  if the stream is not found allocate a new one if there is space                       int j;
2345   in the table
2346  maxtsr specifices the size of the table
2347 */
2348static struct ph_stream_params *
2349ph_find_stream(struct ph_stream_params  **streams, const char *strtype, int maxstrs)
2350{
2351
2352        struct ph_stream_params *si, **strs = streams;
2353
2354        while(si = *strs++)
2355        {
2356                if (!strcmp(si->streamtype, strtype))
2357                        return si;
2358        }
2359
2360        if (!maxstrs)
2361                return 0;
2362
2363        if (strs - streams < (maxstrs - 1))
2364        {
2365                si = calloc(sizeof(*si), 1);
2366                si->streamtype = strdup(strtype);
2367                si->streamport = -1;
2368                strs[-1] = si;
2369                strs[0] = 0;
2370                return si;
2371        }
2372
2373        return 0;
2374}
2375
2376
2377static void 
2378ph_copy_streams_from_args(struct ph_stream_params **streams, va_list args)
2379{
2380        struct ph_stream_params *psi;
2381        int i = 0;
2382
2383        while(0 != (psi = va_arg(args, struct ph_stream_params *))) {
2384                struct ph_stream_params *esi= calloc(sizeof(*psi), 1);
2385                if (!esi)
2386                        return;
2387                streams[i] = esi;
2388                ph_copy_stream(esi, psi);
2389        }
2390
2391        if (i < PH_MAX_STREAMS)
2392                streams[i] = 0;
2393
2394}
2395
2396static int
2397ph_answer_request(int cid, int tid, int reason, const char *ctct)
2398{
2399        int i;
2400
2401        eXosip_lock();
2402        i = ph_answer_call(cid, tid, reason, 0, ctct, 0, 0, 0, 0, 0, 0);
2403        eXosip_unlock();
2404
2405        return i;
2406}
2407
2408
2409PHAPI_EXPORT int
2410phRejectCall(int cid, int reason)
2411{
2412        phcall_t *ca;
2413
2414        if (!phIsInitialized)
2415                return -PH_NOTINIT;
2416
2417        ca = ph_locate_call_by_cid(cid);
2418
2419        if (!ca)
2420                return -PH_BADCID;
2421
2422        return phRejectCall2(cid, ph_get_call_contact(ca), reason);
2423
2424}
2425
2426PHAPI_EXPORT int
2427phRejectCall2(int cid, const char *uri,int reason)
2428{
2429        int i;
2430        phcall_t *ca;
2431        phCallStateInfo_t info;
2432
2433        if (!phIsInitialized)
2434                return -PH_NOTINIT;
2435
2436        ca = ph_locate_call_by_cid(cid);
2437
2438        if (!ca)
2439                return -PH_BADCID;
2440
2441        if(!reason)
2442                reason = 302;
2443
2444        i = ph_answer_request(ca->cid, ca->tid, reason, uri);
2445
2446        ph_release_call(ca);
2447
2448        clear(info);
2449        info.event = phCALLCLOSED;
2450        phcb->callProgress(cid, &info);
2451
2452
2453        return i;
2454}
2455
2456
2457PHAPI_EXPORT int
2458phRingingCall(int cid)
2459{
2460        int i;
2461        osip_message_t *msg = 0;
2462        phcall_t *ca;
2463
2464        if (!phIsInitialized)
2465                return -PH_NOTINIT;
2466
2467        ca = ph_locate_call_by_cid(cid);
2468
2469        if (!ca)
2470                return -PH_BADCID;
2471
2472        eXosip_lock();
2473        i = eXosip_call_build_answer(ca->tid, 180, &msg);
2474        if (i < 0)
2475        {
2476                eXosip_unlock();
2477                return -1;
2478        }
2479
2480
2481        i = eXosip_call_send_answer(ca->tid, 180, msg);
2482        eXosip_unlock();
2483        return i;
2484}
2485
2486
2487
2488PHAPI_EXPORT int
2489phCloseCall(int cid)
2490{
2491        int i;
2492        phcall_t *ca;
2493        phCallStateInfo_t info;
2494        int did;
2495
2496        DBG_SIP_NEGO("phCloseCall %d\n", cid);
2497
2498        if (!phIsInitialized)
2499                return -PH_NOTINIT;
2500
2501        if (cid < 0)
2502                return -PH_BADCID;
2503
2504        eXosip_lock();
2505        ca = ph_locate_call_by_cid(cid);
2506
2507        if (!ca)
2508        {
2509                eXosip_unlock();
2510                return -PH_BADCID;
2511        }
2512
2513        clear(info);
2514        info.event = phCALLCLOSED;
2515
2516        if (ca->isringing)
2517        {
2518                info.event = phCALLCLOSEDandSTOPRING;
2519                ca->isringing = 0;
2520        }
2521
2522
2523        info.vlid = ca->vlid;
2524        did = ca->did;
2525
2526
2527        i = eXosip_call_terminate(cid, did);
2528
2529
2530        ph_release_call(ca);
2531
2532        eXosip_unlock();
2533
2534        if (i)
2535                return i;
2536
2537        info.userData = 0;
2538
2539        info.errorCode = 0;
2540        phcb->callProgress(cid, &info);
2541
2542        return i;
2543
2544}
2545
2546
2547PHAPI_EXPORT int phCallStartMedia(int cid, int streamFlags)
2548{
2549        phcall_t *ca;
2550
2551        if (!phIsInitialized)
2552                return -PH_NOTINIT;
2553
2554        ca = ph_locate_call_by_cid(cid);
2555
2556        if (!ca)
2557                return -PH_BADCID;
2558
2559
2560        ca->user_mflags &= ~(PH_NOMEDIA_STREAMS|PH_STREAM_AUDIO|PH_STREAM_VIDEO_TX|PH_STREAM_VIDEO_RX);
2561        ca->user_mflags |= streamFlags;
2562        ca->nego_mflags = ca->user_mflags;
2563
2564        return ph_call_media_start(ca, 0, 0, 0);
2565
2566}
2567
2568PHAPI_EXPORT int
2569phTransferCall(int cid, int tcid)
2570{
2571        phcall_t *ca;
2572        phcall_t *txca;
2573        char uri[512];
2574        osip_message_t *refer = 0;
2575        int i;
2576
2577        if (!phIsInitialized)
2578                return -PH_NOTINIT;
2579
2580        ca = ph_locate_call_by_cid(cid);
2581        txca = ph_locate_call_by_cid(tcid);
2582
2583        if (!ca || !txca)
2584                return -PH_BADCID;
2585
2586
2587        eXosip_lock();
2588        i = eXosip_call_get_referto(tcid, uri, sizeof(uri));
2589        if (i) goto err;
2590        i = eXosip_call_build_refer(ca->did, uri, &refer);
2591        if (i) goto err;
2592        ph_apply_customizations(refer, NULL, NULL);
2593        i = eXosip_call_send_request(ca->did, refer);
2594        if (i)  goto err;
2595
2596        ca->localrefer = 1;
2597        ca->txcid = tcid;
2598
2599
2600        eXosip_unlock();
2601
2602
2603        return 0;
2604
2605        err:
2606        eXosip_unlock();
2607
2608        if (refer)
2609                osip_message_free(refer);
2610
2611        if (i == OSIP_NOMEM)
2612                return -PH_NORESOURCES;
2613
2614        return -PH_ERROR;
2615
2616}
2617
2618
2619PHAPI_EXPORT  int
2620phSetContact(int vlid, const char *uri)
2621{
2622        return phSetContact2(vlid, uri, 1);
2623}
2624
2625PHAPI_EXPORT  int
2626phSetContact2(int vlid, const char *uri, int translate)
2627{
2628        struct vline *vl;
2629
2630        if (!phIsInitialized)
2631                return -PH_NOTINIT;
2632
2633        if (!vlid)
2634        {
2635                /* set contact for all VL */
2636                strncpy(vcontact, uri, sizeof(vcontact));
2637                return 0;
2638        }
2639
2640        vl = ph_valid_vlid(vlid);
2641
2642        if (!vl)
2643                return -PH_BADVLID;
2644
2645        if (vl->contact)
2646                osip_free(vl->contact);
2647
2648#if OLDOSIP
2649        if (translate)
2650        {
2651                char contact[256];
2652                eXosip_guess_contact_uri(uri, contact, sizeof(contact), 1);
2653                vl->contact = osip_strdup(contact);
2654        }
2655        else
2656#endif
2657                vl->contact = osip_strdup(uri);
2658        return 0;
2659
2660}
2661
2662
2663
2664PHAPI_EXPORT int
2665phConf(int cid1, int cid2)
2666{
2667        phcall_t *ca1;
2668        phcall_t *ca2;
2669
2670        if (!phIsInitialized)
2671                return -PH_NOTINIT;
2672
2673        ca1 = ph_locate_call_by_cid(cid1);
2674        ca2 = ph_locate_call_by_cid(cid2);
2675
2676        if(!ca1 || !ca2)
2677                return -PH_BADCFID;
2678
2679        if (0 > ph_msession_conf_start(ca1->mses, ca2->mses, ca1->audiodev_in, ca1->audiodev_out))
2680                return -PH_NORESOURCES;
2681        else
2682                return 0;
2683}
2684
2685PHAPI_EXPORT int
2686phStopConf(int cid1, int cid2)
2687{
2688        phcall_t *ca1;
2689        phcall_t *ca2;
2690
2691        if (!phIsInitialized)
2692                return -PH_NOTINIT;
2693
2694        ca1 = ph_locate_call_by_cid(cid1);
2695        ca2 = ph_locate_call_by_cid(cid2);
2696
2697        if(!ca1 || !ca2)
2698                return -PH_BADCFID;
2699
2700        if( 0 > ph_msession_conf_stop(ca1->mses, ca2->mses))
2701                return -PH_NORESOURCES;
2702        else
2703                return 0;
2704}
2705
2706#define CONF_MODE 1
2707
2708PHAPI_EXPORT int
2709phSetFollowMe(const char *uri)
2710{
2711        if (!phIsInitialized)
2712                return -PH_NOTINIT;
2713
2714        if (!uri)
2715                ph_follow_me_addr[0] = 0;
2716
2717        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2718                return -PH_REDIRLOOP;
2719
2720        strncpy(ph_follow_me_addr, uri, sizeof(ph_follow_me_addr));
2721        return 0;
2722
2723
2724}
2725
2726
2727PHAPI_EXPORT int
2728phSetBusy(int busyFlag)
2729{
2730        ph_busyFlag = busyFlag;
2731        return 0;
2732}
2733
2734
2735PHAPI_EXPORT int
2736phLineSetFollowMe(int vlid, const char *uri)
2737{
2738        struct vline *vl;
2739
2740        if (!phIsInitialized)
2741                return -PH_NOTINIT;
2742
2743        vl = ph_valid_vlid(vlid);
2744
2745        if (!vl)
2746                return -PH_BADVLID;
2747
2748        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2749                return -PH_REDIRLOOP;
2750
2751        if (vl->followme)
2752                osip_free(vl->followme);
2753
2754        vl->followme = osip_strdup(uri);
2755
2756        return 0;
2757
2758}
2759
2760
2761PHAPI_EXPORT int
2762phBlindTransferCall(int cid, const char *uri)
2763{
2764        int i;
2765        phcall_t *ca;
2766        osip_message_t* refer;
2767
2768        if (!phIsInitialized)
2769                return -PH_NOTINIT;
2770
2771        ca = ph_locate_call_by_cid(cid);
2772
2773        if (!ca)
2774                return -PH_BADCID;
2775
2776        if (!nonempty(uri))
2777                return -PH_BADARG;
2778
2779        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2780                return -PH_REDIRLOOP;
2781
2782
2783        ca->localrefer = 1;
2784        phHoldCall(cid);
2785
2786        eXosip_lock();
2787        i = eXosip_call_build_refer(ca->did, (char *)uri, &refer);
2788        if (!i)
2789                i = eXosip_call_send_request(ca->did, refer);
2790        eXosip_unlock();
2791
2792        return i;
2793
2794}
2795
2796
2797PHAPI_EXPORT int
2798phResumeCall(int cid)
2799{
2800        phcall_t *ca;
2801        int i;
2802        osip_message_t *reinvite;
2803
2804        if (!phIsInitialized)
2805                return -PH_NOTINIT;
2806
2807        ca = ph_locate_call_by_cid(cid);
2808
2809        if (!ca)
2810                return -PH_BADCID;
2811
2812        if (!ca->localhold)
2813                return -PH_HOLDERR;
2814
2815#ifndef CONF_MODE
2816        if (ph_has_active_calls())
2817                return -PH_NORESOURCES;
2818#endif
2819
2820        ca->localhold = 0;
2821        ca->localresume = 1;
2822
2823        eXosip_lock();
2824        if (eXosip_call_build_request(ca->did, "INVITE", &reinvite)) {
2825                eXosip_unlock();
2826                return -1;
2827        }
2828        eXosip_unlock();
2829
2830        osip_message_set_subject(reinvite, "Call resuming");
2831        osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
2832
2833        if (ca->sdpctx && ca->sdpctx->offerstr)
2834        {
2835                //FIXME must change the streams direction to a=sendrecv
2836                ph_req_set_body(reinvite, ca->sdpctx->offerstr, "application/sdp");
2837        }
2838
2839        eXosip_lock();
2840        i = eXosip_call_send_request(ca->did, reinvite);
2841        eXosip_unlock();
2842
2843        return i;
2844}
2845
2846PHAPI_EXPORT int
2847phHoldCall(int cid)
2848{
2849        phcall_t *ca;
2850        osip_message_t *reinvite;
2851        int i;
2852
2853        DBG_SIP_NEGO("SIP_NEGO: phHoldCall\n");
2854
2855        if (!phIsInitialized)
2856                return -PH_NOTINIT;
2857
2858        ca = ph_locate_call_by_cid(cid);
2859
2860        if (!ca)
2861                return -PH_BADCID;
2862
2863        if (ca->localhold)
2864                return -PH_HOLDERR;
2865
2866        ca->localhold = 1;
2867
2868        eXosip_lock();
2869        if (eXosip_call_build_request(ca->did, "INVITE", &reinvite)) {
2870                eXosip_unlock();
2871                return -1;
2872        }
2873        eXosip_unlock();
2874
2875        osip_message_set_subject(reinvite, "Call on hold");
2876        osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
2877        if (ca->sdpctx && ca->sdpctx->offerstr)
2878        {
2879                //FIXME must change the streams direction to a=sendonly
2880                ph_req_set_body(reinvite, ca->sdpctx->offerstr, "application/sdp");
2881        }
2882
2883        eXosip_lock();
2884        i = eXosip_call_send_request(ca->did, reinvite);
2885        eXosip_unlock();
2886
2887        osip_mutex_lock(ph_media_stop_mutex);
2888        if (!i && ph_call_hasaudio(ca))
2889        {
2890#ifndef MEDIA_SUSPEND
2891                ph_call_media_stop(ca);
2892#else
2893                ph_call_media_suspend(ca, 1);
2894#endif
2895        }
2896        osip_mutex_unlock(ph_media_stop_mutex);
2897        return i;
2898}
2899
2900
2901PHAPI_EXPORT int
2902phLineSetBusy(int vlid, int busyFlag)
2903{
2904        struct vline *vl;
2905
2906        if (!phIsInitialized)
2907                return -PH_NOTINIT;
2908
2909        vl = ph_valid_vlid(vlid);
2910
2911        if (!vl)
2912                return -PH_BADVLID;
2913
2914        vl->busy = busyFlag;
2915        return 0;
2916}
2917
2918PHAPI_EXPORT int
2919phAddAuthInfo(const char *username, const char *userid,
2920                const char *passwd, const char *ha1,
2921                const char *realm)
2922{
2923        int ret;
2924
2925        DBG_SIP_EVENT("Add auth info username %s userid %s passwd %s realm %s ha1 %s\n",
2926                username, userid, passwd, realm, ha1);
2927
2928        if (!phIsInitialized)
2929                return -PH_NOTINIT;
2930
2931        if (!username)
2932                return -PH_BADARG;
2933
2934        if (!userid)
2935                return -PH_BADARG;
2936
2937        if (!passwd)
2938                return -PH_BADARG;
2939
2940        eXosip_lock();
2941
2942        ret = eXosip_add_authentication_info(username, userid, passwd, ha1, realm);
2943
2944        eXosip_unlock();
2945
2946        return ret;
2947}
2948
2949PHAPI_EXPORT int
2950phvlRegister(int vlid)
2951{
2952        struct vline *vl;
2953        int ret = -1;
2954        char utmp[256];
2955        char stmp[256];
2956        char *server;
2957        osip_message_t *msg;
2958
2959        if (!phIsInitialized)
2960                return -PH_NOTINIT;
2961
2962        vl = ph_vlid2vline(vlid);
2963
2964        assert(vl!=NULL);
2965        assert(vl->username!=NULL);
2966        assert(vl->server!=NULL);
2967
2968        if (vl->displayname)
2969                snprintf(utmp, sizeof(utmp), "\"%s\" <sip:%s@%s>", vl->displayname, vl->username, vl->server);
2970        else
2971                snprintf(utmp, sizeof(utmp), "sip:%s@%s", vl->username, vl->server);
2972
2973        server = stmp;
2974        if (vl->port && vl->port != 5060)
2975        {
2976                /*     snprintf(stmp, sizeof(stmp), "sip:%s@%s:%d", vl->username, vl->server, vl->port); */
2977                snprintf(stmp, sizeof(stmp), "sip:%s:%d", vl->server, vl->port);
2978        }
2979        else
2980        {
2981                /*     snprintf(stmp, sizeof(stmp), "sip:%s@%s:%d", vl->username, vl->server, vl->port); */
2982                snprintf(stmp, sizeof(stmp), "sip:%s", vl->server);
2983        }
2984
2985        eXosip_lock();
2986
2987        if (vl->rid > 0) {
2988                ret = eXosip_register_build_register(vl->rid, vl->regTimeout, &msg);
2989                if (ret)
2990                        vl->rid = -2;
2991        }  else {
2992#if 1
2993                vl->rid = eXosip_register_build_initial_register(utmp, server, vl->contact, vl->regTimeout, &msg);
2994                if (vl->proxy)
2995                        osip_message_set_route(msg, vl->proxy);
2996        }
2997#else
2998                if (vl->proxy && vl->proxy[0] == '<') {
2999                        int size = strlen(vl->proxy);
3000                        char *proxy = alloca(size-1);
3001                        strncpy(proxy, vl->proxy + 1, size - 2);
3002                        proxy[size-2] = '\0';
3003                        vl->rid = eXosip_register_build_initial_register(utmp, proxy, vl->contact, vl->regTimeout, &msg);
3004                }
3005                else
3006                {
3007                        if (vl->proxy)
3008                                vl->rid = eXosip_register_build_initial_register(utmp, vl->proxy, vl->contact, vl->regTimeout, &msg);
3009                        else
3010                                vl->rid = eXosip_register_build_initial_register(utmp, server, vl->contact, vl->regTimeout, &msg);
3011
3012                }
3013        }
3014#endif
3015
3016        if (vl->rid >= 0)
3017        {
3018                osip_message_set_allow(msg, "INVITE, ACK, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, REGISTER");
3019                ph_apply_customizations(msg, NULL, NULL);
3020                ret = eXosip_register_send_register(vl->rid, msg);
3021
3022                if (ret == 0)
3023                {
3024                        ret = vl->rid;
3025                        vl->lastRegTime = time(0);
3026                }
3027        }
3028
3029        eXosip_unlock();
3030
3031        return ret;
3032
3033}
3034
3035PHAPI_EXPORT int phvlSetRegisterTimeOut(int vlid,int regTimeout)
3036{
3037        struct vline *vl;
3038
3039        if (!phIsInitialized)
3040                return -PH_NOTINIT;
3041
3042        vl = ph_vlid2vline(vlid);
3043
3044        if (vl) {
3045                vl->regTimeout = regTimeout;
3046                return 0;
3047        }
3048        return -1;
3049}
3050
3051PHAPI_EXPORT int
3052phSendDtmf(int cid, int dtmfEvent, int mode)
3053{
3054        phcall_t *ca;
3055        char buf[64];
3056        char *ctt;
3057        int i = -1;
3058        osip_message_t *msg;
3059
3060        if (!phIsInitialized)
3061                return -PH_NOTINIT;
3062
3063        ca = ph_locate_call_by_cid(cid);
3064
3065        if (!ca)
3066                return -PH_BADCID;
3067
3068        if (mode & (PH_DTMF_MODE_SIP|PH_DTMF_MODE_SIPRELAY))
3069        {
3070                if (mode & PH_DTMF_MODE_SIP)
3071                {
3072                        ctt = "application/dtmf";
3073                        snprintf(buf, sizeof(buf), "%c", dtmfEvent);
3074                }
3075                else
3076                {
3077                        char sipEvent[3] = { 0, 0, 0 };
3078                        ctt = "application/dtmf-relay";
3079                        if (dtmfEvent == '!')
3080                        {
3081                                sipEvent[0] = '1';
3082                                sipEvent[1] = '6';
3083                        }
3084                        else
3085                                sipEvent[0] = dtmfEvent;
3086
3087                        snprintf(buf, sizeof(buf), "Signal=%s\r\nDuration=250\r\n", sipEvent);
3088                }
3089
3090                eXosip_lock();
3091
3092                i = eXosip_call_build_info(ca->did, &msg),
3093                                ph_req_set_body(msg, buf, ctt);
3094                osip_message_set_contact(msg, ph_get_call_contact(ca));
3095                ph_apply_customizations(msg, NULL, NULL);
3096                i = eXosip_call_send_request(ca->did, msg);
3097
3098                eXosip_unlock();
3099
3100                if (!(mode & PH_DTMF_MODE_ALLRTP)) /* do we need to send DTMF in RTP stream? */
3101                        return i;
3102
3103        }
3104
3105        if (!ph_call_hasaudio(ca))
3106        {
3107                if (!i)
3108                        return 0;   /*  we've managed to send using SIP INFO request */
3109
3110                return -PH_NOMEDIA;
3111        }
3112
3113        return ph_msession_send_dtmf(ca->mses, dtmfEvent, mode);
3114
3115}
3116
3117
3118PHAPI_EXPORT phStream *
3119phPlaySoundFile(const char *fileName , int loop, const char * deviceid)
3120{
3121        if (!phIsInitialized)
3122                return NULL;
3123
3124        return phms_audio_play_sound_file(fileName,loop,deviceid,phcb->soundFileStopped);
3125}
3126
3127PHAPI_EXPORT int 
3128phSetSoundFileGain( phStream * stream, float gain)
3129{
3130        if (!phIsInitialized)
3131                return -PH_NOTINIT;
3132
3133        return phms_audio_set_sound_file_gain(stream,gain);
3134}
3135
3136PHAPI_EXPORT int
3137phSendSoundFile(int cid, const char *fileName)
3138{
3139        phcall_t *ca;
3140
3141        if (!phIsInitialized)
3142                return -PH_NOTINIT;
3143
3144        ca = ph_locate_call_by_cid(cid);
3145
3146        if (!ca)
3147                return -PH_BADCID;
3148
3149        if (!ph_call_hasaudio(ca))
3150                return -PH_NOMEDIA;
3151
3152        return ph_msession_send_sound_file(ca->mses, fileName);
3153}
3154
3155PHAPI_EXPORT int
3156phStopSoundFile( phStream * stream)
3157{
3158        if (!phIsInitialized)
3159                return -PH_NOTINIT;
3160
3161        return phms_audio_stop_sound_file(stream);
3162}
3163
3164PHAPI_EXPORT int
3165phSetSpeakerVolume(int cid,  int volume)
3166{
3167#if 0
3168        phcall_t *ca = ph_locate_call_by_cid(cid);
3169
3170        if (!ca)
3171                return -PH_BADCID;
3172
3173        return(ph_media_set_spkvol(ca, volume));
3174#else
3175        return 0;
3176#endif
3177}
3178
3179
3180PHAPI_EXPORT int
3181phSetRecLevel(int cid,  int level)
3182{
3183#if 0
3184        phcall_t *ca = ph_locate_call_by_cid(cid);
3185
3186        if (!ca)
3187                return -PH_BADCID;
3188
3189        return(ph_media_set_recvol(ca, level));
3190#else
3191        return 0;
3192#endif
3193}
3194
3195
3196
3197
3198PHAPI_EXPORT int
3199phAddVline(const char* username, const char *server, const char*  proxy,  int regTimeout)
3200{
3201        return phAddVline2(NULL, username, server, proxy,  regTimeout);
3202}
3203
3204/*
3205  scrap the :port part from the host uri
3206 */
3207static const char *
3208ph_scrap_port(char *buf, int bufsize, const char *host, int *port)
3209{
3210
3211        assert(buf != 0);
3212        assert(port != 0);
3213
3214        *port = 0;
3215
3216        if (!host)
3217                return 0;
3218
3219        if (!strchr(host, ':'))
3220                return host;
3221
3222        strncpy(buf, host, bufsize);
3223        host = strchr(buf, ':');
3224        if (host)
3225        {
3226                *( char *) host = 0;
3227                *port = atoi(host+1);
3228        }
3229
3230        return buf;
3231
3232}
3233
3234static const char emptystr[] = { 0 };
3235#define nonull(x) ((x) ? (x) : emptystr)
3236
3237PHAPI_EXPORT int
3238phAddVline2(const char *displayname, const char* username, const char *server, const char*  proxy,  int regTimeout)
3239{
3240        return phAddVline3(displayname, username, server, proxy, regTimeout, 0);
3241}
3242PHAPI_EXPORT int
3243phAddVline3(const char *displayname, const char* username, const char *server, const char*  proxy,  int regTimeout, int mobility)
3244
3245{
3246        struct vline *vl;
3247        int oldTimeout = 0;
3248        char srvbuf[256];
3249        const char *srv2;
3250        int port;
3251
3252        DBG_SIP_NEGO("AddVline3(dn = %s, un=%s, srv=%s pxy=%s regT=%d)\n", nonull(displayname), nonull(username), nonull(server),
3253                        nonull(proxy), regTimeout);
3254
3255        if (!phIsInitialized)
3256                return -PH_NOTINIT;
3257
3258        srv2 = ph_scrap_port(srvbuf, sizeof(srvbuf), server, &port);
3259
3260        if (!port)
3261                port = 5060;
3262
3263        if (!username)
3264                username = "";
3265
3266
3267        vl  = ph_find_matching_vline3(username, srv2, port, 0);
3268
3269        if (0 < regTimeout && regTimeout < 100)
3270                regTimeout = 100;
3271
3272        if (!vl)
3273        {
3274                vl = vline_alloc();
3275                if (!vl)
3276                        return -PH_NORESOURCES;
3277
3278                vl->username = osip_strdup(username);
3279        }
3280        else
3281        {
3282                if (vl->proxy)
3283                {
3284                        osip_free(vl->proxy);
3285                        vl->proxy = 0;
3286                }
3287
3288                if (vl->displayname)
3289                {
3290                        osip_free(vl->displayname);
3291                        vl->displayname = 0;
3292                }
3293
3294                if (vl->contact)
3295                {
3296                        osip_free(vl->contact);
3297                        vl->contact = 0;
3298                }
3299                oldTimeout = vl->regTimeout;
3300
3301        }
3302
3303        vl->port = port;
3304
3305        if (nonempty(proxy))
3306        {
3307                if (0 == strstr(proxy, "sip:"))
3308                {
3309                        int l = 15 + strlen(proxy);
3310                        vl->proxy = osip_malloc(l);
3311                        snprintf(vl->proxy, l, "sip:%s", proxy);
3312                }
3313                else
3314                        vl->proxy = osip_strdup(proxy);
3315        }
3316
3317
3318
3319        if (nonempty(srv2) && !vl->server)
3320                vl->server = osip_strdup(srv2);
3321
3322        if (nonempty(displayname))
3323                vl->displayname = osip_strdup(displayname);
3324
3325        vl->regTimeout = regTimeout;
3326
3327        if(vcontact[0])
3328                vl->contact = osip_strdup(vcontact);
3329        else
3330        {
3331                char ctct[512];
3332
3333                ph_build_contact(ctct, sizeof(ctct), vl);
3334                vl->contact = osip_strdup(ctct);
3335
3336        }
3337
3338        if (checkmobility(mobility,PH_LINE_MOBILITY_FIXED))
3339                add_contact_param(vl, "mobility", "fixed", FALSE);
3340        else if (checkmobility(mobility, PH_LINE_MOBILITY_MOBILE))
3341                add_contact_param(vl, "mobility", "mobile", FALSE);
3342        else if (checkmobility(mobility,PH_LINE_MOBILITY_PHONE))
3343                add_contact_param(vl, "user", "phone", TRUE);
3344
3345
3346        vl->mobility = mobility;
3347
3348        if (nonempty(srv2) && (oldTimeout > 0 || regTimeout > 0))
3349                phvlRegister(ph_vline2vlid(vl));
3350
3351        return ph_vline2vlid(vl);
3352}
3353
3354
3355PHAPI_EXPORT int
3356phDelVline(int vlid)
3357{
3358        struct vline *vl;
3359        phcall_t *ca;
3360
3361        if (!phIsInitialized)
3362                return -PH_NOTINIT;
3363
3364        if (!(vl = ph_valid_vlid(vlid)))
3365                return -PH_BADVLID;
3366
3367        /* forbid deletion of the lines which have pending calls */
3368        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS]; ca++)
3369        {
3370                if (ca->vlid == vlid && ca->cid > 0)
3371                        return -PH_VLBUSY;
3372        }
3373
3374
3375        if (vl->pub.timeout)
3376                phLinePublish2(vlid, vl->pub.uri, 0, 0, 0, 0);
3377
3378        /*
3379     if the line has an associatied timeout,
3380     it means it is regsitered on some server,
3381     so we need to unregister
3382         */
3383        if (vl->regTimeout)
3384        {
3385                osip_message_t *msg;
3386
3387                eXosip_lock();
3388                eXosip_register_build_register(vl->rid, 0, &msg);
3389                eXosip_register_send_register(vl->rid, msg);
3390                vl->regTimeout = 0;
3391                vl->used = VL_DELETING;
3392                eXosip_unlock();
3393
3394        }
3395
3396        if (vl->used != VL_DELETING)
3397                return 0;
3398
3399        return 0;
3400}
3401
3402
3403
3404PHAPI_EXPORT int phChangeAudioDeviceIn(const char *devstr)
3405{
3406        if (devstr)
3407                strncpy(phcfg.audio_dev_in, devstr, sizeof(phcfg.audio_dev_in));
3408
3409        return 0;
3410}
3411
3412PHAPI_EXPORT int phChangeAudioDeviceOut(const char *devstr)
3413{
3414        if (devstr)
3415                strncpy(phcfg.audio_dev_out, devstr, sizeof(phcfg.audio_dev_out));
3416       
3417        return 0;
3418}
3419
3420PHAPI_EXPORT int phChangeVideoDevices(const char *devstr)
3421{
3422        if (devstr)
3423                strncpy(phcfg.video_config.video_device, devstr, sizeof(phcfg.video_config.video_device));
3424       
3425        return 0;
3426}
3427
3428static struct vline *
3429vline_alloc()
3430{
3431        int i;
3432
3433        for(i = 0; i < PH_MAX_VLINES; i++)
3434        {
3435                struct vline *vl = ph_vlines + i;
3436
3437                if (!vl->used)
3438                {
3439                        memset(vl, 0, sizeof(*vl));
3440                        vl->used = 1;
3441                        vl->port = 0;
3442                        return vl;
3443                }
3444
3445        }
3446        return 0;
3447}
3448
3449static void
3450vline_free(struct vline *vl)
3451{
3452        if (vl->used)
3453        {
3454                osip_free(vl->username);
3455                if (vl->server)
3456                        osip_free(vl->server);
3457                if (vl->proxy)
3458                        osip_free(vl->proxy);
3459                if (vl->displayname)
3460                        osip_free(vl->displayname);
3461                if (vl->followme)
3462                        osip_free(vl->followme);
3463                if (vl->contact)
3464                        osip_free(vl->contact);
3465                if (vl->pub.etag)
3466                        osip_free(vl->pub.etag);
3467                if (vl->pub.uri)
3468                        osip_free(vl->pub.uri);
3469                if (vl->pub.evt)
3470                        osip_free(vl->pub.evt);
3471                if (vl->pub.ctt)
3472                        osip_free(vl->pub.ctt);
3473                if (vl->pub.body)
3474                        osip_free(vl->pub.body);
3475
3476
3477                vl->used = 0;
3478        }
3479}
3480
3481static struct vline *
3482ph_find_vline_by_rid(int rid)
3483{
3484        int i;
3485
3486        for(i = 0; i < PH_MAX_VLINES; i++)
3487        {
3488                struct vline *vl = ph_vlines + i;
3489
3490                if (vl->used && rid == vl->rid)
3491                        return vl;
3492        }
3493        return 0;
3494}
3495
3496
3497static osip_from_t *
3498ph_parse_from(const char *userid)
3499{
3500        osip_from_t *from;
3501
3502        osip_from_init(&from);
3503        if (!from)
3504                return 0;
3505
3506        osip_from_parse(from, userid);
3507        if (from->url && from->url->port && !strcmp(from->url->port, "5060"))
3508        {
3509                osip_free(from->url->port);
3510                from->url->port = NULL;
3511        }
3512
3513        return from;
3514
3515}
3516
3517static struct vline *
3518ph_find_matching_vline(const char *userid, int ignore)
3519{
3520        osip_from_t *from;
3521        struct vline *vl;
3522        char *host;
3523        char hostport[256];
3524        char *uname;
3525
3526        hostport[0] = 0;
3527        from = ph_parse_from(userid);
3528
3529        if (!from)
3530                return 0;
3531
3532        if (from->url)
3533                uname = from->url->username;
3534        else
3535                uname = hostport;
3536
3537
3538        if (!(ignore & PHM_IGNORE_PORT) && from->url && from->url->port)
3539        {
3540                snprintf(hostport, sizeof(hostport), "%s:%s", from->url->host, from->url->port);
3541                host = hostport;
3542        }
3543        else if (ignore & PHM_IGNORE_HOST)
3544                host = 0;
3545        else if (from->url)
3546        {
3547                host = from->url->host;
3548        }
3549        else
3550                host = hostport;
3551
3552        vl = ph_find_matching_vline2(uname, host, ignore);
3553
3554        osip_from_free(from);
3555
3556        return vl;
3557
3558}
3559
3560
3561static struct vline *
3562ph_find_matching_vline2(const char *username, const char* host, int ignore)
3563{
3564        return ph_find_matching_vline3(username, host, 0, ignore);
3565}
3566
3567static struct vline *
3568ph_find_matching_vline3(const char *username, const char* host, int port, int ignore)
3569{
3570        int i;
3571        int   hostlen;
3572        int   unamelen;
3573        struct vline *vl, *defaultvl = 0;
3574
3575        if (!username)
3576                username = "";
3577
3578        hostlen = host ? strlen(host) : 0;
3579        unamelen =  strlen(username);
3580
3581        if (port == 0)
3582                port = 5060;
3583
3584        for( i = 0; i < PH_MAX_VLINES; i++)
3585        {
3586                int len;
3587                vl = ph_vlines + i;
3588
3589                if (!vl->used)
3590                        continue;
3591
3592                if (!vl->server)
3593                {
3594                        defaultvl = vl;
3595                        continue;
3596                }
3597
3598                len = strlen(vl->server);
3599
3600                if ((ignore & PHM_IGNORE_HOST) || ((len == hostlen) && !strcasecmp(host, vl->server)))
3601                {
3602                        len = strlen(vl->username);
3603
3604                        if ((len == unamelen) && !strcasecmp(username, vl->username))
3605                        {
3606                                if (ignore & PHM_IGNORE_PORT)
3607                                {
3608                                        defaultvl = vl;
3609                                        break;
3610                                }
3611                                if (port == vl->port)
3612                                {
3613                                        defaultvl = vl;
3614                                        break;
3615                                }
3616                        }
3617                }
3618        }
3619
3620        return defaultvl;
3621}
3622
3623static void
3624ph_nat_refresh(struct vline *vl)
3625{
3626        char buf[128];
3627        char to[128];
3628        assert(vl!=NULL);
3629
3630        ph_build_from(buf, sizeof(buf), vl);
3631        snprintf(to, sizeof(to), "sip:ping@%s", vl->server);
3632        phSendOptions(buf, to);
3633
3634#if 0
3635        int port;
3636
3637
3638        osip_uri_init(&uri);
3639        osip_uri_parse(uri,  (vl->proxy && vl->proxy[0]) ? vl->proxy : vl->server);
3640
3641        port = atoi((uri->port && uri->port[0]) ? uri->port : "5060");
3642        phPing(uri->host, port, 30);
3643
3644        osip_uri_free(uri);
3645#endif
3646
3647}
3648
3649static time_t last_vline_refresh, last_nat_refresh;
3650static void
3651ph_refresh_vlines()
3652{
3653        int nat_refresh_time = ( phcfg.transport == IPPROTO_UDP ) ? phcfg.nat_refresh_udp_time : phcfg.nat_refresh_tcp_time;
3654        time_t now = time(NULL);
3655
3656        if (now - last_vline_refresh > 5)
3657        {
3658                int i;
3659                struct vline *vl;
3660
3661                for( i = 0; i < PH_MAX_VLINES; i++)
3662                {
3663                        vl = ph_vlines + i;
3664                        if (!vl->used)
3665                                continue;
3666
3667                        //it's now handled by eXosip_automatic_action() so no more need to do ti manually
3668                        /*if (vl->server && vl->server[0] && vl->regTimeout > 0)
3669                        {
3670                                if ((now - vl->lastRegTime) > (vl->regTimeout - 10))
3671                                        phvlRegister(ph_vline2vlid(vl));
3672                        }*/
3673                        if (vl->pub.timeout && (now - vl->pub.last) > (vl->pub.timeout - ph_resend_offset))
3674                        {
3675                                phLinePublish2(ph_vline2vlid(vl), vl->pub.uri, 0, 0, 0, vl->pub.timeout);
3676                        }
3677                }
3678                last_vline_refresh = time(0);
3679        }
3680
3681        //if (!phcfg.use_tunnel && phcfg.nat_refresh_time > 0)
3682        if (nat_refresh_time > 0)
3683        {
3684                int i;
3685                struct vline *vl;
3686
3687                if (now - last_nat_refresh > nat_refresh_time)
3688                {
3689                        for( i = 0; i < PH_MAX_VLINES; i++)
3690                        {
3691                                vl = ph_vlines + i;
3692                                if (!vl->used)
3693                                        continue;
3694
3695                                if (vl->server && vl->server[0] && vl->regTimeout > ph_resend_offset)
3696                                {
3697                                        ph_nat_refresh(vl);
3698                                }
3699                        }
3700
3701                        last_nat_refresh = time(0);
3702                }
3703        }
3704
3705
3706}
3707
3708
3709/*
3710  scan call marked for close and close them while delivering phCALLCLOSED to phApi client
3711 */
3712static void
3713ph_scan_calls()
3714{
3715        int i;
3716        phcall_t *ca;
3717
3718        ca = ph_calls;
3719        for(i = PH_MAX_CALLS; i; i--, ca++)
3720        {
3721                if (ca->cid > 0 &&
3722                                (ca->closereq ||
3723                                                ((ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) && !ph_call_stream_alive(ca))))
3724                {
3725                        phCallStateInfo_t info;
3726                        int cid = ca->cid;
3727
3728                        clear(info);
3729                        info.vlid = ca->vlid;
3730                        info.event = phCALLCLOSED;
3731
3732                        ph_release_call(ca);
3733
3734                        phcb->callProgress(cid, &info);
3735                }
3736        }
3737
3738}
3739
3740static char *
3741ph_get_proxy(const char *userid)
3742{
3743        struct vline *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
3744
3745        if (!vl)
3746                return "";
3747
3748        return vl->proxy ? vl->proxy : "";
3749}
3750
3751
3752static char *
3753ph_get_call_contact(phcall_t *ca)
3754{
3755        struct vline *vl;
3756        assert(ca!=NULL);
3757
3758        vl = ph_vlid2vline(ca->vlid);
3759        if (!vl)
3760                return 0;
3761
3762        return vl->contact;
3763}
3764
3765
3766static int
3767ph_get_vline_id(const char *userid, const char *altid)
3768{
3769
3770        struct vline *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
3771
3772        if (vl)
3773                return ph_vline2vlid(vl);
3774
3775        if (nonempty(altid))
3776        {
3777                vl = ph_find_matching_vline(altid, PHM_IGNORE_PORT);
3778                if (vl)
3779                        return ph_vline2vlid(vl);
3780        }
3781
3782        vl = ph_find_matching_vline(userid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
3783        if (vl)
3784                return ph_vline2vlid(vl);
3785
3786
3787        if (nonempty(altid))
3788        {
3789                vl = ph_find_matching_vline(altid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
3790                if (vl)
3791                        return ph_vline2vlid(vl);
3792        }
3793
3794        return 0;
3795
3796}
3797
3798static void ph_setup_payload(const char *ptstring)
3799{
3800        PayloadType *rtppt;
3801        int g722hack = 0;
3802
3803        DBG_CODEC_LOOKUP("trying to setup codec in eXosip: %s\n", ptstring, 0, 0);
3804        if(!strncasecmp(ptstring, "G722", 4))
3805        {
3806                g722hack = 1;
3807                ptstring = "G722/16000";
3808        }
3809
3810        if (ph_media_supported_payload(&rtppt, ptstring))
3811        {
3812                char* fmtp = 0;
3813                if (!strncasecmp(ptstring,"telephone-event", 15))
3814                        fmtp = osip_strdup("0-11");
3815
3816
3817                sdp_payload_list_add(&ph_audio_payloads, rtp_profile_get_payload_number_from_rtpmap(&av_profile, ptstring), payload_type_get_rtpmap(rtppt), fmtp, 0);
3818        } else
3819                DBG_CODEC_LOOKUP("...setup refused %s- not found in ortp profile or not supported by mediastreamer\n", ptstring);
3820}
3821
3822#ifdef PHAPI_VIDEO_SUPPORT
3823static void ph_setup_video_payload(const char *ptstring)
3824{
3825        PayloadType *rtppt;
3826
3827        if (ph_media_supported_payload(&rtppt, ptstring))
3828        {
3829                sdp_payload_list_add(&ph_video_payloads, rtp_profile_get_payload_number_from_rtpmap(&av_profile, ptstring), payload_type_get_rtpmap(rtppt), 1);
3830        }
3831        else
3832        {
3833                DBG_CODEC_LOOKUP("unsupported codec %s\n",ptstring);
3834        }
3835}
3836#endif
3837
3838
3839/**
3840 * Initialize the phoneapi module
3841 */
3842
3843#ifdef OS_WIN32
3844
3845static int
3846wsock_init()
3847{
3848        WORD wVersionRequested;
3849        WSADATA wsaData;
3850        int i;
3851
3852        wVersionRequested = MAKEWORD(2,0);
3853        if(i = WSAStartup(wVersionRequested,  &wsaData))
3854        {
3855                return -1;
3856        }
3857        return 0;
3858}
3859#else
3860#define wsock_init() 0
3861#endif
3862
3863#ifdef ANDROID
3864void  and_osip_print_dbg(char *li, int fi, osip_trace_level_t level, char *chfr, va_list ap)
3865{
3866        int prio;
3867        switch(level){
3868        case OSIP_INFO3:
3869        case OSIP_INFO4:
3870                prio = ANDROID_LOG_DEBUG;
3871                break;                                               
3872        case OSIP_INFO1:
3873        case OSIP_INFO2:
3874                prio = ANDROID_LOG_INFO;
3875                break;                                               
3876        case OSIP_WARNING:
3877                prio = ANDROID_LOG_WARN;
3878                break;                                               
3879        case OSIP_ERROR:
3880                prio = ANDROID_LOG_ERROR;
3881                break;                                               
3882        case OSIP_FATAL:
3883                prio = ANDROID_LOG_FATAL;
3884                break;                                               
3885        default:
3886                prio = ANDROID_LOG_DEFAULT;
3887                break;                                               
3888        }
3889
3890        __android_log_vprint(prio, "phapi", chfr, ap);
3891}
3892#endif
3893
3894
3895static int
3896ph_debug_init()
3897{
3898        const char *dbgstr;
3899
3900        dbgstr = getenv("PH_DEBUG_LEVEL");
3901        if (dbgstr)
3902                phDebugLevel = atoi(dbgstr);
3903
3904        if (phDebugLevel > 0)
3905        {
3906                if (!phLogFileName)
3907                        phLogFileName = getenv("PH_LOG_FILENAME");
3908
3909
3910                ph_log_file = phLogFileName ? fopen (phLogFileName, "w+") : stdout;
3911
3912
3913                if (!ph_log_file)
3914                {
3915                        perror ("phapi: log file");
3916                        return -1;
3917                }
3918                osip_trace_initialize (phDebugLevel, ph_log_file);
3919#ifdef ANDROID
3920
3921        osip_trace_initialize_func(phDebugLevel, and_osip_print_dbg);
3922#endif
3923        }
3924
3925        return 0;
3926
3927}
3928
3929
3930static void
3931ph_avcodec_init()
3932{
3933#ifdef PHAPI_VIDEO_SUPPORT
3934        avcodec_init();
3935        avcodec_register_all();
3936        phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_128KBPS;
3937#endif
3938
3939}
3940
3941
3942static void
3943ph_calls_init()
3944{
3945        int i;
3946
3947        for( i = 0; i < PH_MAX_CALLS; i++)
3948                ph_calls[i].cid = -1;
3949
3950}
3951
3952static int
3953ph_tunnel_init()
3954{
3955#ifdef USE_HTTP_TUNNEL
3956        eXosip_tunnel_t *tunnel = NULL;
3957        int port;
3958        char *c;
3959        char buf[256];
3960        int tunerr;
3961
3962        if (!(phcfg.use_tunnel & PH_TUNNEL_USE))
3963                return 0;
3964
3965        http_tunnel_init_host(phcfg.httpt_server, phcfg.httpt_server_port, phcfg.use_tunnel & PH_TUNNEL_SSL);
3966        http_tunnel_init_proxy(phcfg.http_proxy,phcfg.http_proxy_port,
3967                        phcfg.http_proxy_user, phcfg.http_proxy_passwd);
3968
3969        tunnel = malloc(sizeof(eXosip_tunnel_t));
3970        if (tunnel)
3971        {
3972                strncpy(buf, phcfg.proxy, sizeof(buf));
3973                c = strstr(buf, ":");
3974
3975                port = 5060;
3976                if (c)
3977                {
3978                        *c++ = 0;
3979                        port = atoi(c);
3980                }
3981                tunnel->h_tunnel = http_tunnel_open(buf, port, HTTP_TUNNEL_VAR_MODE, &tunerr, -1);
3982                if (!tunnel->h_tunnel)
3983                {
3984                        if (!tunnel->h_tunnel)
3985                        {
3986                                free(tunnel);
3987                                return -PH_NOTUNNEL;
3988                        }
3989                }
3990
3991                tunnel->tunnel_recv = http_tunnel_recv;
3992                tunnel->tunnel_send = http_tunnel_send;
3993                tunnel->get_tunnel_socket = http_tunnel_get_socket;
3994                phTunnel = tunnel;
3995                ph_nat_type = TUNNEL;
3996                return 0;
3997        }
3998
3999
4000
4001
4002        return -PH_NORESOURCES;
4003#else
4004        return -1;
4005#endif
4006}
4007
4008#ifdef USE_UPNP
4009
4010static int
4011ph_upnp_add_redirection(const char * addr, char * local_port, char * extern_port, char * proto)
4012{
4013        if( UPNP_AddPortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, extern_port,local_port, addr, 0,proto, 0) == UPNPCOMMAND_SUCCESS)
4014        {
4015                return 0;
4016        }
4017       
4018        return -1;
4019}
4020
4021static int
4022ph_upnp_remove_redirection(char * sport, char * proto)
4023{
4024        if( UPNP_DeletePortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, sport, proto,0) == UPNPCOMMAND_SUCCESS)
4025        {
4026                return 0;
4027        }
4028       
4029        return -1;
4030}
4031
4032static int
4033ph_upnp_init()
4034{
4035        int result = -1;
4036       
4037        char lanaddr[16];
4038        struct UPNPDev * devlist = upnpDiscover(500, 0, 0, 0);
4039        if( UPNP_GetValidIGD(devlist, &ph_upnp_urls, &ph_upnp_data, lanaddr, sizeof(lanaddr)) == 1 )
4040        {
4041                if(phcfg.local_ip_addr[0] == 0)
4042                        snprintf(phcfg.local_ip_addr, sizeof(phcfg.local_ip_addr),"%s",lanaddr);
4043                       
4044                if( UPNP_GetExternalIPAddress(ph_upnp_urls.controlURL,ph_upnp_data.first.servicetype,ph_nat_router_addr) == UPNPCOMMAND_SUCCESS)
4045                {
4046                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%s", _get_local_sip_port());
4047                       
4048                        result = ph_upnp_add_redirection(phcfg.local_ip_addr,_get_local_sip_port(),ph_nat_sip_port_str, phcfg.transport == IPPROTO_UDP ? "UDP" : "TCP");
4049                        if(!result)
4050                        {
4051                                eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4052                                ph_nat_type = UPNP;
4053                        }
4054                }
4055        }
4056        freeUPNPDevlist(devlist); 
4057       
4058        return result;
4059}
4060
4061#endif
4062
4063static int
4064ph_stun_init()
4065{
4066        bool_t resPort = 0, hairpin = 0;
4067        StunAddress4 stunServerAddr;
4068        stunParseServerName(phcfg.stunserver, &stunServerAddr);
4069       
4070        ph_stun_nat_type = stunNatType( &stunServerAddr, &resPort, &hairpin,0, 0);
4071       
4072        if( ph_stun_nat_type == StunTypeConeNat || ph_stun_nat_type == StunTypeRestrictedNat || ph_stun_nat_type == StunTypePortRestrictedNat)
4073        {
4074                StunAddress4 mappedAddr;
4075                Socket  sock = stunOpenSocket(&stunServerAddr, &mappedAddr, atoi(_get_local_sip_port()), 0);
4076               
4077                if ( sock != -1 )
4078                {
4079                        ph_ipv4tostr(ph_nat_router_addr, mappedAddr);
4080                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%d", mappedAddr.port);
4081                        closesocket(sock);
4082                       
4083                        eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4084                        ph_nat_type = STUN;
4085                       
4086                        return 0;
4087                }
4088        }
4089       
4090        return -1;
4091}
4092
4093static void
4094ph_nat_init()
4095{
4096        ph_nat_router_addr[0] = 0;
4097        ph_nat_port_str[0] = 0;
4098       
4099        if (!phcfg.nat_refresh_udp_time)
4100                phcfg.nat_refresh_udp_time = 15;
4101       
4102        if (!phcfg.nat_refresh_tcp_time)
4103                phcfg.nat_refresh_tcp_time = 15;
4104
4105#ifdef USE_UPNP
4106        if(phcfg.use_upnp)
4107        {
4108                if(!ph_upnp_init())
4109                        return;
4110        }
4111#endif
4112       
4113        if(phcfg.use_stun)
4114        {
4115                if(!ph_stun_init())
4116                        return;
4117        }
4118       
4119        if(phcfg.use_tunnel)
4120        {
4121                if(!ph_tunnel_init())
4122                        return;
4123        }
4124
4125        //nat should be open
4126        ph_nat_type = OPEN;
4127        phcfg.nat_refresh_udp_time = 0;
4128        phcfg.nat_refresh_tcp_time = 0;
4129       
4130        if (phcfg.local_ip_addr[0] != 0)
4131                eXosip_masquerade_contact(phcfg.local_ip_addr, atoi(_get_local_sip_port()));
4132}
4133
4134/**
4135 * @brief initialize the payload/codecs that are allowed to be handled by the SIP stack
4136 */
4137PHAPI_EXPORT void
4138ph_payloads_init()
4139{
4140        osip_list_init(&ph_audio_payloads);
4141#ifdef PHAPI_VIDEO_SUPPORT
4142        osip_list_init(&ph_video_payloads);
4143        if (!phcfg.video_codecs[0]) {
4144                ph_setup_video_payload("H263/90000");
4145        } else {
4146                char tmp[32];
4147                char *tok = strtok(phcfg.video_codecs, ",");
4148
4149                while(tok) {
4150                        snprintf(tmp, sizeof(tmp), "%s/90000", tok);
4151                        ph_setup_video_payload(tmp);
4152                        DBG_CODEC_LOOKUP("phapi: added video codec: %s\n",tmp);
4153                        tok = strtok(0, ",");
4154                }
4155        }
4156#endif
4157
4158        // init payload/codecs for AUDIO
4159
4160        // add codecs out of an ENV var
4161        {
4162                char *aclist = getenv("PH_AUDIO_CODECS");
4163                if (aclist) {
4164                        strncpy(phcfg.audio_codecs, aclist, sizeof(phcfg.audio_codecs));
4165                }
4166
4167        }
4168
4169
4170        // limit codecs to G711 codecs according to compile time DEFINE
4171#ifdef G711_ONLY
4172        strcpy(phcfg.audio_codecs, "PCMU/8000,PCMA/8000");
4173#endif
4174
4175        // if at this stage, no codecs are required, fix a default list
4176        if (!phcfg.audio_codecs[0])
4177        {
4178                ph_setup_payload("PCMU/8000");
4179                ph_setup_payload("PCMA/8000");
4180                ph_setup_payload("GSM/8000");
4181                ph_setup_payload("ILBC/8000");
4182                ph_setup_payload("SPEEX/16000");
4183                ph_setup_payload("SPEEX/8000");
4184                ph_setup_payload("AMR/8000");
4185                ph_setup_payload("AMR-WB/16000");
4186                ph_setup_payload("G722/8000");
4187                ph_setup_payload("G726-32/8000");
4188
4189        }
4190        // phapi.h client has required a specific list of codecs
4191        else
4192        {
4193
4194                /*
4195        The list is "," separated
4196        some hacks are present to allow for :
4197        - payload usurpation
4198        - default /8000 clockrate when not specified
4199        - ... look at the code
4200                 */
4201
4202
4203                char tmp[32];
4204                char *tok = strtok(phcfg.audio_codecs, ",");
4205
4206                while(tok)
4207                {
4208                        if(!strcasecmp(tok, "G722/8000"))
4209                                strcpy(tmp, "G722/16000");
4210                        else if(!strcmp(tok, "AMR-WB"))
4211                        {
4212#ifdef AMR_OVER_G729_HACK
4213                                snprintf(tmp, sizeof(tmp), "G729/8000");
4214#else
4215                                snprintf(tmp, sizeof(tmp), "%s/16000", tok);
4216#endif
4217                        }
4218#ifdef SPEEX_OVER_G729_HACK
4219                        else if(!strcmp(tok, "SPEEX/16000"))
4220                        {
4221                                snprintf(tmp, sizeof(tmp), "G729/8000");
4222                        }
4223#endif
4224                        else if (strchr(tok, '/'))
4225                                strncpy(tmp, tok, sizeof(tmp));
4226                        else
4227                                snprintf(tmp, sizeof(tmp), "%s/8000", tok);
4228
4229                        ph_setup_payload(tmp);
4230
4231                        tok = strtok(0, ",");
4232                }
4233        }
4234
4235        // set codec in sip stack for CNG (confort noise generator=
4236        if(phcfg.cng)
4237                ph_setup_payload("CN/8000");
4238
4239        // set codec in sip stack for DTMF
4240        ph_setup_payload("telephone-event/8000");
4241}
4242
4243static int
4244ph_get_call_id(int did, char **cid)
4245{
4246        char referto[512];
4247        char *cp, *semi;
4248        int i;
4249
4250        i = eXosip_call_get_referto(did, referto, sizeof(referto));
4251        if (i)
4252                return -PH_ERROR;
4253        cp = strstr(referto, "Replaces");
4254        if (!cp)
4255                return -PH_ERROR;
4256        cp += 9;
4257        semi = strchr(cp, ';');
4258        if (semi)
4259                *semi = 0;
4260
4261        *cid = osip_strdup(cp);
4262
4263        return *cid ? 0 : -PH_NORESOURCES;
4264}
4265
4266
4267PHAPI_EXPORT int
4268phCallGetSipCallID(int cid, char* buf, int bufsize)
4269{
4270        phcall_t *ca;
4271        char *callid;
4272        int i;
4273
4274        if (!phIsInitialized)
4275                return -PH_NOTINIT;
4276
4277        ca = ph_locate_call_by_cid(cid);
4278
4279        if (!ca)
4280                return -PH_BADCID;
4281
4282        if( bufsize  <= 0 || !buf)
4283                return -PH_BADARG;
4284
4285
4286        eXosip_lock();
4287        i = ph_get_call_id(ca->did, &callid);
4288        eXosip_unlock();
4289
4290        if(!i)
4291        {
4292                strncpy(buf, callid, bufsize);
4293                osip_free(callid);
4294                return 0;
4295        }
4296
4297        return -PH_ERROR;
4298}
4299
4300PHAPI_EXPORT int
4301phInit(phCallbacks_t *cbk, char * server, int asyncmode)
4302{
4303        int i;
4304        int proto;
4305        int secure;
4306        const char *tmp;
4307        int nat_refresh_time = 0;
4308
4309        if (phIsInitialized)
4310                return 0;
4311
4312        memset(vcontact, 0, sizeof(vcontact));
4313
4314        i = ph_debug_init();
4315
4316        if (i)
4317                return i;
4318
4319        tmp = getenv("EXOSIP_RESEND_OFFSET");
4320        if (tmp && strlen(tmp))
4321                ph_resend_offset = atoi(tmp);
4322
4323        ph_avcodec_init();
4324        ph_calls_init();
4325
4326        if (phcfg.use_tunnel)
4327        {
4328                i = ph_tunnel_init();
4329                if (i)
4330                        return i;
4331        }
4332
4333#ifdef FORCE_VAD
4334        /* HACK for test */
4335#ifdef EMBED
4336        phcfg.vad = VAD_VALID_MASK | (500 & VAD_THRESHOLD_MASK);
4337#else
4338        phcfg.vad = VAD_VALID_MASK | (1000 & VAD_THRESHOLD_MASK);
4339#endif
4340#endif
4341
4342#ifdef FORCE_CNG
4343        /* HACK for test */
4344        phcfg.cng = 1;
4345#endif
4346
4347
4348        ph_media_init(phcfg.plugin_path); //init ortp/ms2 payloads list, init ms2 and ortp
4349
4350        if (phcfg.use_tunnel) {
4351
4352                // ph_setup_tunnel();
4353
4354        }
4355
4356
4357        proto = phcfg.transport;
4358        secure = 0;
4359
4360
4361        i = eXosip_init();
4362        if (i)
4363                return -1;
4364       
4365        ph_nat_init();
4366       
4367        DBG_SIP_NEGO("NAT type: %s fw=%s \n", ph_get_nat_type(), ph_nat_router_addr);
4368
4369        if (phcfg.public_ip_addr[0])
4370        {
4371                int port = atoi(phcfg.public_sipport);
4372                eXosip_masquerade_contact(phcfg.public_ip_addr, port ? port : atoi(phcfg.sipport));
4373        }
4374
4375        if (phcfg.local_ip_addr[0] == 0)
4376                eXosip_listen_addr(proto, NULL, atoi(phcfg.sipport), AF_INET, secure);
4377        else
4378                eXosip_listen_addr(proto, phcfg.local_ip_addr, atoi(phcfg.sipport), AF_INET, secure);
4379
4380        {
4381                const char * ua  = "phapi/eXosip-" PHAPI_VERSION_STRING;
4382                eXosip_set_user_agent(ua);
4383        }
4384
4385        nat_refresh_time = (phcfg.transport == IPPROTO_UDP) ? phcfg.nat_refresh_udp_time : phcfg.nat_refresh_tcp_time;
4386        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE, &nat_refresh_time);
4387        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE_ADJUST, &phcfg.nat_refresh_time_adjust);
4388
4389        eXosip_set_cbconnection_close(ph_connection_lost);
4390       
4391        memset(ph_vlines, 0, sizeof(ph_vlines));
4392
4393        ph_payloads_init(); //init phapi codecs lists
4394
4395        /* register callbacks? */
4396        phcb = cbk;
4397        phcfg.asyncmode = asyncmode;
4398        if (!asyncmode)
4399                timeout = 1;
4400        else
4401                timeout = 10000;
4402
4403        ph_media_start_mutex = osip_mutex_init();
4404        ph_media_stop_mutex = osip_mutex_init();
4405        ph_custom_mutex = osip_mutex_init();
4406        osip_list_init(&ph_custom_headers);
4407
4408        ph_hdrmon_mutex = osip_mutex_init();
4409        osip_list_init(&ph_hdrmon_list);
4410
4411
4412
4413        if (asyncmode)
4414                phapithread = osip_thread_create(20000, ph_api_thread, (void*)0);
4415
4416        phIsInitialized = 1;
4417
4418        return 0;
4419}
4420
4421PHAPI_EXPORT int
4422phAudioCaptureCardList(ph_audio_card_desc_t** device_tab)
4423{
4424        if (!phIsInitialized)
4425                return -PH_NOTINIT;
4426
4427        return phms_audio_get_capture_sndcard_list(device_tab);
4428}
4429
4430PHAPI_EXPORT int
4431phAudioPlaybackCardList(ph_audio_card_desc_t** device_tab)
4432{
4433        if (!phIsInitialized)
4434                return -PH_NOTINIT;
4435
4436        return phms_audio_get_playback_sndcard_list(device_tab);
4437}
4438
4439PHAPI_EXPORT int
4440phVideoWebcamList(ph_video_web_cam_desc_t** device_tab)
4441{
4442        if (!phIsInitialized)
4443                return -PH_NOTINIT;
4444#ifdef PHAPI_VIDEO_SUPPORT     
4445        return phms_video_get_web_cam_list(device_tab);
4446#else
4447        return 0;
4448#endif
4449}
4450
4451int phTunnelConfig(const char* http_proxy, const int http_proxy_port,
4452                const char* httpt_server, const int httpt_server_port,
4453                const char *proxy_user, const char* proxy_passwd,
4454                int use_ssl, int autoconf)
4455{
4456        if (!phIsInitialized)
4457                return -PH_NOTINIT;
4458
4459        phcfg.httpt_server[0] = 0;
4460        phcfg.http_proxy[0] = 0;
4461        phcfg.use_tunnel = 0;
4462
4463        if (!httpt_server) {
4464                return -1;
4465        }
4466
4467        phcfg.http_proxy_port = http_proxy_port;
4468        if (!httpt_server_port)
4469                if (!http_proxy) {
4470                        phcfg.httpt_server_port = 80;
4471                }
4472                else {
4473                        phcfg.httpt_server_port = 443;
4474                }
4475        else
4476                phcfg.httpt_server_port = httpt_server_port;
4477
4478        if (httpt_server)
4479                strncpy(phcfg.httpt_server, httpt_server, sizeof(phcfg.httpt_server));
4480        if (http_proxy)
4481                strncpy(phcfg.http_proxy, http_proxy, sizeof(phcfg.http_proxy));
4482
4483        if (proxy_user)
4484                strncpy(phcfg.http_proxy_user, proxy_user, sizeof(phcfg.http_proxy_user));
4485        if (proxy_passwd)
4486                strncpy(phcfg.http_proxy_passwd, proxy_passwd, sizeof(phcfg.http_proxy_passwd));
4487
4488        phcfg.use_tunnel = PH_TUNNEL_USE;
4489        if (use_ssl)
4490                phcfg.use_tunnel |= PH_TUNNEL_SSL;
4491
4492        if (autoconf)
4493                phcfg.use_tunnel |= PH_TUNNEL_AUTOCONF;
4494        return 0;
4495}
4496
4497static void ph_payload_cleanup()
4498{
4499        if (osip_list_size(&ph_audio_payloads) > 0)
4500                osip_list_special_free(&ph_audio_payloads, sdp_payload_free);
4501        if (osip_list_size(&ph_video_payloads) > 0)
4502                osip_list_special_free(&ph_video_payloads, sdp_payload_free);
4503}
4504
4505/**
4506 * terminate ph api
4507 */
4508PHAPI_EXPORT void
4509phTerminate()
4510{
4511        int i;
4512
4513        DBG_SIP_EVENT("SIP NEGO: phTerminate\n");
4514        if (!phIsInitialized)
4515                return;
4516
4517        for(i = 0; i < PH_MAX_CALLS; i++)
4518                if (ph_calls[i].cid != -1)
4519                        ph_release_call(&ph_calls[i]);
4520
4521        for(i = 0; i < PH_MAX_VLINES; i++)
4522        {
4523                phDelVline(i+1);
4524        }
4525
4526        usleep(200000);
4527
4528        phPoll();
4529
4530        phIsInitialized = 0;
4531
4532        if (phapithread != NULL) {
4533                i = osip_thread_join((struct osip_thread *) phapithread);
4534                if (i != 0) {
4535                        OSIP_TRACE(osip_trace
4536                                        (__FILE__, __LINE__, OSIP_ERROR, NULL,
4537                                                        "phapithread: can't terminate thread!\n"));
4538                }
4539                osip_free(phapithread);
4540                phapithread = 0;
4541        }
4542        eXosip_quit();
4543
4544
4545        for(i = 0; i < PH_MAX_VLINES; i++)
4546        {
4547                struct vline *vl = ph_vlid2vline(i+1);
4548                if (vl)
4549                        vline_free(vl);
4550        }
4551
4552
4553#ifdef USE_HTTP_TUNNEL
4554        if (phTunnel)
4555        {
4556                http_tunnel_close(phTunnel->h_tunnel);
4557                http_tunnel_clean_up();
4558                free(phTunnel);
4559                phTunnel = 0;
4560        }
4561#endif
4562
4563        ph_media_cleanup();
4564        ph_payload_cleanup();
4565
4566        osip_mutex_destroy(ph_media_start_mutex);
4567        osip_mutex_destroy(ph_custom_mutex);
4568
4569
4570        if (phLogFileName && phDebugLevel > 0)
4571                fclose(ph_log_file);
4572        if (phDebugLevel > 0)
4573                for (i = 0; i <= phDebugLevel && i < END_TRACE_LEVEL; ++i)
4574                        TRACE_DISABLE_LEVEL(i);
4575
4576        if (phLogFileName)
4577                free(phLogFileName);
4578
4579        phLogFileName = 0;
4580
4581}
4582
4583
4584
4585/**
4586 * poll for phApi events.c
4587 */
4588PHAPI_EXPORT int
4589phPoll()
4590{
4591
4592        if (!phIsInitialized)
4593                return -PH_NOTINIT;
4594
4595        if (!phcfg.asyncmode)
4596        {
4597                if (ph_event_get() == -2)
4598                        return -2;
4599
4600                ph_keep_refreshing();
4601        }
4602        return 0;
4603}
4604
4605
4606
4607void ph_refer_notify(int did, int status, const char* msg, int final)
4608{
4609        char  statusmsg[128];
4610        osip_message_t *notify = 0;
4611        int i;
4612
4613        snprintf(statusmsg, sizeof(statusmsg), "SIP/2.0 %d %s", status, msg);
4614
4615        eXosip_lock();
4616
4617        i = eXosip_call_build_notify(did, final ? EXOSIP_SUBCRSTATE_TERMINATED : EXOSIP_SUBCRSTATE_ACTIVE, &notify);
4618        if (i)
4619                goto err;
4620
4621        osip_message_set_body(notify, statusmsg, strlen(statusmsg));
4622        osip_message_set_content_type(notify, "message/sipfrag");
4623
4624        i = eXosip_call_send_request(did, notify);
4625
4626        err:
4627        eXosip_unlock();
4628        if (i && (notify != 0))
4629                osip_message_free(notify);
4630
4631
4632}
4633
4634static int
4635ph_call_retrieve_payloads(phcall_t *ca, int flags)
4636{
4637        int  i = 0;
4638
4639        DBG_SIP_NEGO("looking for payloads...\n");
4640        DBG_SIP_NEGO("audio...\n");
4641        if (_is_audio_enabled(flags))
4642        {
4643                const sdp_payload_t *cur_payload;
4644
4645                if (osip_list_size(&ca->result_audio_payloads) > 0)
4646                {
4647                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, 0);
4648                        ca->audio_payload = cur_payload->pt;
4649                        if (cur_payload->a_rtpmap)
4650                                strncpy(ca->audio_payload_name, cur_payload->a_rtpmap, sizeof(ca->audio_payload_name));
4651                        ca->remote_ptime = cur_payload->a_ptime;
4652                }
4653        }
4654
4655        DBG_SIP_NEGO("video...\n");
4656
4657        if ((_is_video_enabled(flags)))
4658        {
4659                const sdp_payload_t *cur_payload;
4660
4661                ca->video_payload = 0;
4662                if (osip_list_size(&ca->result_video_payloads) > 0)
4663                {
4664                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_video_payloads, 0);
4665                        ca->video_payload = cur_payload->pt;
4666                        if (cur_payload->a_rtpmap)
4667                                strncpy(ca->video_payload_name, cur_payload->a_rtpmap, sizeof(ca->video_payload_name));
4668                        ca->remote_ptime = cur_payload->a_ptime;
4669                }
4670        }
4671
4672        DBG_SIP_NEGO("cng...\n");
4673        if(!i && phcfg.cng && (flags & PH_STREAM_CNG)) {
4674                // ca->cng = !eXosip_retrieve_negotiated_specific_payload(ca->did, PH_MEDIA_CN_PT_STR, strlen(PH_MEDIA_CN_PT_STR));
4675                // DBG_SIP_NEGO("cng: %d", ca->cng);
4676        }
4677        return i;
4678}
4679
4680
4681PHAPI_EXPORT int phCallGetCodecs(int cid, char *audioCodecBuf, int aBufLen, char *videoCodecBuf, int vBufLen)
4682{
4683        phcall_t *ca;
4684
4685        if (!phIsInitialized)
4686                return -PH_NOTINIT;
4687
4688        ca = ph_locate_call_by_cid(cid);
4689
4690        if (!ca)
4691                return -PH_BADCID;
4692
4693        if (audioCodecBuf)
4694                strncpy(audioCodecBuf, ca->audio_payload_name, aBufLen);
4695
4696        if (videoCodecBuf)
4697                strncpy(videoCodecBuf, ca->video_payload_name, vBufLen);
4698
4699        return 0;
4700
4701
4702}
4703
4704PHAPI_EXPORT int
4705phCallGetMediaInfo(int cid, struct ph_confirmed_media_info *mi)
4706{
4707        phcall_t *ca;
4708
4709        if (!phIsInitialized)
4710                return -PH_NOTINIT;
4711
4712        ca = ph_locate_call_by_cid(cid);
4713
4714        if (!ca)
4715                return -PH_BADCID;
4716
4717        mi->audio.localport = ca->local_sdp_audio_port;
4718        mi->audio.remoteport = ca->remote_sdp_audio_port;
4719        strncpy(mi->audio.remoteip, ca->remote_sdp_audio_ip, sizeof(mi->audio.remoteip));
4720        mi->video.localport = ca->local_sdp_video_port;
4721        mi->video.remoteport = ca->remote_sdp_video_port;
4722        strncpy(mi->video.remoteip, ca->remote_sdp_video_ip, sizeof(mi->video.remoteip));
4723
4724        return 0;
4725
4726}
4727
4728static void
4729ph_parse_payload_mime(struct ph_media_payload_s *pt, const char *mime, int rate, int chans)
4730{
4731        const char *rp;
4732        const char *cp;
4733
4734        rp = strchr(mime, '/');
4735        strncpy(pt->string, mime, sizeof(pt->string));
4736        pt->rate = rate;
4737        pt->chans = chans;
4738
4739
4740        if (!rp)
4741                return;
4742
4743        rp++;
4744        if (!*rp)
4745                return;
4746
4747        pt->rate = atol(rp);
4748
4749        cp = strchr(rp, '/');
4750        if (!cp)
4751                return;
4752
4753        cp++;
4754        if (!*cp)
4755                return;
4756
4757        pt->chans = atol(cp);
4758}
4759
4760
4761
4762static int
4763ph_call_media_stop(phcall_t *ca)
4764{
4765        DBG_SIP_NEGO("SIP_NEGO: ph_call_media_stop\n");
4766
4767        if (ca->mses)
4768        {
4769                if (ca->mses->refcnt == 1)
4770                {
4771                        if (!ca->audiodev_in)
4772                                ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
4773                       
4774                        if (!ca->audiodev_out)
4775                                ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
4776
4777                        if (!ph_msession_stopped(ca->mses))
4778                        {
4779                                ph_msession_stop(ca->mses, ca->audiodev_in, ca->audiodev_out,0);
4780                        }
4781                }
4782                ph_msession_free(ca->mses);
4783                ca->mses = 0;
4784        }
4785
4786        return 0;
4787
4788}
4789
4790static int
4791ph_call_media_suspend(phcall_t *ca, int localhold)
4792{
4793        if (ca->mses)
4794        {
4795                if (!ca->audiodev_in)
4796                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
4797
4798                ph_msession_suspend(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in,  ca->audiodev_out);
4799        }
4800
4801        return 0;
4802}
4803
4804
4805static int
4806ph_call_media_resume(phcall_t *ca, int localhold)
4807{
4808        if (ca->mses)
4809        {
4810                if (!ca->audiodev_in)
4811                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
4812               
4813                if (!ca->audiodev_out)
4814                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
4815               
4816                ph_msession_resume(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in, ca->audiodev_out, 0);
4817        }
4818
4819        return 0;
4820}
4821
4822
4823
4824static
4825struct ph_msession_s *ph_msession_new()
4826{
4827        struct ph_msession_s *= (struct ph_msession_s *)calloc(sizeof(struct ph_msession_s), 1);
4828        s->critsec_mstream_init = osip_mutex_init();
4829        s->refcnt = 1;
4830        return s;
4831}
4832
4833
4834static
4835void ph_msession_use(struct ph_msession_s *s)
4836{
4837        if (s)
4838        {
4839                osip_mutex_lock(s->critsec_mstream_init);
4840                s->refcnt++;
4841                osip_mutex_unlock(s->critsec_mstream_init);
4842        }
4843}
4844
4845static
4846void ph_msession_free(struct ph_msession_s *s)
4847{
4848        if (s)
4849        {
4850                osip_mutex_lock(s->critsec_mstream_init);
4851                if (s->refcnt-- == 1)
4852                {
4853                        osip_mutex_unlock(s->critsec_mstream_init);
4854                        osip_mutex_destroy(s->critsec_mstream_init);
4855                        free(s);
4856                        return;
4857                }
4858                osip_mutex_unlock(s->critsec_mstream_init);
4859        }
4860}
4861
4862static int
4863ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag)
4864{
4865        int i = 0;
4866        int use_socket;
4867        struct ph_msession_s *s = NULL;
4868        const char* ptime = getenv("EXOSIP_FORCE_PTIME");
4869        if (!ptime || !*ptime)
4870                ptime = "20";
4871
4872
4873        // cases when the invocation is ignored
4874        if (phcfg.nomedia || ca->localhold || ca->remotehold)
4875        {
4876                return 0;
4877        }
4878
4879        // we will work on the media sessions of the given phcall_t
4880        s = ca->mses;
4881
4882        osip_mutex_lock(ph_media_start_mutex);
4883
4884        // init the ph_msession_s for the call if the call doesn't have one yet
4885        if (!s)
4886        {
4887                s = ca->mses = ph_msession_new();
4888                if (!s)
4889                {
4890                        osip_mutex_unlock(ph_media_start_mutex);
4891                        return -PH_NORESOURCES;
4892                }
4893                s->confflags = 0;
4894                s->confsession = NULL;
4895                s->audio_conf = NULL;
4896                s->activestreams = 0;
4897        }
4898        else
4899        {
4900                if(resumeflag == 0)
4901                {
4902                        if(s->activestreams)
4903                        {
4904                                osip_mutex_lock(ph_media_stop_mutex);
4905                                ph_msession_stop(s, phcfg.audio_dev_in, phcfg.audio_dev_out, 0);
4906                                osip_mutex_unlock(ph_media_stop_mutex);
4907                        }
4908                        s->confflags = 0;
4909                        s->confsession = NULL;
4910                        s->audio_conf = NULL;
4911                        s->activestreams = 0;
4912                }
4913        }
4914        s->cbkInfo = ca;
4915
4916        // we need to understand what is required from the function call
4917        // by default, nothing to do
4918        s->newstreams = 0;
4919
4920        if ( // user accepts video and network accepts video
4921                        (_is_video_enabled(ca->user_mflags))
4922                        && ca->video_payload
4923                        && ca->remote_sdp_video_ip[0]
4924        )
4925        {
4926                // negociated flags (user+SDP) need to be IO
4927                ca->nego_mflags = ca->nego_mflags | PH_STREAM_VIDEO_RX;
4928                ca->nego_mflags = ca->nego_mflags | PH_STREAM_VIDEO_TX;
4929
4930                DBG_SIP_NEGO("will have video stream ip: %s payload=%d\n", ca->remote_sdp_video_ip, ca->video_payload);
4931                DBG_SIP_NEGO("media flags may have changed: user= %d nego=%d\n", ca->user_mflags, ca->nego_mflags);
4932        }
4933        else
4934        {
4935                // video is not negociated
4936                // it is necessary to remove VIDEO IO flags
4937                ca->nego_mflags = ca->nego_mflags & ~PH_STREAM_VIDEO_RX;
4938                ca->nego_mflags = ca->nego_mflags & ~PH_STREAM_VIDEO_TX;
4939
4940                DBG_SIP_NEGO("media flags may have changed: user= %d nego=%d\n", ca->user_mflags, ca->nego_mflags);
4941        }
4942
4943        if ( _is_video_enabled(ca->nego_mflags) )
4944        {
4945                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_VIDEO1];
4946                int ttype;
4947
4948                // program activation of VIDEO1
4949                s->newstreams |= (1 << PH_MSTREAM_VIDEO1);
4950
4951                // define the traffic type of the stream
4952                ttype = _is_video_enabled(ca->user_mflags);
4953                if (ttype == (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX))
4954                {
4955                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
4956                }
4957                else if (ttype == PH_STREAM_VIDEO_RX)
4958                {
4959                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
4960                }
4961                else if (ttype == PH_STREAM_VIDEO_TX)
4962                {
4963                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
4964                }
4965
4966                msp->localport = ca->local_sdp_video_port;
4967                msp->remoteport = ca->remote_sdp_video_port;
4968                strncpy(msp->remoteaddr,
4969                                ca->remote_sdp_video_ip,
4970                                sizeof(msp->remoteaddr));
4971
4972                // define the negociated codec payload on the stream
4973                msp->ipayloads[0].number = ca->video_payload;
4974                ph_parse_payload_mime(&msp->ipayloads[0], ca->video_payload_name, 90000, 1);
4975                msp->opayloads[0] = msp->ipayloads[0];
4976
4977                // define the video callback
4978                s->frameDisplayCbk =  ph_frame_display_cbk;
4979
4980                // additional configuration for video
4981
4982                /* if(sdp_message_bandwidth_get(ca->remote_sdp,  ) && !phcfg.video_config.force_high_speed)
4983      {
4984      msp->video_quality = ph_get_quality_from_bitrate(ca->max_bandwidth);
4985      }
4986    else
4987    msp->video_quality = phcfg.video_config.video_line_configuration;*/
4988        }
4989
4990        if ( // audio is enabled
4991                        _is_audio_enabled(ca->nego_mflags)
4992                        && (!ca || ca->remote_sdp_audio_ip[0])
4993        )
4994        {
4995                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
4996
4997                //TODO uncomment it after the work un payloads
4998                /*if(!strncmp(ca->audio_payload_name, "GSM", 3))
4999                {
5000                        if(30 == atoi(ptime))
5001                        {
5002                                // for GSM reset ptime to 20ms
5003                                ptime = "20";
5004                        }
5005                }*/
5006                // Set to this stream the correct ptime negociated in the SDP
5007                // If there is no ptime negociated, use the default value (20 ms)
5008                //msp->ptime = (ca && ca->ptime > 0 ? ca->ptime : atoi(ptime));
5009                msp->ptime = atoi(ptime);
5010
5011                // program activation of AUDIO1
5012                s->newstreams |= (1 << PH_MSTREAM_AUDIO1);
5013
5014                s->dtmfCallback = ph_wegot_dtmf;
5015                s->endCallback = ph_stream_ended;
5016
5017                if (phcfg.vad & 0x80000000)
5018                {
5019                        msp->flags |= PH_MSTREAM_FLAG_VAD;
5020                        msp->vadthreshold = phcfg.vad & 0x7fff;
5021                }
5022
5023                if (phcfg.cng)
5024                {
5025                        msp->flags |= PH_MSTREAM_FLAG_CNG;
5026                }
5027
5028                msp->jitter = phcfg.jitterdepth;
5029
5030                if (!phcfg.noaec)
5031                {
5032                        msp->flags |= PH_MSTREAM_FLAG_AEC;
5033                }
5034
5035                msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
5036                msp->localport = ca->local_sdp_audio_port;
5037
5038                msp->remoteport = ca->remote_sdp_audio_port;
5039                msp->remotertcpport = ca->remote_sdp_audio_rtcp_port;
5040                use_socket = 0;
5041
5042                strncpy(msp->remoteaddr,
5043                                ca->remote_sdp_audio_ip,
5044                                sizeof(msp->remoteaddr));
5045
5046                // SPIKE_HDX
5047                if (phcfg.hdxmode == PH_HDX_MODE_MIC)
5048                {
5049                        msp->flags |= PH_MSTREAM_FLAG_MICHDX;
5050                        msp->vadthreshold = phcfg.vad & 0x7fff;
5051                }
5052
5053                if (phcfg.hdxmode == PH_HDX_MODE_SPK)
5054                {
5055                        msp->flags |= PH_MSTREAM_FLAG_SPKHDX;
5056                        msp->vadthreshold = phcfg.vad & 0x7fff;
5057                }
5058
5059                {
5060                        const sdp_payload_t *cur_payload;
5061                        int pos = osip_list_size(&ca->result_audio_payloads) -1;
5062                        int i = 0;
5063
5064                        while (pos >= 0)
5065                        {
5066                                cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, pos);
5067
5068                                msp->ipayloads[i].number = cur_payload->pt;
5069                                ph_parse_payload_mime(&msp->ipayloads[i], cur_payload->a_rtpmap, 8000, 1);
5070                                if (!strcasecmp(msp->ipayloads[i].string, "g722"))
5071                                        msp->ipayloads[i].rate = 16000;
5072                                msp->opayloads[i] = msp->ipayloads[i];
5073                                msp->opayloads[i].ptime = cur_payload->a_ptime;
5074
5075                                i++;
5076                                pos--;
5077                        }
5078
5079                }
5080
5081        } // end        if ( // audio is enabled
5082
5083        // take action depending on the streaming configuration
5084        if (s->newstreams | s->activestreams)
5085        {
5086                if (resumeflag)
5087                {
5088                        if (ph_msession_resume(s, PH_MSTREAM_TRAFFIC_IO, phcfg.audio_dev_in, phcfg.audio_dev_out, use_socket))
5089                        {
5090                                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_resume\n");
5091                                i = -PH_NOMEDIA;
5092                        }
5093                }
5094                else if (ph_msession_start(s, ca->audiodev_in, ca->audiodev_out, use_socket))
5095                {
5096                        DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_start\n");
5097                        i = -PH_NOMEDIA;
5098                }
5099        }
5100        else
5101        {
5102                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: nothing to start\n");
5103                i = -PH_NOMEDIA;
5104        }
5105
5106        osip_mutex_unlock(ph_media_start_mutex);
5107
5108        return i;
5109}
5110
5111static char *
5112ph_req_get_from(osip_message_t *msg);
5113
5114
5115
5116
5117void
5118ph_call_new(eXosip_event_t *je)
5119{
5120        phCallStateInfo_t info;
5121        phcall_t *ca;
5122        struct vline *vl;
5123        char *localUri = NULL, *remoteUri= NULL, *sdp = NULL;
5124        int i;
5125
5126        clear(info);
5127        if (ph_busyFlag)
5128        {
5129                ph_answer_request(je->cid, je->tid, 486, 0);
5130                goto done;
5131        }
5132
5133        if (ph_follow_me_addr[0])
5134        {
5135                ph_answer_request(je->cid, je->tid, 302, ph_follow_me_addr);
5136                goto done;
5137        }
5138        osip_uri_to_str(je->request->req_uri, &localUri);
5139        osip_uri_to_str(osip_from_get_url(je->request->from), &remoteUri);
5140        info.vlid = ph_get_vline_id(localUri, NULL);
5141
5142        if (!info.vlid)
5143        {
5144                ph_answer_request(je->cid, je->tid, 404, 0);
5145                goto done;
5146        }
5147
5148        vl = ph_vlid2vline(info.vlid);
5149
5150        assert(vl!=NULL);
5151
5152        ca = ph_locate_call(je, 1);
5153        if (ca)
5154        {
5155                if (vl->busy)
5156                {
5157                        ph_answer_request(je->cid, je->tid, 486, vl->contact);
5158                        goto done;
5159                }
5160
5161                if (vl->followme && vl->followme[0])
5162                {
5163                        ph_answer_request(je->cid, je->tid, 302, vl->followme);
5164                        goto done;
5165                }
5166
5167                ca->vlid = info.vlid;
5168                ca->state = PH_CALLEE_RECEIVED;
5169
5170                i = ph_build_cname(ca->cname, sizeof(ca->cname), vl);
5171
5172                if (i)
5173                {
5174                        ph_answer_request(je->cid, je->tid, 400, vl->contact);
5175                        goto done;
5176                }
5177
5178                if (phcfg.audio_dev_in) {
5179                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5180                }
5181               
5182                if (phcfg.audio_dev_out) {
5183                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5184                }
5185
5186                info.userData = je->external_reference;
5187                info.event = phINCALL;
5188                info.remoteUri = remoteUri;
5189                info.localUri = localUri;
5190                info.streams = ca->nego_mflags;
5191                info.callinfo = 0; //je->call_info;
5192
5193                info.remoteSdp = sdp = ph_req_get_body(je->response);
5194
5195                ph_apply_header_monitor(je->response, &info.hlist);
5196
5197                phcb->callProgress(ca->cid, &info);
5198done:
5199                if (remoteUri)
5200                        osip_free(remoteUri);
5201
5202                if (localUri)
5203                        osip_free(localUri);
5204
5205                if (sdp)
5206                        osip_free(sdp);
5207
5208                if (info.hlist.elems)
5209                        osip_free(info.hlist.elems);
5210
5211        }
5212}
5213
5214#define ph_req_get_status(x) osip_message_get_status_code(x)
5215
5216static char *
5217ph_req_get_to(osip_message_t *msg)
5218{
5219        char *str = 0;
5220
5221        osip_to_to_str(msg->to, &str);
5222        return str;
5223}
5224
5225static char *
5226ph_req_get_from(osip_message_t *msg)
5227{
5228        char *str = 0;
5229
5230        osip_from_to_str(msg->from, &str);
5231        return str;
5232}
5233
5234static char *
5235ph_req_get_body(osip_message_t *msg)
5236{
5237        char *str = 0;
5238        osip_body_t *body;
5239        size_t len;
5240
5241
5242        body = osip_list_get(&msg->bodies, 0);
5243        if (!body)
5244                return 0;
5245
5246        osip_body_to_str(body, &str, &len);
5247        str[len] = 0;
5248        return str;
5249}
5250
5251static osip_header_t *
5252ph_req_find_header(osip_message_t *msg, const char *hname)
5253{
5254        osip_header_t *hdr = 0;
5255
5256        osip_message_header_get_byname(msg, hname, 0, &hdr);
5257        return hdr;
5258
5259}
5260
5261static char *
5262ph_req_get_event(osip_message_t *msg)
5263{
5264        osip_header_t *hdr = 0;
5265
5266        osip_message_header_get_byname(msg, "Event", 0, &hdr);
5267
5268        if (hdr)
5269                return osip_strdup(hdr->hvalue);
5270
5271        return 0;
5272}
5273
5274
5275
5276void
5277ph_call_answered(eXosip_event_t *je)
5278{
5279        phCallStateInfo_t info;
5280        phcall_t *ca, *rca=0;
5281        int rdid;
5282        char *from = 0, *to = 0, *sdp = 0;
5283        osip_message_t *ack;
5284
5285        DBG_SIP_NEGO("SIP NEGO: ph_call_answered\n");
5286        clear(info);
5287
5288        ca = ph_locate_call(je, 0);
5289
5290        if (!ca)
5291                return;
5292
5293        rca = ph_locate_call_by_cid(ca->rcid);
5294
5295        info.remoteSdp = sdp = ph_req_get_body(je->response);
5296
5297        if (!ca->localhold)
5298        {
5299                const int mflags =  -1 & ~(PH_STREAM_MCSEND|PH_STREAM_MCRECV);
5300
5301                if (sdp)
5302                {       
5303                        if (ca->remote_sdp) {
5304                                sdp_message_free(ca->remote_sdp);       
5305                        }
5306                        sdp_message_init(&ca->remote_sdp);
5307                        sdp_message_parse(ca->remote_sdp, sdp);
5308                        ca->sdpctx->answer = ca->remote_sdp;
5309                        sdp_context_process_answer(ca->sdpctx, ca->remote_sdp);
5310                        ph_call_retrieve_payloads(ca, -1);
5311
5312                        if (!ph_call_media_start(ca, je, mflags, ca->localresume))
5313                        {
5314                                DBG_SIP_NEGO("SIP NEGO: ph_call_answered but without stream\n");
5315                        }
5316                }
5317        }
5318
5319        info.localUri = from = ph_req_get_from(je->response);
5320        info.userData = je->external_reference;
5321        if (ca->localhold)
5322        {
5323                info.event = phHOLDOK;
5324        }
5325        else if (ca->localresume)
5326        {
5327                info.event = phRESUMEOK;
5328                ca->localresume = 0;
5329        }
5330        else {
5331                info.event = phCALLOK;
5332        }
5333
5334        eXosip_lock();
5335        eXosip_call_build_ack(ca->did, &ack);
5336        eXosip_call_send_ack(ca->did, ack);
5337        eXosip_unlock();
5338
5339        info.remoteUri = to = ph_req_get_to(je->response);
5340        info.vlid = ca->vlid;
5341        if (rca)
5342        {
5343                info.oldcid = rca->cid;
5344                rdid = rca->rdid;
5345        }
5346
5347        info.streams = PH_STREAM_AUDIO;
5348        if (ca->video_payload)
5349        {
5350                info.streams |= PH_STREAM_VIDEO_RX;
5351        }
5352
5353        if (!ca->localrefer)
5354        {
5355                /*
5356                 * the call back can call phCloseCall(odlcid)...  but we have rdid in
5357                 * the local var
5358                 */
5359                ph_apply_header_monitor(je->response, &info.hlist);
5360                phcb->callProgress(ca->cid, &info);
5361        }
5362
5363        if (rca)
5364        {
5365                ph_refer_notify(rdid, ph_req_get_status(je->response), "OK", 1);
5366        }
5367
5368        if (sdp)
5369                osip_free(sdp);
5370
5371        if (to)
5372                osip_free(to);
5373
5374        if (from)
5375                osip_free(from);
5376
5377        if (info.hlist.elems)
5378                osip_free(info.hlist.elems);
5379
5380}
5381
5382
5383void
5384ph_call_proceeding(eXosip_event_t *je)
5385{
5386        phCallStateInfo_t info;
5387        phcall_t *ca, *rca=0;
5388        char *to = 0;
5389        int s = 0;
5390
5391        DBG_SIP_NEGO("SIP NEGO: ph_call_proceeding\n");
5392        clear(info);
5393
5394
5395        ca = ph_locate_call(je, 1);
5396        if (!ca)
5397                return;
5398
5399        rca = ph_locate_call_by_cid(ca->rcid);
5400
5401        if (ca && !ca->localrefer)
5402        {
5403                ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
5404                ph_call_media_start(ca, je, -1, 0);
5405
5406                info.userData = je->external_reference;
5407                info.event = phDIALING;
5408                info.remoteUri = to = ph_req_get_to(je->response);
5409                info.vlid = ca->vlid;
5410
5411                info.streams = ca->nego_mflags;
5412
5413                ph_apply_header_monitor(je->response, &info.hlist);
5414                phcb->callProgress(ca->cid, &info);
5415        }
5416
5417        if (rca)
5418        {
5419                ph_refer_notify(rca->rdid, s, "Proceeding", 0);
5420        }
5421
5422        if (to)
5423                free(to);
5424
5425        if (info.hlist.elems)
5426                osip_free(info.hlist.elems);
5427
5428
5429}
5430
5431void ph_callStopRinging(eXosip_event_t *je)
5432{
5433        phCallStateInfo_t info;
5434        phcall_t *ca;
5435        char *from = 0, *to = 0;
5436
5437        clear(info);
5438
5439        ca = ph_locate_call(je, 1);
5440        if (ca && ca->isringing)
5441        {
5442                ca->isringing = 0;
5443                info.event = phRINGandSTOP;
5444
5445                info.localUri = from = ph_req_get_from(je->request);
5446                info.userData = je->external_reference;
5447
5448                info.remoteUri = to = ph_req_get_to(je->request);
5449                info.vlid = ca->vlid;
5450
5451                phcb->callProgress(je->cid, &info);
5452        }
5453
5454        if (to)
5455                osip_free(to);
5456        if (from)
5457                osip_free(from);
5458
5459
5460}
5461
5462
5463//from osip_uri.c, Don't add the port number into the string
5464static int ph_uri_to_str(const osip_uri_t * url, char **dest)
5465{
5466        char *buf;
5467        size_t len;
5468        char *tmp;
5469        const char *scheme;
5470
5471        *dest = NULL;
5472        if (url == NULL)
5473                return OSIP_BADPARAMETER;
5474        if (url->host == NULL && url->string == NULL)
5475                return OSIP_BADPARAMETER;
5476        if (url->scheme == NULL && url->string != NULL)
5477                return OSIP_BADPARAMETER;
5478        if (url->string == NULL && url->scheme == NULL)
5479                scheme = "sip";                 /* default is sipurl */
5480        else
5481                scheme = url->scheme;
5482
5483        if (url->string != NULL) {
5484                buf = (char *) osip_malloc(strlen(scheme) + strlen(url->string) + 3);
5485                if (buf == NULL)
5486                        return OSIP_NOMEM;
5487                *dest = buf;
5488                sprintf(buf, "%s:", scheme);
5489                buf = buf + strlen(scheme) + 1;
5490                sprintf(buf, "%s", url->string);
5491                buf = buf + strlen(url->string);
5492                return OSIP_SUCCESS;
5493        }
5494
5495        len = strlen(scheme) + 1 + strlen(url->host) + 5;
5496        if (url->username != NULL)
5497                len = len + (strlen(url->username) * 3) + 1;    /* count escaped char */
5498        if (url->password != NULL)
5499                len = len + (strlen(url->password) * 3) + 1;
5500        if (url->port != NULL)
5501                len = len + strlen(url->port) + 3;
5502
5503        buf = (char *) osip_malloc(len);
5504        if (buf == NULL)
5505                return OSIP_NOMEM;
5506        tmp = buf;
5507
5508        sprintf(tmp, "%s:", scheme);
5509        tmp = tmp + strlen(tmp);
5510
5511        if (url->username != NULL) {
5512                char *tmp2 = __osip_uri_escape_userinfo(url->username);
5513
5514                sprintf(tmp, "%s", tmp2);
5515                osip_free(tmp2);
5516                tmp = tmp + strlen(tmp);
5517        }
5518        if (url->username != NULL) {    /* we add a '@' only when username is present... */
5519                sprintf(tmp, "@");
5520                tmp++;
5521        }
5522        if (strchr(url->host, ':') != NULL) {
5523                sprintf(tmp, "[%s]", url->host);
5524                tmp = tmp + strlen(tmp);
5525        } else {
5526                sprintf(tmp, "%s", url->host);
5527                tmp = tmp + strlen(tmp);
5528        }
5529
5530        *dest = buf;
5531        return OSIP_SUCCESS;
5532}
5533
5534
5535
5536void
5537ph_call_ringing(eXosip_event_t *je)
5538{
5539        int ret = 0;
5540        phCallStateInfo_t info;
5541        phcall_t *ca, *rca=0;
5542        char *from = 0, *to = 0;
5543
5544
5545        DBG_SIP_NEGO("SIP NEGO: ph_call_ringing\n");
5546
5547        clear(info);
5548
5549        ca = ph_locate_call(je, 1);
5550        if (!ca)
5551                return;
5552
5553        rca = ph_locate_call_by_cid(ca->rcid);
5554
5555        ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
5556
5557        ret = ph_call_media_start(ca, je, -1, 0);
5558
5559        info.event = phRINGING;
5560        if (ret == -PH_NOMEDIA && !ph_call_hasaudio(ca) && !ca->isringing) /*  no audio and softPhone is now not ringing and has no sound */
5561        {
5562                ca->isringing = 1;
5563                info.event = phRINGandSTART;
5564        }
5565        else if (ca->isringing )
5566        {
5567                ca->isringing = 0;
5568                info.event = phRINGandSTOP;
5569        }
5570
5571        info.localUri = from = ph_req_get_from(je->response);
5572        info.userData = je->external_reference;
5573
5574        info.remoteUri = to = ph_req_get_to(je->response);
5575        info.vlid = ca->vlid;
5576
5577        info.streams = ca->nego_mflags;
5578
5579        ph_apply_header_monitor(je->response, &info.hlist);
5580
5581        phcb->callProgress(je->cid, &info);
5582
5583        if (rca)
5584        {
5585                ph_refer_notify(rca->rdid, 180, "Ringing", 0);
5586        }
5587
5588        if (to)
5589                osip_free(to);
5590        if (from)
5591                osip_free(from);
5592
5593        if (info.hlist.elems)
5594                osip_free(info.hlist.elems);
5595}
5596
5597
5598static void
5599ph_call_requestfailure(eXosip_event_t *je)
5600{
5601        phCallStateInfo_t info;
5602        phcall_t *ca, *rca=0;
5603        int s = 0;
5604        char *from = 0, *to = 0;
5605
5606        DBG_SIP_NEGO("call invite failure\n");
5607
5608        clear(info);
5609
5610        ca = ph_locate_call(je, 0);
5611        if (!ca)
5612                return;
5613
5614        rca = ph_locate_call_by_cid(ca->rcid);
5615        info.vlid = ca->vlid;
5616
5617        if (je->response) {
5618                s = ph_req_get_status(je->response);
5619                if (s == 407 || s == 401)
5620                        return;
5621        }
5622
5623        ph_release_call(ca);
5624
5625        if (je->response) {
5626                info.localUri = from = ph_req_get_from(je->response);
5627        }
5628
5629        info.userData = je->external_reference;
5630        if (s == 486)
5631        {
5632                info.event = phCALLBUSY;
5633                info.remoteUri = to = ph_req_get_to(je->response);
5634        }
5635        else
5636        {
5637                info.event = phCALLERROR;
5638                info.errorCode = s;
5639        }
5640
5641        ph_apply_header_monitor(je->response, &info.hlist);
5642
5643        phcb->callProgress(je->cid, &info);
5644        if (rca)
5645        {
5646                ph_refer_notify(rca->rdid, s, s == 486 ? "Busy" : "Request failure", 1);
5647        }
5648
5649        if (to)
5650                osip_free(to);
5651        if (from)
5652                osip_free(from);
5653
5654        if (info.hlist.elems)
5655                osip_free(info.hlist.elems);
5656}
5657
5658
5659void
5660ph_call_serverfailure(eXosip_event_t *je)
5661{
5662        phCallStateInfo_t info;
5663        phcall_t *ca, *rca=0;
5664        char *from = 0, *to = 0;
5665        int s = 0;
5666
5667        clear(info);
5668
5669        ca = ph_locate_call(je, 0);
5670        if (ca)
5671        {
5672                rca = ph_locate_call_by_cid(ca->rcid);
5673                info.vlid = ca->vlid;
5674                ph_release_call(ca);
5675        }
5676
5677        if (je->response) {
5678                s = ph_req_get_status(je->response);
5679                info.localUri = from = ph_req_get_from(je->response);
5680        }
5681
5682        info.userData = je->external_reference;
5683        info.event = phCALLERROR;
5684        info.errorCode = s;
5685
5686        ph_apply_header_monitor(je->response, &info.hlist);
5687
5688        phcb->callProgress(je->cid, &info);
5689
5690        if (rca)
5691        {
5692                ph_refer_notify(rca->rdid, s, "Server failure", 1);
5693        }
5694
5695        if (to)
5696                osip_free(to);
5697        if (from)
5698                osip_free(from);
5699
5700        if (info.hlist.elems)
5701                osip_free(info.hlist.elems);
5702}
5703
5704void
5705ph_call_globalfailure(eXosip_event_t *je)
5706{
5707        phCallStateInfo_t info;
5708        phcall_t *ca, *rca=0;
5709        char *from = 0, *to = 0;
5710        int s = 0;
5711
5712        clear(info);
5713
5714        ca = ph_locate_call(je, 0);
5715        if (ca)
5716        {
5717                rca = ph_locate_call_by_cid(ca->rcid);
5718                info.vlid = ca->vlid;
5719                ph_release_call(ca);
5720        }
5721
5722        s = ph_req_get_status(je->response);
5723        info.userData = je->external_reference;
5724        info.localUri = from = ph_req_get_from(je->response);
5725
5726        if (s == 600)
5727        {
5728                info.event = phCALLBUSY;
5729                info.remoteUri = to = ph_req_get_to(je->response);
5730        }
5731        else
5732        {
5733                info.event = phCALLERROR;
5734                info.errorCode = s;
5735        }
5736
5737        ph_apply_header_monitor(je->request, &info.hlist);
5738
5739        phcb->callProgress(je->cid, &info);
5740
5741        if (rca)
5742        {
5743                ph_refer_notify(rca->rdid, s, "Global failure", 1);
5744        }
5745
5746        if (to)
5747                osip_free(to);
5748        if (from)
5749                osip_free(from);
5750
5751        if (info.hlist.elems)
5752                osip_free(info.hlist.elems);
5753}
5754
5755void
5756ph_call_noanswer(eXosip_event_t *je, int alloc)
5757{
5758        phCallStateInfo_t info;
5759        phcall_t *ca, *rca=0;
5760        char *from = 0, *to = 0;
5761
5762
5763        clear(info);
5764
5765        ca = ph_locate_call(je, alloc);
5766        if (ca)
5767        {
5768                rca = ph_locate_call_by_cid(ca->rcid);
5769                info.vlid = ca->vlid;
5770                ph_release_call(ca);
5771        }
5772
5773        if (!ca && !alloc)
5774                return;
5775
5776        info.userData = je->external_reference;
5777        info.event = phNOANSWER;
5778        //      info.remoteUri = to = ph_req_get_to(je->response);
5779        //      info.localUri = from = ph_req_get_to(je->response);
5780
5781        ph_apply_header_monitor(je->request, &info.hlist);
5782
5783        phcb->callProgress(je->cid, &info);
5784
5785        if (rca)
5786        {
5787                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "No answer", 1);
5788        }
5789
5790        if (to)
5791                osip_free(to);
5792        if (from)
5793                osip_free(from);
5794
5795        if (info.hlist.elems)
5796                osip_free(info.hlist.elems);
5797}
5798
5799void
5800ph_call_message_new(eXosip_event_t *je)
5801{
5802}
5803
5804void
5805ph_call_closed(eXosip_event_t *je)
5806{
5807        phCallStateInfo_t info;
5808        phcall_t *ca, *rca=0;
5809
5810        clear(info);
5811
5812        ca = ph_locate_call(je, 0);
5813        if (ca)
5814        {
5815                rca = ph_locate_call_by_cid(ca->rcid);
5816                info.vlid = ca->vlid;
5817
5818
5819                ph_release_call(ca);
5820
5821                info.userData = je->external_reference;
5822                info.event = phCALLCLOSED;
5823                info.errorCode = 0;
5824
5825                ph_apply_header_monitor(je->request, &info.hlist);
5826                phcb->callProgress(je->cid, &info);
5827        }
5828
5829        if (rca)
5830        {
5831                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "Closed", 1);
5832        }
5833
5834        if (info.hlist.elems)
5835                osip_free(info.hlist.elems);
5836}
5837
5838
5839void
5840ph_call_onhold(eXosip_event_t *je)
5841{
5842        phCallStateInfo_t info;
5843        phcall_t *ca;
5844
5845        DBG_SIP_NEGO("SIP_NEGO: ph_call_onhold\n");
5846
5847        clear(info);
5848
5849        ca = ph_locate_call(je, 0);
5850
5851        if (!ca)
5852                return;
5853
5854        info.vlid = ca->vlid;
5855        if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca))
5856        {
5857#ifndef MEDIA_SUSPEND
5858                ph_call_media_stop(ca);
5859#else
5860                ph_call_media_suspend(ca, 0);
5861#endif
5862        }
5863
5864        ca->remotehold = 1;
5865        info.userData = je->external_reference;
5866        info.event = phCALLHELD;
5867        phcb->callProgress(je->cid, &info);
5868}
5869
5870static int ph_find_expires_for_vl(int vlid, osip_message_t *msg)
5871{
5872        //TODO: we must every Contact header field and extracting the value of "expires" param,
5873        //currently let's return 0 so phapi will keep the vline regTimeout
5874        return 0;
5875}
5876
5877void ph_reg_progress(eXosip_event_t *je)
5878{
5879        int i;
5880        struct vline *vl = 0;
5881        int vlid;
5882        int mask = 0;
5883        int status;
5884
5885        vl =  ph_find_vline_by_rid(je->rid);
5886
5887        if (!vl)
5888                return;
5889
5890        if (vl->regTimeout == 0)
5891                mask = PH_UNREG_MASK;
5892        vlid = ph_vline2vlid(vl);
5893
5894        DBG_SIP_NEGO("REGPROGRESS reg=%d for vlid=%d\n", je->rid, vlid);
5895
5896        if (je->type == EXOSIP_REGISTRATION_SUCCESS)
5897        {
5898                int expires = ph_find_expires_for_vl(vlid, je->response);
5899
5900                if (expires)
5901                        vl->regTimeout = expires;
5902
5903                phcb->regProgress(vlid, 0 | mask);
5904                if (vl->used == VL_DELETING)
5905                        vline_free(vl);
5906        }
5907        else if (je->type == EXOSIP_REGISTRATION_FAILURE)
5908        {
5909                int newtimeout = -1;
5910
5911                if (je->response)
5912                        status = ph_req_get_status(je->response);
5913                else status = -1;
5914
5915                if (status == 423)  /* Interval to brief */
5916                {
5917                        osip_header_t *hdr = ph_req_find_header(je->response, "Min-expires");
5918
5919                        if (hdr)
5920                        {
5921                                vl->regTimeout = newtimeout = atoi(hdr->hvalue);
5922                        }
5923                }
5924
5925                if (status == 401 || status == 407 || (newtimeout > 0))
5926                {
5927                        eXosip_lock();
5928                        i = eXosip_default_action(je);
5929                        eXosip_unlock();
5930
5931                        DBG_SIP_NEGO("Retrying reg=%d for vlid=%d i=%d t=%d\n", je->rid, vlid, i, newtimeout);
5932                }
5933
5934
5935                phcb->regProgress(vlid, mask | (status ? status : 500) );
5936
5937                if (vl->used == VL_DELETING)
5938                        vline_free(vl);
5939
5940        }
5941}
5942
5943void ph_notify_handler(eXosip_event_t *je)
5944{
5945        char *ctt = 0;
5946        char *evt = 0;
5947        char *from = 0;
5948        char *body = 0;
5949
5950        if (phcb->onNotify)
5951        {
5952                if (je->request->content_type)
5953                        osip_content_type_to_str(je->request->content_type, &ctt);
5954
5955                evt = ph_req_get_event(je->request);
5956                from = ph_req_get_from(je->request);
5957                body = ph_req_get_body(je->request);
5958
5959                if (body)
5960                        phcb->onNotify(evt, from, ctt, body);
5961                else
5962                        phcb->onNotify(evt, from, "", "");
5963
5964                if (body)
5965                        osip_free(body);
5966                if (from)
5967                        osip_free(from);
5968                if (evt)
5969                        osip_free(evt);
5970                if (ctt)
5971                        osip_free(ctt);
5972        }
5973}
5974
5975void ph_message_progress(eXosip_event_t *je)
5976{
5977        phMsgStateInfo_t info;
5978        char *rawCtt = 0;
5979        phcall_t *ca = ph_locate_call_by_cid(je->cid);
5980        char *from = 0, *to= 0, *body = 0;
5981        osip_content_type_t *ctt;
5982
5983        clear(info);
5984
5985        if (je->response && (ctt = je->response->content_type))
5986                osip_content_type_to_str(ctt, &rawCtt);
5987        else if (je->request && (ctt = je->request->content_type))
5988                osip_content_type_to_str(ctt, &rawCtt);
5989
5990        info.cid = ca ? je->cid : 0;
5991
5992        if (je->type == EXOSIP_MESSAGE_NEW)
5993        {
5994                info.event = phMsgNew;
5995                info.content = body = ph_req_get_body(je->request);
5996                ph_apply_header_monitor(je->request, &info.hlist);
5997
5998                if (ctt)
5999                {
6000                        info.ctype = ctt->type;
6001                        info.subtype = ctt->subtype;
6002                }
6003                info.to = to = ph_req_get_to(je->request);
6004                info.from = from = ph_req_get_from(je->request);
6005                info.rawctt = rawCtt;
6006
6007                eXosip_message_send_answer(je->tid, 202, NULL);
6008                if (phcb->msgProgress != NULL)
6009                        phcb->msgProgress(je->tid, &info);
6010        }
6011        else if (je->type == EXOSIP_MESSAGE_ANSWERED)
6012        {
6013                info.event = phMsgOk;
6014                info.to = to = ph_req_get_to(je->response);
6015                info.from = from = ph_req_get_from(je->response);
6016                ph_apply_header_monitor(je->response, &info.hlist);
6017
6018                if (phcb->msgProgress != NULL)
6019                        phcb->msgProgress(je->tid, &info);
6020        }
6021        else if (je->type == EXOSIP_MESSAGE_REQUESTFAILURE ||
6022                        je->type == EXOSIP_MESSAGE_GLOBALFAILURE ||
6023                        je->type == EXOSIP_MESSAGE_SERVERFAILURE
6024        )
6025        {
6026                if (je->response)
6027                {
6028                        int status = ph_req_get_status(je->response);
6029                        if (status == 401 || status == 407)
6030                        {
6031                                eXosip_lock();
6032                                eXosip_default_action(je);
6033                                eXosip_unlock();
6034                                return;
6035                        }
6036
6037                        ph_apply_header_monitor(je->response, &info.hlist);
6038
6039                        info.to = to = ph_req_get_to(je->response);
6040                        info.from = from = ph_req_get_from(je->response);
6041                } else if (je->request)
6042                {
6043                        ph_apply_header_monitor(je->request, &info.hlist);
6044                        info.to = to = ph_req_get_to(je->request);
6045                        info.from = from = ph_req_get_from(je->request);
6046                }
6047                info.event = phMsgError;
6048                if (phcb->msgProgress != NULL)
6049                        phcb->msgProgress(je->tid, &info);
6050        }
6051
6052        if (rawCtt)
6053                osip_free(rawCtt);
6054
6055        if (to)
6056                osip_free(to);
6057
6058        if (from)
6059                osip_free(from);
6060
6061        if (body)
6062                osip_free(body);
6063
6064        if (info.hlist.elems)
6065                osip_free(info.hlist.elems);
6066}
6067
6068void ph_info_progress(eXosip_event_t *je)
6069{
6070        phcall_t *ca;
6071        osip_content_type_t *ctt;
6072
6073        ca = ph_locate_call_by_cid(je->cid);
6074
6075        if (!ca)
6076                return;
6077
6078        if (je->type == EXOSIP_CALL_MESSAGE_NEW)
6079        {
6080                if (!(ctt = je->request->content_type))
6081                        goto ans;
6082
6083                if (!strcasecmp(ctt->type, "application"))
6084                {
6085                        osip_body_t *body;
6086                        const char *data;
6087                        int event;
6088
6089                        body = osip_list_get(&je->request->bodies, 0);
6090                        if (!body)
6091                                goto ans;
6092
6093                        data = body->body;
6094
6095                        if (!strcasecmp(ctt->subtype, "dtmf-relay"))
6096                        {
6097                                data = strstr(data,"=");
6098                                if (!data)
6099                                        goto ans;
6100                                event = *++data;
6101                        }
6102                        else if (!strcasecmp(ctt->subtype, "dtmf"))
6103                        {
6104                                event = atoi(data);
6105                                if (event == 16)
6106                                        event = '!';
6107                                else if (0 <= event && event <= 9)
6108                                        event += '0';
6109                                else
6110                                        event = 'A' + (event - 10);
6111                        }
6112                        else
6113                                goto ans;
6114
6115                        ph_wegot_dtmf(ca, event);
6116                }
6117                ans:
6118                ph_answer_request(je->cid, je->tid, 200, 0);
6119
6120        }
6121}
6122
6123void ph_subscription_progress(eXosip_event_t *je)
6124{
6125        phSubscriptionStateInfo_t info;
6126
6127        clear(info);
6128
6129        if (je->type == EXOSIP_SUBSCRIPTION_ANSWERED)
6130        {
6131                info.event = phSubscriptionOk;
6132                osip_uri_to_str(je->request->req_uri, &info.from);
6133                osip_uri_to_str(je->response->req_uri, &info.to);
6134
6135                ph_apply_header_monitor(je->response, &info.hlist);
6136
6137                if (phcb->subscriptionProgress != NULL)
6138                        phcb->subscriptionProgress (je->sid, &info);
6139        }
6140        else if (je->type == EXOSIP_SUBSCRIPTION_REQUESTFAILURE)
6141        {
6142                info.event = phSubscriptionError;
6143
6144                if (!je->response)
6145                {
6146                        phcb->subscriptionProgress (je->sid, &info);
6147                }
6148                else
6149                {
6150
6151                        ph_apply_header_monitor(je->response, &info.hlist);
6152
6153                        if (je->response->status_code == 404) {
6154                                info.event = phSubscriptionErrNotFound;
6155                        }
6156
6157                        osip_uri_to_str(je->request->req_uri, &info.from);
6158                        osip_uri_to_str(je->response->req_uri, &info.to);
6159                        if (phcb->subscriptionProgress != NULL)
6160                                phcb->subscriptionProgress (je->sid, &info);
6161                }
6162        }
6163
6164        if (info.from)
6165                osip_free(info.from);
6166
6167        if (info.to)
6168                osip_free(info.to);
6169
6170        if (info.hlist.elems)
6171                osip_free(info.hlist.elems);
6172}
6173
6174
6175static void ph_connection_lost(const char *host, int port)
6176{
6177        ph_is_connection_lost = 1;
6178}
6179
6180static int
6181ph_event_get()
6182{
6183        int counter =0;
6184        /* use events to print some info */
6185        eXosip_event_t *je;
6186
6187        //phReleaseTerminatedCalls();
6188        for (;;)
6189        {
6190                if(!phIsInitialized)
6191                        return -2;
6192
6193                je = eXosip_event_wait(0,timeout);
6194
6195                if(!phIsInitialized)
6196                        return -2;
6197
6198                eXosip_lock();
6199                eXosip_automatic_action();
6200                eXosip_unlock();
6201
6202                if(!phIsInitialized)
6203                        return -2;
6204
6205                if (je==NULL)
6206                        break;
6207
6208                counter++;
6209
6210                if (phDebugLevel > 0)
6211                {
6212                        char *remote=0, *req=0;
6213
6214                        if (je->request)
6215                                osip_uri_to_str(je->request->req_uri, &req);
6216
6217                        if (je->response)
6218                                remote = ph_req_get_to(je->response);
6219                        else if (je->request)
6220                                remote = ph_req_get_from(je->request);
6221                        DBG_SIP_EVENT("\n<- %s (%i %i) [%i %s] %s requri=%s\n",
6222                                        evtnames[je->type], je->cid, je->did,
6223                                        je->response ? ph_req_get_status(je->response) : 0,
6224                                                        je->response ? osip_message_get_reason_phrase(je->response) : "",
6225                                                                        remote, req ? req : "");
6226
6227                        if (remote)
6228                                osip_free(remote);
6229                        if (req)
6230                                osip_free(req);
6231                }
6232
6233                switch(je->type)
6234                {
6235                case EXOSIP_CALL_INVITE:
6236                        ph_call_new(je);
6237                        break;
6238
6239                case EXOSIP_CALL_ANSWERED:
6240                        ph_callStopRinging(je);
6241                        ph_call_answered(je);
6242                        break;
6243
6244                case EXOSIP_CALL_PROCEEDING:
6245                        ph_call_proceeding(je);
6246                        break;
6247
6248                case EXOSIP_CALL_RINGING:
6249                        ph_call_ringing(je);
6250                        break;
6251
6252                case EXOSIP_CALL_REQUESTFAILURE:
6253                case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:
6254                        ph_call_requestfailure(je);
6255                        break;
6256
6257                case EXOSIP_CALL_SERVERFAILURE:
6258                case EXOSIP_CALL_MESSAGE_SERVERFAILURE:
6259                        ph_call_serverfailure(je);
6260                        break;
6261
6262                case EXOSIP_CALL_GLOBALFAILURE:
6263                case EXOSIP_CALL_MESSAGE_GLOBALFAILURE:
6264                        ph_call_globalfailure(je);
6265                        break;
6266
6267                case EXOSIP_CALL_NOANSWER:
6268                        ph_call_noanswer(je, 1);
6269                        break;
6270
6271                case EXOSIP_CALL_CLOSED:
6272                        ph_call_closed(je);
6273                        break;
6274
6275                case EXOSIP_CALL_RELEASED:
6276                        ph_call_noanswer(je, 0);
6277                        break;
6278
6279                case EXOSIP_CALL_MESSAGE_NEW:
6280                case EXOSIP_CALL_MESSAGE_PROCEEDING:
6281                        //case EXOSIP_CALL_MESSAGE_ANSWERED:
6282                        ph_call_message_new(je);
6283                        break;
6284
6285                case EXOSIP_REGISTRATION_SUCCESS:
6286                case EXOSIP_REGISTRATION_FAILURE:
6287                        ph_reg_progress(je);
6288                        break;
6289
6290                case EXOSIP_MESSAGE_NEW:
6291                case EXOSIP_MESSAGE_ANSWERED:        /* announce a 200ok to a previous sent */
6292                case EXOSIP_MESSAGE_PROCEEDING:
6293                case EXOSIP_MESSAGE_REQUESTFAILURE:
6294                case EXOSIP_MESSAGE_GLOBALFAILURE:
6295                case EXOSIP_MESSAGE_SERVERFAILURE:
6296                        ph_message_progress(je);
6297                        break;
6298
6299                case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:
6300                case EXOSIP_SUBSCRIPTION_ANSWERED:
6301                        ph_subscription_progress(je);
6302                        break;
6303
6304                case EXOSIP_SUBSCRIPTION_NOTIFY:
6305                        ph_notify_handler(je);
6306                        break;
6307
6308                default:
6309                        if (phDebugLevel > 0)
6310                                DBG_SIP_NEGO("event(%i %i %i %i) text=%s\n", je->cid, je->sid, je->nid, je->did, je->textinfo);
6311                        break;
6312                }
6313
6314                eXosip_event_free(je);
6315        }
6316
6317        if (ph_is_connection_lost)
6318        {
6319                phcb->connectionLost("", 0);
6320                ph_is_connection_lost = 0;
6321        }
6322
6323        ph_refresh_vlines();
6324        ph_scan_calls();
6325
6326        if (counter>0)
6327                return 0;
6328        return -1;
6329}
6330
6331
6332static void
6333ph_keep_refreshing()
6334{
6335        time_t now;
6336        static time_t last_refresh;
6337
6338        time(&now);
6339        if (now - last_refresh > PH_REFRESH_INTERVAL)
6340        {
6341                phRefresh();
6342                last_refresh = now;
6343        }
6344}
6345
6346
6347
6348/**
6349 * eXosip event reader thread
6350 */
6351void *
6352ph_api_thread(void *arg)
6353{
6354        time_t t1;
6355        t1 = 0;
6356        phIsInitialized = 1;
6357
6358        DBG_SIP_EVENT("phapi thread init\n");
6359
6360        time(&t1);
6361        while(1)
6362        {
6363#ifdef WIN32
6364                Sleep(100);
6365#endif
6366                if (!phIsInitialized)
6367                        return 0;
6368
6369                ph_keep_refreshing();
6370
6371                if (ph_event_get() == -2)
6372                {
6373                        phTerminate();
6374                        break;
6375                }
6376        }
6377
6378        return 0;
6379}
6380
6381#ifdef QOS_DEBUG_ENABLE
6382PHAPI_EXPORT void phrtcp_QoS_enable_rtcp_report(int ToF)
6383{
6384        ortcp_enable_rtcp_report(ToF);
6385}
6386PHAPI_EXPORT void phrtcp_report_set_cb(jt_rtcpCallbacks_t *cbk)
6387{
6388        ortcp_report_set_cb(cbk);
6389}
6390PHAPI_EXPORT int phrtcp_report_begin()
6391{
6392        phrtcp_QoS_enable_rtcp_report(1);
6393        ortcp_report_begin();
6394}
6395PHAPI_EXPORT int phrtcp_report_end()
6396{
6397        ortcp_report_end();
6398}
6399#endif /* end of QOS_DEBUG_ENABLE */
6400
6401
6402int getPublicPort(char *  local_voice_port, char * local_video_port, char * public_voice_port, char * public_video_port)
6403{
6404
6405        Socket  sock;
6406        Socket  sock1;
6407        Socket  sock2;
6408        Socket  sock3;
6409        StunAddress4 mappedAddr, rtcpAddr;
6410        StunAddress4 stunServerAddr;
6411        int res;
6412        int res2;
6413        int loop = 0;
6414
6415        if (phcfg.use_tunnel)
6416                return 1;
6417
6418        stunParseServerName(phcfg.stunserver, &stunServerAddr);
6419
6420        do {
6421
6422                printf("get pub video: %s", local_voice_port);
6423                res = stunOpenSocketPair(&stunServerAddr, &mappedAddr, &rtcpAddr, &sock, &sock1,atoi(local_voice_port), 0);
6424
6425                if (-1 !=  res)
6426                {
6427                        snprintf(local_voice_port, 9, "%i", res);
6428                        snprintf(public_voice_port, 9, "%d", mappedAddr.port);
6429                        closesocket(sock1);
6430                        closesocket(sock);
6431                }
6432                else
6433                {
6434                        closesocket(sock);
6435                        closesocket(sock1);
6436                        snprintf(local_voice_port, 9, "%i",atoi(local_voice_port)+5);
6437                        loop++;
6438                }
6439        } while (res <0 && loop < 4 );
6440
6441        if (res <0)
6442        {
6443                return -1;
6444        }
6445
6446        loop = 0;
6447
6448        do {
6449                printf("get pub video: %s", local_video_port);
6450
6451                res2 = stunOpenSocketPair(&stunServerAddr, &mappedAddr, &rtcpAddr, &sock2, &sock3,atoi(local_video_port), 0);
6452                //sock2 = stunOpenSocket(&stunServerAddr, &mappedAddr, atoi(&local_video_port), NULL, 0);
6453
6454                if (-1 !=  res2)
6455                {
6456                        snprintf(local_video_port, 9, "%i", res2);
6457                        snprintf(public_video_port, 9, "%d", mappedAddr.port);
6458                        closesocket(sock2);
6459                        closesocket(sock3);
6460                }
6461                else
6462                {
6463                        closesocket(sock2);
6464                        closesocket(sock3);
6465                        snprintf(local_video_port, 9, "%i",atoi(local_video_port)+5);
6466
6467                        loop++;
6468                }
6469        } while(res2 <0 && loop < 4 );
6470
6471        if (res2 <0)
6472        {
6473                return -1;
6474        }
6475
6476        printf("get public port public voice_port: %s video: %s  ------ \n \n ",public_voice_port, public_video_port);
6477        return 1;
6478}
6479
6480
6481
6482PHAPI_EXPORT int
6483phAudioSoftRecvVolumeGain(int cid, float gain)
6484{
6485        phcall_t *ca=NULL;
6486        struct ph_msession_s *s = NULL;
6487
6488        if (!phIsInitialized)
6489                return -PH_NOTINIT;
6490
6491        ca = ph_locate_call_by_cid(cid);
6492        if (!ca)
6493                return -PH_BADCID;
6494        s = ca->mses;
6495        if (!s)
6496                return -PH_NOMEDIA;
6497        phms_audio_stream_set_soft_recv_volume_gain(s, gain);
6498        return 0;
6499}
6500
6501PHAPI_EXPORT int
6502phAudioSoftSendVolumeGain(int cid, float gain)
6503{
6504        phcall_t *ca=NULL;
6505        struct ph_msession_s *s = NULL;
6506
6507        if (!phIsInitialized)
6508                return -PH_NOTINIT;
6509
6510        ca = ph_locate_call_by_cid(cid);
6511        if (!ca)
6512                return -PH_BADCID;
6513        s = ca->mses;
6514        if (!s)
6515                return -PH_NOMEDIA;
6516        phms_audio_stream_set_soft_send_volume_gain(s, gain);
6517        return 0;
6518}
6519
6520// from 0 to 100
6521PHAPI_EXPORT int
6522phAudioRecvVolumeLevel(int cid, int level)
6523{
6524        phcall_t *ca=NULL;
6525        struct ph_msession_s *s = NULL;
6526
6527        if (!phIsInitialized)
6528                return -PH_NOTINIT;
6529
6530        ca = ph_locate_call_by_cid(cid);
6531        if (!ca)
6532                return -PH_BADCID;
6533        s = ca->mses;
6534        if (!s)
6535                return -PH_NOMEDIA;
6536        phms_audio_stream_set_recv_volume_level(s, level);
6537        return 0;
6538}
6539// from 0 to 100
6540PHAPI_EXPORT int
6541phAudioSendVolumeLevel(int cid, int level)
6542{
6543        phcall_t *ca=NULL;
6544        struct ph_msession_s *s = NULL;
6545
6546        if (!phIsInitialized)
6547                return -PH_NOTINIT;
6548
6549        ca = ph_locate_call_by_cid(cid);
6550        if (!ca)
6551                return -PH_BADCID;
6552        s = ca->mses;
6553        if (!s)
6554                return -PH_NOMEDIA;
6555        phms_audio_stream_set_send_volume_level(s, level);
6556        return 0;
6557}
6558//val 0: unmute, 1: mute
6559PHAPI_EXPORT int
6560phAudioMutePlayback(int cid, int val)
6561{
6562        phcall_t *ca=NULL;
6563        struct ph_msession_s *s = NULL;
6564
6565        if (!phIsInitialized)
6566                return -PH_NOTINIT;
6567
6568        ca = ph_locate_call_by_cid(cid);
6569        if (!ca)
6570                return -PH_BADCID;
6571        s = ca->mses;
6572        if (!s)
6573                return -PH_NOMEDIA;
6574        phms_audio_stream_mute_playback(s, val);
6575        return 0;
6576}
6577//val 0: unmute, 1: mute
6578PHAPI_EXPORT int
6579phAudioMuteCapture(int cid, int val)
6580{
6581        phcall_t *ca=NULL;
6582        struct ph_msession_s *s = NULL;
6583
6584        if (!phIsInitialized)
6585                return -PH_NOTINIT;
6586
6587        ca = ph_locate_call_by_cid(cid);
6588        if (!ca)
6589                return -PH_BADCID;
6590        s = ca->mses;
6591        if (!s)
6592                return -PH_NOMEDIA;
6593        phms_audio_stream_mute_capture(s, val);
6594        return 0;
6595}
6596
6597
6598int phLineGetSipAddress(int vlid, char buf[], int bufsize)
6599{
6600        struct vline *vl;
6601
6602        if (!phIsInitialized)
6603                return -PH_NOTINIT;
6604
6605        vl = ph_valid_vlid(vlid);
6606
6607        if (!vl) {
6608                return -PH_BADVLID;
6609        }
6610
6611        ph_build_from2(buf, bufsize, vl, FROM_PORT);
6612        return 0;
6613}
6614
6615
6616int phCrash() {
6617        return *(int *)0 = 0;
6618}
6619
6620void phSetDebugLevel(int level) {
6621        phDebugLevel = level;
6622}
6623
6624int phGetDebugLevel() {
6625        return phDebugLevel;
6626}
6627
6628void phSetLogFileName(const char *name)
6629{
6630        if (phLogFileName)
6631                free(phLogFileName);
6632
6633        phLogFileName = name ? strdup(name) : 0;
6634
6635
6636}
6637
6638#else
6639
6640void dummy()
6641{
6642        eXosip_init();
6643}
6644
6645#endif
6646
6647
6648
6649
6650
6651int
6652phAddCustomization(const char *reqnames, const char *hdrname,  const char *hdrval)
6653{
6654    struct ph_custom_hdr *hdr;
6655
6656    hdr = (struct ph_custom_hdr*) osip_malloc(sizeof(struct ph_custom_hdr));
6657
6658    if (!hdr)
6659        return -1;
6660
6661    memset(hdr, 0, sizeof(*hdr));
6662
6663    hdr->matchrequests = osip_strdup(reqnames);
6664    hdr->hdrname = osip_strdup(hdrname);
6665    hdr->hdrvalue = osip_strdup(hdrval);
6666    hdr->enabled = 1;
6667
6668    ph_custom_lock();
6669    hdr->idx = ++ph_custom_idx;
6670    osip_list_add(&ph_custom_headers, hdr, -1);
6671    ph_custom_unlock();
6672
6673    return hdr->idx;
6674
6675
6676
6677}
6678
6679static void
6680set_customized_header(osip_message_t *req, const char *h, const char *v)
6681{
6682
6683    if (!osip_strcasecmp(h, "Expires"))
6684      osip_message_replace_header(req, "Expires", v);
6685    else
6686        osip_message_set_multiple_header(req, h, v);
6687
6688}
6689
6690int
6691ph_apply_customizations(osip_message_t *req, const char *reqname, const char *selectedheaders)
6692{
6693    struct ph_custom_hdr *hdr;
6694    int i = 0;
6695
6696
6697    if (!reqname)
6698        reqname = req->sip_method;
6699
6700        ph_custom_lock();
6701    while(1)
6702    {
6703        hdr = (struct ph_custom_hdr *) osip_list_get(&ph_custom_headers, i);
6704        if (!hdr) {
6705                ph_custom_unlock();
6706            return 0;
6707        }
6708
6709        if (hdr->enabled && (!selectedheaders || (0 != strstr(hdr->hdrname