source: verona/phapi/phapi.c @ 149:58ec07575676

Last change on this file since 149:58ec07575676 was 149:58ec07575676, checked in by Nikita Kozlov <nikita@…>, 2 years ago

fix some memleaks
fix a bug in ph_event_get
verify if je->request or je->response are not null

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