source: verona/phapi/phapi.c @ 470:86bbffb6f40e

Last change on this file since 470:86bbffb6f40e was 470:86bbffb6f40e, checked in by Vadim Lebedev <vadim@…>, 13 months ago

fix calls to lineSubscribe2 and lineSubscribe3

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