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