source: verona/phapi/phapi.c @ 150:5e24ab07af1f

Last change on this file since 150:5e24ab07af1f was 150:5e24ab07af1f, checked in by Nikita Kozlov <nikita@…>, 2 years ago

fix some memleaks in phapi

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