source: verona/phapi/phapi.c @ 478:2516bd824db5

Last change on this file since 478:2516bd824db5 was 478:2516bd824db5, checked in by laurent <laurent@…>, 12 months ago

log callback for ios

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