]> sjero.net Git - linphone/blob - coreapi/sal_eXosip2.c
2ea0f9aff7303066f9433eb6dcbeb1a212cf647f
[linphone] / coreapi / sal_eXosip2.c
1 /*\r
2 linphone\r
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)\r
4 \r
5 This program is free software; you can redistribute it and/or\r
6 modify it under the terms of the GNU General Public License\r
7 as published by the Free Software Foundation; either version 2\r
8 of the License, or (at your option) any later version.\r
9 \r
10 This program is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 GNU General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU General Public License\r
16 along with this program; if not, write to the Free Software\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
18 */\r
19 #ifdef HAVE_CONFIG_H\r
20 #include "config.h"\r
21 #endif\r
22 \r
23 #include "sal_eXosip2.h"\r
24 #include "offeranswer.h"\r
25 \r
26 #ifdef ANDROID\r
27 // Necessary to make it linked\r
28 static void for_linker() { eXosip_transport_hook_register(NULL); }\r
29 #endif\r
30 static bool_t call_failure(Sal *sal, eXosip_event_t *ev);\r
31 \r
32 static void text_received(Sal *sal, eXosip_event_t *ev);\r
33 \r
34 static void masquerade_via(osip_message_t *msg, const char *ip, const char *port);\r
35 static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact);\r
36 static void update_contact_from_response(SalOp *op, osip_message_t *response);\r
37 \r
38 \r
39 void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){\r
40         void *data;\r
41         while(!osip_list_eol(l,0)) {\r
42                 data=osip_list_get(l,0);\r
43                 osip_list_remove(l,0);\r
44                 if (data) freefunc(data);\r
45         }\r
46 }\r
47 \r
48 void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){\r
49         if (eXosip_guess_localip(address_family,ip,iplen)<0){\r
50                 /*default to something */\r
51                 strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);\r
52                 ms_error("Could not find default routable ip address !");\r
53         }\r
54 }\r
55 \r
56 static SalOp * sal_find_call(Sal *sal, int cid){\r
57         const MSList *elem;\r
58         SalOp *op;\r
59         for(elem=sal->calls;elem!=NULL;elem=elem->next){\r
60                 op=(SalOp*)elem->data;\r
61                 if (op->cid==cid) return op;\r
62         }\r
63         return NULL;\r
64 }\r
65 \r
66 static void sal_add_call(Sal *sal, SalOp *op){\r
67         sal->calls=ms_list_append(sal->calls,op);\r
68 }\r
69 \r
70 static void sal_remove_call(Sal *sal, SalOp *op){\r
71         sal->calls=ms_list_remove(sal->calls, op);\r
72 }\r
73 \r
74 static SalOp * sal_find_register(Sal *sal, int rid){\r
75         const MSList *elem;\r
76         SalOp *op;\r
77         for(elem=sal->registers;elem!=NULL;elem=elem->next){\r
78                 op=(SalOp*)elem->data;\r
79                 if (op->rid==rid) return op;\r
80         }\r
81         return NULL;\r
82 }\r
83 \r
84 static void sal_add_register(Sal *sal, SalOp *op){\r
85         sal->registers=ms_list_append(sal->registers,op);\r
86 }\r
87 \r
88 static void sal_remove_register(Sal *sal, int rid){\r
89         MSList *elem;\r
90         SalOp *op;\r
91         for(elem=sal->registers;elem!=NULL;elem=elem->next){\r
92                 op=(SalOp*)elem->data;\r
93                 if (op->rid==rid) {\r
94                         sal->registers=ms_list_remove_link(sal->registers,elem);\r
95                         return;\r
96                 }\r
97         }\r
98 }\r
99 \r
100 static SalOp * sal_find_other(Sal *sal, osip_message_t *message){\r
101         const MSList *elem;\r
102         SalOp *op;\r
103         osip_call_id_t *callid=osip_message_get_call_id(message);\r
104         if (callid==NULL) {\r
105                 ms_error("There is no call-id in this message !");\r
106                 return NULL;\r
107         }\r
108         for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){\r
109                 op=(SalOp*)elem->data;\r
110                 if (osip_call_id_match(callid,op->call_id)==0) return op;\r
111         }\r
112         return NULL;\r
113 }\r
114 \r
115 void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){\r
116         osip_call_id_t *callid=osip_message_get_call_id(request);\r
117         if (callid==NULL) {\r
118                 ms_error("There is no call id in the request !");\r
119                 return;\r
120         }\r
121         osip_call_id_clone(callid,&op->call_id);\r
122         sal->other_transactions=ms_list_append(sal->other_transactions,op);\r
123 }\r
124 \r
125 static void sal_remove_other(Sal *sal, SalOp *op){\r
126         sal->other_transactions=ms_list_remove(sal->other_transactions,op);\r
127 }\r
128 \r
129 \r
130 static void sal_add_pending_auth(Sal *sal, SalOp *op){\r
131         sal->pending_auths=ms_list_append(sal->pending_auths,op);\r
132 }\r
133 \r
134 \r
135 static void sal_remove_pending_auth(Sal *sal, SalOp *op){\r
136         sal->pending_auths=ms_list_remove(sal->pending_auths,op);\r
137 }\r
138 \r
139 void sal_exosip_fix_route(SalOp *op){\r
140         if (sal_op_get_route(op)!=NULL){\r
141                 osip_route_t *rt=NULL;\r
142                 osip_uri_param_t *lr_param=NULL;\r
143                 \r
144                 osip_route_init(&rt);\r
145                 if (osip_route_parse(rt,sal_op_get_route(op))<0){\r
146                         ms_warning("Bad route  %s!",sal_op_get_route(op));\r
147                         sal_op_set_route(op,NULL);\r
148                 }else{\r
149                         /* check if the lr parameter is set , if not add it */\r
150                         osip_uri_uparam_get_byname(rt->url, "lr", &lr_param);\r
151                         if (lr_param==NULL){\r
152                                 char *tmproute;\r
153                                 osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);\r
154                                 osip_route_to_str(rt,&tmproute);\r
155                                 sal_op_set_route(op,tmproute);\r
156                                 osip_free(tmproute);\r
157                         }\r
158                 }\r
159                 osip_route_free(rt);\r
160         }\r
161 }\r
162 \r
163 SalOp * sal_op_new(Sal *sal){\r
164         SalOp *op=ms_new0(SalOp,1);\r
165         __sal_op_init(op,sal);\r
166         op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;\r
167         op->result=NULL;\r
168         op->supports_session_timers=FALSE;\r
169         op->sdp_offering=TRUE;\r
170         op->pending_auth=NULL;\r
171         op->sdp_answer=NULL;\r
172         op->reinvite=FALSE;\r
173         op->call_id=NULL;\r
174         op->replaces=NULL;\r
175         op->referred_by=NULL;\r
176         op->masquerade_via=FALSE;\r
177         op->auto_answer_asked=FALSE;\r
178         op->auth_info=NULL;\r
179         op->terminated=FALSE;\r
180         return op;\r
181 }\r
182 \r
183 bool_t sal_call_autoanswer_asked(SalOp *op)\r
184 {\r
185         return op->auto_answer_asked;\r
186 }\r
187 \r
188 void sal_op_release(SalOp *op){\r
189         if (op->sdp_answer)\r
190                 sdp_message_free(op->sdp_answer);\r
191         if (op->pending_auth)\r
192                 eXosip_event_free(op->pending_auth);\r
193         if (op->rid!=-1){\r
194                 sal_remove_register(op->base.root,op->rid);\r
195                 eXosip_register_remove(op->rid);\r
196         }\r
197         if (op->cid!=-1){\r
198                 ms_message("Cleaning cid %i",op->cid);\r
199                 sal_remove_call(op->base.root,op);\r
200         }\r
201         if (op->sid!=-1){\r
202                 sal_remove_out_subscribe(op->base.root,op);\r
203         }\r
204         if (op->nid!=-1){\r
205                 sal_remove_in_subscribe(op->base.root,op);\r
206                 if (op->call_id)\r
207                         osip_call_id_free(op->call_id);\r
208                 op->call_id=NULL;\r
209         }\r
210         if (op->pending_auth){\r
211                 sal_remove_pending_auth(op->base.root,op);\r
212         }\r
213         if (op->result)\r
214                 sal_media_description_unref(op->result);\r
215         if (op->call_id){\r
216                 sal_remove_other(op->base.root,op);\r
217                 osip_call_id_free(op->call_id);\r
218         }\r
219         if (op->replaces){\r
220                 ms_free(op->replaces);\r
221         }\r
222         if (op->referred_by){\r
223                 ms_free(op->referred_by);\r
224         }\r
225         if (op->auth_info) {\r
226                 sal_auth_info_delete(op->auth_info);\r
227         }\r
228         __sal_op_free(op);\r
229 }\r
230 \r
231 static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){\r
232         int ortp_level=ORTP_DEBUG;\r
233         switch(level){\r
234                 case OSIP_INFO1:\r
235                 case OSIP_INFO2:\r
236                 case OSIP_INFO3:\r
237                 case OSIP_INFO4:\r
238                         ortp_level=ORTP_MESSAGE;\r
239                         break;\r
240                 case OSIP_WARNING:\r
241                         ortp_level=ORTP_WARNING;\r
242                         break;\r
243                 case OSIP_ERROR:\r
244                 case OSIP_BUG:\r
245                         ortp_level=ORTP_ERROR;\r
246                         break;\r
247                 case OSIP_FATAL:\r
248                         ortp_level=ORTP_FATAL;\r
249                         break;\r
250                 case END_TRACE_LEVEL:\r
251                         break;\r
252         }\r
253         if (ortp_log_level_enabled(level)){\r
254                 int len=strlen(chfr);\r
255                 char *chfrdup=ortp_strdup(chfr);\r
256                 /*need to remove endline*/\r
257                 if (len>1){\r
258                         if (chfrdup[len-1]=='\n')\r
259                                 chfrdup[len-1]='\0';\r
260                         if (chfrdup[len-2]=='\r')\r
261                                 chfrdup[len-2]='\0';\r
262                 }\r
263                 ortp_logv(ortp_level,chfrdup,ap);\r
264                 ortp_free(chfrdup);\r
265         }\r
266 }\r
267 \r
268 \r
269 Sal * sal_init(){\r
270         static bool_t firsttime=TRUE;\r
271         Sal *sal;\r
272         if (firsttime){\r
273                 osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func);\r
274                 firsttime=FALSE;\r
275         }\r
276         eXosip_init();\r
277         sal=ms_new0(Sal,1);\r
278         sal->keepalive_period=30;\r
279         sal->double_reg=TRUE;\r
280         sal->use_rports=TRUE;\r
281         sal->use_101=TRUE;\r
282         sal->reuse_authorization=FALSE;\r
283         sal->rootCa = 0;\r
284         sal->verify_server_certs=TRUE;\r
285         sal->verify_server_cn=TRUE;\r
286         sal->expire_old_contact=FALSE;\r
287         sal->add_dates=FALSE;\r
288         sal->dscp=-1;\r
289         return sal;\r
290 }\r
291 \r
292 void sal_uninit(Sal* sal){\r
293         eXosip_quit();\r
294         if (sal->rootCa)\r
295                 ms_free(sal->rootCa);\r
296         ms_free(sal);\r
297 }\r
298 \r
299 void sal_set_user_pointer(Sal *sal, void *user_data){\r
300         sal->up=user_data;\r
301 }\r
302 \r
303 void *sal_get_user_pointer(const Sal *sal){\r
304         return sal->up;\r
305 }\r
306 \r
307 static void unimplemented_stub(){\r
308         ms_warning("Unimplemented SAL callback");\r
309 }\r
310 \r
311 void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){\r
312         memcpy(&ctx->callbacks,cbs,sizeof(*cbs));\r
313         if (ctx->callbacks.call_received==NULL) \r
314                 ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub;\r
315         if (ctx->callbacks.call_ringing==NULL) \r
316                 ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub;\r
317         if (ctx->callbacks.call_accepted==NULL) \r
318                 ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub;\r
319         if (ctx->callbacks.call_failure==NULL) \r
320                 ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;\r
321         if (ctx->callbacks.call_terminated==NULL) \r
322                 ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;\r
323         if (ctx->callbacks.call_released==NULL)\r
324                 ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;\r
325         if (ctx->callbacks.call_updating==NULL) \r
326                 ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;\r
327         if (ctx->callbacks.auth_requested==NULL) \r
328                 ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;\r
329         if (ctx->callbacks.auth_success==NULL) \r
330                 ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub;\r
331         if (ctx->callbacks.register_success==NULL) \r
332                 ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub;\r
333         if (ctx->callbacks.register_failure==NULL) \r
334                 ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub;\r
335         if (ctx->callbacks.dtmf_received==NULL) \r
336                 ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub;\r
337         if (ctx->callbacks.notify==NULL)\r
338                 ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;\r
339         if (ctx->callbacks.notify_presence==NULL)\r
340                 ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;\r
341         if (ctx->callbacks.subscribe_received==NULL)\r
342                 ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;\r
343         if (ctx->callbacks.text_received==NULL)\r
344                 ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;\r
345         if (ctx->callbacks.ping_reply==NULL)\r
346                 ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;\r
347 }\r
348 \r
349 int sal_unlisten_ports(Sal *ctx){\r
350         if (ctx->running){\r
351                 eXosip_quit();\r
352                 eXosip_init();\r
353                 ctx->running=FALSE;\r
354         }\r
355         return 0;\r
356 }\r
357 \r
358 int sal_reset_transports(Sal *ctx){\r
359 #ifdef HAVE_EXOSIP_RESET_TRANSPORTS\r
360         if (ctx->running){\r
361                 ms_message("Exosip transports reset.");\r
362                 eXosip_reset_transports();\r
363         }\r
364         return 0;\r
365 #else\r
366         ms_warning("sal_reset_transports() not implemented in this version.");\r
367         return -1;\r
368 #endif\r
369 }\r
370 \r
371 \r
372 static void set_tls_options(Sal *ctx){\r
373         if (ctx->rootCa) {\r
374                 eXosip_tls_ctx_t tlsCtx;\r
375                 memset(&tlsCtx, 0, sizeof(tlsCtx));\r
376                 snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);\r
377                 eXosip_set_tls_ctx(&tlsCtx);\r
378         }                       \r
379 #ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE\r
380         eXosip_tls_verify_certificate(ctx->verify_server_certs);\r
381 #endif\r
382 #ifdef HAVE_EXOSIP_TLS_VERIFY_CN\r
383         eXosip_tls_verify_cn(ctx->verify_server_cn);\r
384 #endif\r
385 }\r
386 \r
387 void sal_set_dscp(Sal *ctx, int dscp){\r
388         ctx->dscp=dscp;\r
389 #ifdef HAVE_EXOSIP_DSCP\r
390         if (dscp!=-1)\r
391                 eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);\r
392 #endif\r
393 }\r
394 \r
395 int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){\r
396         int err;\r
397         bool_t ipv6;\r
398         int proto=IPPROTO_UDP;\r
399         int keepalive = ctx->keepalive_period;\r
400 \r
401         ctx->transport = tr;\r
402         switch (tr) {\r
403         case SalTransportUDP:\r
404                 proto=IPPROTO_UDP;\r
405                 eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive);\r
406                 break;\r
407         case SalTransportTCP:\r
408         case SalTransportTLS:\r
409                 proto= IPPROTO_TCP;\r
410                 if (!ctx->tcp_tls_keepalive) keepalive=-1;\r
411                 eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);\r
412                 set_tls_options(ctx);\r
413                 break;\r
414         default:\r
415                 ms_warning("unexpected proto, using datagram");\r
416         }\r
417         /*see if it looks like an IPv6 address*/\r
418         int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment\r
419         eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);\r
420         int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment\r
421         eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);\r
422         sal_set_dscp(ctx,ctx->dscp);\r
423         sal_use_dates(ctx,ctx->add_dates);\r
424 \r
425         ipv6=strchr(addr,':')!=NULL;\r
426         eXosip_enable_ipv6(ipv6);\r
427 \r
428         if (is_secure && tr == SalTransportUDP){\r
429                 ms_fatal("SIP over DTLS is not supported yet.");\r
430                 return -1;\r
431         }\r
432         err=eXosip_listen_addr(proto, addr, port, ipv6 ?  PF_INET6 : PF_INET, is_secure);\r
433         ctx->running=TRUE;\r
434         return err;\r
435 }\r
436 \r
437 ortp_socket_t sal_get_socket(Sal *ctx){\r
438 #ifdef HAVE_EXOSIP_GET_SOCKET\r
439         return eXosip_get_socket(IPPROTO_UDP);\r
440 #else\r
441         ms_warning("Sorry, eXosip does not have eXosip_get_socket() method");\r
442         return -1;\r
443 #endif\r
444 }\r
445 \r
446 void sal_set_user_agent(Sal *ctx, const char *user_agent){\r
447         eXosip_set_user_agent(user_agent);\r
448 }\r
449 \r
450 void sal_use_session_timers(Sal *ctx, int expires){\r
451         ctx->session_expires=expires;\r
452 }\r
453 \r
454 void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){\r
455         ctx->one_matching_codec=one_matching_codec;\r
456 }\r
457 \r
458 MSList *sal_get_pending_auths(Sal *sal){\r
459         return ms_list_copy(sal->pending_auths);\r
460 }\r
461 \r
462 void sal_use_double_registrations(Sal *ctx, bool_t enabled){\r
463         ctx->double_reg=enabled;\r
464 }\r
465 \r
466 void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){\r
467         ctx->expire_old_contact=enabled;\r
468 }\r
469 \r
470 void sal_use_dates(Sal *ctx, bool_t enabled){\r
471         ctx->add_dates=enabled;\r
472 #ifdef EXOSIP_OPT_REGISTER_WITH_DATE\r
473         {\r
474                 int tmp=enabled;\r
475                 eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);\r
476         }\r
477 #else\r
478         if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");\r
479 #endif\r
480 }\r
481 \r
482 void sal_use_rport(Sal *ctx, bool_t use_rports){\r
483         ctx->use_rports=use_rports;\r
484 }\r
485 void sal_use_101(Sal *ctx, bool_t use_101){\r
486         ctx->use_101=use_101;\r
487 }\r
488 \r
489 void sal_set_root_ca(Sal* ctx, const char* rootCa) {\r
490         if (ctx->rootCa)\r
491                 ms_free(ctx->rootCa);\r
492         ctx->rootCa = ms_strdup(rootCa);\r
493         set_tls_options(ctx);\r
494 }\r
495 \r
496 const char *sal_get_root_ca(Sal* ctx) {\r
497         return ctx->rootCa;\r
498 }\r
499 \r
500 void sal_verify_server_certificates(Sal *ctx, bool_t verify){\r
501         ctx->verify_server_certs=verify;\r
502 #ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE\r
503         eXosip_tls_verify_certificate(verify);\r
504 #endif\r
505 }\r
506 \r
507 void sal_verify_server_cn(Sal *ctx, bool_t verify){\r
508         ctx->verify_server_cn=verify;\r
509 #ifdef HAVE_EXOSIP_TLS_VERIFY_CN\r
510         eXosip_tls_verify_cn(verify);\r
511 #endif\r
512 }\r
513 \r
514 static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){\r
515         osip_via_t *via=NULL;\r
516         osip_generic_param_t *param=NULL;\r
517         const char *rport=NULL;\r
518 \r
519         *rportval=5060;\r
520         *received=NULL;\r
521         osip_message_get_via(msg,0,&via);\r
522         if (!via) {\r
523                 ms_warning("extract_received_rport(): no via.");\r
524                 return -1;\r
525         }\r
526 \r
527         *transport = sal_transport_parse(via->protocol);\r
528         \r
529         if (via->port && via->port[0]!='\0')\r
530                 *rportval=atoi(via->port);\r
531         \r
532         osip_via_param_get_byname(via,"rport",&param);\r
533         if (param) {\r
534                 rport=param->gvalue;\r
535                 if (rport && rport[0]!='\0') *rportval=atoi(rport);\r
536                 *received=via->host;\r
537         }\r
538         param=NULL;\r
539         osip_via_param_get_byname(via,"received",&param);\r
540         if (param) *received=param->gvalue;\r
541 \r
542         if (rport==NULL && *received==NULL){\r
543                 ms_warning("extract_received_rport(): no rport and no received parameters.");\r
544                 return -1;\r
545         }\r
546         return 0;\r
547 }\r
548 \r
549 static void set_sdp(osip_message_t *sip,sdp_message_t *msg){\r
550         int sdplen;\r
551         char clen[10];\r
552         char *sdp=NULL;\r
553         sdp_message_to_str(msg,&sdp);\r
554         sdplen=strlen(sdp);\r
555         snprintf(clen,sizeof(clen),"%i",sdplen);\r
556         osip_message_set_body(sip,sdp,sdplen);\r
557         osip_message_set_content_type(sip,"application/sdp");\r
558         osip_message_set_content_length(sip,clen);\r
559         osip_free(sdp);\r
560 }\r
561 \r
562 static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){\r
563         sdp_message_t *msg=media_description_to_sdp(desc);\r
564         if (msg==NULL) {\r
565                 ms_error("Fail to print sdp message !");\r
566                 return;\r
567         }\r
568         set_sdp(sip,msg);\r
569         sdp_message_free(msg);\r
570 }\r
571 \r
572 static void sdp_process(SalOp *h){\r
573         ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");\r
574         if (h->result){\r
575                 sal_media_description_unref(h->result);\r
576         }\r
577         h->result=sal_media_description_new();\r
578         if (h->sdp_offering){   \r
579                 offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);\r
580         }else{\r
581                 int i;\r
582                 if (h->sdp_answer){\r
583                         sdp_message_free(h->sdp_answer);\r
584                 }\r
585                 offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);\r
586                 h->sdp_answer=media_description_to_sdp(h->result);\r
587                 /*once we have generated the SDP answer, we modify the result description for processing by the upper layer.\r
588                  It should contains media parameters constraint from the remote offer, not our response*/\r
589                 strcpy(h->result->addr,h->base.remote_media->addr);\r
590                 h->result->bandwidth=h->base.remote_media->bandwidth;\r
591                 \r
592                 for(i=0;i<h->result->n_active_streams;++i){\r
593                         strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);\r
594                         strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);\r
595                         h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;\r
596                         h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;\r
597                         h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;\r
598                         h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;\r
599                         if (h->result->streams[i].proto == SalProtoRtpSavp) {\r
600                                 h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];\r
601                         }\r
602                 }\r
603         }\r
604         \r
605 }\r
606 \r
607 int sal_call_is_offerer(const SalOp *h){\r
608         return h->sdp_offering;\r
609 }\r
610 \r
611 int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){\r
612         if (desc)\r
613                 sal_media_description_ref(desc);\r
614         if (h->base.local_media)\r
615                 sal_media_description_unref(h->base.local_media);\r
616         h->base.local_media=desc;\r
617         if (h->base.remote_media){\r
618                 /*case of an incoming call where we modify the local capabilities between the time\r
619                  * the call is ringing and it is accepted (for example if you want to accept without video*/\r
620                 /*reset the sdp answer so that it is computed again*/\r
621                 if (h->sdp_answer){\r
622                         sdp_message_free(h->sdp_answer);\r
623                         h->sdp_answer=NULL;\r
624                 }\r
625         }\r
626         return 0;\r
627 }\r
628 \r
629 int sal_call(SalOp *h, const char *from, const char *to){\r
630         int err;\r
631         const char *route;\r
632         osip_message_t *invite=NULL;\r
633         osip_call_id_t *callid;\r
634         sal_op_set_from(h,from);\r
635         sal_op_set_to(h,to);\r
636         sal_exosip_fix_route(h);\r
637         \r
638         h->terminated = FALSE;\r
639 \r
640         route = sal_op_get_route(h);\r
641         err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call");\r
642         if (err!=0){\r
643                 ms_error("Could not create call. Error %d (from=%s to=%s route=%s)",\r
644                                 err, from, to, route);\r
645                 return -1;\r
646         }\r
647         osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");\r
648         if (h->base.contact){\r
649                 _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free);\r
650                 osip_message_set_contact(invite,h->base.contact);\r
651         }\r
652         if (h->base.root->session_expires!=0){\r
653                 osip_message_set_header(invite, "Session-expires", "200");\r
654                 osip_message_set_supported(invite, "timer");\r
655         }\r
656         sal_exosip_add_custom_headers(invite,h->base.custom_headers);\r
657         if (h->base.local_media){\r
658                 h->sdp_offering=TRUE;\r
659                 set_sdp_from_desc(invite,h->base.local_media);\r
660         }else h->sdp_offering=FALSE;\r
661         if (h->replaces){\r
662                 osip_message_set_header(invite,"Replaces",h->replaces);\r
663                 if (h->referred_by)\r
664                         osip_message_set_header(invite,"Referred-By",h->referred_by);\r
665         }\r
666         \r
667         eXosip_lock();\r
668         err=eXosip_call_send_initial_invite(invite);\r
669         eXosip_unlock();\r
670         h->cid=err;\r
671         if (err<0){\r
672                 ms_error("Fail to send invite ! Error code %d", err);\r
673                 return -1;\r
674         }else{\r
675                 char *tmp=NULL;\r
676                 callid=osip_message_get_call_id(invite);\r
677                 osip_call_id_to_str(callid,&tmp);\r
678                 h->base.call_id=ms_strdup(tmp);\r
679                 osip_free(tmp);\r
680                 sal_add_call(h->base.root,h);\r
681         }\r
682         return 0;\r
683 }\r
684 \r
685 int sal_call_notify_ringing(SalOp *h, bool_t early_media){\r
686         osip_message_t *msg;\r
687         \r
688         /*if early media send also 180 and 183 */\r
689         if (early_media){\r
690                 msg=NULL;\r
691                 eXosip_lock();\r
692                 eXosip_call_build_answer(h->tid,183,&msg);\r
693                 if (msg){\r
694                         sdp_process(h);\r
695                         if (h->sdp_answer){\r
696                                 set_sdp(msg,h->sdp_answer);\r
697                                 sdp_message_free(h->sdp_answer);\r
698                                 h->sdp_answer=NULL;\r
699                         }\r
700                         eXosip_call_send_answer(h->tid,183,msg);\r
701                 }\r
702                 eXosip_unlock();\r
703         }else{\r
704                 eXosip_lock();\r
705                 eXosip_call_send_answer(h->tid,180,NULL);\r
706                 eXosip_unlock();\r
707         }\r
708         return 0;\r
709 }\r
710 \r
711 int sal_call_accept(SalOp * h){\r
712         osip_message_t *msg;\r
713         const char *contact=sal_op_get_contact(h);\r
714         /* sends a 200 OK */\r
715         int err=eXosip_call_build_answer(h->tid,200,&msg);\r
716         if (err<0 || msg==NULL){\r
717                 ms_error("Fail to build answer for call: err=%i",err);\r
718                 return -1;\r
719         }\r
720         if (h->base.root->session_expires!=0){\r
721                 if (h->supports_session_timers) osip_message_set_supported(msg, "timer");\r
722         }\r
723 \r
724         if (contact) {\r
725                 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
726                 osip_message_set_contact(msg,contact);\r
727         }\r
728         \r
729         if (h->base.local_media){\r
730                 /*this is the case where we received an invite without SDP*/\r
731                 if (h->sdp_offering) {\r
732                         set_sdp_from_desc(msg,h->base.local_media);\r
733                 }else{\r
734                         if (h->sdp_answer==NULL) sdp_process(h);\r
735                         if (h->sdp_answer){\r
736                                 set_sdp(msg,h->sdp_answer);\r
737                                 sdp_message_free(h->sdp_answer);\r
738                                 h->sdp_answer=NULL;\r
739                         }\r
740                 }\r
741         }else{\r
742                 ms_error("You are accepting a call but not defined any media capabilities !");\r
743         }\r
744         eXosip_call_send_answer(h->tid,200,msg);\r
745         return 0;\r
746 }\r
747 \r
748 int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){\r
749         if (reason==SalReasonBusy){\r
750                 eXosip_lock();\r
751                 eXosip_call_send_answer(h->tid,486,NULL);\r
752                 eXosip_unlock();\r
753         }\r
754         else if (reason==SalReasonTemporarilyUnavailable){\r
755                 eXosip_lock();\r
756                 eXosip_call_send_answer(h->tid,480,NULL);\r
757                 eXosip_unlock();\r
758         }else if (reason==SalReasonDoNotDisturb){\r
759                 eXosip_lock();\r
760                 eXosip_call_send_answer(h->tid,600,NULL);\r
761                 eXosip_unlock();\r
762         }else if (reason==SalReasonMedia){\r
763                 eXosip_lock();\r
764                 eXosip_call_send_answer(h->tid,415,NULL);\r
765                 eXosip_unlock();\r
766         }else if (redirect!=NULL && reason==SalReasonRedirect){\r
767                 osip_message_t *msg;\r
768                 int code;\r
769                 if (strstr(redirect,"sip:")!=0) code=302;\r
770                 else code=380;\r
771                 eXosip_lock();\r
772                 eXosip_call_build_answer(h->tid,code,&msg);\r
773                 osip_message_set_contact(msg,redirect);\r
774                 eXosip_call_send_answer(h->tid,code,msg);\r
775                 eXosip_unlock();\r
776         }else sal_call_terminate(h);\r
777         return 0;\r
778 }\r
779 \r
780 SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){\r
781         return h->base.remote_media;\r
782 }\r
783 \r
784 SalMediaDescription * sal_call_get_final_media_description(SalOp *h){\r
785         if (h->base.local_media && h->base.remote_media && !h->result){\r
786                 sdp_process(h);\r
787         }\r
788         return h->result;\r
789 }\r
790 \r
791 int sal_call_set_referer(SalOp *h, SalOp *refered_call){\r
792         if (refered_call->replaces)\r
793                 h->replaces=ms_strdup(refered_call->replaces);\r
794         if (refered_call->referred_by)\r
795                 h->referred_by=ms_strdup(refered_call->referred_by);\r
796         return 0;\r
797 }\r
798 \r
799 static int send_notify_for_refer(int did, const char *sipfrag){\r
800         osip_message_t *msg;\r
801         eXosip_lock();\r
802         eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);\r
803         if (msg==NULL){\r
804                 eXosip_unlock();\r
805                 ms_warning("Could not build NOTIFY for refer.");\r
806                 return -1;\r
807         }\r
808         osip_message_set_content_type(msg,"message/sipfrag");\r
809         osip_message_set_header(msg,"Event","refer");\r
810         osip_message_set_body(msg,sipfrag,strlen(sipfrag));\r
811         eXosip_call_send_request(did,msg);\r
812         eXosip_unlock();\r
813         return 0;\r
814 }\r
815 \r
816 /* currently only support to notify trying and 200Ok*/\r
817 int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){\r
818         if (newcall==NULL){\r
819                 /* in progress*/\r
820                 send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");\r
821         }\r
822         else if (newcall->cid!=-1){\r
823                 if (newcall->did==-1){\r
824                         /* not yet established*/\r
825                         if (!newcall->terminated){\r
826                                 /* in progress*/\r
827                                 send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");\r
828                         }\r
829                 }else{\r
830                         if (!newcall->terminated){\r
831                                 if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){\r
832                                         /* we need previous notify transaction to complete, so buffer the request for later*/\r
833                                         h->sipfrag_pending="SIP/2.0 200 Ok\r\n";\r
834                                 }\r
835                         }\r
836                 }\r
837         }\r
838         return 0;\r
839 }\r
840 \r
841 int sal_ping(SalOp *op, const char *from, const char *to){\r
842         osip_message_t *options=NULL;\r
843         \r
844         sal_op_set_from(op,from);\r
845         sal_op_set_to(op,to);\r
846         sal_exosip_fix_route(op);\r
847 \r
848         eXosip_options_build_request (&options, sal_op_get_to(op),\r
849                         sal_op_get_from(op),sal_op_get_route(op));\r
850         if (options){\r
851                 if (op->base.root->session_expires!=0){\r
852                         osip_message_set_header(options, "Session-expires", "200");\r
853                         osip_message_set_supported(options, "timer");\r
854                 }\r
855                 sal_add_other(sal_op_get_sal(op),op,options);\r
856                 return eXosip_options_send_request(options);\r
857         }\r
858         return -1;\r
859 }\r
860 \r
861 int sal_call_refer(SalOp *h, const char *refer_to){\r
862         osip_message_t *msg=NULL;\r
863         int err=0;\r
864         eXosip_lock();\r
865         eXosip_call_build_refer(h->did,refer_to, &msg);\r
866         if (msg) err=eXosip_call_send_request(h->did, msg);\r
867         else err=-1;\r
868         eXosip_unlock();\r
869         return err;\r
870 }\r
871 \r
872 int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){\r
873         osip_message_t *msg=NULL;\r
874         char referto[256]={0};\r
875         int err=0;\r
876         eXosip_lock();\r
877         if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){\r
878                 ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);\r
879                 eXosip_unlock();\r
880                 return -1;\r
881         }\r
882         eXosip_call_build_refer(h->did,referto, &msg);\r
883         osip_message_set_header(msg,"Referred-By",h->base.from);\r
884         if (msg) err=eXosip_call_send_request(h->did, msg);\r
885         else err=-1;\r
886         eXosip_unlock();\r
887         return err;\r
888 }\r
889 \r
890 SalOp *sal_call_get_replaces(SalOp *h){\r
891         if (h!=NULL && h->replaces!=NULL){\r
892                 int cid;\r
893                 eXosip_lock();\r
894                 cid=eXosip_call_find_by_replaces(h->replaces);\r
895                 eXosip_unlock();\r
896                 if (cid>0){\r
897                         SalOp *ret=sal_find_call(h->base.root,cid);\r
898                         return ret;\r
899                 }\r
900         }\r
901         return NULL;\r
902 }\r
903 \r
904 int sal_call_send_dtmf(SalOp *h, char dtmf){\r
905         osip_message_t *msg=NULL;\r
906         char dtmf_body[128];\r
907         char clen[10];\r
908 \r
909         eXosip_lock();\r
910         eXosip_call_build_info(h->did,&msg);\r
911         if (msg){\r
912                 snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf);\r
913                 osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));\r
914                 osip_message_set_content_type(msg,"application/dtmf-relay");\r
915                 snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));\r
916                 osip_message_set_content_length(msg,clen);              \r
917                 eXosip_call_send_request(h->did,msg);\r
918         }\r
919         eXosip_unlock();\r
920         return 0;\r
921 }\r
922 \r
923 static void push_auth_to_exosip(const SalAuthInfo *info){\r
924         const char *userid;\r
925         if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;\r
926         else userid=info->userid;\r
927         ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm);\r
928         eXosip_add_authentication_info (info->username,userid,\r
929                                   info->password, NULL,info->realm);\r
930 }\r
931 /*\r
932  * Just for symmetry ;-)\r
933  */\r
934 static void pop_auth_from_exosip() {\r
935         eXosip_clear_authentication_info();\r
936 }\r
937 \r
938 int sal_call_terminate(SalOp *h){\r
939         int err;\r
940         if (h == NULL) return -1;\r
941         if (h->auth_info) push_auth_to_exosip(h->auth_info);\r
942         eXosip_lock();\r
943         err=eXosip_call_terminate(h->cid,h->did);\r
944         eXosip_unlock();\r
945         if (!h->base.root->reuse_authorization) pop_auth_from_exosip();\r
946         if (err!=0){\r
947                 ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);\r
948         }\r
949         h->terminated=TRUE;\r
950         return 0;\r
951 }\r
952 \r
953 void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){\r
954        bool_t terminating=FALSE;\r
955        if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) {\r
956                terminating=TRUE;\r
957        }\r
958        if (h->terminated && !terminating) return;\r
959 \r
960        if (h->pending_auth){\r
961                 push_auth_to_exosip(info);\r
962                 \r
963         /*FIXME exosip does not take into account this update register message*/\r
964         /*\r
965         if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) {\r
966             \r
967         };\r
968         */\r
969                 update_contact_from_response(h,h->pending_auth->response);\r
970                 eXosip_lock();\r
971                 eXosip_default_action(h->pending_auth);\r
972                 eXosip_unlock();\r
973                 ms_message("eXosip_default_action() done");\r
974                 if (!h->base.root->reuse_authorization) pop_auth_from_exosip();\r
975                 \r
976                 if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/\r
977                 h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/\r
978         }\r
979 }\r
980 void sal_op_cancel_authentication(SalOp *h) {\r
981         if (h->rid >0) {\r
982                 sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure");\r
983         } else if (h->cid >0) {\r
984                 sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);\r
985         } else {\r
986                 ms_warning("Auth failure not handled");\r
987         }\r
988 \r
989 }\r
990 static void set_network_origin(SalOp *op, osip_message_t *req){\r
991         const char *received=NULL;\r
992         int rport=5060;\r
993         char origin[64]={0};\r
994     SalTransport transport;\r
995         if (extract_received_rport(req,&received,&rport,&transport)!=0){\r
996                 osip_via_t *via=NULL;\r
997                 char *tmp;\r
998                 osip_message_get_via(req,0,&via);\r
999                 received=osip_via_get_host(via);\r
1000                 tmp=osip_via_get_port(via);\r
1001                 if (tmp) rport=atoi(tmp);\r
1002         }\r
1003     if (transport != SalTransportUDP) {\r
1004         snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport);\r
1005     } else {\r
1006        snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); \r
1007     }\r
1008         __sal_op_set_network_origin(op,origin);\r
1009 }\r
1010 \r
1011 static void set_remote_ua(SalOp* op, osip_message_t *req){\r
1012         if (op->base.remote_ua==NULL){\r
1013                 osip_header_t *h=NULL;\r
1014                 osip_message_get_user_agent(req,0,&h);\r
1015                 if (h){\r
1016                         op->base.remote_ua=ms_strdup(h->hvalue);\r
1017                 }\r
1018         }\r
1019 }\r
1020 \r
1021 static void set_remote_contact(SalOp* op, osip_message_t *req){\r
1022         if (op->base.remote_contact==NULL){\r
1023                 osip_contact_t *h=NULL;\r
1024                 osip_message_get_contact(req,0,&h);\r
1025                 if (h){\r
1026                         char *tmp=NULL;\r
1027                         osip_contact_to_str(h,&tmp);\r
1028                         __sal_op_set_remote_contact(op,tmp);\r
1029                         osip_free(tmp);\r
1030                 }\r
1031         }\r
1032 }\r
1033 \r
1034 static void set_replaces(SalOp *op, osip_message_t *req){\r
1035         osip_header_t *h=NULL;\r
1036 \r
1037         if (op->replaces){\r
1038                 ms_free(op->replaces);\r
1039                 op->replaces=NULL;\r
1040         }\r
1041         osip_message_header_get_byname(req,"replaces",0,&h);\r
1042         if (h){\r
1043                 if (h->hvalue && h->hvalue[0]!='\0'){\r
1044                         op->replaces=ms_strdup(h->hvalue);\r
1045                 }\r
1046         }\r
1047 }\r
1048 \r
1049 static SalOp *find_op(Sal *sal, eXosip_event_t *ev){\r
1050         if (ev->cid>0){\r
1051                 return sal_find_call(sal,ev->cid);\r
1052         }\r
1053         if (ev->rid>0){\r
1054                 return sal_find_register(sal,ev->rid);\r
1055         }\r
1056         if (ev->sid>0){\r
1057                 return sal_find_out_subscribe(sal,ev->sid);\r
1058         }\r
1059         if (ev->nid>0){\r
1060                 return sal_find_in_subscribe(sal,ev->nid);\r
1061         }\r
1062         if (ev->response) return sal_find_other(sal,ev->response);\r
1063         else if (ev->request) return sal_find_other(sal,ev->request);\r
1064         return NULL;\r
1065 }\r
1066 \r
1067 static void inc_new_call(Sal *sal, eXosip_event_t *ev){\r
1068         SalOp *op=sal_op_new(sal);\r
1069         osip_from_t *from,*to;\r
1070         osip_call_info_t *call_info;\r
1071         char *tmp=NULL;\r
1072         sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);\r
1073         \r
1074         osip_call_id_t *callid=osip_message_get_call_id(ev->request);\r
1075         \r
1076         osip_call_id_to_str(callid,&tmp);\r
1077         op->base.call_id=ms_strdup(tmp);\r
1078         osip_free(tmp);\r
1079         \r
1080         set_network_origin(op,ev->request);\r
1081         set_remote_contact(op,ev->request);\r
1082         set_remote_ua(op,ev->request);\r
1083         set_replaces(op,ev->request);\r
1084         sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));\r
1085         \r
1086         if (sdp){\r
1087                 op->sdp_offering=FALSE;\r
1088                 op->base.remote_media=sal_media_description_new();\r
1089                 sdp_to_media_description(sdp,op->base.remote_media);\r
1090                 sdp_message_free(sdp);\r
1091         }else op->sdp_offering=TRUE;\r
1092 \r
1093         from=osip_message_get_from(ev->request);\r
1094         to=osip_message_get_to(ev->request);\r
1095         osip_from_to_str(from,&tmp);\r
1096         sal_op_set_from(op,tmp);\r
1097         osip_free(tmp);\r
1098         osip_from_to_str(to,&tmp);\r
1099         sal_op_set_to(op,tmp);\r
1100         osip_free(tmp);\r
1101 \r
1102         osip_message_get_call_info(ev->request,0,&call_info);\r
1103         if(call_info)\r
1104         {\r
1105                 osip_call_info_to_str(call_info,&tmp);\r
1106                 if( strstr(tmp,"answer-after=") != NULL)\r
1107                 {\r
1108                         op->auto_answer_asked=TRUE;\r
1109                         ms_message("The caller asked to automatically answer the call(Emergency?)\n");\r
1110                 }\r
1111                 osip_free(tmp);\r
1112         }\r
1113 \r
1114         op->tid=ev->tid;\r
1115         op->cid=ev->cid;\r
1116         op->did=ev->did;\r
1117         sal_add_call(op->base.root,op);\r
1118         sal->callbacks.call_received(op);\r
1119 }\r
1120 \r
1121 static void handle_reinvite(Sal *sal,  eXosip_event_t *ev){\r
1122         SalOp *op=find_op(sal,ev);\r
1123         sdp_message_t *sdp;\r
1124 \r
1125         if (op==NULL) {\r
1126                 ms_warning("Reinvite for non-existing operation !");\r
1127                 return;\r
1128         }\r
1129         op->reinvite=TRUE;\r
1130         op->tid=ev->tid;\r
1131         sdp=eXosip_get_sdp_info(ev->request);\r
1132         if (op->base.remote_media){\r
1133                 sal_media_description_unref(op->base.remote_media);\r
1134                 op->base.remote_media=NULL;\r
1135         }\r
1136         if (op->result){\r
1137                 sal_media_description_unref(op->result);\r
1138                 op->result=NULL;\r
1139         }\r
1140         if (sdp){\r
1141                 op->sdp_offering=FALSE;\r
1142                 op->base.remote_media=sal_media_description_new();\r
1143                 sdp_to_media_description(sdp,op->base.remote_media);\r
1144                 sdp_message_free(sdp);\r
1145                 \r
1146         }else {\r
1147                 op->sdp_offering=TRUE;\r
1148         }\r
1149         sal->callbacks.call_updating(op);\r
1150 }\r
1151 \r
1152 static void handle_ack(Sal *sal,  eXosip_event_t *ev){\r
1153         SalOp *op=find_op(sal,ev);\r
1154         sdp_message_t *sdp;\r
1155 \r
1156         if (op==NULL) {\r
1157                 ms_warning("ack for non-existing call !");\r
1158                 return;\r
1159         }\r
1160         if (op->terminated) {\r
1161                 ms_warning("ack for terminated call, ignoring");\r
1162                 return;\r
1163         }\r
1164         \r
1165         if (op->sdp_offering){\r
1166                 sdp=eXosip_get_sdp_info(ev->ack);\r
1167                 if (sdp){\r
1168                         if (op->base.remote_media)\r
1169                                 sal_media_description_unref(op->base.remote_media);\r
1170                         op->base.remote_media=sal_media_description_new();\r
1171                         sdp_to_media_description(sdp,op->base.remote_media);\r
1172                         sdp_process(op);\r
1173                         sdp_message_free(sdp);\r
1174                 }\r
1175         }\r
1176         if (op->reinvite){\r
1177                 op->reinvite=FALSE;\r
1178         }\r
1179         sal->callbacks.call_ack(op);\r
1180 }\r
1181 \r
1182 static void update_contact_from_response(SalOp *op, osip_message_t *response){\r
1183         const char *received;\r
1184         int rport;\r
1185         SalTransport transport;\r
1186         if (extract_received_rport(response,&received,&rport,&transport)==0){\r
1187                 const char *contact=sal_op_get_contact(op);\r
1188                 if (!contact){\r
1189                         /*no contact given yet, use from instead*/\r
1190                         contact=sal_op_get_from(op);\r
1191                 }\r
1192                 if (contact){\r
1193                         SalAddress *addr=sal_address_new(contact);\r
1194                         char *tmp;\r
1195                         sal_address_set_domain(addr,received);\r
1196                         sal_address_set_port_int(addr,rport);\r
1197                         if (transport!=SalTransportUDP)\r
1198                                 sal_address_set_transport(addr,transport);\r
1199                         tmp=sal_address_as_string(addr);\r
1200                         ms_message("Contact address updated to %s",tmp);\r
1201                         sal_op_set_contact(op,tmp);\r
1202                         sal_address_destroy(addr);\r
1203                         ms_free(tmp);\r
1204                 }\r
1205         }\r
1206 }\r
1207 \r
1208 static int call_proceeding(Sal *sal, eXosip_event_t *ev){\r
1209         SalOp *op=find_op(sal,ev);\r
1210 \r
1211         if (op==NULL || op->terminated==TRUE) {\r
1212                 ms_warning("This call has been canceled.");\r
1213                 eXosip_lock();\r
1214                 eXosip_call_terminate(ev->cid,ev->did);\r
1215                 eXosip_unlock();\r
1216                 return -1;\r
1217         }\r
1218         if (ev->did>0)\r
1219                 op->did=ev->did;\r
1220         op->tid=ev->tid;\r
1221         \r
1222         /* update contact if received and rport are set by the server\r
1223          note: will only be used by remote for next INVITE, if any...*/\r
1224         update_contact_from_response(op,ev->response);\r
1225         return 0;\r
1226 }\r
1227 \r
1228 static void call_ringing(Sal *sal, eXosip_event_t *ev){\r
1229         sdp_message_t *sdp;\r
1230         SalOp *op=find_op(sal,ev);\r
1231         if (call_proceeding(sal, ev)==-1) return;\r
1232 \r
1233         set_remote_ua(op,ev->response);\r
1234         sdp=eXosip_get_sdp_info(ev->response);\r
1235         if (sdp){\r
1236                 op->base.remote_media=sal_media_description_new();\r
1237                 sdp_to_media_description(sdp,op->base.remote_media);\r
1238                 sdp_message_free(sdp);\r
1239                 if (op->base.local_media) sdp_process(op);\r
1240         }\r
1241         sal->callbacks.call_ringing(op);\r
1242 }\r
1243 \r
1244 static void call_accepted(Sal *sal, eXosip_event_t *ev){\r
1245         sdp_message_t *sdp;\r
1246         osip_message_t *msg=NULL;\r
1247         SalOp *op=find_op(sal,ev);\r
1248         const char *contact;\r
1249         \r
1250         if (op==NULL || op->terminated==TRUE) {\r
1251                 ms_warning("This call has been already terminated.");\r
1252                 eXosip_lock();\r
1253                 eXosip_call_terminate(ev->cid,ev->did);\r
1254                 eXosip_unlock();\r
1255                 return ;\r
1256         }\r
1257 \r
1258         op->did=ev->did;\r
1259         set_remote_ua(op,ev->response);\r
1260         set_remote_contact(op,ev->response);\r
1261 \r
1262         sdp=eXosip_get_sdp_info(ev->response);\r
1263         if (sdp){\r
1264                 op->base.remote_media=sal_media_description_new();\r
1265                 sdp_to_media_description(sdp,op->base.remote_media);\r
1266                 sdp_message_free(sdp);\r
1267                 if (op->base.local_media) sdp_process(op);\r
1268         }\r
1269         eXosip_call_build_ack(ev->did,&msg);\r
1270         if (msg==NULL) {\r
1271                 ms_warning("This call has been already terminated.");\r
1272                 eXosip_lock();\r
1273                 eXosip_call_terminate(ev->cid,ev->did);\r
1274                 eXosip_unlock();\r
1275                 return ;\r
1276         }\r
1277         contact=sal_op_get_contact(op);\r
1278         if (contact) {\r
1279                 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
1280                 osip_message_set_contact(msg,contact);\r
1281         }\r
1282         if (op->sdp_answer){\r
1283                 set_sdp(msg,op->sdp_answer);\r
1284                 sdp_message_free(op->sdp_answer);\r
1285                 op->sdp_answer=NULL;\r
1286         }\r
1287         eXosip_call_send_ack(ev->did,msg);\r
1288         sal->callbacks.call_accepted(op);\r
1289 }\r
1290 \r
1291 static void call_terminated(Sal *sal, eXosip_event_t *ev){\r
1292         char *from=NULL;\r
1293         SalOp *op=find_op(sal,ev);\r
1294         if (op==NULL){\r
1295                 ms_warning("Call terminated for already closed call ?");\r
1296                 return;\r
1297         }\r
1298         if (ev->request){\r
1299                 osip_from_to_str(ev->request->from,&from);\r
1300         }\r
1301         sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));\r
1302         if (from) osip_free(from);\r
1303         op->terminated=TRUE;\r
1304 }\r
1305 \r
1306 static void call_released(Sal *sal, eXosip_event_t *ev){\r
1307         SalOp *op=find_op(sal,ev);\r
1308         if (op==NULL){\r
1309                 ms_warning("No op associated to this call_released()");\r
1310                 return;\r
1311         }\r
1312         if (!op->terminated){\r
1313                 /* no response received so far */\r
1314                 call_failure(sal,ev);\r
1315         }\r
1316         sal->callbacks.call_released(op);\r
1317 }\r
1318 \r
1319 static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){\r
1320         const char *prx_realm=NULL,*www_realm=NULL;\r
1321         osip_proxy_authenticate_t *prx_auth;\r
1322         osip_www_authenticate_t *www_auth;\r
1323         \r
1324         *username=osip_uri_get_username(resp->from->url);\r
1325         prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0);\r
1326         www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0);\r
1327         if (prx_auth!=NULL)\r
1328                 prx_realm=osip_proxy_authenticate_get_realm(prx_auth);\r
1329         if (www_auth!=NULL)\r
1330                 www_realm=osip_www_authenticate_get_realm(www_auth);\r
1331 \r
1332         if (prx_realm){\r
1333                 *realm=prx_realm;\r
1334         }else if (www_realm){\r
1335                 *realm=www_realm;\r
1336         }else{\r
1337                 return -1;\r
1338         }\r
1339         return 0;\r
1340 }\r
1341 \r
1342 static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){\r
1343         osip_authorization_t *auth=NULL;\r
1344         osip_proxy_authorization_t *prx_auth=NULL;\r
1345         \r
1346         *username=osip_uri_get_username(msg->from->url);\r
1347         osip_message_get_authorization(msg, 0, &auth);\r
1348         if (auth){\r
1349                 *realm=osip_authorization_get_realm(auth);\r
1350                 return 0;\r
1351         }\r
1352         osip_message_get_proxy_authorization(msg,0,&prx_auth);\r
1353         if (prx_auth){\r
1354                 *realm=osip_proxy_authorization_get_realm(prx_auth);\r
1355                 return 0;\r
1356         }\r
1357         return -1;\r
1358 }\r
1359 \r
1360 static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){\r
1361         if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0;\r
1362         if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0;\r
1363         return -1;\r
1364 }\r
1365 \r
1366 int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){\r
1367         if (op->pending_auth){\r
1368                 return get_auth_data(op->pending_auth,realm,username);\r
1369         }\r
1370         return -1;\r
1371 }\r
1372 \r
1373 static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){\r
1374         SalOp *op;\r
1375         const char *username,*realm;\r
1376         op=find_op(sal,ev);\r
1377         if (op==NULL){\r
1378                 ms_warning("No operation associated with this authentication !");\r
1379                 return TRUE;\r
1380         }\r
1381         if (get_auth_data(ev,&realm,&username)==0){\r
1382                 if (op->pending_auth!=NULL){\r
1383                         eXosip_event_free(op->pending_auth);\r
1384                         op->pending_auth=ev;\r
1385                 }else{\r
1386                         op->pending_auth=ev;\r
1387                         sal_add_pending_auth(sal,op);\r
1388                 }\r
1389                 \r
1390                 sal->callbacks.auth_requested(op,realm,username);\r
1391                 return FALSE;\r
1392         }\r
1393         return TRUE;\r
1394 }\r
1395 \r
1396 static void authentication_ok(Sal *sal, eXosip_event_t *ev){\r
1397         SalOp *op;\r
1398         const char *username,*realm;\r
1399         op=find_op(sal,ev);\r
1400         if (op==NULL){\r
1401                 ms_warning("No operation associated with this authentication_ok!");\r
1402                 return ;\r
1403         }\r
1404         if (op->pending_auth){\r
1405                 eXosip_event_free(op->pending_auth);\r
1406                 sal_remove_pending_auth(sal,op);\r
1407                 op->pending_auth=NULL;\r
1408         }\r
1409         if (get_auth_data(ev,&realm,&username)==0){\r
1410                 sal->callbacks.auth_success(op,realm,username);\r
1411         }\r
1412 }\r
1413 \r
1414 static bool_t call_failure(Sal *sal, eXosip_event_t *ev){\r
1415         SalOp *op;\r
1416         int code=0;\r
1417         char* computedReason=NULL;\r
1418         const char *reason=NULL;\r
1419         SalError error=SalErrorUnknown;\r
1420         SalReason sr=SalReasonUnknown;\r
1421         \r
1422 \r
1423         op=(SalOp*)find_op(sal,ev);\r
1424 \r
1425         if (op==NULL) {\r
1426                 ms_warning("Call failure reported for a closed call, ignored.");\r
1427                 return TRUE;\r
1428         }\r
1429 \r
1430         if (ev->response){\r
1431                 code=osip_message_get_status_code(ev->response);\r
1432                 reason=osip_message_get_reason_phrase(ev->response);\r
1433                 osip_header_t *h=NULL;\r
1434                 if (!osip_message_header_get_byname(    ev->response\r
1435                                                                                         ,"Reason"\r
1436                                                                                         ,0\r
1437                                                                                         ,&h)) {\r
1438                         computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h));\r
1439                         reason = computedReason;\r
1440 \r
1441                 }\r
1442         }\r
1443         switch(code)\r
1444         {\r
1445                 case 401:\r
1446                 case 407:\r
1447                         return process_authentication(sal,ev);\r
1448                         break;\r
1449                 case 400:\r
1450                         error=SalErrorUnknown;\r
1451                 break;\r
1452                 case 404:\r
1453                         error=SalErrorFailure;\r
1454                         sr=SalReasonNotFound;\r
1455                 break;\r
1456                 case 415:\r
1457                         error=SalErrorFailure;\r
1458                         sr=SalReasonMedia;\r
1459                 break;\r
1460                 case 422:\r
1461                         eXosip_default_action(ev);\r
1462                         return TRUE;\r
1463                 break;\r
1464                 case 480:\r
1465                         error=SalErrorFailure;\r
1466                         sr=SalReasonTemporarilyUnavailable;\r
1467                 case 486:\r
1468                         error=SalErrorFailure;\r
1469                         sr=SalReasonBusy;\r
1470                 break;\r
1471                 case 487:\r
1472                 break;\r
1473                 case 600:\r
1474                         error=SalErrorFailure;\r
1475                         sr=SalReasonDoNotDisturb;\r
1476                 break;\r
1477                 case 603:\r
1478                         error=SalErrorFailure;\r
1479                         sr=SalReasonDeclined;\r
1480                 break;\r
1481                 default:\r
1482                         if (code>0){\r
1483                                 error=SalErrorFailure;\r
1484                                 sr=SalReasonUnknown;\r
1485                         }else error=SalErrorNoResponse;\r
1486         }\r
1487         op->terminated=TRUE;\r
1488         sal->callbacks.call_failure(op,error,sr,reason,code);\r
1489         if (computedReason != NULL){\r
1490                 ms_free(computedReason);\r
1491         }\r
1492         return TRUE;\r
1493 }\r
1494 \r
1495 /* Request remote side to send us VFU */\r
1496 void sal_call_send_vfu_request(SalOp *h){\r
1497         osip_message_t *msg=NULL;\r
1498         char info_body[] =\r
1499                         "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"\r
1500                          "<media_control>"\r
1501                          "  <vc_primitive>"\r
1502                          "    <to_encoder>"\r
1503                          "      <picture_fast_update></picture_fast_update>"\r
1504                          "    </to_encoder>"\r
1505                          "  </vc_primitive>"\r
1506                          "</media_control>";\r
1507 \r
1508         char clen[10];\r
1509 \r
1510         eXosip_lock();\r
1511         eXosip_call_build_info(h->did,&msg);\r
1512         if (msg){\r
1513                 osip_message_set_body(msg,info_body,strlen(info_body));\r
1514                 osip_message_set_content_type(msg,"application/media_control+xml");\r
1515                 snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body));\r
1516                 osip_message_set_content_length(msg,clen);\r
1517                 eXosip_call_send_request(h->did,msg);\r
1518                 ms_message("Sending VFU request !");\r
1519         }\r
1520         eXosip_unlock();\r
1521 }\r
1522 \r
1523 static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){\r
1524         SalOp *op=find_op(sal,ev);\r
1525         osip_body_t *body=NULL;\r
1526 \r
1527         if (op==NULL){\r
1528                 ms_warning("media control xml received without operation context!");\r
1529                 return ;\r
1530         }\r
1531         \r
1532         osip_message_get_body(ev->request,0,&body);\r
1533         if (body && body->body!=NULL &&\r
1534                 strstr(body->body,"picture_fast_update")){\r
1535                 osip_message_t *ans=NULL;\r
1536                 ms_message("Receiving VFU request !");\r
1537                 if (sal->callbacks.vfu_request){\r
1538                         sal->callbacks.vfu_request(op);\r
1539                         eXosip_call_build_answer(ev->tid,200,&ans);\r
1540                         if (ans)\r
1541                                 eXosip_call_send_answer(ev->tid,200,ans);\r
1542                         return;\r
1543                 }\r
1544         }\r
1545         /*in all other cases we must say it is not implemented.*/\r
1546         {\r
1547                 osip_message_t *ans=NULL;\r
1548                 eXosip_lock();\r
1549                 eXosip_call_build_answer(ev->tid,501,&ans);\r
1550                 if (ans)\r
1551                         eXosip_call_send_answer(ev->tid,501,ans);\r
1552                 eXosip_unlock();\r
1553         }\r
1554 }\r
1555 \r
1556 static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){\r
1557         SalOp *op=find_op(sal,ev);\r
1558         osip_body_t *body=NULL;\r
1559 \r
1560         if (op==NULL){\r
1561                 ms_warning("media dtmf relay received without operation context!");\r
1562                 return ;\r
1563         }\r
1564         \r
1565         osip_message_get_body(ev->request,0,&body);\r
1566         if (body && body->body!=NULL){\r
1567                 osip_message_t *ans=NULL;\r
1568                 const char *name=strstr(body->body,"Signal");\r
1569                 if (name==NULL) name=strstr(body->body,"signal");\r
1570                 if (name==NULL) {\r
1571                         ms_warning("Could not extract the dtmf name from the SIP INFO.");\r
1572                 }else{\r
1573                         char tmp[2];\r
1574                         name+=strlen("signal");\r
1575                         if (sscanf(name," = %1s",tmp)==1){\r
1576                                 ms_message("Receiving dtmf %s via SIP INFO.",tmp);\r
1577                                 if (sal->callbacks.dtmf_received != NULL)\r
1578                                         sal->callbacks.dtmf_received(op, tmp[0]);\r
1579                         }\r
1580                 }\r
1581                 eXosip_lock();\r
1582                 eXosip_call_build_answer(ev->tid,200,&ans);\r
1583                 if (ans)\r
1584                         eXosip_call_send_answer(ev->tid,200,ans);\r
1585                 eXosip_unlock();\r
1586         }\r
1587 }\r
1588 \r
1589 static void fill_options_answer(osip_message_t *options){\r
1590         osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");\r
1591         osip_message_set_accept(options,"application/sdp");\r
1592 }\r
1593 \r
1594 static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){\r
1595         osip_header_t *h=NULL;\r
1596         osip_message_t *ans=NULL;\r
1597         ms_message("Receiving REFER request !");\r
1598         osip_message_header_get_byname(ev->request,"Refer-To",0,&h);\r
1599 \r
1600         if (h){\r
1601                 osip_from_t *from=NULL;\r
1602                 char *tmp;\r
1603                 osip_from_init(&from);\r
1604         \r
1605                 if (osip_from_parse(from,h->hvalue)==0){\r
1606                         if (op ){\r
1607                                 osip_uri_header_t *uh=NULL;\r
1608                                 osip_header_t *referred_by=NULL;\r
1609                                 osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);\r
1610                                 if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){\r
1611                                         ms_message("Found replaces in Refer-To");\r
1612                                         if (op->replaces){\r
1613                                                 ms_free(op->replaces);\r
1614                                         }\r
1615                                         op->replaces=ms_strdup(uh->gvalue);\r
1616                                 }\r
1617                                 osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);\r
1618                                 if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){\r
1619                                         if (op->referred_by)\r
1620                                                 ms_free(op->referred_by);\r
1621                                         op->referred_by=ms_strdup(referred_by->hvalue);\r
1622                                 }\r
1623                         }\r
1624                         osip_uri_header_freelist(&from->url->url_headers);\r
1625                         osip_from_to_str(from,&tmp);\r
1626                         sal->callbacks.refer_received(sal,op,tmp);\r
1627                         osip_free(tmp);\r
1628                         osip_from_free(from);\r
1629                 }\r
1630                 eXosip_lock();\r
1631                 eXosip_call_build_answer(ev->tid,202,&ans);\r
1632                 if (ans)\r
1633                         eXosip_call_send_answer(ev->tid,202,ans);\r
1634                 eXosip_unlock();\r
1635         }\r
1636         else\r
1637         {\r
1638                 ms_warning("cannot do anything with the refer without destination\n");\r
1639         }\r
1640 }\r
1641 \r
1642 static void process_notify(Sal *sal, eXosip_event_t *ev){\r
1643         osip_header_t *h=NULL;\r
1644         char *from=NULL;\r
1645         SalOp *op=find_op(sal,ev);\r
1646         osip_message_t *ans=NULL;\r
1647 \r
1648         ms_message("Receiving NOTIFY request !");\r
1649         osip_from_to_str(ev->request->from,&from);\r
1650         osip_message_header_get_byname(ev->request,"Event",0,&h);\r
1651         if(h){\r
1652                 osip_body_t *body=NULL;\r
1653                 //osip_content_type_t *ct=NULL;\r
1654                 osip_message_get_body(ev->request,0,&body);\r
1655                 //ct=osip_message_get_content_type(ev->request);\r
1656                 if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){\r
1657                         /*special handling of refer events*/\r
1658                         if (body && body->body){\r
1659                                 osip_message_t *msg;\r
1660                                 osip_message_init(&msg);\r
1661                                 if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){\r
1662                                         int code=osip_message_get_status_code(msg);\r
1663                                         if (code==100){\r
1664                                                 sal->callbacks.notify_refer(op,SalReferTrying);\r
1665                                         }else if (code==200){\r
1666                                                 sal->callbacks.notify_refer(op,SalReferSuccess);\r
1667                                         }else if (code>=400){\r
1668                                                 sal->callbacks.notify_refer(op,SalReferFailed);\r
1669                                         }\r
1670                                 }\r
1671                                 osip_message_free(msg);\r
1672                         }\r
1673                 }else{\r
1674                         /*generic handling*/\r
1675                         sal->callbacks.notify(op,from,h->hvalue);\r
1676                 }\r
1677         }\r
1678         /*answer that we received the notify*/\r
1679         eXosip_lock();\r
1680         eXosip_call_build_answer(ev->tid,200,&ans);\r
1681         if (ans)\r
1682                 eXosip_call_send_answer(ev->tid,200,ans);\r
1683         eXosip_unlock();\r
1684         osip_free(from);\r
1685 }\r
1686 \r
1687 static void call_message_new(Sal *sal, eXosip_event_t *ev){\r
1688         osip_message_t *ans=NULL;\r
1689         if (ev->request){\r
1690                 if (MSG_IS_INFO(ev->request)){\r
1691                         osip_content_type_t *ct;\r
1692                         ct=osip_message_get_content_type(ev->request);\r
1693                         if (ct && ct->subtype){\r
1694                                 if (strcmp(ct->subtype,"media_control+xml")==0)\r
1695                                         process_media_control_xml(sal,ev);\r
1696                                 else if (strcmp(ct->subtype,"dtmf-relay")==0)\r
1697                                         process_dtmf_relay(sal,ev);\r
1698                                 else {\r
1699                                         ms_message("Unhandled SIP INFO.");\r
1700                                         /*send an "Not implemented" answer*/\r
1701                                         eXosip_lock();\r
1702                                         eXosip_call_build_answer(ev->tid,501,&ans);\r
1703                                         if (ans)\r
1704                                                 eXosip_call_send_answer(ev->tid,501,ans);\r
1705                                         eXosip_unlock();\r
1706                                 }\r
1707                         }else{\r
1708                                 /*empty SIP INFO, probably to test we are alive. Send an empty answer*/\r
1709                                 eXosip_lock();\r
1710                                 eXosip_call_build_answer(ev->tid,200,&ans);\r
1711                                 if (ans)\r
1712                                         eXosip_call_send_answer(ev->tid,200,ans);\r
1713                                 eXosip_unlock();\r
1714                         }\r
1715                 }else if(MSG_IS_MESSAGE(ev->request)){\r
1716                         /* SIP messages could be received into call */\r
1717                         text_received(sal, ev);\r
1718                         eXosip_lock();\r
1719                         eXosip_call_build_answer(ev->tid,200,&ans);\r
1720                         if (ans)\r
1721                                 eXosip_call_send_answer(ev->tid,200,ans);\r
1722                         eXosip_unlock();\r
1723                 }else if(MSG_IS_REFER(ev->request)){\r
1724                         SalOp *op=find_op(sal,ev);\r
1725                         \r
1726                         ms_message("Receiving REFER request !");\r
1727                         process_refer(sal,op,ev);\r
1728                 }else if(MSG_IS_NOTIFY(ev->request)){\r
1729                         process_notify(sal,ev);\r
1730                 }else if (MSG_IS_OPTIONS(ev->request)){\r
1731                         eXosip_lock();\r
1732                         eXosip_call_build_answer(ev->tid,200,&ans);\r
1733                         if (ans){\r
1734                                 fill_options_answer(ans);\r
1735                                 eXosip_call_send_answer(ev->tid,200,ans);\r
1736                         }\r
1737                         eXosip_unlock();\r
1738                 }\r
1739         }else ms_warning("call_message_new: No request ?");\r
1740 }\r
1741 \r
1742 static void inc_update(Sal *sal, eXosip_event_t *ev){\r
1743         osip_message_t *msg=NULL;\r
1744         ms_message("Processing incoming UPDATE");\r
1745         eXosip_lock();\r
1746         eXosip_message_build_answer(ev->tid,200,&msg);\r
1747         if (msg!=NULL)\r
1748                 eXosip_message_send_answer(ev->tid,200,msg);\r
1749         eXosip_unlock();\r
1750 }\r
1751 \r
1752 static bool_t comes_from_local_if(osip_message_t *msg){\r
1753         osip_via_t *via=NULL;\r
1754         osip_message_get_via(msg,0,&via);\r
1755         if (via){\r
1756                 const char *host;\r
1757                 host=osip_via_get_host(via);\r
1758                 if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){\r
1759                         osip_generic_param_t *param=NULL;\r
1760                         osip_via_param_get_byname(via,"received",&param);\r
1761                         if (param==NULL) return TRUE;\r
1762                         if (param->gvalue &&\r
1763                                 (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){\r
1764                                 return TRUE;\r
1765                         }\r
1766                 }\r
1767         }\r
1768         return FALSE;\r
1769 }\r
1770 \r
1771 static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};\r
1772 static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};\r
1773 \r
1774 static void text_received(Sal *sal, eXosip_event_t *ev){\r
1775         osip_body_t *body=NULL;\r
1776         char *from=NULL,*msg=NULL;\r
1777         osip_content_type_t* content_type;\r
1778         osip_uri_param_t* external_body_url; \r
1779         char unquoted_external_body_url [256];\r
1780         int external_body_size=0;\r
1781         SalMessage salmsg;\r
1782         char message_id[256]={0};\r
1783         osip_header_t *date=NULL;\r
1784         struct tm ret={0};\r
1785         char tmp1[80]={0};\r
1786         char tmp2[80]={0};\r
1787         SalOp *op=sal_op_new(sal);\r
1788 \r
1789         osip_message_get_date(ev->request,0,&date);\r
1790         if(date!=NULL){\r
1791                 int i,j;\r
1792                 sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2,\r
1793                      &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec);\r
1794                 ret.tm_year-=1900;\r
1795                 for(i=0;i<7;i++) { \r
1796                         if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; \r
1797                 }\r
1798                 for(j=0;j<12;j++) { \r
1799                         if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; \r
1800                 }\r
1801         }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent.");\r
1802         \r
1803         content_type= osip_message_get_content_type(ev->request);\r
1804         if (!content_type) {\r
1805                 ms_error("Could not get message because no content type");\r
1806                 return;\r
1807         }\r
1808         osip_from_to_str(ev->request->from,&from);\r
1809         if (content_type->type \r
1810                 && strcmp(content_type->type, "text")==0 \r
1811                 && content_type->subtype\r
1812                 && strcmp(content_type->subtype, "plain")==0 ) {\r
1813                 osip_message_get_body(ev->request,0,&body);\r
1814                 if (body==NULL){\r
1815                         ms_error("Could not get text message from SIP body");\r
1816                         osip_free(from);\r
1817                         return;\r
1818                 }\r
1819                 msg=body->body;\r
1820         }else if (content_type->type \r
1821                   && strcmp(content_type->type, "message")==0 \r
1822                   && content_type->subtype\r
1823                   && strcmp(content_type->subtype, "external-body")==0 ) {\r
1824                 \r
1825                 osip_content_type_param_get_byname(content_type, "URL", &external_body_url);\r
1826                 /*remove both first and last character*/\r
1827                 strncpy(unquoted_external_body_url\r
1828                                 ,&external_body_url->gvalue[1]\r
1829                                 ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));\r
1830                 unquoted_external_body_url[external_body_size-1]='\0';\r
1831         } else {\r
1832                 ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);\r
1833                 osip_free(from);\r
1834                 return;\r
1835         }\r
1836         sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));\r
1837         \r
1838         snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);\r
1839         \r
1840         salmsg.from=from;\r
1841         salmsg.text=msg;\r
1842         salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;\r
1843         salmsg.message_id=message_id;\r
1844         salmsg.time=date!=NULL ? mktime(&ret) : time(NULL);\r
1845         sal->callbacks.text_received(op,&salmsg);\r
1846         sal_op_release(op);\r
1847         osip_free(from);\r
1848 }\r
1849 \r
1850 static void other_request(Sal *sal, eXosip_event_t *ev){\r
1851         ms_message("in other_request");\r
1852         if (ev->request==NULL) return;\r
1853         if (strcmp(ev->request->sip_method,"MESSAGE")==0){\r
1854                 text_received(sal,ev);\r
1855                 eXosip_message_send_answer(ev->tid,200,NULL);\r
1856         }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){\r
1857                 osip_message_t *options=NULL;\r
1858                 eXosip_options_build_answer(ev->tid,200,&options);\r
1859                 fill_options_answer(options);\r
1860                 eXosip_options_send_answer(ev->tid,200,options);\r
1861         }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){\r
1862                 ms_message("Receiving REFER request !");\r
1863                 if (comes_from_local_if(ev->request)) {\r
1864                         process_refer(sal,NULL,ev);\r
1865                 }else ms_warning("Ignored REFER not coming from this local loopback interface.");\r
1866         }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){\r
1867                 inc_update(sal,ev);\r
1868         }else {\r
1869                 char *tmp=NULL;\r
1870                 size_t msglen=0;\r
1871                 osip_message_to_str(ev->request,&tmp,&msglen);\r
1872                 if (tmp){\r
1873                         ms_message("Unsupported request received:\n%s",tmp);\r
1874                         osip_free(tmp);\r
1875                 }\r
1876                 /*answer with a 501 Not implemented*/\r
1877                 eXosip_message_send_answer(ev->tid,501,NULL);\r
1878         }\r
1879 }\r
1880 \r
1881 static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){\r
1882         osip_via_t *via=NULL;\r
1883         osip_message_get_via(msg,0,&via);\r
1884         if (via){\r
1885                 osip_free(via->port);\r
1886                 via->port=osip_strdup(port);\r
1887                 osip_free(via->host);\r
1888                 via->host=osip_strdup(ip);\r
1889         }\r
1890 }\r
1891 \r
1892 \r
1893 static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {\r
1894         osip_contact_t *ctt=NULL;\r
1895         const char *received;\r
1896         int rport;\r
1897         SalTransport transport;\r
1898         char port[20];\r
1899 \r
1900         if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
1901         osip_message_get_contact(request,0,&ctt);\r
1902         if (ctt == NULL) {\r
1903                 ms_warning("fix_message_contact(): no contact to update");\r
1904                 return FALSE;\r
1905         }\r
1906         if (expire_last_contact){\r
1907                 osip_contact_t *oldct=NULL,*prevct;\r
1908                 osip_generic_param_t *param=NULL;\r
1909                 osip_contact_clone(ctt,&oldct);\r
1910                 while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){\r
1911                         osip_contact_free(prevct);\r
1912                         osip_list_remove(&request->contacts,1);\r
1913                 }\r
1914                 osip_list_add(&request->contacts,oldct,1);\r
1915                 osip_contact_param_get_byname(oldct,"expires",&param);\r
1916                 if (param){\r
1917                         if (param->gvalue) osip_free(param->gvalue);\r
1918                         param->gvalue=osip_strdup("0");\r
1919                 }else{\r
1920                         osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));\r
1921                 }\r
1922         }\r
1923         if (ctt->url->host!=NULL){\r
1924                 osip_free(ctt->url->host);\r
1925         }\r
1926         ctt->url->host=osip_strdup(received);\r
1927         if (ctt->url->port!=NULL){\r
1928                 osip_free(ctt->url->port);\r
1929         }\r
1930         snprintf(port,sizeof(port),"%i",rport);\r
1931         ctt->url->port=osip_strdup(port);\r
1932         if (op->masquerade_via) masquerade_via(request,received,port);\r
1933 \r
1934         if (transport != SalTransportUDP) {\r
1935                 sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); \r
1936         }\r
1937         return TRUE;    \r
1938 }\r
1939 \r
1940 static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){\r
1941         osip_contact_t *ctt=NULL;\r
1942         SalAddress* ori_contact_address=NULL;\r
1943         const char *received;\r
1944         int rport;\r
1945         SalTransport transport;\r
1946         char* tmp;\r
1947         osip_message_t *msg=NULL;\r
1948         Sal* sal=op->base.root;\r
1949         int i=0;\r
1950         bool_t found_valid_contact=FALSE;\r
1951         bool_t from_request=FALSE;\r
1952 \r
1953         if (sal->double_reg==FALSE ) return FALSE; \r
1954 \r
1955         if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
1956         do{\r
1957                 ctt=NULL;\r
1958                 osip_message_get_contact(last_answer,i,&ctt);\r
1959                 if (!from_request && ctt==NULL) {\r
1960                         osip_message_get_contact(orig_request,0,&ctt);\r
1961                         from_request=TRUE;\r
1962                 }\r
1963                 if (ctt){\r
1964                         osip_contact_to_str(ctt,&tmp);\r
1965                         ori_contact_address = sal_address_new(tmp);\r
1966         \r
1967                         /*check if contact is up to date*/\r
1968                         if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 \r
1969                                 && sal_address_get_port_int(ori_contact_address) == rport\r
1970                         && sal_address_get_transport(ori_contact_address) == transport) {\r
1971                                 if (!from_request){\r
1972                                         ms_message("Register response has up to date contact, doing nothing.");\r
1973                                 }else {\r
1974                                         ms_warning("Register response does not have up to date contact, but last request had."\r
1975                                                 "Stupid registrar detected, giving up.");\r
1976                                 }\r
1977                                 found_valid_contact=TRUE;\r
1978                         }\r
1979                         osip_free(tmp);\r
1980                         sal_address_destroy(ori_contact_address);\r
1981                 }else break;\r
1982                 i++;\r
1983         }while(!found_valid_contact);\r
1984         if (!found_valid_contact)\r
1985                 ms_message("Contact do not match, resending register.");\r
1986         else return FALSE;\r
1987 \r
1988         eXosip_lock();\r
1989         eXosip_register_build_register(op->rid,op->expires,&msg);\r
1990         if (msg==NULL){\r
1991             eXosip_unlock();\r
1992             ms_warning("Fail to create a contact updated register.");\r
1993             return FALSE;\r
1994         }\r
1995         if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {\r
1996                 eXosip_register_send_register(op->rid,msg);\r
1997                 eXosip_unlock();  \r
1998                 ms_message("Resending new register with updated contact");\r
1999                 update_contact_from_response(op,last_answer);\r
2000                 return TRUE;\r
2001         } else {\r
2002             ms_warning("Fail to send updated register.");\r
2003             eXosip_unlock();\r
2004             return FALSE;\r
2005         }\r
2006         eXosip_unlock();\r
2007         return FALSE;\r
2008 }\r
2009 \r
2010 static void registration_success(Sal *sal, eXosip_event_t *ev){\r
2011         SalOp *op=sal_find_register(sal,ev->rid);\r
2012         osip_header_t *h=NULL;\r
2013         bool_t registered;\r
2014         if (op==NULL){\r
2015                 ms_error("Receiving register response for unknown operation");\r
2016                 return;\r
2017         }\r
2018         osip_message_get_expires(ev->request,0,&h);\r
2019         if (h!=NULL && atoi(h->hvalue)!=0){\r
2020                 registered=TRUE;\r
2021                 if (!register_again_with_updated_contact(op,ev->request,ev->response)){\r
2022                         sal->callbacks.register_success(op,registered);\r
2023                 }\r
2024         }else {\r
2025                 sal->callbacks.register_success(op,FALSE);\r
2026         }\r
2027 }\r
2028 \r
2029 static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){\r
2030         int status_code=0;\r
2031         const char *reason=NULL;\r
2032         SalOp *op=sal_find_register(sal,ev->rid);\r
2033         SalReason sr=SalReasonUnknown;\r
2034         SalError se=SalErrorUnknown;\r
2035         \r
2036         if (op==NULL){\r
2037                 ms_error("Receiving register failure for unknown operation");\r
2038                 return TRUE;\r
2039         }\r
2040         if (ev->response){\r
2041                 status_code=osip_message_get_status_code(ev->response);\r
2042                 reason=osip_message_get_reason_phrase(ev->response);\r
2043         }\r
2044         switch(status_code){\r
2045                 case 401:\r
2046                 case 407:\r
2047                         return process_authentication(sal,ev);\r
2048                         break;\r
2049                 case 423: /*interval too brief*/\r
2050                         {/*retry with greater interval */\r
2051                                 osip_header_t *h=NULL;\r
2052                                 osip_message_t *msg=NULL;\r
2053                                 osip_message_header_get_byname(ev->response,"min-expires",0,&h);\r
2054                                 if (h && h->hvalue && h->hvalue[0]!='\0'){\r
2055                                         int val=atoi(h->hvalue);\r
2056                                         if (val>op->expires)\r
2057                                                 op->expires=val;\r
2058                                 }else op->expires*=2;\r
2059                                 eXosip_lock();\r
2060                                 eXosip_register_build_register(op->rid,op->expires,&msg);\r
2061                                 eXosip_register_send_register(op->rid,msg);\r
2062                                 eXosip_unlock();\r
2063                         }\r
2064                 break;\r
2065                 case 606: /*Not acceptable, workaround for proxies that don't like private addresses\r
2066                                  in vias, such as ekiga.net \r
2067                                  On the opposite, freephonie.net bugs when via are masqueraded.\r
2068                                  */\r
2069                         op->masquerade_via=TRUE;\r
2070                 default:\r
2071                         /* if contact is up to date, process the failure, otherwise resend a new register with\r
2072                                 updated contact first, just in case the faillure is due to incorrect contact */\r
2073                         if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response))\r
2074                                 return TRUE; /*we are retrying with an updated contact*/\r
2075                         if (status_code==403){\r
2076                                 se=SalErrorFailure;\r
2077                                 sr=SalReasonForbidden;\r
2078                         }else if (status_code==0){\r
2079                                 se=SalErrorNoResponse;\r
2080                         }\r
2081                         sal->callbacks.register_failure(op,se,sr,reason);\r
2082         }\r
2083         return TRUE;\r
2084 }\r
2085 \r
2086 static void other_request_reply(Sal *sal,eXosip_event_t *ev){\r
2087         SalOp *op=find_op(sal,ev);\r
2088         if (op==NULL){\r
2089                 ms_warning("other_request_reply(): Receiving response to unknown request.");\r
2090                 return;\r
2091         }\r
2092         if (ev->response){\r
2093                 ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));\r
2094                 update_contact_from_response(op,ev->response);\r
2095                 if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)\r
2096                         sal->callbacks.ping_reply(op);\r
2097         }\r
2098         if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {\r
2099                 /*out of call message acknolegment*/\r
2100                 SalTextDeliveryStatus status=SalTextDeliveryFailed;\r
2101                 if (ev->response){\r
2102                         if (ev->response->status_code<200){\r
2103                                 status=SalTextDeliveryInProgress;\r
2104                         }else if (ev->response->status_code<300 && ev->response->status_code>=200){\r
2105                                 status=SalTextDeliveryDone;\r
2106                         }\r
2107                 }\r
2108                 sal->callbacks.text_delivery_update(op,status);\r
2109         }\r
2110 }\r
2111 \r
2112 static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){\r
2113         SalOp *op=find_op(sal,ev);\r
2114         if (ev->response){\r
2115                 if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){\r
2116                         if (op->sipfrag_pending){\r
2117                                 send_notify_for_refer(op->did,op->sipfrag_pending);\r
2118                                 op->sipfrag_pending=NULL;\r
2119                         }\r
2120                 }\r
2121         }\r
2122 }\r
2123 \r
2124 static bool_t process_event(Sal *sal, eXosip_event_t *ev){\r
2125         ms_message("linphone process event get a message %d\n",ev->type);\r
2126         switch(ev->type){\r
2127                 case EXOSIP_CALL_ANSWERED:\r
2128                         ms_message("CALL_ANSWERED\n");\r
2129                         call_accepted(sal,ev);\r
2130                         authentication_ok(sal,ev);\r
2131                         break;\r
2132                 case EXOSIP_CALL_CLOSED:\r
2133                 case EXOSIP_CALL_CANCELLED:\r
2134                         ms_message("CALL_CLOSED or CANCELLED\n");\r
2135                         call_terminated(sal,ev);\r
2136                         break;\r
2137                 case EXOSIP_CALL_TIMEOUT:\r
2138                 case EXOSIP_CALL_NOANSWER:\r
2139                         ms_message("CALL_TIMEOUT or NOANSWER\n");\r
2140                         return call_failure(sal,ev);\r
2141                         break;\r
2142                 case EXOSIP_CALL_REQUESTFAILURE:\r
2143                 case EXOSIP_CALL_GLOBALFAILURE:\r
2144                 case EXOSIP_CALL_SERVERFAILURE:\r
2145                         ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n");\r
2146                         return call_failure(sal,ev);\r
2147                         break;\r
2148                 case EXOSIP_CALL_RELEASED:\r
2149                         ms_message("CALL_RELEASED\n");\r
2150                         call_released(sal, ev);\r
2151                         break;\r
2152                 case EXOSIP_CALL_INVITE:\r
2153                         ms_message("CALL_NEW\n");\r
2154                         inc_new_call(sal,ev);\r
2155                         break;\r
2156                 case EXOSIP_CALL_REINVITE:\r
2157                         handle_reinvite(sal,ev);\r
2158                         break;\r
2159                 case EXOSIP_CALL_ACK:\r
2160                         ms_message("CALL_ACK");\r
2161                         handle_ack(sal,ev);\r
2162                         break;\r
2163                 case EXOSIP_CALL_REDIRECTED:\r
2164                         ms_message("CALL_REDIRECTED");\r
2165                         eXosip_default_action(ev);\r
2166                         break;\r
2167                 case EXOSIP_CALL_PROCEEDING:\r
2168                         ms_message("CALL_PROCEEDING");\r
2169                         call_proceeding(sal,ev);\r
2170                         break;\r
2171                 case EXOSIP_CALL_RINGING:\r
2172                         ms_message("CALL_RINGING");\r
2173                         call_ringing(sal,ev);\r
2174                         authentication_ok(sal,ev);\r
2175                         break;\r
2176                 case EXOSIP_CALL_MESSAGE_NEW:\r
2177                         ms_message("EXOSIP_CALL_MESSAGE_NEW");\r
2178                         call_message_new(sal,ev);\r
2179                         break;\r
2180                 case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:\r
2181                         if (ev->response &&\r
2182                                 (ev->response->status_code==407 || ev->response->status_code==401)){\r
2183                                  return process_authentication(sal,ev);\r
2184                         }\r
2185                         break;\r
2186                 case EXOSIP_CALL_MESSAGE_ANSWERED:\r
2187                         ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");\r
2188                         process_in_call_reply(sal,ev);\r
2189                 break;\r
2190                 case EXOSIP_IN_SUBSCRIPTION_NEW:\r
2191                         ms_message("CALL_IN_SUBSCRIPTION_NEW ");\r
2192                         sal_exosip_subscription_recv(sal,ev);\r
2193                         break;\r
2194                 case EXOSIP_IN_SUBSCRIPTION_RELEASED:\r
2195                         ms_message("CALL_SUBSCRIPTION_NEW ");\r
2196                         sal_exosip_in_subscription_closed(sal,ev);\r
2197                         break;\r
2198                 case EXOSIP_SUBSCRIPTION_UPDATE:\r
2199                         ms_message("CALL_SUBSCRIPTION_UPDATE");\r
2200                         break;\r
2201                 case EXOSIP_SUBSCRIPTION_NOTIFY:\r
2202                         ms_message("CALL_SUBSCRIPTION_NOTIFY");\r
2203                         sal_exosip_notify_recv(sal,ev);\r
2204                         break;\r
2205                 case EXOSIP_SUBSCRIPTION_ANSWERED:\r
2206                         ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);\r
2207                         sal_exosip_subscription_answered(sal,ev);\r
2208                         break;\r
2209                 case EXOSIP_SUBSCRIPTION_CLOSED:\r
2210                         ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");\r
2211                         sal_exosip_subscription_closed(sal,ev);\r
2212                         break;\r
2213                 case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:   /**< announce a request failure      */\r
2214                         if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){\r
2215                                 return process_authentication(sal,ev);\r
2216                         }\r
2217                 case EXOSIP_SUBSCRIPTION_SERVERFAILURE:\r
2218                 case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:\r
2219                         sal_exosip_subscription_closed(sal,ev);\r
2220                         break;\r
2221                 case EXOSIP_REGISTRATION_FAILURE:\r
2222                         ms_message("REGISTRATION_FAILURE\n");\r
2223                         return registration_failure(sal,ev);\r
2224                         break;\r
2225                 case EXOSIP_REGISTRATION_SUCCESS:\r
2226                         authentication_ok(sal,ev);\r
2227                         registration_success(sal,ev);\r
2228                         break;\r
2229                 case EXOSIP_MESSAGE_NEW:\r
2230                         other_request(sal,ev);\r
2231                         break;\r
2232                 case EXOSIP_MESSAGE_PROCEEDING:\r
2233                 case EXOSIP_MESSAGE_ANSWERED:\r
2234                 case EXOSIP_MESSAGE_REDIRECTED:\r
2235                 case EXOSIP_MESSAGE_SERVERFAILURE:\r
2236                 case EXOSIP_MESSAGE_GLOBALFAILURE:\r
2237                         other_request_reply(sal,ev);\r
2238                         break;\r
2239                 case EXOSIP_MESSAGE_REQUESTFAILURE:\r
2240                 case EXOSIP_NOTIFICATION_REQUESTFAILURE:\r
2241                         if (ev->response) {\r
2242                                 switch (ev->response->status_code) {\r
2243                                         case 407:\r
2244                                         case 401:\r
2245                                                 return process_authentication(sal,ev);\r
2246                                         case 412: {\r
2247                                                 eXosip_automatic_action ();\r
2248                                                 return 1;\r
2249                                         }\r
2250                                 }\r
2251                         }\r
2252                         other_request_reply(sal,ev);\r
2253                         break;\r
2254                 default:\r
2255                         ms_message("Unhandled exosip event ! %i",ev->type);\r
2256                         break;\r
2257         }\r
2258         return TRUE;\r
2259 }\r
2260 \r
2261 int sal_iterate(Sal *sal){\r
2262         eXosip_event_t *ev;\r
2263         while((ev=eXosip_event_wait(0,0))!=NULL){\r
2264                 if (process_event(sal,ev))\r
2265                         eXosip_event_free(ev);\r
2266         }\r
2267 #ifdef HAVE_EXOSIP_TRYLOCK\r
2268         if (eXosip_trylock()==0){\r
2269                 eXosip_automatic_refresh();\r
2270                 eXosip_unlock();\r
2271         }else{\r
2272                 ms_warning("eXosip_trylock busy.");\r
2273         }\r
2274 #else\r
2275         eXosip_lock();\r
2276         eXosip_automatic_refresh();\r
2277         eXosip_unlock();\r
2278 #endif\r
2279         return 0;\r
2280 }\r
2281 \r
2282 static void register_set_contact(osip_message_t *msg, const char *contact){\r
2283         osip_uri_param_t *param = NULL;\r
2284         osip_contact_t *ct=NULL;\r
2285         char *line=NULL;\r
2286         /*we get the line parameter choosed by exosip, and add it to our own contact*/\r
2287         osip_message_get_contact(msg,0,&ct);\r
2288         if (ct!=NULL){\r
2289                 osip_uri_uparam_get_byname(ct->url, "line", &param);\r
2290                 if (param && param->gvalue)\r
2291                         line=osip_strdup(param->gvalue);\r
2292         }\r
2293         _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
2294         osip_message_set_contact(msg,contact);\r
2295         osip_message_get_contact(msg,0,&ct);\r
2296         osip_uri_uparam_add(ct->url,osip_strdup("line"),line);\r
2297 }\r
2298 \r
2299 static void sal_register_add_route(osip_message_t *msg, const char *proxy){\r
2300         osip_route_t *route;\r
2301 \r
2302         osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);\r
2303         \r
2304         osip_route_init(&route);\r
2305         if (osip_route_parse(route,proxy)==0){\r
2306                 osip_uri_param_t *lr_param = NULL;\r
2307                 osip_uri_uparam_get_byname(route->url, "lr", &lr_param);\r
2308                 if (lr_param == NULL){\r
2309                         osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);\r
2310                 }\r
2311                 osip_list_add(&msg->routes,route,0);\r
2312                 return;\r
2313         }\r
2314         osip_route_free(route);\r
2315 }\r
2316 \r
2317 \r
2318 int sal_register(SalOp *h, const char *proxy, const char *from, int expires){\r
2319         osip_message_t *msg;\r
2320         const char *contact=sal_op_get_contact(h);\r
2321 \r
2322         sal_op_set_route(h,proxy);\r
2323         if (h->rid==-1){\r
2324                 SalAddress *from_parsed=sal_address_new(from);\r
2325                 char domain[256];\r
2326                 char *uri, *domain_ptr = NULL;\r
2327                 if (from_parsed==NULL) {\r
2328                         ms_warning("sal_register() bad from %s",from);\r
2329                         return -1;\r
2330                 }\r
2331                 /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of\r
2332                    using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */\r
2333                 uri = sal_address_as_string_uri_only(from_parsed);\r
2334                 if (uri) domain_ptr = strchr(uri, '@');\r
2335                 if (domain_ptr) {\r
2336                         snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);\r
2337                 } else {\r
2338                         snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));\r
2339                 }\r
2340                 if (uri) ms_free(uri);\r
2341                 sal_address_destroy(from_parsed);\r
2342                 eXosip_lock();\r
2343                 h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);\r
2344                 if (msg){\r
2345                         if (contact) register_set_contact(msg,contact);\r
2346                         sal_register_add_route(msg,proxy);\r
2347                         sal_add_register(h->base.root,h);\r
2348                 }else{\r
2349                         ms_error("Could not build initial register.");\r
2350                         eXosip_unlock();\r
2351                         return -1;\r
2352                 }\r
2353         }else{\r
2354                 eXosip_lock();\r
2355                 eXosip_register_build_register(h->rid,expires,&msg);\r
2356                 sal_register_add_route(msg,proxy);\r
2357         }\r
2358         if (msg){\r
2359                 eXosip_register_send_register(h->rid,msg);\r
2360         }\r
2361         eXosip_unlock();\r
2362         h->expires=expires;\r
2363         return (msg != NULL) ? 0 : -1;\r
2364 }\r
2365 \r
2366 int sal_register_refresh(SalOp *op, int expires){\r
2367         osip_message_t *msg=NULL;\r
2368         const char *contact=sal_op_get_contact(op);\r
2369         \r
2370         if (op->rid==-1){\r
2371                 ms_error("Unexistant registration context, not possible to refresh.");\r
2372                 return -1;\r
2373         }\r
2374 #ifdef HAVE_EXOSIP_TRYLOCK\r
2375         {\r
2376                 int tries=0;\r
2377                 /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.\r
2378                 * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take\r
2379                 * the exosip lock in a non blocking way, and give up if it takes too long*/\r
2380                 while (eXosip_trylock()!=0){\r
2381                         ms_usleep(100000);\r
2382                         if (tries>30) {/*after 3 seconds, give up*/\r
2383                                 ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");\r
2384                                 return -1;\r
2385                         }\r
2386                 }\r
2387         }\r
2388 #else\r
2389         eXosip_lock();\r
2390 #endif\r
2391         eXosip_register_build_register(op->rid,expires,&msg);\r
2392         if (msg!=NULL){\r
2393                 if (contact) register_set_contact(msg,contact);\r
2394                 sal_register_add_route(msg,sal_op_get_route(op));\r
2395                 eXosip_register_send_register(op->rid,msg);\r
2396         }else ms_error("Could not build REGISTER refresh message.");\r
2397         eXosip_unlock();\r
2398         return (msg != NULL) ? 0 : -1;\r
2399 }\r
2400 \r
2401 \r
2402 int sal_unregister(SalOp *h){\r
2403         osip_message_t *msg=NULL;\r
2404         eXosip_lock();\r
2405         eXosip_register_build_register(h->rid,0,&msg);\r
2406         if (msg) eXosip_register_send_register(h->rid,msg);\r
2407         else ms_warning("Could not build unREGISTER !");\r
2408         eXosip_unlock();\r
2409         return 0;\r
2410 }\r
2411 \r
2412 SalAddress * sal_address_new(const char *uri){\r
2413         osip_from_t *from;\r
2414         osip_from_init(&from);\r
2415 \r
2416         // Remove front spaces\r
2417         while (uri[0]==' ') {\r
2418                 uri++;\r
2419         }\r
2420                 \r
2421         if (osip_from_parse(from,uri)!=0){\r
2422                 osip_from_free(from);\r
2423                 return NULL;\r
2424         }\r
2425         if (from->displayname!=NULL && from->displayname[0]=='"'){\r
2426                 char *unquoted=osip_strdup_without_quote(from->displayname);\r
2427                 osip_free(from->displayname);\r
2428                 from->displayname=unquoted;\r
2429         }\r
2430         return (SalAddress*)from;\r
2431 }\r
2432 \r
2433 SalAddress * sal_address_clone(const SalAddress *addr){\r
2434         osip_from_t *ret=NULL;\r
2435         osip_from_clone((osip_from_t*)addr,&ret);\r
2436         return (SalAddress*)ret;\r
2437 }\r
2438 \r
2439 #define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )\r
2440 \r
2441 const char *sal_address_get_scheme(const SalAddress *addr){\r
2442         const osip_from_t *u=(const osip_from_t*)addr;\r
2443         return null_if_empty(u->url->scheme);\r
2444 }\r
2445 \r
2446 const char *sal_address_get_display_name(const SalAddress* addr){\r
2447         const osip_from_t *u=(const osip_from_t*)addr;\r
2448         return null_if_empty(u->displayname);\r
2449 }\r
2450 \r
2451 const char *sal_address_get_username(const SalAddress *addr){\r
2452         const osip_from_t *u=(const osip_from_t*)addr;\r
2453         return null_if_empty(u->url->username);\r
2454 }\r
2455 \r
2456 const char *sal_address_get_domain(const SalAddress *addr){\r
2457         const osip_from_t *u=(const osip_from_t*)addr;\r
2458         return null_if_empty(u->url->host);\r
2459 }\r
2460 \r
2461 void sal_address_set_display_name(SalAddress *addr, const char *display_name){\r
2462         osip_from_t *u=(osip_from_t*)addr;\r
2463         if (u->displayname!=NULL){\r
2464                 osip_free(u->displayname);\r
2465                 u->displayname=NULL;\r
2466         }\r
2467         if (display_name!=NULL && display_name[0]!='\0'){\r
2468                 u->displayname=osip_strdup(display_name);\r
2469         }\r
2470 }\r
2471 \r
2472 void sal_address_set_username(SalAddress *addr, const char *username){\r
2473         osip_from_t *uri=(osip_from_t*)addr;\r
2474         if (uri->url->username!=NULL){\r
2475                 osip_free(uri->url->username);\r
2476                 uri->url->username=NULL;\r
2477         }\r
2478         if (username)\r
2479                 uri->url->username=osip_strdup(username);\r
2480 }\r
2481 \r
2482 void sal_address_set_domain(SalAddress *addr, const char *host){\r
2483         osip_from_t *uri=(osip_from_t*)addr;\r
2484         if (uri->url->host!=NULL){\r
2485                 osip_free(uri->url->host);\r
2486                 uri->url->host=NULL;\r
2487         }\r
2488         if (host)\r
2489                 uri->url->host=osip_strdup(host);\r
2490 }\r
2491 \r
2492 void sal_address_set_port(SalAddress *addr, const char *port){\r
2493         osip_from_t *uri=(osip_from_t*)addr;\r
2494         if (uri->url->port!=NULL){\r
2495                 osip_free(uri->url->port);\r
2496                 uri->url->port=NULL;\r
2497         }\r
2498         if (port)\r
2499                 uri->url->port=osip_strdup(port);\r
2500 }\r
2501 \r
2502 void sal_address_set_port_int(SalAddress *uri, int port){\r
2503         char tmp[12];\r
2504         if (port==5060){\r
2505                 /*this is the default, special case to leave the port field blank*/\r
2506                 sal_address_set_port(uri,NULL);\r
2507                 return;\r
2508         }\r
2509         snprintf(tmp,sizeof(tmp),"%i",port);\r
2510         sal_address_set_port(uri,tmp);\r
2511 }\r
2512 \r
2513 void sal_address_clean(SalAddress *addr){\r
2514         osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params);\r
2515         osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params);\r
2516 }\r
2517 \r
2518 char *sal_address_as_string(const SalAddress *u){\r
2519         char *tmp,*ret;\r
2520         osip_from_t *from=(osip_from_t *)u;\r
2521         char *old_displayname=NULL;\r
2522         /* hack to force use of quotes around the displayname*/\r
2523         if (from->displayname!=NULL\r
2524             && from->displayname[0]!='"'){\r
2525                 old_displayname=from->displayname;\r
2526                 from->displayname=osip_enquote(from->displayname);\r
2527         }\r
2528         osip_from_to_str(from,&tmp);\r
2529         if (old_displayname!=NULL){\r
2530                 ms_free(from->displayname);\r
2531                 from->displayname=old_displayname;\r
2532         }\r
2533         ret=ms_strdup(tmp);\r
2534         osip_free(tmp);\r
2535         return ret;\r
2536 }\r
2537 \r
2538 char *sal_address_as_string_uri_only(const SalAddress *u){\r
2539         char *tmp=NULL,*ret;\r
2540         osip_uri_to_str(((osip_from_t*)u)->url,&tmp);\r
2541         ret=ms_strdup(tmp);\r
2542         osip_free(tmp);\r
2543         return ret;\r
2544 }\r
2545 void sal_address_set_param(SalAddress *u,const char* name,const char* value) {\r
2546         osip_uri_param_t *param=NULL;\r
2547     osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,&param);\r
2548     if (param == NULL){\r
2549         osip_uri_uparam_add     (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL);\r
2550     } else {\r
2551         osip_free(param->gvalue);\r
2552         param->gvalue=value ? osip_strdup(value) : NULL;\r
2553     }\r
2554     \r
2555 }\r
2556 \r
2557 void sal_address_destroy(SalAddress *u){\r
2558         osip_from_free((osip_from_t*)u);\r
2559 }\r
2560 \r
2561 void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {\r
2562         ctx->tcp_tls_keepalive = enabled;\r
2563 }\r
2564 \r
2565 void sal_set_keepalive_period(Sal *ctx,unsigned int value) {\r
2566         switch (ctx->transport) {\r
2567                 case SalTransportUDP:\r
2568                         ctx->keepalive_period = value;\r
2569                         break;\r
2570                 case SalTransportTCP:\r
2571                 case SalTransportTLS:\r
2572                         if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value;\r
2573                         else ctx->keepalive_period = -1;\r
2574                         break;\r
2575                 default:\r
2576                         break;\r
2577         }\r
2578         eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);\r
2579 }\r
2580 unsigned int sal_get_keepalive_period(Sal *ctx) {\r
2581         return ctx->keepalive_period;\r
2582 }\r
2583 \r
2584 const char * sal_address_get_port(const SalAddress *addr) {\r
2585         const osip_from_t *u=(const osip_from_t*)addr;\r
2586         return null_if_empty(u->url->port);\r
2587 }\r
2588 \r
2589 int sal_address_get_port_int(const SalAddress *uri) {\r
2590         const char* port = sal_address_get_port(uri);\r
2591         if (port != NULL) {\r
2592                 return atoi(port);\r
2593         } else {\r
2594                 return 5060;\r
2595         }\r
2596 }\r
2597 SalTransport sal_address_get_transport(const SalAddress* addr) {\r
2598     const osip_from_t *u=(const osip_from_t*)addr;\r
2599     osip_uri_param_t *transport_param=NULL;\r
2600     osip_uri_uparam_get_byname(u->url,"transport",&transport_param);\r
2601     if (transport_param == NULL){\r
2602         return SalTransportUDP;\r
2603     }  else {\r
2604         return sal_transport_parse(transport_param->gvalue);\r
2605     }\r
2606 }\r
2607 void sal_address_set_transport(SalAddress* addr,SalTransport transport) {\r
2608     sal_address_set_param(addr, "transport", sal_transport_to_string(transport));\r
2609 }\r
2610 \r
2611 /* sends a reinvite. Local media description may have changed by application since call establishment*/\r
2612 int sal_call_update(SalOp *h, const char *subject){\r
2613         int err=0;\r
2614         osip_message_t *reinvite=NULL;\r
2615 \r
2616         eXosip_lock();\r
2617         if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){\r
2618                 eXosip_unlock();\r
2619                 return -1;\r
2620         }\r
2621         eXosip_unlock();\r
2622         osip_message_set_subject(reinvite,subject);\r
2623         osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");\r
2624         if (h->base.contact){\r
2625                 _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);\r
2626                 osip_message_set_contact(reinvite,h->base.contact);\r
2627         }\r
2628         if (h->base.root->session_expires!=0){\r
2629                 osip_message_set_header(reinvite, "Session-expires", "200");\r
2630                 osip_message_set_supported(reinvite, "timer");\r
2631         }\r
2632         if (h->base.local_media){\r
2633                 h->sdp_offering=TRUE;\r
2634                 set_sdp_from_desc(reinvite,h->base.local_media);\r
2635         }else h->sdp_offering=FALSE;\r
2636         eXosip_lock();\r
2637         err = eXosip_call_send_request(h->did, reinvite);\r
2638         eXosip_unlock();\r
2639         return err;\r
2640 }\r
2641 \r
2642 void sal_reuse_authorization(Sal *ctx, bool_t value) {\r
2643         ctx->reuse_authorization=value;\r
2644 }\r
2645 \r
2646 void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){\r
2647         MSList *elem=(MSList*)ch;\r
2648         for (;elem!=NULL;elem=elem->next){\r
2649                 SalCustomHeader *it=(SalCustomHeader*)elem;\r
2650                 osip_message_set_header(msg,it->header_name,it->header_value);\r
2651         }\r
2652 }\r
2653 \r
2654 SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){\r
2655         int i=0;\r
2656         osip_header_t *header;\r
2657         SalCustomHeader *ret=NULL;\r
2658 \r
2659         while((header=osip_list_get(&msg->headers,i))!=NULL){\r
2660                 ret=sal_custom_header_append(ret,header->hname,header->hvalue);\r
2661                 i++;\r
2662         }\r
2663         return ret;\r
2664 }\r
2665 \r