2 * Asterisk -- A telephony toolkit for Linux.
4 * Provide a directory of extensions
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/config.h>
21 #include <asterisk/say.h>
27 #include "../asterisk.h"
28 #include "../astconf.h"
30 static char *tdesc = "Extension Directory";
31 static char *app = "Directory";
33 static char *synopsis = "Provide directory of voicemail extensions";
34 static char *descrip =
35 " Directory(vm-context[|dial-context]): Presents the user with a directory\n"
36 "of extensions from which they may select by name. The list of names \n"
37 "and extensions is discovered from voicemail.conf. The vm-context argument\n"
38 "is required, and specifies the context of voicemail.conf to use. The\n"
39 "dial-context is the context to use for dialing the users, and defaults to\n"
40 "the vm-context if unspecified. Returns 0 unless the user hangs up. It also\n"
41 "sets up the channel on exit to enter the extension the user selected.\n";
43 /* For simplicity, I'm keeping the format compatible with the voicemail config,
44 but i'm open to suggestions for isolating it */
46 #define DIRECTORY_CONFIG "voicemail.conf"
48 /* How many digits to read in */
55 static char *convert(char *lastname)
59 tmp = malloc(NUMDIGITS + 1);
61 while((*lastname > 32) && lcount < NUMDIGITS) {
62 switch(toupper(*lastname)) {
124 static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit)
126 /* Read in the first three digits.. "digit" is the first digit, already read */
127 char ext[NUMDIGITS + 1];
129 struct ast_variable *v;
132 char *start, *pos, *conv,*stringp=NULL;
135 if (!context || !strlen(context)) {
136 ast_log(LOG_WARNING, "Directory must be called with an argument (context in which to interpret extensions)\n");
139 memset(ext, 0, sizeof(ext));
142 if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1;
144 /* Search for all names which start with those digits */
145 v = ast_variable_browse(cfg, context);
147 /* Find all candidate extensions */
149 /* Find a candidate extension */
150 start = strdup(v->value);
153 strsep(&stringp, ",");
154 pos = strsep(&stringp, ",");
156 strncpy(name, pos, sizeof(name) - 1);
157 /* Grab the last name */
158 if (strrchr(pos, ' '))
159 pos = strrchr(pos, ' ') + 1;
162 if (!strcmp(conv, ext)) {
177 /* We have a match -- play a greeting if they have it */
178 /* Check for the VoiceMail2 greeting first */
179 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", (char *)ast_config_AST_SPOOL_DIR, context, v->name);
180 /* Otherwise, check for an old-style Voicemail greeting */
181 snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet", (char *)ast_config_AST_SPOOL_DIR, v->name);
182 if (ast_fileexists(fn, NULL, chan->language) > 0) {
183 res = ast_streamfile(chan, fn, chan->language);
185 res = ast_waitstream(chan, AST_DIGIT_ANY);
186 ast_stopstream(chan);
187 } else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
188 res = ast_streamfile(chan, fn2, chan->language);
190 res = ast_waitstream(chan, AST_DIGIT_ANY);
191 ast_stopstream(chan);
193 res = ast_say_character_str(chan, strlen(name) ? name : v->name, AST_DIGIT_ANY, chan->language);
197 res = ast_streamfile(chan, "dir-instr", chan->language);
199 res = ast_waitstream(chan, AST_DIGIT_ANY);
201 res = ast_waitfordigit(chan, 3000);
202 ast_stopstream(chan);
205 if (ast_exists_extension(chan, dialcontext, v->name, 1, chan->callerid)) {
206 strncpy(chan->exten, v->name, sizeof(chan->exten)-1);
208 strncpy(chan->context, dialcontext, sizeof(chan->context)-1);
211 ast_log(LOG_WARNING, "Can't find extension '%s' in context '%s'. Did you pass the wrong context to Directory?\n", v->name, context);
215 } else if (res == '*') {
225 res = ast_streamfile(chan, "dir-nomore", chan->language);
227 res = ast_streamfile(chan, "dir-nomatch", chan->language);
238 static int directory_exec(struct ast_channel *chan, void *data)
242 struct ast_config *cfg;
243 char *context, *dialcontext, *dirintro;
245 ast_log(LOG_WARNING, "directory requires an argument (context)\n");
248 cfg = ast_load(DIRECTORY_CONFIG);
250 ast_log(LOG_WARNING, "Unable to open directory configuration %s\n", DIRECTORY_CONFIG);
255 context = ast_strdupa(data);
256 dialcontext = strchr(context, '|');
261 dialcontext = context;
262 dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
263 if (!dirintro || !strlen(dirintro))
264 dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
265 if (!dirintro || !strlen(dirintro))
266 dirintro = "dir-intro";
267 if (chan->_state != AST_STATE_UP)
268 res = ast_answer(chan);
270 res = ast_streamfile(chan, dirintro, chan->language);
272 res = ast_waitstream(chan, AST_DIGIT_ANY);
273 ast_stopstream(chan);
275 res = ast_waitfordigit(chan, 5000);
277 res = do_directory(chan, cfg, context, dialcontext, res);
279 res = ast_waitstream(chan, AST_DIGIT_ANY);
280 ast_stopstream(chan);
287 LOCAL_USER_REMOVE(u);
291 int unload_module(void)
293 STANDARD_HANGUP_LOCALUSERS;
294 return ast_unregister_application(app);
297 int load_module(void)
299 return ast_register_application(app, directory_exec, synopsis, descrip);
302 char *description(void)
310 STANDARD_USECOUNT(res);
316 return ASTERISK_GPL_KEY;