Realtime improvements
[asterisk/asterisk.git] / pbx / pbx_realtime.c
1 /*
2  * Realtime PBX Module
3  *
4  * Copyright (C) 2004, Digium Inc.
5  *
6  * Written by Mark Spencer <markster@digium.com>
7  *
8  * This program is Free Software distributed under the terms of
9  * of the GNU General Public License.
10  */
11
12 #include <asterisk/file.h>
13 #include <asterisk/logger.h>
14 #include <asterisk/channel.h>
15 #include <asterisk/config.h>
16 #include <asterisk/options.h>
17 #include <asterisk/pbx.h>
18 #include <asterisk/module.h>
19 #include <asterisk/frame.h>
20 #include <asterisk/file.h>
21 #include <asterisk/cli.h>
22 #include <asterisk/lock.h>
23 #include <asterisk/md5.h>
24 #include <asterisk/linkedlists.h>
25 #include <asterisk/chanvars.h>
26 #include <asterisk/sched.h>
27 #include <asterisk/io.h>
28 #include <asterisk/utils.h>
29 #include <asterisk/crypto.h>
30 #include <asterisk/astdb.h>
31
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #define MODE_MATCH 0
38 #define MODE_MATCHMORE 1
39 #define MODE_CANMATCH 2
40
41 static char *tdesc = "Realtime Switch";
42
43 /* Realtime switch looks up extensions in the supplied realtime table.
44
45         [context@][realtimetable][/options]
46
47         If the realtimetable is omitted it is assumed to be "extensions".  If no context is 
48         specified the context is assumed to be whatever is the container.
49
50         The realtime table should have entries for context,exten,priority,app,args
51         
52         The realtime table currently does not support patterns or callerid fields.
53
54 */
55
56
57 #define REALTIME_COMMON(mode) \
58         char *buf; \
59         char *opts; \
60         const char *cxt; \
61         char *table; \
62         int res=-1; \
63         struct ast_variable *var=NULL; \
64         buf = ast_strdupa(data); \
65         if (buf) { \
66                 opts = strchr(buf, '/'); \
67                 if (opts) { \
68                         *opts='\0'; \
69                         opts++; \
70                 } else \
71                         opts=""; \
72                 table = strchr(buf, '@'); \
73                 if (table) { \
74                         *table = '\0'; \
75                         table++;\
76                         cxt = buf; \
77                 } else cxt = NULL; \
78                 if (!cxt || ast_strlen_zero(cxt)) \
79                         cxt = context;\
80                 if (!table || ast_strlen_zero(table)) \
81                         table = "extensions"; \
82                 var = realtime_switch_common(table, cxt, exten, priority, mode); \
83         } else \
84                 res = -1; 
85
86 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
87 {
88         struct ast_variable *var;
89         char pri[20];
90         char *ematch;
91         char rexten[AST_MAX_EXTENSION + 20]="";
92         snprintf(pri, sizeof(pri), "%d", priority);
93         switch(mode) {
94         case MODE_MATCHMORE:
95                 ematch = "exten LIKE";
96                 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
97                 break;
98         case MODE_CANMATCH:
99                 ematch = "exten LIKE";
100                 snprintf(rexten, sizeof(rexten), "%s%%", exten);
101                 break;
102         case MODE_MATCH:
103         default:
104                 ematch = "exten";
105                 strncpy(rexten, exten, sizeof(rexten) - 1);
106         }
107         var = ast_load_realtime(table, "context", context, ematch, rexten, "priority", pri, NULL);
108         return var;
109 }
110
111 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
112 {
113         REALTIME_COMMON(MODE_MATCH);
114         if (var) ast_destroy_realtime(var);
115         if (var)
116                 res = 1;
117         return res > 0 ? res : 0;
118 }
119
120 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
121 {
122         REALTIME_COMMON(MODE_CANMATCH);
123         if (var) ast_destroy_realtime(var);
124         if (var)
125                 res = 1;
126         return res > 0 ? res : 0;
127 }
128
129 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data)
130 {
131         char app[256];
132         char *appdata="";
133         struct ast_app *a;
134         struct ast_variable *v;
135         REALTIME_COMMON(MODE_MATCH);
136         if (var) {
137                 v = var;
138                 while(v) {
139                         if (!strcasecmp(v->name, "app"))
140                                 strncpy(app, v->value, sizeof(app) -1 );
141                         else if (!strcasecmp(v->name, "appdata"))
142                                 appdata = ast_strdupa(v->value);
143                         v = v->next;
144                 }
145                 ast_destroy_realtime(var);
146                 if (!ast_strlen_zero(app)) {
147                         a = pbx_findapp(app);
148                         if (a) {
149                                 res = pbx_exec(chan, a, appdata, newstack);
150                         } else
151                                 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
152                 }
153         }
154         return res;
155 }
156
157 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
158 {
159         REALTIME_COMMON(MODE_MATCHMORE);
160         if (var) ast_destroy_realtime(var);
161         if (var)
162                 res = 1;
163         return res > 0 ? res : 0;
164 }
165
166 static struct ast_switch realtime_switch =
167 {
168         name:                   "Realtime",
169         description:                    "Realtime Dialplan Switch",
170         exists:                 realtime_exists,
171         canmatch:               realtime_canmatch,
172         exec:                   realtime_exec,
173         matchmore:              realtime_matchmore,
174 };
175
176 char *description(void)
177 {
178         return tdesc;
179 }
180
181 int usecount(void)
182 {
183         return 1;
184 }
185
186 char *key()
187 {
188         return ASTERISK_GPL_KEY;
189 }
190
191 int unload_module(void)
192 {
193         ast_unregister_switch(&realtime_switch);
194         return 0;
195 }
196
197 int load_module(void)
198 {
199         ast_register_switch(&realtime_switch);
200         return 0;
201 }
202