source: verona/phapi/phapi.c @ 93:352243f5dc95

Last change on this file since 93:352243f5dc95 was 93:352243f5dc95, checked in by Nikita Kozlov <nikita@…>, 3 years ago

accepting NULL realm in phAddAuthInfos

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