source: verona/phapi/phapi.c @ 251:036da14859a9

Last change on this file since 251:036da14859a9 was 251:036da14859a9, checked in by laurent@…, 2 years ago

407 on msg progress

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