File: | libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c |
Location: | line 489, column 30 |
Description: | Access to field 'du_cr' results in a dereference of a null pointer (loaded from variable 'du') |
1 | /* | |||||
2 | * This file is part of the Sofia-SIP package | |||||
3 | * | |||||
4 | * Copyright (C) 2006 Nokia Corporation. | |||||
5 | * | |||||
6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||||
7 | * | |||||
8 | * This library is free software; you can redistribute it and/or | |||||
9 | * modify it under the terms of the GNU Lesser General Public License | |||||
10 | * as published by the Free Software Foundation; either version 2.1 of | |||||
11 | * the License, or (at your option) any later version. | |||||
12 | * | |||||
13 | * This library is distributed in the hope that it will be useful, but | |||||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
16 | * Lesser General Public License for more details. | |||||
17 | * | |||||
18 | * You should have received a copy of the GNU Lesser General Public | |||||
19 | * License along with this library; if not, write to the Free Software | |||||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||||
21 | * 02110-1301 USA | |||||
22 | * | |||||
23 | */ | |||||
24 | ||||||
25 | /**@CFILE nua_subnotref.c | |||||
26 | * @brief Subscriber (event watcher) | |||||
27 | * | |||||
28 | * This file contains implementation SUBSCRIBE UAC, NOTIFY UAS, REFER UAC. | |||||
29 | * The implementation of SUBSCRIBE UAS, NOTIFY UAC and REFER UAS is in | |||||
30 | * nua_notifier.c. | |||||
31 | * Alternative implementation using nea is in nua_event_server.c. | |||||
32 | * | |||||
33 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> | |||||
34 | * | |||||
35 | * @date Created: Wed Mar 8 15:10:08 EET 2006 ppessi | |||||
36 | */ | |||||
37 | ||||||
38 | #include "config.h" | |||||
39 | ||||||
40 | #include <stddef.h> | |||||
41 | #include <stdlib.h> | |||||
42 | #include <string.h> | |||||
43 | #include <limits.h> | |||||
44 | ||||||
45 | #include <assert.h> | |||||
46 | ||||||
47 | #include <sofia-sip/su_string.h> | |||||
48 | #include <sofia-sip/sip_protos.h> | |||||
49 | #include <sofia-sip/sip_status.h> | |||||
50 | #include <sofia-sip/sip_extra.h> | |||||
51 | #include <sofia-sip/sip_util.h> | |||||
52 | #include <sofia-sip/su_uniqueid.h> | |||||
53 | ||||||
54 | #include "nua_stack.h" | |||||
55 | ||||||
56 | /* ---------------------------------------------------------------------- */ | |||||
57 | /* Subcriber event usage */ | |||||
58 | ||||||
59 | struct event_usage | |||||
60 | { | |||||
61 | enum nua_substate eu_substate; /**< Subscription state */ | |||||
62 | unsigned eu_delta; /**< Proposed expiration */ | |||||
63 | sip_time_t eu_expires; /**< Absolute expiration time */ | |||||
64 | unsigned eu_notified; /**< Number of NOTIFYs received */ | |||||
65 | unsigned eu_unsolicited:1; /**< Not SUBSCRIBEd or REFERed */ | |||||
66 | unsigned eu_refer:1; /**< Implied subscription by refer */ | |||||
67 | unsigned eu_final_wait:1; /**< Waiting for final NOTIFY */ | |||||
68 | unsigned eu_no_id:1; /**< Do not use "id" (even if we have one) */ | |||||
69 | }; | |||||
70 | ||||||
71 | static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du); | |||||
72 | static int nua_subscribe_usage_add(nua_handle_t *nh, | |||||
73 | nua_dialog_state_t *ds, | |||||
74 | nua_dialog_usage_t *du); | |||||
75 | static void nua_subscribe_usage_remove(nua_handle_t *nh, | |||||
76 | nua_dialog_state_t *ds, | |||||
77 | nua_dialog_usage_t *du, | |||||
78 | nua_client_request_t *cr, | |||||
79 | nua_server_request_t *sr); | |||||
80 | static void nua_subscribe_usage_refresh(nua_handle_t *, | |||||
81 | nua_dialog_state_t *, | |||||
82 | nua_dialog_usage_t *, | |||||
83 | sip_time_t); | |||||
84 | static int nua_subscribe_usage_shutdown(nua_handle_t *, | |||||
85 | nua_dialog_state_t *, | |||||
86 | nua_dialog_usage_t *); | |||||
87 | ||||||
88 | static nua_usage_class const nua_subscribe_usage[1] = { | |||||
89 | { | |||||
90 | sizeof (struct event_usage), (sizeof nua_subscribe_usage), | |||||
91 | nua_subscribe_usage_add, | |||||
92 | nua_subscribe_usage_remove, | |||||
93 | nua_subscribe_usage_name, | |||||
94 | nua_base_usage_update_params, | |||||
95 | NULL((void*)0), | |||||
96 | nua_subscribe_usage_refresh, | |||||
97 | nua_subscribe_usage_shutdown | |||||
98 | }}; | |||||
99 | ||||||
100 | static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du) | |||||
101 | { | |||||
102 | return "subscribe"; | |||||
103 | } | |||||
104 | ||||||
105 | static | |||||
106 | int nua_subscribe_usage_add(nua_handle_t *nh, | |||||
107 | nua_dialog_state_t *ds, | |||||
108 | nua_dialog_usage_t *du) | |||||
109 | { | |||||
110 | ds->ds_has_events++; | |||||
111 | ds->ds_has_subscribes++; | |||||
112 | ||||||
113 | return 0; | |||||
114 | } | |||||
115 | ||||||
116 | static | |||||
117 | void nua_subscribe_usage_remove(nua_handle_t *nh, | |||||
118 | nua_dialog_state_t *ds, | |||||
119 | nua_dialog_usage_t *du, | |||||
120 | nua_client_request_t *cr, | |||||
121 | nua_server_request_t *sr) | |||||
122 | { | |||||
123 | ds->ds_has_events--; | |||||
124 | ds->ds_has_subscribes--; | |||||
125 | } | |||||
126 | ||||||
127 | /* ====================================================================== */ | |||||
128 | /* SUBSCRIBE */ | |||||
129 | ||||||
130 | /**@fn void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); | |||||
131 | * | |||||
132 | * Subscribe to a SIP event. | |||||
133 | * | |||||
134 | * Subscribe a SIP event using the SIP SUBSCRIBE request. If the | |||||
135 | * SUBSCRBE is successful a subscription state is established and | |||||
136 | * the subscription is refreshed regularly. The refresh requests will | |||||
137 | * generate #nua_r_subscribe events. | |||||
138 | * | |||||
139 | * @param nh Pointer to operation handle | |||||
140 | * @param tag, value, ... List of tagged parameters | |||||
141 | * | |||||
142 | * @return | |||||
143 | * nothing | |||||
144 | * | |||||
145 | * @par Related Tags: | |||||
146 | * NUTAG_URL() | |||||
147 | * Header tags defined in <sofia-sip/sip_tag.h> | |||||
148 | * | |||||
149 | * @par Events: | |||||
150 | * #nua_r_subscribe \n | |||||
151 | * #nua_i_notify | |||||
152 | * | |||||
153 | * @sa NUTAG_SUBSTATE(), @RFC3265 | |||||
154 | */ | |||||
155 | ||||||
156 | /**@fn void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); | |||||
157 | * | |||||
158 | * Unsubscribe an event. | |||||
159 | * | |||||
160 | * Unsubscribe an active or pending subscription with SUBSCRIBE request | |||||
161 | * containing Expires: header with value 0. The dialog associated with | |||||
162 | * subscription will be destroyed if there is no other subscriptions or | |||||
163 | * call using this dialog. | |||||
164 | * | |||||
165 | * @param nh Pointer to operation handle | |||||
166 | * @param tag, value, ... List of tagged parameters | |||||
167 | * | |||||
168 | * @return | |||||
169 | * nothing | |||||
170 | * | |||||
171 | * @par Related Tags: | |||||
172 | * SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n | |||||
173 | * Header tags defined in <sofia-sip/sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR() | |||||
174 | * | |||||
175 | * @par Events: | |||||
176 | * #nua_r_unsubscribe | |||||
177 | * | |||||
178 | * @sa NUTAG_SUBSTATE(), @RFC3265 | |||||
179 | */ | |||||
180 | ||||||
181 | static int nua_subscribe_client_init(nua_client_request_t *cr, | |||||
182 | msg_t *, sip_t *, | |||||
183 | tagi_t const *tags); | |||||
184 | static int nua_subscribe_client_request(nua_client_request_t *cr, | |||||
185 | msg_t *, sip_t *, | |||||
186 | tagi_t const *tags); | |||||
187 | static int nua_subscribe_client_response(nua_client_request_t *cr, | |||||
188 | int status, char const *phrase, | |||||
189 | sip_t const *sip); | |||||
190 | ||||||
191 | static nua_client_methods_t const nua_subscribe_client_methods = { | |||||
192 | SIP_METHOD_SUBSCRIBEsip_method_subscribe, "SUBSCRIBE", /* crm_method, crm_method_name */ | |||||
193 | 0, /* crm_extra */ | |||||
194 | { /* crm_flags */ | |||||
195 | /* create_dialog */ 1, | |||||
196 | /* in_dialog */ 1, | |||||
197 | /* target refresh */ 1 | |||||
198 | }, | |||||
199 | NULL((void*)0), /* crm_template */ | |||||
200 | nua_subscribe_client_init, /* crm_init */ | |||||
201 | nua_subscribe_client_request, /* crm_send */ | |||||
202 | NULL((void*)0), /* crm_check_restart */ | |||||
203 | nua_subscribe_client_response, /* crm_recv */ | |||||
204 | NULL((void*)0), /* crm_preliminary */ | |||||
205 | NULL((void*)0), /* crm_report */ | |||||
206 | NULL((void*)0), /* crm_complete */ | |||||
207 | }; | |||||
208 | ||||||
209 | int | |||||
210 | nua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e, | |||||
211 | tagi_t const *tags) | |||||
212 | { | |||||
213 | return nua_client_create(nh, e, &nua_subscribe_client_methods, tags); | |||||
214 | } | |||||
215 | ||||||
216 | static int nua_subscribe_client_init(nua_client_request_t *cr, | |||||
217 | msg_t *msg, sip_t *sip, | |||||
218 | tagi_t const *tags) | |||||
219 | { | |||||
220 | nua_handle_t *nh = cr->cr_owner; | |||||
221 | nua_dialog_usage_t *du; | |||||
222 | sip_event_t *o = sip->sip_event; | |||||
223 | ||||||
224 | du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o); | |||||
225 | ||||||
226 | if (du == NULL((void*)0) && o == NULL((void*)0)) | |||||
227 | du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE((void *)-1)); | |||||
228 | ||||||
229 | if (du) { | |||||
230 | if (du->du_event && o == NULL((void*)0)) | |||||
231 | /* Add Event header */ | |||||
232 | sip_add_dup(msg, sip, (sip_header_t *)du->du_event); | |||||
233 | } | |||||
234 | else if (cr->cr_event == nua_r_subscribe) { | |||||
235 | /* Create dialog usage */ | |||||
236 | du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o); | |||||
237 | /* Note that we allow SUBSCRIBE without event */ | |||||
238 | } | |||||
239 | ||||||
240 | cr->cr_usage = du; | |||||
241 | ||||||
242 | return 0; | |||||
243 | } | |||||
244 | ||||||
245 | static int nua_subscribe_client_request(nua_client_request_t *cr, | |||||
246 | msg_t *msg, sip_t *sip, | |||||
247 | tagi_t const *tags) | |||||
248 | { | |||||
249 | nua_dialog_usage_t *du = cr->cr_usage; | |||||
250 | sip_time_t expires = 0; | |||||
251 | ||||||
252 | if (cr->cr_event == nua_r_destroy || !du || du->du_shutdown) | |||||
253 | nua_client_set_terminating(cr, 1); | |||||
254 | ||||||
255 | if (du) { | |||||
256 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
257 | sip_event_t *o = sip->sip_event; | |||||
258 | ||||||
259 | if (nua_client_bind(cr, du) < 0) | |||||
260 | return -1; | |||||
261 | ||||||
262 | if (eu->eu_no_id && o && o->o_id) { | |||||
263 | /* Notifier does not handle id properly, remove it */ | |||||
264 | msg_header_remove_param(o->o_common, "id"); | |||||
265 | } | |||||
266 | ||||||
267 | #if 0 | |||||
268 | if (cr->cr_terminating) { | |||||
269 | /* Already terminated subscription? */ | |||||
270 | if (eu->eu_substate == nua_substate_terminated || | |||||
271 | eu->eu_substate == nua_substate_embryonic) { | |||||
272 | return nua_client_return(cr, SIP_200_OK200, sip_200_OK, msg); | |||||
273 | } | |||||
274 | } | |||||
275 | #endif | |||||
276 | ||||||
277 | nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */ | |||||
278 | ||||||
279 | if (cr->cr_terminating || cr->cr_event != nua_r_subscribe) | |||||
280 | expires = eu->eu_delta = 0; | |||||
281 | else if (sip->sip_expires) | |||||
282 | /* Use value specified by application or negotiated with Min-Expires */ | |||||
283 | expires = eu->eu_delta = sip->sip_expires->ex_delta; | |||||
284 | else | |||||
285 | /* We just use common default value, but the default is actually | |||||
286 | package-specific according to the RFC 3265 section 4.4.4: | |||||
287 | [Event] packages MUST also define a | |||||
288 | default "Expires" value to be used if none is specified. */ | |||||
289 | expires = eu->eu_delta = 3600; | |||||
290 | ||||||
291 | eu->eu_final_wait = 0; | |||||
292 | ||||||
293 | if (eu->eu_substate == nua_substate_terminated) | |||||
294 | eu->eu_substate = nua_substate_embryonic; | |||||
295 | } | |||||
296 | ||||||
297 | if (!sip->sip_expires || sip->sip_expires->ex_delta != expires) { | |||||
298 | sip_expires_t ex[1]; | |||||
299 | sip_expires_init(ex)->ex_delta = expires; | |||||
300 | sip_add_dup(msg, sip, (sip_header_t *)ex); | |||||
301 | } | |||||
302 | ||||||
303 | return nua_base_client_request(cr, msg, sip, tags); | |||||
304 | } | |||||
305 | ||||||
306 | /** @NUA_EVENT nua_r_subscribe | |||||
307 | * | |||||
308 | * Response to an outgoing SUBSCRIBE request. | |||||
309 | * | |||||
310 | * The SUBSCRIBE request may have been sent explicitly by nua_subscribe() or | |||||
311 | * implicitly by NUA state machine. | |||||
312 | * | |||||
313 | * @param status response status code | |||||
314 | * (if the request is retried, @a status is 100, the @a | |||||
315 | * sip->sip_status->st_status contain the real status code | |||||
316 | * from the response message, e.g., 302, 401, or 407) | |||||
317 | * @param phrase a short textual description of @a status code | |||||
318 | * @param nh operation handle associated with the subscription | |||||
319 | * @param hmagic application context associated with the handle | |||||
320 | * @param sip response to SUBSCRIBE request or NULL upon an error | |||||
321 | * (status code is in @a status and | |||||
322 | * descriptive message in @a phrase parameters) | |||||
323 | * @param tags NUTAG_SUBSTATE() | |||||
324 | * | |||||
325 | * @sa nua_subscribe(), @RFC3265 | |||||
326 | * | |||||
327 | * @END_NUA_EVENT | |||||
328 | */ | |||||
329 | ||||||
330 | /** @NUA_EVENT nua_r_unsubscribe | |||||
331 | * | |||||
332 | * Response to an outgoing un-SUBSCRIBE. | |||||
333 | * | |||||
334 | * @param status response status code | |||||
335 | * (if the request is retried, @a status is 100, the @a | |||||
336 | * sip->sip_status->st_status contain the real status code | |||||
337 | * from the response message, e.g., 302, 401, or 407) | |||||
338 | * @param phrase a short textual description of @a status code | |||||
339 | * @param nh operation handle associated with the subscription | |||||
340 | * @param hmagic application context associated with the handle | |||||
341 | * @param sip response to SUBSCRIBE request or NULL upon an error | |||||
342 | * (status code is in @a status and | |||||
343 | * descriptive message in @a phrase parameters) | |||||
344 | * @param tags NUTAG_SUBSTATE() | |||||
345 | * | |||||
346 | * @sa nua_unsubscribe(), @RFC3265 | |||||
347 | * | |||||
348 | * @END_NUA_EVENT | |||||
349 | */ | |||||
350 | ||||||
351 | static int nua_subscribe_client_response(nua_client_request_t *cr, | |||||
352 | int status, char const *phrase, | |||||
353 | sip_t const *sip) | |||||
354 | { | |||||
355 | nua_handle_t *nh = cr->cr_owner; | |||||
356 | nua_dialog_usage_t *du = cr->cr_usage; | |||||
357 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
358 | enum nua_substate substate; | |||||
359 | ||||||
360 | if (eu == NULL((void*)0) || cr->cr_terminated) | |||||
361 | substate = nua_substate_terminated; | |||||
362 | else if (status >= 300) | |||||
363 | substate = eu->eu_substate; | |||||
364 | else { | |||||
365 | int win_messenger_enable = NH_PGET(nh, win_messenger_enable)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_win_messenger_enable ? ((nh)->nh_prefs)->nhp_win_messenger_enable : ((nh)-> nh_nua->nua_handles->nh_prefs)->nhp_win_messenger_enable ); | |||||
366 | sip_time_t delta, now = sip_now(); | |||||
367 | ||||||
368 | du->du_ready = 1; | |||||
369 | ||||||
370 | if (eu->eu_substate != nua_substate_terminated) | |||||
371 | /* If there is no @Expires header, | |||||
372 | use default value stored in eu_delta */ | |||||
373 | delta = sip_contact_expires(NULL((void*)0), sip->sip_expires, sip->sip_date, | |||||
374 | eu->eu_delta, now); | |||||
375 | else | |||||
376 | delta = 0; | |||||
377 | ||||||
378 | if (delta > eu->eu_delta) | |||||
379 | delta = eu->eu_delta; | |||||
380 | ||||||
381 | if (win_messenger_enable && !nua_dialog_is_established(nh->nh_ds)) { | |||||
382 | /* Notify from messanger does not match with dialog tag */ | |||||
383 | nh->nh_ds->ds_remote_tag = su_strdup(nh->nh_home, ""); | |||||
384 | } | |||||
385 | ||||||
386 | if (delta > 0) { | |||||
387 | nua_dialog_usage_set_refresh(du, delta); | |||||
388 | eu->eu_expires = du->du_refquested + delta; | |||||
389 | } | |||||
390 | else { | |||||
391 | if (eu->eu_substate == nua_substate_terminated) { | |||||
392 | if (!eu->eu_notified) | |||||
393 | eu->eu_substate = nua_substate_embryonic; | |||||
394 | } | |||||
395 | ||||||
396 | if (eu->eu_substate != nua_substate_terminated) { | |||||
397 | /* Wait 32 seconds for NOTIFY. */ | |||||
398 | delta = 64 * NTA_SIP_T1 / 1000; | |||||
399 | ||||||
400 | eu->eu_final_wait = 1; | |||||
401 | ||||||
402 | if (!eu->eu_notified && win_messenger_enable) | |||||
403 | delta = 4 * 60; /* Wait 4 minutes for NOTIFY from Messenger */ | |||||
404 | ||||||
405 | nua_dialog_usage_set_refresh_range(du, delta, delta); | |||||
406 | } | |||||
407 | else { | |||||
408 | nua_dialog_usage_reset_refresh(du); | |||||
409 | } | |||||
410 | ||||||
411 | eu->eu_expires = du->du_refquested; | |||||
412 | } | |||||
413 | ||||||
414 | substate = eu->eu_substate; | |||||
415 | ||||||
416 | if (substate == nua_substate_terminated) | |||||
417 | /* let nua_base_client_tresponse to remove usage */ | |||||
418 | cr->cr_terminated = 1; | |||||
419 | } | |||||
420 | ||||||
421 | return nua_base_client_tresponse(cr, status, phrase, sip, | |||||
422 | NUTAG_SUBSTATE(substate)nutag_substate, tag_int_v(substate), | |||||
423 | SIPTAG_EVENT(du ? du->du_event : NULL)siptag_event, siptag_event_v(du ? du->du_event : ((void*)0 )), | |||||
424 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
425 | } | |||||
426 | ||||||
427 | /** Refresh subscription */ | |||||
428 | static void nua_subscribe_usage_refresh(nua_handle_t *nh, | |||||
429 | nua_dialog_state_t *ds, | |||||
430 | nua_dialog_usage_t *du, | |||||
431 | sip_time_t now) | |||||
432 | { | |||||
433 | nua_client_request_t *cr = du->du_cr; | |||||
434 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
435 | ||||||
436 | assert(eu)((eu) ? (void) (0) : __assert_fail ("eu", "nua_subnotref.c", 436 , __PRETTY_FUNCTION__)); | |||||
437 | ||||||
438 | if (eu->eu_final_wait) { | |||||
439 | /* Did not receive NOTIFY for fetch */ | |||||
440 | sip_event_t const *o = du->du_event; | |||||
441 | char const *id = o ? o->o_id : NULL((void*)0); | |||||
442 | ||||||
443 | SU_DEBUG_3(("nua(%p): event %s%s%s fetch timeouts\n",((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_subnotref.c" , (const char *)__func__, 445, "nua(%p): event %s%s%s fetch timeouts\n" , (void *)nh, o ? o->o_type : "(empty)", id ? "; id=" : "" , id ? id : "")) : (void)0) | |||||
444 | (void *)nh, o ? o->o_type : "(empty)",((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_subnotref.c" , (const char *)__func__, 445, "nua(%p): event %s%s%s fetch timeouts\n" , (void *)nh, o ? o->o_type : "(empty)", id ? "; id=" : "" , id ? id : "")) : (void)0) | |||||
445 | id ? "; id=" : "", id ? id : ""))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_subnotref.c" , (const char *)__func__, 445, "nua(%p): event %s%s%s fetch timeouts\n" , (void *)nh, o ? o->o_type : "(empty)", id ? "; id=" : "" , id ? id : "")) : (void)0); | |||||
446 | ||||||
447 | nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), | |||||
448 | nua_i_notify, 408, "Fetch Timeouts without NOTIFY", | |||||
449 | NUTAG_SUBSTATE(nua_substate_terminated)nutag_substate, tag_int_v(nua_substate_terminated), | |||||
450 | SIPTAG_EVENT(du->du_event)siptag_event, siptag_event_v(du->du_event), | |||||
451 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
452 | nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0)); | |||||
453 | ||||||
454 | return; | |||||
455 | } | |||||
456 | ||||||
457 | if (cr) { | |||||
458 | if (nua_client_resend_request(cr, 0) >= 0) | |||||
459 | return; | |||||
460 | } | |||||
461 | else if (eu->eu_refer) { | |||||
462 | /* | |||||
463 | * XXX - If we have received a NOTIFY, we should try to terminate | |||||
464 | * subscription | |||||
465 | */ | |||||
466 | } | |||||
467 | ||||||
468 | if (!eu->eu_unsolicited) | |||||
469 | nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), | |||||
470 | nua_i_notify, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_subnotref.c" ":" "470", | |||||
471 | NUTAG_SUBSTATE(nua_substate_terminated)nutag_substate, tag_int_v(nua_substate_terminated), | |||||
472 | SIPTAG_EVENT(du->du_event)siptag_event, siptag_event_v(du->du_event), | |||||
473 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
474 | ||||||
475 | nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0)); | |||||
476 | } | |||||
477 | ||||||
478 | /** Terminate subscription. | |||||
479 | * | |||||
480 | * @retval >0 shutdown done | |||||
481 | * @retval 0 shutdown in progress | |||||
482 | * @retval <0 try again later | |||||
483 | */ | |||||
484 | static int nua_subscribe_usage_shutdown(nua_handle_t *nh, | |||||
485 | nua_dialog_state_t *ds, | |||||
486 | nua_dialog_usage_t *du) | |||||
487 | { | |||||
488 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
| ||||||
489 | nua_client_request_t *cr = du->du_cr; | |||||
| ||||||
490 | ||||||
491 | assert(eu)((eu) ? (void) (0) : __assert_fail ("eu", "nua_subnotref.c", 491 , __PRETTY_FUNCTION__)); (void)eu; | |||||
492 | ||||||
493 | if (cr) { | |||||
494 | if (nua_client_resend_request(cr, 1) >= 0) | |||||
495 | return 0; | |||||
496 | } | |||||
497 | ||||||
498 | nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0)); | |||||
499 | return 200; | |||||
500 | } | |||||
501 | ||||||
502 | /* ======================================================================== */ | |||||
503 | /* NOTIFY server */ | |||||
504 | ||||||
505 | /** @NUA_EVENT nua_i_notify | |||||
506 | * | |||||
507 | * Event for incoming NOTIFY request. | |||||
508 | * | |||||
509 | * @param status statuscode of response sent automatically by stack | |||||
510 | * @param phrase a short textual description of @a status code | |||||
511 | * @param nh operation handle associated with the subscription | |||||
512 | * @param hmagic application context associated with the handle | |||||
513 | * @param sip incoming NOTIFY request | |||||
514 | * @param tags NUTAG_SUBSTATE() indicating the subscription state | |||||
515 | * | |||||
516 | * @sa nua_subscribe(), nua_unsubscribe(), @RFC3265, #nua_i_subscribe | |||||
517 | * | |||||
518 | * @END_NUA_EVENT | |||||
519 | */ | |||||
520 | ||||||
521 | int nua_notify_server_init(nua_server_request_t *sr); | |||||
522 | int nua_notify_server_preprocess(nua_server_request_t *sr); | |||||
523 | int nua_notify_server_report(nua_server_request_t *, tagi_t const *); | |||||
524 | ||||||
525 | nua_server_methods_t const nua_notify_server_methods = | |||||
526 | { | |||||
527 | SIP_METHOD_NOTIFYsip_method_notify, "NOTIFY", | |||||
528 | nua_i_notify, /* Event */ | |||||
529 | { | |||||
530 | /* create_dialog: */ 1, /* Do create dialog */ | |||||
531 | /* in_dialog: */ 0, /* Not always in-dialog request */ | |||||
532 | /* target_refresh: */ 1, /* Target refresh request */ | |||||
533 | /* add_contact: */ 1, /* Add Contact to response */ | |||||
534 | }, | |||||
535 | nua_notify_server_init, | |||||
536 | nua_notify_server_preprocess, | |||||
537 | nua_base_server_params((void*)0), | |||||
538 | nua_base_server_respond, | |||||
539 | nua_notify_server_report, | |||||
540 | }; | |||||
541 | ||||||
542 | ||||||
543 | int nua_notify_server_init(nua_server_request_t *sr) | |||||
544 | { | |||||
545 | if (!sr->sr_initial) { | |||||
546 | nua_dialog_state_t *ds = sr->sr_owner->nh_ds; | |||||
547 | ||||||
548 | /* Check for forked subscription. */ | |||||
549 | if (ds->ds_remote_tag && ds->ds_remote_tag[0] && | |||||
550 | su_strcasecmp(ds->ds_remote_tag, | |||||
551 | sr->sr_request.sip->sip_from->a_tag)) { | |||||
552 | sip_contact_t const *m = NULL((void*)0); | |||||
553 | ||||||
554 | m = nua_stack_get_contact(sr->sr_owner->nh_nua->nua_registrations); | |||||
555 | ||||||
556 | if (m) { | |||||
557 | sip_warning_t w[1]; | |||||
558 | ||||||
559 | sip_warning_init(w)->w_code = 399; | |||||
560 | w->w_host = m->m_url->url_host; | |||||
561 | w->w_port = m->m_url->url_port; | |||||
562 | w->w_text = "Forking SUBSCRIBEs are not supported"; | |||||
563 | ||||||
564 | sip_add_dup(sr->sr_response.msg, NULL((void*)0), (sip_header_t*)w); | |||||
565 | } | |||||
566 | ||||||
567 | return SR_STATUS(sr, 481, "Subscription Does Not Exist")((sr)->sr_phrase = ("Subscription Does Not Exist"), (sr)-> sr_status = (481)); | |||||
568 | } | |||||
569 | } | |||||
570 | ||||||
571 | return 0; | |||||
572 | } | |||||
573 | ||||||
574 | int nua_notify_server_preprocess(nua_server_request_t *sr) | |||||
575 | { | |||||
576 | nua_dialog_state_t *ds = sr->sr_owner->nh_ds; | |||||
577 | nua_dialog_usage_t *du; | |||||
578 | struct event_usage *eu; | |||||
579 | sip_t const *sip = sr->sr_request.sip; | |||||
580 | sip_event_t *o = sip->sip_event; | |||||
581 | enum nua_substate substate = nua_substate_terminated; | |||||
582 | sip_subscription_state_t *subs = sip->sip_subscription_state; | |||||
583 | char const *what = "", *reason = NULL((void*)0); | |||||
584 | int solicited = 1; | |||||
585 | ||||||
586 | du = nua_dialog_usage_get(ds, nua_subscribe_usage, o); | |||||
587 | ||||||
588 | if (du == NULL((void*)0)) { | |||||
589 | if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method)(((sr->sr_owner)->nh_prefs)->nhp_set_.set_bits.nhb_appl_method ? ((sr->sr_owner)->nh_prefs)->nhp_appl_method : ((sr ->sr_owner)->nh_nua->nua_handles->nh_prefs)->nhp_appl_method ), SIP_METHOD_NOTIFYsip_method_notify, "NOTIFY")) | |||||
590 | return SR_STATUS(sr, 481, "Subscription Does Not Exist")((sr)->sr_phrase = ("Subscription Does Not Exist"), (sr)-> sr_status = (481)); | |||||
591 | ||||||
592 | solicited = 0; /* Let application to handle unsolicited NOTIFY */ | |||||
593 | du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o); | |||||
594 | if (!du) | |||||
595 | return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error); | |||||
596 | } | |||||
597 | ||||||
598 | sr->sr_usage = du; | |||||
599 | eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); assert(eu)((eu) ? (void) (0) : __assert_fail ("eu", "nua_subnotref.c", 599 , __PRETTY_FUNCTION__)); | |||||
600 | eu->eu_notified++; | |||||
601 | if (!o || !o->o_id) | |||||
602 | eu->eu_no_id = 1; | |||||
603 | ||||||
604 | if (subs == NULL((void*)0)) { | |||||
605 | /* Compatibility */ | |||||
606 | unsigned long delta = eu->eu_delta; | |||||
607 | if (sip->sip_expires) | |||||
608 | delta = sip->sip_expires->ex_delta; | |||||
609 | ||||||
610 | if (delta == 0) | |||||
611 | substate = nua_substate_terminated, what = "terminated"; | |||||
612 | else | |||||
613 | substate = nua_substate_active, what = "active"; | |||||
614 | } | |||||
615 | else if (su_casematch(subs->ss_substate, what = "terminated")) { | |||||
616 | substate = nua_substate_terminated; | |||||
617 | reason = subs->ss_reason; | |||||
618 | ||||||
619 | if (su_casematch(reason, "deactivated") || | |||||
620 | su_casematch(reason, "probation")) | |||||
621 | substate = nua_substate_embryonic; | |||||
622 | } | |||||
623 | else if (su_casematch(subs->ss_substate, what = "pending")) { | |||||
624 | substate = nua_substate_pending; | |||||
625 | } | |||||
626 | else /* if (su_casematch(subs->ss_substate, what = "active")) */ { | |||||
627 | /* Any extended state is considered as active */ | |||||
628 | what = subs->ss_substate; | |||||
629 | substate = nua_substate_active; | |||||
630 | } | |||||
631 | ||||||
632 | eu->eu_substate = substate; | |||||
633 | if (!solicited) | |||||
634 | eu->eu_unsolicited = 1; | |||||
635 | ||||||
636 | SU_DEBUG_5(("nua(%p): %s: %s (%s)\n",((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_subnotref.c" , (const char *)__func__, 638, "nua(%p): %s: %s (%s)\n", (void *)sr->sr_owner, "nua_notify_server_preprocess", what, reason ? reason : "")) : (void)0) | |||||
637 | (void *)sr->sr_owner, "nua_notify_server_preprocess",((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_subnotref.c" , (const char *)__func__, 638, "nua(%p): %s: %s (%s)\n", (void *)sr->sr_owner, "nua_notify_server_preprocess", what, reason ? reason : "")) : (void)0) | |||||
638 | what, reason ? reason : ""))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_subnotref.c" , (const char *)__func__, 638, "nua(%p): %s: %s (%s)\n", (void *)sr->sr_owner, "nua_notify_server_preprocess", what, reason ? reason : "")) : (void)0); | |||||
639 | ||||||
640 | if (solicited) | |||||
641 | return SR_STATUS1(sr, SIP_200_OK)sr_status(sr, 200, sip_200_OK); | |||||
642 | ||||||
643 | return 0; | |||||
644 | } | |||||
645 | ||||||
646 | ||||||
647 | int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags) | |||||
648 | { | |||||
649 | nua_handle_t *nh = sr->sr_owner; | |||||
650 | nua_dialog_usage_t *du = sr->sr_usage; | |||||
651 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
652 | sip_t const *sip = sr->sr_request.sip; | |||||
653 | enum nua_substate substate = nua_substate_terminated; | |||||
654 | sip_time_t delta = SIP_TIME_MAX((sip_time_t)((msg_time_t)(9223372036854775807L *2UL+1UL))); | |||||
655 | sip_event_t const *o = sip->sip_event; | |||||
656 | int retry = -1; | |||||
657 | int retval; | |||||
658 | ||||||
659 | if (eu) { | |||||
660 | sip_subscription_state_t *subs = sip->sip_subscription_state; | |||||
661 | ||||||
662 | substate = eu->eu_substate; | |||||
663 | ||||||
664 | if (substate == nua_substate_active || substate == nua_substate_pending) { | |||||
665 | if (subs && subs->ss_expires) { | |||||
666 | sip_time_t now = sip_now(); | |||||
667 | sip_time_t delta0 = strtoul(subs->ss_expires, NULL((void*)0), 10); | |||||
668 | if (now + delta0 <= eu->eu_expires) | |||||
669 | delta = delta0; | |||||
670 | } | |||||
671 | } | |||||
672 | else if (substate == nua_substate_embryonic) { | |||||
673 | if (subs && subs->ss_reason) { | |||||
674 | if (su_casematch(subs->ss_reason, "deactivated")) { | |||||
675 | retry = 0; /* retry immediately */ | |||||
676 | } | |||||
677 | else if (su_casematch(subs->ss_reason, "probation")) { | |||||
678 | retry = 30; | |||||
679 | if (subs->ss_retry_after) | |||||
680 | retry = strtoul(subs->ss_retry_after, NULL((void*)0), 10); | |||||
681 | if (retry > 3600) | |||||
682 | retry = 3600; | |||||
683 | } | |||||
684 | } | |||||
685 | } | |||||
686 | else if (substate == nua_substate_terminated) { | |||||
687 | sr->sr_terminating = 1; | |||||
688 | } | |||||
689 | } | |||||
690 | ||||||
691 | retval = nua_base_server_treport(sr, /* can destroy sr */ | |||||
692 | NUTAG_SUBSTATE(substate)nutag_substate, tag_int_v(substate), | |||||
693 | SIPTAG_EVENT(o)siptag_event, siptag_event_v(o), | |||||
694 | TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | |||||
695 | ||||||
696 | if (retval != 1 || du == NULL((void*)0)) | |||||
697 | return retval; | |||||
698 | ||||||
699 | if (eu->eu_unsolicited) { | |||||
700 | /* Xyzzy */; | |||||
701 | } | |||||
702 | else if (retry >= 0) { /* Try to subscribe again */ | |||||
703 | /* XXX - this needs through testing */ | |||||
704 | nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */ | |||||
705 | nua_dialog_usage_set_refresh_range(du, retry, retry + 5); | |||||
706 | } | |||||
707 | else { | |||||
708 | if (delta < SIP_TIME_MAX((sip_time_t)((msg_time_t)(9223372036854775807L *2UL+1UL)))) { | |||||
709 | nua_dialog_usage_set_refresh(du, delta); | |||||
710 | eu->eu_expires = du->du_refquested + delta; | |||||
711 | } | |||||
712 | } | |||||
713 | ||||||
714 | return retval; | |||||
715 | } | |||||
716 | ||||||
717 | ||||||
718 | /* ======================================================================== */ | |||||
719 | /* REFER */ | |||||
720 | ||||||
721 | /**@fn void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); | |||||
722 | * | |||||
723 | * Transfer a call. | |||||
724 | * | |||||
725 | * Send a REFER request asking the recipient to transfer the call. | |||||
726 | * | |||||
727 | * The REFER request also establishes an implied subscription to the "refer" | |||||
728 | * event. The "refer" event can have an "id" parameter, which has the value | |||||
729 | * of CSeq number in the REFER request. After initiating the REFER request, | |||||
730 | * the nua engine sends application a #nua_r_refer event with status 100 and | |||||
731 | * tag NUTAG_REFER_EVENT() containing a matching event header with id | |||||
732 | * parameter. | |||||
733 | * | |||||
734 | * Note that the @Event header in the locally generated #nua_r_refer event | |||||
735 | * contains the @a id parameter. The @a id parameter contains the @CSeq | |||||
736 | * number of the REFER request, and it may get incremented if the request is | |||||
737 | * retried because it got challenged or redirected. In that case, the | |||||
738 | * application gets a new #nua_r_refer event with status 100 and tag | |||||
739 | * NUTAG_REFER_EVENT(). Also the recipient of the REFER request may or may | |||||
740 | * not include the @a id parameter with the @Event header in the NOTIFY | |||||
741 | * requests messages which it sends to the sender of the REFER request. | |||||
742 | * | |||||
743 | * Therefore the application is not able to modify the state of the implied | |||||
744 | * subscription before receiving the first NOTIFY request. | |||||
745 | * | |||||
746 | * @param nh Pointer to operation handle | |||||
747 | * @param tag, value, ... List of tagged parameters | |||||
748 | * | |||||
749 | * @return | |||||
750 | * nothing | |||||
751 | * | |||||
752 | * @par Related Tags: | |||||
753 | * NUTAG_URL() \n | |||||
754 | * Tags of nua_set_hparams() \n | |||||
755 | * Header tags defined in <sofia-sip/sip_tag.h> | |||||
756 | * | |||||
757 | * @par Events: | |||||
758 | * #nua_r_refer \n | |||||
759 | * #nua_i_notify | |||||
760 | * | |||||
761 | * @sa #nua_r_refer, NUTAG_SUBSTATE(), NUTAG_REFER_EVENT(),#nua_i_refer, | |||||
762 | * @RFC3515, @ReferTo, SIPTAG_REFER_TO(), SIPTAG_REFER_TO_STR(), | |||||
763 | * @RFC3892, @ReferredBy, SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR(), | |||||
764 | * @RFC3891, @Replaces, SIPTAG_REPLACES(), SIPTAG_REPLACES_STR(), | |||||
765 | * @RFC4488, @ReferSub, SIPTAG_REFER_SUB(), SIPTAG_REFER_SUB_STR() | |||||
766 | */ | |||||
767 | ||||||
768 | /**@NUA_EVENT nua_r_refer | |||||
769 | * | |||||
770 | * @brief Response to outgoing REFER. | |||||
771 | * | |||||
772 | * @param status response status code | |||||
773 | * (if the request is retried, @a status is 100, the @a | |||||
774 | * sip->sip_status->st_status contain the real status code | |||||
775 | * from the response message, e.g., 302, 401, or 407) | |||||
776 | * @param phrase a short textual description of @a status code | |||||
777 | * @param nh operation handle associated with the REFER request | |||||
778 | * @param hmagic application context associated with the handle | |||||
779 | * @param sip response to REFER request or NULL upon an error | |||||
780 | * (status code is in @a status and | |||||
781 | * descriptive message in @a phrase parameters) | |||||
782 | * @param tags NUTAG_REFER_EVENT() \n | |||||
783 | * NUTAG_SUBSTATE() | |||||
784 | * | |||||
785 | * @sa nua_refer(), NUTAG_SUBSTATE(), #nua_i_refer, | |||||
786 | * @RFC3515, @RFC4488, @ReferSub | |||||
787 | * | |||||
788 | * @END_NUA_EVENT | |||||
789 | */ | |||||
790 | ||||||
791 | static int nua_refer_client_init(nua_client_request_t *cr, | |||||
792 | msg_t *, sip_t *, | |||||
793 | tagi_t const *tags); | |||||
794 | static int nua_refer_client_request(nua_client_request_t *cr, | |||||
795 | msg_t *, sip_t *, | |||||
796 | tagi_t const *tags); | |||||
797 | static int nua_refer_client_response(nua_client_request_t *cr, | |||||
798 | int status, char const *phrase, | |||||
799 | sip_t const *sip); | |||||
800 | ||||||
801 | static nua_client_methods_t const nua_refer_client_methods = { | |||||
802 | SIP_METHOD_REFERsip_method_refer, "REFER", /* crm_method, crm_method_name */ | |||||
803 | 0, /* crm_extra */ | |||||
804 | { /* crm_flags */ | |||||
805 | /* create_dialog */ 1, | |||||
806 | /* in_dialog */ 1, | |||||
807 | /* target refresh */ 1 | |||||
808 | }, | |||||
809 | NULL((void*)0), /* crm_template */ | |||||
810 | nua_refer_client_init, /* crm_init */ | |||||
811 | nua_refer_client_request, /* crm_send */ | |||||
812 | NULL((void*)0), /* crm_check_restart */ | |||||
813 | nua_refer_client_response, /* crm_recv */ | |||||
814 | nua_refer_client_response, /* crm_preliminary */ | |||||
815 | NULL((void*)0), /* crm_report */ | |||||
816 | NULL((void*)0), /* crm_complete */ | |||||
817 | }; | |||||
818 | ||||||
819 | int | |||||
820 | nua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, | |||||
821 | tagi_t const *tags) | |||||
822 | { | |||||
823 | return nua_client_create(nh, e, &nua_refer_client_methods, tags); | |||||
824 | } | |||||
825 | ||||||
826 | static int nua_refer_client_init(nua_client_request_t *cr, | |||||
827 | msg_t *msg, sip_t *sip, | |||||
828 | tagi_t const *tags) | |||||
829 | { | |||||
830 | nua_handle_t *nh = cr->cr_owner; | |||||
831 | ||||||
832 | if (sip->sip_referred_by == NULL((void*)0)) { | |||||
833 | sip_from_t *a = sip->sip_from; | |||||
834 | sip_referred_by_t by[1]; | |||||
835 | ||||||
836 | sip_referred_by_init(by); | |||||
837 | ||||||
838 | if (a == NULL((void*)0)) | |||||
839 | a = nh->nh_nua->nua_from; | |||||
840 | by->b_display = a->a_display; | |||||
841 | *by->b_url = *a->a_url; | |||||
842 | ||||||
843 | sip_add_dup(msg, sip, (sip_header_t *)by); | |||||
844 | } | |||||
845 | ||||||
846 | if (sip->sip_event) | |||||
847 | sip_header_remove(msg, sip, (sip_header_t *)sip->sip_event); | |||||
848 | ||||||
849 | return 0; | |||||
850 | } | |||||
851 | ||||||
852 | static int nua_refer_client_request(nua_client_request_t *cr, | |||||
853 | msg_t *msg, sip_t *sip, | |||||
854 | tagi_t const *tags) | |||||
855 | { | |||||
856 | nua_handle_t *nh = cr->cr_owner; | |||||
857 | nua_dialog_usage_t *du, *du0 = cr->cr_usage; | |||||
858 | struct event_usage *eu; | |||||
859 | sip_event_t *event; | |||||
860 | int error; | |||||
861 | ||||||
862 | cr->cr_usage = NULL((void*)0); | |||||
863 | ||||||
864 | event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq); | |||||
865 | if (!event) | |||||
866 | return -1; | |||||
867 | ||||||
868 | if (du0 == NULL((void*)0) || | |||||
869 | du0->du_event == NULL((void*)0) || | |||||
870 | du0->du_event->o_id == NULL((void*)0) || | |||||
871 | strcmp(du0->du_event->o_id, event->o_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (du0->du_event->o_id) && __builtin_constant_p ( event->o_id) && (__s1_len = __builtin_strlen (du0-> du_event->o_id), __s2_len = __builtin_strlen (event->o_id ), (!((size_t)(const void *)((du0->du_event->o_id) + 1) - (size_t)(const void *)(du0->du_event->o_id) == 1) || __s1_len >= 4) && (!((size_t)(const void *)((event ->o_id) + 1) - (size_t)(const void *)(event->o_id) == 1 ) || __s2_len >= 4)) ? __builtin_strcmp (du0->du_event-> o_id, event->o_id) : (__builtin_constant_p (du0->du_event ->o_id) && ((size_t)(const void *)((du0->du_event ->o_id) + 1) - (size_t)(const void *)(du0->du_event-> o_id) == 1) && (__s1_len = __builtin_strlen (du0-> du_event->o_id), __s1_len < 4) ? (__builtin_constant_p ( event->o_id) && ((size_t)(const void *)((event-> o_id) + 1) - (size_t)(const void *)(event->o_id) == 1) ? __builtin_strcmp (du0->du_event->o_id, event->o_id) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (event->o_id); int __result = (((const unsigned char *) (const char *) (du0->du_event->o_id))[0] - __s2[0]) ; if (__s1_len > 0 && __result == 0) { __result = ( ((const unsigned char *) (const char *) (du0->du_event-> o_id))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ( du0->du_event->o_id))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char * ) (const char *) (du0->du_event->o_id))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (event->o_id) && ((size_t)(const void *)((event->o_id) + 1) - (size_t)(const void *)(event->o_id) == 1) && (__s2_len = __builtin_strlen (event->o_id), __s2_len < 4) ? (__builtin_constant_p ( du0->du_event->o_id) && ((size_t)(const void *) ((du0->du_event->o_id) + 1) - (size_t)(const void *)(du0 ->du_event->o_id) == 1) ? __builtin_strcmp (du0->du_event ->o_id, event->o_id) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (du0-> du_event->o_id); int __result = (((const unsigned char *) ( const char *) (event->o_id))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (event->o_id))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (event->o_id))[2] - __s2[2]); if ( __s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (event->o_id))[3] - __s2[ 3]); } } __result; })))) : __builtin_strcmp (du0->du_event ->o_id, event->o_id)))); })) { | |||||
872 | du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event); | |||||
873 | if (!du) | |||||
874 | return -1; | |||||
875 | } | |||||
876 | else { | |||||
877 | du = du0, du0 = NULL((void*)0); | |||||
878 | } | |||||
879 | ||||||
880 | if (du0) | |||||
881 | nua_dialog_usage_remove(nh, nh->nh_ds, du0, NULL((void*)0), NULL((void*)0)); | |||||
882 | ||||||
883 | eu = nua_dialog_usage_private(cr->cr_usage = du)((cr->cr_usage = du) ? (void*)((cr->cr_usage = du) + 1) : ((void*)0)); | |||||
884 | eu ->eu_refer = 1; | |||||
885 | ||||||
886 | error = nua_base_client_request(cr, msg, sip, tags); | |||||
887 | ||||||
888 | if (!error) { | |||||
889 | /* Give application an Event header for matching NOTIFYs with REFER */ | |||||
890 | nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), | |||||
891 | (enum nua_event_e)cr->cr_event, SIP_100_TRYING100, sip_100_Trying, | |||||
892 | NUTAG_REFER_EVENT(event)nutag_refer_event, siptag_event_v(event), | |||||
893 | SIPTAG_EVENT(event)siptag_event, siptag_event_v(event), | |||||
894 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
895 | su_free(nh->nh_home, event); | |||||
896 | } | |||||
897 | ||||||
898 | return error; | |||||
899 | } | |||||
900 | ||||||
901 | static int nua_refer_client_response(nua_client_request_t *cr, | |||||
902 | int status, char const *phrase, | |||||
903 | sip_t const *sip) | |||||
904 | { | |||||
905 | nua_dialog_usage_t *du = cr->cr_usage; | |||||
906 | enum nua_substate substate = nua_substate_terminated; | |||||
907 | ||||||
908 | if (du) { | |||||
909 | struct event_usage *eu = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||||
910 | ||||||
911 | if (status < 200) { | |||||
912 | substate = eu->eu_substate; | |||||
913 | } | |||||
914 | else if (status < 300) { | |||||
915 | sip_refer_sub_t const *rs = sip_refer_sub(sip)((sip_refer_sub_t *)msg_header_access((msg_pub_t*)(sip), sip_refer_sub_class )); | |||||
916 | ||||||
917 | if (rs && su_casematch("false", rs->rs_value)) | |||||
918 | cr->cr_terminated = 1; | |||||
919 | ||||||
920 | if (!cr->cr_terminated) | |||||
921 | substate = eu->eu_substate; | |||||
922 | } | |||||
923 | } | |||||
924 | ||||||
925 | return nua_base_client_tresponse(cr, status, phrase, sip, | |||||
926 | NUTAG_SUBSTATE(substate)nutag_substate, tag_int_v(substate), | |||||
927 | SIPTAG_EVENT(du ? du->du_event : NULL)siptag_event, siptag_event_v(du ? du->du_event : ((void*)0 )), | |||||
928 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
929 | } |