Version 0.1.10 from FTP
[asterisk/asterisk.git] / apps / app_voicemail.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Voicemail System (did you ever think it could be so easy?)
5  * 
6  * Copyright (C) 1999, Mark Spencer
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/options.h>
19 #include <asterisk/config.h>
20 #include <asterisk/say.h>
21 #include <asterisk/module.h>
22 #include <asterisk/adsi.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 #include <time.h>
32
33 #include <pthread.h>
34 #include "../asterisk.h"
35
36 #define COMMAND_TIMEOUT 5000
37
38 #define VOICEMAIL_CONFIG "voicemail.conf"
39 #define ASTERISK_USERNAME "asterisk"
40
41 #define SENDMAIL "/usr/sbin/sendmail -t"
42
43 #define INTRO "vm-intro"
44
45 #define MAXMSG 100
46
47 #define MAX_OTHER_FORMATS 10
48
49 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
50
51
52 static char *tdesc = "Comedian Mail (Voicemail System)";
53
54 static char *adapp = "CoMa";
55
56 static char *adsec = "_AST";
57
58 static char *addesc = "Comedian Mail";
59
60 static int adver = 1;
61
62 static char *synopsis_vm =
63 "Leave a voicemail message";
64
65 static char *descrip_vm =
66 "  VoiceMail([s|u|b]extension): Leaves voicemail for a given  extension (must\n"
67 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
68 "then instructions for leaving the message will be skipped.  If the extension\n"
69 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
70 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.  If the extension\n"
71 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
72 "busy instead of unavail).  At most one of 's', 'u', or 'b' may be specified.\n"
73 "Returns  -1 on  error or mailbox not found, or if the user hangs up. \n"
74 "Otherwise, it returns 0. \n";
75
76 static char *synopsis_vmain =
77 "Enter voicemail system";
78
79 static char *descrip_vmain =
80 "  VoiceMailMain(): Enters the main voicemail system for the checking of voicemail.  Returns\n"
81 "  -1 if the user hangs up or 0 otherwise.\n";
82
83 /* Leave a message */
84 static char *app = "VoiceMail";
85
86 /* Check mail, control, etc */
87 static char *app2 = "VoiceMailMain";
88
89 STANDARD_LOCAL_USER;
90
91 LOCAL_USER_DECL;
92
93 static int make_dir(char *dest, int len, char *ext, char *mailbox)
94 {
95         return snprintf(dest, len, "%s/%s/%s", VM_SPOOL_DIR, ext, mailbox);
96 }
97
98 static int make_file(char *dest, int len, char *dir, int num)
99 {
100         return snprintf(dest, len, "%s/msg%04d", dir, num);
101 }
102
103 #if 0
104
105 static int announce_message(struct ast_channel *chan, char *dir, int msgcnt)
106 {
107         char *fn;
108         int res;
109         res = ast_streamfile(chan, "vm-message", chan->language);
110         if (!res) {
111                 res = ast_waitstream(chan, AST_DIGIT_ANY);
112                 if (!res) {
113                         res = ast_say_number(chan, msgcnt+1, chan->language);
114                         if (!res) {
115                                 fn = get_fn(dir, msgcnt);
116                                 if (fn) {
117                                         res = ast_streamfile(chan, fn, chan->language);
118                                         free(fn);
119                                 }
120                         }
121                 }
122         }
123         if (res < 0)
124                 ast_log(LOG_WARNING, "Unable to announce message\n");
125         return res;
126 }
127 #endif
128
129 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid)
130 {
131         FILE *p;
132         char date[256];
133         char host[256];
134         char who[256];
135         time_t t;
136         struct tm *tm;
137         p = popen(SENDMAIL, "w");
138         if (p) {
139                 if (strchr(srcemail, '@'))
140                         strncpy(who, srcemail, sizeof(who)-1);
141                 else {
142                         gethostname(host, sizeof(host));
143                         snprintf(who, sizeof(who), "%s@%s", srcemail, host);
144                 }
145                 time(&t);
146                 tm = localtime(&t);
147                 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", tm);
148                 fprintf(p, "Date: %s\n", date);
149                 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
150                 fprintf(p, "From: Asterisk PBX <%s>\n", who);
151                 fprintf(p, "To: %s <%s>\n", name, email);
152                 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n\n", msgnum, mailbox);
153                 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm);
154                 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a message (number %d)\n"
155                            "in mailbox %s from %s, on %s so you might\n"
156                                    "want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n", name, 
157                         msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
158                 fprintf(p, ".\n");
159                 pclose(p);
160         } else {
161                 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
162                 return -1;
163         }
164         return 0;
165 }
166
167 static int get_date(char *s, int len)
168 {
169         struct tm *tm;
170         time_t t;
171         t = time(0);
172         tm = localtime(&t);
173         return strftime(s, len, "%a %b %e %r %Z %Y", tm);
174 }
175
176 static int invent_message(struct ast_channel *chan, char *ext, int busy)
177 {
178         int res;
179         res = ast_streamfile(chan, "vm-theperson", chan->language);
180         if (res)
181                 return -1;
182         res = ast_waitstream(chan, "#");
183         if (res)
184                 return res;
185         res = ast_say_digit_str(chan, ext, "#", chan->language);
186         if (res)
187                 return res;
188         if (busy)
189                 res = ast_streamfile(chan, "vm-isonphone", chan->language);
190         else
191                 res = ast_streamfile(chan, "vm-isunavail", chan->language);
192         if (res)
193                 return -1;
194         res = ast_waitstream(chan, "#");
195         return res;
196 }
197
198 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
199 {
200         struct ast_config *cfg;
201         char *copy, *name, *passwd, *email, *fmt, *fmts;
202         char comment[256];
203         struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS];
204         char *sfmt[MAX_OTHER_FORMATS];
205         char txtfile[256];
206         FILE *txt;
207         int res = -1, fmtcnt=0, x;
208         int msgnum;
209         int outmsg=0;
210         struct ast_frame *f;
211         char date[256];
212         char dir[256];
213         char fn[256];
214         char prefile[256]="";
215         char *astemail;
216         
217         cfg = ast_load(VOICEMAIL_CONFIG);
218         if (!cfg) {
219                 ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG);
220                 return -1;
221         }
222         if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) 
223                 astemail = ASTERISK_USERNAME;
224         if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
225                 /* Setup pre-file if appropriate */
226                 if (busy)
227                         snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
228                 else if (unavail)
229                         snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
230                 /* Make sure they have an entry in the config */
231                 copy = strdup(copy);
232                 passwd = strtok(copy, ",");
233                 name = strtok(NULL, ",");
234                 email = strtok(NULL, ",");
235                 make_dir(dir, sizeof(dir), ext, "");
236                 /* It's easier just to try to make it than to check for its existence */
237                 if (mkdir(dir, 0700) && (errno != EEXIST))
238                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
239                 make_dir(dir, sizeof(dir), ext, "INBOX");
240                 if (mkdir(dir, 0700) && (errno != EEXIST))
241                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
242                 /* Play the beginning intro if desired */
243                 if (strlen(prefile)) {
244                         if (ast_fileexists(prefile, NULL, NULL) < 0) {
245                                 if (ast_streamfile(chan, prefile, chan->language) > -1) 
246                                     silent = ast_waitstream(chan, "#");
247                         } else {
248                                 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
249                                 silent = invent_message(chan, ext, busy);
250                         }
251                         if (silent < 0) {
252                                 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
253                                 free(copy);
254                                 return -1;
255                         }
256                 }
257                 /* If they hit "#" we should still play the beep sound */
258                 if (silent == '#') {
259                         if (!ast_streamfile(chan, "beep", chan->language) < 0)
260                                 silent = 1;
261                         ast_waitstream(chan, "");
262                 }
263                 /* Stream an info message */
264                 if (silent || !ast_streamfile(chan, INTRO, chan->language)) {
265                         /* Wait for the message to finish */
266                         if (silent || !ast_waitstream(chan, "")) {
267                                 fmt = ast_variable_retrieve(cfg, "general", "format");
268                                 if (fmt) {
269                                         fmts = strdup(fmt);
270                                         fmt = strtok(fmts, "|");
271                                         msgnum = 0;
272                                         do {
273                                                 make_file(fn, sizeof(fn), dir, msgnum);
274                                                 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
275                                                                                         (chan->callerid ? chan->callerid : "Unknown"), 
276                                                                                         name, ext, chan->name);
277                                                 if (ast_fileexists(fn, NULL, chan->language) > 0) {
278                                                         msgnum++;
279                                                         continue;
280                                                 }
281                                                 writer = ast_writefile(fn, fmt, comment, O_EXCL, 1 /* check for other formats */, 0700);
282                                                 if (!writer)
283                                                         break;
284                                                 msgnum++;
285                                         } while(!writer && (msgnum < MAXMSG));
286                                         if (writer) {
287                                                 /* Store information */
288                                                 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
289                                                 txt = fopen(txtfile, "w+");
290                                                 if (txt) {
291                                                         get_date(date, sizeof(date));
292                                                         fprintf(txt, 
293 "#\n"
294 "# Message Information file\n"
295 "#\n"
296 "origmailbox=%s\n"
297 "context=%s\n"
298 "exten=%s\n"
299 "priority=%d\n"
300 "callerchan=%s\n"
301 "callerid=%s\n"
302 "origdate=%s\n",
303         ext,
304         chan->context,
305         chan->exten,
306         chan->priority,
307         chan->name,
308         chan->callerid ? chan->callerid : "Unknown",
309         date);
310                                                         fclose(txt);
311                                                 } else
312                                                         ast_log(LOG_WARNING, "Error opening text file for output\n");
313         
314                                                 /* We need to reset these values */
315                                                 free(fmts);
316                                                 fmt = ast_variable_retrieve(cfg, "general", "format");
317                                                 fmts = strdup(fmt);
318                                                 strtok(fmts, "|");
319                                                 while((fmt = strtok(NULL, "|"))) {
320                                                         if (fmtcnt > MAX_OTHER_FORMATS - 1) {
321                                                                 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
322                                                                 break;
323                                                         }
324                                                         sfmt[fmtcnt++] = strdup(fmt);
325                                                 }
326                                                 for (x=0;x<fmtcnt;x++) {
327                                                         others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
328                                                         if (!others[x]) {
329                                                                 /* Ick, the other format didn't work, but be sure not
330                                                                    to leak memory here */
331                                                                 int y;
332                                                                 for(y=x+1;y < fmtcnt;y++)
333                                                                         free(sfmt[y]);
334                                                                 break;
335                                                         }
336                                                         free(sfmt[x]);
337                                                 }
338                                                 if (x == fmtcnt) {
339                                                         /* Loop forever, writing the packets we read to the writer(s), until
340                                                            we read a # or get a hangup */
341                                                         if (option_verbose > 2) 
342                                                                 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
343                                                         while((f = ast_read(chan))) {
344                                                                 if (f->frametype == AST_FRAME_VOICE) {
345                                                                         /* Write the primary format */
346                                                                         res = ast_writestream(writer, f);
347                                                                         if (res) {
348                                                                                 ast_log(LOG_WARNING, "Error writing primary frame\n");
349                                                                                 break;
350                                                                         }
351                                                                         /* And each of the others */
352                                                                         for (x=0;x<fmtcnt;x++) {
353                                                                                 res |= ast_writestream(others[x], f);
354                                                                         }
355                                                                         ast_frfree(f);
356                                                                         /* Exit on any error */
357                                                                         if (res) {
358                                                                                 ast_log(LOG_WARNING, "Error writing frame\n");
359                                                                                 break;
360                                                                         }
361                                                                 }
362                                                                 if (f->frametype == AST_FRAME_DTMF) {
363                                                                         if (f->subclass == '#') {
364                                                                                 if (option_verbose > 2) 
365                                                                                         ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
366                                                                                 outmsg=2;
367                                                                                 break;
368                                                                         }
369                                                                 }
370                                                         }
371                                                         if (!f) {
372                                                                 if (option_verbose > 2) 
373                                                                         ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
374                                                                 res = -1;
375                                                                 outmsg=1;
376                                                         }
377                                                 } else {
378                                                         ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]); 
379                                                         free(sfmt[x]);
380                                                 }
381                                                 ast_closestream(writer);
382                                                 for (x=0;x<fmtcnt;x++) {
383                                                         if (!others[x])
384                                                                 break;
385                                                         ast_closestream(others[x]);
386                                                 }
387                                                 if (outmsg) {
388                                                         if (outmsg > 1) {
389                                                                 /* Let them know it worked */
390                                                                 ast_streamfile(chan, "vm-msgsaved", chan->language);
391                                                                 ast_waitstream(chan, "");
392                                                         }
393                                                         /* Send e-mail if applicable */
394                                                         if (email) 
395                                                                 sendmail(astemail, email, name, msgnum, ext, chan->callerid);
396                                                 }
397                                         } else {
398                                                 if (msgnum < MAXMSG)
399                                                         ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
400                                                 else
401                                                         ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
402                                         }
403                                         free(fmts);
404                                 } else 
405                                         ast_log(LOG_WARNING, "No format to save messages in \n");
406                         }
407                 } else
408                         ast_log(LOG_WARNING, "Unable to playback instructions\n");
409                         
410                 free(copy);
411         } else
412                 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
413         ast_destroy(cfg);
414         /* Leave voicemail for someone */
415         return res;
416 }
417
418 static char *mbox(int id)
419 {
420         switch(id) {
421         case 0:
422                 return "INBOX";
423         case 1:
424                 return "Old";
425         case 2:
426                 return "Work";
427         case 3:
428                 return "Family";
429         case 4:
430                 return "Friends";
431         case 5:
432                 return "Cust1";
433         case 6:
434                 return "Cust2";
435         case 7:
436                 return "Cust3";
437         case 8:
438                 return "Cust4";
439         case 9:
440                 return "Cust5";
441         default:
442                 return "Unknown";
443         }
444 }
445
446 static int count_messages(char *dir)
447 {
448         int x;
449         char fn[256];
450         for (x=0;x<MAXMSG;x++) {
451                 make_file(fn, sizeof(fn), dir, x);
452                 if (ast_fileexists(fn, NULL, NULL) < 1)
453                         break;
454         }
455         return x;
456 }
457
458 static int play_and_wait(struct ast_channel *chan, char *fn)
459 {
460         int d;
461         d = ast_streamfile(chan, fn, chan->language);
462         if (d)
463                 return d;
464         d = ast_waitstream(chan, AST_DIGIT_ANY);
465         return d;
466 }
467
468 static int say_and_wait(struct ast_channel *chan, int num)
469 {
470         int d;
471         d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
472         return d;
473 }
474
475 static int copy(char *infile, char *outfile)
476 {
477         int ifd;
478         int ofd;
479         int res;
480         int len;
481         char buf[4096];
482         if ((ifd = open(infile, O_RDONLY)) < 0) {
483                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
484                 return -1;
485         }
486         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
487                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
488                 close(ifd);
489                 return -1;
490         }
491         do {
492                 len = read(ifd, buf, sizeof(buf));
493                 if (len < 0) {
494                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
495                         close(ifd);
496                         close(ofd);
497                         unlink(outfile);
498                 }
499                 if (len) {
500                         res = write(ofd, buf, len);
501                         if (res != len) {
502                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
503                                 close(ifd);
504                                 close(ofd);
505                                 unlink(outfile);
506                         }
507                 }
508         } while(len);
509         close(ifd);
510         close(ofd);
511         return 0;
512 }
513
514 static int save_to_folder(char *dir, int msg, char *username, int box)
515 {
516         char sfn[256];
517         char dfn[256];
518         char ddir[256];
519         char txt[256];
520         char ntxt[256];
521         char *dbox = mbox(box);
522         int x;
523         make_file(sfn, sizeof(sfn), dir, msg);
524         make_dir(ddir, sizeof(ddir), username, dbox);
525         mkdir(ddir, 0700);
526         for (x=0;x<MAXMSG;x++) {
527                 make_file(dfn, sizeof(dfn), ddir, x);
528                 if (ast_fileexists(dfn, NULL, NULL) < 0)
529                         break;
530         }
531         if (x >= MAXMSG)
532                 return -1;
533         ast_filecopy(sfn, dfn, NULL);
534         if (strcmp(sfn, dfn)) {
535                 snprintf(txt, sizeof(txt), "%s.txt", sfn);
536                 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
537                 copy(txt, ntxt);
538         }
539         return 0;
540 }
541
542 static int adsi_logo(unsigned char *buf)
543 {
544         int bytes = 0;
545         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
546         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
547         return bytes;
548 }
549
550 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
551 {
552         char buf[256];
553         int bytes=0;
554         int x;
555         char num[5];
556
557         *useadsi = 0;
558         bytes += adsi_data_mode(buf + bytes);
559         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
560
561         bytes = 0;
562         bytes += adsi_logo(buf);
563         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
564 #ifdef DISPLAY
565         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
566 #endif
567         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
568         bytes += adsi_data_mode(buf + bytes);
569         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
570
571         if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
572                 bytes = 0;
573                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
574                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
575                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
576                 bytes += adsi_voice_mode(buf + bytes, 0);
577                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
578                 return 0;
579         }
580
581 #ifdef DISPLAY
582         /* Add a dot */
583         bytes = 0;
584         bytes += adsi_logo(buf);
585         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
586         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
587         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
588         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
589 #endif
590         bytes = 0;
591         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
592         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
593         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
594         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
595         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
596         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
597         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
598
599 #ifdef DISPLAY
600         /* Add another dot */
601         bytes = 0;
602         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
603         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
604         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
605 #endif
606
607         bytes = 0;
608         /* These buttons we load but don't use yet */
609         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
610         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
611         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
612         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
613         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
614         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
615         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
616
617 #ifdef DISPLAY
618         /* Add another dot */
619         bytes = 0;
620         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
621         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
622         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
623 #endif
624
625         bytes = 0;
626         for (x=0;x<5;x++) {
627                 snprintf(num, sizeof(num), "%d", x);
628                 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
629         }
630         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
631         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
632
633 #ifdef DISPLAY
634         /* Add another dot */
635         bytes = 0;
636         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
637         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
638         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
639 #endif
640
641         if (adsi_end_download(chan)) {
642                 bytes = 0;
643                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
644                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
645                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
646                 bytes += adsi_voice_mode(buf + bytes, 0);
647                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
648                 return 0;
649         }
650         bytes = 0;
651         bytes += adsi_download_disconnect(buf + bytes);
652         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
653
654         ast_log(LOG_DEBUG, "Done downloading scripts...\n");
655
656 #ifdef DISPLAY
657         /* Add last dot */
658         bytes = 0;
659         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
660         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
661 #endif
662         ast_log(LOG_DEBUG, "Restarting session...\n");
663
664         bytes = 0;
665         /* Load the session now */
666         if (adsi_load_session(chan, adapp, adver, 1) == 1) {
667                 *useadsi = 1;
668                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
669         } else
670                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
671
672         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
673         return 0;
674 }
675
676 static void adsi_begin(struct ast_channel *chan, int *useadsi)
677 {
678         int x;
679         x = adsi_load_session(chan, adapp, adver, 1);
680         if (x < 0)
681                 return;
682         if (!x) {
683                 if (adsi_load_vmail(chan, useadsi)) {
684                         ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
685                         return;
686                 }
687         } else
688                 *useadsi = 1;
689 }
690
691 static void adsi_login(struct ast_channel *chan)
692 {
693         char buf[256];
694         int bytes=0;
695         unsigned char keys[6];
696         int x;
697         if (!adsi_available(chan))
698                 return;
699
700         for (x=0;x<6;x++)
701                 keys[x] = 0;
702         /* Set one key for next */
703         keys[3] = ADSI_KEY_APPS + 3;
704
705         bytes += adsi_logo(buf + bytes);
706         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
707         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
708         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
709         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
710         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
711         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
712         bytes += adsi_set_keys(buf + bytes, keys);
713         bytes += adsi_voice_mode(buf + bytes, 0);
714         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
715 }
716
717 static void adsi_password(struct ast_channel *chan)
718 {
719         char buf[256];
720         int bytes=0;
721         unsigned char keys[6];
722         int x;
723         if (!adsi_available(chan))
724                 return;
725
726         for (x=0;x<6;x++)
727                 keys[x] = 0;
728         /* Set one key for next */
729         keys[3] = ADSI_KEY_APPS + 3;
730
731         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
732         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
733         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
734         bytes += adsi_set_keys(buf + bytes, keys);
735         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
736 }
737
738 static void adsi_folders(struct ast_channel *chan, int start, char *label)
739 {
740         char buf[256];
741         int bytes=0;
742         unsigned char keys[6];
743         int x,y;
744
745         if (!adsi_available(chan))
746                 return;
747
748         for (x=0;x<5;x++) {
749                 y = ADSI_KEY_APPS + 12 + start + x;
750                 if (y > ADSI_KEY_APPS + 12 + 4)
751                         y = 0;
752                 keys[x] = ADSI_KEY_SKT | y;
753         }
754         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
755
756         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
757         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
758         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
759         bytes += adsi_set_keys(buf + bytes, keys);
760         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
761 }
762
763 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
764 {
765         int bytes=0;
766         char buf[256], buf1[256], buf2[256];
767         char fn2[256];
768         char cid[256]="";
769         char *val;
770         char *name, *num;
771         char datetime[21]="";
772         FILE *f;
773
774         unsigned char keys[6];
775
776         int x;
777
778         if (!adsi_available(chan))
779                 return;
780
781         /* Retrieve important info */
782         snprintf(fn2, sizeof(fn2), "%s.txt", fn);
783         f = fopen(fn2, "r");
784         if (f) {
785                 while(!feof(f)) {       
786                         fgets(buf, sizeof(buf), f);
787                         if (!feof(f)) {
788                                 strtok(buf, "=");
789                                 val = strtok(NULL, "=");
790                                 if (val && strlen(val)) {
791                                         if (!strcmp(buf, "callerid"))
792                                                 strncpy(cid, val, sizeof(cid) - 1);
793                                         if (!strcmp(buf, "origdate"))
794                                                 strncpy(datetime, val, sizeof(datetime) - 1);
795                                 }
796                         }
797                 }
798                 fclose(f);
799         }
800         /* New meaning for keys */
801         for (x=0;x<5;x++)
802                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
803
804         if (!msg) {
805                 /* No prev key, provide "Folder" instead */
806                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
807         }
808         if (msg >= last) {
809                 /* If last message ... */
810                 if (msg) {
811                         /* but not only message, provide "Folder" instead */
812                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
813                 } else {
814                         /* Otherwise if only message, leave blank */
815                         keys[3] = 1;
816                 }
817         }
818
819         if (strlen(cid)) {
820                 ast_callerid_parse(cid, &name, &num);
821                 if (!name)
822                         name = num;
823         } else
824                 name = "Unknown Caller";
825
826         /* If deleted, show "undeleted" */
827         if (deleted)
828                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
829
830         /* Except "Exit" */
831         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
832         snprintf(buf1, sizeof(buf1), "%s%s", folder,
833                  strcasecmp(folder, "INBOX") ? " Messages" : "");
834         snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
835
836         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
837         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
838         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
839         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
840         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
841         bytes += adsi_set_keys(buf + bytes, keys);
842         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
843 }
844
845 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
846 {
847         int bytes=0;
848         char buf[256];
849         unsigned char keys[6];
850
851         int x;
852
853         if (!adsi_available(chan))
854                 return;
855
856         /* New meaning for keys */
857         for (x=0;x<5;x++)
858                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
859
860         if (!msg) {
861                 /* No prev key, provide "Folder" instead */
862                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
863         }
864         if (msg >= last) {
865                 /* If last message ... */
866                 if (msg) {
867                         /* but not only message, provide "Folder" instead */
868                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
869                 } else {
870                         /* Otherwise if only message, leave blank */
871                         keys[3] = 1;
872                 }
873         }
874
875         /* If deleted, show "undeleted" */
876         if (deleted) 
877                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
878
879         /* Except "Exit" */
880         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
881         bytes += adsi_set_keys(buf + bytes, keys);
882         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
883 }
884
885 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
886 {
887         char buf[256], buf1[256], buf2[256];
888         int bytes=0;
889         unsigned char keys[6];
890         int x;
891
892         char *newm = (new == 1) ? "message" : "messages";
893         char *oldm = (old == 1) ? "message" : "messages";
894         if (!adsi_available(chan))
895                 return;
896         if (new) {
897                 snprintf(buf1, sizeof(buf1), "You have %d new", new);
898                 if (old) {
899                         strcat(buf1, " and");
900                         snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
901                 } else {
902                         snprintf(buf2, sizeof(buf2), "%s.", newm);
903                 }
904         } else if (old) {
905                 snprintf(buf1, sizeof(buf1), "You have %d old", old);
906                 snprintf(buf2, sizeof(buf2), "%s.", oldm);
907         } else {
908                 strcpy(buf1, "You have no messages.");
909                 strcpy(buf2, " ");
910         }
911         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
912         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
913         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
914
915         for (x=0;x<6;x++)
916                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
917
918         /* Don't let them listen if there are none */
919         if (lastmsg < 0)
920                 keys[0] = 1;
921         bytes += adsi_set_keys(buf + bytes, keys);
922
923         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
924 }
925
926 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
927 {
928         char buf[256], buf1[256], buf2[256];
929         int bytes=0;
930         unsigned char keys[6];
931         int x;
932
933         char *mess = (messages == 1) ? "message" : "messages";
934
935         if (!adsi_available(chan))
936                 return;
937
938         /* Original command keys */
939         for (x=0;x<6;x++)
940                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
941
942         if (messages < 1)
943                 keys[0] = 0;
944
945         snprintf(buf1, sizeof(buf1), "%s%s has", folder,
946                         strcasecmp(folder, "INBOX") ? " folder" : "");
947
948         if (messages)
949                 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
950         else
951                 strcpy(buf2, "no messages.");
952         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
953         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
954         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
955         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
956         bytes += adsi_set_keys(buf + bytes, keys);
957
958         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
959         
960 }
961
962 static void adsi_clear(struct ast_channel *chan)
963 {
964         char buf[256];
965         int bytes=0;
966         if (!adsi_available(chan))
967                 return;
968         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
969         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
970 }
971
972 static void adsi_goodbye(struct ast_channel *chan)
973 {
974         char buf[256];
975         int bytes=0;
976         if (!adsi_available(chan))
977                 return;
978         bytes += adsi_logo(buf + bytes);
979         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
980         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
981         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
982         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
983 }
984
985 static int get_folder(struct ast_channel *chan, int start)
986 {
987         int x;
988         int d;
989         char fn[256];
990         d = play_and_wait(chan, "vm-press");
991         if (d)
992                 return d;
993         for (x = start; x< 5; x++) {
994                 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
995                         return d;
996                 d = play_and_wait(chan, "vm-for");
997                 if (d)
998                         return d;
999                 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1000                 d = play_and_wait(chan, fn);
1001                 if (d)
1002                         return d;
1003                 d = play_and_wait(chan, "vm-messages");
1004                 if (d)
1005                         return d;
1006                 d = ast_waitfordigit(chan, 500);
1007                 if (d)
1008                         return d;
1009         }
1010         d = play_and_wait(chan, "vm-tocancel");
1011         if (d)
1012                 return d;
1013         d = ast_waitfordigit(chan, 4000);
1014         return d;
1015 }
1016
1017 #define WAITCMD(a) do { \
1018         d = (a); \
1019         if (d < 0) \
1020                 goto out; \
1021         if (d) \
1022                 goto cmd; \
1023 } while(0)
1024
1025 #define WAITFILE2(file) do { \
1026         if (ast_streamfile(chan, file, chan->language)) \
1027                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1028         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1029         if (d < 0) { \
1030                 goto out; \
1031         }\
1032 } while(0)
1033
1034 #define WAITFILE(file) do { \
1035         if (ast_streamfile(chan, file, chan->language)) \
1036                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1037         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1038         if (!d) { \
1039                 repeats = 0; \
1040                 goto instructions; \
1041         } else if (d < 0) { \
1042                 goto out; \
1043         } else goto cmd;\
1044 } while(0)
1045
1046 #define PLAYMSG(a) do { \
1047         starting = 0; \
1048         make_file(fn, sizeof(fn), curdir, a); \
1049         adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1050         if (!a) \
1051                 WAITFILE2("vm-first"); \
1052         else if (a == lastmsg) \
1053                 WAITFILE2("vm-last"); \
1054         WAITFILE2("vm-message"); \
1055         if (a && (a != lastmsg)) { \
1056                 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1057                 if (d < 0) goto out; \
1058                 if (d) goto cmd; \
1059         } \
1060         make_file(fn, sizeof(fn), curdir, a); \
1061         heard[a] = 1; \
1062         WAITFILE(fn); \
1063 } while(0)
1064
1065 #define CLOSE_MAILBOX do { \
1066         if (lastmsg > -1) { \
1067                 /* Get the deleted messages fixed */ \
1068                 curmsg = -1; \
1069                 for (x=0;x<=lastmsg;x++) { \
1070                         if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1071                                 /* Save this message.  It's not in INBOX or hasn't been heard */ \
1072                                 curmsg++; \
1073                                 make_file(fn, sizeof(fn), curdir, x); \
1074                                 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1075                                 if (strcmp(fn, fn2)) { \
1076                                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1077                                         snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1078                                         ast_filerename(fn, fn2, NULL); \
1079                                         rename(txt, ntxt); \
1080                                 } \
1081                         } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1082                                 /* Move to old folder before deleting */ \
1083                                 save_to_folder(curdir, x, username, 1); \
1084                         } \
1085                 } \
1086                 for (x = curmsg + 1; x<=lastmsg; x++) { \
1087                         make_file(fn, sizeof(fn), curdir, x); \
1088                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1089                         ast_filedelete(fn, NULL); \
1090                         unlink(txt); \
1091                 } \
1092         } \
1093         memset(deleted, 0, sizeof(deleted)); \
1094         memset(heard, 0, sizeof(heard)); \
1095 } while(0)
1096
1097 #define OPEN_MAILBOX(a) do { \
1098         strcpy(curbox, mbox(a)); \
1099         make_dir(curdir, sizeof(curdir), username, curbox); \
1100         lastmsg = count_messages(curdir) - 1; \
1101         snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1102 } while (0)
1103
1104
1105 static int vm_execmain(struct ast_channel *chan, void *data)
1106 {
1107         /* XXX This is, admittedly, some pretty horrendus code.  For some
1108            reason it just seemed a lot easier to do with GOTO's.  I feel
1109            like I'm back in my GWBASIC days. XXX */
1110         int res=-1;
1111         int valid = 0;
1112         char d;
1113         struct localuser *u;
1114         char username[80];
1115         char password[80], *copy;
1116         char curbox[80];
1117         char curdir[256];
1118         char vmbox[256];
1119         char fn[256];
1120         char fn2[256];
1121         int x;
1122         char ntxt[256];
1123         char txt[256];
1124         int deleted[MAXMSG] = { 0, };
1125         int heard[MAXMSG] = { 0, };
1126         int newmessages;
1127         int oldmessages;
1128         int repeats = 0;
1129         int curmsg = 0;
1130         int lastmsg = 0;
1131         int starting = 1;
1132         int box;
1133         int useadsi = 0;
1134         struct ast_config *cfg;
1135         
1136         LOCAL_USER_ADD(u);
1137         cfg = ast_load(VOICEMAIL_CONFIG);
1138         if (!cfg) {
1139                 ast_log(LOG_WARNING, "No voicemail configuration\n");
1140                 goto out;
1141         }
1142         if (chan->state != AST_STATE_UP)
1143                 ast_answer(chan);
1144
1145         /* If ADSI is supported, setup login screen */
1146         adsi_begin(chan, &useadsi);
1147         if (useadsi)
1148                 adsi_login(chan);
1149         if (ast_streamfile(chan, "vm-login", chan->language)) {
1150                 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1151                 goto out;
1152         }
1153         
1154         /* Authenticate them and get their mailbox/password */
1155         
1156         do {
1157                 /* Prompt for, and read in the username */
1158                 if (ast_readstring(chan, username, sizeof(username), 2000, 10000, "#") < 0) {
1159                         ast_log(LOG_WARNING, "Couldn't read username\n");
1160                         goto out;
1161                 }                       
1162                 if (!strlen(username)) {
1163                         if (option_verbose > 2)
1164                                 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1165                         res = 0;
1166                         goto out;
1167                 }
1168                 if (useadsi)
1169                         adsi_password(chan);
1170                 if (ast_streamfile(chan, "vm-password", chan->language)) {
1171                         ast_log(LOG_WARNING, "Unable to stream password file\n");
1172                         goto out;
1173                 }
1174                 if (ast_readstring(chan, password, sizeof(password), 2000, 10000, "#") < 0) {
1175                         ast_log(LOG_WARNING, "Unable to read password\n");
1176                         goto out;
1177                 }
1178                 copy = ast_variable_retrieve(cfg, NULL, username);
1179                 if (copy) {
1180                         copy = strdup(copy);
1181                         strtok(copy, ",");
1182                         if (!strcmp(password,copy))
1183                                 valid++;
1184                         else if (option_verbose > 2)
1185                                 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1186                         free(copy);
1187                 } else if (option_verbose > 2)
1188                         ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1189                 if (!valid) {
1190                         if (useadsi)
1191                                 adsi_login(chan);
1192                         if (ast_streamfile(chan, "vm-incorrect", chan->language))
1193                                 break;
1194 #if 0
1195                         if (ast_waitstream(chan, ""))
1196                                 break;
1197 #endif
1198                 }
1199         } while (!valid);
1200
1201         if (valid) {
1202                 OPEN_MAILBOX(1);
1203                 oldmessages = lastmsg + 1;
1204                 /* Start in INBOX */
1205                 OPEN_MAILBOX(0);
1206                 newmessages = lastmsg + 1;
1207                 
1208
1209                 /* Select proper mailbox FIRST!! */
1210                 if (!newmessages && oldmessages) {
1211                         /* If we only have old messages start here */
1212                         OPEN_MAILBOX(1);
1213                 }
1214
1215                 if (useadsi)
1216                         adsi_status(chan, newmessages, oldmessages, lastmsg);
1217
1218                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1219                 if (newmessages) {
1220                         WAITCMD(say_and_wait(chan, newmessages));
1221                         WAITCMD(play_and_wait(chan, "vm-INBOX"));
1222                         if (oldmessages)
1223                                 WAITCMD(play_and_wait(chan, "vm-and"));
1224                         else {
1225                                 if (newmessages == 1)
1226                                         WAITCMD(play_and_wait(chan, "vm-message"));
1227                                 else
1228                                         WAITCMD(play_and_wait(chan, "vm-messages"));
1229                         }
1230                                 
1231                 }
1232                 if (oldmessages) {
1233                         WAITCMD(say_and_wait(chan, oldmessages));
1234                         WAITCMD(play_and_wait(chan, "vm-Old"));
1235                         if (oldmessages == 1)
1236                                 WAITCMD(play_and_wait(chan, "vm-message"));
1237                         else
1238                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1239                 }
1240                 if (!oldmessages && !newmessages) {
1241                         WAITCMD(play_and_wait(chan, "vm-no"));
1242                         WAITCMD(play_and_wait(chan, "vm-messages"));
1243                 }
1244                 repeats = 0;
1245                 starting = 1;
1246 instructions:
1247                 if (starting) {
1248                         if (lastmsg > -1) {
1249                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
1250                                 WAITCMD(play_and_wait(chan, vmbox));
1251                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1252                         }
1253                         WAITCMD(play_and_wait(chan, "vm-opts"));
1254                 } else {
1255                         if (curmsg)
1256                                 WAITCMD(play_and_wait(chan, "vm-prev"));
1257                         WAITCMD(play_and_wait(chan, "vm-repeat"));
1258                         if (curmsg != lastmsg)
1259                                 WAITCMD(play_and_wait(chan, "vm-next"));
1260                         if (!deleted[curmsg])
1261                                 WAITCMD(play_and_wait(chan, "vm-delete"));
1262                         else
1263                                 WAITCMD(play_and_wait(chan, "vm-undelete"));
1264                         WAITCMD(play_and_wait(chan, "vm-toforward"));
1265                         WAITCMD(play_and_wait(chan, "vm-savemessage"));
1266                 }
1267                 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1268                 d = ast_waitfordigit(chan, 6000);
1269                 if (d < 0)
1270                         goto out;
1271                 if (!d) {
1272                         repeats++;
1273                         if (repeats > 2) {
1274                                 play_and_wait(chan, "vm-goodbye");
1275                                 goto out;
1276                         }
1277                         goto instructions;
1278                 }
1279 cmd:
1280                 switch(d) {
1281                 case '2':
1282                         if (useadsi)
1283                                 adsi_folders(chan, 0, "Change to folder...");
1284                         box = play_and_wait(chan, "vm-changeto");
1285                         if (box < 0)
1286                                 goto out;
1287                         while((box < '0') || (box > '9')) {
1288                                 box = get_folder(chan, 0);
1289                                 if (box < 0)
1290                                         goto out;
1291                                 if (box == '#')
1292                                         goto instructions;
1293                         } 
1294                         box = box - '0';
1295                         CLOSE_MAILBOX;
1296                         OPEN_MAILBOX(box);
1297                         if (useadsi)
1298                                 adsi_status2(chan, curbox, lastmsg + 1);
1299                         WAITCMD(play_and_wait(chan, vmbox));
1300                         WAITCMD(play_and_wait(chan, "vm-messages"));
1301                         starting = 1;
1302                         goto instructions;
1303                 case '4':
1304                         if (curmsg) {
1305                                 curmsg--;
1306                                 PLAYMSG(curmsg);
1307                         } else {
1308                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1309                                 goto instructions;
1310                         }
1311                 case '1':
1312                                 curmsg = 0;
1313                                 /* Fall through */
1314                 case '5':
1315                         if (lastmsg > -1) {
1316                                 PLAYMSG(curmsg);
1317                         } else {
1318                                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1319                                 WAITCMD(play_and_wait(chan, "vm-no"));
1320                                 snprintf(fn, sizeof(fn), "vm-%s", curbox);
1321                                 WAITCMD(play_and_wait(chan, fn));
1322                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1323                                 goto instructions;
1324                         }
1325                 case '6':
1326                         if (curmsg < lastmsg) {
1327                                 curmsg++;
1328                                 PLAYMSG(curmsg);
1329                         } else {
1330                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1331                                 goto instructions;
1332                         }
1333                 case '7':
1334                         deleted[curmsg] = !deleted[curmsg];
1335                         if (useadsi)
1336                                 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
1337                         if (deleted[curmsg]) 
1338                                 WAITCMD(play_and_wait(chan, "vm-deleted"));
1339                         else
1340                                 WAITCMD(play_and_wait(chan, "vm-undeleted"));
1341                         goto instructions;
1342                 case '9':
1343                         if (useadsi)
1344                                 adsi_folders(chan, 1, "Save to folder...");
1345                         box = play_and_wait(chan, "vm-savefolder");
1346                         if (box < 0)
1347                                 goto out;
1348                         while((box < '1') || (box > '9')) {
1349                                 box = get_folder(chan, 1);
1350                                 if (box < 0)
1351                                         goto out;
1352                                 if (box == '#')
1353                                         goto instructions;
1354                         } 
1355                         box = box - '0';
1356                         if (option_debug)
1357                                 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
1358                         if (save_to_folder(curdir, curmsg, username, box))
1359                                 goto out;
1360                         deleted[curmsg]=1;
1361                         make_file(fn, sizeof(fn), curdir, curmsg);
1362                         if (useadsi)
1363                                 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
1364                         WAITCMD(play_and_wait(chan, "vm-message"));
1365                         WAITCMD(say_and_wait(chan, curmsg + 1) );
1366                         WAITCMD(play_and_wait(chan, "vm-savedto"));
1367                         snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
1368                         WAITCMD(play_and_wait(chan, fn));
1369                         WAITCMD(play_and_wait(chan, "vm-messages"));
1370                         goto instructions;
1371                 case '*':
1372                         if (!starting) {
1373                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
1374                                 WAITCMD(play_and_wait(chan, vmbox));
1375                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1376                                 WAITCMD(play_and_wait(chan, "vm-opts"));
1377                         }
1378                         goto instructions;
1379                 case '#':
1380                         ast_stopstream(chan);
1381                         adsi_goodbye(chan);
1382                         play_and_wait(chan, "vm-goodbye");
1383                         res = 0;
1384                         goto out2;
1385                 default:
1386                         goto instructions;
1387                 }
1388         }
1389 out:
1390         adsi_goodbye(chan);
1391 out2:
1392         CLOSE_MAILBOX;
1393         ast_stopstream(chan);
1394         if (cfg)
1395                 ast_destroy(cfg);
1396         if (useadsi)
1397                 adsi_unload_session(chan);
1398         adsi_channel_init(chan);
1399         LOCAL_USER_REMOVE(u);
1400         return res;
1401 }
1402
1403 static int vm_exec(struct ast_channel *chan, void *data)
1404 {
1405         int res=0, silent=0, busy=0, unavail=0;
1406         struct localuser *u;
1407         char *ext = (char *)data;
1408         
1409         if (!data) {
1410                 ast_log(LOG_WARNING, "vm requires an argument (extension)\n");
1411                 return -1;
1412         }
1413         LOCAL_USER_ADD(u);
1414         if (*ext == 's') {
1415                 silent++;
1416                 ext++;
1417         } else if (*ext == 'b') {
1418                 busy++;
1419                 ext++;
1420         } else if (*ext == 'u') {
1421                 unavail++;
1422                 ext++;
1423         }
1424         if (chan->state != AST_STATE_UP)
1425                 ast_answer(chan);
1426         res = leave_voicemail(chan, ext, silent, busy, unavail);
1427         LOCAL_USER_REMOVE(u);
1428         return res;
1429 }
1430
1431 int unload_module(void)
1432 {
1433         int res;
1434         STANDARD_HANGUP_LOCALUSERS;
1435         res = ast_unregister_application(app);
1436         res |= ast_unregister_application(app2);
1437         return res;
1438 }
1439
1440 int load_module(void)
1441 {
1442         int res;
1443         res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
1444         if (!res)
1445                 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
1446         return res;
1447 }
1448
1449 char *description(void)
1450 {
1451         return tdesc;
1452 }
1453
1454 int usecount(void)
1455 {
1456         int res;
1457         STANDARD_USECOUNT(res);
1458         return res;
1459 }
1460
1461 char *key()
1462 {
1463         return ASTERISK_GPL_KEY;
1464 }