source: verona/phapi/phapi.c @ 500:14e6bfd2a601

Last change on this file since 500:14e6bfd2a601 was 500:14e6bfd2a601, checked in by Vadim Lebedev <vadim@…>, 12 months ago

fixes to ensure arguments constness in set_customized_header

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