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