3ea6cff461fba90f5e0b5072a29ea9392be2ad2c
[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/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/options.h>
20 #include <asterisk/config.h>
21 #include <asterisk/say.h>
22 #include <asterisk/module.h>
23 #include <asterisk/adsi.h>
24 #include <asterisk/app.h>
25 #include <asterisk/manager.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/stat.h>
34 #include <time.h>
35
36 #include <pthread.h>
37 #include "../asterisk.h"
38 #include "../astconf.h"
39
40 #define COMMAND_TIMEOUT 5000
41
42 #define VOICEMAIL_CONFIG "voicemail.conf"
43 #define ASTERISK_USERNAME "asterisk"
44
45 #define SENDMAIL "/usr/sbin/sendmail -t"
46
47 #define INTRO "vm-intro"
48
49 #define MAXMSG 100
50
51 #define MAX_OTHER_FORMATS 10
52
53 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
54
55 #define BASEMAXINLINE 256
56
57 #define BASELINELEN 72
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62
63 #define BASEMAXINLINE 256
64 #define BASELINELEN 72
65 #define eol "\r\n"
66
67 int iocp;
68 int iolen;
69 int linelength;
70 int ateof;
71 unsigned char iobuf[BASEMAXINLINE];
72
73 static char *tdesc = "Comedian Mail (Voicemail System)";
74
75 static char *adapp = "CoMa";
76
77 static char *adsec = "_AST";
78
79 static char *addesc = "Comedian Mail";
80
81 static int adver = 1;
82
83 static char *synopsis_vm =
84 "Leave a voicemail message";
85
86 static char *descrip_vm =
87 "  VoiceMail([s|u|b]extension): Leaves voicemail for a given  extension (must\n"
88 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
89 "then instructions for leaving the message will be skipped.  If the extension\n"
90 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
91 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.  If the extension\n"
92 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
93 "busy instead of unavail).  At most one of 's', 'u', or 'b' may be specified.\n"
94 "Returns  -1 on  error or mailbox not found, or if the user hangs up. \n"
95 "Otherwise, it returns 0. \n";
96
97 static char *synopsis_vmain =
98 "Enter voicemail system";
99
100 static char *descrip_vmain =
101 "  VoiceMailMain(): Enters the main voicemail system for the checking of voicemail.  The mailbox\n"
102 "can be passed as the option, which will stop the voicemail system from prompting the user\n"
103 "for the mailbox.  If the mailbox is preceeded by 's' then the passsword check will be skipped.\n"
104 "Returns -1 if the user hangs up or 0 otherwise.\n";
105
106 /* Leave a message */
107 static char *app = "VoiceMail";
108
109 /* Check mail, control, etc */
110 static char *app2 = "VoiceMailMain";
111
112 STANDARD_LOCAL_USER;
113
114 LOCAL_USER_DECL;
115
116 static int make_dir(char *dest, int len, char *ext, char *mailbox)
117 {
118         return snprintf(dest, len, "%s/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", ext, mailbox);
119 }
120
121 static int make_file(char *dest, int len, char *dir, int num)
122 {
123         return snprintf(dest, len, "%s/msg%04d", dir, num);
124 }
125
126 static int vm_change_password(char *username, char *password, char *newpassword)
127 {
128         /*  There's probably a better way of doing this. */
129         /*  That's why I've put the password change in a separate function. */
130
131         FILE *configin;
132         FILE *configout;
133                 char inbuf[256];
134                 char orig[256];
135                 char tmpin[AST_CONFIG_MAX_PATH];
136                 char tmpout[AST_CONFIG_MAX_PATH];
137                 char *user, *pass, *rest, *trim;
138         snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
139         snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
140         configin = fopen((char *)tmpin,"r");
141         configout = fopen((char *)tmpout,"w+");
142
143         while (!feof(configin)) {
144                         /* Read in the line */
145                         fgets(inbuf, sizeof(inbuf), configin);
146                         if (!feof(configin)) {
147                                 /* Make a backup of it */
148                                 memcpy(orig, inbuf, sizeof(orig));
149                                 /* Strip trailing \n and comment */
150                                 inbuf[strlen(inbuf) - 1] = '\0';
151                                 user = strchr(inbuf, ';');
152                                 if (user)
153                                         *user = '\0';
154                                 user=inbuf;
155                                 while(*user < 33)
156                                         user++;
157                                 pass = strchr(user, '=');
158                                 if (pass > user) {
159                                         trim = pass - 1;
160                                         while(*trim && *trim < 33) {
161                                                 *trim = '\0';
162                                                 trim--;
163                                         }
164                                 }
165                                 if (pass) {
166                                         *pass = '\0';
167                                         pass++;
168                                         if (*pass == '>')
169                                                 pass++;
170                                         while(*pass && *pass < 33)
171                                                 pass++;
172                                 }
173                                 if (pass) {
174                                         rest = strchr(pass,',');
175                                         if (rest) {
176                                                 *rest = '\0';
177                                                 rest++;
178                                         }
179                                 } else
180                                         rest = NULL;
181                                 if (user && pass && *user && *pass && !strcmp(user, username) && !strcmp(pass, password)) {
182                                         /* This is the line */
183                                         if (rest) {
184                                                 fprintf(configout, "%s => %s,%s\n", username,newpassword,rest);
185                                         } else {
186                                                 fprintf(configout, "%s => %s\n", username,newpassword);
187                                         }
188                                 } else {
189                                         /* Put it back like it was */
190                                         fprintf(configout, orig);
191                                 }
192                         }
193         }
194         fclose(configin);
195         fclose(configout);
196
197         unlink((char *)tmpin);
198         rename((char *)tmpout,(char *)tmpin);
199         return(1);
200 }
201
202 static int
203 inbuf(FILE *fi)
204 {
205         int l;
206
207         if(ateof)
208                 return 0;
209
210         if ( (l = fread(iobuf,1,BASEMAXINLINE,fi)) <= 0) {
211                 if(ferror(fi))
212                         return -1;
213
214                 ateof = 1;
215                 return 0;
216         }
217
218         iolen= l;
219         iocp= 0;
220
221         return 1;
222 }
223
224 static int 
225 inchar(FILE *fi)
226 {
227         if(iocp>=iolen)
228                 if(!inbuf(fi))
229                         return EOF;
230
231         return iobuf[iocp++];
232 }
233
234 static int
235 ochar(int c, FILE *so)
236 {
237         if(linelength>=BASELINELEN) {
238                 if(fputs(eol,so)==EOF)
239                         return -1;
240
241                 linelength= 0;
242         }
243
244         if(putc(((unsigned char)c),so)==EOF)
245                 return -1;
246
247         linelength++;
248
249         return 1;
250 }
251
252 static int base_encode(char *filename, FILE *so)
253 {
254         unsigned char dtable[BASEMAXINLINE];
255         int i,hiteof= 0;
256         FILE *fi;
257
258         linelength = 0;
259         iocp = BASEMAXINLINE;
260         iolen = 0;
261         ateof = 0;
262
263         if ( !(fi = fopen(filename, "rb"))) {
264                 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
265                 return -1;
266         }
267
268         for(i= 0;i<9;i++){
269                 dtable[i]= 'A'+i;
270                 dtable[i+9]= 'J'+i;
271                 dtable[26+i]= 'a'+i;
272                 dtable[26+i+9]= 'j'+i;
273         }
274         for(i= 0;i<8;i++){
275                 dtable[i+18]= 'S'+i;
276                 dtable[26+i+18]= 's'+i;
277         }
278         for(i= 0;i<10;i++){
279                 dtable[52+i]= '0'+i;
280         }
281         dtable[62]= '+';
282         dtable[63]= '/';
283
284         while(!hiteof){
285                 unsigned char igroup[3],ogroup[4];
286                 int c,n;
287
288                 igroup[0]= igroup[1]= igroup[2]= 0;
289
290                 for(n= 0;n<3;n++){
291                         if ( (c = inchar(fi)) == EOF) {
292                                 hiteof= 1;
293                                 break;
294                         }
295
296                         igroup[n]= (unsigned char)c;
297                 }
298
299                 if(n> 0){
300                         ogroup[0]= dtable[igroup[0]>>2];
301                         ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
302                         ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
303                         ogroup[3]= dtable[igroup[2]&0x3F];
304
305                         if(n<3) {
306                                 ogroup[3]= '=';
307
308                                 if(n<2)
309                                         ogroup[2]= '=';
310                         }
311
312                         for(i= 0;i<4;i++)
313                                 ochar(ogroup[i], so);
314                 }
315         }
316
317         if(fputs(eol,so)==EOF)
318                 return 0;
319
320         fclose(fi);
321
322         return 1;
323 }
324
325 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
326 {
327         FILE *p;
328         char date[256];
329         char host[256];
330         char who[256];
331         char bound[256];
332         char fname[256];
333         char dur[256];
334         time_t t;
335         struct tm *tm;
336         char *astattach;
337         struct ast_config *cfg;
338         p = popen(SENDMAIL, "w");
339         cfg = ast_load(VOICEMAIL_CONFIG);
340         if (!(astattach = ast_variable_retrieve(cfg, "general", "attach"))) 
341                 astattach = "yes";
342         if (p) {
343                 gethostname(host, sizeof(host));
344                 if (strchr(srcemail, '@'))
345                         strncpy(who, srcemail, sizeof(who)-1);
346                 else {
347                         snprintf(who, sizeof(who), "%s@%s", srcemail, host);
348                 }
349                 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
350                 time(&t);
351                 tm = localtime(&t);
352                 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", tm);
353                 fprintf(p, "Date: %s\n", date);
354                 fprintf(p, "From: Asterisk PBX <%s>\n", who);
355                 fprintf(p, "To: %s <%s>\n", name, email);
356                 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
357                 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
358                 fprintf(p, "MIME-Version: 1.0\n");
359                 if (ast_true(astattach)) {
360                         // Something unique.
361                         snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
362
363                         fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
364
365                         fprintf(p, "--%s\n", bound);
366                 }
367                         fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
368                         strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm);
369                         fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
370
371                            "in mailbox %s from %s, on %s so you might\n"
372                                    "want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", name, 
373                                 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
374                 if (ast_true(astattach)) {
375                         fprintf(p, "--%s\n", bound);
376                         fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
377                         fprintf(p, "Content-Transfer-Encoding: BASE64\n");
378                         fprintf(p, "Content-Description: Voicemail sound attachment.\n");
379                         fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
380
381                         snprintf(fname, sizeof(fname), "%s.%s", attach, format);
382                         base_encode(fname, p);
383                         fprintf(p, "\n\n--%s--\n.\n", bound);
384                 }
385                 pclose(p);
386         } else {
387                 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
388                 return -1;
389         }
390         return 0;
391 }
392
393 static int get_date(char *s, int len)
394 {
395         struct tm *tm;
396         time_t t;
397         t = time(0);
398         tm = localtime(&t);
399         return strftime(s, len, "%a %b %e %r %Z %Y", tm);
400 }
401
402 static int invent_message(struct ast_channel *chan, char *ext, int busy, char *ecodes)
403 {
404         int res;
405         char fn[256];
406         snprintf(fn, sizeof(fn), "vm/%s/greet", ext);
407         if (ast_fileexists(fn, NULL, NULL) > 0) {
408                 res = ast_streamfile(chan, fn, chan->language);
409                 if (res)
410                         return -1;
411                 res = ast_waitstream(chan, ecodes);
412                 if (res)
413                         return res;
414         } else {
415                 res = ast_streamfile(chan, "vm-theperson", chan->language);
416                 if (res)
417                         return -1;
418                 res = ast_waitstream(chan, ecodes);
419                 if (res)
420                         return res;
421                 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
422                 if (res)
423                         return res;
424         }
425         if (busy)
426                 res = ast_streamfile(chan, "vm-isonphone", chan->language);
427         else
428                 res = ast_streamfile(chan, "vm-isunavail", chan->language);
429         if (res)
430                 return -1;
431         res = ast_waitstream(chan, ecodes);
432         return res;
433 }
434
435 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
436 {
437         struct ast_config *cfg;
438         char *copy, *name, *passwd, *email, *fmt, *fmts;
439         char comment[256];
440         struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS];
441         char *sfmt[MAX_OTHER_FORMATS];
442         char txtfile[256];
443         FILE *txt;
444         int res = -1, fmtcnt=0, x;
445         int msgnum;
446         int outmsg=0;
447         int wavother=0;
448         int maxmessage=0;
449         struct ast_frame *f;
450         char date[256];
451         char dir[256];
452         char fn[256];
453         char prefile[256]="";
454         char *astemail;
455         char *ecodes = "#";
456         char *s;
457         time_t start;
458         time_t end;
459
460         cfg = ast_load(VOICEMAIL_CONFIG);
461         if (!cfg) {
462                 ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG);
463                 return -1;
464         }
465         if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) 
466                 astemail = ASTERISK_USERNAME;
467         if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
468                 if (sscanf(s, "%d", &x) == 1) {
469                         maxmessage = x;
470                 } else {
471                         ast_log(LOG_WARNING, "Invalid max message time length\n");
472                 }
473         }
474         if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
475                 char *stringp=NULL;
476                 /* Setup pre-file if appropriate */
477                 if (busy)
478                         snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
479                 else if (unavail)
480                         snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
481                 /* Make sure they have an entry in the config */
482                 copy = strdup(copy);
483                 stringp=copy;
484                 passwd = strsep(&stringp, ",");
485                 name = strsep(&stringp, ",");
486                 email = strsep(&stringp, ",");
487                 make_dir(dir, sizeof(dir), ext, "");
488                 /* It's easier just to try to make it than to check for its existence */
489                 if (mkdir(dir, 0700) && (errno != EEXIST))
490                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
491                 make_dir(dir, sizeof(dir), ext, "INBOX");
492                 if (mkdir(dir, 0700) && (errno != EEXIST))
493                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
494                 if (ast_exists_extension(chan, chan->context, "o", 1, chan->callerid))
495                         ecodes = "#0";
496                 /* Play the beginning intro if desired */
497                 if (strlen(prefile)) {
498                         if (ast_fileexists(prefile, NULL, NULL) > 0) {
499                                 if (ast_streamfile(chan, prefile, chan->language) > -1) 
500                                     silent = ast_waitstream(chan, "#0");
501                         } else {
502                                 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
503                                 silent = invent_message(chan, ext, busy, ecodes);
504                         }
505                         if (silent < 0) {
506                                 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
507                                 free(copy);
508                                 return -1;
509                         }
510                 }
511                 /* If they hit "#" we should still play the beep sound */
512                 if (silent == '#') {
513                         if (!ast_streamfile(chan, "beep", chan->language) < 0)
514                                 silent = 1;
515                         if (ast_waitstream(chan, "") <0) {
516                                 ast_log(LOG_DEBUG, "Hangup during beep\n");
517                                 free(copy);
518                                 return -1;
519                         }
520                 } else if (silent == '0') {
521                         strncpy(chan->exten, "0", sizeof(chan->exten) - 1);
522                         chan->priority = 0;
523                         free(copy);
524                         return 0;
525                 }
526                 /* Stream an info message */
527                 if (silent || !ast_streamfile(chan, INTRO, chan->language)) {
528                         /* Wait for the message to finish */
529                         if (silent || !ast_waitstream(chan, "")) {
530                                 if (!ast_streamfile(chan, "beep", chan->language) < 0)
531                                         silent = 1;
532                                 if (ast_waitstream(chan, "") <0) {
533                                         ast_log(LOG_DEBUG, "Hangup during beep\n");
534                                         free(copy);
535                                         return -1;
536                                 }
537                                 fmt = ast_variable_retrieve(cfg, "general", "format");
538                                 if (fmt) {
539                                         char *stringp=NULL;
540                                         fmts = strdup(fmt);
541                                         stringp=fmts;
542                                         fmt = strsep(&stringp, "|");
543                                         msgnum = 0;
544                                         do {
545                                                 make_file(fn, sizeof(fn), dir, msgnum);
546                                                 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
547                                                                                         (chan->callerid ? chan->callerid : "Unknown"), 
548                                                                                         name, ext, chan->name);
549                                                 if (ast_fileexists(fn, NULL, chan->language) > 0) {
550                                                         msgnum++;
551                                                         continue;
552                                                 }
553                                                 writer = ast_writefile(fn, fmt, comment, O_EXCL, 1 /* check for other formats */, 0700);
554                                                 if (!writer)
555                                                         break;
556                                                 msgnum++;
557                                         } while(!writer && (msgnum < MAXMSG));
558                                         if (writer) {
559                                                 char *stringp=NULL;
560                                                 /* Store information */
561                                                 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
562                                                 txt = fopen(txtfile, "w+");
563                                                 if (txt) {
564                                                         get_date(date, sizeof(date));
565                                                         time(&start);
566                                                         fprintf(txt, 
567 "#\n"
568 "# Message Information file\n"
569 "#\n"
570 "origmailbox=%s\n"
571 "context=%s\n"
572 "exten=%s\n"
573 "priority=%d\n"
574 "callerchan=%s\n"
575 "callerid=%s\n"
576 "origdate=%s\n"
577 "origtime=%ld\n",
578         ext,
579         chan->context,
580         chan->exten,
581         chan->priority,
582         chan->name,
583         chan->callerid ? chan->callerid : "Unknown",
584         date, time(NULL));
585                                                         fclose(txt);
586                                                 } else
587                                                         ast_log(LOG_WARNING, "Error opening text file for output\n");
588         
589                                                 /* We need to reset these values */
590                                                 free(fmts);
591                                                 fmt = ast_variable_retrieve(cfg, "general", "format");
592                                                 fmts = strdup(fmt);
593                                                 stringp=fmts;
594                                                 strsep(&stringp, "|");
595                                                 while((fmt = strsep(&stringp, "|"))) {
596                                                         if (fmtcnt > MAX_OTHER_FORMATS - 1) {
597                                                                 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
598                                                                 break;
599                                                         }
600                                                         sfmt[fmtcnt++] = strdup(fmt);
601                                                 }
602                                                 for (x=0;x<fmtcnt;x++) {
603                                                         others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
604                                                         if (!others[x]) {
605                                                                 /* Ick, the other format didn't work, but be sure not
606                                                                    to leak memory here */
607                                                                 int y;
608                                                                 for(y=x+1;y < fmtcnt;y++)
609                                                                         free(sfmt[y]);
610                                                                 break;
611                                                         }
612                                                         if(!strcasecmp(sfmt[x], "wav"))
613                                                                 wavother++;
614                                                         free(sfmt[x]);
615                                                 }
616                                                 if (x == fmtcnt) {
617                                                         /* Loop forever, writing the packets we read to the writer(s), until
618                                                            we read a # or get a hangup */
619                                                         if (option_verbose > 2) 
620                                                                 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
621                                                         f = NULL;
622                                                         for(;;) {
623                                                                 res = ast_waitfor(chan, 2000);
624                                                                 if (!res) {
625                                                                         ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
626                                                                         /* Try one more time in case of masq */
627                                                                         res = ast_waitfor(chan, 2000);
628                                                                         if (!res) {
629                                                                                 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
630                                                                                 res = -1;
631                                                                         }
632                                                                 }
633                                                                 
634                                                                 if (res < 0) {
635                                                                         f = NULL;
636                                                                         break;
637                                                                 }
638
639                                                                 f = ast_read(chan);
640                                                                 if (!f)
641                                                                         break;
642                                                                 if (f->frametype == AST_FRAME_VOICE) {
643                                                                         /* Write the primary format */
644                                                                         res = ast_writestream(writer, f);
645                                                                         if (res) {
646                                                                                 ast_log(LOG_WARNING, "Error writing primary frame\n");
647                                                                                 break;
648                                                                         }
649                                                                         /* And each of the others */
650                                                                         for (x=0;x<fmtcnt;x++) {
651                                                                                 res |= ast_writestream(others[x], f);
652                                                                         }
653                                                                         /* Exit on any error */
654                                                                         if (res) {
655                                                                                 ast_log(LOG_WARNING, "Error writing frame\n");
656                                                                                 ast_frfree(f);
657                                                                                 break;
658                                                                         }
659                                                                 } else if (f->frametype == AST_FRAME_DTMF) {
660                                                                         if (f->subclass == '#') {
661                                                                                 if (option_verbose > 2) 
662                                                                                         ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
663                                                                                 outmsg=2;
664                                                                                 ast_frfree(f);
665                                                                                 res = 0;
666                                                                                 break;
667                                                                         }
668                                                                 }
669                                                                 ast_frfree(f);
670                                                                 time(&end);
671                                                                 if (maxmessage && (end - start > maxmessage)) {
672                                                                         if (option_verbose > 2) 
673                                                                                 ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n");
674                                                                         outmsg = 2;
675                                                                         res = 0;
676                                                                         break;
677                                                                 }
678                                                         }
679                                                         if (!f) {
680                                                                 if (option_verbose > 2) 
681                                                                         ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
682                                                                 res = -1;
683                                                                 outmsg=1;
684                                                         }
685                                                 } else {
686                                                         ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]); 
687                                                         free(sfmt[x]);
688                                                 }
689
690                                                 ast_closestream(writer);
691                                                 for (x=0;x<fmtcnt;x++) {
692                                                         if (!others[x])
693                                                                 break;
694                                                         ast_closestream(others[x]);
695                                                 }
696                                                 if (outmsg) {
697                                                         if (outmsg > 1) {
698                                                                 /* Let them know it worked */
699                                                                 ast_streamfile(chan, "vm-msgsaved", chan->language);
700                                                                 ast_waitstream(chan, "");
701                                                         }
702                                                         txt = fopen(txtfile, "a");
703                                                         if (txt) {
704                                                                 time(&end);
705                                                                 fprintf(txt, "duration=%ld\n", end-start);
706                                                                 fclose(txt);
707                                                         }
708                                                         /* Send e-mail if applicable */
709                                                         if (email)
710                                                                 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start);
711                                                 }
712                                         } else {
713                                                 if (msgnum < MAXMSG)
714                                                         ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
715                                                 else
716                                                         ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
717                                         }
718                                         free(fmts);
719                                 } else 
720                                         ast_log(LOG_WARNING, "No format to save messages in \n");
721                         }
722                 } else
723                         ast_log(LOG_WARNING, "Unable to playback instructions\n");
724                         
725                 free(copy);
726         } else
727                 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
728         ast_destroy(cfg);
729         /* Leave voicemail for someone */
730         manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
731         return res;
732 }
733
734 static char *mbox(int id)
735 {
736         switch(id) {
737         case 0:
738                 return "INBOX";
739         case 1:
740                 return "Old";
741         case 2:
742                 return "Work";
743         case 3:
744                 return "Family";
745         case 4:
746                 return "Friends";
747         case 5:
748                 return "Cust1";
749         case 6:
750                 return "Cust2";
751         case 7:
752                 return "Cust3";
753         case 8:
754                 return "Cust4";
755         case 9:
756                 return "Cust5";
757         default:
758                 return "Unknown";
759         }
760 }
761
762 static int count_messages(char *dir)
763 {
764         int x;
765         char fn[256];
766         for (x=0;x<MAXMSG;x++) {
767                 make_file(fn, sizeof(fn), dir, x);
768                 if (ast_fileexists(fn, NULL, NULL) < 1)
769                         break;
770         }
771         return x;
772 }
773
774 static int play_and_wait(struct ast_channel *chan, char *fn)
775 {
776         int d;
777         d = ast_streamfile(chan, fn, chan->language);
778         if (d)
779                 return d;
780         d = ast_waitstream(chan, AST_DIGIT_ANY);
781         return d;
782 }
783
784 static int say_and_wait(struct ast_channel *chan, int num)
785 {
786         int d;
787         d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
788         return d;
789 }
790
791 static int copy(char *infile, char *outfile)
792 {
793         int ifd;
794         int ofd;
795         int res;
796         int len;
797         char buf[4096];
798         if ((ifd = open(infile, O_RDONLY)) < 0) {
799                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
800                 return -1;
801         }
802         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
803                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
804                 close(ifd);
805                 return -1;
806         }
807         do {
808                 len = read(ifd, buf, sizeof(buf));
809                 if (len < 0) {
810                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
811                         close(ifd);
812                         close(ofd);
813                         unlink(outfile);
814                 }
815                 if (len) {
816                         res = write(ofd, buf, len);
817                         if (res != len) {
818                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
819                                 close(ifd);
820                                 close(ofd);
821                                 unlink(outfile);
822                         }
823                 }
824         } while(len);
825         close(ifd);
826         close(ofd);
827         return 0;
828 }
829
830 static int save_to_folder(char *dir, int msg, char *username, int box)
831 {
832         char sfn[256];
833         char dfn[256];
834         char ddir[256];
835         char txt[256];
836         char ntxt[256];
837         char *dbox = mbox(box);
838         int x;
839         make_file(sfn, sizeof(sfn), dir, msg);
840         make_dir(ddir, sizeof(ddir), username, dbox);
841         mkdir(ddir, 0700);
842         for (x=0;x<MAXMSG;x++) {
843                 make_file(dfn, sizeof(dfn), ddir, x);
844                 if (ast_fileexists(dfn, NULL, NULL) < 0)
845                         break;
846         }
847         if (x >= MAXMSG)
848                 return -1;
849         ast_filecopy(sfn, dfn, NULL);
850         if (strcmp(sfn, dfn)) {
851                 snprintf(txt, sizeof(txt), "%s.txt", sfn);
852                 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
853                 copy(txt, ntxt);
854         }
855         return 0;
856 }
857
858 static int adsi_logo(unsigned char *buf)
859 {
860         int bytes = 0;
861         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
862         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
863         return bytes;
864 }
865
866 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
867 {
868         char buf[256];
869         int bytes=0;
870         int x;
871         char num[5];
872
873         *useadsi = 0;
874         bytes += adsi_data_mode(buf + bytes);
875         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
876
877         bytes = 0;
878         bytes += adsi_logo(buf);
879         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
880 #ifdef DISPLAY
881         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
882 #endif
883         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
884         bytes += adsi_data_mode(buf + bytes);
885         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
886
887         if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
888                 bytes = 0;
889                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
890                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
891                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
892                 bytes += adsi_voice_mode(buf + bytes, 0);
893                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
894                 return 0;
895         }
896
897 #ifdef DISPLAY
898         /* Add a dot */
899         bytes = 0;
900         bytes += adsi_logo(buf);
901         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
902         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
903         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
904         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
905 #endif
906         bytes = 0;
907         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
908         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
909         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
910         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
911         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
912         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
913         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
914
915 #ifdef DISPLAY
916         /* Add another dot */
917         bytes = 0;
918         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
919         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
920         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
921 #endif
922
923         bytes = 0;
924         /* These buttons we load but don't use yet */
925         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
926         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
927         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
928         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
929         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
930         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
931         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
932
933 #ifdef DISPLAY
934         /* Add another dot */
935         bytes = 0;
936         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
937         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
938         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
939 #endif
940
941         bytes = 0;
942         for (x=0;x<5;x++) {
943                 snprintf(num, sizeof(num), "%d", x);
944                 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
945         }
946         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
947         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
948
949 #ifdef DISPLAY
950         /* Add another dot */
951         bytes = 0;
952         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
953         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
954         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
955 #endif
956
957         if (adsi_end_download(chan)) {
958                 bytes = 0;
959                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
960                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
961                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
962                 bytes += adsi_voice_mode(buf + bytes, 0);
963                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
964                 return 0;
965         }
966         bytes = 0;
967         bytes += adsi_download_disconnect(buf + bytes);
968         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
969
970         ast_log(LOG_DEBUG, "Done downloading scripts...\n");
971
972 #ifdef DISPLAY
973         /* Add last dot */
974         bytes = 0;
975         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
976         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
977 #endif
978         ast_log(LOG_DEBUG, "Restarting session...\n");
979
980         bytes = 0;
981         /* Load the session now */
982         if (adsi_load_session(chan, adapp, adver, 1) == 1) {
983                 *useadsi = 1;
984                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
985         } else
986                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
987
988         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
989         return 0;
990 }
991
992 static void adsi_begin(struct ast_channel *chan, int *useadsi)
993 {
994         int x;
995         x = adsi_load_session(chan, adapp, adver, 1);
996         if (x < 0)
997                 return;
998         if (!x) {
999                 if (adsi_load_vmail(chan, useadsi)) {
1000                         ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1001                         return;
1002                 }
1003         } else
1004                 *useadsi = 1;
1005 }
1006
1007 static void adsi_login(struct ast_channel *chan)
1008 {
1009         char buf[256];
1010         int bytes=0;
1011         unsigned char keys[8];
1012         int x;
1013         if (!adsi_available(chan))
1014                 return;
1015
1016         for (x=0;x<8;x++)
1017                 keys[x] = 0;
1018         /* Set one key for next */
1019         keys[3] = ADSI_KEY_APPS + 3;
1020
1021         bytes += adsi_logo(buf + bytes);
1022         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1023         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1024         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1025         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1026         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1027         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1028         bytes += adsi_set_keys(buf + bytes, keys);
1029         bytes += adsi_voice_mode(buf + bytes, 0);
1030         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1031 }
1032
1033 static void adsi_password(struct ast_channel *chan)
1034 {
1035         char buf[256];
1036         int bytes=0;
1037         unsigned char keys[8];
1038         int x;
1039         if (!adsi_available(chan))
1040                 return;
1041
1042         for (x=0;x<8;x++)
1043                 keys[x] = 0;
1044         /* Set one key for next */
1045         keys[3] = ADSI_KEY_APPS + 3;
1046
1047         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1048         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1049         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1050         bytes += adsi_set_keys(buf + bytes, keys);
1051         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1052 }
1053
1054 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1055 {
1056         char buf[256];
1057         int bytes=0;
1058         unsigned char keys[8];
1059         int x,y;
1060
1061         if (!adsi_available(chan))
1062                 return;
1063
1064         for (x=0;x<5;x++) {
1065                 y = ADSI_KEY_APPS + 12 + start + x;
1066                 if (y > ADSI_KEY_APPS + 12 + 4)
1067                         y = 0;
1068                 keys[x] = ADSI_KEY_SKT | y;
1069         }
1070         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1071         keys[6] = 0;
1072         keys[7] = 0;
1073
1074         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1075         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1076         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1077         bytes += adsi_set_keys(buf + bytes, keys);
1078         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1079 }
1080
1081 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1082 {
1083         int bytes=0;
1084         char buf[256], buf1[256], buf2[256];
1085         char fn2[256];
1086         char cid[256]="";
1087         char *val;
1088         char *name, *num;
1089         char datetime[21]="";
1090         FILE *f;
1091
1092         unsigned char keys[8];
1093
1094         int x;
1095
1096         if (!adsi_available(chan))
1097                 return;
1098
1099         /* Retrieve important info */
1100         snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1101         f = fopen(fn2, "r");
1102         if (f) {
1103                 while(!feof(f)) {       
1104                         fgets(buf, sizeof(buf), f);
1105                         if (!feof(f)) {
1106                                 char *stringp=NULL;
1107                                 stringp=buf;
1108                                 strsep(&stringp, "=");
1109                                 val = strsep(&stringp, "=");
1110                                 if (val && strlen(val)) {
1111                                         if (!strcmp(buf, "callerid"))
1112                                                 strncpy(cid, val, sizeof(cid) - 1);
1113                                         if (!strcmp(buf, "origdate"))
1114                                                 strncpy(datetime, val, sizeof(datetime) - 1);
1115                                 }
1116                         }
1117                 }
1118                 fclose(f);
1119         }
1120         /* New meaning for keys */
1121         for (x=0;x<5;x++)
1122                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1123         keys[6] = 0x0;
1124         keys[7] = 0x0;
1125
1126         if (!msg) {
1127                 /* No prev key, provide "Folder" instead */
1128                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1129         }
1130         if (msg >= last) {
1131                 /* If last message ... */
1132                 if (msg) {
1133                         /* but not only message, provide "Folder" instead */
1134                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1135                 } else {
1136                         /* Otherwise if only message, leave blank */
1137                         keys[3] = 1;
1138                 }
1139         }
1140
1141         if (strlen(cid)) {
1142                 ast_callerid_parse(cid, &name, &num);
1143                 if (!name)
1144                         name = num;
1145         } else
1146                 name = "Unknown Caller";
1147
1148         /* If deleted, show "undeleted" */
1149         if (deleted)
1150                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1151
1152         /* Except "Exit" */
1153         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1154         snprintf(buf1, sizeof(buf1), "%s%s", folder,
1155                  strcasecmp(folder, "INBOX") ? " Messages" : "");
1156         snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1157
1158         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1159         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1160         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1161         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1162         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1163         bytes += adsi_set_keys(buf + bytes, keys);
1164         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1165 }
1166
1167 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1168 {
1169         int bytes=0;
1170         char buf[256];
1171         unsigned char keys[8];
1172
1173         int x;
1174
1175         if (!adsi_available(chan))
1176                 return;
1177
1178         /* New meaning for keys */
1179         for (x=0;x<5;x++)
1180                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1181
1182         keys[6] = 0x0;
1183         keys[7] = 0x0;
1184
1185         if (!msg) {
1186                 /* No prev key, provide "Folder" instead */
1187                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1188         }
1189         if (msg >= last) {
1190                 /* If last message ... */
1191                 if (msg) {
1192                         /* but not only message, provide "Folder" instead */
1193                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1194                 } else {
1195                         /* Otherwise if only message, leave blank */
1196                         keys[3] = 1;
1197                 }
1198         }
1199
1200         /* If deleted, show "undeleted" */
1201         if (deleted) 
1202                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1203
1204         /* Except "Exit" */
1205         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1206         bytes += adsi_set_keys(buf + bytes, keys);
1207         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1208 }
1209
1210 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1211 {
1212         char buf[256], buf1[256], buf2[256];
1213         int bytes=0;
1214         unsigned char keys[8];
1215         int x;
1216
1217         char *newm = (new == 1) ? "message" : "messages";
1218         char *oldm = (old == 1) ? "message" : "messages";
1219         if (!adsi_available(chan))
1220                 return;
1221         if (new) {
1222                 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1223                 if (old) {
1224                         strcat(buf1, " and");
1225                         snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1226                 } else {
1227                         snprintf(buf2, sizeof(buf2), "%s.", newm);
1228                 }
1229         } else if (old) {
1230                 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1231                 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1232         } else {
1233                 strcpy(buf1, "You have no messages.");
1234                 strcpy(buf2, " ");
1235         }
1236         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1237         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1238         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1239
1240         for (x=0;x<6;x++)
1241                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1242         keys[6] = 0;
1243         keys[7] = 0;
1244
1245         /* Don't let them listen if there are none */
1246         if (lastmsg < 0)
1247                 keys[0] = 1;
1248         bytes += adsi_set_keys(buf + bytes, keys);
1249
1250         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1251 }
1252
1253 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1254 {
1255         char buf[256], buf1[256], buf2[256];
1256         int bytes=0;
1257         unsigned char keys[8];
1258         int x;
1259
1260         char *mess = (messages == 1) ? "message" : "messages";
1261
1262         if (!adsi_available(chan))
1263                 return;
1264
1265         /* Original command keys */
1266         for (x=0;x<6;x++)
1267                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1268
1269         keys[6] = 0;
1270         keys[7] = 0;
1271
1272         if (messages < 1)
1273                 keys[0] = 0;
1274
1275         snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1276                         strcasecmp(folder, "INBOX") ? " folder" : "");
1277
1278         if (messages)
1279                 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1280         else
1281                 strcpy(buf2, "no messages.");
1282         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1283         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1284         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1285         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1286         bytes += adsi_set_keys(buf + bytes, keys);
1287
1288         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1289         
1290 }
1291
1292 static void adsi_clear(struct ast_channel *chan)
1293 {
1294         char buf[256];
1295         int bytes=0;
1296         if (!adsi_available(chan))
1297                 return;
1298         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1299         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1300 }
1301
1302 static void adsi_goodbye(struct ast_channel *chan)
1303 {
1304         char buf[256];
1305         int bytes=0;
1306         if (!adsi_available(chan))
1307                 return;
1308         bytes += adsi_logo(buf + bytes);
1309         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1310         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1311         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1312         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1313 }
1314
1315 static int get_folder(struct ast_channel *chan, int start)
1316 {
1317         int x;
1318         int d;
1319         char fn[256];
1320         d = play_and_wait(chan, "vm-press");
1321         if (d)
1322                 return d;
1323         for (x = start; x< 5; x++) {
1324                 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1325                         return d;
1326                 d = play_and_wait(chan, "vm-for");
1327                 if (d)
1328                         return d;
1329                 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1330                 d = play_and_wait(chan, fn);
1331                 if (d)
1332                         return d;
1333                 d = play_and_wait(chan, "vm-messages");
1334                 if (d)
1335                         return d;
1336                 d = ast_waitfordigit(chan, 500);
1337                 if (d)
1338                         return d;
1339         }
1340         d = play_and_wait(chan, "vm-tocancel");
1341         if (d)
1342                 return d;
1343         d = ast_waitfordigit(chan, 4000);
1344         return d;
1345 }
1346
1347 static int
1348 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg)
1349 {
1350         char username[70];
1351         char sys[256];
1352         char todir[256];
1353         int todircount=0;
1354
1355         while(1) {
1356                 ast_streamfile(chan, "vm-extension", chan->language);
1357
1358                 if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)
1359                         return 0;
1360                 if (ast_variable_retrieve(cfg, NULL, username)) {
1361                         printf("Got %d\n", atoi(username));
1362                         if (play_and_wait(chan, "vm-savedto"))
1363                                 break;
1364
1365                         snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX",  (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1366                         snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1367                         puts(sys);
1368                         system(sys);
1369
1370                         todircount = count_messages(todir);
1371
1372                         snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1373                         puts(sys);
1374                         system(sys);
1375
1376                         break;
1377                 } else {
1378                         if ( play_and_wait(chan, "pbx-invalid"))
1379                                 break;
1380                 }
1381         }
1382
1383         return 0;
1384 }
1385
1386 #define WAITCMD(a) do { \
1387         d = (a); \
1388         if (d < 0) \
1389                 goto out; \
1390         if (d) \
1391                 goto cmd; \
1392 } while(0)
1393
1394 #define WAITFILE2(file) do { \
1395         if (ast_streamfile(chan, file, chan->language)) \
1396                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1397         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1398         if (d < 0) { \
1399                 goto out; \
1400         }\
1401 } while(0)
1402
1403 #define WAITFILE(file) do { \
1404         if (ast_streamfile(chan, file, chan->language)) \
1405                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1406         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1407         if (!d) { \
1408                 repeats = 0; \
1409                 goto instructions; \
1410         } else if (d < 0) { \
1411                 goto out; \
1412         } else goto cmd;\
1413 } while(0)
1414
1415 #define PLAYMSG(a) do { \
1416         starting = 0; \
1417         make_file(fn, sizeof(fn), curdir, a); \
1418         adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1419         if (!a) \
1420                 WAITFILE2("vm-first"); \
1421         else if (a == lastmsg) \
1422                 WAITFILE2("vm-last"); \
1423         WAITFILE2("vm-message"); \
1424         if (a && (a != lastmsg)) { \
1425                 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1426                 if (d < 0) goto out; \
1427                 if (d) goto cmd; \
1428         } \
1429         make_file(fn, sizeof(fn), curdir, a); \
1430         heard[a] = 1; \
1431         WAITFILE(fn); \
1432 } while(0)
1433
1434 #define CLOSE_MAILBOX do { \
1435         if (lastmsg > -1) { \
1436                 /* Get the deleted messages fixed */ \
1437                 curmsg = -1; \
1438                 for (x=0;x<=lastmsg;x++) { \
1439                         if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1440                                 /* Save this message.  It's not in INBOX or hasn't been heard */ \
1441                                 curmsg++; \
1442                                 make_file(fn, sizeof(fn), curdir, x); \
1443                                 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1444                                 if (strcmp(fn, fn2)) { \
1445                                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1446                                         snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1447                                         ast_filerename(fn, fn2, NULL); \
1448                                         rename(txt, ntxt); \
1449                                 } \
1450                         } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1451                                 /* Move to old folder before deleting */ \
1452                                 save_to_folder(curdir, x, username, 1); \
1453                         } \
1454                 } \
1455                 for (x = curmsg + 1; x<=lastmsg; x++) { \
1456                         make_file(fn, sizeof(fn), curdir, x); \
1457                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1458                         ast_filedelete(fn, NULL); \
1459                         unlink(txt); \
1460                 } \
1461         } \
1462         memset(deleted, 0, sizeof(deleted)); \
1463         memset(heard, 0, sizeof(heard)); \
1464 } while(0)
1465
1466 #define OPEN_MAILBOX(a) do { \
1467         strcpy(curbox, mbox(a)); \
1468         make_dir(curdir, sizeof(curdir), username, curbox); \
1469         lastmsg = count_messages(curdir) - 1; \
1470         snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1471 } while (0)
1472
1473 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime)
1474 {
1475         char d, *fmt, *fmts;
1476         char comment[256];
1477         int x, fmtcnt=1, res=-1,outmsg=0, wavother=0;
1478         struct ast_frame *f;
1479         struct ast_config *cfg;
1480         struct ast_filestream *others[MAX_OTHER_FORMATS];
1481         char *sfmt[MAX_OTHER_FORMATS];
1482         char *stringp=NULL;
1483         time_t start, end;
1484         
1485         
1486         ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile);
1487         snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name);
1488         
1489         d = play_and_wait(chan, playfile);
1490         if (d < 0)
1491                 return -1;
1492         ast_streamfile(chan, "beep",chan->language);
1493         ast_waitstream(chan,"");
1494         cfg = ast_load(VOICEMAIL_CONFIG);
1495         
1496         fmt = ast_variable_retrieve(cfg, "general", "format");
1497         ast_log(LOG_DEBUG,"Recording Formats: fmt=%s\n", fmt);  
1498         
1499         fmts = strdup(fmt);
1500         
1501         ast_destroy(cfg);
1502
1503         stringp=fmts;
1504         strsep(&stringp, "|");
1505         ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);       
1506         sfmt[0] = strdup(fmts);
1507         
1508         while((fmt = strsep(&stringp, "|"))) {
1509                 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1510                         ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1511                         break;
1512                         }
1513                 sfmt[fmtcnt++] = strdup(fmt);
1514                 }
1515
1516         if (maxtime)
1517                 time(&start);
1518         for (x=0;x<fmtcnt;x++) {
1519                 others[x] = ast_writefile(recordfile, sfmt[x], comment, 0, 0, 0700);
1520                 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s\n", x, recordfile, sfmt[x]);
1521                         
1522                 if (!others[x]) {
1523                 /* Ick, the other format didn't work, but be sure not
1524                    to leak memory here */
1525                         int y;
1526                         for(y=x+1;y < fmtcnt;y++)
1527                         free(sfmt[y]);
1528                         break;
1529                         }
1530                 if(!strcasecmp(sfmt[x], "wav"))
1531                         wavother++;
1532                         free(sfmt[x]);
1533                         }
1534                 if (x == fmtcnt) {
1535                 /* Loop forever, writing the packets we read to the writer(s), until
1536                    we read a # or get a hangup */
1537                         f = NULL;
1538                         for(;;) {
1539                                 res = ast_waitfor(chan, 2000);
1540                                 if (!res) {
1541                                         ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1542                                         /* Try one more time in case of masq */
1543                                         res = ast_waitfor(chan, 2000);
1544                                         if (!res) {
1545                                                 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1546                                                 res = -1;
1547                                         }
1548                                 }
1549                                 
1550                                 if (res < 0) {
1551                                         f = NULL;
1552                                         break;
1553                                 }
1554
1555                                 f = ast_read(chan);
1556                                 if (!f)
1557                                         break;
1558                                 if (f->frametype == AST_FRAME_VOICE) {
1559                                         /* write each format */
1560                                         for (x=0;x<fmtcnt;x++) {
1561                                                 res = ast_writestream(others[x], f);
1562                                                 }
1563                                         /* Exit on any error */
1564                                         if (res) {
1565                                                 ast_log(LOG_WARNING, "Error writing frame\n");
1566                                                 ast_frfree(f);
1567                                                 break;
1568                                         }
1569                                 } else if (f->frametype == AST_FRAME_DTMF) {
1570                                         if (f->subclass == '#') {
1571                                                 if (option_verbose > 2) 
1572                                                         ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1573                                                 outmsg=2;
1574                                                 break;
1575                                         }
1576                                 }
1577                                 if (maxtime) {
1578                                         time(&end);
1579                                         if (maxtime < (end - start)) {
1580                                                 if (option_verbose > 2)
1581                                                         ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1582                                                 outmsg=2;
1583                                                 break;
1584                                         }
1585                                 }
1586                                 ast_frfree(f);
1587                         }
1588                         if (!f) {
1589                                 if (option_verbose > 2) 
1590                                         ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1591                                 res = -1;
1592                                 outmsg=1;
1593                                 }
1594                         } else {
1595                                 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]); 
1596                                 free(sfmt[x]);
1597                                 }
1598
1599                         for (x=0;x<fmtcnt;x++) {
1600                                 if (!others[x])
1601                                         break;
1602                                 ast_closestream(others[x]);
1603                                 }
1604                         if (outmsg) {
1605                                 if (outmsg > 1) {
1606                                 /* Let them know it worked */
1607                                         ast_streamfile(chan, "vm-msgsaved", chan->language);
1608                                         ast_waitstream(chan, "");
1609                                 }
1610                 }       
1611
1612         
1613         return 0;
1614 }
1615
1616
1617
1618
1619 static int vm_execmain(struct ast_channel *chan, void *data)
1620 {
1621         /* XXX This is, admittedly, some pretty horrendus code.  For some
1622            reason it just seemed a lot easier to do with GOTO's.  I feel
1623            like I'm back in my GWBASIC days. XXX */
1624         int res=-1;
1625         int valid = 0;
1626         int prefix = 0;
1627         char d;
1628         struct localuser *u;
1629         char username[80] ="";
1630         char prefixstr[80] ="";
1631         char empty[80] = "";
1632         char password[80] = "", *copy;
1633         char newpassword[80] = "";
1634         char newpassword2[80] = "";
1635         char curbox[80] = "";
1636         char curdir[256] = "";
1637         char vmbox[256] = "";
1638         char fn[256] = "";
1639         char fn2[256] = "";
1640         char prefile[256]="";
1641         int x;
1642         char ntxt[256] = "";
1643         char txt[256] = "";
1644         int deleted[MAXMSG] = { 0, };
1645         int heard[MAXMSG] = { 0, };
1646         int newmessages;
1647         int oldmessages;
1648         int repeats = 0;
1649         int curmsg = 0;
1650         int lastmsg = 0;
1651         int starting = 1;
1652         int box;
1653         int useadsi = 0;
1654         int skipuser = 0;
1655         char *s;
1656         int maxgreet = 0;
1657         char tmp[256], *ext;
1658         struct ast_config *cfg;
1659
1660         LOCAL_USER_ADD(u);
1661         cfg = ast_load(VOICEMAIL_CONFIG);
1662         if (!cfg) {
1663                 ast_log(LOG_WARNING, "No voicemail configuration\n");
1664                 goto out;
1665         }
1666         if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1667                 if (sscanf(s, "%d", &x) == 1) {
1668                         maxgreet = x;
1669                 } else {
1670                         ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1671                 }
1672         }
1673         if (chan->_state != AST_STATE_UP)
1674                 ast_answer(chan);
1675
1676         if (strlen(data)) {
1677                 strncpy(tmp, data, sizeof(tmp) - 1);
1678                 ext = tmp;
1679
1680                 switch (*ext) {
1681                         case 's':
1682                  /* We should skip the user's password */
1683                                 valid++;
1684                                 ext++;
1685                                 break;
1686                         case 'p':
1687                  /* We should prefix the mailbox with the supplied data */
1688                                 prefix++;
1689                                 ext++;
1690                                 break;
1691                 }
1692
1693
1694                 if (prefix)
1695                         strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1696                 else
1697                         strncpy(username, ext, sizeof(username) - 1);
1698                 /* make sure username passed as an option is valid */
1699                 if (ast_variable_retrieve(cfg, NULL, username)) 
1700                         skipuser++;
1701                 else
1702                         valid = 0;
1703
1704         }
1705
1706         /* If ADSI is supported, setup login screen */
1707         adsi_begin(chan, &useadsi);
1708         if (!skipuser && useadsi)
1709                 adsi_login(chan);
1710         if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1711                 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1712                 goto out;
1713         }
1714         
1715         /* Authenticate them and get their mailbox/password */
1716         
1717         while (!valid) {
1718                 /* Prompt for, and read in the username */
1719                 if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) {
1720                         ast_log(LOG_WARNING, "Couldn't read username\n");
1721                         goto out;
1722                 }
1723                 if (!strlen(username)) {
1724                         if (option_verbose > 2)
1725                                 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1726                         res = 0;
1727                         goto out;
1728                 }
1729                 if (useadsi)
1730                         adsi_password(chan);
1731                 if (ast_streamfile(chan, "vm-password", chan->language)) {
1732                         ast_log(LOG_WARNING, "Unable to stream password file\n");
1733                         goto out;
1734                 }
1735                 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1736                         ast_log(LOG_WARNING, "Unable to read password\n");
1737                         goto out;
1738                 }
1739                 if (prefix) {
1740                         char fullusername[80] = "";
1741                         strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1742                         strncat(fullusername, username, sizeof(fullusername) - 1);
1743                         strncpy(username, fullusername, sizeof(username) - 1);
1744                 }
1745                 copy = ast_variable_retrieve(cfg, NULL, username);
1746                 if (copy) {
1747                         char *stringp=NULL;
1748                         copy = strdup(copy);
1749                         stringp=copy;
1750                         strsep(&stringp, ",");
1751                         if (!strcmp(password,copy))
1752                                 valid++;
1753                         else {
1754                                 if (option_verbose > 2)
1755                                         ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1756                                 if (prefix)
1757                                         strncpy(username, empty, sizeof(username) -1);
1758                         }
1759                         free(copy);
1760                 } else {
1761                         skipuser = 0;
1762                         if (option_verbose > 2)
1763                                 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1764                 }
1765                 if (!valid) {
1766                         if (useadsi)
1767                                 adsi_login(chan);
1768                         if (ast_streamfile(chan, "vm-incorrect", chan->language))
1769                                 break;
1770 #if 0
1771                         if (ast_waitstream(chan, ""))
1772                                 break;
1773 #endif
1774                 }
1775         }
1776
1777         if (valid) {
1778                 snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1779                 mkdir(curdir, 0700);
1780                 OPEN_MAILBOX(1);
1781                 oldmessages = lastmsg + 1;
1782                 /* Start in INBOX */
1783                 OPEN_MAILBOX(0);
1784                 newmessages = lastmsg + 1;
1785                 
1786
1787                 /* Select proper mailbox FIRST!! */
1788                 if (!newmessages && oldmessages) {
1789                         /* If we only have old messages start here */
1790                         OPEN_MAILBOX(1);
1791                 }
1792
1793                 if (useadsi)
1794                         adsi_status(chan, newmessages, oldmessages, lastmsg);
1795
1796                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1797                 if (newmessages) {
1798                         WAITCMD(say_and_wait(chan, newmessages));
1799                         WAITCMD(play_and_wait(chan, "vm-INBOX"));
1800
1801                         if (oldmessages)
1802                                 WAITCMD(play_and_wait(chan, "vm-and"));
1803                         else {
1804                                 if (newmessages == 1)
1805                                         WAITCMD(play_and_wait(chan, "vm-message"));
1806                                 else
1807                                         WAITCMD(play_and_wait(chan, "vm-messages"));
1808                         }
1809                                 
1810                 }
1811                 if (oldmessages) {
1812                         WAITCMD(say_and_wait(chan, oldmessages));
1813                         WAITCMD(play_and_wait(chan, "vm-Old"));
1814                         if (oldmessages == 1)
1815                                 WAITCMD(play_and_wait(chan, "vm-message"));
1816                         else
1817                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1818                 }
1819                 if (!oldmessages && !newmessages) {
1820                         WAITCMD(play_and_wait(chan, "vm-no"));
1821                         WAITCMD(play_and_wait(chan, "vm-messages"));
1822                 }
1823                 repeats = 0;
1824                 starting = 1;
1825 instructions:
1826                 if (starting) {
1827                         if (lastmsg > -1) {
1828                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
1829                                 WAITCMD(play_and_wait(chan, vmbox));
1830                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1831                         }
1832                         WAITCMD(play_and_wait(chan, "vm-opts"));
1833                 } else {
1834                         if (curmsg)
1835                                 WAITCMD(play_and_wait(chan, "vm-prev"));
1836                         WAITCMD(play_and_wait(chan, "vm-repeat"));
1837                         if (curmsg != lastmsg)
1838                                 WAITCMD(play_and_wait(chan, "vm-next"));
1839                         if (!deleted[curmsg])
1840                                 WAITCMD(play_and_wait(chan, "vm-delete"));
1841                         else
1842                                 WAITCMD(play_and_wait(chan, "vm-undelete"));
1843                         WAITCMD(play_and_wait(chan, "vm-toforward"));
1844                         WAITCMD(play_and_wait(chan, "vm-savemessage"));
1845                 }
1846                 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1847                 d = ast_waitfordigit(chan, 6000);
1848                 if (d < 0)
1849                         goto out;
1850                 if (!d) {
1851                         repeats++;
1852                         if (repeats > 2) {
1853                                 play_and_wait(chan, "vm-goodbye");
1854                                 goto out;
1855                         }
1856                         goto instructions;
1857                 }
1858 cmd:
1859                 switch(d) {
1860                 case '2':
1861                         if (useadsi)
1862                                 adsi_folders(chan, 0, "Change to folder...");
1863                         box = play_and_wait(chan, "vm-changeto");
1864                         if (box < 0)
1865                                 goto out;
1866                         while((box < '0') || (box > '9')) {
1867                                 box = get_folder(chan, 0);
1868                                 if (box < 0)
1869                                         goto out;
1870                                 if (box == '#')
1871                                         goto instructions;
1872                         } 
1873                         box = box - '0';
1874                         CLOSE_MAILBOX;
1875                         OPEN_MAILBOX(box);
1876                         if (useadsi)
1877                                 adsi_status2(chan, curbox, lastmsg + 1);
1878                         WAITCMD(play_and_wait(chan, vmbox));
1879                         WAITCMD(play_and_wait(chan, "vm-messages"));
1880                         starting = 1;
1881                         goto instructions;
1882                 case '4':
1883                         if (curmsg) {
1884                                 curmsg--;
1885                                 PLAYMSG(curmsg);
1886                         } else {
1887                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1888                                 goto instructions;
1889                         }
1890                 case '1':
1891                                 curmsg = 0;
1892                                 /* Fall through */
1893                 case '5':
1894                         if (lastmsg > -1) {
1895                                 PLAYMSG(curmsg);
1896                         } else {
1897                                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1898                                 WAITCMD(play_and_wait(chan, "vm-no"));
1899                                 snprintf(fn, sizeof(fn), "vm-%s", curbox);
1900                                 WAITCMD(play_and_wait(chan, fn));
1901                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1902                                 goto instructions;
1903                         }
1904                 case '6':
1905                         if (curmsg < lastmsg) {
1906                                 curmsg++;
1907                                 PLAYMSG(curmsg);
1908                         } else {
1909                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1910                                 goto instructions;
1911                         }
1912                 case '7':
1913                         deleted[curmsg] = !deleted[curmsg];
1914                         if (useadsi)
1915                                 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
1916                         if (deleted[curmsg]) 
1917                                 WAITCMD(play_and_wait(chan, "vm-deleted"));
1918                         else
1919                                 WAITCMD(play_and_wait(chan, "vm-undeleted"));
1920                         goto instructions;
1921                 case '8':
1922                         if(lastmsg > -1)
1923                                 if(forward_message(chan, cfg, curdir, curmsg) < 0)
1924                                         goto out;
1925                         goto instructions;
1926                 case '9':
1927                         if (useadsi)
1928                                 adsi_folders(chan, 1, "Save to folder...");
1929                         box = play_and_wait(chan, "vm-savefolder");
1930                         if (box < 0)
1931                                 goto out;
1932                         while((box < '1') || (box > '9')) {
1933                                 box = get_folder(chan, 1);
1934                                 if (box < 0)
1935                                         goto out;
1936                                 if (box == '#')
1937                                         goto instructions;
1938                         } 
1939                         box = box - '0';
1940                         if (option_debug)
1941                                 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
1942                         if (save_to_folder(curdir, curmsg, username, box))
1943                                 goto out;
1944                         deleted[curmsg]=1;
1945                         make_file(fn, sizeof(fn), curdir, curmsg);
1946                         if (useadsi)
1947                                 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
1948                         WAITCMD(play_and_wait(chan, "vm-message"));
1949                         WAITCMD(say_and_wait(chan, curmsg + 1) );
1950                         WAITCMD(play_and_wait(chan, "vm-savedto"));
1951                         snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
1952                         WAITCMD(play_and_wait(chan, fn));
1953                         WAITCMD(play_and_wait(chan, "vm-messages"));
1954                         goto instructions;
1955                 case '*':
1956                         if (!starting) {
1957                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
1958                                 WAITCMD(play_and_wait(chan, vmbox));
1959                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1960                                 WAITCMD(play_and_wait(chan, "vm-opts"));
1961                         }
1962                         goto instructions;
1963                 case '#':
1964                         ast_stopstream(chan);
1965                         adsi_goodbye(chan);
1966                         play_and_wait(chan, "vm-goodbye");
1967                         res = 0;
1968                         goto out2;
1969
1970                 case '0':
1971                         goto vm_options;
1972
1973                 default:
1974                         goto instructions;
1975                 }
1976         }
1977 out:
1978         adsi_goodbye(chan);
1979 out2:
1980         CLOSE_MAILBOX;
1981         ast_stopstream(chan);
1982         if (cfg)
1983                 ast_destroy(cfg);
1984         if (useadsi)
1985                 adsi_unload_session(chan);
1986         if (valid) {
1987                 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
1988         }
1989         LOCAL_USER_REMOVE(u);
1990         return res;
1991
1992 vm_options:
1993         d = play_and_wait(chan,"vm-options");
1994         if (!d)
1995                 d = ast_waitfordigit(chan,6000);
1996         if (d < 0)
1997                 goto out;
1998         switch (d) {
1999                 
2000                 case '1':
2001                         snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username);
2002                         play_and_record(chan,"vm-rec-unv",prefile, maxgreet);
2003                         break;
2004                 case '2': 
2005                         snprintf(prefile,sizeof(prefile),"vm/%s/busy",username);
2006                         play_and_record(chan,"vm-rec-busy",prefile, maxgreet);
2007                         break;
2008                 case '3': 
2009                         snprintf(prefile,sizeof(prefile),"vm/%s/greet",username);
2010                         play_and_record(chan,"vm-rec-name",prefile, maxgreet);
2011                         break;
2012                 case '4':
2013                         newpassword[1] = '\0';
2014                         newpassword[0] = play_and_wait(chan,"vm-newpassword");
2015                         if (ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#") < 0) {
2016                                 play_and_wait(chan, "vm-sorry");
2017                                 ast_log(LOG_NOTICE,"Unable to read new password\n");
2018                                 goto vm_options;
2019             }
2020                         newpassword2[1] = '\0';
2021                         newpassword2[0] = play_and_wait(chan,"vm-reenterpassword");
2022
2023                         if (ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#") < 0) {
2024                                 play_and_wait(chan, "vm-sorry");
2025                                 ast_log(LOG_NOTICE,"Unable to read re-entered password\n");
2026                                 goto vm_options;
2027             }
2028                         if (strcmp(newpassword, newpassword2)) {
2029                                 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", username, newpassword, newpassword2);
2030                                 play_and_wait(chan, "vm-mismatch");
2031                                 goto vm_options;
2032                         }
2033                         if (vm_change_password(username,password,newpassword) < 0)
2034                         {
2035                                 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",username);
2036                         } else
2037                 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",username,newpassword,strlen(newpassword));
2038                         play_and_wait(chan,"vm-passchanged");
2039                         break;
2040                 case '*': 
2041                         goto instructions;
2042
2043                 default: 
2044                         goto vm_options;
2045                  }
2046         goto vm_options;
2047 }
2048
2049 static int vm_exec(struct ast_channel *chan, void *data)
2050 {
2051         int res=0, silent=0, busy=0, unavail=0;
2052         struct localuser *u;
2053         char tmp[256], *ext;
2054         
2055         LOCAL_USER_ADD(u);
2056         if (chan->_state != AST_STATE_UP)
2057                 ast_answer(chan);
2058         if (data)
2059                 strncpy(tmp, data, sizeof(tmp) - 1);
2060         else {
2061                 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2062                 if (res < 0)
2063                         return res;
2064                 if (!strlen(tmp))
2065                         return 0;
2066         }
2067         ext = tmp;
2068         if (*ext == 's') {
2069                 silent++;
2070                 ext++;
2071         } else if (*ext == 'b') {
2072                 busy++;
2073                 ext++;
2074         } else if (*ext == 'u') {
2075                 unavail++;
2076                 ext++;
2077         }
2078         res = leave_voicemail(chan, ext, silent, busy, unavail);
2079         LOCAL_USER_REMOVE(u);
2080         return res;
2081 }
2082
2083 int unload_module(void)
2084 {
2085         int res;
2086         STANDARD_HANGUP_LOCALUSERS;
2087         res = ast_unregister_application(app);
2088         res |= ast_unregister_application(app2);
2089         return res;
2090 }
2091
2092 int load_module(void)
2093 {
2094         int res;
2095         res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2096         if (!res)
2097                 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2098         return res;
2099 }
2100
2101 char *description(void)
2102 {
2103         return tdesc;
2104 }
2105
2106 int usecount(void)
2107 {
2108         int res;
2109         STANDARD_USECOUNT(res);
2110         return res;
2111 }
2112
2113 char *key()
2114 {
2115         return ASTERISK_GPL_KEY;
2116 }