]> sjero.net Git - linphone/blob - coreapi/sal_eXosip2.c
change unread messages picture
[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                 ret.tm_isdst=-1;\r
1802         }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent.");\r
1803         \r
1804         content_type= osip_message_get_content_type(ev->request);\r
1805         if (!content_type) {\r
1806                 ms_error("Could not get message because no content type");\r
1807                 return;\r
1808         }\r
1809         osip_from_to_str(ev->request->from,&from);\r
1810         if (content_type->type \r
1811                 && strcmp(content_type->type, "text")==0 \r
1812                 && content_type->subtype\r
1813                 && strcmp(content_type->subtype, "plain")==0 ) {\r
1814                 osip_message_get_body(ev->request,0,&body);\r
1815                 if (body==NULL){\r
1816                         ms_error("Could not get text message from SIP body");\r
1817                         osip_free(from);\r
1818                         return;\r
1819                 }\r
1820                 msg=body->body;\r
1821         }else if (content_type->type \r
1822                   && strcmp(content_type->type, "message")==0 \r
1823                   && content_type->subtype\r
1824                   && strcmp(content_type->subtype, "external-body")==0 ) {\r
1825                 \r
1826                 osip_content_type_param_get_byname(content_type, "URL", &external_body_url);\r
1827                 /*remove both first and last character*/\r
1828                 strncpy(unquoted_external_body_url\r
1829                                 ,&external_body_url->gvalue[1]\r
1830                                 ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));\r
1831                 unquoted_external_body_url[external_body_size-1]='\0';\r
1832         } else {\r
1833                 ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);\r
1834                 osip_free(from);\r
1835                 return;\r
1836         }\r
1837         sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));\r
1838         \r
1839         snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);\r
1840         \r
1841         salmsg.from=from;\r
1842         salmsg.text=msg;\r
1843         salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;\r
1844         salmsg.message_id=message_id;\r
1845         salmsg.time=date!=NULL ? mktime(&ret) : time(NULL);\r
1846         sal->callbacks.text_received(op,&salmsg);\r
1847         sal_op_release(op);\r
1848         osip_free(from);\r
1849 }\r
1850 \r
1851 static void other_request(Sal *sal, eXosip_event_t *ev){\r
1852         ms_message("in other_request");\r
1853         if (ev->request==NULL) return;\r
1854         if (strcmp(ev->request->sip_method,"MESSAGE")==0){\r
1855                 text_received(sal,ev);\r
1856                 eXosip_message_send_answer(ev->tid,200,NULL);\r
1857         }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){\r
1858                 osip_message_t *options=NULL;\r
1859                 eXosip_options_build_answer(ev->tid,200,&options);\r
1860                 fill_options_answer(options);\r
1861                 eXosip_options_send_answer(ev->tid,200,options);\r
1862         }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){\r
1863                 ms_message("Receiving REFER request !");\r
1864                 if (comes_from_local_if(ev->request)) {\r
1865                         process_refer(sal,NULL,ev);\r
1866                 }else ms_warning("Ignored REFER not coming from this local loopback interface.");\r
1867         }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){\r
1868                 inc_update(sal,ev);\r
1869         }else {\r
1870                 char *tmp=NULL;\r
1871                 size_t msglen=0;\r
1872                 osip_message_to_str(ev->request,&tmp,&msglen);\r
1873                 if (tmp){\r
1874                         ms_message("Unsupported request received:\n%s",tmp);\r
1875                         osip_free(tmp);\r
1876                 }\r
1877                 /*answer with a 501 Not implemented*/\r
1878                 eXosip_message_send_answer(ev->tid,501,NULL);\r
1879         }\r
1880 }\r
1881 \r
1882 static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){\r
1883         osip_via_t *via=NULL;\r
1884         osip_message_get_via(msg,0,&via);\r
1885         if (via){\r
1886                 osip_free(via->port);\r
1887                 via->port=osip_strdup(port);\r
1888                 osip_free(via->host);\r
1889                 via->host=osip_strdup(ip);\r
1890         }\r
1891 }\r
1892 \r
1893 \r
1894 static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {\r
1895         osip_contact_t *ctt=NULL;\r
1896         const char *received;\r
1897         int rport;\r
1898         SalTransport transport;\r
1899         char port[20];\r
1900 \r
1901         if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
1902         osip_message_get_contact(request,0,&ctt);\r
1903         if (ctt == NULL) {\r
1904                 ms_warning("fix_message_contact(): no contact to update");\r
1905                 return FALSE;\r
1906         }\r
1907         if (expire_last_contact){\r
1908                 osip_contact_t *oldct=NULL,*prevct;\r
1909                 osip_generic_param_t *param=NULL;\r
1910                 osip_contact_clone(ctt,&oldct);\r
1911                 while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){\r
1912                         osip_contact_free(prevct);\r
1913                         osip_list_remove(&request->contacts,1);\r
1914                 }\r
1915                 osip_list_add(&request->contacts,oldct,1);\r
1916                 osip_contact_param_get_byname(oldct,"expires",&param);\r
1917                 if (param){\r
1918                         if (param->gvalue) osip_free(param->gvalue);\r
1919                         param->gvalue=osip_strdup("0");\r
1920                 }else{\r
1921                         osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));\r
1922                 }\r
1923         }\r
1924         if (ctt->url->host!=NULL){\r
1925                 osip_free(ctt->url->host);\r
1926         }\r
1927         ctt->url->host=osip_strdup(received);\r
1928         if (ctt->url->port!=NULL){\r
1929                 osip_free(ctt->url->port);\r
1930         }\r
1931         snprintf(port,sizeof(port),"%i",rport);\r
1932         ctt->url->port=osip_strdup(port);\r
1933         if (op->masquerade_via) masquerade_via(request,received,port);\r
1934 \r
1935         if (transport != SalTransportUDP) {\r
1936                 sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); \r
1937         }\r
1938         return TRUE;    \r
1939 }\r
1940 \r
1941 static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){\r
1942         osip_contact_t *ctt=NULL;\r
1943         SalAddress* ori_contact_address=NULL;\r
1944         const char *received;\r
1945         int rport;\r
1946         SalTransport transport;\r
1947         char* tmp;\r
1948         osip_message_t *msg=NULL;\r
1949         Sal* sal=op->base.root;\r
1950         int i=0;\r
1951         bool_t found_valid_contact=FALSE;\r
1952         bool_t from_request=FALSE;\r
1953 \r
1954         if (sal->double_reg==FALSE ) return FALSE; \r
1955 \r
1956         if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
1957         do{\r
1958                 ctt=NULL;\r
1959                 osip_message_get_contact(last_answer,i,&ctt);\r
1960                 if (!from_request && ctt==NULL) {\r
1961                         osip_message_get_contact(orig_request,0,&ctt);\r
1962                         from_request=TRUE;\r
1963                 }\r
1964                 if (ctt){\r
1965                         osip_contact_to_str(ctt,&tmp);\r
1966                         ori_contact_address = sal_address_new(tmp);\r
1967         \r
1968                         /*check if contact is up to date*/\r
1969                         if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 \r
1970                                 && sal_address_get_port_int(ori_contact_address) == rport\r
1971                         && sal_address_get_transport(ori_contact_address) == transport) {\r
1972                                 if (!from_request){\r
1973                                         ms_message("Register response has up to date contact, doing nothing.");\r
1974                                 }else {\r
1975                                         ms_warning("Register response does not have up to date contact, but last request had."\r
1976                                                 "Stupid registrar detected, giving up.");\r
1977                                 }\r
1978                                 found_valid_contact=TRUE;\r
1979                         }\r
1980                         osip_free(tmp);\r
1981                         sal_address_destroy(ori_contact_address);\r
1982                 }else break;\r
1983                 i++;\r
1984         }while(!found_valid_contact);\r
1985         if (!found_valid_contact)\r
1986                 ms_message("Contact do not match, resending register.");\r
1987         else return FALSE;\r
1988 \r
1989         eXosip_lock();\r
1990         eXosip_register_build_register(op->rid,op->expires,&msg);\r
1991         if (msg==NULL){\r
1992             eXosip_unlock();\r
1993             ms_warning("Fail to create a contact updated register.");\r
1994             return FALSE;\r
1995         }\r
1996         if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {\r
1997                 eXosip_register_send_register(op->rid,msg);\r
1998                 eXosip_unlock();  \r
1999                 ms_message("Resending new register with updated contact");\r
2000                 update_contact_from_response(op,last_answer);\r
2001                 return TRUE;\r
2002         } else {\r
2003             ms_warning("Fail to send updated register.");\r
2004             eXosip_unlock();\r
2005             return FALSE;\r
2006         }\r
2007         eXosip_unlock();\r
2008         return FALSE;\r
2009 }\r
2010 \r
2011 static void registration_success(Sal *sal, eXosip_event_t *ev){\r
2012         SalOp *op=sal_find_register(sal,ev->rid);\r
2013         osip_header_t *h=NULL;\r
2014         bool_t registered;\r
2015         if (op==NULL){\r
2016                 ms_error("Receiving register response for unknown operation");\r
2017                 return;\r
2018         }\r
2019         osip_message_get_expires(ev->request,0,&h);\r
2020         if (h!=NULL && atoi(h->hvalue)!=0){\r
2021                 registered=TRUE;\r
2022                 if (!register_again_with_updated_contact(op,ev->request,ev->response)){\r
2023                         sal->callbacks.register_success(op,registered);\r
2024                 }\r
2025         }else {\r
2026                 sal->callbacks.register_success(op,FALSE);\r
2027         }\r
2028 }\r
2029 \r
2030 static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){\r
2031         int status_code=0;\r
2032         const char *reason=NULL;\r
2033         SalOp *op=sal_find_register(sal,ev->rid);\r
2034         SalReason sr=SalReasonUnknown;\r
2035         SalError se=SalErrorUnknown;\r
2036         \r
2037         if (op==NULL){\r
2038                 ms_error("Receiving register failure for unknown operation");\r
2039                 return TRUE;\r
2040         }\r
2041         if (ev->response){\r
2042                 status_code=osip_message_get_status_code(ev->response);\r
2043                 reason=osip_message_get_reason_phrase(ev->response);\r
2044         }\r
2045         switch(status_code){\r
2046                 case 401:\r
2047                 case 407:\r
2048                         return process_authentication(sal,ev);\r
2049                         break;\r
2050                 case 423: /*interval too brief*/\r
2051                         {/*retry with greater interval */\r
2052                                 osip_header_t *h=NULL;\r
2053                                 osip_message_t *msg=NULL;\r
2054                                 osip_message_header_get_byname(ev->response,"min-expires",0,&h);\r
2055                                 if (h && h->hvalue && h->hvalue[0]!='\0'){\r
2056                                         int val=atoi(h->hvalue);\r
2057                                         if (val>op->expires)\r
2058                                                 op->expires=val;\r
2059                                 }else op->expires*=2;\r
2060                                 eXosip_lock();\r
2061                                 eXosip_register_build_register(op->rid,op->expires,&msg);\r
2062                                 eXosip_register_send_register(op->rid,msg);\r
2063                                 eXosip_unlock();\r
2064                         }\r
2065                 break;\r
2066                 case 606: /*Not acceptable, workaround for proxies that don't like private addresses\r
2067                                  in vias, such as ekiga.net \r
2068                                  On the opposite, freephonie.net bugs when via are masqueraded.\r
2069                                  */\r
2070                         op->masquerade_via=TRUE;\r
2071                 default:\r
2072                         /* if contact is up to date, process the failure, otherwise resend a new register with\r
2073                                 updated contact first, just in case the faillure is due to incorrect contact */\r
2074                         if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response))\r
2075                                 return TRUE; /*we are retrying with an updated contact*/\r
2076                         if (status_code==403){\r
2077                                 se=SalErrorFailure;\r
2078                                 sr=SalReasonForbidden;\r
2079                         }else if (status_code==0){\r
2080                                 se=SalErrorNoResponse;\r
2081                         }\r
2082                         sal->callbacks.register_failure(op,se,sr,reason);\r
2083         }\r
2084         return TRUE;\r
2085 }\r
2086 \r
2087 static void other_request_reply(Sal *sal,eXosip_event_t *ev){\r
2088         SalOp *op=find_op(sal,ev);\r
2089         if (op==NULL){\r
2090                 ms_warning("other_request_reply(): Receiving response to unknown request.");\r
2091                 return;\r
2092         }\r
2093         if (ev->response){\r
2094                 ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));\r
2095                 update_contact_from_response(op,ev->response);\r
2096                 if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)\r
2097                         sal->callbacks.ping_reply(op);\r
2098         }\r
2099         if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {\r
2100                 /*out of call message acknolegment*/\r
2101                 SalTextDeliveryStatus status=SalTextDeliveryFailed;\r
2102                 if (ev->response){\r
2103                         if (ev->response->status_code<200){\r
2104                                 status=SalTextDeliveryInProgress;\r
2105                         }else if (ev->response->status_code<300 && ev->response->status_code>=200){\r
2106                                 status=SalTextDeliveryDone;\r
2107                         }\r
2108                 }\r
2109                 sal->callbacks.text_delivery_update(op,status);\r
2110         }\r
2111 }\r
2112 \r
2113 static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){\r
2114         SalOp *op=find_op(sal,ev);\r
2115         if (ev->response){\r
2116                 if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){\r
2117                         if (op->sipfrag_pending){\r
2118                                 send_notify_for_refer(op->did,op->sipfrag_pending);\r
2119                                 op->sipfrag_pending=NULL;\r
2120                         }\r
2121                 }\r
2122         }\r
2123 }\r
2124 \r
2125 static bool_t process_event(Sal *sal, eXosip_event_t *ev){\r
2126         ms_message("linphone process event get a message %d\n",ev->type);\r
2127         switch(ev->type){\r
2128                 case EXOSIP_CALL_ANSWERED:\r
2129                         ms_message("CALL_ANSWERED\n");\r
2130                         call_accepted(sal,ev);\r
2131                         authentication_ok(sal,ev);\r
2132                         break;\r
2133                 case EXOSIP_CALL_CLOSED:\r
2134                 case EXOSIP_CALL_CANCELLED:\r
2135                         ms_message("CALL_CLOSED or CANCELLED\n");\r
2136                         call_terminated(sal,ev);\r
2137                         break;\r
2138                 case EXOSIP_CALL_TIMEOUT:\r
2139                 case EXOSIP_CALL_NOANSWER:\r
2140                         ms_message("CALL_TIMEOUT or NOANSWER\n");\r
2141                         return call_failure(sal,ev);\r
2142                         break;\r
2143                 case EXOSIP_CALL_REQUESTFAILURE:\r
2144                 case EXOSIP_CALL_GLOBALFAILURE:\r
2145                 case EXOSIP_CALL_SERVERFAILURE:\r
2146                         ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n");\r
2147                         return call_failure(sal,ev);\r
2148                         break;\r
2149                 case EXOSIP_CALL_RELEASED:\r
2150                         ms_message("CALL_RELEASED\n");\r
2151                         call_released(sal, ev);\r
2152                         break;\r
2153                 case EXOSIP_CALL_INVITE:\r
2154                         ms_message("CALL_NEW\n");\r
2155                         inc_new_call(sal,ev);\r
2156                         break;\r
2157                 case EXOSIP_CALL_REINVITE:\r
2158                         handle_reinvite(sal,ev);\r
2159                         break;\r
2160                 case EXOSIP_CALL_ACK:\r
2161                         ms_message("CALL_ACK");\r
2162                         handle_ack(sal,ev);\r
2163                         break;\r
2164                 case EXOSIP_CALL_REDIRECTED:\r
2165                         ms_message("CALL_REDIRECTED");\r
2166                         eXosip_default_action(ev);\r
2167                         break;\r
2168                 case EXOSIP_CALL_PROCEEDING:\r
2169                         ms_message("CALL_PROCEEDING");\r
2170                         call_proceeding(sal,ev);\r
2171                         break;\r
2172                 case EXOSIP_CALL_RINGING:\r
2173                         ms_message("CALL_RINGING");\r
2174                         call_ringing(sal,ev);\r
2175                         authentication_ok(sal,ev);\r
2176                         break;\r
2177                 case EXOSIP_CALL_MESSAGE_NEW:\r
2178                         ms_message("EXOSIP_CALL_MESSAGE_NEW");\r
2179                         call_message_new(sal,ev);\r
2180                         break;\r
2181                 case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:\r
2182                         if (ev->response &&\r
2183                                 (ev->response->status_code==407 || ev->response->status_code==401)){\r
2184                                  return process_authentication(sal,ev);\r
2185                         }\r
2186                         break;\r
2187                 case EXOSIP_CALL_MESSAGE_ANSWERED:\r
2188                         ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");\r
2189                         process_in_call_reply(sal,ev);\r
2190                 break;\r
2191                 case EXOSIP_IN_SUBSCRIPTION_NEW:\r
2192                         ms_message("CALL_IN_SUBSCRIPTION_NEW ");\r
2193                         sal_exosip_subscription_recv(sal,ev);\r
2194                         break;\r
2195                 case EXOSIP_IN_SUBSCRIPTION_RELEASED:\r
2196                         ms_message("CALL_SUBSCRIPTION_NEW ");\r
2197                         sal_exosip_in_subscription_closed(sal,ev);\r
2198                         break;\r
2199                 case EXOSIP_SUBSCRIPTION_UPDATE:\r
2200                         ms_message("CALL_SUBSCRIPTION_UPDATE");\r
2201                         break;\r
2202                 case EXOSIP_SUBSCRIPTION_NOTIFY:\r
2203                         ms_message("CALL_SUBSCRIPTION_NOTIFY");\r
2204                         sal_exosip_notify_recv(sal,ev);\r
2205                         break;\r
2206                 case EXOSIP_SUBSCRIPTION_ANSWERED:\r
2207                         ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);\r
2208                         sal_exosip_subscription_answered(sal,ev);\r
2209                         break;\r
2210                 case EXOSIP_SUBSCRIPTION_CLOSED:\r
2211                         ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");\r
2212                         sal_exosip_subscription_closed(sal,ev);\r
2213                         break;\r
2214                 case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:   /**< announce a request failure      */\r
2215                         if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){\r
2216                                 return process_authentication(sal,ev);\r
2217                         }\r
2218                 case EXOSIP_SUBSCRIPTION_SERVERFAILURE:\r
2219                 case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:\r
2220                         sal_exosip_subscription_closed(sal,ev);\r
2221                         break;\r
2222                 case EXOSIP_REGISTRATION_FAILURE:\r
2223                         ms_message("REGISTRATION_FAILURE\n");\r
2224                         return registration_failure(sal,ev);\r
2225                         break;\r
2226                 case EXOSIP_REGISTRATION_SUCCESS:\r
2227                         authentication_ok(sal,ev);\r
2228                         registration_success(sal,ev);\r
2229                         break;\r
2230                 case EXOSIP_MESSAGE_NEW:\r
2231                         other_request(sal,ev);\r
2232                         break;\r
2233                 case EXOSIP_MESSAGE_PROCEEDING:\r
2234                 case EXOSIP_MESSAGE_ANSWERED:\r
2235                 case EXOSIP_MESSAGE_REDIRECTED:\r
2236                 case EXOSIP_MESSAGE_SERVERFAILURE:\r
2237                 case EXOSIP_MESSAGE_GLOBALFAILURE:\r
2238                         other_request_reply(sal,ev);\r
2239                         break;\r
2240                 case EXOSIP_MESSAGE_REQUESTFAILURE:\r
2241                 case EXOSIP_NOTIFICATION_REQUESTFAILURE:\r
2242                         if (ev->response) {\r
2243                                 switch (ev->response->status_code) {\r
2244                                         case 407:\r
2245                                         case 401:\r
2246                                                 return process_authentication(sal,ev);\r
2247                                         case 412: {\r
2248                                                 eXosip_automatic_action ();\r
2249                                                 return 1;\r
2250                                         }\r
2251                                 }\r
2252                         }\r
2253                         other_request_reply(sal,ev);\r
2254                         break;\r
2255                 default:\r
2256                         ms_message("Unhandled exosip event ! %i",ev->type);\r
2257                         break;\r
2258         }\r
2259         return TRUE;\r
2260 }\r
2261 \r
2262 int sal_iterate(Sal *sal){\r
2263         eXosip_event_t *ev;\r
2264         while((ev=eXosip_event_wait(0,0))!=NULL){\r
2265                 if (process_event(sal,ev))\r
2266                         eXosip_event_free(ev);\r
2267         }\r
2268 #ifdef HAVE_EXOSIP_TRYLOCK\r
2269         if (eXosip_trylock()==0){\r
2270                 eXosip_automatic_refresh();\r
2271                 eXosip_unlock();\r
2272         }else{\r
2273                 ms_warning("eXosip_trylock busy.");\r
2274         }\r
2275 #else\r
2276         eXosip_lock();\r
2277         eXosip_automatic_refresh();\r
2278         eXosip_unlock();\r
2279 #endif\r
2280         return 0;\r
2281 }\r
2282 \r
2283 static void register_set_contact(osip_message_t *msg, const char *contact){\r
2284         osip_uri_param_t *param = NULL;\r
2285         osip_contact_t *ct=NULL;\r
2286         char *line=NULL;\r
2287         /*we get the line parameter choosed by exosip, and add it to our own contact*/\r
2288         osip_message_get_contact(msg,0,&ct);\r
2289         if (ct!=NULL){\r
2290                 osip_uri_uparam_get_byname(ct->url, "line", &param);\r
2291                 if (param && param->gvalue)\r
2292                         line=osip_strdup(param->gvalue);\r
2293         }\r
2294         _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
2295         osip_message_set_contact(msg,contact);\r
2296         osip_message_get_contact(msg,0,&ct);\r
2297         osip_uri_uparam_add(ct->url,osip_strdup("line"),line);\r
2298 }\r
2299 \r
2300 static void sal_register_add_route(osip_message_t *msg, const char *proxy){\r
2301         osip_route_t *route;\r
2302 \r
2303         osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);\r
2304         \r
2305         osip_route_init(&route);\r
2306         if (osip_route_parse(route,proxy)==0){\r
2307                 osip_uri_param_t *lr_param = NULL;\r
2308                 osip_uri_uparam_get_byname(route->url, "lr", &lr_param);\r
2309                 if (lr_param == NULL){\r
2310                         osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);\r
2311                 }\r
2312                 osip_list_add(&msg->routes,route,0);\r
2313                 return;\r
2314         }\r
2315         osip_route_free(route);\r
2316 }\r
2317 \r
2318 \r
2319 int sal_register(SalOp *h, const char *proxy, const char *from, int expires){\r
2320         osip_message_t *msg;\r
2321         const char *contact=sal_op_get_contact(h);\r
2322 \r
2323         sal_op_set_route(h,proxy);\r
2324         if (h->rid==-1){\r
2325                 SalAddress *from_parsed=sal_address_new(from);\r
2326                 char domain[256];\r
2327                 char *uri, *domain_ptr = NULL;\r
2328                 if (from_parsed==NULL) {\r
2329                         ms_warning("sal_register() bad from %s",from);\r
2330                         return -1;\r
2331                 }\r
2332                 /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of\r
2333                    using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */\r
2334                 uri = sal_address_as_string_uri_only(from_parsed);\r
2335                 if (uri) domain_ptr = strchr(uri, '@');\r
2336                 if (domain_ptr) {\r
2337                         snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);\r
2338                 } else {\r
2339                         snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));\r
2340                 }\r
2341                 if (uri) ms_free(uri);\r
2342                 sal_address_destroy(from_parsed);\r
2343                 eXosip_lock();\r
2344                 h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);\r
2345                 if (msg){\r
2346                         if (contact) register_set_contact(msg,contact);\r
2347                         sal_register_add_route(msg,proxy);\r
2348                         sal_add_register(h->base.root,h);\r
2349                 }else{\r
2350                         ms_error("Could not build initial register.");\r
2351                         eXosip_unlock();\r
2352                         return -1;\r
2353                 }\r
2354         }else{\r
2355                 eXosip_lock();\r
2356                 eXosip_register_build_register(h->rid,expires,&msg);\r
2357                 sal_register_add_route(msg,proxy);\r
2358         }\r
2359         if (msg){\r
2360                 eXosip_register_send_register(h->rid,msg);\r
2361         }\r
2362         eXosip_unlock();\r
2363         h->expires=expires;\r
2364         return (msg != NULL) ? 0 : -1;\r
2365 }\r
2366 \r
2367 int sal_register_refresh(SalOp *op, int expires){\r
2368         osip_message_t *msg=NULL;\r
2369         const char *contact=sal_op_get_contact(op);\r
2370         \r
2371         if (op->rid==-1){\r
2372                 ms_error("Unexistant registration context, not possible to refresh.");\r
2373                 return -1;\r
2374         }\r
2375 #ifdef HAVE_EXOSIP_TRYLOCK\r
2376         {\r
2377                 int tries=0;\r
2378                 /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.\r
2379                 * 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
2380                 * the exosip lock in a non blocking way, and give up if it takes too long*/\r
2381                 while (eXosip_trylock()!=0){\r
2382                         ms_usleep(100000);\r
2383                         if (tries>30) {/*after 3 seconds, give up*/\r
2384                                 ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");\r
2385                                 return -1;\r
2386                         }\r
2387                 }\r
2388         }\r
2389 #else\r
2390         eXosip_lock();\r
2391 #endif\r
2392         eXosip_register_build_register(op->rid,expires,&msg);\r
2393         if (msg!=NULL){\r
2394                 if (contact) register_set_contact(msg,contact);\r
2395                 sal_register_add_route(msg,sal_op_get_route(op));\r
2396                 eXosip_register_send_register(op->rid,msg);\r
2397         }else ms_error("Could not build REGISTER refresh message.");\r
2398         eXosip_unlock();\r
2399         return (msg != NULL) ? 0 : -1;\r
2400 }\r
2401 \r
2402 \r
2403 int sal_unregister(SalOp *h){\r
2404         osip_message_t *msg=NULL;\r
2405         eXosip_lock();\r
2406         eXosip_register_build_register(h->rid,0,&msg);\r
2407         if (msg) eXosip_register_send_register(h->rid,msg);\r
2408         else ms_warning("Could not build unREGISTER !");\r
2409         eXosip_unlock();\r
2410         return 0;\r
2411 }\r
2412 \r
2413 SalAddress * sal_address_new(const char *uri){\r
2414         osip_from_t *from;\r
2415         osip_from_init(&from);\r
2416 \r
2417         // Remove front spaces\r
2418         while (uri[0]==' ') {\r
2419                 uri++;\r
2420         }\r
2421                 \r
2422         if (osip_from_parse(from,uri)!=0){\r
2423                 osip_from_free(from);\r
2424                 return NULL;\r
2425         }\r
2426         if (from->displayname!=NULL && from->displayname[0]=='"'){\r
2427                 char *unquoted=osip_strdup_without_quote(from->displayname);\r
2428                 osip_free(from->displayname);\r
2429                 from->displayname=unquoted;\r
2430         }\r
2431         return (SalAddress*)from;\r
2432 }\r
2433 \r
2434 SalAddress * sal_address_clone(const SalAddress *addr){\r
2435         osip_from_t *ret=NULL;\r
2436         osip_from_clone((osip_from_t*)addr,&ret);\r
2437         return (SalAddress*)ret;\r
2438 }\r
2439 \r
2440 #define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )\r
2441 \r
2442 const char *sal_address_get_scheme(const SalAddress *addr){\r
2443         const osip_from_t *u=(const osip_from_t*)addr;\r
2444         return null_if_empty(u->url->scheme);\r
2445 }\r
2446 \r
2447 const char *sal_address_get_display_name(const SalAddress* addr){\r
2448         const osip_from_t *u=(const osip_from_t*)addr;\r
2449         return null_if_empty(u->displayname);\r
2450 }\r
2451 \r
2452 const char *sal_address_get_username(const SalAddress *addr){\r
2453         const osip_from_t *u=(const osip_from_t*)addr;\r
2454         return null_if_empty(u->url->username);\r
2455 }\r
2456 \r
2457 const char *sal_address_get_domain(const SalAddress *addr){\r
2458         const osip_from_t *u=(const osip_from_t*)addr;\r
2459         return null_if_empty(u->url->host);\r
2460 }\r
2461 \r
2462 void sal_address_set_display_name(SalAddress *addr, const char *display_name){\r
2463         osip_from_t *u=(osip_from_t*)addr;\r
2464         if (u->displayname!=NULL){\r
2465                 osip_free(u->displayname);\r
2466                 u->displayname=NULL;\r
2467         }\r
2468         if (display_name!=NULL && display_name[0]!='\0'){\r
2469                 u->displayname=osip_strdup(display_name);\r
2470         }\r
2471 }\r
2472 \r
2473 void sal_address_set_username(SalAddress *addr, const char *username){\r
2474         osip_from_t *uri=(osip_from_t*)addr;\r
2475         if (uri->url->username!=NULL){\r
2476                 osip_free(uri->url->username);\r
2477                 uri->url->username=NULL;\r
2478         }\r
2479         if (username)\r
2480                 uri->url->username=osip_strdup(username);\r
2481 }\r
2482 \r
2483 void sal_address_set_domain(SalAddress *addr, const char *host){\r
2484         osip_from_t *uri=(osip_from_t*)addr;\r
2485         if (uri->url->host!=NULL){\r
2486                 osip_free(uri->url->host);\r
2487                 uri->url->host=NULL;\r
2488         }\r
2489         if (host)\r
2490                 uri->url->host=osip_strdup(host);\r
2491 }\r
2492 \r
2493 void sal_address_set_port(SalAddress *addr, const char *port){\r
2494         osip_from_t *uri=(osip_from_t*)addr;\r
2495         if (uri->url->port!=NULL){\r
2496                 osip_free(uri->url->port);\r
2497                 uri->url->port=NULL;\r
2498         }\r
2499         if (port)\r
2500                 uri->url->port=osip_strdup(port);\r
2501 }\r
2502 \r
2503 void sal_address_set_port_int(SalAddress *uri, int port){\r
2504         char tmp[12];\r
2505         if (port==5060){\r
2506                 /*this is the default, special case to leave the port field blank*/\r
2507                 sal_address_set_port(uri,NULL);\r
2508                 return;\r
2509         }\r
2510         snprintf(tmp,sizeof(tmp),"%i",port);\r
2511         sal_address_set_port(uri,tmp);\r
2512 }\r
2513 \r
2514 void sal_address_clean(SalAddress *addr){\r
2515         osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params);\r
2516         osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params);\r
2517 }\r
2518 \r
2519 char *sal_address_as_string(const SalAddress *u){\r
2520         char *tmp,*ret;\r
2521         osip_from_t *from=(osip_from_t *)u;\r
2522         char *old_displayname=NULL;\r
2523         /* hack to force use of quotes around the displayname*/\r
2524         if (from->displayname!=NULL\r
2525             && from->displayname[0]!='"'){\r
2526                 old_displayname=from->displayname;\r
2527                 from->displayname=osip_enquote(from->displayname);\r
2528         }\r
2529         osip_from_to_str(from,&tmp);\r
2530         if (old_displayname!=NULL){\r
2531                 ms_free(from->displayname);\r
2532                 from->displayname=old_displayname;\r
2533         }\r
2534         ret=ms_strdup(tmp);\r
2535         osip_free(tmp);\r
2536         return ret;\r
2537 }\r
2538 \r
2539 char *sal_address_as_string_uri_only(const SalAddress *u){\r
2540         char *tmp=NULL,*ret;\r
2541         osip_uri_to_str(((osip_from_t*)u)->url,&tmp);\r
2542         ret=ms_strdup(tmp);\r
2543         osip_free(tmp);\r
2544         return ret;\r
2545 }\r
2546 void sal_address_set_param(SalAddress *u,const char* name,const char* value) {\r
2547         osip_uri_param_t *param=NULL;\r
2548     osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,&param);\r
2549     if (param == NULL){\r
2550         osip_uri_uparam_add     (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL);\r
2551     } else {\r
2552         osip_free(param->gvalue);\r
2553         param->gvalue=value ? osip_strdup(value) : NULL;\r
2554     }\r
2555     \r
2556 }\r
2557 \r
2558 void sal_address_destroy(SalAddress *u){\r
2559         osip_from_free((osip_from_t*)u);\r
2560 }\r
2561 \r
2562 void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {\r
2563         ctx->tcp_tls_keepalive = enabled;\r
2564 }\r
2565 \r
2566 void sal_set_keepalive_period(Sal *ctx,unsigned int value) {\r
2567         switch (ctx->transport) {\r
2568                 case SalTransportUDP:\r
2569                         ctx->keepalive_period = value;\r
2570                         break;\r
2571                 case SalTransportTCP:\r
2572                 case SalTransportTLS:\r
2573                         if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value;\r
2574                         else ctx->keepalive_period = -1;\r
2575                         break;\r
2576                 default:\r
2577                         break;\r
2578         }\r
2579         eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);\r
2580 }\r
2581 unsigned int sal_get_keepalive_period(Sal *ctx) {\r
2582         return ctx->keepalive_period;\r
2583 }\r
2584 \r
2585 const char * sal_address_get_port(const SalAddress *addr) {\r
2586         const osip_from_t *u=(const osip_from_t*)addr;\r
2587         return null_if_empty(u->url->port);\r
2588 }\r
2589 \r
2590 int sal_address_get_port_int(const SalAddress *uri) {\r
2591         const char* port = sal_address_get_port(uri);\r
2592         if (port != NULL) {\r
2593                 return atoi(port);\r
2594         } else {\r
2595                 return 5060;\r
2596         }\r
2597 }\r
2598 SalTransport sal_address_get_transport(const SalAddress* addr) {\r
2599     const osip_from_t *u=(const osip_from_t*)addr;\r
2600     osip_uri_param_t *transport_param=NULL;\r
2601     osip_uri_uparam_get_byname(u->url,"transport",&transport_param);\r
2602     if (transport_param == NULL){\r
2603         return SalTransportUDP;\r
2604     }  else {\r
2605         return sal_transport_parse(transport_param->gvalue);\r
2606     }\r
2607 }\r
2608 void sal_address_set_transport(SalAddress* addr,SalTransport transport) {\r
2609     sal_address_set_param(addr, "transport", sal_transport_to_string(transport));\r
2610 }\r
2611 \r
2612 /* sends a reinvite. Local media description may have changed by application since call establishment*/\r
2613 int sal_call_update(SalOp *h, const char *subject){\r
2614         int err=0;\r
2615         osip_message_t *reinvite=NULL;\r
2616 \r
2617         eXosip_lock();\r
2618         if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){\r
2619                 eXosip_unlock();\r
2620                 return -1;\r
2621         }\r
2622         eXosip_unlock();\r
2623         osip_message_set_subject(reinvite,subject);\r
2624         osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");\r
2625         if (h->base.contact){\r
2626                 _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);\r
2627                 osip_message_set_contact(reinvite,h->base.contact);\r
2628         }\r
2629         if (h->base.root->session_expires!=0){\r
2630                 osip_message_set_header(reinvite, "Session-expires", "200");\r
2631                 osip_message_set_supported(reinvite, "timer");\r
2632         }\r
2633         if (h->base.local_media){\r
2634                 h->sdp_offering=TRUE;\r
2635                 set_sdp_from_desc(reinvite,h->base.local_media);\r
2636         }else h->sdp_offering=FALSE;\r
2637         eXosip_lock();\r
2638         err = eXosip_call_send_request(h->did, reinvite);\r
2639         eXosip_unlock();\r
2640         return err;\r
2641 }\r
2642 \r
2643 void sal_reuse_authorization(Sal *ctx, bool_t value) {\r
2644         ctx->reuse_authorization=value;\r
2645 }\r
2646 \r
2647 void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){\r
2648         MSList *elem=(MSList*)ch;\r
2649         for (;elem!=NULL;elem=elem->next){\r
2650                 SalCustomHeader *it=(SalCustomHeader*)elem;\r
2651                 osip_message_set_header(msg,it->header_name,it->header_value);\r
2652         }\r
2653 }\r
2654 \r
2655 SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){\r
2656         int i=0;\r
2657         osip_header_t *header;\r
2658         SalCustomHeader *ret=NULL;\r
2659 \r
2660         while((header=osip_list_get(&msg->headers,i))!=NULL){\r
2661                 ret=sal_custom_header_append(ret,header->hname,header->hvalue);\r
2662                 i++;\r
2663         }\r
2664         return ret;\r
2665 }\r
2666 \r