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