source: verona/phapi/phapi.c @ 453:be77f63cf114

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

fixes for sendmessage3

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