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_register.c
26  * @brief REGISTER and registrations
27  *
28  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29  *
30  * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
31  */
32 
33 #include "config.h"
34 
35 #include <sofia-sip/su_string.h>
36 #include <sofia-sip/su_strlst.h>
37 #include <sofia-sip/token64.h>
38 #include <sofia-sip/su_tagarg.h>
39 #include <sofia-sip/su_tag_inline.h>
40 
41 #include <sofia-sip/bnf.h>
42 
43 #include <sofia-sip/sip_protos.h>
44 #include <sofia-sip/sip_util.h>
45 #include <sofia-sip/sip_status.h>
46 #include <sofia-sip/msg_parser.h>
47 
48 #include "nua_stack.h"
49 
50 #include <stddef.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <limits.h>
54 
55 #include <assert.h>
56 
57 /* ====================================================================== */
58 /* Helper macros and functions for handling #nua_handle_preferences_t. */
59 
60 #define NHP_IS_ANY_SET(nhp) nhp_is_any_set((nhp))
61 
62 /** Check if any preference is set in @a nhp. */
nhp_is_any_set(nua_handle_preferences_t const * nhp)63 su_inline int nhp_is_any_set(nua_handle_preferences_t const *nhp)
64 {
65   char nhp_zero[sizeof nhp->nhp_set] = { 0 };
66   return memcmp(&nhp->nhp_set, nhp_zero, sizeof nhp->nhp_set) != 0;
67 }
68 
69 /** Copy set parameters from @a b to @a a.
70  *
71  * If preference is set in @a b, mark it set also in @a a.
72  */
nhp_or_set(nua_handle_preferences_t * a,nua_handle_preferences_t const * b)73 su_inline void nhp_or_set(nua_handle_preferences_t *a,
74 			  nua_handle_preferences_t const *b)
75 {
76   memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set));
77 
78   /* Bitwise or of bitfields, casted to unsigned */
79   a->nhp_set_.set_unsigned[0] |= b->nhp_set_.set_unsigned[0];
80   a->nhp_set_.set_unsigned[1] |= b->nhp_set_.set_unsigned[1];
81 }
82 
83 static int nhp_set_tags(su_home_t *home,
84 			nua_handle_preferences_t *nhp,
85 			nua_global_preferences_t *ngp,
86 			tagi_t const *tags);
87 
88 static int nhp_merge_lists(su_home_t *home,
89 			   msg_hclass_t *hc,
90 			   msg_list_t **return_new_list,
91 			   msg_list_t const *old_list,
92 			   int already_set,
93 			   int already_parsed,
94 			   int always_merge,
95 			   tag_value_t value);
96 
97 static int nhp_save_params(nua_handle_t *nh,
98 			   su_home_t *tmphome,
99 			   nua_global_preferences_t *gsrc,
100 			   nua_handle_preferences_t *src);
101 
102 /* ====================================================================== */
103 /* Magical NUTAG_USER_AGENT() - add NHP_USER_AGENT there if it is not there */
104 
105 #define NHP_USER_AGENT PACKAGE_NAME "/" PACKAGE_VERSION
106 
already_contains_package_name(char const * s)107 static int already_contains_package_name(char const *s)
108 {
109   char const pn[] = " " PACKAGE_NAME "/";
110   size_t pnlen = strlen(pn + 1);
111 
112   return su_casenmatch(s, pn + 1, pnlen) || su_strcasestr(s, pn);
113 }
114 
115 /* ====================================================================== */
116 /* Stack and handle parameters */
117 
118 static int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags);
119 
120 /** @internal Methods allowed by default. */
121 static char const nua_allow_str[] =
122 "INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, "
123 "MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE";
124 
125 /** @internal Set default parameters */
nua_stack_set_defaults(nua_handle_t * nh,nua_handle_preferences_t * nhp)126 int nua_stack_set_defaults(nua_handle_t *nh,
127 			   nua_handle_preferences_t *nhp)
128 {
129   su_home_t *home = (su_home_t *)nh;
130 
131   /* Set some defaults */
132   NHP_SET(nhp, retry_count, 3);
133   NHP_SET(nhp, max_subscriptions, 20);
134 
135   NHP_SET(nhp, media_enable, 1);
136   NHP_SET(nhp, invite_enable, 1);
137   NHP_SET(nhp, auto_alert, 0);
138   NHP_SET(nhp, early_media, 0);
139   NHP_SET(nhp, only183_100rel, 0);
140   NHP_SET(nhp, auto_answer, 0);
141   NHP_SET(nhp, auto_ack, 1);
142   NHP_SET(nhp, timer_autorequire, 1);
143   NHP_SET(nhp, invite_timeout, 120);
144 
145   nhp->nhp_session_timer = 1800;
146   nhp->nhp_refresher = nua_no_refresher;
147 
148   NHP_SET(nhp, min_se, 120);
149   NHP_SET(nhp, update_refresh, 0);
150 
151   NHP_SET(nhp, message_enable, 1);
152   NHP_SET(nhp, win_messenger_enable, 0);
153   if (getenv("PIMIW_HACK") != 0)
154     NHP_SET(nhp, message_auto_respond, 1);
155 
156   NHP_SET(nhp, media_features,  0);
157   NHP_SET(nhp, callee_caps, 0);
158   NHP_SET(nhp, service_route_enable, 1);
159   NHP_SET(nhp, path_enable, 1);
160   NHP_SET(nhp, retry_after_enable, 1);
161 
162   NHP_SET(nhp, refer_expires, 300);
163   NHP_SET(nhp, refer_with_id, 1);
164 
165   NHP_SET(nhp, substate, nua_substate_active);
166   NHP_SET(nhp, sub_expires, 3600);
167 
168   NHP_SET(nhp, allow, sip_allow_make(home, nua_allow_str));
169   NHP_SET(nhp, supported, sip_supported_make(home, "timer, 100rel"));
170   NHP_SET(nhp, user_agent, su_strdup(home, NHP_USER_AGENT));
171 
172   NHP_SET(nhp, outbound, su_strdup(home, "natify"));
173 
174   NHP_SET(nhp, keepalive, 120000);
175 
176   NHP_SET(nhp, auto_invite_100, 1);
177 
178   NHP_SET(nhp, appl_method,
179 	  sip_allow_make(home, "INVITE, REGISTER, PUBLISH, SUBSCRIBE"));
180 
181   if (!nhp->nhp_allow ||
182       !nhp->nhp_supported ||
183       !nhp->nhp_user_agent ||
184       !nhp->nhp_outbound)
185     return -1;
186 
187   return 0;
188 }
189 
190 /** @internal Set the default from field */
nua_stack_set_from(nua_t * nua,int initial,tagi_t const * tags)191 int nua_stack_set_from(nua_t *nua, int initial, tagi_t const *tags)
192 {
193   sip_from_t const *from = NONE;
194   char const *str = NONE;
195   sip_from_t *f = NULL,  f0[1];
196   int set;
197 
198   tl_gets(tags,
199 	  /* By nua_stack_set_from() */
200 	  SIPTAG_FROM_REF(from),
201 	  SIPTAG_FROM_STR_REF(str),
202 	  TAG_END());
203 
204   if (!initial && from == NONE && str == NONE)
205     return 0;
206 
207   sip_from_init(f0);
208 
209   if (from && from != NONE) {
210     f0->a_display = from->a_display;
211     *f0->a_url = *from->a_url;
212     f = sip_from_dup(nua->nua_home, f0);
213     set = 1;
214   }
215   else if (str && str != NONE) {
216     f = sip_from_make(nua->nua_home, str);
217     if (f)
218       *f0 = *f, f = f0, f->a_params = NULL;
219     set = 1;
220   }
221   else {
222     sip_contact_t const *m;
223 
224     m = nua_stack_get_contact(nua->nua_registrations);
225 
226     if (m) {
227       f0->a_display = m->m_display;
228       *f0->a_url = *m->m_url;
229       f = sip_from_dup(nua->nua_home, f0);
230     }
231     set = 0;
232   }
233 
234   if (!f)
235     return -1;
236 
237   nua->nua_from_is_set = set;
238   *nua->nua_from = *f;
239   return 0;
240 }
241 
242 /** @internal Initialize instance ID. */
nua_stack_init_instance(nua_handle_t * nh,tagi_t const * tags)243 int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
244 {
245   nua_handle_preferences_t *nhp = nh->nh_prefs;
246 
247   char const *instance = NONE;
248 
249   tl_gets(tags, NUTAG_INSTANCE_REF(instance), TAG_END());
250 
251   if (instance != NONE) {
252     NHP_SET(nhp, instance, su_strdup(nh->nh_home, instance));
253     if (instance && !nhp->nhp_instance)
254       return -1;
255   }
256 
257   return 0;
258 }
259 
260 /**@fn void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
261  *
262  * Set @nua parameters, shared by all handles.
263  *
264  * @param nua             Pointer to NUA stack object
265  * @param tag, value, ... List of tagged parameters
266  *
267  * @return
268  *     nothing
269  *
270  * @par Related tags:
271  *   NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
272  *   NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
273  *                         SIPTAG_ALLOW_EVENTS_STR() \n
274  *   NUTAG_AUTOACK() \n
275  *   NUTAG_AUTOALERT() \n
276  *   NUTAG_AUTOANSWER() \n
277  *   NUTAG_CALLEE_CAPS() \n
278  *   NUTAG_DETECT_NETWORK_UPDATES() \n
279  *   NUTAG_EARLY_ANSWER() \n
280  *   NUTAG_EARLY_MEDIA() \n
281  *   NUTAG_ENABLEINVITE() \n
282  *   NUTAG_ENABLEMESSAGE() \n
283  *   NUTAG_ENABLEMESSENGER() \n
284  *   NUTAG_INITIAL_ROUTE() \n
285  *   NUTAG_INITIAL_ROUTE_STR() \n
286  *   NUTAG_INSTANCE() \n
287  *   NUTAG_INVITE_TIMER() \n
288  *   NUTAG_KEEPALIVE() \n
289  *   NUTAG_KEEPALIVE_STREAM() \n
290  *   NUTAG_MAX_SUBSCRIPTIONS() \n
291  *   NUTAG_MEDIA_ENABLE() \n
292  *   NUTAG_MEDIA_FEATURES() \n
293  *   NUTAG_MIN_SE() \n
294  *   NUTAG_M_DISPLAY() \n
295  *   NUTAG_M_FEATURES() \n
296  *   NUTAG_M_PARAMS() \n
297  *   NUTAG_M_USERNAME() \n
298  *   NUTAG_ONLY183_100REL() \n
299  *   NUTAG_OUTBOUND() \n
300  *   NUTAG_PATH_ENABLE() \n
301  *   NUTAG_RETRY_AFTER_ENABLE() \n
302  *   NUTAG_PROXY() (aka NTATAG_DEFAULT_PROXY()) \n
303  *   NUTAG_REFER_EXPIRES() \n
304  *   NUTAG_REFER_WITH_ID() \n
305  *   NUTAG_REFRESH_WITHOUT_SDP() \n
306  *   NUTAG_REGISTRAR() \n
307  *   NUTAG_RETRY_COUNT() \n
308  *   NUTAG_SERVICE_ROUTE_ENABLE() \n
309  *   NUTAG_SESSION_REFRESHER() \n
310  *   NUTAG_SESSION_TIMER() \n
311  *   NUTAG_SMIME_ENABLE() \n
312  *   NUTAG_SMIME_KEY_ENCRYPTION() \n
313  *   NUTAG_SMIME_MESSAGE_DIGEST() \n
314  *   NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
315  *   NUTAG_SMIME_OPT() \n
316  *   NUTAG_SMIME_PROTECTION_MODE() \n
317  *   NUTAG_SMIME_SIGNATURE() \n
318  *   NUTAG_SOA_NAME() \n
319  *   NUTAG_SUBSTATE() \n
320  *   NUTAG_SUB_EXPIRES() \n
321  *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
322  *   NUTAG_UPDATE_REFRESH() \n
323  *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
324  *   SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
325  *
326  * nua_set_params() also accepts any soa tags, defined in
327  * <sofia-sip/soa_tag.h>, and nta tags, defined in <sofia-sip/nta_tag.h>.
328  *
329  * @par Events:
330  *     #nua_r_set_params
331  *
332  * @par SIP Header as NUA Parameters
333  * The @nua parameters include SIP headers @Allow, @Supported, @Organization,
334  * @UserAgent and @From. They are included in most of the SIP messages sent
335  * by @nua. They are set in the same way as the tagged arguments are
336  * used to populate a SIP message.
337  * @par
338  * When multiple tags for the same header are specified, the behaviour
339  * depends on the header type. If only a single header field can be included
340  * in a SIP message, the latest non-NULL value is used, e.g., @Organization.
341  * However, if the SIP header can consist of multiple lines or header fields
342  * separated by comma, in this case, @Allow and @Supported, all the tagged
343  * values are concatenated.
344  * @par
345  * However, if the tag value is #SIP_NONE (-1 casted as a void pointer), the
346  * values from previous tags are ignored.
347  *
348  * For example, the nua_set_params() call like this:
349  * @code
350  * nua_set_params(nua,
351  *                SIPTAG_USER_AGENT_STR("tester/1.0"),
352  *                SIPTAG_ALLOW_STR("INVITE,CANCEL,BYE,ACK"),
353  *                SIPTAG_ORGANIZATION(NULL),
354  *                SIPTAG_USER_AGENT(NULL),
355  *                SIPTAG_ALLOW(SIP_NONE),
356  *                TAG_END());
357  * @endcode
358  * will leave @Allow and @Organization headers empty. The @UserAgent header
359  * will contain value "tester/1.0".
360  * @code
361  * nua_set_params(nua,
362  *                SIPTAG_ORGANIZATION_STR("Malevolent Microwavers"),
363  *                SIPTAG_ALLOW_STR("OPTIONS"),
364  *                SIPTAG_ALLOW(SIP_NONE),
365  *                SIPTAG_ORGANIZATION_STR("The Phone Company"),
366  *                SIPTAG_ALLOW_STR("SUBSCRIBE"),
367  *                SIPTAG_ALLOW(NULL),
368  *                SIPTAG_ORGANIZATION_STR(NULL),
369  *                TAG_END());
370  * @endcode
371  * sets the header @Allow with value <code>SUBSCRIBE</code> and the
372  * header @Organization will have value <code>The Phone Company</code>.
373  *
374  */
375 
376 /**@fn void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
377  *
378  * Set the handle-specific parameters.
379  *
380  * The handle-specific parameters override default or global parameters set
381  * by nua_set_params(). The handle-specific parameters are set by several
382  * other operations: nua_invite(), nua_respond(), nua_ack(),
383  * nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(),
384  * nua_message(), nua_register(), nua_publish(), nua_refer(),
385  * nua_subscribe(), nua_notify(), nua_refer(), and nua_notifier().
386  *
387  * @param nh              Pointer to a NUA handle
388  * @param tag, value, ... List of tagged parameters
389  *
390  * @return
391  *     nothing
392  *
393  * @par Tags Used to Set Handle-Specific Parameters:
394  *   NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
395  *   NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
396  *                         SIPTAG_ALLOW_EVENTS_STR() \n
397  *   NUTAG_AUTH_CACHE() \n
398  *   NUTAG_AUTOACK() \n
399  *   NUTAG_AUTOALERT() \n
400  *   NUTAG_AUTOANSWER() \n
401  *   NUTAG_CALLEE_CAPS() \n
402  *   NUTAG_EARLY_ANSWER() \n
403  *   NUTAG_EARLY_MEDIA() \n
404  *   NUTAG_ENABLEINVITE() \n
405  *   NUTAG_ENABLEMESSAGE() \n
406  *   NUTAG_ENABLEMESSENGER() \n
407  *   NUTAG_INITIAL_ROUTE() \n
408  *   NUTAG_INITIAL_ROUTE_STR() \n
409  *   NUTAG_INSTANCE() \n
410  *   NUTAG_INVITE_TIMER() \n
411  *   NUTAG_KEEPALIVE() \n
412  *   NUTAG_KEEPALIVE_STREAM() \n
413  *   NUTAG_MAX_SUBSCRIPTIONS() \n
414  *   NUTAG_MEDIA_ENABLE() \n
415  *   NUTAG_MEDIA_FEATURES() \n
416  *   NUTAG_MIN_SE() \n
417  *   NUTAG_M_DISPLAY() \n
418  *   NUTAG_M_FEATURES() \n
419  *   NUTAG_M_PARAMS() \n
420  *   NUTAG_M_USERNAME() \n
421  *   NUTAG_ONLY183_100REL() \n
422  *   NUTAG_OUTBOUND() \n
423  *   NUTAG_PATH_ENABLE() \n
424  *   NUTAG_RETRY_AFTER_ENABLE() \n
425  *   NUTAG_PROXY() (aka NTATAG_DEFAULT_PROXY()) \n
426  *   NUTAG_REFER_EXPIRES() \n
427  *   NUTAG_REFER_WITH_ID() \n
428  *   NUTAG_REFRESH_WITHOUT_SDP() \n
429  *   NUTAG_REGISTRAR() \n
430  *   NUTAG_RETRY_COUNT() \n
431  *   NUTAG_SERVICE_ROUTE_ENABLE() \n
432  *   NUTAG_SESSION_REFRESHER() \n
433  *   NUTAG_SESSION_TIMER() \n
434  *   NUTAG_SOA_NAME() \n
435  *   NUTAG_SUBSTATE() \n
436  *   NUTAG_SUB_EXPIRES() \n
437  *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
438  *   NUTAG_UPDATE_REFRESH() \n
439  *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
440  *   SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
441  * Any soa tags are also considered as handle-specific parameters. They are
442  * defined in <sofia-sip/soa_tag.h>.
443  *
444  * The global parameters that can not be set by nua_set_hparams() include
445  * NUTAG_DETECT_NETWORK_UPDATES(), NUTAG_SMIME_* tags, and all NTA tags.
446  *
447  * @par Events:
448  *     #nua_r_set_params
449  */
450 
451 /** @NUA_EVENT nua_r_set_params
452  *
453  * Response to nua_set_params() or nua_set_hparams().
454  *
455  * @param status 200 when successful, error code otherwise
456  * @param phrase a short textual description of @a status code
457  * @param nh     NULL when responding to nua_set_params(),
458  *               operation handle when responding to nua_set_hparams()
459  * @param hmagic NULL when responding to nua_set_params(),
460  *               application contact associated with the operation handle
461  *               when responding to nua_set_hparams()
462  * @param sip    NULL
463  * @param tags   None
464  *
465  * @sa nua_set_params(), nua_set_hparams(),
466  * #nua_r_get_params, nua_get_params(), nua_get_hparams()
467  *
468  * @END_NUA_EVENT
469  */
470 
nua_stack_set_params(nua_t * nua,nua_handle_t * nh,nua_event_t e,tagi_t const * tags)471 int nua_stack_set_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
472 			 tagi_t const *tags)
473 {
474   nua_handle_t *dnh = nua->nua_dhandle;
475 
476   int status;
477   char const *phrase;
478 
479   nua_handle_preferences_t tmp[1];
480   int any_changes = 0;
481 
482   enter;
483 
484   {
485     su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
486     nua_handle_preferences_t *nhp = nh->nh_prefs;
487     nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
488     nua_global_preferences_t gtmp[1], *ngp = NULL;
489 
490     *tmp = *nhp; NHP_UNSET_ALL(tmp);
491 
492     /*
493      * Supported features, allowed methods and events are merged
494      * with previous or default settings.
495      *
496      * Here we just copy pointers from default settings. However when saving
497      * settings we have to be extra careful so that we
498      * 1) zero the pointers if the setting has not been modified
499      * 2) do not free pointer if the setting has been modified
500      * See NHP_ZAP_OVERRIDEN() below for gorier details.
501      */
502     if (!NHP_ISSET(nhp, supported))
503       tmp->nhp_supported = dnhp->nhp_supported;
504     if (!NHP_ISSET(nhp, allow))
505       tmp->nhp_allow = dnhp->nhp_allow;
506     if (!NHP_ISSET(nhp, allow_events))
507       tmp->nhp_allow_events = dnhp->nhp_allow_events;
508     if (!NHP_ISSET(nhp, appl_method))
509       tmp->nhp_appl_method = dnhp->nhp_appl_method;
510 
511     if (nh == dnh) /* nua_set_params() call, save stack-wide params, too */
512       ngp = gtmp, *gtmp = *nua->nua_prefs;
513 
514     /* Set and save parameters to tmp */
515     if (!nh->nh_used_ptags &&
516 	nhp_set_tags(tmphome, tmp, NULL, nh->nh_ptags) < 0)
517       status = 900, phrase = "Error storing default handle parameters";
518     else if (nhp_set_tags(tmphome, tmp, ngp, tags) < 0)
519       status = 900, phrase = "Error storing parameters";
520     else if ((any_changes = nhp_save_params(nh, tmphome, ngp, tmp)) < 0)
521       status = 900, phrase = su_strerror(ENOMEM);
522     else
523       status = 200, phrase = "OK", nh->nh_used_ptags = 1;
524 
525     su_home_deinit(tmphome);
526   }
527 
528   if (status == 200) {
529     nua_handle_preferences_t const *nhp = nh->nh_prefs;
530     nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
531 
532     if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
533       /* Create soa when needed */
534       char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
535 
536       if (dnh->nh_soa)
537 	nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
538       else
539 	nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
540 
541       if (!nh->nh_soa)
542 	status = 900, phrase = "Error Creating SOA Object";
543       else if (soa_set_params(nh->nh_soa, TAG_NEXT(nh->nh_ptags)) < 0)
544 	status = 900, phrase = "Error Setting SOA Parameters";
545     }
546     else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
547       /* ... destroy soa when not needed */
548       soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
549     }
550 
551     if (status == 200 && tags && nh->nh_soa &&
552 	soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0)
553       status = 900, phrase = "Error Setting SOA Parameters";
554   }
555 
556   if (status == 200 && nh == dnh) {
557     /* Set stack-specific things below */
558     if (nua_stack_set_smime_params(nua, tags) < 0) {
559       status = 900, phrase = "Error setting S/MIME parameters";
560     }
561     else if (nua->nua_nta &&
562 	     nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
563       status = 900, phrase = "Error setting NTA parameters";
564     }
565     else {
566       nua_stack_set_from(nua, 0, tags);
567 
568       if (nua->nua_prefs->ngp_detect_network_updates)
569 	nua_stack_launch_network_change_detector(nua);
570     }
571   }
572 
573   if (status != 200) {
574     if (e == nua_i_none)
575       SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase));
576     return UA_EVENT2(e, status, phrase), -1;
577   }
578   else {
579     if (e == nua_r_set_params)
580       UA_EVENT2(e, status, phrase);
581 
582     if (any_changes) {
583       nua_handle_preferences_t changed[1];
584 
585       *changed = *nh->nh_prefs;
586       memcpy(&changed->nhp_set_, &tmp->nhp_set_, sizeof changed->nhp_set_);
587 
588       nua_dialog_update_params(nh->nh_ds,
589 			       changed,
590 			       nh->nh_prefs,
591 			       dnh->nh_prefs);
592     }
593     return 0;
594   }
595 }
596 
597 
598 /** Parse parameters from tags to @a nhp or @a ngp.
599  *
600  * @param home allocate new values from @a home
601  * @param nhp  structure to store handle preferences
602  * @param ngp  structure to store global preferences
603  * @param tags list of tags to parse
604  */
nhp_set_tags(su_home_t * home,nua_handle_preferences_t * nhp,nua_global_preferences_t * ngp,tagi_t const * tags)605 static int nhp_set_tags(su_home_t *home,
606 			nua_handle_preferences_t *nhp,
607 			nua_global_preferences_t *ngp,
608 			tagi_t const *tags)
609 {
610 
611 /* Set copy of string to handle pref structure */
612 #define NHP_SET_STR(nhp, name, v)				 \
613   if ((v) != (tag_value_t)0) {					 \
614     char const *_value = (char const *)v;			 \
615     char *_new = _value ? su_strdup(home, _value) : NULL;	 \
616     if (NHP_ISSET(nhp, name))					 \
617       su_free(home, (void *)nhp->nhp_##name);			 \
618     NHP_SET(nhp, name, _new);					 \
619     if (_new == NULL && _value != NULL)				 \
620       return -1;						 \
621   }
622 
623 /* Set copy of string from url to handle pref structure */
624 #define NHP_SET_STR_BY_URL(nhp, type, name, v)			 \
625   if ((v) != (tag_value_t)-1) {					 \
626     url_t const *_value = (url_t const *)(v);			 \
627     type *_new = (type *)url_as_string(home, (void *)_value);	 \
628     if (NHP_ISSET(nhp, name))					 \
629       su_free(home, (void *)nhp->nhp_##name);			 \
630     NHP_SET(nhp, name, _new);					 \
631     if (_new == NULL && _value != NULL)				 \
632       return -1;						 \
633   }
634 
635 /* Set copy of header to handle pref structure */
636 #define NHP_SET_HEADER(nhp, name, hdr, v)			 \
637   if ((v) != 0) {						 \
638     sip_##hdr##_t const *_value = (sip_##hdr##_t const *)(v);	 \
639     sip_##hdr##_t *_new = NULL;				 \
640     if (_value != SIP_NONE)					 \
641       _new = sip_##name##_dup(home, _value);			 \
642     if (NHP_ISSET(nhp, name))					 \
643       msg_header_free_all(home, (void *)nhp->nhp_##name);	 \
644     NHP_SET(nhp, name, _new);					 \
645     if (_new == NULL && _value != SIP_NONE)			 \
646       return -1;						 \
647   }
648 
649 /* Set header made of string to handle pref structure */
650 #define NHP_SET_HEADER_STR(nhp, name, hdr, v)			 \
651   if ((v) != 0) {						 \
652     char const *_value = (char const *)(v);			 \
653     sip_##hdr##_t *_new = NULL;				 \
654     if (_value != SIP_NONE)					 \
655       _new = sip_##name##_make(home, _value);			 \
656     if (NHP_ISSET(nhp, name))					 \
657       msg_header_free_all(home, (void *)nhp->nhp_##name);	 \
658     NHP_SET(nhp, name, _new);					 \
659     if (_new == NULL && _value != SIP_NONE)			 \
660       return -1;						 \
661   }
662 
663 /* Append copy of header to handle pref structure */
664 #define NHP_APPEND_HEADER(nhp, name, hdr, is_str, next, v)	 \
665   {								 \
666     sip_##hdr##_t const *_value = (sip_##hdr##_t const *)(v);	 \
667     char const *_str = (char const *)(v);			 \
668     sip_##hdr##_t *_new = NULL;					 \
669     sip_##hdr##_t **_end = &nhp->nhp_##name;			 \
670     if (_value != SIP_NONE && _value != NULL) {			 \
671       _new = (is_str)						 \
672 	? sip_##hdr##_make(home, _str)				 \
673 	: sip_##hdr##_dup(home, _value);			 \
674       if (_new == NULL) return -1;				 \
675     }								 \
676     if (NHP_ISSET(nhp, name))					 \
677       while(*_end)						 \
678 	_end = next(*_end);					 \
679     nhp->nhp_set.nhb_##name = 1;				 \
680     *_end = _new;						 \
681   }
682 
683 /* Set copy of string from header to handle pref structure */
684 #define NHP_SET_STR_BY_HEADER(nhp, name, v)			 \
685   if ((v) != 0) {					 \
686     sip_##name##_t const *_value = (sip_##name##_t const *)(v);	 \
687     char *_new = NULL;						 \
688     if (_value != SIP_NONE)					 \
689       _new = sip_header_as_string(home, (void *)_value);	 \
690     if (NHP_ISSET(nhp, name))					 \
691       su_free(home, (void *)nhp->nhp_##name);			 \
692     NHP_SET(nhp, name, _new);					 \
693     if (_new == NULL && _value != SIP_NONE)			 \
694       return -1;						 \
695   }
696 
697 
698   tagi_t const *t;
699 
700   for (t = tags; t; t = tl_next(t)) {
701     tag_type_t tag = t->t_tag;
702     tag_value_t value = t->t_value;
703 
704     if (tag == NULL)
705       break;
706     /* NUTAG_RETRY_COUNT(retry_count) */
707     else if (tag == nutag_retry_count) {
708       NHP_SET(nhp, retry_count, (unsigned)value);
709     }
710     /* NUTAG_MAX_SUBSCRIPTIONS(max_subscriptions) */
711     else if (tag == nutag_max_subscriptions) {
712       NHP_SET(nhp, max_subscriptions, (unsigned)value);
713     }
714     /* NUTAG_SOA_NAME(soa_name) */
715     else if (tag == nutag_soa_name) {
716       NHP_SET_STR(nhp, soa_name, value);
717     }
718     /* NUTAG_MEDIA_ENABLE(media_enable) */
719     else if (tag == nutag_media_enable) {
720       NHP_SET(nhp, media_enable, value != 0);
721     }
722     /* NUTAG_ENABLEINVITE(invite_enable) */
723     else if (tag == nutag_enableinvite) {
724       NHP_SET(nhp, invite_enable, value != 0);
725     }
726     /* NUTAG_AUTOALERT(auto_alert) */
727     else if (tag == nutag_autoalert) {
728       NHP_SET(nhp, auto_alert, value != 0);
729     }
730     /* NUTAG_EARLY_ANSWER(early_answer) */
731     else if (tag == nutag_early_answer) {
732       NHP_SET(nhp, early_answer, value != 0);
733     }
734     /* NUTAG_EARLY_MEDIA(early_media) */
735     else if (tag == nutag_early_media) {
736       NHP_SET(nhp, early_media, value != 0);
737     }
738     /* NUTAG_ONLY183_100REL(only183_100rel) */
739     else if (tag == nutag_only183_100rel) {
740       NHP_SET(nhp, only183_100rel, value != 0);
741     }
742     /* NUTAG_AUTOANSWER(auto_answer) */
743     else if (tag == nutag_autoanswer) {
744       NHP_SET(nhp, auto_answer, value != 0);
745     }
746     /* NUTAG_AUTOACK(auto_ack) */
747     else if (tag == nutag_autoack) {
748       NHP_SET(nhp, auto_ack, value != 0);
749     }
750     /* NUTAG_TIMER_AUTOREQUIRE(timer_autorequire) */
751     else if (tag == nutag_timer_autorequire) {
752       NHP_SET(nhp, timer_autorequire, value != 0);
753     }
754     /* NUTAG_INVITE_TIMER(invite_timeout) */
755     else if (tag == nutag_invite_timer) {
756       NHP_SET(nhp, invite_timeout, (unsigned)value);
757     }
758     /* NUTAG_SESSION_TIMER(session_timer) */
759     else if (tag == nutag_session_timer) {
760       NHP_SET(nhp, session_timer, (unsigned)value);
761     }
762     /* NUTAG_MIN_SE(min_se) */
763     else if (tag == nutag_min_se) {
764       NHP_SET(nhp, min_se, (unsigned)value);
765     }
766     /* NUTAG_SESSION_REFRESHER(refresher) */
767     else if (tag == nutag_session_refresher) {
768       int refresher = value;
769 
770       if (refresher >= nua_remote_refresher)
771 	refresher = nua_remote_refresher;
772       else if (refresher <= nua_no_refresher)
773 	refresher = nua_no_refresher;
774 
775       NHP_SET(nhp, refresher, (enum nua_session_refresher)refresher);
776     }
777     /* NUTAG_UPDATE_REFRESH(update_refresh) */
778     else if (tag == nutag_update_refresh) {
779       NHP_SET(nhp, update_refresh, value != 0);
780     }
781     /* NUTAG_REFRESH_WITHOUT_SDP(refresh_without_sdp) */
782     else if (tag == nutag_refresh_without_sdp) {
783       NHP_SET(nhp, refresh_without_sdp, value != 0);
784     }
785     /* NUTAG_ENABLEMESSAGE(message_enable) */
786     else if (tag == nutag_enablemessage) {
787       NHP_SET(nhp, message_enable, value != 0);
788     }
789     /* NUTAG_ENABLEMESSENGER(win_messenger_enable) */
790     else if (tag == nutag_enablemessenger) {
791       NHP_SET(nhp, win_messenger_enable, value != 0);
792     }
793     /* NUTAG_CALLEE_CAPS(callee_caps) */
794     else if (tag == nutag_callee_caps) {
795       NHP_SET(nhp, callee_caps, value != 0);
796     }
797     /* NUTAG_MEDIA_FEATURES(media_features) */
798     else if (tag == nutag_media_features) {
799       NHP_SET(nhp, media_features, value != 0);
800     }
801     /* NUTAG_SERVICE_ROUTE_ENABLE(service_route_enable) */
802     else if (tag == nutag_service_route_enable) {
803       NHP_SET(nhp, service_route_enable, value != 0);
804     }
805     /* NUTAG_PATH_ENABLE(path_enable) */
806     else if (tag == nutag_path_enable) {
807       NHP_SET(nhp, path_enable, value != 0);
808     }
809     /* NUTAG_RETRY_AFTER_ENABLE(retry_after_enable) */
810     else if (tag == nutag_retry_after_enable) {
811       NHP_SET(nhp, retry_after_enable, value != 0);
812     }
813     /* NUTAG_AUTH_CACHE(auth_cache) */
814     else if (tag == nutag_auth_cache) {
815       if (value >= 0 && value < (tag_value_t)_nua_auth_cache_invalid)
816 	NHP_SET(nhp, auth_cache, (int)value);
817     }
818     /* NUTAG_REFER_EXPIRES(refer_expires) */
819     else if (tag == nutag_refer_expires) {
820       NHP_SET(nhp, refer_expires, value);
821     }
822     /* NUTAG_REFER_WITH_ID(refer_with_id) */
823     else if (tag == nutag_refer_with_id) {
824       NHP_SET(nhp, refer_with_id, value != 0);
825     }
826     /* NUTAG_SUBSTATE(substate) */
827     else if (tag == nutag_substate) {
828       NHP_SET(nhp, substate, (int)value);
829     }
830     /* NUTAG_SUB_EXPIRES(sub_expires) */
831     else if (tag == nutag_sub_expires) {
832       NHP_SET(nhp, sub_expires, value);
833     }
834     /* NUTAG_KEEPALIVE(keepalive) */
835     else if (tag == nutag_keepalive) {
836       NHP_SET(nhp, keepalive, (unsigned)value);
837     }
838     /* NUTAG_KEEPALIVE_STREAM(keepalive_stream) */
839     else if (tag == nutag_keepalive_stream) {
840       NHP_SET(nhp, keepalive_stream, (unsigned)value);
841     }
842 
843     /* NUTAG_SUPPORTED(feature) */
844     /* SIPTAG_SUPPORTED_STR(supported_str) */
845     /* SIPTAG_SUPPORTED(supported) */
846     else if (tag == nutag_supported ||
847 	     tag == siptag_supported ||
848 	     tag == siptag_supported_str) {
849       int ok;
850       sip_supported_t *supported = NULL;
851 
852       ok = nhp_merge_lists(home,
853 			   sip_supported_class, &supported, nhp->nhp_supported,
854 			   NHP_ISSET(nhp, supported), /* already set by tags */
855 			   tag == siptag_supported, /* dup it, don't make */
856 			   tag == nutag_supported, /* merge with old value */
857 			   t->t_value);
858       if (ok < 0)
859 	return -1;
860       else if (ok)
861 	NHP_SET(nhp, supported, supported);
862     }
863     /* NUTAG_ALLOW(allowing) */
864     /* SIPTAG_ALLOW_STR(allow_str) */
865     /* SIPTAG_ALLOW(allow) */
866     else if (tag == nutag_allow ||
867 	     tag == siptag_allow_str ||
868 	     tag == siptag_allow) {
869       int ok;
870       msg_list_t *allow = NULL;
871 
872       ok = nhp_merge_lists(home,
873 			   sip_allow_class,
874 			   &allow,
875 			   (msg_list_t const *)nhp->nhp_allow,
876 			   NHP_ISSET(nhp, allow), /* already set by tags */
877 			   tag == siptag_allow, /* dup it, don't make */
878 			   tag == nutag_allow, /* merge with old value */
879 			   t->t_value);
880       if (ok < 0)
881 	return -1;
882       else if (ok)
883 	NHP_SET(nhp, allow, (sip_allow_t *)allow);
884     }
885     /* NUTAG_ALLOW_EVENTS(allow_events) */
886     /* SIPTAG_ALLOW_EVENTS_STR(allow_events) */
887     /* SIPTAG_ALLOW_EVENTS(allow_events) */
888     else if (tag == nutag_allow_events ||
889 	     tag == siptag_allow_events_str ||
890 	     tag == siptag_allow_events) {
891       int ok;
892       sip_allow_events_t *allow_events = NULL;
893 
894       ok = nhp_merge_lists(home,
895 			   sip_allow_events_class,
896 			   &allow_events,
897 			   nhp->nhp_allow_events,
898 			   NHP_ISSET(nhp, allow_events), /* already set */
899 			   tag == siptag_allow_events, /* dup it, don't make */
900 			   tag == nutag_allow_events, /* merge with old value */
901 			   t->t_value);
902       if (ok < 0)
903 	return -1;
904       else if (ok)
905 	NHP_SET(nhp, allow_events, allow_events);
906     }
907     /* NUTAG_APPL_METHOD(appl_method) */
908     else if (tag == nutag_appl_method) {
909       if (t->t_value == 0) {
910 	NHP_SET(nhp, appl_method, NULL);
911       }
912       else {
913 	int ok;
914 	msg_list_t *appl_method = NULL;
915 
916 	ok = nhp_merge_lists(home,
917 			     sip_allow_class,
918 			     &appl_method,
919 			     (msg_list_t const *)nhp->nhp_appl_method,
920 			     /* already set by tags? */
921 			     NHP_ISSET(nhp, appl_method),
922 			     0, /* dup it, don't make */
923 			     1, /* merge with old value */
924 			     t->t_value);
925 	if (ok < 0)
926 	  return -1;
927 	else if (ok)
928 	  NHP_SET(nhp, appl_method, (sip_allow_t *)appl_method);
929       }
930     }
931     else if (tag == nutag_initial_route ||
932 	     tag == nutag_initial_route_str) {
933 #define next_route(r) (&(r)->r_next)
934       NHP_APPEND_HEADER(nhp, initial_route, route,
935 			(tag == nutag_initial_route_str),
936 			next_route,
937 			t->t_value);
938       sip_route_fix(nhp->nhp_initial_route);
939     }
940     /* SIPTAG_USER_AGENT(user_agent) */
941     else if (tag == siptag_user_agent) {
942       NHP_SET_STR_BY_HEADER(nhp, user_agent, value);
943     }
944     /* SIPTAG_USER_AGENT_STR(user_agent_str) */
945     else if (tag == siptag_user_agent_str && value != 0) {
946       if (value == -1)
947 	value = 0;
948       NHP_SET_STR(nhp, user_agent, value);
949     }
950     /* NUTAG_USER_AGENT(ua_name) */
951     else if (tag == nutag_user_agent) {
952       /* Add contents of NUTAG_USER_AGENT() to our distribution name */
953       char const *str = (void *)value, *ua;
954 
955       if (str && !already_contains_package_name(str))
956 	ua = su_sprintf(home, "%s %s", str, NHP_USER_AGENT);
957       else if (str)
958 	ua = su_strdup(home, str);
959       else
960 	ua = su_strdup(home, NHP_USER_AGENT);
961 
962       NHP_SET(nhp, user_agent, ua);
963     }
964     /* SIPTAG_ORGANIZATION(organization) */
965     else if (tag == siptag_organization) {
966       NHP_SET_STR_BY_HEADER(nhp, organization, value);
967     }
968     /* SIPTAG_ORGANIZATION_STR(organization_str) */
969     else if (tag == siptag_organization_str) {
970       if (value == -1)
971 	value = 0;
972       NHP_SET_STR(nhp, organization, value);
973     }
974     /* SIPTAG_VIA(via) */
975     else if (tag == siptag_via) {
976       NHP_SET_STR_BY_HEADER(nhp, via, value);
977     }
978     /* SIPTAG_VIA_STR(via_str) */
979     else if (tag == siptag_via_str) {
980       if (value == -1)
981 	value = 0;
982       NHP_SET_STR(nhp, via, value);
983     }
984     /* NUTAG_REGISTRAR(registrar) */
985     else if (tag == nutag_registrar) {
986       NHP_SET_STR_BY_URL(nhp, char, registrar, value);
987       if (NHP_ISSET(nhp, registrar) && su_strmatch(nhp->nhp_registrar, "*"))
988 	NHP_SET_STR(nhp, registrar, 0);
989     }
990     /* NUTAG_INSTANCE(instance) */
991     else if (tag == nutag_instance) {
992       NHP_SET_STR(nhp, instance, value);
993     }
994     /* NUTAG_M_DISPLAY(m_display) */
995     else if (tag == nutag_m_display) {
996       NHP_SET_STR(nhp, m_display, value);
997     }
998     /* NUTAG_M_USERNAME(m_username) */
999     else if (tag == nutag_m_username) {
1000       NHP_SET_STR(nhp, m_username, value);
1001     }
1002     /* NUTAG_M_PARAMS(m_params) */
1003     else if (tag == nutag_m_params) {
1004       NHP_SET_STR(nhp, m_params, value);
1005     }
1006     /* NUTAG_M_FEATURES(m_features) */
1007     else if (tag == nutag_m_features) {
1008       NHP_SET_STR(nhp, m_features, value);
1009     }
1010     /* NUTAG_OUTBOUND(outbound) */
1011     else if (tag == nutag_outbound) {
1012       NHP_SET_STR(nhp, outbound, value);
1013     }
1014     /* NUTAG_PROXY() (aka NTATAG_DEFAULT_PROXY()) */
1015     else if (tag == ntatag_default_proxy) {
1016       NHP_SET_STR_BY_URL(nhp, url_string_t, proxy, value);
1017     }
1018     /* NUTAG_AUTO_INVITE_100() */
1019     else if (tag == nutag_auto_invite_100) {
1020       NHP_SET(nhp, auto_invite_100, value != 0);
1021     }
1022     /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
1023     else if (ngp && tag == nutag_detect_network_updates) {
1024       int detector = (int)value;
1025 
1026       if (detector < NUA_NW_DETECT_NOTHING)
1027 	detector = NUA_NW_DETECT_NOTHING;
1028       else if (detector > NUA_NW_DETECT_TRY_FULL)
1029 	detector = NUA_NW_DETECT_TRY_FULL;
1030 
1031       ngp->ngp_detect_network_updates = detector;
1032       ngp->ngp_set.ngp_detect_network_updates = 1;
1033     }
1034     /* NUTAG_SHUTDOWN_EVENTS() */
1035     else if (ngp && tag == nutag_shutdown_events) {
1036       ngp->ngp_shutdown_events = value != 0;
1037       ngp->ngp_set.ngp_shutdown_events = 1;
1038     }
1039   }
1040 
1041   return 0;
1042 }
1043 
1044 /** Merge (when needed) new values with old values. */
nhp_merge_lists(su_home_t * home,msg_hclass_t * hc,msg_list_t ** return_new_list,msg_list_t const * old_list,int already_set,int already_parsed,int always_merge,tag_value_t value)1045 static int nhp_merge_lists(su_home_t *home,
1046 			   msg_hclass_t *hc,
1047 			   msg_list_t **return_new_list,
1048 			   msg_list_t const *old_list,
1049 			   int already_set,
1050 			   int already_parsed,
1051 			   int always_merge,
1052 			   tag_value_t value)
1053 {
1054   msg_list_t *list, *elems;
1055 
1056   if (value == -1) {
1057     *return_new_list = NULL;
1058     return 1;
1059   }
1060 
1061   if (value == 0) {
1062     if (!already_set && !always_merge) {
1063       *return_new_list = NULL;
1064       return 1;
1065     }
1066     return 0;
1067   }
1068 
1069   if (already_parsed)
1070     elems = (void *)msg_header_dup_as(home, hc, (msg_header_t *)value);
1071   else
1072     elems = (void *)msg_header_make(home, hc, (char const *)value);
1073 
1074   if (!elems)
1075     return -1;
1076 
1077   list = (msg_list_t *)old_list;
1078 
1079   if (!already_set) {
1080     if (always_merge && list) {
1081       list = (void *)msg_header_dup_as(home, hc, (void *)old_list);
1082       if (!list)
1083 	return -1;
1084     }
1085     else
1086       list = NULL;
1087   }
1088 
1089   if (!list) {
1090     *return_new_list = elems;
1091     return 1;
1092   }
1093 
1094   /* Add contents to the new list to the old list */
1095   if (msg_params_join(home, (msg_param_t **)&list->k_items, elems->k_items,
1096 		      2 /* prune */, 0 /* don't dup */) < 0)
1097     return -1;
1098 
1099   *return_new_list =
1100     (msg_list_t *)msg_header_dup_as(home, hc, (msg_header_t *)list);
1101   if (!*return_new_list)
1102     return -1;
1103 
1104   msg_header_free(home, (msg_header_t *)list);
1105   msg_header_free(home, (msg_header_t *)elems);
1106 
1107   return 1;
1108 }
1109 
1110 /** Save parameters in @a gtmp and @a tmp.
1111  *
1112  * @retval 1 - parameters were changed
1113  * @retval 0 - no changes in parameters
1114  * @retval -1 - an error
1115  */
1116 static
nhp_save_params(nua_handle_t * nh,su_home_t * tmphome,nua_global_preferences_t * gsrc,nua_handle_preferences_t * src)1117 int nhp_save_params(nua_handle_t *nh,
1118 		    su_home_t *tmphome,
1119 		    nua_global_preferences_t *gsrc,
1120 		    nua_handle_preferences_t *src)
1121 {
1122   su_home_t *home = nh->nh_home;
1123   nua_t *nua = nh->nh_nua;
1124   nua_handle_t *dnh = nua->nua_dhandle;
1125   nua_handle_preferences_t *dst, old[1];
1126 
1127   if (gsrc) {
1128     *nua->nua_prefs = *gsrc;	/* No pointers this far */
1129   }
1130 
1131   if (!NHP_IS_ANY_SET(src))
1132     return 0;
1133 
1134   if (nh == dnh || nh->nh_prefs != dnh->nh_prefs) {
1135     dst = nh->nh_prefs, *old = *dst;
1136   }
1137   else {
1138     dst = su_zalloc(home, sizeof *dst), memset(old, 0, sizeof *old);
1139     if (!dst)
1140       return -1;
1141   }
1142 
1143   /* Move allocations from tmphome to home */
1144   su_home_move(nh->nh_home, tmphome);
1145 
1146   /* Copy parameters that are set from src to dst */
1147   nhp_or_set(dst, src);
1148 
1149   /* Handle pointer items. Free changed ones and zap unset ones. */
1150   /* Note that pointer items where !NHP_ISSET(old, pref) are not freed
1151      (because they were just on loan from the default preference set) */
1152 #define NHP_ZAP_OVERRIDEN(old, dst, free, pref)				\
1153   (((NHP_ISSET(old, pref) &&						\
1154      (old)->nhp_##pref && (old)->nhp_##pref != (dst)->nhp_##pref)	\
1155     ? (free)(home, (void *)(old)->nhp_##pref) : (void)0),		\
1156    (void)(!(dst)->nhp_set.nhb_##pref ? (dst)->nhp_##pref = NULL : NULL))
1157 
1158   NHP_ZAP_OVERRIDEN(old, dst, su_free, soa_name);
1159   NHP_ZAP_OVERRIDEN(old, dst, su_free, registrar);
1160   NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow);
1161   NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, supported);
1162   NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow_events);
1163   NHP_ZAP_OVERRIDEN(old, dst, su_free, user_agent);
1164   NHP_ZAP_OVERRIDEN(old, dst, su_free, organization);
1165   NHP_ZAP_OVERRIDEN(old, dst, su_free, via);
1166   NHP_ZAP_OVERRIDEN(old, dst, su_free, m_display);
1167   NHP_ZAP_OVERRIDEN(old, dst, su_free, m_username);
1168   NHP_ZAP_OVERRIDEN(old, dst, su_free, m_params);
1169   NHP_ZAP_OVERRIDEN(old, dst, su_free, m_features);
1170   NHP_ZAP_OVERRIDEN(old, dst, su_free, instance);
1171   NHP_ZAP_OVERRIDEN(old, dst, su_free, outbound);
1172   NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, appl_method);
1173   NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, initial_route);
1174 
1175   nh->nh_prefs = dst;
1176 
1177   return memcmp(dst, old, sizeof *dst) != 0;
1178 }
1179 
1180 static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t);
1181 static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t);
1182 
1183 /** Save taglist to a handle */
nua_handle_save_tags(nua_handle_t * nh,tagi_t * tags)1184 int nua_handle_save_tags(nua_handle_t *nh, tagi_t *tags)
1185 {
1186   /* Initialization parameters */
1187   url_string_t const *url = NULL;
1188   sip_to_t const *p_to = NULL;
1189   char const *to_str = NULL;
1190   sip_from_t const *p_from = NULL;
1191   char const *from_str = NULL;
1192   nua_handle_t *identity = NULL;
1193 
1194   tagi_t const *t;
1195 
1196   su_home_t tmphome[SU_HOME_AUTO_SIZE(1024)];
1197 
1198   int error;
1199 
1200 #if HAVE_OPEN_C
1201   /* Nice. An old symbian compiler */
1202   tagi_t tagfilter[2];
1203   tagi_t paramfilter[2];
1204 
1205   tagfilter[0].t_tag = tag_filter;
1206   tagfilter[0].t_value = tag_filter_v(nua_handle_tags_filter);
1207   tagfilter[1].t_tag = (tag_type_t)0;
1208   tagfilter[1].t_value = (tag_value_t)0;
1209 
1210   paramfilter[0].t_tag = tag_filter;
1211   paramfilter[0].t_value = tag_filter_v(nua_handle_param_filter);
1212   paramfilter[1].t_tag = (tag_type_t)0;
1213   paramfilter[1].t_value = (tag_value_t)0;
1214 
1215 #else
1216   tagi_t const tagfilter[] = {
1217     { TAG_FILTER(nua_handle_tags_filter) },
1218     { TAG_NULL() }
1219   };
1220   tagi_t const paramfilter[] = {
1221     { TAG_FILTER(nua_handle_param_filter) },
1222     { TAG_NULL() }
1223   };
1224 #endif
1225 
1226   for (t = tags; t; t = tl_next(t)) {
1227     if (t->t_tag == NULL)
1228       break;
1229     /* SIPTAG_FROM_REF(p_from) */
1230     else if (t->t_tag == siptag_from) {
1231       p_from = (sip_from_t *)t->t_value, from_str = NULL;
1232     }
1233     /* SIPTAG_FROM_STR_REF(from_str) */
1234     else if (t->t_tag == siptag_from_str) {
1235       from_str = (char const *)t->t_value, p_from = NULL;
1236     }
1237     /* SIPTAG_TO_REF(p_to) */
1238     else if (t->t_tag == siptag_to) {
1239       p_to = (sip_to_t *)t->t_value, to_str = NULL;
1240     }
1241     /* SIPTAG_TO_STR_REF(to_str) */
1242     else if (t->t_tag == siptag_to_str) {
1243       to_str = (char const *)t->t_value, p_to = NULL;
1244     }
1245     /* NUTAG_IDENTITY_REF(identity) */
1246     else if (t->t_tag == nutag_identity) {
1247       identity = (nua_handle_t *)t->t_value;
1248     }
1249     /* NUTAG_URL_REF(url) */
1250     else if (t->t_tag == nutag_url) {
1251       url = (url_string_t *)t->t_value;
1252     }
1253     /* NUTAG_SIPS_URL_REF(url) */
1254     else if (t->t_tag == nutag_sips_url) {
1255       url = (url_string_t *)t->t_value;
1256     }
1257     /* NUTAG_WS_URL_REF(url) */
1258     else if (t->t_tag == nutag_ws_url) {
1259       url = (url_string_t *)t->t_value;
1260     }
1261     /* NUTAG_WSS_URL_REF(url) */
1262     else if (t->t_tag == nutag_wss_url) {
1263       url = (url_string_t *)t->t_value;
1264     }
1265   }
1266 
1267   su_home_auto(tmphome, sizeof tmphome);
1268 
1269   if (p_from)
1270     ;
1271   else if (from_str)
1272     p_from = sip_from_make(tmphome, from_str);
1273   else
1274     p_from = SIP_NONE;
1275 
1276   if (p_to)
1277     ;
1278   else if (to_str)
1279     p_to = sip_to_make(tmphome, to_str);
1280   else if (url)
1281     p_to = sip_to_create(tmphome, url),
1282       p_to ? sip_aor_strip((url_t*)p_to->a_url) : 0;
1283   else
1284     p_to = SIP_NONE;
1285 
1286   if (p_to == NULL || p_from == NULL) {
1287     su_home_deinit(tmphome);
1288     return -1;
1289   }
1290 
1291   nh->nh_tags =
1292     tl_filtered_tlist(nh->nh_home, tagfilter,
1293 		      TAG_IF(p_from != SIP_NONE, SIPTAG_FROM(p_from)),
1294 		      TAG_IF(p_from != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
1295 		      TAG_IF(p_to != SIP_NONE, SIPTAG_TO(p_to)),
1296 		      TAG_IF(p_to != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
1297 		      TAG_NEXT(tags));
1298 
1299   nh->nh_ptags =
1300     tl_filtered_tlist(nh->nh_home, paramfilter, TAG_NEXT(tags));
1301 
1302   error = nh->nh_tags == NULL || nh->nh_ptags == NULL;
1303 
1304   if (!error)
1305     tl_gets(nh->nh_tags,	/* These does not change while nh lives */
1306 	    SIPTAG_FROM_REF(nh->nh_ds->ds_local),
1307 	    SIPTAG_TO_REF(nh->nh_ds->ds_remote),
1308 	    TAG_END());
1309 
1310   if (nh->nh_ptags && nh->nh_ptags->t_tag == NULL)
1311     su_free(nh->nh_home, nh->nh_ptags), nh->nh_ptags = NULL;
1312 
1313   if (identity)
1314     nh->nh_identity = nua_handle_ref(identity);
1315 
1316   su_home_deinit(tmphome);
1317 
1318   return -error;
1319 }
1320 
1321 /** Filter tags used for settings. */
nua_handle_param_filter(tagi_t const * f,tagi_t const * t)1322 static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t)
1323 {
1324   char const *ns;
1325 
1326   if (!t || !t->t_tag)
1327     return 0;
1328 
1329   if (t->t_tag == nutag_url ||
1330       t->t_tag == nutag_sips_url ||
1331       t->t_tag == nutag_ws_url ||
1332       t->t_tag == nutag_wss_url ||
1333       t->t_tag == nutag_identity)
1334     return 0;
1335 
1336   ns = t->t_tag->tt_ns;
1337   if (!ns)
1338     return 0;
1339 
1340   return strcmp(ns, "nua") == 0 || strcmp(ns, "soa") == 0;
1341 }
1342 
1343 /** Filter tags stored permanently as taglist. */
nua_handle_tags_filter(tagi_t const * f,tagi_t const * t)1344 static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t)
1345 {
1346   tag_type_t tag;
1347 
1348   if (!t || !t->t_tag)
1349     return 0;
1350 
1351   tag = t->t_tag;
1352 
1353   if (tag == tag_filter)
1354     return 0;
1355 
1356   /* Accept @From or @To only when they are followed by
1357      TAG_FILTER(nua_handle_tags_filter) */
1358   if (tag == siptag_from || tag == siptag_to) {
1359     t = tl_next(t);
1360     return t && t->t_tag == tag_filter &&
1361       t->t_value == (tag_value_t)nua_handle_tags_filter;
1362   }
1363 
1364   if (tag == nutag_identity)
1365     return 0;
1366   if (tag == siptag_from_str)
1367     return 0;
1368   if (tag == siptag_to_str)
1369     return 0;
1370 
1371   /** Ignore @CSeq, @RSeq, @RAck, @Timestamp, and @ContentLength */
1372   if (tag == siptag_cseq || tag == siptag_cseq_str)
1373     return 0;
1374   if (tag == siptag_rseq || tag == siptag_rseq_str)
1375     return 0;
1376   if (tag == siptag_rack || tag == siptag_rack_str)
1377     return 0;
1378   if (tag == siptag_timestamp || tag == siptag_timestamp_str)
1379     return 0;
1380   if (tag == siptag_content_length || tag == siptag_content_length_str)
1381     return 0;
1382 
1383   return ! nua_handle_param_filter(f, t);
1384 }
1385 
1386 static
nua_stack_set_smime_params(nua_t * nua,tagi_t const * tags)1387 int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
1388 {
1389 #if HAVE_SOFIA_SMIME
1390   int           smime_enable = nua->sm->sm_enable;
1391   int           smime_opt = nua->sm->sm_opt;
1392   int           smime_protection_mode = nua->sm->sm_protection_mode;
1393   char const   *smime_message_digest = NONE;
1394   char const   *smime_signature = NONE;
1395   char const   *smime_key_encryption = NONE;
1396   char const   *smime_message_encryption = NONE;
1397   char const   *smime_path = NONE;
1398 
1399   int n;
1400 
1401   n = tl_gets(tags,
1402 	      NUTAG_SMIME_ENABLE_REF(smime_enable),
1403 	      NUTAG_SMIME_OPT_REF(smime_opt),
1404 	      NUTAG_SMIME_PROTECTION_MODE_REF(smime_protection_mode),
1405 	      NUTAG_SMIME_MESSAGE_DIGEST_REF(smime_message_digest),
1406 	      NUTAG_SMIME_SIGNATURE_REF(smime_signature),
1407 	      NUTAG_SMIME_KEY_ENCRYPTION_REF(smime_key_encryption),
1408 	      NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(smime_message_encryption),
1409 	      NUTAG_CERTIFICATE_DIR_REF(smime_path),
1410 	      TAG_NULL());
1411   if (n <= 0)
1412     return n;
1413 
1414   /* XXX - all other S/MIME parameters? */
1415   return sm_set_params(nua->sm, smime_enable, smime_opt,
1416 		       smime_protection_mode, smime_path);
1417 #endif
1418 
1419   return 0;
1420 }
1421 
1422 /**@fn void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
1423  *
1424  * Get NUA parameters matching with the given filter.
1425  * The values of NUA parameters is returned in #nua_r_get_params event.
1426  *
1427  * @param nua             Pointer to NUA stack object
1428  * @param tag, value, ... List of tagged parameters
1429  *
1430  * @return
1431  *     nothing
1432  *
1433  * @par Related tags:
1434  *     TAG_ANY() \n
1435  *     otherwise same tags as nua_set_params()
1436  *
1437  * @par Events:
1438  *     #nua_r_get_params
1439  *
1440  * @par Examples
1441  * Find out default values of all parameters:
1442  * @code
1443  *    nua_get_params(nua, TAG_ANY(), TAG_END());
1444  * @endcode
1445  */
1446 
1447 /**@fn void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
1448  *
1449  * Get values of handle-specific parameters in #nua_r_get_params event.
1450  *
1451  * Application will specify either expilicit list of tags it is interested
1452  * in, or a filter (at the moment, TAG_ANY()). The values are returned as a
1453  * list of tags in the #nua_r_get_params event.
1454  *
1455  * @param nh              Pointer to operation handle
1456  * @param tag, value, ... List of tagged parameters
1457  *
1458  * The handle-specific parameters will contain only the parameters actually
1459  * modified by application, either by nua_set_hparams() or some other
1460  * handle-specific call. Currently, no NTA parameters are returned. They are
1461  * returned only when application asks for user-agent-level parameters using
1462  * either nua_get_params() or using default handle, eg.
1463  * @code
1464  * nua_get_hparams(nua_default(nua), TAG_ANY())
1465  * @endcode
1466  *
1467  * @return
1468  *     nothing
1469  *
1470  * @par Related tags:
1471  *     #TAG_ANY \n
1472  *     othervise same tags as nua_set_hparams()
1473  *
1474  * @par Events:
1475  *     #nua_r_get_params
1476  */
1477 
1478 /** @NUA_EVENT nua_r_get_params
1479  *
1480  * Answer to nua_get_params() or nua_get_hparams().
1481  *
1482  * @param status 200 when succesful, error code otherwise
1483  * @param phrase a short textual description of @a status code
1484  * @param nh     NULL when responding to nua_get_params(),
1485  *               operation handle when responding to nua_get_hparams()
1486  * @param hmagic NULL when responding to nua_get_params(),
1487  *               application contact associated with the operation handle
1488  *               when responding to nua_get_hparams()
1489  * @param sip    NULL
1490  * @param tags
1491  *   NUTAG_APPL_METHOD() \n
1492  *   NUTAG_AUTH_CACHE() \n
1493  *   NUTAG_AUTOACK() \n
1494  *   NUTAG_AUTOALERT() \n
1495  *   NUTAG_AUTOANSWER() \n
1496  *   NUTAG_CALLEE_CAPS() \n
1497  *   NUTAG_DETECT_NETWORK_UPDATES() \n
1498  *   NUTAG_EARLY_ANSWER() \n
1499  *   NUTAG_EARLY_MEDIA() \n
1500  *   NUTAG_ENABLEINVITE() \n
1501  *   NUTAG_ENABLEMESSAGE() \n
1502  *   NUTAG_ENABLEMESSENGER() \n
1503  *   NUTAG_INITIAL_ROUTE() \n
1504  *   NUTAG_INITIAL_ROUTE_STR() \n
1505  *   NUTAG_INSTANCE() \n
1506  *   NUTAG_INVITE_TIMER() \n
1507  *   NUTAG_KEEPALIVE() \n
1508  *   NUTAG_KEEPALIVE_STREAM() \n
1509  *   NUTAG_MAX_SUBSCRIPTIONS() \n
1510  *   NUTAG_MEDIA_ENABLE() \n
1511  *   NUTAG_MEDIA_FEATURES() \n
1512  *   NUTAG_MIN_SE() \n
1513  *   NUTAG_M_DISPLAY() \n
1514  *   NUTAG_M_FEATURES() \n
1515  *   NUTAG_M_PARAMS() \n
1516  *   NUTAG_M_USERNAME() \n
1517  *   NUTAG_ONLY183_100REL() \n
1518  *   NUTAG_OUTBOUND() \n
1519  *   NUTAG_PATH_ENABLE() \n
1520  *   NUTAG_RETRY_AFTER_ENABLE() \n
1521  *   NUTAG_REFER_EXPIRES() \n
1522  *   NUTAG_REFER_WITH_ID() \n
1523  *   NUTAG_REFRESH_WITHOUT_SDP() \n
1524  *   NUTAG_REGISTRAR() \n
1525  *   NUTAG_RETRY_COUNT() \n
1526  *   NUTAG_SERVICE_ROUTE_ENABLE() \n
1527  *   NUTAG_SESSION_REFRESHER() \n
1528  *   NUTAG_SESSION_TIMER() \n
1529  *   NUTAG_SMIME_ENABLE() \n
1530  *   NUTAG_SMIME_KEY_ENCRYPTION() \n
1531  *   NUTAG_SMIME_MESSAGE_DIGEST() \n
1532  *   NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
1533  *   NUTAG_SMIME_OPT() \n
1534  *   NUTAG_SMIME_PROTECTION_MODE() \n
1535  *   NUTAG_SMIME_SIGNATURE() \n
1536  *   NUTAG_SOA_NAME() \n
1537  *   NUTAG_SUBSTATE() \n
1538  *   NUTAG_SUB_EXPIRES() \n
1539  *   NUTAG_UPDATE_REFRESH() \n
1540  *   NUTAG_USER_AGENT() \n
1541  *   SIPTAG_ALLOW() \n
1542  *   SIPTAG_ALLOW_STR() \n
1543  *   SIPTAG_ALLOW_EVENTS() \n
1544  *   SIPTAG_ALLOW_EVENTS_STR() \n
1545  *   SIPTAG_FROM() \n
1546  *   SIPTAG_FROM_STR() \n
1547  *   SIPTAG_ORGANIZATION() \n
1548  *   SIPTAG_ORGANIZATION_STR() \n
1549  *   SIPTAG_SUPPORTED() \n
1550  *   SIPTAG_SUPPORTED_STR() \n
1551  *   SIPTAG_USER_AGENT() \n
1552  *   SIPTAG_USER_AGENT_STR() \n
1553  *
1554  * @sa nua_get_params(), nua_get_hparams(),
1555  * nua_set_params(), nua_set_hparams(), #nua_r_set_params
1556  *
1557  * @END_NUA_EVENT
1558  */
1559 
1560 /**@internal
1561  * Send a list of NUA parameters to the application.
1562  *
1563  * This function gets invoked when application calls either nua_get_params()
1564  * or nua_get_hparams().
1565  *
1566  * The parameter tag list will initially contain all the relevant parameter
1567  * tags, and it will be filtered down to parameters asked by application.
1568  *
1569  * The handle-specific parameters will contain only the parameters actually
1570  * modified by application, either by nua_set_hparams() or some other
1571  * handle-specific call. NTA parameters are returned only when application
1572  * asks for user-agent-level parameters using nua_get_params().
1573  *
1574  */
nua_stack_get_params(nua_t * nua,nua_handle_t * nh,nua_event_t e,tagi_t const * tags)1575 int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1576 			 tagi_t const *tags)
1577 {
1578   nua_handle_t *dnh = nua->nua_dhandle;
1579   nua_global_preferences_t const *ngp = nua->nua_prefs;
1580   nua_handle_preferences_t const *nhp = nh->nh_prefs;
1581   nua_handle_preferences_t const nhp_zero[1] = {{ 0 }};
1582   tagi_t *lst;
1583 
1584   int has_from;
1585   sip_from_t from[1];
1586 
1587   sip_contact_t const *m;
1588 
1589   /* nta */
1590   unsigned udp_mtu = 0;
1591   usize_t max_proceeding = 0;
1592   unsigned sip_t1 = 0, sip_t2 = 0, sip_t4 = 0, sip_t1x64 = 0;
1593   unsigned debug_drop_prob = 0;
1594   url_string_t const *proxy = NULL;
1595   sip_contact_t const *aliases = NULL;
1596   unsigned flags = 0;
1597 
1598   /* soa */
1599   tagi_t *media_params = NULL;
1600 
1601   su_home_t tmphome[SU_HOME_AUTO_SIZE(16536)];
1602 
1603   enter;
1604 
1605   if (nh == dnh)
1606     nta_agent_get_params(nua->nua_nta,
1607 			 NTATAG_UDP_MTU_REF(udp_mtu),
1608 			 NTATAG_MAX_PROCEEDING_REF(max_proceeding),
1609 			 NTATAG_SIP_T1_REF(sip_t1),
1610 			 NTATAG_SIP_T2_REF(sip_t2),
1611 			 NTATAG_SIP_T4_REF(sip_t4),
1612 			 NTATAG_SIP_T1X64_REF(sip_t1x64),
1613 			 NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob),
1614 			 NTATAG_DEFAULT_PROXY_REF(proxy),
1615 			 NTATAG_ALIASES_REF(aliases),
1616 			 NTATAG_SIPFLAGS_REF(flags),
1617 			 TAG_END());
1618 
1619   if (nh->nh_ds->ds_local)
1620     has_from = 1, *from = *nh->nh_ds->ds_local, from->a_params = NULL;
1621   else /* if (nua->nua_from_is_set) */
1622     has_from = 1, *from = *nua->nua_from;
1623 
1624   media_params = soa_get_paramlist(nh->nh_soa, TAG_END());
1625 
1626   m = nua_stack_get_contact(nua->nua_registrations);
1627 
1628   /* Include tag in the list returned to user
1629    * if it has been earlier set (by user) */
1630 #define TIF(TAG, pref) \
1631   TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
1632 
1633   /* Include tag in the list returned to user
1634    * if it has been earlier set (by user)
1635    * but always include in the default parameters */
1636 #define TIFD(TAG, pref) \
1637   TAG_IF(nh == dnh || nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
1638 
1639   /* Include string tag made out of SIP header
1640    * if it has been earlier set (by user) */
1641 #define TIF_STR(TAG, pref)						\
1642   TAG_IF(nhp->nhp_set.nhb_##pref,					\
1643 	 TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref			\
1644 	     ? sip_header_as_string(tmphome, (void *)nhp->nhp_##pref) : NULL))
1645 
1646   /* Include header tag made out of string
1647    * if it has been earlier set (by user) */
1648 #define TIF_SIP(TAG, pref)						\
1649   TAG_IF(nhp->nhp_set.nhb_##pref,					\
1650 	 TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref			\
1651 	     ? sip_##pref##_make(tmphome, (char *)nhp->nhp_##pref)	\
1652 	     : NULL))
1653 
1654   if (nh != dnh && nhp == dnh->nh_prefs)
1655     nhp = nhp_zero;
1656 
1657   su_home_auto(tmphome, sizeof(tmphome));
1658 
1659   lst = tl_filtered_tlist
1660     (tmphome, tags,
1661      TAG_IF(has_from, SIPTAG_FROM(from)),
1662      TAG_IF(has_from,
1663 	    SIPTAG_FROM_STR(has_from
1664 			    ? sip_header_as_string(tmphome, (void *)from)
1665 			    : NULL)),
1666 
1667      TIF(NUTAG_RETRY_COUNT, retry_count),
1668      TIF(NUTAG_MAX_SUBSCRIPTIONS, max_subscriptions),
1669 
1670      TIF(NUTAG_SOA_NAME, soa_name),
1671      TIF(NUTAG_MEDIA_ENABLE, media_enable),
1672      TIF(NUTAG_ENABLEINVITE, invite_enable),
1673      TIF(NUTAG_AUTOALERT, auto_alert),
1674      TIF(NUTAG_EARLY_ANSWER, early_answer),
1675      TIF(NUTAG_EARLY_MEDIA, early_media),
1676      TIF(NUTAG_ONLY183_100REL, only183_100rel),
1677      TIF(NUTAG_AUTOANSWER, auto_answer),
1678      TIF(NUTAG_AUTOACK, auto_ack),
1679      TIF(NUTAG_TIMER_AUTOREQUIRE, timer_autorequire),
1680      TIF(NUTAG_INVITE_TIMER, invite_timeout),
1681 
1682      TIFD(NUTAG_SESSION_TIMER, session_timer),
1683      TIF(NUTAG_MIN_SE, min_se),
1684      TIFD(NUTAG_SESSION_REFRESHER, refresher),
1685      TIF(NUTAG_UPDATE_REFRESH, update_refresh),
1686      TIF(NUTAG_REFRESH_WITHOUT_SDP, refresh_without_sdp),
1687 
1688      TIF(NUTAG_ENABLEMESSAGE, message_enable),
1689      TIF(NUTAG_ENABLEMESSENGER, win_messenger_enable),
1690      /* TIF(NUTAG_AUTORESPOND, autorespond), */
1691 
1692      TIF(NUTAG_CALLEE_CAPS, callee_caps),
1693      TIF(NUTAG_MEDIA_FEATURES, media_features),
1694      TIF(NUTAG_SERVICE_ROUTE_ENABLE, service_route_enable),
1695      TIF(NUTAG_PATH_ENABLE, path_enable),
1696      TIF(NUTAG_RETRY_AFTER_ENABLE, retry_after_enable),
1697      TIF(NUTAG_AUTH_CACHE, auth_cache),
1698      TIF(NUTAG_REFER_EXPIRES, refer_expires),
1699      TIF(NUTAG_REFER_WITH_ID, refer_with_id),
1700 
1701      TIF(NUTAG_SUBSTATE, substate),
1702      TIF(NUTAG_SUB_EXPIRES, sub_expires),
1703 
1704      TIF(SIPTAG_SUPPORTED, supported),
1705      TIF_STR(SIPTAG_SUPPORTED_STR, supported),
1706      TIF(SIPTAG_ALLOW, allow),
1707      TIF_STR(SIPTAG_ALLOW_STR, allow),
1708      TIF_STR(NUTAG_APPL_METHOD, appl_method),
1709      TIF(SIPTAG_ALLOW_EVENTS, allow_events),
1710      TIF_STR(SIPTAG_ALLOW_EVENTS_STR, allow_events),
1711      TIF_SIP(SIPTAG_USER_AGENT, user_agent),
1712      TIF(SIPTAG_USER_AGENT_STR, user_agent),
1713      TIF(NUTAG_USER_AGENT, user_agent),
1714 
1715      TIF_SIP(SIPTAG_ORGANIZATION, organization),
1716      TIF(SIPTAG_ORGANIZATION_STR, organization),
1717 
1718      TIF_SIP(SIPTAG_VIA, via),
1719      TIF(SIPTAG_VIA_STR, via),
1720 
1721      TIF(NUTAG_INITIAL_ROUTE, initial_route),
1722      TIF_STR(NUTAG_INITIAL_ROUTE_STR, initial_route),
1723 
1724      TIF(NUTAG_REGISTRAR, registrar),
1725      TIF(NUTAG_KEEPALIVE, keepalive),
1726      TIF(NUTAG_KEEPALIVE_STREAM, keepalive_stream),
1727 
1728      TIF(NUTAG_INSTANCE, instance),
1729      TIF(NUTAG_M_DISPLAY, m_display),
1730      TIF(NUTAG_M_USERNAME, m_username),
1731      TIF(NUTAG_M_PARAMS, m_params),
1732      TIF(NUTAG_M_FEATURES, m_features),
1733      TIF(NUTAG_OUTBOUND, outbound),
1734 
1735      /* Handle-specific proxy */
1736      TAG_IF(nh != dnh && nhp->nhp_set.nhb_proxy,
1737 	    NUTAG_PROXY(nhp->nhp_proxy)),
1738 
1739      /* Skip user-agent-level parameters if parameters are for handle only */
1740      TAG_IF(nh != dnh, TAG_NEXT(media_params)),
1741 
1742   /* Include tag in the list returned to user
1743    * if it has been earlier set (by user) */
1744 #define GIF(TAG, pref) \
1745      TAG_IF(ngp->ngp_set.ngp_##pref, TAG(ngp->ngp_##pref))
1746 
1747      GIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
1748      GIF(NUTAG_SHUTDOWN_EVENTS, shutdown_events),
1749 
1750      NTATAG_CONTACT(m),
1751 
1752 #if HAVE_SOFIA_SMIME
1753      NUTAG_SMIME_ENABLE(nua->sm->sm_enable),
1754      NUTAG_SMIME_OPT(nua->sm->sm_opt),
1755      NUTAG_SMIME_PROTECTION_MODE(nua->sm->sm_protection_mode),
1756      NUTAG_SMIME_MESSAGE_DIGEST(nua->sm->sm_message_digest),
1757      NUTAG_SMIME_SIGNATURE(nua->sm->sm_signature),
1758      NUTAG_SMIME_KEY_ENCRYPTION(nua->sm->sm_key_encryption),
1759      NUTAG_SMIME_MESSAGE_ENCRYPTION(nua->sm->sm_message_encryption),
1760 #endif
1761 
1762      NTATAG_UDP_MTU(udp_mtu),
1763      NTATAG_MAX_PROCEEDING(max_proceeding),
1764      NTATAG_SIP_T1(sip_t1),
1765      NTATAG_SIP_T2(sip_t2),
1766      NTATAG_SIP_T4(sip_t4),
1767      NTATAG_SIP_T1X64(sip_t1x64),
1768      NTATAG_DEBUG_DROP_PROB(debug_drop_prob),
1769      /* Stack-wide proxy */
1770      NTATAG_DEFAULT_PROXY(proxy),
1771      NTATAG_ALIASES(aliases),
1772      NTATAG_SIPFLAGS(flags),
1773 
1774      TAG_NEXT(media_params));
1775 
1776   nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, lst);
1777 
1778   su_home_deinit(tmphome);
1779 
1780   tl_vfree(media_params);
1781 
1782   return 0;
1783 }
1784