source: verona/phapi/phapi.c @ 328:6958600035b6

Last change on this file since 328:6958600035b6 was 328:6958600035b6, checked in by laurent <laurent@…>, 20 months ago

bug fix : audio/video codec payload

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