pjsip/config_global: regcontext context not created
[asterisk/asterisk.git] / res / res_pjsip / config_global.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 #include "asterisk.h"
20
21 #include <pjsip.h>
22 #include <pjlib.h>
23
24 #include "asterisk/res_pjsip.h"
25 #include "include/res_pjsip_private.h"
26 #include "asterisk/pbx.h"
27 #include "asterisk/sorcery.h"
28 #include "asterisk/taskprocessor.h"
29 #include "asterisk/ast_version.h"
30 #include "asterisk/res_pjsip_cli.h"
31
32 #define DEFAULT_MAX_FORWARDS 70
33 #define DEFAULT_KEEPALIVE_INTERVAL 90
34 #define DEFAULT_USERAGENT_PREFIX "Asterisk PBX"
35 #define DEFAULT_OUTBOUND_ENDPOINT "default_outbound_endpoint"
36 #define DEFAULT_DEBUG "no"
37 #define DEFAULT_ENDPOINT_IDENTIFIER_ORDER "ip,username,anonymous"
38 #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0
39 #define DEFAULT_FROM_USER "asterisk"
40 #define DEFAULT_REALM "asterisk"
41 #define DEFAULT_REGCONTEXT ""
42 #define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30
43 #define DEFAULT_DISABLE_MULTI_DOMAIN 0
44 #define DEFAULT_VOICEMAIL_EXTENSION ""
45 #define DEFAULT_UNIDENTIFIED_REQUEST_COUNT 5
46 #define DEFAULT_UNIDENTIFIED_REQUEST_PERIOD 5
47 #define DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL 30
48 #define DEFAULT_MWI_TPS_QUEUE_HIGH AST_TASKPROCESSOR_HIGH_WATER_LEVEL
49 #define DEFAULT_MWI_TPS_QUEUE_LOW -1
50 #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0
51 #define DEFAULT_IGNORE_URI_USER_OPTIONS 0
52 #define DEFAULT_USE_CALLERID_CONTACT 0
53 #define DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION 0
54
55 /*!
56  * \brief Cached global config object
57  *
58  * \details
59  * Cached so we don't have to keep asking sorcery for the config.
60  * We could ask for it hundreds of times a second if not more.
61  */
62 static AO2_GLOBAL_OBJ_STATIC(global_cfg);
63
64 static char default_useragent[256];
65
66 struct global_config {
67         SORCERY_OBJECT(details);
68         AST_DECLARE_STRING_FIELDS(
69                 AST_STRING_FIELD(useragent);
70                 AST_STRING_FIELD(regcontext);
71                 AST_STRING_FIELD(default_outbound_endpoint);
72                 /*! Debug logging yes|no|host */
73                 AST_STRING_FIELD(debug);
74                 /*! Order by which endpoint identifiers are checked (comma separated list) */
75                 AST_STRING_FIELD(endpoint_identifier_order);
76                 /*! User name to place in From header if there is no better option */
77                 AST_STRING_FIELD(default_from_user);
78                 /*! Default voicemail extension */
79                 AST_STRING_FIELD(default_voicemail_extension);
80                 /*! Realm to use in challenges before an endpoint is identified */
81                 AST_STRING_FIELD(default_realm);
82         );
83         /*! Value to put in Max-Forwards header */
84         unsigned int max_forwards;
85         /*! The interval at which to send keep alive messages to active connection-oriented transports */
86         unsigned int keep_alive_interval;
87         /*! The maximum time for all contacts to be qualified at startup */
88         unsigned int max_initial_qualify_time;
89         /*! The interval at which to check for expired contacts */
90         unsigned int contact_expiration_check_interval;
91         /*! Nonzero to disable multi domain support */
92         unsigned int disable_multi_domain;
93         /*! The maximum number of unidentified requests per source IP address before a security event is logged */
94         unsigned int unidentified_request_count;
95         /*! The period during which unidentified requests are accumulated */
96         unsigned int unidentified_request_period;
97         /*! Interval at which expired unidentifed requests will be pruned */
98         unsigned int unidentified_request_prune_interval;
99         struct {
100                 /*! Taskprocessor high water alert trigger level */
101                 unsigned int tps_queue_high;
102                 /*! Taskprocessor low water clear alert level. */
103                 int tps_queue_low;
104                 /*! Nonzero to disable sending unsolicited mwi to all endpoints on startup */
105                 unsigned int disable_initial_unsolicited;
106         } mwi;
107         /*! Nonzero if URI user field options are ignored. */
108         unsigned int ignore_uri_user_options;
109         /*! Nonzero if CALLERID(num) is to be used as the default contact username instead of default_from_user */
110         unsigned int use_callerid_contact;
111         /*! Nonzero if need to send AMI ContactStatus event when a contact is updated */
112         unsigned int send_contact_status_on_update_registration;
113 };
114
115 static void global_destructor(void *obj)
116 {
117         struct global_config *cfg = obj;
118
119         ast_string_field_free_memory(cfg);
120 }
121
122 static void *global_alloc(const char *name)
123 {
124         struct global_config *cfg;
125
126         cfg = ast_sorcery_generic_alloc(sizeof(*cfg), global_destructor);
127         if (!cfg || ast_string_field_init(cfg, 100)) {
128                 ao2_cleanup(cfg);
129                 return NULL;
130         }
131
132         return cfg;
133 }
134
135 /*
136  * There is ever only one global section, so we can use a single global
137  * value here to track the regcontext through reloads.
138  */
139 static char *previous_regcontext = NULL;
140
141 static int check_regcontext(const struct global_config *cfg)
142 {
143         char *current = NULL;
144
145         if (previous_regcontext && !strcmp(previous_regcontext, cfg->regcontext)) {
146                 /* Nothing changed so nothing to do */
147                 return 0;
148         }
149
150         if (!ast_strlen_zero(cfg->regcontext)) {
151                 current = ast_strdup(cfg->regcontext);
152                 if (!current) {
153                         return -1;
154                 }
155
156                 if (ast_sip_persistent_endpoint_add_to_regcontext(cfg->regcontext)) {
157                         ast_free(current);
158                         return -1;
159                 }
160         }
161
162         if (!ast_strlen_zero(previous_regcontext)) {
163                 ast_context_destroy_by_name(previous_regcontext, "PJSIP");
164                 ast_free(previous_regcontext);
165                 previous_regcontext = NULL;
166         }
167
168         if (current) {
169                 previous_regcontext = current;
170         }
171
172         return 0;
173 }
174
175 static int global_apply(const struct ast_sorcery *sorcery, void *obj)
176 {
177         struct global_config *cfg = obj;
178         char max_forwards[10];
179
180         if (ast_strlen_zero(cfg->debug)) {
181                 ast_log(LOG_ERROR,
182                         "Global option 'debug' can't be empty.  Set it to a valid value or remove the entry to accept 'no' as the default\n");
183                 return -1;
184         }
185
186         if (ast_strlen_zero(cfg->default_from_user)) {
187                 ast_log(LOG_ERROR,
188                         "Global option 'default_from_user' can't be empty.  Set it to a valid value or remove the entry to accept 'asterisk' as the default\n");
189                 return -1;
190         }
191
192         snprintf(max_forwards, sizeof(max_forwards), "%u", cfg->max_forwards);
193
194         ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1);
195         ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1);
196         ast_sip_add_global_response_header("Server", cfg->useragent, 1);
197
198         if (check_regcontext(cfg)) {
199                 return -1;
200         }
201
202         ao2_t_global_obj_replace_unref(global_cfg, cfg, "Applying global settings");
203         return 0;
204 }
205
206 static struct global_config *get_global_cfg(void)
207 {
208         return ao2_global_obj_ref(global_cfg);
209 }
210
211 char *ast_sip_global_default_outbound_endpoint(void)
212 {
213         char *str;
214         struct global_config *cfg;
215
216         cfg = get_global_cfg();
217         if (!cfg) {
218                 return ast_strdup(DEFAULT_OUTBOUND_ENDPOINT);
219         }
220
221         str = ast_strdup(cfg->default_outbound_endpoint);
222         ao2_ref(cfg, -1);
223         return str;
224 }
225
226 char *ast_sip_get_debug(void)
227 {
228         char *res;
229         struct global_config *cfg;
230
231         cfg = get_global_cfg();
232         if (!cfg) {
233                 return ast_strdup(DEFAULT_DEBUG);
234         }
235
236         res = ast_strdup(cfg->debug);
237         ao2_ref(cfg, -1);
238         return res;
239 }
240
241 char *ast_sip_get_regcontext(void)
242 {
243         char *res;
244         struct global_config *cfg;
245
246         cfg = get_global_cfg();
247         if (!cfg) {
248                 return ast_strdup(DEFAULT_REGCONTEXT);
249         }
250
251         res = ast_strdup(cfg->regcontext);
252         ao2_ref(cfg, -1);
253
254         return res;
255 }
256
257 char *ast_sip_get_default_voicemail_extension(void)
258 {
259         char *res;
260         struct global_config *cfg;
261
262         cfg = get_global_cfg();
263         if (!cfg) {
264                 return ast_strdup(DEFAULT_VOICEMAIL_EXTENSION);
265         }
266
267         res = ast_strdup(cfg->default_voicemail_extension);
268         ao2_ref(cfg, -1);
269
270         return res;
271 }
272
273 char *ast_sip_get_endpoint_identifier_order(void)
274 {
275         char *res;
276         struct global_config *cfg;
277
278         cfg = get_global_cfg();
279         if (!cfg) {
280                 return ast_strdup(DEFAULT_ENDPOINT_IDENTIFIER_ORDER);
281         }
282
283         res = ast_strdup(cfg->endpoint_identifier_order);
284         ao2_ref(cfg, -1);
285         return res;
286 }
287
288 unsigned int ast_sip_get_keep_alive_interval(void)
289 {
290         unsigned int interval;
291         struct global_config *cfg;
292
293         cfg = get_global_cfg();
294         if (!cfg) {
295                 return DEFAULT_KEEPALIVE_INTERVAL;
296         }
297
298         interval = cfg->keep_alive_interval;
299         ao2_ref(cfg, -1);
300         return interval;
301 }
302
303 unsigned int ast_sip_get_contact_expiration_check_interval(void)
304 {
305         unsigned int interval;
306         struct global_config *cfg;
307
308         cfg = get_global_cfg();
309         if (!cfg) {
310                 return DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL;
311         }
312
313         interval = cfg->contact_expiration_check_interval;
314         ao2_ref(cfg, -1);
315         return interval;
316 }
317
318 unsigned int ast_sip_get_disable_multi_domain(void)
319 {
320         unsigned int disable_multi_domain;
321         struct global_config *cfg;
322
323         cfg = get_global_cfg();
324         if (!cfg) {
325                 return DEFAULT_DISABLE_MULTI_DOMAIN;
326         }
327
328         disable_multi_domain = cfg->disable_multi_domain;
329         ao2_ref(cfg, -1);
330         return disable_multi_domain;
331 }
332
333 unsigned int ast_sip_get_max_initial_qualify_time(void)
334 {
335         unsigned int time;
336         struct global_config *cfg;
337
338         cfg = get_global_cfg();
339         if (!cfg) {
340                 return DEFAULT_MAX_INITIAL_QUALIFY_TIME;
341         }
342
343         time = cfg->max_initial_qualify_time;
344         ao2_ref(cfg, -1);
345         return time;
346 }
347
348 void ast_sip_get_unidentified_request_thresholds(unsigned int *count, unsigned int *period,
349         unsigned int *prune_interval)
350 {
351         struct global_config *cfg;
352
353         cfg = get_global_cfg();
354         if (!cfg) {
355                 *count = DEFAULT_UNIDENTIFIED_REQUEST_COUNT;
356                 *period = DEFAULT_UNIDENTIFIED_REQUEST_PERIOD;
357                 *prune_interval = DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL;
358                 return;
359         }
360
361         *count = cfg->unidentified_request_count;
362         *period = cfg->unidentified_request_period;
363         *prune_interval = cfg->unidentified_request_prune_interval;
364
365         ao2_ref(cfg, -1);
366         return;
367 }
368
369 void ast_sip_get_default_realm(char *realm, size_t size)
370 {
371         struct global_config *cfg;
372
373         cfg = get_global_cfg();
374         if (!cfg) {
375                 ast_copy_string(realm, DEFAULT_REALM, size);
376         } else {
377                 ast_copy_string(realm, cfg->default_realm, size);
378                 ao2_ref(cfg, -1);
379         }
380 }
381
382 void ast_sip_get_default_from_user(char *from_user, size_t size)
383 {
384         struct global_config *cfg;
385
386         cfg = get_global_cfg();
387         if (!cfg) {
388                 ast_copy_string(from_user, DEFAULT_FROM_USER, size);
389         } else {
390                 ast_copy_string(from_user, cfg->default_from_user, size);
391                 ao2_ref(cfg, -1);
392         }
393 }
394
395
396 unsigned int ast_sip_get_mwi_tps_queue_high(void)
397 {
398         unsigned int tps_queue_high;
399         struct global_config *cfg;
400
401         cfg = get_global_cfg();
402         if (!cfg) {
403                 return DEFAULT_MWI_TPS_QUEUE_HIGH;
404         }
405
406         tps_queue_high = cfg->mwi.tps_queue_high;
407         ao2_ref(cfg, -1);
408         return tps_queue_high;
409 }
410
411 int ast_sip_get_mwi_tps_queue_low(void)
412 {
413         int tps_queue_low;
414         struct global_config *cfg;
415
416         cfg = get_global_cfg();
417         if (!cfg) {
418                 return DEFAULT_MWI_TPS_QUEUE_LOW;
419         }
420
421         tps_queue_low = cfg->mwi.tps_queue_low;
422         ao2_ref(cfg, -1);
423         return tps_queue_low;
424 }
425
426 unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void)
427 {
428         unsigned int disable_initial_unsolicited;
429         struct global_config *cfg;
430
431         cfg = get_global_cfg();
432         if (!cfg) {
433                 return DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED;
434         }
435
436         disable_initial_unsolicited = cfg->mwi.disable_initial_unsolicited;
437         ao2_ref(cfg, -1);
438         return disable_initial_unsolicited;
439 }
440
441 unsigned int ast_sip_get_ignore_uri_user_options(void)
442 {
443         unsigned int ignore_uri_user_options;
444         struct global_config *cfg;
445
446         cfg = get_global_cfg();
447         if (!cfg) {
448                 return DEFAULT_IGNORE_URI_USER_OPTIONS;
449         }
450
451         ignore_uri_user_options = cfg->ignore_uri_user_options;
452         ao2_ref(cfg, -1);
453         return ignore_uri_user_options;
454 }
455
456 unsigned int ast_sip_get_use_callerid_contact(void)
457 {
458         unsigned int use_callerid_contact;
459         struct global_config *cfg;
460
461         cfg = get_global_cfg();
462         if (!cfg) {
463                 return DEFAULT_USE_CALLERID_CONTACT;
464         }
465
466         use_callerid_contact = cfg->use_callerid_contact;
467         ao2_ref(cfg, -1);
468         return use_callerid_contact;
469 }
470
471 unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
472 {
473         unsigned int send_contact_status_on_update_registration;
474         struct global_config *cfg;
475
476         cfg = get_global_cfg();
477         if (!cfg) {
478                 return DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION;
479         }
480
481         send_contact_status_on_update_registration = cfg->send_contact_status_on_update_registration;
482         ao2_ref(cfg, -1);
483         return send_contact_status_on_update_registration;
484 }
485
486 /*!
487  * \internal
488  * \brief Observer to set default global object if none exist.
489  *
490  * \param name Module name owning the sorcery instance.
491  * \param sorcery Instance being observed.
492  * \param object_type Name of object being observed.
493  * \param reloaded Non-zero if the object is being reloaded.
494  *
495  * \return Nothing
496  */
497 static void global_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
498 {
499         struct ao2_container *globals;
500         struct global_config *cfg;
501
502         if (strcmp(object_type, "global")) {
503                 /* Not interested */
504                 return;
505         }
506
507         globals = ast_sorcery_retrieve_by_fields(sorcery, "global",
508                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
509         if (globals) {
510                 int count;
511
512                 count = ao2_container_count(globals);
513                 ao2_ref(globals, -1);
514
515                 if (1 < count) {
516                         ast_log(LOG_ERROR,
517                                 "At most one pjsip.conf type=global object can be defined.  You have %d defined.\n",
518                                 count);
519                         return;
520                 }
521                 if (count) {
522                         return;
523                 }
524         }
525
526         ast_debug(1, "No pjsip.conf type=global object exists so applying defaults.\n");
527         cfg = ast_sorcery_alloc(sorcery, "global", NULL);
528         if (!cfg) {
529                 return;
530         }
531         global_apply(sorcery, cfg);
532         ao2_ref(cfg, -1);
533 }
534
535 static const struct ast_sorcery_instance_observer observer_callbacks_global = {
536         .object_type_loaded = global_loaded_observer,
537 };
538
539 int sip_cli_print_global(struct ast_sip_cli_context *context)
540 {
541         struct global_config *cfg = get_global_cfg();
542
543         if (!cfg) {
544                 cfg = ast_sorcery_alloc(ast_sip_get_sorcery(), "global", NULL);
545                 if (!cfg) {
546                         return -1;
547                 }
548         }
549
550         ast_str_append(&context->output_buffer, 0, "\nGlobal Settings:\n\n");
551         ast_sip_cli_print_sorcery_objectset(cfg, context, 0);
552
553         ao2_ref(cfg, -1);
554         return 0;
555 }
556
557 int ast_sip_destroy_sorcery_global(void)
558 {
559         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
560
561         ast_sorcery_instance_observer_remove(sorcery, &observer_callbacks_global);
562
563         if (previous_regcontext) {
564                 ast_context_destroy_by_name(previous_regcontext, "PJSIP");
565                 ast_free(previous_regcontext);
566         }
567
568         ao2_t_global_obj_release(global_cfg, "Module is unloading");
569
570         return 0;
571 }
572
573
574 int ast_sip_initialize_sorcery_global(void)
575 {
576         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
577
578         snprintf(default_useragent, sizeof(default_useragent), "%s %s",
579                 DEFAULT_USERAGENT_PREFIX, ast_get_version());
580
581         ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global,single_object=yes,explicit_name=global");
582
583         if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {
584                 return -1;
585         }
586
587         ast_sorcery_object_field_register(sorcery, "global", "type", "", OPT_NOOP_T, 0, 0);
588         ast_sorcery_object_field_register(sorcery, "global", "max_forwards",
589                 __stringify(DEFAULT_MAX_FORWARDS),
590                 OPT_UINT_T, 0, FLDSET(struct global_config, max_forwards));
591         ast_sorcery_object_field_register(sorcery, "global", "user_agent", default_useragent,
592                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, useragent));
593         ast_sorcery_object_field_register(sorcery, "global", "default_outbound_endpoint",
594                 DEFAULT_OUTBOUND_ENDPOINT,
595                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_outbound_endpoint));
596         ast_sorcery_object_field_register(sorcery, "global", "debug", DEFAULT_DEBUG,
597                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, debug));
598         ast_sorcery_object_field_register(sorcery, "global", "endpoint_identifier_order",
599                 DEFAULT_ENDPOINT_IDENTIFIER_ORDER,
600                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, endpoint_identifier_order));
601         ast_sorcery_object_field_register(sorcery, "global", "keep_alive_interval",
602                 __stringify(DEFAULT_KEEPALIVE_INTERVAL),
603                 OPT_UINT_T, 0, FLDSET(struct global_config, keep_alive_interval));
604         ast_sorcery_object_field_register(sorcery, "global", "max_initial_qualify_time",
605                 __stringify(DEFAULT_MAX_INITIAL_QUALIFY_TIME),
606                 OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time));
607         ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER,
608                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user));
609         ast_sorcery_object_field_register(sorcery, "global", "default_voicemail_extension",
610                 DEFAULT_VOICEMAIL_EXTENSION, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config,
611                 default_voicemail_extension));
612         ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT,
613                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext));
614         ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval",
615                 __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL),
616                 OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval));
617         ast_sorcery_object_field_register(sorcery, "global", "disable_multi_domain",
618                 DEFAULT_DISABLE_MULTI_DOMAIN ? "yes" : "no",
619                 OPT_BOOL_T, 1, FLDSET(struct global_config, disable_multi_domain));
620         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_count",
621                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_COUNT),
622                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_count));
623         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_period",
624                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PERIOD),
625                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_period));
626         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_prune_interval",
627                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL),
628                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_prune_interval));
629         ast_sorcery_object_field_register(sorcery, "global", "default_realm", DEFAULT_REALM,
630                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_realm));
631         ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_high",
632                 __stringify(DEFAULT_MWI_TPS_QUEUE_HIGH),
633                 OPT_UINT_T, 0, FLDSET(struct global_config, mwi.tps_queue_high));
634         ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_low",
635                 __stringify(DEFAULT_MWI_TPS_QUEUE_LOW),
636                 OPT_INT_T, 0, FLDSET(struct global_config, mwi.tps_queue_low));
637         ast_sorcery_object_field_register(sorcery, "global", "mwi_disable_initial_unsolicited",
638                 DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED ? "yes" : "no",
639                 OPT_BOOL_T, 1, FLDSET(struct global_config, mwi.disable_initial_unsolicited));
640         ast_sorcery_object_field_register(sorcery, "global", "ignore_uri_user_options",
641                 DEFAULT_IGNORE_URI_USER_OPTIONS ? "yes" : "no",
642                 OPT_BOOL_T, 1, FLDSET(struct global_config, ignore_uri_user_options));
643         ast_sorcery_object_field_register(sorcery, "global", "use_callerid_contact",
644                 DEFAULT_USE_CALLERID_CONTACT ? "yes" : "no",
645                 OPT_YESNO_T, 1, FLDSET(struct global_config, use_callerid_contact));
646         ast_sorcery_object_field_register(sorcery, "global", "send_contact_status_on_update_registration",
647                 DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION ? "yes" : "no",
648                 OPT_YESNO_T, 1, FLDSET(struct global_config, send_contact_status_on_update_registration));
649
650         if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) {
651                 return -1;
652         }
653
654         return 0;
655 }