Asterisk - The Open Source Telephony Project  21.4.1
pbx_loopback.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, 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 Loopback PBX Module
22  *
23  */
24 
25 /*** MODULEINFO
26  <support_level>core</support_level>
27  ***/
28 
29 #include "asterisk.h"
30 
31 #include "asterisk/file.h"
32 #include "asterisk/logger.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/config.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/lock.h"
40 #include "asterisk/md5.h"
41 #include "asterisk/linkedlists.h"
42 #include "asterisk/chanvars.h"
43 #include "asterisk/sched.h"
44 #include "asterisk/io.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/astdb.h"
47 
48 
49 /* Loopback switch creates a 'tunnel' to another context. When extension
50  lookups pass through the 'tunnel', Asterisk expressions can be used
51  to modify the target extension, context, and priority in any way desired.
52  If there is a match at the far end, execution jumps through the 'tunnel'
53  to the matched context, extension, and priority.
54 
55  Global variables as well as ${CONTEXT}, ${EXTEN}, and ${PRIORITY} are
56  available for substitution. After substitution Loopback expects to get
57  a string of the form:
58 
59  [exten]@context[:priority][/extramatch]
60 
61  Where exten, context, and priority are another extension, context, and priority
62  to lookup and "extramatch" is a dialplan extension pattern which the *original*
63  number must match. If exten or priority are empty, the original values are
64  used.
65 
66  Note that the search context MUST be a different context from the current
67  context or the search will not succeed. This is intended to reduce the
68  likelihood of loops (they're still possible if you try hard, so be careful!)
69 
70 */
71 
72 
73 #define LOOPBACK_COMMON \
74  char buf[1024]; \
75  int res; \
76  char *newexten=(char *)exten, *newcontext=(char *)context; \
77  int newpriority=priority; \
78  char *newpattern=NULL; \
79  loopback_subst(buf, sizeof(buf), exten, context, priority, data); \
80  loopback_parse(&newexten, &newcontext, &newpriority, &newpattern, buf); \
81  ast_debug(1, "Parsed into %s @ %s priority %d pattern %s\n", newexten, newcontext, newpriority, newpattern); \
82  if (!strcasecmp(newcontext, context)) return -1
83 
84 static char *loopback_subst(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
85 {
86  struct ast_var_t *newvariable;
87  struct varshead headp;
88  char tmp[80];
89 
90  snprintf(tmp, sizeof(tmp), "%d", priority);
92  if ((newvariable = ast_var_assign("EXTEN", exten))) {
93  AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
94  }
95  if ((newvariable = ast_var_assign("CONTEXT", context))) {
96  AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
97  }
98  if ((newvariable = ast_var_assign("PRIORITY", tmp))) {
99  AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
100  }
101  /* Substitute variables */
102  pbx_substitute_variables_varshead(&headp, data, buf, buflen);
103  /* free the list */
104  while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
105  ast_var_delete(newvariable);
106  return buf;
107 }
108 
109 static void loopback_parse(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
110 {
111  char *con;
112  char *pri;
113  *newpattern = strchr(buf, '/');
114  if (*newpattern)
115  *(*newpattern)++ = '\0';
116  con = strchr(buf, '@');
117  if (con) {
118  *con++ = '\0';
119  pri = strchr(con, ':');
120  } else
121  pri = strchr(buf, ':');
122  if (!ast_strlen_zero(buf))
123  *newexten = buf;
124  if (!ast_strlen_zero(con))
125  *newcontext = con;
126  if (!ast_strlen_zero(pri))
127  sscanf(pri, "%30d", priority);
128 }
129 
130 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
131 {
132  LOOPBACK_COMMON;
133  if (newpattern && !ast_extension_match(newpattern, exten))
134  res = 0;
135  else
136  res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
137  return res;
138 }
139 
140 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
141 {
142  LOOPBACK_COMMON;
143  if (newpattern && !ast_extension_match(newpattern, exten))
144  res = 0;
145  else
146  res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
147  return res;
148 }
149 
150 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
151 {
152  int found;
153  LOOPBACK_COMMON;
154  res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
155  return res;
156 }
157 
158 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
159 {
160  LOOPBACK_COMMON;
161  if (newpattern && !ast_extension_match(newpattern, exten))
162  res = 0;
163  else
164  res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
165  return res;
166 }
167 
168 static struct ast_switch loopback_switch =
169 {
170  .name = "Loopback",
171  .description = "Loopback Dialplan Switch",
172  .exists = loopback_exists,
173  .canmatch = loopback_canmatch,
174  .exec = loopback_exec,
175  .matchmore = loopback_matchmore,
176 };
177 
178 static int unload_module(void)
179 {
180  ast_unregister_switch(&loopback_switch);
181  return 0;
182 }
183 
184 static int load_module(void)
185 {
186  if (ast_register_switch(&loopback_switch))
189 }
190 
191 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch) ...
Definition: pbx.c:4195
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
Channel Variables.
void ast_unregister_switch(struct ast_switch *sw)
Unregister an alternative switch.
Definition: pbx_switch.c:76
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
I/O Management (derived from Cheops-NG)
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4190
Utility functions.
const char * name
Definition: pbx.h:162
Configuration File Parser.
General Asterisk PBX channel definitions.
Scheduler Routines (derived from cheops)
Asterisk internal frame definitions.
A set of macros to manage forward-linked lists.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
Core PBX routines and definitions.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: extconf.c:4295
int ast_register_switch(struct ast_switch *sw)
Register an alternative dialplan switch.
Definition: pbx_switch.c:58
Module could not be loaded properly.
Definition: module.h:102
Support for logging to various files, console and syslog Configuration in file logger.conf.
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
Launch a new extension (i.e. new stack)
Definition: pbx.c:4200
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
Standard Command Line Interface.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
MD5 digest functions.
Persistent data storage (akin to *doze registry)