source: verona/phapi/phapi.c @ 429:92c63fc5b57b

Last change on this file since 429:92c63fc5b57b was 429:92c63fc5b57b, checked in by laurent <laurent@…>, 16 months ago

USE_PNP => USE_UPNP

File size: 162.7 KB
Line 
1/*
2 * phapi   phone api
3 *
4 * Copyright (C) 2004        Vadim Lebedev <vadim@mbdsys.com>
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as
8 * published by the Free Software F undation; either version 2,
9 * or (at your option) any later version.
10 *
11 * This is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with dpkg; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/**
22 * @file phapi.c
23 * @brief softphone  API
24 *
25 * phapi is a library providing simplified api to create VOIP sessions
26 * using eXosip library oSIP stack and oRTP stack
27 * <P>
28 */
29
30#include "phglobal.h"
31#ifdef OS_WIN32
32#include <winsock2.h>
33#include <windows.h>
34#endif
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <errno.h>
41#include <limits.h>
42#include <ctype.h>
43#include <assert.h>
44#include <time.h>
45
46#if !defined(OS_WIN32) && !defined(_WIN32_WCE)
47//#include "config.h"
48#include <sys/wait.h>
49#include <unistd.h>
50#include <dirent.h>
51#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
52#include <sys/soundcard.h>
53#endif
54#include <sys/ioctl.h>
55#include <fcntl.h>
56#else  /* WIN32 */
57#define snprintf _snprintf
58#ifndef _WIN32_WCE
59#define strncasecmp strnicmp
60#endif /* !_WIN32_WCE */
61# if !defined(strcasecmp)
62#  define strcasecmp stricmp
63# endif
64#define usleep(usecs) Sleep((usecs)/1000)
65#define random rand
66#define osip_free_func osip_free
67#endif
68
69#ifdef HAVE_NETINET_IN_H
70#include <netinet/in.h>
71#endif
72#include <osipparser2/osip_list.h>
73#include <osipparser2/osip_port.h>
74#include <osip2/osip_dialog.h>
75#include <osip2/osip_mt.h>
76#include <osip2/osip.h>
77#include <eXosip2/eXosip.h>
78#include <ortp/stun.h>
79#include <ortp/ortp.h>
80#include <ortp/payloadtype.h>
81
82#include "phapi-config.h"
83
84#include "phdebug.h"
85#include "phapi.h"
86#include "phcall.h"
87#include "phrpc.h"
88
89#include "phms.h"
90#include "phms_audiostream.h"
91#include "sdphandler.h"
92
93#ifdef USE_HTTP_TUNNEL
94#include "httptunnel.h"
95#endif
96
97#if  1
98
99#ifdef PHAPI_VIDEO_SUPPORT
100#include <libavcodec/avcodec.h>
101#include "phms_videostream.h"
102#endif
103
104#ifdef USE_UPNP
105#include <miniupnpc/upnpcommands.h>
106#include <miniupnpc/miniupnpc.h>
107
108static struct UPNPUrls ph_upnp_urls;
109static struct IGDdatas ph_upnp_data;
110static struct UPNPDev * ph_upnp_devlist;
111#endif
112
113static struct osip_thread *phapithread = NULL;
114
115phcall_t *ph_locate_call(eXosip_event_t *je, int creatit);
116phcall_t *ph_allocate_call(int cid);
117phcall_t *ph_locate_call_for_refer(eXosip_event_t *je);
118
119void ph_wegot_dtmf(void  *ctx, int dtmfEvent);
120static int ph_event_get();
121
122
123static char *ph_get_call_(phcall_t *ca);
124static void set_customized_header(osip_message_t *req, const char *h, const char *v);
125static char *ph_get_call_contact(phcall_t *ca);
126
127//#define MEDIA_SUSPEND
128
129/*#ifndef PH_STREAM_AUDIO
130#define PH_STREAM_AUDIO (1 << 0)
131#define PH_STREAM_VIDEO_RX (1 << 1)
132#define PH_STREAM_VIDEO_TX (1 << 2)
133#endif*/
134
135#define PH_STREAM_CNG (1 << 30)
136
137
138static int ph_call_retrieve_payloads(phcall_t *ca, int flags);
139static int ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag);
140static char *ph_ipv4tostr(char *buf, size_t s, const StunAddress4 addr);
141static void ph_release_stream_ports(phcall_t *ca);
142
143void ph_release_call(phcall_t *ca);
144static  int timeout = 10;
145
146static int ph_resend_offset = 30;
147
148#define PORT_STRING_LEN 16
149static char ph_nat_router_addr[32];
150static char ph_nat_port_str[PORT_STRING_LEN];
151
152#ifdef PHAPI_VIDEO_SUPPORT
153static char ph_nat_video_port_str[16];
154#endif
155
156static char ph_nat_sip_port_str[16];
157
158static char vcontact[256];
159
160typedef enum phNatType
161{
162        OPEN,
163        UPNP,
164        STUN,
165        TUNNEL
166}phNatType;
167
168static phNatType ph_nat_type = OPEN;
169static NatType ph_stun_nat_type = StunTypeOpen;
170
171static size_t ph_generate_rfc5626_probe(int rid, const void *addr, int addrlen, char* buf, size_t bsize);
172static char * _get_local_sip_port();
173static void  _get_local_video_sdp_port(char buf[]);
174static void  _get_local_audio_sdp_port(char buf[]);
175
176static char*  _get_public_sip_port();
177
178static void ph_connection_lost(const char *host, int port);
179static int ph_is_connection_lost;
180static char* ph_is_connection_lost_host;
181static int ph_is_connection_lost_port;
182
183void ph_message_progress(eXosip_event_t *je);
184static void ph_keep_refreshing();
185static void  ph_call_requestfailure(eXosip_event_t *je);
186
187static void ph_frame_display_cbk(void *ctx, void *event);
188static void ph_qos_info_cbk(void *ctx, void *info);
189
190static int ph_call_media_stop(phcall_t * ca);
191static int ph_call_media_suspend(phcall_t *ca, int localhold);
192
193enum ph_direction
194{
195        sendrecv,
196        sendonly,
197        recvonly,
198        inactive
199};
200
201enum ph_direction ph_get_media_direction( sdp_message_t * sdp, const char * media_type);
202enum ph_direction ph_get_local_media_direction( phcall_t *ca, const char * media_type);
203int ph_set_media_direction( sdp_message_t * sdp, const char *media_type, enum ph_direction direction);
204const char * ph_get_str_direction( enum ph_direction direction);
205
206#define nonempty(x)  ((x) && (x)[0])
207
208
209#define USE_VLINES 1
210#ifndef PH_MAX_VLINES
211#define PH_MAX_VLINES 16
212#endif
213
214
215struct vline
216{
217        char  *displayname;
218        char  *nrusername;   /* username for non-REGISTER requests */
219        char  *rusername;    /* username for REGISTER requests */
220        char  *server;
221        int    port;
222        char  *proxy;
223        char  *contact;
224        time_t   regTimeout;
225        time_t   lastRegTime;
226        int   rid;
227#define VL_USED 1
228#define VL_DELETING 2
229        int   used;
230        int   busy;
231        char  *followme;
232        int    mobility;
233        struct
234        {
235                time_t  timeout;
236                time_t  last;
237                char    *etag;
238                char    *uri;
239                char    *evt;
240                char    *ctt;
241                char    *body;
242        } pub;
243};
244
245
246struct vline ph_vlines[PH_MAX_VLINES];
247
248#ifdef ENABLE_SOCKS
249#define TUNNEL_MAX 16
250struct tunnel_info {
251        char tunnel_proto[16];
252        char tunnel_server[64];
253        char tunnel_port[8];
254};
255
256static struct tunnel_info sip_tunnel_set[TUNNEL_MAX];
257static int sip_tunnel_count;
258
259static struct tunnel_info rtp_tunnel_set[TUNNEL_MAX];
260static int rtp_tunnel_count;
261
262static void copyfield(char *dst, const char* src, const char *eos, int M)
263{
264        int L = eos - src;
265
266        osip_strncpy(dst, src, M);
267        if (L < M)
268                dst[L] = 0;
269
270}
271/*
272 *  parse proto://addr:port
273 *  return 0 in case of success
274 */
275int ph_parse_tunnel_info(struct tunnel_info *tun,  const char *uri)
276{
277        const char  *addr, *port;
278        const char *eos;
279
280        addr = strstr(uri, "://");
281        if (!addr)
282                return -1;
283
284        port = strstr(addr+3, ":");
285        if (!port)
286                return -1;
287
288        eos = port+1;
289        while(*eos && isdigit(*eos))
290                eos++;
291
292        while(*uri && isspace(*uri))
293                uri++;
294
295
296        copyfield(tun->tunnel_proto,  uri, addr, sizeof(tun->tunnel_proto)-1);
297        copyfield(tun->tunnel_server,  addr+3, port, sizeof(tun->tunnel_server)-1);
298        copyfield(tun->tunnel_port,  port+1, eos, sizeof(tun->tunnel_port)-1);
299
300        return 0;
301
302}
303
304/*
305 * parse proto1://addr1:port1,proto2://addr2:port2,.....
306 * return number of parsed elements
307 */
308int ph_parse_tunnel_list(struct tunnel_info *tinfo, const char* urilist, int N)
309{
310        int i = 0;
311        struct tunnel_info *tun = tinfo;
312        const char *p = urilist;
313
314        while(p && (i++ < N)) {
315                if (ph_parse_tunnel_info(tun, p))
316                        break;
317                p = strchr(p, ',');
318                if (p)
319                        p++;
320        }
321
322        return i;
323}
324
325struct tunnel_info *ph_select_tunnel(struct tunnel_info *tinfo, int N)
326{
327        return tinfo + random() % N;
328
329}
330#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, 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_mflags)) {
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_UPNP
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_UPNP
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        return 0;
4265#endif
4266
4267#ifdef USE_HTTP_TUNNEL
4268        eXosip_tunnel_t *tunnel = NULL;
4269        int port;
4270        char *c;
4271        char buf[256];
4272        int tunerr;
4273
4274        if (!(phcfg.use_tunnel & PH_TUNNEL_USE))
4275                return 0;
4276
4277        http_tunnel_init_host(phcfg.httpt_server, phcfg.httpt_server_port, phcfg.use_tunnel & PH_TUNNEL_SSL);
4278        http_tunnel_init_proxy(phcfg.http_proxy,phcfg.http_proxy_port,
4279                        phcfg.http_proxy_user, phcfg.http_proxy_passwd);
4280
4281        tunnel = malloc(sizeof(eXosip_tunnel_t));
4282        if (tunnel)
4283        {
4284                osip_strncpy(buf, phcfg.proxy, sizeof(buf)-1);
4285                c = strstr(buf, ":");
4286
4287                port = 5060;
4288                if (c)
4289                {
4290                        *c++ = 0;
4291                        port = atoi(c);
4292                }
4293                tunnel->h_tunnel = http_tunnel_open(buf, port, HTTP_TUNNEL_VAR_MODE, &tunerr, -1);
4294                if (!tunnel->h_tunnel)
4295                {
4296                        if (!tunnel->h_tunnel)
4297                        {
4298                                free(tunnel);
4299                                return -PH_NOTUNNEL;
4300                        }
4301                }
4302
4303                tunnel->tunnel_recv = http_tunnel_recv;
4304                tunnel->tunnel_send = http_tunnel_send;
4305                tunnel->get_tunnel_socket = http_tunnel_get_socket;
4306                phTunnel = tunnel;
4307                ph_nat_type = TUNNEL;
4308                return 0;
4309        }
4310
4311
4312
4313
4314        return -PH_NORESOURCES;
4315#else
4316        return -1;
4317#endif
4318}
4319
4320#ifdef USE_UPNP
4321
4322static int
4323ph_upnp_add_redirection(const char * addr, char * local_port, char * extern_port, char * proto)
4324{
4325        if( UPNP_AddPortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, extern_port,local_port, addr, 0,proto, 0) == UPNPCOMMAND_SUCCESS)
4326        {
4327                return 0;
4328        }
4329       
4330        return -1;
4331}
4332
4333static int
4334ph_upnp_remove_redirection(char * sport, char * proto)
4335{
4336        if( UPNP_DeletePortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, sport, proto,0) == UPNPCOMMAND_SUCCESS)
4337        {
4338                return 0;
4339        }
4340       
4341        return -1;
4342}
4343
4344static int
4345ph_upnp_redirect_port(const char* addr, int lport, int* pport, const char *proto)
4346{
4347        char lpstr[16], ppstr[16];
4348
4349        sinprintf(lpstr, 16, "%d", lport);
4350
4351        if (!ph_upnp_add_redirection(addr, lpstr, pppstr, proto)) {
4352                *pport = atoi(ppstr);
4353                return 0;
4354        }
4355
4356        return -1;
4357
4358}
4359
4360static int
4361ph_upnp_release_port(int lport, const char *proto)
4362{
4363        char lpstr[16], ppstr[16];
4364
4365        sinprintf(lpstr, 16, "%d", lport);
4366
4367        if (!ph_upnp_remove_redirection(lpstr, proto)) {
4368                return 0;
4369        }
4370
4371        return -1;
4372
4373}
4374
4375
4376static int
4377ph_upnp_init()
4378{
4379        int result = -1;
4380       
4381        char lanaddr[16];
4382        struct UPNPDev * devlist = upnpDiscover(500, 0, 0, 0);
4383        if( UPNP_GetValidIGD(devlist, &ph_upnp_urls, &ph_upnp_data, lanaddr, sizeof(lanaddr)) == 1 )
4384        {
4385                if(phcfg.local_ip_addr[0] == 0)
4386                        snprintf(phcfg.local_ip_addr, sizeof(phcfg.local_ip_addr),"%s",lanaddr);
4387                       
4388                if( UPNP_GetExternalIPAddress(ph_upnp_urls.controlURL,ph_upnp_data.first.servicetype,ph_nat_router_addr) == UPNPCOMMAND_SUCCESS)
4389                {
4390                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%s", _get_local_sip_port());
4391                       
4392                        result = ph_upnp_add_redirection(phcfg.local_ip_addr,_get_local_sip_port(),ph_nat_sip_port_str, phcfg.transport == IPPROTO_UDP ? "UDP" : "TCP");
4393                        if(!result)
4394                        {
4395                                eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4396                                ph_nat_type = UPNP;
4397                        }
4398                }
4399        }
4400        ph_upnp_devlist = devlist;
4401       
4402        return result;
4403}
4404
4405#endif
4406
4407static int
4408ph_stun_init()
4409{
4410        bool_t resPort = 0, hairpin = 0;
4411        StunAddress4 stunServerAddr;
4412        stunParseServerName(phcfg.stunserver, &stunServerAddr);
4413       
4414        ph_stun_nat_type = stunNatType( &stunServerAddr, &resPort, &hairpin,0, 0);
4415       
4416        if( ph_stun_nat_type == StunTypeConeNat || ph_stun_nat_type == StunTypeRestrictedNat || ph_stun_nat_type == StunTypePortRestrictedNat)
4417        {
4418                StunAddress4 mappedAddr;
4419                Socket  sock = stunOpenSocket(&stunServerAddr, &mappedAddr, atoi(_get_local_sip_port()), 0);
4420               
4421                if ( sock != -1 )
4422                {
4423                        ph_ipv4tostr(ph_nat_router_addr, sizeof(ph_nat_router_addr), mappedAddr);
4424                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%d", mappedAddr.port);
4425                        closesocket(sock);
4426                       
4427                        eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4428                        ph_nat_type = STUN;
4429                       
4430                        return 0;
4431                }
4432        }
4433       
4434        return -1;
4435}
4436
4437static void
4438ph_nat_init()
4439{
4440        ph_nat_router_addr[0] = 0;
4441        ph_nat_port_str[0] = 0;
4442
4443#if 0
4444        if (!phcfg.nat_refresh_udp_time)
4445                phcfg.nat_refresh_udp_time = 15;
4446       
4447        if (!phcfg.nat_refresh_tcp_time)
4448                phcfg.nat_refresh_tcp_time = 15;
4449#endif
4450
4451#ifdef USE_UPNP
4452        if(phcfg.use_upnp)
4453        {
4454                if(!ph_upnp_init())
4455                        return;
4456        }
4457#endif
4458       
4459        if(phcfg.use_stun)
4460        {
4461                if(!ph_stun_init())
4462                        return;
4463        }
4464       
4465        if(phcfg.use_tunnel)
4466        {
4467                if(!ph_tunnel_init())
4468                        return;
4469        }
4470
4471        //nat should be open
4472        ph_nat_type = OPEN;
4473//      phcfg.nat_refresh_udp_time = 0;
4474//      phcfg.nat_refresh_tcp_time = 0;
4475       
4476        if (phcfg.local_ip_addr[0] != 0)
4477                eXosip_masquerade_contact(phcfg.local_ip_addr, atoi(_get_local_sip_port()));
4478}
4479
4480/**
4481 * @brief initialize the payload/codecs that are allowed to be handled by the SIP stack
4482 */
4483PHAPI_EXPORT void
4484ph_payloads_init()
4485{
4486        char audio_codecs[128];
4487       
4488#ifdef PHAPI_VIDEO_SUPPORT
4489        char video_codecs[128];
4490        osip_strncpy(video_codecs,phcfg.video_codecs,sizeof(phcfg.video_codecs)-1);
4491        osip_list_init(&ph_video_payloads);
4492        if (!video_codecs[0]) {
4493                ph_setup_video_payload("H263/90000");
4494        } else {
4495                char tmp[32];
4496                char *tok = strtok(video_codecs, ",");
4497
4498                while(tok) {
4499                        snprintf(tmp, sizeof(tmp), "%s/90000", tok);
4500                        ph_setup_video_payload(tmp);
4501                        tok = strtok(0, ",");
4502                }
4503        }
4504#endif
4505       
4506        // init payload/codecs for AUDIO
4507        osip_list_init(&ph_audio_payloads);
4508        osip_strncpy(audio_codecs,phcfg.audio_codecs,sizeof(phcfg.audio_codecs)-1);
4509       
4510        // add codecs out of an ENV var
4511        {
4512                char *aclist = getenv("PH_AUDIO_CODECS");
4513                if (aclist) {
4514                        osip_strncpy(audio_codecs, aclist, sizeof(audio_codecs)-1);
4515                }
4516
4517        }
4518
4519
4520        // limit codecs to G711 codecs according to compile time DEFINE
4521#ifdef G711_ONLY
4522        strcpy(audio_codecs, "PCMU/8000,PCMA/8000");
4523#endif
4524
4525        // if at this stage, no codecs are required, fix a default list
4526        if (!audio_codecs[0])
4527        {
4528                ph_setup_payload("PCMU/8000");
4529                ph_setup_payload("PCMA/8000");
4530                ph_setup_payload("GSM/8000");
4531                ph_setup_payload("ILBC/8000");
4532                ph_setup_payload("SPEEX/16000");
4533                ph_setup_payload("SPEEX/8000");
4534                ph_setup_payload("AMR/8000");
4535                ph_setup_payload("AMR-WB/16000");
4536                ph_setup_payload("G722/8000");
4537                ph_setup_payload("G726-32/8000");
4538
4539        }
4540        // phapi.h client has required a specific list of codecs
4541        else
4542        {
4543
4544                /*
4545        The list is "," separated
4546        some hacks are present to allow for :
4547        - payload usurpation
4548        - default /8000 clockrate when not specified
4549        - ... look at the code
4550                 */
4551
4552
4553                char tmp[32];
4554                char *tok = strtok(audio_codecs, ",");
4555
4556                while(tok)
4557                {
4558                        if(!strcmp(tok, "AMR-WB"))
4559                        {
4560#ifdef AMR_OVER_G729_HACK
4561                                snprintf(tmp, sizeof(tmp), "G729/8000");
4562#else
4563                                snprintf(tmp, sizeof(tmp), "%s/16000", tok);
4564#endif
4565                        }
4566#ifdef SPEEX_OVER_G729_HACK
4567                        else if(!strcmp(tok, "SPEEX/16000"))
4568                        {
4569                                snprintf(tmp, sizeof(tmp), "G729/8000");
4570                        }
4571#endif
4572                        else if (strchr(tok, '/'))
4573                                osip_strncpy(tmp, tok, sizeof(tmp)-1);
4574                        else
4575                                snprintf(tmp, sizeof(tmp), "%s/8000", tok);
4576
4577                        ph_setup_payload(tmp);
4578
4579                        tok = strtok(0, ",");
4580                }
4581        }
4582
4583        // set codec in sip stack for CNG (confort noise generator=
4584        if(phcfg.cng)
4585                ph_setup_payload("CN/8000");
4586
4587        // set codec in sip stack for DTMF
4588        ph_setup_payload("telephone-event/8000");
4589}
4590
4591static int
4592ph_get_call_id(int did, char **cid)
4593{
4594        char referto[512];
4595        char *cp, *semi;
4596        int i;
4597
4598        i = eXosip_call_get_referto(did, referto, sizeof(referto));
4599        if (i)
4600                return -PH_ERROR;
4601        cp = strstr(referto, "Replaces");
4602        if (!cp)
4603                return -PH_ERROR;
4604        cp += 9;
4605        semi = strchr(cp, ';');
4606        if (semi)
4607                *semi = 0;
4608
4609        *cid = osip_strdup(cp);
4610
4611        return *cid ? 0 : -PH_NORESOURCES;
4612}
4613
4614
4615PHAPI_EXPORT int
4616phCallGetSipCallID(int cid, char* buf, int bufsize)
4617{
4618        phcall_t *ca;
4619        char *callid;
4620        int i;
4621
4622        if (!phIsInitialized)
4623                return -PH_NOTINIT;
4624
4625        ca = ph_locate_call_by_cid(cid);
4626
4627        if (!ca)
4628                return -PH_BADCID;
4629
4630        if( bufsize  <= 0 || !buf)
4631                return -PH_BADARG;
4632
4633
4634        eXosip_lock();
4635        i = ph_get_call_id(ca->did, &callid);
4636        eXosip_unlock();
4637
4638        if(!i)
4639        {
4640                osip_strncpy(buf, callid, bufsize-1);
4641                osip_free(callid);
4642                return 0;
4643        }
4644
4645        return -PH_ERROR;
4646}
4647
4648PHAPI_EXPORT int
4649phListenAddr(int local_sip_port)
4650{
4651        int i, cpt = 0;
4652        int secure = 0;
4653        int proto = phcfg.transport;
4654
4655        for (cpt = 0; cpt < 5; cpt++)
4656        {
4657                if (phcfg.local_ip_addr[0] == 0)
4658                        i = eXosip_listen_addr(proto, NULL,local_sip_port + cpt, AF_INET, secure);
4659                else
4660                        i = eXosip_listen_addr(proto, phcfg.local_ip_addr,local_sip_port + cpt, AF_INET, secure);
4661
4662                if(!i)
4663                        break;
4664        }
4665
4666        return i;
4667}
4668
4669PHAPI_EXPORT int
4670phInit(phCallbacks_t *cbk, char * server, int asyncmode)
4671{
4672        int i;
4673        const char *tmp;
4674        int nat_refresh_time = 0;
4675
4676        if (phIsInitialized)
4677                return 0;
4678
4679        memset(vcontact, 0, sizeof(vcontact));
4680
4681        i = ph_debug_init();
4682
4683        if (i)
4684                return i;
4685
4686        tmp = getenv("EXOSIP_RESEND_OFFSET");
4687        if (tmp && strlen(tmp))
4688                ph_resend_offset = atoi(tmp);
4689
4690        ph_avcodec_init();
4691        ph_calls_init();
4692
4693        if (phcfg.use_tunnel)
4694        {
4695                i = ph_tunnel_init();
4696                if (i)
4697                        return i;
4698        }
4699
4700#ifdef FORCE_VAD
4701        /* HACK for test */
4702#ifdef EMBED
4703        phcfg.vad = VAD_VALID_MASK | (500 & VAD_THRESHOLD_MASK);
4704#else
4705        phcfg.vad = VAD_VALID_MASK | (1000 & VAD_THRESHOLD_MASK);
4706#endif
4707#endif
4708
4709#ifdef FORCE_CNG
4710        /* HACK for test */
4711        phcfg.cng = 1;
4712#endif
4713
4714
4715        ph_media_init(phcfg.plugin_path); //init ortp/ms2 payloads list, init ms2 and ortp
4716
4717        if (phcfg.use_tunnel) {
4718
4719                // ph_setup_tunnel();
4720
4721        }
4722
4723        i = eXosip_init();
4724        if (i)
4725                return -1;
4726
4727        if (phcfg.use_tunnel & PH_TUNNEL_USE) {
4728                struct tunnel_info *tun;
4729
4730                tun = ph_select_tunnel(sip_tunnel_set, sip_tunnel_count);
4731                if (tun)
4732                        eXosip_set_tunnel(tun->tunnel_proto, tun->tunnel_server, tun->tunnel_port);;
4733        }
4734
4735       
4736        ph_nat_init();
4737       
4738        DBG_SIP_NEGO("NAT type: %s fw=%s \n", ph_get_nat_type(), ph_nat_router_addr);
4739
4740        if (phcfg.public_ip_addr[0])
4741        {
4742                int port = atoi(phcfg.public_sipport);
4743                eXosip_masquerade_contact(phcfg.public_ip_addr, port ? port : atoi(phcfg.sipport));
4744        }
4745
4746        if (!(phcfg.use_tunnel & PH_TUNNEL_USE)) {
4747                i = phListenAddr(atoi(phcfg.sipport));
4748                if(i)
4749                        return -1;
4750        }
4751
4752        {
4753                const char * ua  = "phapi/eXosip-" PHAPI_VERSION_STRING;
4754                eXosip_set_user_agent(ua);
4755        }
4756
4757        nat_refresh_time = (phcfg.transport == IPPROTO_UDP) ? phcfg.nat_refresh_udp_time : phcfg.nat_refresh_tcp_time;
4758        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE, &nat_refresh_time);
4759        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE_ADJUST, &phcfg.nat_refresh_time_adjust);
4760
4761        eXosip_set_cbconnection_close(ph_connection_lost);
4762       
4763        memset(ph_vlines, 0, sizeof(ph_vlines));
4764
4765        ph_payloads_init(); //init phapi codecs lists
4766
4767        /* register callbacks? */
4768        phcb = cbk;
4769        phcfg.asyncmode = asyncmode;
4770        if (!asyncmode)
4771                timeout = 0;
4772        else
4773                timeout = 10;
4774
4775        ph_media_start_mutex = osip_mutex_init();
4776        ph_media_stop_mutex = osip_mutex_init();
4777        ph_custom_mutex = osip_mutex_init();
4778        osip_list_init(&ph_custom_headers);
4779
4780        ph_hdrmon_mutex = osip_mutex_init();
4781        osip_list_init(&ph_hdrmon_list);
4782
4783
4784
4785        if (asyncmode)
4786                phapithread = osip_thread_create(20000, ph_api_thread, (void*)0);
4787
4788        phIsInitialized = 1;
4789
4790        return 0;
4791}
4792
4793PHAPI_EXPORT int
4794phAudioCaptureCardList(ph_audio_card_desc_t** device_tab)
4795{
4796        if (!phIsInitialized)
4797                return -PH_NOTINIT;
4798
4799        return phms_audio_get_capture_sndcard_list(device_tab);
4800}
4801
4802PHAPI_EXPORT int
4803phAudioPlaybackCardList(ph_audio_card_desc_t** device_tab)
4804{
4805        if (!phIsInitialized)
4806                return -PH_NOTINIT;
4807
4808        return phms_audio_get_playback_sndcard_list(device_tab);
4809}
4810
4811PHAPI_EXPORT int
4812phVideoWebcamList(ph_video_web_cam_desc_t** device_tab)
4813{
4814        if (!phIsInitialized)
4815                return -PH_NOTINIT;
4816#ifdef PHAPI_VIDEO_SUPPORT     
4817        return phms_video_get_web_cam_list(device_tab);
4818#else
4819        return 0;
4820#endif
4821}
4822
4823#if 0
4824int phTunnelConfig(const char* http_proxy, const int http_proxy_port,
4825                const char* httpt_server, const int httpt_server_port,
4826                const char *proxy_user, const char* proxy_passwd,
4827                int use_ssl, int autoconf)
4828{
4829        if (!phIsInitialized)
4830                return -PH_NOTINIT;
4831
4832        phcfg.httpt_server[0] = 0;
4833        phcfg.http_proxy[0] = 0;
4834        phcfg.use_tunnel = 0;
4835
4836        if (!httpt_server) {
4837                return -1;
4838        }
4839
4840        phcfg.http_proxy_port = http_proxy_port;
4841        if (!httpt_server_port)
4842                if (!http_proxy) {
4843                        phcfg.httpt_server_port = 80;
4844                }
4845                else {
4846                        phcfg.httpt_server_port = 443;
4847                }
4848        else
4849                phcfg.httpt_server_port = httpt_server_port;
4850
4851        if (httpt_server)
4852                osip_strncpy(phcfg.httpt_server, httpt_server, sizeof(phcfg.httpt_server)-1);
4853        if (http_proxy)
4854                osip_strncpy(phcfg.http_proxy, http_proxy, sizeof(phcfg.http_proxy)-1);
4855
4856        if (proxy_user)
4857                osip_strncpy(phcfg.http_proxy_user, proxy_user, sizeof(phcfg.http_proxy_user)-1);
4858        if (proxy_passwd)
4859                osip_strncpy(phcfg.http_proxy_passwd, proxy_passwd, sizeof(phcfg.http_proxy_passwd)-1);
4860
4861        phcfg.use_tunnel = PH_TUNNEL_USE;
4862        if (use_ssl)
4863                phcfg.use_tunnel |= PH_TUNNEL_SSL;
4864
4865        if (autoconf)
4866                phcfg.use_tunnel |= PH_TUNNEL_AUTOCONF;
4867        return 0;
4868}
4869#endif
4870
4871int phTunnelConfig2(const char* sip_tunnel_uris,  const char *rtp_tunnel_uris, const char  *http_proxy,
4872                                                                const char *proxy_user, const char* proxy_passwd)
4873{
4874        if (sip_tunnel_uris)
4875                osip_strncpy(phcfg.sip_tunnel_uris, sip_tunnel_uris, sizeof(phcfg.sip_tunnel_uris)-1 );
4876
4877
4878        if (rtp_tunnel_uris)
4879                osip_strncpy(phcfg.rtp_tunnel_uris, rtp_tunnel_uris, sizeof(phcfg.rtp_tunnel_uris)-1 );
4880
4881
4882        if (http_proxy)
4883                osip_strncpy(phcfg.http_proxy, http_proxy, sizeof(phcfg.http_proxy)-1);
4884
4885        if (proxy_user)
4886                osip_strncpy(phcfg.http_proxy_user, proxy_user, sizeof(phcfg.http_proxy_user)-1);
4887
4888        if (proxy_passwd)
4889                osip_strncpy(phcfg.http_proxy_passwd, proxy_passwd, sizeof(phcfg.http_proxy_passwd)-1);
4890
4891        phcfg.use_tunnel = PH_TUNNEL_USE;
4892
4893}
4894
4895
4896static void ph_payload_cleanup()
4897{
4898        if (osip_list_size(&ph_audio_payloads) > 0)
4899                osip_list_special_free(&ph_audio_payloads, sdp_payload_free);
4900        if (osip_list_size(&ph_video_payloads) > 0)
4901                osip_list_special_free(&ph_video_payloads, sdp_payload_free);
4902}
4903
4904/**
4905 * terminate ph api
4906 */
4907PHAPI_EXPORT void
4908phTerminate()
4909{
4910        int i;
4911
4912        DBG_SIP_EVENT("SIP NEGO: phTerminate\n");
4913        if (!phIsInitialized)
4914                return;
4915
4916        for(i = 0; i < PH_MAX_CALLS; i++)
4917                if (ph_calls[i].cid != -1)
4918                        ph_release_call(&ph_calls[i]);
4919
4920        for(i = 0; i < PH_MAX_VLINES; i++)
4921        {
4922                phDelVline(i+1);
4923        }
4924
4925        usleep(200000);
4926
4927        phPoll();
4928
4929        phIsInitialized = 0;
4930
4931        if (phapithread != NULL) {
4932                i = osip_thread_join((struct osip_thread *) phapithread);
4933                if (i != 0) {
4934                        OSIP_TRACE(osip_trace
4935                                        (__FILE__, __LINE__, OSIP_ERROR, NULL,
4936                                                        "phapithread: can't terminate thread!\n"));
4937                }
4938                osip_free(phapithread);
4939                phapithread = 0;
4940        }
4941        eXosip_quit();
4942
4943
4944        for(i = 0; i < PH_MAX_VLINES; i++)
4945        {
4946                struct vline *vl = ph_vlid2vline(i+1);
4947                if (vl)
4948                        vline_free(vl);
4949        }
4950
4951
4952#ifdef USE_HTTP_TUNNEL
4953        if (phTunnel)
4954        {
4955                http_tunnel_close(phTunnel->h_tunnel);
4956                http_tunnel_clean_up();
4957                free(phTunnel);
4958                phTunnel = 0;
4959        }
4960#endif
4961
4962        ph_media_cleanup();
4963        ph_payload_cleanup();
4964
4965        osip_mutex_destroy(ph_media_start_mutex);
4966        osip_mutex_destroy(ph_custom_mutex);
4967
4968
4969        if (phLogFileName && phDebugLevel > 0)
4970                fclose(ph_log_file);
4971        if (phDebugLevel > 0)
4972                for (i = 0; i <= phDebugLevel && i < END_TRACE_LEVEL; ++i)
4973                        TRACE_DISABLE_LEVEL(i);
4974
4975        if (phLogFileName)
4976                free(phLogFileName);
4977
4978        phLogFileName = 0;
4979
4980}
4981
4982
4983
4984/**
4985 * poll for phApi events.c
4986 */
4987PHAPI_EXPORT int
4988phPoll()
4989{
4990
4991        if (!phIsInitialized)
4992                return -PH_NOTINIT;
4993
4994        if (!phcfg.asyncmode)
4995        {
4996                if (ph_event_get() == -2)
4997                        return -2;
4998
4999                ph_keep_refreshing();
5000        }
5001        return 0;
5002}
5003
5004
5005
5006void ph_refer_notify(int did, int status, const char* msg, int final)
5007{
5008        char  statusmsg[128];
5009        osip_message_t *notify = 0;
5010        int i;
5011
5012        snprintf(statusmsg, sizeof(statusmsg), "SIP/2.0 %d %s", status, msg);
5013
5014        eXosip_lock();
5015
5016        i = eXosip_call_build_notify(did, final ? EXOSIP_SUBCRSTATE_TERMINATED : EXOSIP_SUBCRSTATE_ACTIVE, &notify);
5017        if (i)
5018                goto err;
5019
5020        osip_message_set_body(notify, statusmsg, strlen(statusmsg));
5021        osip_message_set_content_type(notify, "message/sipfrag");
5022
5023        i = eXosip_call_send_request(did, notify);
5024
5025        err:
5026        eXosip_unlock();
5027        if (i && (notify != 0))
5028                osip_message_free(notify);
5029
5030
5031}
5032char * ph_get_fixed_payload_name(int idx)
5033{
5034        if( idx == 0 )
5035                return "PCMU";
5036        else if( idx == 8 )
5037                return "PCMA";
5038        else if( idx == 9 )
5039                return "G722";
5040        else if( idx == 18 )
5041                return "G729";
5042        else if( idx == 34 )
5043                return "H263";
5044
5045        return NULL;
5046}
5047
5048static int
5049ph_call_retrieve_payloads(phcall_t *ca, int flags)
5050{
5051        int  i = 0;
5052
5053        DBG_SIP_NEGO("looking for payloads...\n");
5054        DBG_SIP_NEGO("audio...\n");
5055        if (_is_audio_enabled(flags))
5056        {
5057                const sdp_payload_t *cur_payload;
5058
5059                if (osip_list_size(&ca->result_audio_payloads) > 0)
5060                {
5061                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, 0);
5062                        ca->audio_payload = cur_payload->pt;
5063
5064                        if (cur_payload->a_rtpmap)
5065                                osip_strncpy(ca->audio_payload_name, cur_payload->a_rtpmap, sizeof(ca->audio_payload_name)-1);
5066                        else
5067                        {
5068                                char * payload_name = ph_get_fixed_payload_name(ca->audio_payload);
5069                                if(payload_name)
5070                                        osip_strncpy(ca->audio_payload_name, payload_name, sizeof(ca->audio_payload_name)-1);
5071                        }
5072
5073                        ca->remote_ptime = cur_payload->a_ptime;
5074                }
5075        }
5076
5077        DBG_SIP_NEGO("video...\n");
5078
5079        if ((_is_video_enabled(flags)))
5080        {
5081                const sdp_payload_t *cur_payload;
5082
5083                ca->video_payload = 0;
5084                if (osip_list_size(&ca->result_video_payloads) > 0)
5085                {
5086                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_video_payloads, 0);
5087                        ca->video_payload = cur_payload->pt;
5088                        if (cur_payload->a_rtpmap)
5089                                osip_strncpy(ca->video_payload_name, cur_payload->a_rtpmap, sizeof(ca->video_payload_name)-1);
5090                        else
5091                        {
5092                                char * payload_name = ph_get_fixed_payload_name(ca->audio_payload);
5093                                if(payload_name)
5094                                        osip_strncpy(ca->video_payload_name, payload_name, sizeof(ca->video_payload_name)-1);
5095                        }
5096
5097                        ca->remote_ptime = cur_payload->a_ptime;
5098                }
5099        }
5100
5101        DBG_SIP_NEGO("cng...\n");
5102        if(!i && phcfg.cng && (flags & PH_STREAM_CNG)) {
5103                // ca->cng = !eXosip_retrieve_negotiated_specific_payload(ca->did, PH_MEDIA_CN_PT_STR, strlen(PH_MEDIA_CN_PT_STR));
5104                // DBG_SIP_NEGO("cng: %d", ca->cng);
5105        }
5106        return i;
5107}
5108
5109
5110PHAPI_EXPORT int phCallGetCodecs(int cid, char *audioCodecBuf, int aBufLen, char *videoCodecBuf, int vBufLen)
5111{
5112        phcall_t *ca;
5113
5114        if (!phIsInitialized)
5115                return -PH_NOTINIT;
5116
5117        ca = ph_locate_call_by_cid(cid);
5118
5119        if (!ca)
5120                return -PH_BADCID;
5121
5122        if (audioCodecBuf)
5123                osip_strncpy(audioCodecBuf, ca->audio_payload_name, aBufLen-1);
5124
5125        if (videoCodecBuf)
5126                osip_strncpy(videoCodecBuf, ca->video_payload_name, vBufLen-1);
5127
5128        return 0;
5129
5130
5131}
5132
5133PHAPI_EXPORT int
5134phCallGetMediaInfo(int cid, struct ph_confirmed_media_info *mi)
5135{
5136        phcall_t *ca;
5137
5138        if (!phIsInitialized)
5139                return -PH_NOTINIT;
5140
5141        ca = ph_locate_call_by_cid(cid);
5142
5143        if (!ca)
5144                return -PH_BADCID;
5145
5146        mi->audio.localport = ca->loc_sdp_audio_port;
5147        mi->audio.remoteport = ca->remote_sdp_audio_port;
5148        osip_strncpy(mi->audio.remoteip, ca->remote_sdp_audio_ip, sizeof(mi->audio.remoteip-1));
5149        mi->video.localport = ca->loc_sdp_video_port;
5150        mi->video.remoteport = ca->remote_sdp_video_port;
5151        osip_strncpy(mi->video.remoteip, ca->remote_sdp_video_ip, sizeof(mi->video.remoteip)-1);
5152
5153        return 0;
5154
5155}
5156
5157static void
5158ph_parse_payload_mime(struct ph_media_payload_s *pt, const char *mime, int rate, int chans)
5159{
5160        const char *rp = 0;
5161        const char *cp = 0;
5162
5163        if (mime) {
5164            rp = strchr(mime, '/');
5165            strncpy(pt->string, mime, sizeof(pt->string));
5166        }
5167        pt->rate = rate;
5168        pt->chans = chans;
5169
5170
5171        if (!rp)
5172                return;
5173
5174        rp++;
5175        if (!*rp)
5176                return;
5177
5178        pt->rate = atol(rp);
5179
5180        cp = strchr(rp, '/');
5181        if (!cp)
5182                return;
5183
5184        cp++;
5185        if (!*cp)
5186                return;
5187
5188        pt->chans = atol(cp);
5189}
5190
5191
5192
5193static int
5194ph_call_media_stop(phcall_t *ca)
5195{
5196        DBG_SIP_NEGO("SIP_NEGO: ph_call_media_stop\n");
5197
5198        if (ca->mses)
5199        {
5200                if (ca->mses->refcnt == 1)
5201                {
5202                        if (!ca->audiodev_in)
5203                                ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5204                       
5205                        if (!ca->audiodev_out)
5206                                ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5207
5208                        if (!ph_msession_stopped(ca->mses))
5209                        {
5210                                ph_msession_stop(ca->mses, ca->audiodev_in, ca->audiodev_out,0);
5211                        }
5212                }
5213                ph_msession_free(ca->mses);
5214                ca->mses = 0;
5215        }
5216
5217        return 0;
5218
5219}
5220
5221static int
5222ph_call_media_suspend(phcall_t *ca, int localhold)
5223{
5224        if (ca->mses)
5225        {
5226                if (!ca->audiodev_in)
5227                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5228
5229                ph_msession_suspend(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in,  ca->audiodev_out);
5230        }
5231
5232        return 0;
5233}
5234
5235
5236static int
5237ph_call_media_resume(phcall_t *ca, int localhold)
5238{
5239        if (ca->mses)
5240        {
5241                if (!ca->audiodev_in)
5242                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5243               
5244                if (!ca->audiodev_out)
5245                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5246               
5247                ph_msession_resume(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in, ca->audiodev_out, 0);
5248        }
5249
5250        return 0;
5251}
5252
5253
5254
5255static
5256struct ph_msession_s *ph_msession_new()
5257{
5258        struct ph_msession_s *= (struct ph_msession_s *)calloc(sizeof(struct ph_msession_s), 1);
5259        s->critsec_mstream_init = osip_mutex_init();
5260        s->refcnt = 1;
5261        return s;
5262}
5263
5264
5265static
5266void ph_msession_use(struct ph_msession_s *s)
5267{
5268        if (s)
5269        {
5270                osip_mutex_lock(s->critsec_mstream_init);
5271                s->refcnt++;
5272                osip_mutex_unlock(s->critsec_mstream_init);
5273        }
5274}
5275
5276static
5277void ph_msession_free(struct ph_msession_s *s)
5278{
5279        if (s)
5280        {
5281                osip_mutex_lock(s->critsec_mstream_init);
5282                if (s->refcnt-- == 1)
5283                {
5284                        osip_mutex_unlock(s->critsec_mstream_init);
5285                        osip_mutex_destroy(s->critsec_mstream_init);
5286                        free(s);
5287                        return;
5288                }
5289                osip_mutex_unlock(s->critsec_mstream_init);
5290        }
5291}
5292
5293static int
5294ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag)
5295{
5296        int use_socket;
5297        int result = 0;
5298        struct ph_msession_s *s = NULL;
5299        const char* ptime = getenv("EXOSIP_FORCE_PTIME");
5300        if (!ptime || !*ptime)
5301                ptime = "20";
5302
5303        if (!ca)
5304                return -PH_BADARG;
5305
5306        // cases when the invocation is ignored
5307        if (phcfg.nomedia || ca->remotehold)
5308        {
5309                return 0;
5310        }
5311
5312        // we will work on the media sessions of the given phcall_t
5313        s = ca->mses;
5314
5315        osip_mutex_lock(ph_media_start_mutex);
5316
5317        // init the ph_msession_s for the call if the call doesn't have one yet
5318        if (!s)
5319        {
5320                s = ca->mses = ph_msession_new();
5321                if (!s)
5322                {
5323                        osip_mutex_unlock(ph_media_start_mutex);
5324                        return -PH_NORESOURCES;
5325                }
5326                s->confflags = 0;
5327                s->confsession = NULL;
5328                s->audio_conf = NULL;
5329                s->activestreams = 0;
5330                s->dtmfCallback = ph_wegot_dtmf;
5331                s->endCallback = ph_stream_ended;
5332                s->qosInfoCbk = ph_qos_info_cbk;
5333                s->frameDisplayCbk =  ph_frame_display_cbk;
5334        }
5335        else
5336        {
5337                if(resumeflag == 0)
5338                {
5339                        if(s->activestreams)
5340                        {
5341                                osip_mutex_lock(ph_media_stop_mutex);
5342                                ph_msession_stop(s, phcfg.audio_dev_in, phcfg.audio_dev_out, 0);
5343                                osip_mutex_unlock(ph_media_stop_mutex);
5344                        }
5345                        s->confflags = 0;
5346                        s->confsession = NULL;
5347                        s->audio_conf = NULL;
5348                        s->activestreams = 0;
5349                }
5350        }
5351        s->cbkInfo = ca;
5352
5353        // we need to understand what is required from the function call
5354        // by default, nothing to do
5355        s->newstreams = 0;
5356
5357        if ( _is_video_enabled(ca->nego_mflags) && ca->video_payload && ca->remote_sdp_video_ip[0] && osip_strcasecmp(ca->remote_sdp_video_ip, "0"))
5358        {
5359                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_VIDEO1];
5360                int ttype;
5361
5362                // program activation of VIDEO1
5363                s->newstreams |= (1 << PH_MSTREAM_VIDEO1);
5364
5365                // define the traffic type of the stream
5366                ttype = _is_video_enabled(ca->nego_mflags);
5367                if (ttype == (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX))
5368                {
5369                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
5370                }
5371                else if (ttype == PH_STREAM_VIDEO_RX)
5372                {
5373                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
5374                }
5375                else if (ttype == PH_STREAM_VIDEO_TX)
5376                {
5377                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
5378                }
5379
5380                msp->localport = ca->loc_sdp_video_port;
5381                msp->remoteport = ca->remote_sdp_video_port;
5382                msp->remotertcpport = ca->remote_sdp_video_rtcp_port;
5383                osip_strncpy(msp->remoteaddr,
5384                                ca->remote_sdp_video_ip,
5385                                sizeof(msp->remoteaddr)-1);
5386               
5387                {
5388                        const sdp_payload_t *cur_payload;
5389                        int pos = osip_list_size(&ca->result_video_payloads);
5390                        int i = 0;
5391                       
5392                        for (; i < pos ; i++)
5393                        {
5394                                cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_video_payloads, i);
5395                               
5396                                msp->ipayloads[i].number = cur_payload->pt;
5397                                if(cur_payload->a_rtpmap)
5398                                        ph_parse_payload_mime(&msp->ipayloads[0], cur_payload->a_rtpmap, 90000, 1);
5399                                else
5400                                {
5401                                        char * payload_name = ph_get_fixed_payload_name(msp->ipayloads[i].number);
5402                                        if(payload_name)
5403                                                ph_parse_payload_mime(&msp->ipayloads[i], payload_name, 90000, 1);
5404                                }
5405                                msp->opayloads[i] = msp->ipayloads[i];
5406                                msp->opayloads[i].ptime = cur_payload->a_ptime;
5407                        }
5408                }
5409
5410                // define the video callback
5411               
5412
5413                // additional configuration for video
5414
5415                /* if(sdp_message_bandwidth_get(ca->remote_sdp,  ) && !phcfg.video_config.force_high_speed)
5416      {
5417      msp->video_quality = ph_get_quality_from_bitrate(ca->max_bandwidth);
5418      }
5419    else
5420    msp->video_quality = phcfg.video_config.video_line_configuration;*/
5421        }
5422
5423        if (_is_audio_enabled(ca->nego_mflags) && ca->remote_sdp_audio_ip[0] && osip_strcasecmp(ca->remote_sdp_audio_ip, "0"))
5424        {
5425                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
5426                int ttype = 0;
5427
5428                //TODO uncomment it after the work un payloads
5429                /*if(!strncmp(ca->audio_payload_name, "GSM", 3))
5430                {
5431                        if(30 == atoi(ptime))
5432                        {
5433                                // for GSM reset ptime to 20ms
5434                                ptime = "20";
5435                        }
5436                }*/
5437                // Set to this stream the correct ptime negociated in the SDP
5438                // If there is no ptime negociated, use the default value (20 ms)
5439                //msp->ptime = (ca && ca->ptime > 0 ? ca->ptime : atoi(ptime));
5440                msp->ptime = atoi(ptime);
5441
5442                // program activation of AUDIO1
5443                s->newstreams |= (1 << PH_MSTREAM_AUDIO1);
5444
5445                if (phcfg.vad & 0x80000000)
5446                {
5447                        msp->flags |= PH_MSTREAM_FLAG_VAD;
5448                        msp->vadthreshold = phcfg.vad & 0x7fff;
5449                }
5450
5451                if (phcfg.cng)
5452                {
5453                        msp->flags |= PH_MSTREAM_FLAG_CNG;
5454                }
5455
5456                msp->jitter = phcfg.jitterdepth;
5457
5458                if (!phcfg.noaec)
5459                {
5460                        msp->flags |= PH_MSTREAM_FLAG_AEC;
5461                }
5462
5463                ttype = _is_audio_enabled(ca->nego_mflags);
5464                if (ttype == (PH_STREAM_AUDIO_RX | PH_STREAM_AUDIO_TX))
5465                {
5466                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
5467                }
5468                else if (ttype == PH_STREAM_AUDIO_RX)
5469                {
5470                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
5471                }
5472                else if (ttype == PH_STREAM_AUDIO_TX)
5473                {
5474                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
5475                }
5476               
5477                msp->localport = ca->loc_sdp_audio_port;
5478
5479                msp->remoteport = ca->remote_sdp_audio_port;
5480                msp->remotertcpport = ca->remote_sdp_audio_rtcp_port;
5481                use_socket = 0;
5482                msp->rtcptr = ca->audio_rtcptr;
5483                msp->rtptr = ca->audio_rtptr;
5484
5485                osip_strncpy(msp->remoteaddr,
5486                                ca->remote_sdp_audio_ip,
5487                                sizeof(msp->remoteaddr)-1);
5488
5489                // SPIKE_HDX
5490                if (phcfg.hdxmode == PH_HDX_MODE_MIC)
5491                {
5492                        msp->flags |= PH_MSTREAM_FLAG_MICHDX;
5493                        msp->vadthreshold = phcfg.vad & 0x7fff;
5494                }
5495
5496                if (phcfg.hdxmode == PH_HDX_MODE_SPK)
5497                {
5498                        msp->flags |= PH_MSTREAM_FLAG_SPKHDX;
5499                        msp->vadthreshold = phcfg.vad & 0x7fff;
5500                }
5501
5502                {
5503                        const sdp_payload_t *cur_payload;
5504                        int pos = osip_list_size(&ca->result_audio_payloads);
5505                        int i = 0;
5506
5507                        for (; i < pos ; i++)
5508                        {
5509                                cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, i);
5510
5511                                msp->ipayloads[i].number = cur_payload->pt;
5512                                if(cur_payload->a_rtpmap)
5513                                        ph_parse_payload_mime(&msp->ipayloads[i], cur_payload->a_rtpmap, 8000, 1);
5514                                else
5515                                {
5516                                        char * payload_name = ph_get_fixed_payload_name(msp->ipayloads[i].number);
5517                                        if(payload_name)
5518                                                ph_parse_payload_mime(&msp->ipayloads[i], payload_name, 8000, 1);
5519                                }
5520                                if (!strcasecmp(msp->ipayloads[i].string, "g722"))
5521                                        msp->ipayloads[i].rate = 16000;
5522                                msp->opayloads[i] = msp->ipayloads[i];
5523                                msp->opayloads[i].ptime = cur_payload->a_ptime;
5524                        }
5525                }
5526
5527        } // end        if ( // audio is enabled
5528
5529        // take action depending on the streaming configuration
5530        if (s->newstreams || s->activestreams)
5531        {
5532                if (ph_msession_start(s, ca->audiodev_in, ca->audiodev_out, use_socket))
5533                {
5534                        DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_start\n");
5535                        result = -PH_NOMEDIA;
5536                }
5537        }
5538        else
5539        {
5540                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: nothing to start\n");
5541                result = -PH_NOMEDIA;
5542        }
5543
5544        osip_mutex_unlock(ph_media_start_mutex);
5545
5546        return result;
5547}
5548
5549static char *
5550ph_req_get_from(osip_message_t *msg);
5551
5552
5553
5554
5555void
5556ph_call_new(eXosip_event_t *je)
5557{
5558        phCallStateInfo_t info;
5559        phcall_t *ca;
5560        struct vline *vl;
5561        char *localUri = NULL, *remoteUri= NULL, *sdp = NULL;
5562        int i;
5563
5564        clear(info);
5565        if (ph_busyFlag)
5566        {
5567                ph_answer_request(je->cid, je->tid, 486, 0);
5568                goto done;
5569        }
5570
5571        if (ph_follow_me_addr[0])
5572        {
5573                ph_answer_request(je->cid, je->tid, 302, ph_follow_me_addr);
5574                goto done;
5575        }
5576        osip_uri_to_str(je->request->req_uri, &localUri);
5577        osip_uri_to_str(osip_from_get_url(je->request->from), &remoteUri);
5578        info.vlid = ph_get_vline_id(localUri, NULL);
5579
5580        if (!info.vlid)
5581        {
5582                ph_answer_request(je->cid, je->tid, 404, 0);
5583                goto done;
5584        }
5585
5586        vl = ph_vlid2vline(info.vlid);
5587
5588        assert(vl!=NULL);
5589
5590        ca = ph_locate_call(je, 1);
5591        if (ca)
5592        {
5593                if (vl->busy)
5594                {
5595                        ph_answer_request(je->cid, je->tid, 486, vl->contact);
5596                        goto done;
5597                }
5598
5599                if (vl->followme && vl->followme[0])
5600                {
5601                        ph_answer_request(je->cid, je->tid, 302, vl->followme);
5602                        goto done;
5603                }
5604
5605                ca->vlid = info.vlid;
5606                ca->state = PH_CALLEE_RECEIVED;
5607
5608                i = ph_build_cname(ca->cname, sizeof(ca->cname), vl);
5609
5610                if (i)
5611                {
5612                        ph_answer_request(je->cid, je->tid, 400, vl->contact);
5613                        goto done;
5614                }
5615
5616                if (phcfg.audio_dev_in) {
5617                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5618                }
5619               
5620                if (phcfg.audio_dev_out) {
5621                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5622                }
5623
5624                info.userData = je->external_reference;
5625                info.event = phINCALL;
5626                info.remoteUri = remoteUri;
5627                info.localUri = localUri;
5628                info.streams = ca->nego_mflags;
5629                info.callinfo = 0; //je->call_info;
5630
5631                info.remoteSdp = sdp = ph_req_get_body(je->response);
5632
5633                ph_apply_header_monitor(je->request, &info.hlist);
5634
5635                phcb->callProgress(ca->cid, &info);
5636done:
5637                if (remoteUri)
5638                        osip_free(remoteUri);
5639
5640                if (localUri)
5641                        osip_free(localUri);
5642
5643                if (sdp)
5644                        osip_free(sdp);
5645
5646                if (info.hlist.elems)
5647                        osip_free(info.hlist.elems);
5648
5649        }
5650}
5651
5652#define ph_req_get_status(x) osip_message_get_status_code(x)
5653
5654
5655static char *
5656ph_req_get_to(osip_message_t *msg)
5657{
5658        char *str = 0;
5659
5660        osip_to_to_str(msg->to, &str);
5661        return str;
5662}
5663
5664static char *
5665ph_req_get_from(osip_message_t *msg)
5666{
5667        char *str = 0;
5668
5669        osip_from_to_str(msg->from, &str);
5670        return str;
5671}
5672
5673static char *
5674ph_req_get_body(osip_message_t *msg)
5675{
5676        char *str = 0;
5677        osip_body_t *body;
5678        size_t len;
5679
5680
5681        body = osip_list_get(&msg->bodies, 0);
5682        if (!body)
5683                return 0;
5684
5685        osip_body_to_str(body, &str, &len);
5686        str[len] = 0;
5687        return str;
5688}
5689
5690static osip_header_t *
5691ph_req_find_header(osip_message_t *msg, const char *hname)
5692{
5693        osip_header_t *hdr = 0;
5694
5695        osip_message_header_get_byname(msg, hname, 0, &hdr);
5696        return hdr;
5697
5698}
5699
5700static char *
5701ph_req_get_event(osip_message_t *msg)
5702{
5703        osip_header_t *hdr = 0;
5704
5705        osip_message_header_get_byname(msg, "Event", 0, &hdr);
5706
5707        if (hdr)
5708                return osip_strdup(hdr->hvalue);
5709
5710        return 0;
5711}
5712
5713static int
5714sdp_cmp(struct sdp_message* m1, struct sdp_message* m2)
5715{
5716        char *s1, *s2;
5717        int ret = -1;
5718
5719        sdp_message_to_str(m1, &s1);
5720        sdp_message_to_str(m2, &s2);
5721
5722        if (s1 && s2)
5723                ret = strcmp(s1, s2);
5724
5725        osip_free(s2);
5726        osip_free(s1);
5727
5728        return ret;
5729
5730}
5731
5732
5733void
5734ph_call_answered(eXosip_event_t *je)
5735{
5736        phCallStateInfo_t info;
5737        phcall_t *ca, *rca=0;
5738        int rdid;
5739        char *from = 0, *to=0, *sdp = 0;
5740        osip_message_t *ack;
5741
5742        DBG_SIP_NEGO("SIP NEGO: ph_call_answered\n");
5743        clear(info);
5744
5745        ca = ph_locate_call(je, 0);
5746
5747        if (!ca)
5748                return;
5749
5750        rca = ph_locate_call_by_cid(ca->rcid);
5751
5752        info.remoteSdp = sdp = ph_req_get_body(je->response);
5753
5754        //if (!ca->localhold)
5755        {
5756                const int mflags =  -1 & ~(PH_STREAM_MCSEND|PH_STREAM_MCRECV);
5757
5758                if (sdp)
5759                {       
5760                        struct sdp_message* new_sdp;
5761
5762                        sdp_message_init(&new_sdp);
5763                        sdp_message_parse(new_sdp, sdp);
5764
5765                        if (ca->remote_sdp) {
5766                                if (!sdp_cmp(new_sdp, ca->remote_sdp)) {
5767                                        sdp_message_free(new_sdp);
5768                                        DBG_SIP_NEGO("ph_call_answered: same sdp\n")
5769                                        goto same_sdp;
5770                                }
5771                                else {
5772                                        DBG_SIP_NEGO("ph_call_answered: different sdp restarting streams\n");
5773                                }
5774                                sdp_message_free(ca->remote_sdp);
5775                        }
5776                        ph_call_media_stop(ca);
5777                        ca->remote_sdp = new_sdp;
5778                        ca->sdpctx->answer = ca->remote_sdp;
5779                        osip_list_special_free(&ca->result_audio_payloads, sdp_payload_free);
5780                        osip_list_special_free(&ca->result_video_payloads, sdp_payload_free);
5781                        sdp_context_process_answer(ca->sdpctx, ca->remote_sdp);
5782                        ph_call_retrieve_payloads(ca, -1);
5783       
5784                        ph_update_nego_mflags(ca,ph_get_media_direction(new_sdp,"audio"),ph_get_media_direction(new_sdp,"video"));
5785       
5786                        if (ph_call_media_start(ca, je, mflags, ca->localresume))
5787                        {
5788                                DBG_SIP_NEGO("SIP NEGO: ph_call_answered but without stream\n");
5789                        }
5790                }
5791        }
5792same_sdp:
5793        info.localUri = from = ph_req_get_from(je->response);
5794        info.userData = je->external_reference;
5795        if (ca->localhold)
5796        {
5797                info.event = phHOLDOK;
5798        }
5799        else if (ca->localresume)
5800        {
5801                info.event = phRESUMEOK;
5802                ca->localresume = 0;
5803        }
5804        else {
5805                info.event = phCALLOK;
5806        }
5807
5808        eXosip_lock();
5809        eXosip_call_build_ack(ca->did, &ack);
5810        eXosip_call_send_ack(ca->did, ack);
5811        eXosip_unlock();
5812
5813        info.remoteUri = to = ph_req_get_to(je->response);
5814        info.vlid = ca->vlid;
5815        if (rca)
5816        {
5817                info.oldcid = rca->cid;
5818                rdid = rca->rdid;
5819        }
5820
5821        info.streams = PH_STREAM_AUDIO;
5822        if (ca->video_payload)
5823        {
5824                info.streams |= PH_STREAM_VIDEO_RX;
5825        }
5826
5827        if (!ca->localrefer)
5828        {
5829                /*
5830                 * the call back can call phCloseCall(odlcid)...  but we have rdid in
5831                 * the local var
5832                 */
5833                ph_apply_header_monitor(je->response, &info.hlist);
5834                phcb->callProgress(ca->cid, &info);
5835        }
5836
5837        if (rca)
5838        {
5839                ph_refer_notify(rdid, ph_req_get_status(je->response), "OK", 1);
5840        }
5841
5842        if (sdp)
5843                osip_free(sdp);
5844
5845        if (to)
5846                osip_free(to);
5847
5848        if (from)
5849                osip_free(from);
5850
5851        if (info.hlist.elems)
5852                osip_free(info.hlist.elems);
5853
5854}
5855
5856
5857void
5858ph_call_proceeding(eXosip_event_t *je)
5859{
5860        phCallStateInfo_t info;
5861        phcall_t *ca, *rca=0;
5862        char *to = 0;
5863        int s = 0;
5864
5865        DBG_SIP_NEGO("SIP NEGO: ph_call_proceeding\n");
5866        clear(info);
5867
5868
5869        ca = ph_locate_call(je, 1);
5870        if (!ca)
5871                return;
5872
5873        rca = ph_locate_call_by_cid(ca->rcid);
5874
5875        if (ca && !ca->localrefer && !ca->localhold && !ca->localresume)
5876        {
5877                ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
5878                ph_call_media_start(ca, je, -1, 0);
5879
5880                info.userData = je->external_reference;
5881                info.event = phDIALING;
5882                info.remoteUri = to = ph_req_get_to(je->response);
5883                info.vlid = ca->vlid;
5884
5885                info.streams = ca->nego_mflags;
5886
5887                ph_apply_header_monitor(je->response, &info.hlist);
5888                phcb->callProgress(ca->cid, &info);
5889        }
5890
5891        if (rca)
5892        {
5893                ph_refer_notify(rca->rdid, s, "Proceeding", 0);
5894        }
5895
5896        if (to)
5897                free(to);
5898
5899        if (info.hlist.elems)
5900                osip_free(info.hlist.elems);
5901
5902
5903}
5904
5905void ph_callStopRinging(eXosip_event_t *je)
5906{
5907        phCallStateInfo_t info;
5908        phcall_t *ca;
5909        char *from = 0, *to = 0;
5910
5911        clear(info);
5912
5913        ca = ph_locate_call(je, 1);
5914        if (ca && ca->isringing)
5915        {
5916                ca->isringing = 0;
5917                info.event = phRINGandSTOP;
5918
5919                info.localUri = from = ph_req_get_from(je->request);
5920                info.userData = je->external_reference;
5921
5922                info.remoteUri = to = ph_req_get_to(je->request);
5923                info.vlid = ca->vlid;
5924
5925                phcb->callProgress(je->cid, &info);
5926        }
5927
5928        if (to)
5929                osip_free(to);
5930        if (from)
5931                osip_free(from);
5932
5933
5934}
5935
5936
5937//from osip_uri.c, Don't add the port number into the string
5938static int ph_uri_to_str(const osip_uri_t * url, char **dest)
5939{
5940        char *buf;
5941        size_t len;
5942        char *tmp;
5943        const char *scheme;
5944
5945        *dest = NULL;
5946        if (url == NULL)
5947                return OSIP_BADPARAMETER;
5948        if (url->host == NULL && url->string == NULL)
5949                return OSIP_BADPARAMETER;
5950        if (url->scheme == NULL && url->string != NULL)
5951                return OSIP_BADPARAMETER;
5952        if (url->string == NULL && url->scheme == NULL)
5953                scheme = "sip";                 /* default is sipurl */
5954        else
5955                scheme = url->scheme;
5956
5957        if (url->string != NULL) {
5958                buf = (char *) osip_malloc(strlen(scheme) + strlen(url->string) + 3);
5959                if (buf == NULL)
5960                        return OSIP_NOMEM;
5961                *dest = buf;
5962                sprintf(buf, "%s:", scheme);
5963                buf = buf + strlen(scheme) + 1;
5964                sprintf(buf, "%s", url->string);
5965                buf = buf + strlen(url->string);
5966                return OSIP_SUCCESS;
5967        }
5968
5969        len = strlen(scheme) + 1 + strlen(url->host) + 5;
5970        if (url->username != NULL)
5971                len = len + (strlen(url->username) * 3) + 1;    /* count escaped char */
5972        if (url->password != NULL)
5973                len = len + (strlen(url->password) * 3) + 1;
5974        if (url->port != NULL)
5975                len = len + strlen(url->port) + 3;
5976
5977        buf = (char *) osip_malloc(len);
5978        if (buf == NULL)
5979                return OSIP_NOMEM;
5980        tmp = buf;
5981
5982        sprintf(tmp, "%s:", scheme);
5983        tmp = tmp + strlen(tmp);
5984
5985        if (url->username != NULL) {
5986                char *tmp2 = __osip_uri_escape_userinfo(url->username);
5987
5988                sprintf(tmp, "%s", tmp2);
5989                osip_free(tmp2);
5990                tmp = tmp + strlen(tmp);
5991        }
5992        if (url->username != NULL) {    /* we add a '@' only when username is present... */
5993                sprintf(tmp, "@");
5994                tmp++;
5995        }
5996        if (strchr(url->host, ':') != NULL) {
5997                sprintf(tmp, "[%s]", url->host);
5998                tmp = tmp + strlen(tmp);
5999        } else {
6000                sprintf(tmp, "%s", url->host);
6001                tmp = tmp + strlen(tmp);
6002        }
6003
6004        *dest = buf;
6005        return OSIP_SUCCESS;
6006}
6007
6008
6009
6010void
6011ph_call_ringing(eXosip_event_t *je)
6012{
6013        int ret = 0;
6014        phCallStateInfo_t info;
6015        phcall_t *ca, *rca=0;
6016        char *from = 0, *to = 0;
6017        const int mflags =  -1 & ~(PH_STREAM_MCSEND|PH_STREAM_MCRECV);
6018        char *sdp = 0;
6019
6020        DBG_SIP_NEGO("SIP NEGO: ph_call_ringing\n");
6021
6022        clear(info);
6023
6024        ca = ph_locate_call(je, 1);
6025        if (!ca)
6026                return;
6027
6028        rca = ph_locate_call_by_cid(ca->rcid);
6029
6030        info.remoteSdp = sdp = ph_req_get_body(je->response);
6031
6032        if (!(ca->user_mflags & PH_NOEARLY_MEDIA) && 0 != sdp)
6033        {
6034                if (ca->remote_sdp) {
6035                        sdp_message_free(ca->remote_sdp);
6036                }
6037                sdp_message_init(&ca->remote_sdp);
6038                sdp_message_parse(ca->remote_sdp, sdp);
6039                ca->sdpctx->answer = ca->remote_sdp;
6040                sdp_context_process_answer(ca->sdpctx, ca->remote_sdp);
6041        }
6042
6043
6044        ph_call_retrieve_payloads(ca, -1);
6045
6046        ret = ph_call_media_start(ca, je, mflags, 0);
6047
6048//      ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
6049
6050//      ret = ph_call_media_start(ca, je, -1, 0);
6051
6052        info.event = phRINGING;
6053        if (ret == -PH_NOMEDIA && !ph_call_hasaudio(ca) && !ca->isringing) /*  no audio and softPhone is now not ringing and has no sound */
6054        {
6055                ca->isringing = 1;
6056                info.event = phRINGandSTART;
6057        }
6058        else if (ca->isringing )
6059        {
6060                ca->isringing = 0;
6061                info.event = phRINGandSTOP;
6062        }
6063
6064        info.localUri = from = ph_req_get_from(je->response);
6065        info.userData = je->external_reference;
6066
6067        info.remoteUri = to = ph_req_get_to(je->response);
6068        info.vlid = ca->vlid;
6069
6070        info.streams = ca->nego_mflags;
6071
6072        ph_apply_header_monitor(je->response, &info.hlist);
6073
6074        phcb->callProgress(je->cid, &info);
6075
6076        if (rca)
6077        {
6078                ph_refer_notify(rca->rdid, 180, "Ringing", 0);
6079        }
6080
6081        if (sdp)
6082                osip_free(sdp);
6083
6084        if (to)
6085                osip_free(to);
6086        if (from)
6087                osip_free(from);
6088
6089        if (info.hlist.elems)
6090                osip_free(info.hlist.elems);
6091}
6092
6093
6094static void
6095ph_call_requestfailure(eXosip_event_t *je)
6096{
6097        phCallStateInfo_t info;
6098        phcall_t *ca, *rca=0;
6099        int s = 0;
6100        char *from = 0, *to = 0;
6101
6102        DBG_SIP_NEGO("call invite failure\n");
6103
6104        clear(info);
6105
6106        ca = ph_locate_call(je, 0);
6107        if (!ca)
6108                return;
6109
6110        rca = ph_locate_call_by_cid(ca->rcid);
6111        info.vlid = ca->vlid;
6112
6113        if (je->response) {
6114                s = ph_req_get_status(je->response);
6115                if (s == 407 || s == 401)
6116                        return;
6117        }
6118
6119        ph_release_call(ca);
6120
6121        if (je->response) {
6122                info.localUri = from = ph_req_get_from(je->response);
6123        }
6124
6125        info.userData = je->external_reference;
6126        if (s == 486)
6127        {
6128                info.event = phCALLBUSY;
6129                info.remoteUri = to = ph_req_get_to(je->response);
6130        }
6131        else
6132        {
6133                info.event = phCALLERROR;
6134                info.errorCode = s;
6135        }
6136
6137        ph_apply_header_monitor(je->response, &info.hlist);
6138
6139        phcb->callProgress(je->cid, &info);
6140        if (rca)
6141        {
6142                ph_refer_notify(rca->rdid, s, s == 486 ? "Busy" : "Request failure", 1);
6143        }
6144
6145        if (to)
6146                osip_free(to);
6147        if (from)
6148                osip_free(from);
6149
6150        if (info.hlist.elems)
6151                osip_free(info.hlist.elems);
6152}
6153
6154
6155void
6156ph_call_serverfailure(eXosip_event_t *je)
6157{
6158        phCallStateInfo_t info;
6159        phcall_t *ca, *rca=0;
6160        char *from = 0, *to = 0;
6161        int s = 0;
6162
6163        clear(info);
6164
6165        ca = ph_locate_call(je, 0);
6166        if (ca)
6167        {
6168                rca = ph_locate_call_by_cid(ca->rcid);
6169                info.vlid = ca->vlid;
6170                ph_release_call(ca);
6171        }
6172
6173        if (je->response) {
6174                s = ph_req_get_status(je->response);
6175                info.localUri = from = ph_req_get_from(je->response);
6176        }
6177
6178        info.userData = je->external_reference;
6179        info.event = phCALLERROR;
6180        info.errorCode = s;
6181
6182        ph_apply_header_monitor(je->response, &info.hlist);
6183
6184        phcb->callProgress(je->cid, &info);
6185
6186        if (rca)
6187        {
6188                ph_refer_notify(rca->rdid, s, "Server failure", 1);
6189        }
6190
6191        if (to)
6192                osip_free(to);
6193        if (from)
6194                osip_free(from);
6195
6196        if (info.hlist.elems)
6197                osip_free(info.hlist.elems);
6198}
6199
6200void
6201ph_call_globalfailure(eXosip_event_t *je)
6202{
6203        phCallStateInfo_t info;
6204        phcall_t *ca, *rca=0;
6205        char *from = 0, *to = 0;
6206        int s = 0;
6207
6208        clear(info);
6209
6210        ca = ph_locate_call(je, 0);
6211        if (ca)
6212        {
6213                rca = ph_locate_call_by_cid(ca->rcid);
6214                info.vlid = ca->vlid;
6215                ph_release_call(ca);
6216        }
6217
6218        s = ph_req_get_status(je->response);
6219        info.userData = je->external_reference;
6220        info.localUri = from = ph_req_get_from(je->response);
6221
6222        if (s == 600)
6223        {
6224                info.event = phCALLBUSY;
6225                info.remoteUri = to = ph_req_get_to(je->response);
6226        }
6227        else
6228        {
6229                info.event = phCALLERROR;
6230                info.errorCode = s;
6231        }
6232
6233        ph_apply_header_monitor(je->request, &info.hlist);
6234
6235        phcb->callProgress(je->cid, &info);
6236
6237        if (rca)
6238        {
6239                ph_refer_notify(rca->rdid, s, "Global failure", 1);
6240        }
6241
6242        if (to)
6243                osip_free(to);
6244        if (from)
6245                osip_free(from);
6246
6247        if (info.hlist.elems)
6248                osip_free(info.hlist.elems);
6249}
6250
6251void
6252ph_call_noanswer(eXosip_event_t *je, int alloc)
6253{
6254        phCallStateInfo_t info;
6255        phcall_t *ca, *rca=0;
6256        char *from = 0, *to = 0;
6257
6258
6259        clear(info);
6260
6261        ca = ph_locate_call(je, alloc);
6262        if (ca)
6263        {
6264                rca = ph_locate_call_by_cid(ca->rcid);
6265                info.vlid = ca->vlid;
6266                ph_release_call(ca);
6267        }
6268
6269        if (!ca && !alloc)
6270                return;
6271
6272        info.userData = je->external_reference;
6273        info.event = phNOANSWER;
6274        //      info.remoteUri = to = ph_req_get_to(je->response);
6275        //      info.localUri = from = ph_req_get_to(je->response);
6276
6277        ph_apply_header_monitor(je->request, &info.hlist);
6278
6279        phcb->callProgress(je->cid, &info);
6280
6281        if (rca)
6282        {
6283                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "No answer", 1);
6284        }
6285
6286        if (to)
6287                osip_free(to);
6288        if (from)
6289                osip_free(from);
6290
6291        if (info.hlist.elems)
6292                osip_free(info.hlist.elems);
6293}
6294
6295void
6296ph_call_message_new(eXosip_event_t *je)
6297{
6298        int i;
6299        osip_message_t *msg;
6300        int status = 405;
6301
6302
6303        if (MSG_IS_OPTIONS(je->request))
6304                status = 200;
6305
6306        eXosip_lock();
6307        i = eXosip_call_build_answer(je->tid, status, &msg);
6308
6309        if (!i)
6310                i = eXosip_call_send_answer(je->tid, status, msg);
6311        eXosip_unlock();
6312
6313}
6314
6315void
6316ph_call_closed(eXosip_event_t *je)
6317{
6318        phCallStateInfo_t info;
6319        phcall_t *ca, *rca=0;
6320
6321        clear(info);
6322
6323        ca = ph_locate_call(je, 0);
6324        if (ca)
6325        {
6326                rca = ph_locate_call_by_cid(ca->rcid);
6327                info.vlid = ca->vlid;
6328
6329
6330                ph_release_call(ca);
6331
6332                info.userData = je->external_reference;
6333                info.event = phCALLCLOSED;
6334                info.errorCode = 0;
6335
6336                ph_apply_header_monitor(je->request, &info.hlist);
6337                phcb->callProgress(je->cid, &info);
6338        }
6339
6340        if (rca)
6341        {
6342                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "Closed", 1);
6343        }
6344
6345        if (info.hlist.elems)
6346                osip_free(info.hlist.elems);
6347}
6348
6349
6350void
6351ph_call_onhold(eXosip_event_t *je)
6352{
6353        phCallStateInfo_t info;
6354        phcall_t *ca;
6355
6356        DBG_SIP_NEGO("SIP_NEGO: ph_call_onhold\n");
6357
6358        clear(info);
6359
6360        ca = ph_locate_call(je, 0);
6361
6362        if (!ca)
6363                return;
6364
6365        info.vlid = ca->vlid;
6366        /*if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca))
6367        {
6368#ifndef MEDIA_SUSPEND
6369                ph_call_media_stop(ca);
6370#else
6371                ph_call_media_suspend(ca, 0);
6372#endif
6373        }*/
6374
6375        ca->remotehold = 1;
6376        info.userData = je->external_reference;
6377        info.event = phCALLHELD;
6378        phcb->callProgress(je->cid, &info);
6379}
6380
6381void
6382ph_call_offhold(eXosip_event_t *je)
6383{
6384        phCallStateInfo_t info;
6385        phcall_t *ca;
6386        int remotehold;
6387
6388        DBG_SIP_NEGO("SIP NEGO: ph_call_offhold\n");
6389
6390        ca = ph_locate_call(je, 0);
6391        if (!ca)
6392                return;
6393
6394        clear(info);
6395
6396        info.vlid = ca->vlid;
6397
6398        remotehold = ca->remotehold;
6399        ca->remotehold = 0;
6400
6401        /*if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) {
6402                ph_call_retrieve_payloads(ca, -1);
6403                ph_call_media_resume(ca, !remotehold);
6404        }*/
6405
6406        if (remotehold) {
6407                info.userData = je->external_reference;
6408                info.event = phCALLRESUMED;
6409                info.streams = ca->nego_mflags;
6410
6411                if (phcb->callProgress) {
6412                        phcb->callProgress(ca->cid, &info);
6413                }
6414        }
6415}
6416
6417#define keywordcmp(key,str)  strncmp(key,str,strlen(key))
6418
6419int ph_set_media_direction( sdp_message_t * sdp, const char *media_type, enum ph_direction direction)
6420{
6421        int mline =0;
6422       
6423        for (mline=0; !sdp_message_endof_media (sdp, mline); mline++) 
6424        {
6425                const char * mtype = sdp_message_m_media_get(sdp, mline);
6426                if(!osip_strcasecmp(media_type, mtype))
6427                {
6428                        const char * sdir = ph_get_str_direction(direction);
6429                        sdp_message_a_attribute_del(sdp, mline, "inactive");
6430                        sdp_message_a_attribute_del(sdp, mline, "sendonly");
6431                        sdp_message_a_attribute_del(sdp, mline, "sendrecv");
6432                        sdp_message_a_attribute_add(sdp, mline, osip_strdup(sdir), 0);
6433                       
6434                        return 0;
6435                }
6436        }
6437        return -1;
6438}
6439
6440enum ph_direction ph_get_local_media_direction( phcall_t *ca, const char * media_type)
6441{
6442        if(!osip_strcasecmp(media_type, "audio"))
6443        {
6444                if(ca->nego_mflags & PH_STREAM_AUDIO_TX &&  ca->nego_mflags & PH_STREAM_AUDIO_RX)
6445                        return sendrecv;
6446                if(ca->nego_mflags & PH_STREAM_AUDIO_TX)
6447                        return sendonly;
6448                if(ca->nego_mflags & PH_STREAM_AUDIO_RX)
6449                        return recvonly;
6450        }
6451        else if(!osip_strcasecmp(media_type, "video"))
6452        {
6453                if(ca->nego_mflags & PH_STREAM_VIDEO_TX && ca->nego_mflags & PH_STREAM_VIDEO_RX)
6454                        return sendrecv;
6455                if(ca->nego_mflags & PH_STREAM_VIDEO_TX)
6456                        return sendonly;
6457                if(ca->nego_mflags & PH_STREAM_VIDEO_RX)
6458                        return recvonly;
6459        }
6460       
6461        return inactive;
6462}
6463
6464enum ph_direction ph_get_media_direction( sdp_message_t * sdp, const char * media_type)
6465{
6466        int mline = 0;
6467        for (mline=0; !sdp_message_endof_media (sdp, mline); mline++) 
6468        {
6469                int i =0;
6470                sdp_attribute_t *attr;
6471                const char * mtype = sdp_message_m_media_get(sdp, mline);
6472                if(!osip_strcasecmp(media_type, mtype))
6473                {
6474                        for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++) 
6475                        {
6476                                if ( keywordcmp("sendrecv",attr->a_att_field) == 0 )
6477                                {
6478                                        return sendrecv;
6479                                }
6480                                else if( keywordcmp("sendonly",attr->a_att_field) == 0 )
6481                                {
6482                                        return sendonly;
6483                                }
6484                                else if( keywordcmp("recvonly",attr->a_att_field) == 0 )
6485                                {
6486                                        return recvonly;
6487                                }
6488                                else if( keywordcmp("inactive",attr->a_att_field) == 0 )
6489                                {
6490                                        return inactive;
6491                                }
6492                        }
6493                       
6494                        return sendrecv;
6495                }
6496        }
6497        return inactive;
6498}
6499
6500int ph_update_nego_mflags( phcall_t *ca, enum ph_direction remote_audio_direction, enum ph_direction remote_video_direction)
6501{
6502        switch(remote_audio_direction)
6503        {
6504                case sendrecv:
6505                        ca->nego_mflags |= PH_STREAM_AUDIO;
6506                break;
6507               
6508                case sendonly:
6509                        ca->nego_mflags &= ~PH_STREAM_AUDIO_TX;
6510                        //ca->nego_mflags |= PH_STREAM_AUDIO_RX;
6511                break;
6512               
6513                case recvonly:
6514                        ca->nego_mflags &= ~PH_STREAM_AUDIO_RX;
6515                        ca->nego_mflags |= PH_STREAM_AUDIO_TX;
6516                break;
6517               
6518                case inactive:
6519                        ca->nego_mflags &= ~PH_STREAM_AUDIO;
6520                break;
6521        }
6522       
6523        switch(remote_video_direction)
6524        {
6525                case sendrecv:
6526                        ca->nego_mflags |= PH_STREAM_VIDEO;
6527                break;
6528               
6529                case sendonly:
6530                        ca->nego_mflags &= ~PH_STREAM_VIDEO_TX;
6531                        //ca->nego_mflags |= PH_STREAM_VIDEO_RX;
6532                break;
6533               
6534                case recvonly:
6535                        ca->nego_mflags &= ~PH_STREAM_VIDEO_RX;
6536                        ca->nego_mflags |= PH_STREAM_VIDEO_TX;
6537                break;
6538               
6539                case inactive:
6540                        ca->nego_mflags &= ~PH_STREAM_VIDEO;
6541                break;
6542        }
6543       
6544        return 0;
6545}
6546
6547const char * ph_get_str_direction( enum ph_direction direction) 
6548{
6549        switch(direction)
6550        {
6551                case sendrecv:
6552                        return "sendrecv";
6553                break;
6554               
6555                case sendonly:
6556                        return "sendonly";
6557                break;
6558               
6559                case recvonly:
6560                        return "recvonly";
6561                break;
6562               
6563                case inactive:
6564                        return "inactive";
6565                break;
6566        }
6567       
6568        return "";
6569}
6570
6571int
6572ph_call_reinvite(eXosip_event_t *je)
6573{
6574        int i = 0;
6575        int isHeld = 0;
6576        int mline = 0;
6577        phcall_t *ca = 0;
6578        sdp_message_t * sdp = 0;
6579        struct vline *vl;
6580        osip_message_t *msg = 0;
6581        char *body = NULL;
6582        struct ph_msession_s * msession;
6583       
6584        ca = ph_locate_call(je, 0);
6585
6586        if (!ca)
6587                return -PH_BADCID;
6588               
6589        vl = ph_valid_vlid(ca->vlid);
6590
6591        if (!vl)
6592                return -PH_BADVLID;
6593               
6594        msession = ca->mses;
6595               
6596        sdp = eXosip_get_sdp_info(je->request);
6597               
6598        ca->sdpctx->offer = ca->remote_sdp = sdp;
6599       
6600        i = eXosip_call_build_answer(ca->tid, 200, &msg);
6601        if