source: verona/phapi/phapi.c @ 252:690efbd91dd4

Last change on this file since 252:690efbd91dd4 was 252:690efbd91dd4, checked in by Vadim Lebedev <vadim@…>, 23 months ago

Add support for specifying explicit NAT router address
Fix handling of route for REGISTER requests
Implement support for adding user=phone to Contact header

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