Version 0.1.0 from FTP
[asterisk/asterisk.git] / apps / app_directory.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Provide a directory of extensions
5  * 
6  * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/file.h>
15 #include <asterisk/logger.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/pbx.h>
18 #include <asterisk/module.h>
19 #include <asterisk/config.h>
20 #include <asterisk/say.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25 #include <stdio.h>
26 #include "../asterisk.h"
27
28 static char *tdesc = "Extension Directory";
29 static char *app = "Directory";
30
31 /* For simplicity, I'm keeping the format compatible with the voicemail config,
32    but i'm open to suggestions for isolating it */
33
34 #define DIRECTORY_CONFIG "voicemail.conf"
35
36 /* How many digits to read in */
37 #define NUMDIGITS 3
38
39 STANDARD_LOCAL_USER;
40
41 LOCAL_USER_DECL;
42
43 static char *convert(char *lastname)
44 {
45         char *tmp;
46         int lcount = 0;
47         tmp = malloc(NUMDIGITS + 1);
48         if (tmp) {
49                 while((*lastname > 32) && lcount < NUMDIGITS) {
50                         switch(toupper(*lastname)) {
51                         case '1':
52                                 tmp[lcount++] = '1';
53                                 break;
54                         case '2':
55                         case 'A':
56                         case 'B':
57                         case 'C':
58                                 tmp[lcount++] = '2';
59                                 break;
60                         case '3':
61                         case 'D':
62                         case 'E':
63                         case 'F':
64                                 tmp[lcount++] = '3';
65                                 break;
66                         case '4':
67                         case 'G':
68                         case 'H':
69                         case 'I':
70                                 tmp[lcount++] = '4';
71                                 break;
72                         case '5':
73                         case 'J':
74                         case 'K':
75                         case 'L':
76                                 tmp[lcount++] = '5';
77                                 break;
78                         case '6':
79                         case 'M':
80                         case 'N':
81                         case 'O':
82                                 tmp[lcount++] = '6';
83                                 break;
84                         case '7':
85                         case 'P':
86                         case 'Q':
87                         case 'R':
88                         case 'S':
89                                 tmp[lcount++] = '7';
90                                 break;
91                         case '8':
92                         case 'T':
93                         case 'U':
94                         case 'V':
95                                 tmp[lcount++] = '8';
96                                 break;
97                         case '9':
98                         case 'W':
99                         case 'X':
100                         case 'Y':
101                         case 'Z':
102                                 tmp[lcount++] = '9';
103                                 break;
104                         default:
105                         }
106                         lastname++;
107                 }
108                 tmp[lcount] = '\0';
109         }
110         return tmp;
111 }
112
113 static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char digit)
114 {
115         /* Read in the first three digits..  "digit" is the first digit, already read */
116         char ext[NUMDIGITS + 1];
117         struct ast_variable *v;
118         int res;
119         int found=0;
120         char *start, *pos, *conv;
121         char fn[256];
122         memset(ext, 0, sizeof(ext));
123         ext[0] = digit;
124         res = ast_readstring(chan, ext + 1, NUMDIGITS, 3000, 3000, "#");
125         if (!res) {
126                 /* Search for all names which start with those digits */
127                 v = ast_variable_browse(cfg, context);
128                 while(v && !res) {
129                         /* Find all candidate extensions */
130                         while(v) {
131                                 /* Find a candidate extension */
132                                 start = strdup(v->value);
133                                 if (start) {
134                                         strtok(start, ",");
135                                         pos = strtok(NULL, ",");
136                                         if (pos) {
137                                                 /* Grab the last name */
138                                                 if (strrchr(pos, ' '))
139                                                         pos = strrchr(pos, ' ') + 1;
140                                                 conv = convert(pos);
141                                                 if (conv) {
142                                                         if (!strcmp(conv, ext)) {
143                                                                 /* Match! */
144                                                                 found++;
145                                                                 free(conv);
146                                                                 free(start);
147                                                                 break;
148                                                         }
149                                                         free(conv);
150                                                 }
151                                         }
152                                         free(start);
153                                 }
154                                 v = v->next;
155                         }
156                         if (v) {
157                                 /* We have a match -- play a greeting if they have it */
158                                 snprintf(fn, sizeof(fn), "%s/vm/%s/greet", AST_SPOOL_DIR, v->name);
159                                 if (ast_fileexists(fn, NULL)) {
160                                         res = ast_streamfile(chan, fn);
161                                         if (!res)
162                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
163                                         ast_stopstream(chan);
164                                 } else {
165                                         res = ast_say_digit_str(chan, v->name);
166                                 }
167 ahem:
168                                 if (!res)
169                                         res = ast_streamfile(chan, "dir-instr");
170                                 if (!res)
171                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
172                                 if (!res)
173                                         res = ast_waitfordigit(chan, 3000);
174                                 ast_stopstream(chan);
175                                 if (res > -1) {
176                                         if (res == '1') {
177                                                 strncpy(chan->exten, v->name, sizeof(chan->exten));
178                                                 chan->priority = 0;
179                                                 strncpy(chan->context, context, sizeof(chan->context));
180                                                 res = 0;
181                                                 break;
182                                         } else if (res == '*') {
183                                                 res = 0;
184                                                 v = v->next;
185                                         } else {
186                                                 res = 0;
187                                                 goto ahem;
188                                         }
189                                 }
190                         } else {
191                                 if (found) 
192                                         res = ast_streamfile(chan, "dir-nomore");
193                                 else
194                                         res = ast_streamfile(chan, "dir-nomatch");
195                                 if (!res)
196                                         res = 1;
197                                 return res;
198                         }
199                 }
200                 
201         }
202         return res;
203 }
204
205 static int directory_exec(struct ast_channel *chan, void *data)
206 {
207         int res = 0;
208         struct localuser *u;
209         struct ast_config *cfg;
210         if (!data) {
211                 ast_log(LOG_WARNING, "directory requires an argument (context)\n");
212                 return -1;
213         }
214         cfg = ast_load(DIRECTORY_CONFIG);
215         if (!cfg) {
216                 ast_log(LOG_WARNING, "Unable to open directory configuration %s\n", DIRECTORY_CONFIG);
217                 return -1;
218         }
219         LOCAL_USER_ADD(u);
220 top:
221         if (!res)
222                 res = ast_streamfile(chan, "dir-intro");
223         if (!res)
224                 res = ast_waitstream(chan, AST_DIGIT_ANY);
225         ast_stopstream(chan);
226         if (!res)
227                 res = ast_waitfordigit(chan, 5000);
228         if (res > 0) {
229                 res = do_directory(chan, cfg, (char *)data, res);
230                 if (res > 0) {
231                         res = ast_waitstream(chan, AST_DIGIT_ANY);
232                         ast_stopstream(chan);
233                         if (res >= 0) {
234                                 goto top;
235                         }
236                 }
237         }
238         ast_destroy(cfg);
239         LOCAL_USER_REMOVE(u);
240         return res;
241 }
242
243 int unload_module(void)
244 {
245         STANDARD_HANGUP_LOCALUSERS;
246         return ast_unregister_application(app);
247 }
248
249 int load_module(void)
250 {
251         return ast_register_application(app, directory_exec);
252 }
253
254 char *description(void)
255 {
256         return tdesc;
257 }
258
259 int usecount(void)
260 {
261         int res;
262         STANDARD_USECOUNT(res);
263         return res;
264 }