source: verona/phapi/phapi.c @ 364:e1b6bfaba51c

Last change on this file since 364:e1b6bfaba51c was 364:e1b6bfaba51c, checked in by Vadim Lebedev <vadim@…>, 19 months ago

Implement correct hanling of Expires parameter value in Contact header of REGISTER replies

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