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