Asterisk - The Open Source Telephony Project GIT-master-2de1a68
pbx_config.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@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/*! \file
20 *
21 * \brief Populate and remember extensions from static config file
22 *
23 *
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30/*** DOCUMENTATION
31 <manager name="DialplanExtensionAdd" language="en_US">
32 <synopsis>
33 Add an extension to the dialplan
34 </synopsis>
35 <syntax>
36 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
37 <parameter name="Context" required="true">
38 <para>Context where the extension will be created. The context will
39 be created if it does not already exist.</para>
40 </parameter>
41 <parameter name="Extension" required="true">
42 <para>Name of the extension that will be created (may include callerid match by separating
43 with '/')</para>
44 </parameter>
45 <parameter name="Priority" required="true">
46 <para>Priority being added to this extension. Must be either <literal>hint</literal> or a
47 numerical value.</para>
48 </parameter>
49 <parameter name="Application" required="true">
50 <para>The application to use for this extension at the requested priority</para>
51 </parameter>
52 <parameter name="ApplicationData" required="false">
53 <para>Arguments to the application.</para>
54 </parameter>
55 <parameter name="Replace" required="false">
56 <para>If set to 'yes', '1', 'true' or any of the other values we evaluate as true, then
57 if an extension already exists at the requested context, extension, and priority it will
58 be overwritten. Otherwise, the existing extension will remain and the action will fail.
59 </para>
60 </parameter>
61 </syntax>
62 </manager>
63 <manager name="DialplanExtensionRemove" language="en_US">
64 <synopsis>
65 Remove an extension from the dialplan
66 </synopsis>
67 <syntax>
68 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
69 <parameter name="Context" required="true">
70 <para>Context of the extension being removed</para>
71 </parameter>
72 <parameter name="Extension" required="true">
73 <para>Name of the extension being removed (may include callerid match by separating with '/')</para>
74 </parameter>
75 <parameter name="Priority" required="false">
76 <para>If provided, only remove this priority from the extension instead of all
77 priorities in the extension.</para>
78 </parameter>
79 </syntax>
80 </manager>
81 ***/
82
83#include "asterisk.h"
84
85#include <ctype.h>
86
87#include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */
88#include "asterisk/pbx.h"
89#include "asterisk/config.h"
90#include "asterisk/module.h"
91#include "asterisk/logger.h"
92#include "asterisk/cli.h"
93#include "asterisk/channel.h" /* AST_MAX_EXTENSION */
94#include "asterisk/callerid.h"
95
96static const char config[] = "extensions.conf";
97static const char registrar[] = "pbx_config";
98static char userscontext[AST_MAX_EXTENSION] = "default";
99
100static int static_config = 0;
101static int write_protect_config = 1;
106
108
110
112
114static struct ast_hashtab *local_table = NULL;
115/*
116 * Prototypes for our completion functions
117 */
119static char *complete_dialplan_add_include(struct ast_cli_args *);
121static char *complete_dialplan_add_ignorepat(struct ast_cli_args *);
123static char *complete_dialplan_add_extension(struct ast_cli_args *);
125
126/*
127 * Implementation of functions provided by this module
128 */
129
130/*!
131 * * REMOVE context command stuff
132 */
133
134static char *handle_cli_dialplan_remove_context(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
135{
136 switch (cmd) {
137 case CLI_INIT:
138 e->command = "dialplan remove context";
139 e->usage =
140 "Usage: dialplan remove context <context>\n"
141 " Removes all extensions from a specified context.\n";
142 return NULL;
143 case CLI_GENERATE:
145 }
146
147 if (a->argc != 4) {
148 return CLI_SHOWUSAGE;
149 }
150
151 if (ast_context_destroy_by_name(a->argv[3], NULL)) {
152 ast_cli(a->fd, "There is no such context as '%s'\n", a->argv[3]);
153 return CLI_SUCCESS;
154 } else {
155 ast_cli(a->fd, "Removed context '%s'\n", a->argv[3]);
156 return CLI_SUCCESS;
157 }
158}
159/*!
160 * REMOVE INCLUDE command stuff
161 */
162static char *handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
163{
164 switch (cmd) {
165 case CLI_INIT:
166 e->command = "dialplan remove include";
167 e->usage =
168 "Usage: dialplan remove include <context> from <context>\n"
169 " Remove an included context from another context.\n";
170 return NULL;
171 case CLI_GENERATE:
173 }
174
175 if (a->argc != 6 || strcmp(a->argv[4], "from"))
176 return CLI_SHOWUSAGE;
177
178 if (!ast_context_remove_include(a->argv[5], a->argv[3], registrar)) {
179 ast_cli(a->fd, "We are not including '%s' into '%s' now\n",
180 a->argv[3], a->argv[5]);
181 return CLI_SUCCESS;
182 }
183
184 ast_cli(a->fd, "Failed to remove '%s' include from '%s' context\n",
185 a->argv[3], a->argv[5]);
186 return CLI_FAILURE;
187}
188
189/*! \brief return true if 'name' is included by context c */
190static int lookup_ci(struct ast_context *c, const char *name)
191{
192 int idx;
193 int ret = 0;
194
195 if (ast_rdlock_context(c)) {
196 /* error, skip */
197 return 0;
198 }
199
200 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
201 const struct ast_include *i = ast_context_includes_get(c, idx);
202
203 if (!strcmp(name, ast_get_include_name(i))) {
204 ret = -1;
205 break;
206 }
207 }
209
210 return ret;
211}
212
213/*! \brief return true if 'name' is in the ignorepats for context c */
214static int lookup_c_ip(struct ast_context *c, const char *name)
215{
216 int idx;
217 int ret = 0;
218
219 if (ast_rdlock_context(c)) {
220 /* error, skip */
221 return 0;
222 }
223
224 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
225 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
226
227 if (!strcmp(name, ast_get_ignorepat_name(ip))) {
228 ret = -1;
229 break;
230 }
231 }
233
234 return ret;
235}
236
237/*! \brief moves to the n-th word in the string, or empty string if none */
238static const char *skip_words(const char *p, int n)
239{
240 int in_blank = 0;
241 for (;n && *p; p++) {
242 if (isblank(*p) /* XXX order is important */ && !in_blank) {
243 n--; /* one word is gone */
244 in_blank = 1;
245 } else if (/* !is_blank(*p), we know already, && */ in_blank) {
246 in_blank = 0;
247 }
248 }
249 return p;
250}
251
252/*! \brief match the first 'len' chars of word. len==0 always succeeds */
253static int partial_match(const char *s, const char *word, int len)
254{
255 return (len == 0 || !strncmp(s, word, len));
256}
257
258/*! \brief split extension\@context in two parts, return -1 on error.
259 * The return string is malloc'ed and pointed by *ext
260 */
261static int split_ec(const char *src, char **ext, char ** const ctx, char ** const cid)
262{
263 char *i, *c, *e = ast_strdup(src); /* now src is not used anymore */
264
265 if (e == NULL)
266 return -1; /* malloc error */
267 /* now, parse values from 'exten@context' */
268 *ext = e;
269 c = strchr(e, '@');
270 if (c == NULL) /* no context part */
271 *ctx = ""; /* it is not overwritten, anyways */
272 else { /* found context, check for duplicity ... */
273 *c++ = '\0';
274 *ctx = c;
275 if (strchr(c, '@')) { /* two @, not allowed */
276 ast_free(e);
277 return -1;
278 }
279 }
280 if (cid && (i = strchr(e, '/'))) {
281 *i++ = '\0';
282 *cid = i;
283 } else if (cid) {
284 /* Signal none detected */
285 *cid = NULL;
286 }
287 return 0;
288}
289
290/* _X_ is the string we need to complete */
292{
293 int which = 0;
294 char *res = NULL;
295 int len = strlen(a->word); /* how many bytes to match */
296 struct ast_context *c = NULL;
297
298 if (a->pos == 3) { /* "dialplan remove include _X_" */
299 if (ast_wrlock_contexts()) {
300 ast_log(LOG_ERROR, "Failed to lock context list\n");
301 return NULL;
302 }
303 /* walk contexts and their includes, return the n-th match */
304 while (!res && (c = ast_walk_contexts(c))) {
305 int idx;
306
307 if (ast_rdlock_context(c)) /* error ? skip this one */
308 continue;
309
310 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
311 const struct ast_include *i = ast_context_includes_get(c, idx);
312 const char *i_name = ast_get_include_name(i);
313 struct ast_context *nc = NULL;
314 int already_served = 0;
315
316 if (!partial_match(i_name, a->word, len))
317 continue; /* not matched */
318
319 /* check if this include is already served or not */
320
321 /* go through all contexts again till we reach actual
322 * context or already_served = 1
323 */
324 while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served)
325 already_served = lookup_ci(nc, i_name);
326
327 if (!already_served && ++which > a->n) {
328 res = ast_strdup(i_name);
329 break;
330 }
331 }
333 }
334
336 return res;
337 } else if (a->pos == 4) { /* "dialplan remove include CTX _X_" */
338 /*
339 * complete as 'from', but only if previous context is really
340 * included somewhere
341 */
342 char *context, *dupline;
343 const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'include' */
344
345 if (a->n > 0)
346 return NULL;
347 context = dupline = ast_strdup(s);
348 if (!dupline) {
349 ast_log(LOG_ERROR, "Out of free memory\n");
350 return NULL;
351 }
352 strsep(&dupline, " ");
353
354 if (ast_rdlock_contexts()) {
355 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
357 return NULL;
358 }
359
360 /* go through all contexts and check if is included ... */
361 while (!res && (c = ast_walk_contexts(c)))
362 if (lookup_ci(c, context)) /* context is really included, complete "from" command */
363 res = ast_strdup("from");
365 if (!res)
366 ast_log(LOG_WARNING, "%s not included anywhere\n", context);
368 return res;
369 } else if (a->pos == 5) { /* "dialplan remove include CTX from _X_" */
370 /*
371 * Context from which we removing include ...
372 */
373 char *context, *dupline, *from;
374 const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'include' */
375 context = dupline = ast_strdup(s);
376 if (!dupline) {
377 ast_log(LOG_ERROR, "Out of free memory\n");
378 return NULL;
379 }
380
381 strsep(&dupline, " "); /* skip context */
382
383 /* fourth word must be 'from' */
384 from = strsep(&dupline, " ");
385 if (!from || strcmp(from, "from")) {
387 return NULL;
388 }
389
390 if (ast_rdlock_contexts()) {
391 ast_log(LOG_ERROR, "Failed to lock context list\n");
393 return NULL;
394 }
395
396 /* walk through all contexts ... */
397 c = NULL;
398 while ( !res && (c = ast_walk_contexts(c))) {
399 const char *c_name = ast_get_context_name(c);
400 if (!partial_match(c_name, a->word, len)) /* not a good target */
401 continue;
402 /* walk through all includes and check if it is our context */
403 if (lookup_ci(c, context) && ++which > a->n)
404 res = ast_strdup(c_name);
405 }
408 return res;
409 }
410
411 return NULL;
412}
413
414/*!
415 * REMOVE EXTENSION command stuff
416 */
417static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
418{
419 int removing_priority = 0;
420 char *exten, *context, *cid;
421 char *ret = CLI_FAILURE;
422
423 switch (cmd) {
424 case CLI_INIT:
425 e->command = "dialplan remove extension";
426 e->usage =
427 "Usage: dialplan remove extension exten[/cid]@context [priority]\n"
428 " Remove an extension from a given context. If a priority\n"
429 " is given, only that specific priority from the given extension\n"
430 " will be removed.\n";
431 return NULL;
432 case CLI_GENERATE:
434 }
435
436 if (a->argc != 5 && a->argc != 4)
437 return CLI_SHOWUSAGE;
438
439 /*
440 * Priority input checking ...
441 */
442 if (a->argc == 5) {
443 const char *c = a->argv[4];
444
445 /* check for digits in whole parameter for right priority ...
446 * why? because atoi (strtol) returns 0 if any characters in
447 * string and whole extension will be removed, it's not good
448 */
449 if (!strcmp("hint", c))
450 removing_priority = PRIORITY_HINT;
451 else {
452 while (*c && isdigit(*c))
453 c++;
454 if (*c) { /* non-digit in string */
455 ast_cli(a->fd, "Invalid priority '%s'\n", a->argv[4]);
456 return CLI_FAILURE;
457 }
458 removing_priority = atoi(a->argv[4]);
459 }
460
461 if (removing_priority == 0) {
462 ast_cli(a->fd, "If you want to remove whole extension, please " \
463 "omit priority argument\n");
464 return CLI_FAILURE;
465 }
466 }
467
468 /* XXX original overwrote argv[3] */
469 /*
470 * Format exten@context checking ...
471 */
472 if (split_ec(a->argv[3], &exten, &context, &cid))
473 return CLI_FAILURE; /* XXX malloc failure */
474 if ((!strlen(exten)) || (!(strlen(context)))) {
475 ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n",
476 a->argv[3]);
477 ast_free(exten);
478 return CLI_FAILURE;
479 }
480
481 if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
482 /* Do NOT substitute S_OR; it is NOT the same thing */
483 cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
484 if (!removing_priority)
485 ast_cli(a->fd, "Whole extension %s@%s removed\n",
486 exten, context);
487 else
488 ast_cli(a->fd, "Extension %s@%s with priority %d removed\n",
489 exten, context, removing_priority);
490
491 ret = CLI_SUCCESS;
492 } else {
493 if (cid) {
494 ast_cli(a->fd, "Failed to remove extension %s/%s@%s\n", exten, cid, context);
495 } else {
496 ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context);
497 }
498 ret = CLI_FAILURE;
499 }
500 ast_free(exten);
501 return ret;
502}
503
504static int manager_dialplan_extension_remove(struct mansession *s, const struct message *m)
505{
506 const char *context = astman_get_header(m, "Context");
507 const char *extension = astman_get_header(m, "Extension");
508 const char *priority = astman_get_header(m, "Priority");
509
510 int ipriority;
511 char *exten;
512 char *cidmatch = NULL;
513
515 astman_send_error(s, m, "Context and Extension must be provided "
516 "for DialplanExtensionRemove");
517 return 0;
518 }
519
520 exten = ast_strdupa(extension);
521
522 if (strchr(exten, '/')) {
523 cidmatch = exten;
524 strsep(&cidmatch, "/");
525 }
526
528 ipriority = 0;
529 } else if (!strcmp("hint", priority)) {
530 ipriority = PRIORITY_HINT;
531 } else if ((sscanf(priority, "%30d", &ipriority) != 1) || ipriority <= 0) {
532 astman_send_error(s, m, "The priority specified was invalid.");
533 return 0;
534 }
535
536 if (!ast_context_remove_extension_callerid(context, exten, ipriority,
537 /* Do not substitute S_OR; it is not the same thing */
538 !ast_strlen_zero(cidmatch) ? cidmatch : (ipriority ? "" : NULL),
539 !ast_strlen_zero(cidmatch) ? 1 : 0, registrar)) {
540 if (ipriority) {
541 astman_send_ack(s, m, "Removed the requested priority from the extension");
542 } else {
543 astman_send_ack(s, m, "Removed the requested extension");
544 }
545 } else {
546 astman_send_error(s, m, "Failed to remove requested extension");
547 }
548
549 return 0;
550}
551
553{
554 char *ret = NULL;
555 int which = 0;
556
557 if (a->pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */
558 struct ast_context *c = NULL;
559 char *context = NULL, *exten = NULL, *cid = NULL;
560 int le = 0; /* length of extension */
561 int lc = 0; /* length of context */
562 int lcid = 0; /* length of cid */
563
564 lc = split_ec(a->word, &exten, &context, &cid);
565 if (lc) { /* error */
566 return NULL;
567 }
568 le = strlen(exten);
569 lc = strlen(context);
570 lcid = cid ? strlen(cid) : -1;
571
572 if (ast_rdlock_contexts()) {
573 ast_log(LOG_ERROR, "Failed to lock context list\n");
574 goto error2;
575 }
576
577 /* find our context ... */
578 while ( (c = ast_walk_contexts(c)) ) { /* match our context if any */
579 struct ast_exten *e = NULL;
580 /* XXX locking ? */
582 continue; /* context not matched */
583 while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */
584 if ( !strchr(a->word, '/') ||
585 (!strchr(a->word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
586 (strchr(a->word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
587 if ( ((strchr(a->word, '/') || strchr(a->word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
588 (!strchr(a->word, '/') && !strchr(a->word, '@') && partial_match(ast_get_extension_name(e), exten, le))) { /* n-th match */
589 if (++which > a->n) {
590 /* If there is an extension then return exten@context. */
591 if (ast_get_extension_matchcid(e) && (!strchr(a->word, '@') || strchr(a->word, '/'))) {
593 ret = NULL;
594 }
595 break;
596 } else if (!ast_get_extension_matchcid(e) && !strchr(a->word, '/')) {
597 if (ast_asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)) < 0) {
598 ret = NULL;
599 }
600 break;
601 }
602 }
603 }
604 }
605 }
606 if (e) /* got a match */
607 break;
608 }
609
611 error2:
613 } else if (a->pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */
614 char *exten = NULL, *context, *cid, *p;
615 struct ast_context *c;
616 int le, lc, len;
617 const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'extension' */
618 int i = split_ec(s, &exten, &context, &cid); /* parse ext@context */
619
620 if (i) /* error */
621 goto error3;
622 if ( (p = strchr(exten, ' ')) ) /* remove space after extension */
623 *p = '\0';
624 if ( (p = strchr(context, ' ')) ) /* remove space after context */
625 *p = '\0';
626 le = strlen(exten);
627 lc = strlen(context);
628 len = strlen(a->word);
629 if (le == 0 || lc == 0)
630 goto error3;
631
632 if (ast_rdlock_contexts()) {
633 ast_log(LOG_ERROR, "Failed to lock context list\n");
634 goto error3;
635 }
636
637 /* walk contexts */
638 c = NULL;
639 while ( (c = ast_walk_contexts(c)) ) {
640 /* XXX locking on c ? */
641 struct ast_exten *e;
642 if (strcmp(ast_get_context_name(c), context) != 0)
643 continue;
644 /* got it, we must match here */
645 e = NULL;
646 while ( (e = ast_walk_context_extensions(c, e)) ) {
647 struct ast_exten *priority;
648 char buffer[10];
649
650 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
651 continue;
652 }
653 if (strcmp(ast_get_extension_name(e), exten) != 0)
654 continue;
655 /* XXX lock e ? */
656 priority = NULL;
657 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
658 snprintf(buffer, sizeof(buffer), "%d", ast_get_extension_priority(priority));
659 if (partial_match(buffer, a->word, len) && ++which > a->n) /* n-th match */
660 ret = ast_strdup(buffer);
661 }
662 break;
663 }
664 break;
665 }
667 error3:
669 }
670 return ret;
671}
672
673/*!
674 * Include context ...
675 */
676static char *handle_cli_dialplan_add_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
677{
678 const char *into_context;
679
680 switch (cmd) {
681 case CLI_INIT:
682 e->command = "dialplan add include";
683 e->usage =
684 "Usage: dialplan add include <context> into <context>\n"
685 " Include a context in another context.\n";
686 return NULL;
687 case CLI_GENERATE:
689 }
690
691 if (a->argc != 6) /* dialplan add include CTX in CTX */
692 return CLI_SHOWUSAGE;
693
694 /* fifth arg must be 'into' ... */
695 if (strcmp(a->argv[4], "into"))
696 return CLI_SHOWUSAGE;
697
698 into_context = a->argv[5];
699
700 if (!ast_context_find(into_context)) {
701 ast_cli(a->fd, "Context '%s' did not exist prior to add include - the context will be created.\n", into_context);
702 }
703
704 if (!ast_context_find_or_create(NULL, NULL, into_context, registrar)) {
705 ast_cli(a->fd, "ast_context_find_or_create() failed\n");
706 ast_cli(a->fd, "Failed to include '%s' in '%s' context\n",a->argv[3], a->argv[5]);
707 return CLI_FAILURE;
708 }
709
710 if (ast_context_add_include(a->argv[5], a->argv[3], registrar)) {
711 switch (errno) {
712 case ENOMEM:
713 ast_cli(a->fd, "Out of memory for context addition\n");
714 break;
715
716 case EBUSY:
717 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
718 break;
719
720 case EEXIST:
721 ast_cli(a->fd, "Context '%s' already included in '%s' context\n",
722 a->argv[3], a->argv[5]);
723 break;
724
725 case ENOENT:
726 case EINVAL:
727 ast_cli(a->fd, "There is no existence of context '%s'\n",
728 errno == ENOENT ? a->argv[5] : a->argv[3]);
729 break;
730
731 default:
732 ast_cli(a->fd, "Failed to include '%s' in '%s' context\n",
733 a->argv[3], a->argv[5]);
734 break;
735 }
736 return CLI_FAILURE;
737 }
738
739 /* show some info ... */
740 ast_cli(a->fd, "Context '%s' included in '%s' context\n",
741 a->argv[3], a->argv[5]);
742
743 return CLI_SUCCESS;
744}
745
747{
748 struct ast_context *c;
749 int which = 0;
750 char *ret = NULL;
751 int len = strlen(a->word);
752
753 if (a->pos == 3) { /* 'dialplan add include _X_' (context) ... */
754 if (ast_rdlock_contexts()) {
755 ast_log(LOG_ERROR, "Failed to lock context list\n");
756 return NULL;
757 }
758 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
759 if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
762 return ret;
763 } else if (a->pos == 4) { /* dialplan add include CTX _X_ */
764 /* always complete as 'into' */
765 return (a->n == 0) ? ast_strdup("into") : NULL;
766 } else if (a->pos == 5) { /* 'dialplan add include CTX into _X_' (dst context) */
767 char *context, *dupline, *into;
768 const char *s = skip_words(a->line, 3); /* should not fail */
769 context = dupline = ast_strdup(s);
770
771 if (!dupline) {
772 ast_log(LOG_ERROR, "Out of free memory\n");
773 return NULL;
774 }
775
776 strsep(&dupline, " "); /* skip context */
777 into = strsep(&dupline, " ");
778 /* error if missing context or fifth word is not 'into' */
779 if (!strlen(context) || strcmp(into, "into")) {
780 ast_log(LOG_ERROR, "bad context %s or missing into %s\n",
781 context, into);
782 goto error3;
783 }
784
785 if (ast_rdlock_contexts()) {
786 ast_log(LOG_ERROR, "Failed to lock context list\n");
787 goto error3;
788 }
789
790 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
791 if (!strcmp(context, ast_get_context_name(c)))
792 continue; /* skip ourselves */
793 if (partial_match(ast_get_context_name(c), a->word, len) &&
794 !lookup_ci(c, context) /* not included yet */ &&
795 ++which > a->n) {
797 }
798 }
800 error3:
802 return ret;
803 }
804
805 return NULL;
806}
807
808/*!
809 * \brief 'save dialplan' CLI command implementation functions ...
810 */
811static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
812{
813 char filename[256], overrideswitch[256] = "";
814 struct ast_context *c;
815 struct ast_config *cfg;
816 struct ast_variable *v;
817 int incomplete = 0; /* incomplete config write? */
818 FILE *output;
819 struct ast_flags config_flags = { 0 };
820 const char *base, *slash;
821
822 switch (cmd) {
823 case CLI_INIT:
824 e->command = "dialplan save";
825 e->usage =
826 "Usage: dialplan save [/path/to/extension/file]\n"
827 " Save dialplan created by pbx_config module.\n"
828 "\n"
829 "Example: dialplan save (/etc/asterisk/extensions.conf)\n"
830 " dialplan save /home/markster (/home/markster/extensions.conf)\n";
831 return NULL;
832 case CLI_GENERATE:
833 return NULL;
834 }
835
837 ast_cli(a->fd,
838 "I can't save dialplan now, see '%s' example file.\n",
839 config);
840 return CLI_FAILURE;
841 }
842
843 if (a->argc != 2 && a->argc != 3)
844 return CLI_SHOWUSAGE;
845
847 ast_cli(a->fd,
848 "Failed to lock dialplan saving (another process saving?)\n");
849 return CLI_FAILURE;
850 }
851 /* XXX the code here is quite loose, a pathname with .conf in it
852 * is assumed to be a complete pathname
853 */
854 if (a->argc == 3) { /* have config path. Look for *.conf */
855 base = a->argv[2];
856 if (!strstr(a->argv[2], ".conf")) { /*no, this is assumed to be a pathname */
857 /* if filename ends with '/', do not add one */
858 slash = (*(a->argv[2] + strlen(a->argv[2]) -1) == '/') ? "/" : "";
859 } else { /* yes, complete file name */
860 slash = "";
861 }
862 } else {
863 /* no config file, default one */
865 slash = "/";
866 }
867 snprintf(filename, sizeof(filename), "%s%s%s", base, slash, config);
868
869 cfg = ast_config_load("extensions.conf", config_flags);
870 if (!cfg) {
871 ast_cli(a->fd, "Failed to load extensions.conf\n");
873 return CLI_FAILURE;
874 }
875
876 /* try to lock contexts list */
877 if (ast_rdlock_contexts()) {
878 ast_cli(a->fd, "Failed to lock contexts list\n");
881 return CLI_FAILURE;
882 }
883
884 /* create new file ... */
885 if (!(output = fopen(filename, "wt"))) {
886 ast_cli(a->fd, "Failed to create file '%s'\n",
887 filename);
891 return CLI_FAILURE;
892 }
893
894 /* fireout general info */
896 snprintf(overrideswitch, sizeof(overrideswitch), "overrideswitch=%s\n", overrideswitch_config);
897 }
898 fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\n%sextenpatternmatchnew=%s\n\n",
899 static_config ? "yes" : "no",
900 write_protect_config ? "yes" : "no",
901 autofallthrough_config ? "yes" : "no",
902 clearglobalvars_config ? "yes" : "no",
904 extenpatternmatchnew_config ? "yes" : "no");
905
906 if ((v = ast_variable_browse(cfg, "globals"))) {
907 fprintf(output, "[globals]\n");
908 while(v) {
909 int escaped_len = 2 * strlen(v->value) + 1;
910 char escaped[escaped_len];
911
912 ast_escape_semicolons(v->value, escaped, escaped_len);
913 fprintf(output, "%s => %s\n", v->name, escaped);
914 v = v->next;
915 }
916 fprintf(output, "\n");
917 }
918
920
921#define PUT_CTX_HDR do { \
922 if (!context_header_written) { \
923 fprintf(output, "[%s]\n", ast_get_context_name(c)); \
924 context_header_written = 1; \
925 } \
926 } while (0)
927
928 /* walk all contexts */
929 for (c = NULL; (c = ast_walk_contexts(c)); ) {
930 int context_header_written = 0;
931 struct ast_exten *ext, *last_written_e = NULL;
932 int idx;
933
934 /* try to lock context and fireout all info */
935 if (ast_rdlock_context(c)) { /* lock failure */
936 incomplete = 1;
937 continue;
938 }
939 /* registered by this module? */
940 /* XXX do we need this ? */
941 if (!strcmp(ast_get_context_registrar(c), registrar)) {
942 fprintf(output, "[%s]\n", ast_get_context_name(c));
943 context_header_written = 1;
944 }
945
946 /* walk extensions ... */
947 for (ext = NULL; (ext = ast_walk_context_extensions(c, ext)); ) {
948 struct ast_exten *p = NULL;
949
950 /* fireout priorities */
951 while ( (p = ast_walk_extension_priorities(ext, p)) ) {
952 if (strcmp(ast_get_extension_registrar(p), registrar) != 0) /* not this source */
953 continue;
954
955 /* make empty line between different extensions */
956 if (last_written_e != NULL &&
957 strcmp(ast_get_extension_name(last_written_e),
959 fprintf(output, "\n");
960 last_written_e = p;
961
963
964 if (ast_get_extension_priority(p) == PRIORITY_HINT) { /* easy */
965 fprintf(output, "exten => %s,hint,%s\n",
968 } else {
969 const char *sep, *cid;
970 const char *el = ast_get_extension_label(p);
971 char label[128] = "";
972 char *appdata = ast_get_extension_app_data(p);
973
974 int escaped_len = (!ast_strlen_zero(appdata)) ? 2 * strlen(appdata) + 1 : 1;
975 char escaped[escaped_len];
976
978 sep = "/";
980 } else {
981 sep = cid = "";
982 }
983
984 if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2))) {
985 incomplete = 1; /* error encountered or label > 125 chars */
986 }
987
988 if (!ast_strlen_zero(appdata)) {
989 ast_escape_semicolons(appdata, escaped, escaped_len);
990 } else {
991 escaped[0] = '\0';
992 }
993
994 fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
995 ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
997 ast_get_extension_app(p), escaped);
998 }
999 }
1000 }
1001
1002 /* written any extensions? ok, write space between exten & inc */
1003 if (last_written_e)
1004 fprintf(output, "\n");
1005
1006 /* walk through includes */
1007 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
1008 const struct ast_include *i = ast_context_includes_get(c, idx);
1009
1010 if (strcmp(ast_get_include_registrar(i), registrar) != 0)
1011 continue; /* not mine */
1013 fprintf(output, "include => %s\n", ast_get_include_name(i));
1014 }
1016 fprintf(output, "\n");
1017 }
1018
1019 /* walk through switches */
1020 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
1021 const struct ast_sw *sw = ast_context_switches_get(c, idx);
1022
1023 if (strcmp(ast_get_switch_registrar(sw), registrar) != 0)
1024 continue; /* not mine */
1026 fprintf(output, "switch => %s/%s\n",
1028 }
1029
1031 fprintf(output, "\n");
1032 }
1033
1034 /* fireout ignorepats ... */
1035 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
1036 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
1037
1038 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0)
1039 continue; /* not mine */
1041 fprintf(output, "ignorepat => %s\n",
1043 }
1044
1046 }
1047
1050 fclose(output);
1051
1052 if (incomplete) {
1053 ast_cli(a->fd, "Saved dialplan is incomplete\n");
1054 return CLI_FAILURE;
1055 }
1056
1057 ast_cli(a->fd, "Dialplan successfully saved into '%s'\n",
1058 filename);
1059 return CLI_SUCCESS;
1060}
1061
1062/*!
1063 * \brief ADD EXTENSION command stuff
1064 */
1065static char *handle_cli_dialplan_add_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1066{
1067 char *whole_exten;
1068 char *exten, *prior;
1069 int iprior = -2;
1070 char *cidmatch, *app, *app_data;
1071 char *start, *end;
1072 const char *into_context;
1073
1074 switch (cmd) {
1075 case CLI_INIT:
1076 e->command = "dialplan add extension";
1077 e->usage =
1078 "Usage: dialplan add extension <exten>,<priority>,<app> into <context> [replace]\n"
1079 "\n"
1080 " app can be either:\n"
1081 " app-name\n"
1082 " app-name(app-data)\n"
1083 " app-name,<app-data>\n"
1084 "\n"
1085 " This command will add the new extension into <context>. If\n"
1086 " an extension with the same priority already exists and the\n"
1087 " 'replace' option is given we will replace the extension.\n"
1088 "\n"
1089 "Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
1090 " Now, you can dial 6123 and talk to Markster :)\n";
1091 return NULL;
1092 case CLI_GENERATE:
1094 }
1095
1096 /* check for arguments at first */
1097 if (a->argc != 6 && a->argc != 7)
1098 return CLI_SHOWUSAGE;
1099 if (strcmp(a->argv[4], "into"))
1100 return CLI_SHOWUSAGE;
1101 if (a->argc == 7)
1102 if (strcmp(a->argv[6], "replace"))
1103 return CLI_SHOWUSAGE;
1104
1105 whole_exten = ast_strdupa(a->argv[3]);
1106 exten = strsep(&whole_exten,",");
1107 if (strchr(exten, '/')) {
1108 cidmatch = exten;
1109 strsep(&cidmatch,"/");
1110 } else {
1111 cidmatch = NULL;
1112 }
1113 prior = strsep(&whole_exten,",");
1114 if (prior) {
1115 if (!strcmp(prior, "hint")) {
1116 iprior = PRIORITY_HINT;
1117 } else {
1118 if (sscanf(prior, "%30d", &iprior) != 1) {
1119 ast_cli(a->fd, "'%s' is not a valid priority\n", prior);
1120 prior = NULL;
1121 }
1122 }
1123 }
1124 app = whole_exten;
1125 if (app) {
1126 if ((start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
1127 *start = *end = '\0';
1128 app_data = start + 1;
1129 } else {
1130 app_data = strchr(app, ',');
1131 if (app_data) {
1132 *app_data++ = '\0';
1133 }
1134 }
1135 } else {
1136 app_data = NULL;
1137 }
1138
1139 if (!exten || !prior || !app) {
1140 return CLI_SHOWUSAGE;
1141 }
1142
1143 if (!app_data) {
1144 app_data = "";
1145 }
1146 into_context = a->argv[5];
1147
1148 if (!ast_context_find(into_context)) {
1149 ast_cli(a->fd, "Context '%s' did not exist prior to add extension - the context will be created.\n", into_context);
1150 }
1151
1152 if (!ast_context_find_or_create(NULL, NULL, into_context, registrar)) {
1153 ast_cli(a->fd, "Failed to add '%s,%s,%s(%s)' extension into '%s' context\n",
1154 exten, prior, app, app_data, into_context);
1155 return CLI_FAILURE;
1156 }
1157
1158 if (ast_add_extension(into_context, a->argc == 7 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
1160 switch (errno) {
1161 case ENOMEM:
1162 ast_cli(a->fd, "Out of free memory\n");
1163 break;
1164
1165 case EBUSY:
1166 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
1167 break;
1168
1169 case ENOENT:
1170 ast_cli(a->fd, "No existence of '%s' context\n", into_context);
1171 break;
1172
1173 case EEXIST:
1174 ast_cli(a->fd, "Extension %s@%s with priority %s already exists\n",
1175 exten, into_context, prior);
1176 break;
1177
1178 default:
1179 ast_cli(a->fd, "Failed to add '%s,%s,%s(%s)' extension into '%s' context\n",
1180 exten, prior, app, app_data, into_context);
1181 break;
1182 }
1183 return CLI_FAILURE;
1184 }
1185
1186 if (a->argc == 7) {
1187 ast_cli(a->fd, "Extension %s@%s (%s) replace by '%s,%s,%s(%s)'\n",
1188 exten, into_context, prior, exten, prior, app, app_data);
1189 } else {
1190 ast_cli(a->fd, "Extension '%s,%s,%s(%s)' added into '%s' context\n",
1191 exten, prior, app, app_data, into_context);
1192 }
1193
1194 return CLI_SUCCESS;
1195}
1196
1197static int manager_dialplan_extension_add(struct mansession *s, const struct message *m)
1198{
1199 const char *context = astman_get_header(m, "Context");
1200 const char *extension = astman_get_header(m, "Extension");
1201 const char *priority = astman_get_header(m, "Priority");
1202 const char *application = astman_get_header(m, "Application");
1203 const char *application_data = astman_get_header(m, "ApplicationData");
1204 int replace = ast_true(astman_get_header(m, "Replace"));
1205 int ipriority;
1206 char *exten;
1207 char *cidmatch = NULL;
1208 struct ast_context *add_context;
1209
1211 ast_strlen_zero(priority) || ast_strlen_zero(application)) {
1212 astman_send_error(s, m, "Context, Extension, Priority, and "
1213 "Application must be defined for DialplanExtensionAdd.");
1214 return 0;
1215 }
1216
1217 /* Priority conversion/validation */
1218 if (!strcmp(priority, "hint")) {
1219 ipriority = PRIORITY_HINT;
1220 } else if ((sscanf(priority, "%30d", &ipriority) != 1) || (ipriority < 0)) {
1221 astman_send_error(s, m, "The priority specified was invalid.");
1222 return 0;
1223 }
1224
1225 /* Split extension from cidmatch */
1226 exten = ast_strdupa(extension);
1227
1228 if (strchr(exten, '/')) {
1229 cidmatch = exten;
1230 strsep(&cidmatch, "/");
1231 }
1232
1233 if (ast_wrlock_contexts()) {
1234 astman_send_error(s, m, "Failed to lock contexts list. Try again later.");
1235 return 0;
1236 }
1237
1239 if (!add_context) {
1240 astman_send_error(s, m, "Could not find or create context specified "
1241 "for the extension.");
1243 return 0;
1244 }
1245
1246 if (ast_add_extension2(add_context, replace, exten, ipriority, NULL, cidmatch,
1247 application, ast_strdup(application_data), ast_free_ptr, registrar, NULL, 0)) {
1249 switch (errno) {
1250 case ENOMEM:
1251 astman_send_error(s, m, "Out of Memory");
1252 break;
1253
1254 case EBUSY:
1255 astman_send_error(s, m, "Failed to lock context(s) list");
1256 break;
1257
1258 case ENOENT:
1259 astman_send_error(s, m, "Context does not exist");
1260 break;
1261
1262 case EEXIST:
1263 astman_send_error(s, m, "That extension and priority already exist at that context");
1264 break;
1265
1266 default:
1267 astman_send_error(s, m, "Failed to add extension");
1268 break;
1269 }
1270 return 0;
1271 }
1273
1274 astman_send_ack(s, m, "Added requested extension");
1275
1276 return 0;
1277}
1278
1280{
1281 struct ast_context *c = NULL;
1282 int len = strlen(a->word);
1283 char *res = NULL;
1284 int which = 0;
1285
1286 if (a->pos != 3) {
1287 return NULL;
1288 }
1289
1290
1291 /* try to lock contexts list ... */
1292 if (ast_rdlock_contexts()) {
1293 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1294 return NULL;
1295 }
1296
1297 /* walk through all contexts */
1298 while ( !res && (c = ast_walk_contexts(c)) ) {
1299 if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n) {
1301 }
1302 }
1304 return res;
1305}
1306
1307/*! dialplan add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
1309{
1310 int which = 0;
1311
1312 if (a->pos == 4) { /* complete 'into' word ... */
1313 return (a->n == 0) ? ast_strdup("into") : NULL;
1314 } else if (a->pos == 5) { /* complete context */
1315 struct ast_context *c = NULL;
1316 int len = strlen(a->word);
1317 char *res = NULL;
1318
1319 /* try to lock contexts list ... */
1320 if (ast_rdlock_contexts()) {
1321 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1322 return NULL;
1323 }
1324
1325 /* walk through all contexts */
1326 while ( !res && (c = ast_walk_contexts(c)) )
1327 if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
1330 return res;
1331 } else if (a->pos == 6) {
1332 return a->n == 0 ? ast_strdup("replace") : NULL;
1333 }
1334 return NULL;
1335}
1336
1337/*!
1338 * IGNOREPAT CLI stuff
1339 */
1340static char *handle_cli_dialplan_add_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1341{
1342 switch (cmd) {
1343 case CLI_INIT:
1344 e->command = "dialplan add ignorepat";
1345 e->usage =
1346 "Usage: dialplan add ignorepat <pattern> into <context>\n"
1347 " This command adds a new ignore pattern into context <context>\n"
1348 "\n"
1349 "Example: dialplan add ignorepat _3XX into local\n";
1350 return NULL;
1351 case CLI_GENERATE:
1353 }
1354
1355 if (a->argc != 6)
1356 return CLI_SHOWUSAGE;
1357
1358 if (strcmp(a->argv[4], "into"))
1359 return CLI_SHOWUSAGE;
1360
1361 if (ast_context_add_ignorepat(a->argv[5], a->argv[3], registrar)) {
1362 switch (errno) {
1363 case ENOMEM:
1364 ast_cli(a->fd, "Out of free memory\n");
1365 break;
1366
1367 case ENOENT:
1368 ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
1369 break;
1370
1371 case EEXIST:
1372 ast_cli(a->fd, "Ignore pattern '%s' already included in '%s' context\n",
1373 a->argv[3], a->argv[5]);
1374 break;
1375
1376 case EBUSY:
1377 ast_cli(a->fd, "Failed to lock context(s) list, please, try again later\n");
1378 break;
1379
1380 default:
1381 ast_cli(a->fd, "Failed to add ignore pattern '%s' into '%s' context\n",
1382 a->argv[3], a->argv[5]);
1383 break;
1384 }
1385 return CLI_FAILURE;
1386 }
1387
1388 ast_cli(a->fd, "Ignore pattern '%s' added into '%s' context\n",
1389 a->argv[3], a->argv[5]);
1390
1391 return CLI_SUCCESS;
1392}
1393
1395{
1396 if (a->pos == 4)
1397 return a->n == 0 ? ast_strdup("into") : NULL;
1398 else if (a->pos == 5) {
1399 struct ast_context *c;
1400 int which = 0;
1401 char *dupline, *ignorepat = NULL;
1402 const char *s;
1403 char *ret = NULL;
1404 int len = strlen(a->word);
1405
1406 /* XXX skip first three words 'dialplan' 'add' 'ignorepat' */
1407 s = skip_words(a->line, 3);
1408 if (s == NULL)
1409 return NULL;
1410 dupline = ast_strdup(s);
1411 if (!dupline) {
1412 ast_log(LOG_ERROR, "Malloc failure\n");
1413 return NULL;
1414 }
1415 ignorepat = strsep(&dupline, " ");
1416
1417 if (ast_rdlock_contexts()) {
1418 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
1419 return NULL;
1420 }
1421
1422 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
1423 int found = 0;
1424
1425 if (!partial_match(ast_get_context_name(c), a->word, len))
1426 continue; /* not mine */
1427 if (ignorepat) /* there must be one, right ? */
1428 found = lookup_c_ip(c, ignorepat);
1429 if (!found && ++which > a->n)
1431 }
1432
1433 ast_free(ignorepat);
1435 return ret;
1436 }
1437
1438 return NULL;
1439}
1440
1441static char *handle_cli_dialplan_remove_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1442{
1443 switch (cmd) {
1444 case CLI_INIT:
1445 e->command = "dialplan remove ignorepat";
1446 e->usage =
1447 "Usage: dialplan remove ignorepat <pattern> from <context>\n"
1448 " This command removes an ignore pattern from context <context>\n"
1449 "\n"
1450 "Example: dialplan remove ignorepat _3XX from local\n";
1451 return NULL;
1452 case CLI_GENERATE:
1454 }
1455
1456 if (a->argc != 6)
1457 return CLI_SHOWUSAGE;
1458
1459 if (strcmp(a->argv[4], "from"))
1460 return CLI_SHOWUSAGE;
1461
1462 if (ast_context_remove_ignorepat(a->argv[5], a->argv[3], registrar)) {
1463 switch (errno) {
1464 case EBUSY:
1465 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
1466 break;
1467
1468 case ENOENT:
1469 ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
1470 break;
1471
1472 case EINVAL:
1473 ast_cli(a->fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
1474 a->argv[3], a->argv[5]);
1475 break;
1476
1477 default:
1478 ast_cli(a->fd, "Failed to remove ignore pattern '%s' from '%s' context\n",
1479 a->argv[3], a->argv[5]);
1480 break;
1481 }
1482 return CLI_FAILURE;
1483 }
1484
1485 ast_cli(a->fd, "Ignore pattern '%s' removed from '%s' context\n",
1486 a->argv[3], a->argv[5]);
1487 return CLI_SUCCESS;
1488}
1489
1491{
1492 struct ast_context *c;
1493 int which = 0;
1494 char *ret = NULL;
1495
1496 if (a->pos == 3) {
1497 int len = strlen(a->word);
1498 if (ast_rdlock_contexts()) {
1499 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1500 return NULL;
1501 }
1502
1503 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
1504 int idx;
1505
1506 if (ast_rdlock_context(c)) /* error, skip it */
1507 continue;
1508 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
1509 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
1510
1511 if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) {
1512 /* n-th match */
1513 struct ast_context *cw = NULL;
1514 int found = 0;
1515 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
1516 /* XXX do i stop on c, or skip it ? */
1517 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
1518 }
1519 if (!found)
1521 }
1522 }
1524 }
1526 return ret;
1527 } else if (a->pos == 4) {
1528 return a->n == 0 ? ast_strdup("from") : NULL;
1529 } else if (a->pos == 5) { /* XXX check this */
1530 char *dupline, *duplinet, *ignorepat;
1531 int len = strlen(a->word);
1532
1533 dupline = ast_strdup(a->line);
1534 if (!dupline) {
1535 ast_log(LOG_WARNING, "Out of free memory\n");
1536 return NULL;
1537 }
1538
1539 duplinet = dupline;
1540 strsep(&duplinet, " ");
1541 strsep(&duplinet, " ");
1542 ignorepat = strsep(&duplinet, " ");
1543
1544 if (!ignorepat) {
1545 ast_free(dupline);
1546 return NULL;
1547 }
1548
1549 if (ast_rdlock_contexts()) {
1550 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
1551 ast_free(dupline);
1552 return NULL;
1553 }
1554
1555 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
1556 if (ast_rdlock_context(c)) {
1557 /* fail, skip it */
1558 continue;
1559 }
1560 if (!partial_match(ast_get_context_name(c), a->word, len)) {
1562 continue;
1563 }
1564 if (lookup_c_ip(c, ignorepat) && ++which > a->n)
1567 }
1569 ast_free(dupline);
1570 return ret;
1571 }
1572
1573 return NULL;
1574}
1575
1576static int pbx_load_module(void);
1577
1578static char *handle_cli_dialplan_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1579{
1580 switch (cmd) {
1581 case CLI_INIT:
1582 e->command = "dialplan reload";
1583 e->usage =
1584 "Usage: dialplan reload\n"
1585 " Reload extensions.conf without reloading any other\n"
1586 " modules. This command does not delete global variables\n"
1587 " unless clearglobalvars is set to yes in extensions.conf\n";
1588 return NULL;
1589 case CLI_GENERATE:
1590 return NULL;
1591 }
1592
1593 if (a->argc != 2)
1594 return CLI_SHOWUSAGE;
1595
1598
1600 ast_cli(a->fd, "Dialplan reloaded.\n");
1601 return CLI_SUCCESS;
1602}
1603
1604/*!
1605 * CLI entries for commands provided by this module
1606 */
1608 AST_CLI_DEFINE(handle_cli_dialplan_add_extension, "Add new extension into context"),
1609 AST_CLI_DEFINE(handle_cli_dialplan_remove_extension, "Remove a specified extension"),
1610 AST_CLI_DEFINE(handle_cli_dialplan_remove_context, "Remove a specified context"),
1611 AST_CLI_DEFINE(handle_cli_dialplan_add_ignorepat, "Add new ignore pattern"),
1612 AST_CLI_DEFINE(handle_cli_dialplan_remove_ignorepat, "Remove ignore pattern from context"),
1613 AST_CLI_DEFINE(handle_cli_dialplan_add_include, "Include context in other context"),
1614 AST_CLI_DEFINE(handle_cli_dialplan_remove_include, "Remove a specified include from context"),
1615 AST_CLI_DEFINE(handle_cli_dialplan_reload, "Reload extensions and *only* extensions")
1616};
1617
1619 AST_CLI_DEFINE(handle_cli_dialplan_save, "Save current dialplan into a file");
1620
1621#define AMI_EXTENSION_ADD "DialplanExtensionAdd"
1622#define AMI_EXTENSION_REMOVE "DialplanExtensionRemove"
1623
1624/*!
1625 * Standard module functions ...
1626 */
1627static int unload_module(void)
1628{
1632
1637
1639
1640 return 0;
1641}
1642
1643/*!\note Protect against misparsing based upon commas in the middle of fields
1644 * like character classes. We've taken steps to permit pretty much every other
1645 * printable character in a character class, so properly handling a comma at
1646 * this level is a natural extension. This is almost like the standard
1647 * application parser in app.c, except that it handles square brackets. */
1648static char *pbx_strsep(char **destructible, const char *delim)
1649{
1650 int square = 0;
1651 char *res;
1652
1653 if (!destructible || !*destructible) {
1654 return NULL;
1655 }
1656 res = *destructible;
1657 for (; **destructible; (*destructible)++) {
1658 if (**destructible == '[' && !strchr(delim, '[')) {
1659 square++;
1660 } else if (**destructible == ']' && !strchr(delim, ']')) {
1661 if (square) {
1662 square--;
1663 }
1664 } else if (**destructible == '\\' && !strchr(delim, '\\')) {
1665 (*destructible)++;
1666 } else if (strchr(delim, **destructible) && !square) {
1667 **destructible = '\0';
1668 (*destructible)++;
1669 break;
1670 }
1671 }
1672 if (**destructible == '\0') {
1673 *destructible = NULL;
1674 }
1675 return res;
1676}
1677
1678static int pbx_load_config(const char *config_file)
1679{
1680 struct ast_config *cfg;
1681 char *end;
1682 char *label;
1683#ifdef LOW_MEMORY
1684 char realvalue[256];
1685#else
1686 char realvalue[8192];
1687#endif
1688 int lastpri = -2;
1689 struct ast_context *con;
1690 struct ast_variable *v;
1691 const char *cxt;
1692 const char *aft;
1693 const char *newpm, *ovsw;
1694 struct ast_flags config_flags = { 0 };
1695 char lastextension[256];
1696 cfg = ast_config_load(config_file, config_flags);
1697 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID)
1698 return 0;
1699
1700 /* Use existing config to populate the PBX table */
1701 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
1702 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
1703 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
1705 if ((newpm = ast_variable_retrieve(cfg, "general", "extenpatternmatchnew")))
1707 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
1708 if ((ovsw = ast_variable_retrieve(cfg, "general", "overrideswitch"))) {
1711 }
1712 if (!ast_strlen_zero(ovsw)) {
1714 } else {
1716 }
1717 }
1718
1719 ast_copy_string(userscontext, ast_variable_retrieve(cfg, "general", "userscontext") ?: "default", sizeof(userscontext));
1720
1721 /* ast_variable_browse does not merge multiple [globals] sections */
1722 for (cxt = ast_category_browse(cfg, NULL);
1723 cxt;
1724 cxt = ast_category_browse(cfg, cxt)) {
1725 if (strcasecmp(cxt, "globals")) {
1726 continue;
1727 }
1728
1729 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
1730 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1731 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
1732 }
1733 }
1734
1735 for (cxt = ast_category_browse(cfg, NULL);
1736 cxt;
1737 cxt = ast_category_browse(cfg, cxt)) {
1738 /* All categories but "general" or "globals" are considered contexts */
1739 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
1740 continue;
1741 }
1743 continue;
1744 }
1745
1746 /* Reset continuation items at the beginning of each context */
1747 lastextension[0] = '\0';
1748 lastpri = -2;
1749
1750 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
1751 char *tc = NULL;
1752 char realext[256] = "";
1753 char *stringp, *ext;
1754 const char *vfile;
1755
1756 /* get filename for error reporting from top level or an #include */
1757 vfile = !*v->file ? config_file : v->file;
1758
1759 if (!strncasecmp(v->name, "same", 4)) {
1760 if (ast_strlen_zero(lastextension)) {
1762 "No previous pattern in the first entry of context '%s' to match '%s' at line %d of %s!\n",
1763 cxt, v->name, v->lineno, vfile);
1764 continue;
1765 }
1766 if ((stringp = tc = ast_strdup(v->value))) {
1767 ast_copy_string(realext, lastextension, sizeof(realext));
1768 goto process_extension;
1769 }
1770 } else if (!strcasecmp(v->name, "exten")) {
1771 int ipri;
1772 char *plus;
1773 char *pri, *appl, *data, *cidmatch;
1774
1775 if (!(stringp = tc = ast_strdup(v->value))) {
1776 continue;
1777 }
1778
1779 ext = S_OR(pbx_strsep(&stringp, ","), "");
1780 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
1781 ast_copy_string(lastextension, realext, sizeof(lastextension));
1782process_extension:
1783 ipri = -2;
1784 if ((cidmatch = strchr(realext, '/'))) {
1785 *cidmatch++ = '\0';
1786 ast_shrink_phone_number(cidmatch);
1787 }
1788 pri = ast_strip(S_OR(strsep(&stringp, ","), ""));
1789 if ((label = strchr(pri, '('))) {
1790 *label++ = '\0';
1791 if ((end = strchr(label, ')'))) {
1792 *end = '\0';
1793 } else {
1795 "Label missing trailing ')' at line %d of %s\n",
1796 v->lineno, vfile);
1797 ast_free(tc);
1798 continue;
1799 }
1800 }
1801 if ((plus = strchr(pri, '+'))) {
1802 *plus++ = '\0';
1803 }
1804 if (!strcmp(pri,"hint")) {
1805 ipri = PRIORITY_HINT;
1806 } else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
1807 if (lastpri > -2) {
1808 ipri = lastpri + 1;
1809 } else {
1811 "Can't use 'next' priority on the first entry at line %d of %s!\n",
1812 v->lineno, vfile);
1813 ast_free(tc);
1814 continue;
1815 }
1816 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
1817 if (lastpri > -2) {
1818 ipri = lastpri;
1819 } else {
1821 "Can't use 'same' priority on the first entry at line %d of %s!\n",
1822 v->lineno, vfile);
1823 ast_free(tc);
1824 continue;
1825 }
1826 } else if (sscanf(pri, "%30d", &ipri) != 1 &&
1827 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
1829 "Invalid priority/label '%s' at line %d of %s\n",
1830 pri, v->lineno, vfile);
1831 ipri = 0;
1832 ast_free(tc);
1833 continue;
1834 } else if (ipri < 1) {
1835 ast_log(LOG_WARNING, "Invalid priority '%s' at line %d of %s\n",
1836 pri, v->lineno, vfile);
1837 ast_free(tc);
1838 continue;
1839 }
1840 appl = S_OR(stringp, "");
1841 /* Find the first occurrence of '(' */
1842 if (!strchr(appl, '(')) {
1843 /* No arguments */
1844 data = "";
1845 } else {
1846 char *orig_appl = ast_strdup(appl);
1847
1848 if (!orig_appl) {
1849 ast_free(tc);
1850 continue;
1851 }
1852
1853 appl = strsep(&stringp, "(");
1854
1855 /* check if there are variables or expressions without an application, like: exten => 100,hint,DAHDI/g0/${GLOBAL(var)} */
1856 if (strstr(appl, "${") || strstr(appl, "$[")){
1857 /* set appl to original one */
1858 strcpy(appl, orig_appl);
1859 /* set no data */
1860 data = "";
1861 /* no variable before application found -> go ahead */
1862 } else {
1863 data = S_OR(stringp, "");
1864 if ((end = strrchr(data, ')'))) {
1865 *end = '\0';
1866 } else {
1868 "No closing parenthesis found? '%s(%s' at line %d of %s\n",
1869 appl, data, v->lineno, vfile);
1870 }
1871 }
1872 ast_free(orig_appl);
1873 }
1874
1875 appl = ast_skip_blanks(appl);
1876 if (ipri) {
1877 const char *registrar_file;
1878 if (plus) {
1879 ipri += atoi(plus);
1880 }
1881 lastpri = ipri;
1882 if (!ast_opt_dont_warn && (!strcmp(realext, "_.") || !strcmp(realext, "_!"))) {
1884 "The use of '%s' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X%c' instead at line %d of %s\n",
1885 realext, realext[1], v->lineno, vfile);
1886 }
1887 /* Don't include full path if the configuration file includes slashes */
1888 registrar_file = strrchr(vfile, '/');
1889 if (!registrar_file) {
1890 registrar_file = vfile;
1891 } else {
1892 registrar_file++; /* Skip past the end slash */
1893 }
1894 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, ast_strdup(data), ast_free_ptr, registrar, registrar_file, v->lineno)) {
1896 "Unable to register extension at line %d of %s\n",
1897 v->lineno, vfile);
1898 }
1899 }
1900 ast_free(tc);
1901 } else if (!strcasecmp(v->name, "include")) {
1902 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1903 if (ast_context_add_include2(con, realvalue, registrar)) {
1904 switch (errno) {
1905 case ENOMEM:
1906 ast_log(LOG_WARNING, "Out of memory for context addition\n");
1907 break;
1908
1909 case EBUSY:
1910 ast_log(LOG_WARNING, "Failed to lock context(s) list, please try again later\n");
1911 break;
1912
1913 case EEXIST:
1915 "Context '%s' already included in '%s' context on include at line %d of %s\n",
1916 v->value, cxt, v->lineno, vfile);
1917 break;
1918
1919 case ENOENT:
1920 case EINVAL:
1922 "There is no existence of context '%s' included at line %d of %s\n",
1923 errno == ENOENT ? v->value : cxt, v->lineno, vfile);
1924 break;
1925
1926 default:
1928 "Failed to include '%s' in '%s' context at line %d of %s\n",
1929 v->value, cxt, v->lineno, vfile);
1930 break;
1931 }
1932 }
1933 } else if (!strcasecmp(v->name, "ignorepat")) {
1934 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1935 if (ast_context_add_ignorepat2(con, realvalue, registrar)) {
1937 "Unable to include ignorepat '%s' in context '%s' at line %d of %s\n",
1938 v->value, cxt, v->lineno, vfile);
1939 }
1940 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
1941 char *appl, *data;
1942 stringp = realvalue;
1943
1944 if (!strcasecmp(v->name, "switch")) {
1945 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
1946 } else {
1947 ast_copy_string(realvalue, v->value, sizeof(realvalue));
1948 }
1949 appl = strsep(&stringp, "/");
1950 data = S_OR(stringp, "");
1951 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar)) {
1953 "Unable to include switch '%s' in context '%s' at line %d of %s\n",
1954 v->value, cxt, v->lineno, vfile);
1955 }
1956 } else if (!strcasecmp(v->name, "autohints")) {
1958 } else {
1960 "==!!== Unknown directive: %s at line %d of %s -- IGNORING!!!\n",
1961 v->name, v->lineno, vfile);
1962 }
1963 }
1964 }
1965 ast_config_destroy(cfg);
1966 return 1;
1967}
1968
1969static void append_interface(char *iface, int maxlen, char *add)
1970{
1971 int len = strlen(iface);
1972 if (strlen(add) + len < maxlen - 2) {
1973 if (strlen(iface)) {
1974 iface[len] = '&';
1975 strcpy(iface + len + 1, add);
1976 } else
1977 strcpy(iface, add);
1978 }
1979}
1980
1981static void startup_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
1982{
1983 struct ast_json_payload *payload;
1984 const char *type;
1985
1987 return;
1988 }
1989
1990 payload = stasis_message_data(message);
1991 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1992
1993 if (strcmp(type, "FullyBooted")) {
1994 return;
1995 }
1996
1997 ast_log(LOG_WARNING, "users.conf is deprecated and will be removed in a future version of Asterisk\n");
1998
2000}
2001
2002static void pbx_load_users(void)
2003{
2004 struct ast_config *cfg;
2005 char *cat, *chan;
2006 const char *dahdichan;
2007 const char *hasexten, *altexts;
2008 char tmp[256];
2009 char iface[256];
2010 char dahdicopy[256];
2011 char *ext, altcopy[256];
2012 char *c;
2013 int hasvoicemail;
2014 int start, finish, x;
2015 struct ast_context *con = NULL;
2016 struct ast_flags config_flags = { 0 };
2017
2018 cfg = ast_config_load("users.conf", config_flags);
2019 if (!cfg)
2020 return;
2021
2022 /*! \todo Remove users.conf support in Asterisk 23 */
2025
2026 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
2027 if (!strcasecmp(cat, "general"))
2028 continue;
2029 iface[0] = '\0';
2030 if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
2031 snprintf(tmp, sizeof(tmp), "IAX2/%s", cat);
2032 append_interface(iface, sizeof(iface), tmp);
2033 }
2034 if (ast_true(ast_config_option(cfg, cat, "hash323"))) {
2035 snprintf(tmp, sizeof(tmp), "H323/%s", cat);
2036 append_interface(iface, sizeof(iface), tmp);
2037 }
2038 hasexten = ast_config_option(cfg, cat, "hasexten");
2039 if (hasexten && !ast_true(hasexten))
2040 continue;
2041 hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
2042 dahdichan = ast_variable_retrieve(cfg, cat, "dahdichan");
2043 if (!dahdichan)
2044 dahdichan = ast_variable_retrieve(cfg, "general", "dahdichan");
2045 if (!ast_strlen_zero(dahdichan)) {
2046 ast_copy_string(dahdicopy, dahdichan, sizeof(dahdicopy));
2047 c = dahdicopy;
2048 chan = strsep(&c, ",");
2049 while (chan) {
2050 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
2051 /* Range */
2052 } else if (sscanf(chan, "%30d", &start)) {
2053 /* Just one */
2054 finish = start;
2055 } else {
2056 start = 0; finish = 0;
2057 }
2058 if (finish < start) {
2059 x = finish;
2060 finish = start;
2061 start = x;
2062 }
2063 for (x = start; x <= finish; x++) {
2064 snprintf(tmp, sizeof(tmp), "DAHDI/%d", x);
2065 append_interface(iface, sizeof(iface), tmp);
2066 }
2067 chan = strsep(&c, ",");
2068 }
2069 }
2070 if (!ast_strlen_zero(iface)) {
2071 /* Only create a context here when it is really needed. Otherwise default empty context
2072 created by pbx_config may conflict with the one explicitly created by pbx_ael */
2073 if (!con)
2075
2076 if (!con) {
2077 ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
2078 return;
2079 }
2080
2081 /* Add hint */
2082 ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar, NULL, 0);
2083 /* If voicemail, use "stdexten" else use plain old dial */
2084 if (hasvoicemail) {
2085 snprintf(tmp, sizeof(tmp), "%s,stdexten(${HINT})", cat);
2086 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Gosub", ast_strdup(tmp), ast_free_ptr, registrar, NULL, 0);
2087 } else {
2088 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", ast_strdup("${HINT}"), ast_free_ptr, registrar, NULL, 0);
2089 }
2090 altexts = ast_variable_retrieve(cfg, cat, "alternateexts");
2091 if (!ast_strlen_zero(altexts)) {
2092 snprintf(tmp, sizeof(tmp), "%s,1", cat);
2093 ast_copy_string(altcopy, altexts, sizeof(altcopy));
2094 c = altcopy;
2095 ext = strsep(&c, ",");
2096 while (ext) {
2097 ast_add_extension2(con, 0, ext, 1, NULL, NULL, "Goto", ast_strdup(tmp), ast_free_ptr, registrar, NULL, 0);
2098 ext = strsep(&c, ",");
2099 }
2100 }
2101 }
2102 }
2103 ast_config_destroy(cfg);
2104}
2105
2106static int pbx_load_module(void)
2107{
2108 struct ast_context *con;
2109
2111
2112 if (!local_table) {
2114 if (!local_table) {
2117 }
2118 }
2119
2120 if (!pbx_load_config(config)) {
2122 local_table = NULL;
2125 }
2126
2128
2130 local_table = NULL; /* the local table has been moved into the global one. */
2132
2134
2135 for (con = NULL; (con = ast_walk_contexts(con));)
2137
2141
2143}
2144
2145static int load_module(void)
2146{
2147 int res;
2148
2149 if (pbx_load_module()) {
2150 unload_module();
2152 }
2153
2157
2162
2163 if (res) {
2164 unload_module();
2166 }
2167
2169}
2170
2171static int reload(void)
2172{
2175 return pbx_load_module();
2176}
2177
2178AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
2179 .support_level = AST_MODULE_SUPPORT_CORE,
2180 .load = load_module,
2181 .unload = unload_module,
2182 .reload = reload,
static const char app[]
Definition: app_adsiprog.c:56
static EditLine * el
Definition: asterisk.c:340
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition: callerid.c:1002
static int priority
static const char config_file[]
Definition: cdr_odbc.c:54
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
#define AST_MAX_EXTENSION
Definition: channel.h:134
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2429
#define ast_cli_register(e)
Registers a command or an array of commands.
Definition: cli.h:256
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
char * end
Definition: eagi_proxy.c:73
static const char name[]
Definition: format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:888
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3354
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1845
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3386
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3015
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8014
void ast_hashtab_destroy(struct ast_hashtab *tab, void(*objdestroyfunc)(void *obj))
This func will free the hash table and all its memory.
Definition: hashtab.c:363
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:127
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
Definition: hashtab.h:254
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition: hashtab.c:84
const char * ext
Definition: http.c:150
char * strsep(char **str, const char *delims)
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
Definition: main/config.c:773
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_ERROR
#define LOG_WARNING
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
int errno
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:315
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_opt_dont_warn
Definition: options.h:125
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
static char * overrideswitch
Definition: pbx.c:770
Core PBX routines and definitions.
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8562
const struct ast_sw * ast_context_switches_get(const struct ast_context *con, int idx)
Definition: pbx.c:8639
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6928
int ast_context_destroy_by_name(const char *context, const char *registrar)
Destroy a context by name.
Definition: pbx.c:8205
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Remove an ignorepat.
Definition: pbx.c:6795
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4024
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8519
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8463
void ast_context_set_autohints(struct ast_context *con, int enabled)
Enable or disable autohints support on a context.
Definition: pbx.c:6230
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: ael_main.c:589
int ast_context_add_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Add an ignorepat.
Definition: pbx.c:6835
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8547
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4172
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8557
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:6664
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Add an extension to an extension context, this time with an ast_context *.
Definition: pbx.c:7257
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition: ael_main.c:359
const char * ast_get_switch_name(const struct ast_sw *sw)
Definition: pbx_sw.c:48
int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: ael_main.c:348
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8552
const char * ast_get_extension_label(struct ast_exten *e)
Definition: pbx.c:8514
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: ael_main.c:596
const char * ast_get_switch_data(const struct ast_sw *sw)
Definition: pbx_sw.c:53
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6149
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const char * ast_get_context_registrar(struct ast_context *c)
Definition: pbx.c:8527
void pbx_set_overrideswitch(const char *newval)
Definition: pbx.c:4784
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8491
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
Definition: pbx.c:6426
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4061
int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar)
Definition: pbx.c:4953
int pbx_set_extenpatternmatchnew(int newval)
Definition: pbx.c:4777
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
const char * ast_get_ignorepat_registrar(const struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:47
void pbx_builtin_clear_globals(void)
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8221
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8468
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8722
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
Definition: ael_main.c:370
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8684
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: extconf.c:4975
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:8732
int ast_context_remove_include(const char *context, const char *include, const char *registrar)
Remove a context include.
Definition: pbx.c:4836
#define PRIORITY_HINT
Definition: pbx.h:54
const struct ast_ignorepat * ast_context_ignorepats_get(const struct ast_context *con, int idx)
Definition: pbx.c:8727
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8473
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8634
int pbx_set_autofallthrough(int newval)
Definition: pbx.c:4770
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8679
const char * ast_get_include_registrar(const struct ast_include *i)
Definition: pbx_include.c:60
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8509
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8486
const char * ast_get_ignorepat_name(const struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:42
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8532
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
const char * ast_get_switch_registrar(const struct ast_sw *sw)
Definition: pbx_sw.c:63
static char * complete_dialplan_remove_extension(struct ast_cli_args *)
Definition: pbx_config.c:552
static char * complete_dialplan_add_extension(struct ast_cli_args *)
Definition: pbx_config.c:1308
static char * complete_dialplan_remove_context(struct ast_cli_args *)
Definition: pbx_config.c:1279
static int manager_dialplan_extension_add(struct mansession *s, const struct message *m)
Definition: pbx_config.c:1197
static void pbx_load_users(void)
Definition: pbx_config.c:2002
static char * complete_dialplan_add_include(struct ast_cli_args *)
Definition: pbx_config.c:746
static const char registrar[]
Definition: pbx_config.c:97
static char * pbx_strsep(char **destructible, const char *delim)
Definition: pbx_config.c:1648
static char * overrideswitch_config
Definition: pbx_config.c:105
static int extenpatternmatchnew_config
Definition: pbx_config.c:104
static char * handle_cli_dialplan_remove_context(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:134
static int autofallthrough_config
Definition: pbx_config.c:102
static char * complete_dialplan_add_ignorepat(struct ast_cli_args *)
Definition: pbx_config.c:1394
static char * handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
'save dialplan' CLI command implementation functions ...
Definition: pbx_config.c:811
static struct ast_cli_entry cli_dialplan_save
Definition: pbx_config.c:1618
static const char * skip_words(const char *p, int n)
moves to the n-th word in the string, or empty string if none
Definition: pbx_config.c:238
#define AMI_EXTENSION_ADD
Definition: pbx_config.c:1621
static int lookup_c_ip(struct ast_context *c, const char *name)
return true if 'name' is in the ignorepats for context c
Definition: pbx_config.c:214
static int pbx_load_module(void)
Definition: pbx_config.c:2106
static void startup_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: pbx_config.c:1981
static char * handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:162
static struct ast_context * local_contexts
Definition: pbx_config.c:113
static struct ast_cli_entry cli_pbx_config[]
Definition: pbx_config.c:1607
static char * handle_cli_dialplan_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:1578
#define AMI_EXTENSION_REMOVE
Definition: pbx_config.c:1622
static char * handle_cli_dialplan_add_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
ADD EXTENSION command stuff.
Definition: pbx_config.c:1065
static int clearglobalvars_config
Definition: pbx_config.c:103
static int split_ec(const char *src, char **ext, char **const ctx, char **const cid)
split extension@context in two parts, return -1 on error. The return string is malloc'ed and pointed ...
Definition: pbx_config.c:261
static char * handle_cli_dialplan_add_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:1340
static char * handle_cli_dialplan_remove_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:1441
static struct stasis_subscription * fully_booted_subscription
Definition: pbx_config.c:107
static char * complete_dialplan_remove_include(struct ast_cli_args *)
Definition: pbx_config.c:291
static const char config[]
Definition: pbx_config.c:96
static int static_config
Definition: pbx_config.c:100
static char userscontext[AST_MAX_EXTENSION]
Definition: pbx_config.c:98
static int pbx_load_config(const char *config_file)
Definition: pbx_config.c:1678
static int lookup_ci(struct ast_context *c, const char *name)
return true if 'name' is included by context c
Definition: pbx_config.c:190
static ast_mutex_t reload_lock
Definition: pbx_config.c:111
static int load_module(void)
Definition: pbx_config.c:2145
static void append_interface(char *iface, int maxlen, char *add)
Definition: pbx_config.c:1969
static int unload_module(void)
Definition: pbx_config.c:1627
static int reload(void)
Definition: pbx_config.c:2171
static char * handle_cli_dialplan_add_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:676
static ast_mutex_t save_dialplan_lock
Definition: pbx_config.c:109
#define PUT_CTX_HDR
static char * complete_dialplan_remove_ignorepat(struct ast_cli_args *)
Definition: pbx_config.c:1490
static int partial_match(const char *s, const char *word, int len)
match the first 'len' chars of word. len==0 always succeeds
Definition: pbx_config.c:253
static struct ast_hashtab * local_table
Definition: pbx_config.c:114
static char * handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_config.c:417
static int manager_dialplan_extension_remove(struct mansession *s, const struct message *m)
Definition: pbx_config.c:504
static int write_protect_config
Definition: pbx_config.c:101
struct stasis_forward * sub
Definition: res_corosync.c:240
#define NULL
Definition: resample.c:96
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:680
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:971
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
ast_context: An extension context
Definition: pbx.c:284
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:237
char * exten
Definition: pbx.c:238
const char * label
Definition: pbx.c:244
Structure used to handle boolean flags.
Definition: utils.h:199
ast_ignorepat: Ignore patterns in dial plan
Definition: pbx_ignorepat.c:37
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
struct ast_json * json
Definition: json.h:1083
ast_sw: Switch statement in extensions.conf
Definition: pbx_sw.c:37
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
structure to hold extensions
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1750
static struct test_val a
static struct test_val c
char * ast_escape_semicolons(const char *string, char *outbuf, int buflen)
Escape semicolons found in a string.
Definition: utils.c:811
#define ARRAY_LEN(a)
Definition: utils.h:666