source: verona/phapi/phapi.c @ 415:a7c9cc9649df

Last change on this file since 415:a7c9cc9649df was 415:a7c9cc9649df, checked in by Vadim Lebedev <vadim@…>, 17 months ago

finlize tunneling support

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