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