Wed Mar 5 07:00:00 CET 2003
[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 "[message]\n"
571 "origmailbox=%s\n"
572 "context=%s\n"
573 "exten=%s\n"
574 "priority=%d\n"
575 "callerchan=%s\n"
576 "callerid=%s\n"
577 "origdate=%s\n"
578 "origtime=%ld\n",
579         ext,
580         chan->context,
581         chan->exten,
582         chan->priority,
583         chan->name,
584         chan->callerid ? chan->callerid : "Unknown",
585         date, time(NULL));
586                                                         fclose(txt);
587                                                 } else
588                                                         ast_log(LOG_WARNING, "Error opening text file for output\n");
589         
590                                                 /* We need to reset these values */
591                                                 free(fmts);
592                                                 fmt = ast_variable_retrieve(cfg, "general", "format");
593                                                 fmts = strdup(fmt);
594                                                 stringp=fmts;
595                                                 strsep(&stringp, "|");
596                                                 while((fmt = strsep(&stringp, "|"))) {
597                                                         if (fmtcnt > MAX_OTHER_FORMATS - 1) {
598                                                                 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
599                                                                 break;
600                                                         }
601                                                         sfmt[fmtcnt++] = strdup(fmt);
602                                                 }
603                                                 for (x=0;x<fmtcnt;x++) {
604                                                         others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
605                                                         if (!others[x]) {
606                                                                 /* Ick, the other format didn't work, but be sure not
607                                                                    to leak memory here */
608                                                                 int y;
609                                                                 for(y=x+1;y < fmtcnt;y++)
610                                                                         free(sfmt[y]);
611                                                                 break;
612                                                         }
613                                                         if(!strcasecmp(sfmt[x], "wav"))
614                                                                 wavother++;
615                                                         free(sfmt[x]);
616                                                 }
617                                                 if (x == fmtcnt) {
618                                                         /* Loop forever, writing the packets we read to the writer(s), until
619                                                            we read a # or get a hangup */
620                                                         if (option_verbose > 2) 
621                                                                 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
622                                                         f = NULL;
623                                                         for(;;) {
624                                                                 res = ast_waitfor(chan, 2000);
625                                                                 if (!res) {
626                                                                         ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
627                                                                         /* Try one more time in case of masq */
628                                                                         res = ast_waitfor(chan, 2000);
629                                                                         if (!res) {
630                                                                                 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
631                                                                                 res = -1;
632                                                                         }
633                                                                 }
634                                                                 
635                                                                 if (res < 0) {
636                                                                         f = NULL;
637                                                                         break;
638                                                                 }
639
640                                                                 f = ast_read(chan);
641                                                                 if (!f)
642                                                                         break;
643                                                                 if (f->frametype == AST_FRAME_VOICE) {
644                                                                         /* Write the primary format */
645                                                                         res = ast_writestream(writer, f);
646                                                                         if (res) {
647                                                                                 ast_log(LOG_WARNING, "Error writing primary frame\n");
648                                                                                 break;
649                                                                         }
650                                                                         /* And each of the others */
651                                                                         for (x=0;x<fmtcnt;x++) {
652                                                                                 res |= ast_writestream(others[x], f);
653                                                                         }
654                                                                         /* Exit on any error */
655                                                                         if (res) {
656                                                                                 ast_log(LOG_WARNING, "Error writing frame\n");
657                                                                                 ast_frfree(f);
658                                                                                 break;
659                                                                         }
660                                                                 } else if (f->frametype == AST_FRAME_DTMF) {
661                                                                         if (f->subclass == '#') {
662                                                                                 if (option_verbose > 2) 
663                                                                                         ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
664                                                                                 outmsg=2;
665                                                                                 ast_frfree(f);
666                                                                                 res = 0;
667                                                                                 break;
668                                                                         }
669                                                                 }
670                                                                 ast_frfree(f);
671                                                                 time(&end);
672                                                                 if (maxmessage && (end - start > maxmessage)) {
673                                                                         if (option_verbose > 2) 
674                                                                                 ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n");
675                                                                         outmsg = 2;
676                                                                         res = 0;
677                                                                         break;
678                                                                 }
679                                                         }
680                                                         if (!f) {
681                                                                 if (option_verbose > 2) 
682                                                                         ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
683                                                                 res = -1;
684                                                                 outmsg=1;
685                                                         }
686                                                 } else {
687                                                         ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]); 
688                                                         free(sfmt[x]);
689                                                 }
690
691                                                 ast_closestream(writer);
692                                                 for (x=0;x<fmtcnt;x++) {
693                                                         if (!others[x])
694                                                                 break;
695                                                         ast_closestream(others[x]);
696                                                 }
697                                                 if (outmsg) {
698                                                         if (outmsg > 1) {
699                                                                 /* Let them know it worked */
700                                                                 ast_streamfile(chan, "vm-msgsaved", chan->language);
701                                                                 ast_waitstream(chan, "");
702                                                         }
703                                                         txt = fopen(txtfile, "a");
704                                                         if (txt) {
705                                                                 time(&end);
706                                                                 fprintf(txt, "duration=%ld\n", end-start);
707                                                                 fclose(txt);
708                                                         }
709                                                         /* Send e-mail if applicable */
710                                                         if (email)
711                                                                 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start);
712                                                 }
713                                         } else {
714                                                 if (msgnum < MAXMSG)
715                                                         ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
716                                                 else
717                                                         ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
718                                         }
719                                         free(fmts);
720                                 } else 
721                                         ast_log(LOG_WARNING, "No format to save messages in \n");
722                         }
723                 } else
724                         ast_log(LOG_WARNING, "Unable to playback instructions\n");
725                         
726                 free(copy);
727         } else
728                 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
729         ast_destroy(cfg);
730         /* Leave voicemail for someone */
731         manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
732         return res;
733 }
734
735 static char *mbox(int id)
736 {
737         switch(id) {
738         case 0:
739                 return "INBOX";
740         case 1:
741                 return "Old";
742         case 2:
743                 return "Work";
744         case 3:
745                 return "Family";
746         case 4:
747                 return "Friends";
748         case 5:
749                 return "Cust1";
750         case 6:
751                 return "Cust2";
752         case 7:
753                 return "Cust3";
754         case 8:
755                 return "Cust4";
756         case 9:
757                 return "Cust5";
758         default:
759                 return "Unknown";
760         }
761 }
762
763 static int count_messages(char *dir)
764 {
765         int x;
766         char fn[256];
767         for (x=0;x<MAXMSG;x++) {
768                 make_file(fn, sizeof(fn), dir, x);
769                 if (ast_fileexists(fn, NULL, NULL) < 1)
770                         break;
771         }
772         return x;
773 }
774
775 static int play_and_wait(struct ast_channel *chan, char *fn)
776 {
777         int d;
778         d = ast_streamfile(chan, fn, chan->language);
779         if (d)
780                 return d;
781         d = ast_waitstream(chan, AST_DIGIT_ANY);
782         return d;
783 }
784
785 static int say_and_wait(struct ast_channel *chan, int num)
786 {
787         int d;
788         d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
789         return d;
790 }
791
792 static int copy(char *infile, char *outfile)
793 {
794         int ifd;
795         int ofd;
796         int res;
797         int len;
798         char buf[4096];
799         if ((ifd = open(infile, O_RDONLY)) < 0) {
800                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
801                 return -1;
802         }
803         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
804                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
805                 close(ifd);
806                 return -1;
807         }
808         do {
809                 len = read(ifd, buf, sizeof(buf));
810                 if (len < 0) {
811                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
812                         close(ifd);
813                         close(ofd);
814                         unlink(outfile);
815                 }
816                 if (len) {
817                         res = write(ofd, buf, len);
818                         if (res != len) {
819                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
820                                 close(ifd);
821                                 close(ofd);
822                                 unlink(outfile);
823                         }
824                 }
825         } while(len);
826         close(ifd);
827         close(ofd);
828         return 0;
829 }
830
831 static int save_to_folder(char *dir, int msg, char *username, int box)
832 {
833         char sfn[256];
834         char dfn[256];
835         char ddir[256];
836         char txt[256];
837         char ntxt[256];
838         char *dbox = mbox(box);
839         int x;
840         make_file(sfn, sizeof(sfn), dir, msg);
841         make_dir(ddir, sizeof(ddir), username, dbox);
842         mkdir(ddir, 0700);
843         for (x=0;x<MAXMSG;x++) {
844                 make_file(dfn, sizeof(dfn), ddir, x);
845                 if (ast_fileexists(dfn, NULL, NULL) < 0)
846                         break;
847         }
848         if (x >= MAXMSG)
849                 return -1;
850         ast_filecopy(sfn, dfn, NULL);
851         if (strcmp(sfn, dfn)) {
852                 snprintf(txt, sizeof(txt), "%s.txt", sfn);
853                 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
854                 copy(txt, ntxt);
855         }
856         return 0;
857 }
858
859 static int adsi_logo(unsigned char *buf)
860 {
861         int bytes = 0;
862         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
863         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
864         return bytes;
865 }
866
867 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
868 {
869         char buf[256];
870         int bytes=0;
871         int x;
872         char num[5];
873
874         *useadsi = 0;
875         bytes += adsi_data_mode(buf + bytes);
876         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
877
878         bytes = 0;
879         bytes += adsi_logo(buf);
880         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
881 #ifdef DISPLAY
882         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
883 #endif
884         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
885         bytes += adsi_data_mode(buf + bytes);
886         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
887
888         if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
889                 bytes = 0;
890                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
891                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
892                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
893                 bytes += adsi_voice_mode(buf + bytes, 0);
894                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
895                 return 0;
896         }
897
898 #ifdef DISPLAY
899         /* Add a dot */
900         bytes = 0;
901         bytes += adsi_logo(buf);
902         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
903         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
904         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
905         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
906 #endif
907         bytes = 0;
908         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
909         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
910         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
911         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
912         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
913         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
914         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
915
916 #ifdef DISPLAY
917         /* Add another dot */
918         bytes = 0;
919         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
920         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
921         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
922 #endif
923
924         bytes = 0;
925         /* These buttons we load but don't use yet */
926         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
927         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
928         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
929         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
930         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
931         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
932         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
933
934 #ifdef DISPLAY
935         /* Add another dot */
936         bytes = 0;
937         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
938         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
939         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
940 #endif
941
942         bytes = 0;
943         for (x=0;x<5;x++) {
944                 snprintf(num, sizeof(num), "%d", x);
945                 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
946         }
947         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
948         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
949
950 #ifdef DISPLAY
951         /* Add another dot */
952         bytes = 0;
953         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
954         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
955         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
956 #endif
957
958         if (adsi_end_download(chan)) {
959                 bytes = 0;
960                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
961                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
962                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
963                 bytes += adsi_voice_mode(buf + bytes, 0);
964                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
965                 return 0;
966         }
967         bytes = 0;
968         bytes += adsi_download_disconnect(buf + bytes);
969         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
970
971         ast_log(LOG_DEBUG, "Done downloading scripts...\n");
972
973 #ifdef DISPLAY
974         /* Add last dot */
975         bytes = 0;
976         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
977         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
978 #endif
979         ast_log(LOG_DEBUG, "Restarting session...\n");
980
981         bytes = 0;
982         /* Load the session now */
983         if (adsi_load_session(chan, adapp, adver, 1) == 1) {
984                 *useadsi = 1;
985                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
986         } else
987                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
988
989         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
990         return 0;
991 }
992
993 static void adsi_begin(struct ast_channel *chan, int *useadsi)
994 {
995         int x;
996         if(!strcasecmp(chan->type, "sip")){
997           *useadsi = 0;
998           return;
999         }
1000
1001         x = adsi_load_session(chan, adapp, adver, 1);
1002         if (x < 0)
1003                 return;
1004         if (!x) {
1005                 if (adsi_load_vmail(chan, useadsi)) {
1006                         ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1007                         return;
1008                 }
1009         } else
1010                 *useadsi = 1;
1011 }
1012
1013 static void adsi_login(struct ast_channel *chan)
1014 {
1015         char buf[256];
1016         int bytes=0;
1017         unsigned char keys[8];
1018         int x;
1019         if (!adsi_available(chan))
1020                 return;
1021
1022         for (x=0;x<8;x++)
1023                 keys[x] = 0;
1024         /* Set one key for next */
1025         keys[3] = ADSI_KEY_APPS + 3;
1026
1027         bytes += adsi_logo(buf + bytes);
1028         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1029         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1030         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1031         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1032         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1033         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1034         bytes += adsi_set_keys(buf + bytes, keys);
1035         bytes += adsi_voice_mode(buf + bytes, 0);
1036         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1037 }
1038
1039 static void adsi_password(struct ast_channel *chan)
1040 {
1041         char buf[256];
1042         int bytes=0;
1043         unsigned char keys[8];
1044         int x;
1045         if (!adsi_available(chan))
1046                 return;
1047
1048         for (x=0;x<8;x++)
1049                 keys[x] = 0;
1050         /* Set one key for next */
1051         keys[3] = ADSI_KEY_APPS + 3;
1052
1053         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1054         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1055         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1056         bytes += adsi_set_keys(buf + bytes, keys);
1057         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1058 }
1059
1060 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1061 {
1062         char buf[256];
1063         int bytes=0;
1064         unsigned char keys[8];
1065         int x,y;
1066
1067         if (!adsi_available(chan))
1068                 return;
1069
1070         for (x=0;x<5;x++) {
1071                 y = ADSI_KEY_APPS + 12 + start + x;
1072                 if (y > ADSI_KEY_APPS + 12 + 4)
1073                         y = 0;
1074                 keys[x] = ADSI_KEY_SKT | y;
1075         }
1076         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1077         keys[6] = 0;
1078         keys[7] = 0;
1079
1080         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1081         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1082         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1083         bytes += adsi_set_keys(buf + bytes, keys);
1084         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1085 }
1086
1087 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1088 {
1089         int bytes=0;
1090         char buf[256], buf1[256], buf2[256];
1091         char fn2[256];
1092         char cid[256]="";
1093         char *val;
1094         char *name, *num;
1095         char datetime[21]="";
1096         FILE *f;
1097
1098         unsigned char keys[8];
1099
1100         int x;
1101
1102         if (!adsi_available(chan))
1103                 return;
1104
1105         /* Retrieve important info */
1106         snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1107         f = fopen(fn2, "r");
1108         if (f) {
1109                 while(!feof(f)) {       
1110                         fgets(buf, sizeof(buf), f);
1111                         if (!feof(f)) {
1112                                 char *stringp=NULL;
1113                                 stringp=buf;
1114                                 strsep(&stringp, "=");
1115                                 val = strsep(&stringp, "=");
1116                                 if (val && strlen(val)) {
1117                                         if (!strcmp(buf, "callerid"))
1118                                                 strncpy(cid, val, sizeof(cid) - 1);
1119                                         if (!strcmp(buf, "origdate"))
1120                                                 strncpy(datetime, val, sizeof(datetime) - 1);
1121                                 }
1122                         }
1123                 }
1124                 fclose(f);
1125         }
1126         /* New meaning for keys */
1127         for (x=0;x<5;x++)
1128                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1129         keys[6] = 0x0;
1130         keys[7] = 0x0;
1131
1132         if (!msg) {
1133                 /* No prev key, provide "Folder" instead */
1134                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1135         }
1136         if (msg >= last) {
1137                 /* If last message ... */
1138                 if (msg) {
1139                         /* but not only message, provide "Folder" instead */
1140                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1141                 } else {
1142                         /* Otherwise if only message, leave blank */
1143                         keys[3] = 1;
1144                 }
1145         }
1146
1147         if (strlen(cid)) {
1148                 ast_callerid_parse(cid, &name, &num);
1149                 if (!name)
1150                         name = num;
1151         } else
1152                 name = "Unknown Caller";
1153
1154         /* If deleted, show "undeleted" */
1155         if (deleted)
1156                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1157
1158         /* Except "Exit" */
1159         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1160         snprintf(buf1, sizeof(buf1), "%s%s", folder,
1161                  strcasecmp(folder, "INBOX") ? " Messages" : "");
1162         snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1163
1164         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1165         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1166         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1167         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1168         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1169         bytes += adsi_set_keys(buf + bytes, keys);
1170         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1171 }
1172
1173 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1174 {
1175         int bytes=0;
1176         char buf[256];
1177         unsigned char keys[8];
1178
1179         int x;
1180
1181         if (!adsi_available(chan))
1182                 return;
1183
1184         /* New meaning for keys */
1185         for (x=0;x<5;x++)
1186                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1187
1188         keys[6] = 0x0;
1189         keys[7] = 0x0;
1190
1191         if (!msg) {
1192                 /* No prev key, provide "Folder" instead */
1193                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1194         }
1195         if (msg >= last) {
1196                 /* If last message ... */
1197                 if (msg) {
1198                         /* but not only message, provide "Folder" instead */
1199                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1200                 } else {
1201                         /* Otherwise if only message, leave blank */
1202                         keys[3] = 1;
1203                 }
1204         }
1205
1206         /* If deleted, show "undeleted" */
1207         if (deleted) 
1208                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1209
1210         /* Except "Exit" */
1211         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1212         bytes += adsi_set_keys(buf + bytes, keys);
1213         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1214 }
1215
1216 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1217 {
1218         char buf[256], buf1[256], buf2[256];
1219         int bytes=0;
1220         unsigned char keys[8];
1221         int x;
1222
1223         char *newm = (new == 1) ? "message" : "messages";
1224         char *oldm = (old == 1) ? "message" : "messages";
1225         if (!adsi_available(chan))
1226                 return;
1227         if (new) {
1228                 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1229                 if (old) {
1230                         strcat(buf1, " and");
1231                         snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1232                 } else {
1233                         snprintf(buf2, sizeof(buf2), "%s.", newm);
1234                 }
1235         } else if (old) {
1236                 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1237                 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1238         } else {
1239                 strcpy(buf1, "You have no messages.");
1240                 strcpy(buf2, " ");
1241         }
1242         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1243         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1244         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1245
1246         for (x=0;x<6;x++)
1247                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1248         keys[6] = 0;
1249         keys[7] = 0;
1250
1251         /* Don't let them listen if there are none */
1252         if (lastmsg < 0)
1253                 keys[0] = 1;
1254         bytes += adsi_set_keys(buf + bytes, keys);
1255
1256         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1257 }
1258
1259 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1260 {
1261         char buf[256], buf1[256], buf2[256];
1262         int bytes=0;
1263         unsigned char keys[8];
1264         int x;
1265
1266         char *mess = (messages == 1) ? "message" : "messages";
1267
1268         if (!adsi_available(chan))
1269                 return;
1270
1271         /* Original command keys */
1272         for (x=0;x<6;x++)
1273                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1274
1275         keys[6] = 0;
1276         keys[7] = 0;
1277
1278         if (messages < 1)
1279                 keys[0] = 0;
1280
1281         snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1282                         strcasecmp(folder, "INBOX") ? " folder" : "");
1283
1284         if (messages)
1285                 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1286         else
1287                 strcpy(buf2, "no messages.");
1288         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1289         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1290         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1291         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1292         bytes += adsi_set_keys(buf + bytes, keys);
1293
1294         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1295         
1296 }
1297
1298 static void adsi_clear(struct ast_channel *chan)
1299 {
1300         char buf[256];
1301         int bytes=0;
1302         if (!adsi_available(chan))
1303                 return;
1304         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1305         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1306 }
1307
1308 static void adsi_goodbye(struct ast_channel *chan)
1309 {
1310         char buf[256];
1311         int bytes=0;
1312         if(!strcasecmp(chan->type, "sip")){
1313           return;
1314         }
1315         if (!adsi_available(chan))
1316                 return;
1317         bytes += adsi_logo(buf + bytes);
1318         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1319         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1320         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1321         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1322 }
1323
1324 static int get_folder(struct ast_channel *chan, int start)
1325 {
1326         int x;
1327         int d;
1328         char fn[256];
1329         d = play_and_wait(chan, "vm-press");
1330         if (d)
1331                 return d;
1332         for (x = start; x< 5; x++) {
1333                 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1334                         return d;
1335                 d = play_and_wait(chan, "vm-for");
1336                 if (d)
1337                         return d;
1338                 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1339                 d = play_and_wait(chan, fn);
1340                 if (d)
1341                         return d;
1342                 d = play_and_wait(chan, "vm-messages");
1343                 if (d)
1344                         return d;
1345                 d = ast_waitfordigit(chan, 500);
1346                 if (d)
1347                         return d;
1348         }
1349         d = play_and_wait(chan, "vm-tocancel");
1350         if (d)
1351                 return d;
1352         d = ast_waitfordigit(chan, 4000);
1353         return d;
1354 }
1355
1356 static int
1357 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg, char* myusername)
1358 {
1359         char username[70];
1360         char sys[256];
1361         char todir[256];
1362         int todircount=0;
1363         struct ast_config *mif;
1364         char miffile[256];
1365         char *copy, *name, *passwd, *email;
1366         char *mycopy, *myname, *mypasswd, *myemail;
1367         char fn[256];
1368         char callerid[512];
1369         
1370         while(1) {
1371                 ast_streamfile(chan, "vm-extension", chan->language);
1372
1373                 if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)
1374                         return 0;
1375                 if (ast_variable_retrieve(cfg, NULL, username)) {
1376                         printf("Got %d\n", atoi(username));
1377                         /* if (play_and_wait(chan, "vm-savedto"))
1378                                 break;
1379                         */
1380
1381                         snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX",  (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1382                         snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1383                         puts(sys);
1384                         system(sys);
1385
1386                         todircount = count_messages(todir);
1387
1388                         snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1389                         puts(sys);
1390                         system(sys);
1391
1392                         /* TODO: use config to determine what other formats to copy the message in */
1393                         snprintf(sys, sizeof(sys), "cp %s/msg%04d.wav %s/msg%04d.wav\n", dir, curmsg, todir, todircount);
1394                         puts(sys);
1395                         system(sys);
1396
1397                         /* copy the message information file too */
1398                         snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
1399                         puts(sys);
1400                         system(sys);
1401                         
1402                         snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1403
1404                         /* load the information on the source message so we can send an e-mail like a new message */
1405                         snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1406                         if ((mif=ast_load(miffile))) {
1407
1408                           /* send an e-mail like it was a new message if appropriate */
1409                           if ((copy = ast_variable_retrieve(cfg, NULL, username))) {                      
1410                             char *stringp=NULL;
1411                             /* Make sure they have an entry in the config */
1412                             copy = strdup(copy);
1413                             stringp=copy;
1414                             passwd = strsep(&stringp, ",");
1415                             name = strsep(&stringp, ",");
1416                             email = strsep(&stringp, ",");
1417                           }
1418                           
1419                           if ((mycopy = ast_variable_retrieve(cfg, NULL, myusername))) {                          
1420                             char *mystringp=NULL;
1421                             /* Make sure they have an entry in the config */
1422                             mycopy = strdup(mycopy);
1423                             mystringp=mycopy;
1424                             mypasswd = strsep(&mystringp, ",");
1425                             myname = strsep(&mystringp, ",");
1426                             myemail = strsep(&mystringp, ",");
1427                           }
1428
1429                           if (email) {
1430                             snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", myname, ast_variable_retrieve(mif, NULL, "callerid"));
1431                             sendmail(ast_variable_retrieve(cfg, "general", "serveremail"),
1432                                      email, name, todircount, username,
1433                                      callerid,
1434                                      fn,
1435                                      "wav",
1436                                      atol(ast_variable_retrieve(mif, NULL, "duration"))
1437                                      );
1438                           }
1439                           
1440                           free(copy); /* no leaks here */
1441                           free(mycopy); /* or here */
1442                           ast_destroy(mif); /* or here */
1443                         }
1444
1445                         /* give confirmatopm that the message was saved */
1446                         if (play_and_wait(chan, "vm-message")) break;
1447                         if (play_and_wait(chan, "vm-saved")) break;
1448
1449                         break;
1450                 } else {
1451                         if ( play_and_wait(chan, "pbx-invalid"))
1452                                 break;
1453                 }
1454         }
1455         return 0;
1456 }
1457
1458 #define WAITCMD(a) do { \
1459         d = (a); \
1460         if (d < 0) \
1461                 goto out; \
1462         if (d) \
1463                 goto cmd; \
1464 } while(0)
1465
1466 #define WAITFILE2(file) do { \
1467         if (ast_streamfile(chan, file, chan->language)) \
1468                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1469         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1470         if (d < 0) { \
1471                 goto out; \
1472         }\
1473 } while(0)
1474
1475 #define WAITFILE(file) do { \
1476         if (ast_streamfile(chan, file, chan->language)) \
1477                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1478         d = ast_waitstream(chan, AST_DIGIT_ANY); \
1479         if (!d) { \
1480                 repeats = 0; \
1481                 goto instructions; \
1482         } else if (d < 0) { \
1483                 goto out; \
1484         } else goto cmd;\
1485 } while(0)
1486
1487 #define PLAYMSG(a) do { \
1488         starting = 0; \
1489         make_file(fn, sizeof(fn), curdir, a); \
1490         adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1491         if (!a) \
1492                 WAITFILE2("vm-first"); \
1493         else if (a == lastmsg) \
1494                 WAITFILE2("vm-last"); \
1495         WAITFILE2("vm-message"); \
1496         if (a && (a != lastmsg)) { \
1497                 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1498                 if (d < 0) goto out; \
1499                 if (d) goto cmd; \
1500         } \
1501         make_file(fn, sizeof(fn), curdir, a); \
1502         heard[a] = 1; \
1503         WAITFILE(fn); \
1504 } while(0)
1505
1506 #define CLOSE_MAILBOX do { \
1507         if (lastmsg > -1) { \
1508                 /* Get the deleted messages fixed */ \
1509                 curmsg = -1; \
1510                 for (x=0;x<=lastmsg;x++) { \
1511                         if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1512                                 /* Save this message.  It's not in INBOX or hasn't been heard */ \
1513                                 curmsg++; \
1514                                 make_file(fn, sizeof(fn), curdir, x); \
1515                                 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1516                                 if (strcmp(fn, fn2)) { \
1517                                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1518                                         snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1519                                         ast_filerename(fn, fn2, NULL); \
1520                                         rename(txt, ntxt); \
1521                                 } \
1522                         } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1523                                 /* Move to old folder before deleting */ \
1524                                 save_to_folder(curdir, x, username, 1); \
1525                         } \
1526                 } \
1527                 for (x = curmsg + 1; x<=lastmsg; x++) { \
1528                         make_file(fn, sizeof(fn), curdir, x); \
1529                         snprintf(txt, sizeof(txt), "%s.txt", fn); \
1530                         ast_filedelete(fn, NULL); \
1531                         unlink(txt); \
1532                 } \
1533         } \
1534         memset(deleted, 0, sizeof(deleted)); \
1535         memset(heard, 0, sizeof(heard)); \
1536 } while(0)
1537
1538 #define OPEN_MAILBOX(a) do { \
1539         strcpy(curbox, mbox(a)); \
1540         make_dir(curdir, sizeof(curdir), username, curbox); \
1541         lastmsg = count_messages(curdir) - 1; \
1542         snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1543 } while (0)
1544
1545 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime)
1546 {
1547         char d, *fmt, *fmts;
1548         char comment[256];
1549         int x, fmtcnt=1, res=-1,outmsg=0, wavother=0;
1550         struct ast_frame *f;
1551         struct ast_config *cfg;
1552         struct ast_filestream *others[MAX_OTHER_FORMATS];
1553         char *sfmt[MAX_OTHER_FORMATS];
1554         char *stringp=NULL;
1555         time_t start, end;
1556         
1557         
1558         ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile);
1559         snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name);
1560         
1561         d = play_and_wait(chan, playfile);
1562         if (d < 0)
1563                 return -1;
1564         ast_streamfile(chan, "beep",chan->language);
1565         ast_waitstream(chan,"");
1566         cfg = ast_load(VOICEMAIL_CONFIG);
1567         
1568         fmt = ast_variable_retrieve(cfg, "general", "format");
1569         ast_log(LOG_DEBUG,"Recording Formats: fmt=%s\n", fmt);  
1570         
1571         fmts = strdup(fmt);
1572         
1573         ast_destroy(cfg);
1574
1575         stringp=fmts;
1576         strsep(&stringp, "|");
1577         ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);       
1578         sfmt[0] = strdup(fmts);
1579         
1580         while((fmt = strsep(&stringp, "|"))) {
1581                 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1582                         ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1583                         break;
1584                         }
1585                 sfmt[fmtcnt++] = strdup(fmt);
1586                 }
1587
1588         if (maxtime)
1589                 time(&start);
1590         for (x=0;x<fmtcnt;x++) {
1591                 others[x] = ast_writefile(recordfile, sfmt[x], comment, 0, 0, 0700);
1592                 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s\n", x, recordfile, sfmt[x]);
1593                         
1594                 if (!others[x]) {
1595                 /* Ick, the other format didn't work, but be sure not
1596                    to leak memory here */
1597                         int y;
1598                         for(y=x+1;y < fmtcnt;y++)
1599                         free(sfmt[y]);
1600                         break;
1601                         }
1602                 if(!strcasecmp(sfmt[x], "wav"))
1603                         wavother++;
1604                         free(sfmt[x]);
1605                         }
1606                 if (x == fmtcnt) {
1607                 /* Loop forever, writing the packets we read to the writer(s), until
1608                    we read a # or get a hangup */
1609                         f = NULL;
1610                         for(;;) {
1611                                 res = ast_waitfor(chan, 2000);
1612                                 if (!res) {
1613                                         ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1614                                         /* Try one more time in case of masq */
1615                                         res = ast_waitfor(chan, 2000);
1616                                         if (!res) {
1617                                                 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1618                                                 res = -1;
1619                                         }
1620                                 }
1621                                 
1622                                 if (res < 0) {
1623                                         f = NULL;
1624                                         break;
1625                                 }
1626
1627                                 f = ast_read(chan);
1628                                 if (!f)
1629                                         break;
1630                                 if (f->frametype == AST_FRAME_VOICE) {
1631                                         /* write each format */
1632                                         for (x=0;x<fmtcnt;x++) {
1633                                                 res = ast_writestream(others[x], f);
1634                                                 }
1635                                         /* Exit on any error */
1636                                         if (res) {
1637                                                 ast_log(LOG_WARNING, "Error writing frame\n");
1638                                                 ast_frfree(f);
1639                                                 break;
1640                                         }
1641                                 } else if (f->frametype == AST_FRAME_DTMF) {
1642                                         if (f->subclass == '#') {
1643                                                 if (option_verbose > 2) 
1644                                                         ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1645                                                 outmsg=2;
1646                                                 break;
1647                                         }
1648                                 }
1649                                 if (maxtime) {
1650                                         time(&end);
1651                                         if (maxtime < (end - start)) {
1652                                                 if (option_verbose > 2)
1653                                                         ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1654                                                 outmsg=2;
1655                                                 break;
1656                                         }
1657                                 }
1658                                 ast_frfree(f);
1659                         }
1660                         if (!f) {
1661                                 if (option_verbose > 2) 
1662                                         ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1663                                 res = -1;
1664                                 outmsg=1;
1665                                 }
1666                         } else {
1667                                 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]); 
1668                                 free(sfmt[x]);
1669                                 }
1670
1671                         for (x=0;x<fmtcnt;x++) {
1672                                 if (!others[x])
1673                                         break;
1674                                 ast_closestream(others[x]);
1675                                 }
1676                         if (outmsg) {
1677                                 if (outmsg > 1) {
1678                                 /* Let them know it worked */
1679                                         ast_streamfile(chan, "vm-msgsaved", chan->language);
1680                                         ast_waitstream(chan, "");
1681                                 }
1682                 }       
1683
1684         
1685         return 0;
1686 }
1687
1688
1689
1690
1691 static int vm_execmain(struct ast_channel *chan, void *data)
1692 {
1693         /* XXX This is, admittedly, some pretty horrendus code.  For some
1694            reason it just seemed a lot easier to do with GOTO's.  I feel
1695            like I'm back in my GWBASIC days. XXX */
1696         int res=-1;
1697         int valid = 0;
1698         int prefix = 0;
1699         char d;
1700         struct localuser *u;
1701         char username[80] ="";
1702         char prefixstr[80] ="";
1703         char empty[80] = "";
1704         char password[80] = "", *copy;
1705         char newpassword[80] = "";
1706         char newpassword2[80] = "";
1707         char curbox[80] = "";
1708         char curdir[256] = "";
1709         char vmbox[256] = "";
1710         char fn[256] = "";
1711         char fn2[256] = "";
1712         char prefile[256]="";
1713         int x;
1714         char ntxt[256] = "";
1715         char txt[256] = "";
1716         int deleted[MAXMSG] = { 0, };
1717         int heard[MAXMSG] = { 0, };
1718         int newmessages;
1719         int oldmessages;
1720         int repeats = 0;
1721         int curmsg = 0;
1722         int lastmsg = 0;
1723         int starting = 1;
1724         int box;
1725         int useadsi = 0;
1726         int skipuser = 0;
1727         char *s;
1728         int maxgreet = 0;
1729         char tmp[256], *ext;
1730         struct ast_config *cfg;
1731
1732         LOCAL_USER_ADD(u);
1733         cfg = ast_load(VOICEMAIL_CONFIG);
1734         if (!cfg) {
1735                 ast_log(LOG_WARNING, "No voicemail configuration\n");
1736                 goto out;
1737         }
1738         if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1739                 if (sscanf(s, "%d", &x) == 1) {
1740                         maxgreet = x;
1741                 } else {
1742                         ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1743                 }
1744         }
1745         if (chan->_state != AST_STATE_UP)
1746                 ast_answer(chan);
1747
1748         if (strlen(data)) {
1749                 strncpy(tmp, data, sizeof(tmp) - 1);
1750                 ext = tmp;
1751
1752                 switch (*ext) {
1753                         case 's':
1754                  /* We should skip the user's password */
1755                                 valid++;
1756                                 ext++;
1757                                 break;
1758                         case 'p':
1759                  /* We should prefix the mailbox with the supplied data */
1760                                 prefix++;
1761                                 ext++;
1762                                 break;
1763                 }
1764
1765
1766                 if (prefix)
1767                         strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1768                 else
1769                         strncpy(username, ext, sizeof(username) - 1);
1770                 /* make sure username passed as an option is valid */
1771                 if (ast_variable_retrieve(cfg, NULL, username)) 
1772                         skipuser++;
1773                 else
1774                         valid = 0;
1775
1776         }
1777
1778         /* If ADSI is supported, setup login screen */
1779         adsi_begin(chan, &useadsi);
1780         if (!skipuser && useadsi)
1781                 adsi_login(chan);
1782         if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1783                 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1784                 goto out;
1785         }
1786         
1787         /* Authenticate them and get their mailbox/password */
1788         
1789         while (!valid) {
1790                 /* Prompt for, and read in the username */
1791                 if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) {
1792                         ast_log(LOG_WARNING, "Couldn't read username\n");
1793                         goto out;
1794                 }
1795                 if (!strlen(username)) {
1796                         if (option_verbose > 2)
1797                                 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1798                         res = 0;
1799                         goto out;
1800                 }
1801                 if (useadsi)
1802                         adsi_password(chan);
1803                 if (ast_streamfile(chan, "vm-password", chan->language)) {
1804                         ast_log(LOG_WARNING, "Unable to stream password file\n");
1805                         goto out;
1806                 }
1807                 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1808                         ast_log(LOG_WARNING, "Unable to read password\n");
1809                         goto out;
1810                 }
1811                 if (prefix) {
1812                         char fullusername[80] = "";
1813                         strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1814                         strncat(fullusername, username, sizeof(fullusername) - 1);
1815                         strncpy(username, fullusername, sizeof(username) - 1);
1816                 }
1817                 copy = ast_variable_retrieve(cfg, NULL, username);
1818                 if (copy) {
1819                         char *stringp=NULL;
1820                         copy = strdup(copy);
1821                         stringp=copy;
1822                         strsep(&stringp, ",");
1823                         if (!strcmp(password,copy))
1824                                 valid++;
1825                         else {
1826                                 if (option_verbose > 2)
1827                                         ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1828                                 if (prefix)
1829                                         strncpy(username, empty, sizeof(username) -1);
1830                         }
1831                         free(copy);
1832                 } else {
1833                         skipuser = 0;
1834                         if (option_verbose > 2)
1835                                 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1836                 }
1837                 if (!valid) {
1838                         if (useadsi)
1839                                 adsi_login(chan);
1840                         if (ast_streamfile(chan, "vm-incorrect", chan->language))
1841                                 break;
1842 #if 0
1843                         if (ast_waitstream(chan, ""))
1844                                 break;
1845 #endif
1846                 }
1847         }
1848
1849         if (valid) {
1850                 snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1851                 mkdir(curdir, 0700);
1852                 OPEN_MAILBOX(1);
1853                 oldmessages = lastmsg + 1;
1854                 /* Start in INBOX */
1855                 OPEN_MAILBOX(0);
1856                 newmessages = lastmsg + 1;
1857                 
1858
1859                 /* Select proper mailbox FIRST!! */
1860                 if (!newmessages && oldmessages) {
1861                         /* If we only have old messages start here */
1862                         OPEN_MAILBOX(1);
1863                 }
1864
1865                 if (useadsi)
1866                         adsi_status(chan, newmessages, oldmessages, lastmsg);
1867
1868                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1869                 if (newmessages) {
1870                         WAITCMD(say_and_wait(chan, newmessages));
1871                         WAITCMD(play_and_wait(chan, "vm-INBOX"));
1872
1873                         if (oldmessages)
1874                                 WAITCMD(play_and_wait(chan, "vm-and"));
1875                         else {
1876                                 if (newmessages == 1)
1877                                         WAITCMD(play_and_wait(chan, "vm-message"));
1878                                 else
1879                                         WAITCMD(play_and_wait(chan, "vm-messages"));
1880                         }
1881                                 
1882                 }
1883                 if (oldmessages) {
1884                         WAITCMD(say_and_wait(chan, oldmessages));
1885                         WAITCMD(play_and_wait(chan, "vm-Old"));
1886                         if (oldmessages == 1)
1887                                 WAITCMD(play_and_wait(chan, "vm-message"));
1888                         else
1889                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1890                 }
1891                 if (!oldmessages && !newmessages) {
1892                         WAITCMD(play_and_wait(chan, "vm-no"));
1893                         WAITCMD(play_and_wait(chan, "vm-messages"));
1894                 }
1895                 repeats = 0;
1896                 starting = 1;
1897 instructions:
1898                 if (starting) {
1899                         if (lastmsg > -1) {
1900                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
1901                                 WAITCMD(play_and_wait(chan, vmbox));
1902                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1903                         }
1904                         WAITCMD(play_and_wait(chan, "vm-opts"));
1905                 } else {
1906                         if (curmsg)
1907                                 WAITCMD(play_and_wait(chan, "vm-prev"));
1908                         WAITCMD(play_and_wait(chan, "vm-repeat"));
1909                         if (curmsg != lastmsg)
1910                                 WAITCMD(play_and_wait(chan, "vm-next"));
1911                         if (!deleted[curmsg])
1912                                 WAITCMD(play_and_wait(chan, "vm-delete"));
1913                         else
1914                                 WAITCMD(play_and_wait(chan, "vm-undelete"));
1915                         WAITCMD(play_and_wait(chan, "vm-toforward"));
1916                         WAITCMD(play_and_wait(chan, "vm-savemessage"));
1917                 }
1918                 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1919                 d = ast_waitfordigit(chan, 6000);
1920                 if (d < 0)
1921                         goto out;
1922                 if (!d) {
1923                         repeats++;
1924                         if (repeats > 2) {
1925                                 play_and_wait(chan, "vm-goodbye");
1926                                 goto out;
1927                         }
1928                         goto instructions;
1929                 }
1930 cmd:
1931                 switch(d) {
1932                 case '2':
1933                         if (useadsi)
1934                                 adsi_folders(chan, 0, "Change to folder...");
1935                         box = play_and_wait(chan, "vm-changeto");
1936                         if (box < 0)
1937                                 goto out;
1938                         while((box < '0') || (box > '9')) {
1939                                 box = get_folder(chan, 0);
1940                                 if (box < 0)
1941                                         goto out;
1942                                 if (box == '#')
1943                                         goto instructions;
1944                         } 
1945                         box = box - '0';
1946                         CLOSE_MAILBOX;
1947                         OPEN_MAILBOX(box);
1948                         if (useadsi)
1949                                 adsi_status2(chan, curbox, lastmsg + 1);
1950                         WAITCMD(play_and_wait(chan, vmbox));
1951                         WAITCMD(play_and_wait(chan, "vm-messages"));
1952                         starting = 1;
1953                         goto instructions;
1954                 case '4':
1955                         if (curmsg) {
1956                                 curmsg--;
1957                                 PLAYMSG(curmsg);
1958                         } else {
1959                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1960                                 goto instructions;
1961                         }
1962                 case '1':
1963                                 curmsg = 0;
1964                                 /* Fall through */
1965                 case '5':
1966                         if (lastmsg > -1) {
1967                                 PLAYMSG(curmsg);
1968                         } else {
1969                                 WAITCMD(play_and_wait(chan, "vm-youhave"));
1970                                 WAITCMD(play_and_wait(chan, "vm-no"));
1971                                 snprintf(fn, sizeof(fn), "vm-%s", curbox);
1972                                 WAITCMD(play_and_wait(chan, fn));
1973                                 WAITCMD(play_and_wait(chan, "vm-messages"));
1974                                 goto instructions;
1975                         }
1976                 case '6':
1977                         if (curmsg < lastmsg) {
1978                                 curmsg++;
1979                                 PLAYMSG(curmsg);
1980                         } else {
1981                                 WAITCMD(play_and_wait(chan, "vm-nomore"));
1982                                 goto instructions;
1983                         }
1984                 case '7':
1985                         deleted[curmsg] = !deleted[curmsg];
1986                         if (useadsi)
1987                                 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
1988                         if (deleted[curmsg]) 
1989                                 WAITCMD(play_and_wait(chan, "vm-deleted"));
1990                         else
1991                                 WAITCMD(play_and_wait(chan, "vm-undeleted"));
1992                         goto instructions;
1993                 case '8':
1994                         if(lastmsg > -1)
1995                                 if(forward_message(chan, cfg, curdir, curmsg, username) < 0)
1996                                         goto out;
1997                         goto instructions;
1998                 case '9':
1999                         if (useadsi)
2000                                 adsi_folders(chan, 1, "Save to folder...");
2001                         box = play_and_wait(chan, "vm-savefolder");
2002                         if (box < 0)
2003                                 goto out;
2004                         while((box < '1') || (box > '9')) {
2005                                 box = get_folder(chan, 1);
2006                                 if (box < 0)
2007                                         goto out;
2008                                 if (box == '#')
2009                                         goto instructions;
2010                         } 
2011                         box = box - '0';
2012                         if (option_debug)
2013                                 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
2014                         if (save_to_folder(curdir, curmsg, username, box))
2015                                 goto out;
2016                         deleted[curmsg]=1;
2017                         make_file(fn, sizeof(fn), curdir, curmsg);
2018                         if (useadsi)
2019                                 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
2020                         WAITCMD(play_and_wait(chan, "vm-message"));
2021                         WAITCMD(say_and_wait(chan, curmsg + 1) );
2022                         WAITCMD(play_and_wait(chan, "vm-savedto"));
2023                         snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
2024                         WAITCMD(play_and_wait(chan, fn));
2025                         WAITCMD(play_and_wait(chan, "vm-messages"));
2026                         goto instructions;
2027                 case '*':
2028                         if (!starting) {
2029                                 WAITCMD(play_and_wait(chan, "vm-onefor"));
2030                                 WAITCMD(play_and_wait(chan, vmbox));
2031                                 WAITCMD(play_and_wait(chan, "vm-messages"));
2032                                 WAITCMD(play_and_wait(chan, "vm-opts"));
2033                         }
2034                         goto instructions;
2035                 case '#':
2036                         ast_stopstream(chan);
2037                         adsi_goodbye(chan);
2038                         play_and_wait(chan, "vm-goodbye");
2039                         res = 0;
2040                         goto out2;
2041
2042                 case '0':
2043                         goto vm_options;
2044
2045                 default:
2046                         goto instructions;
2047                 }
2048         }
2049 out:
2050         adsi_goodbye(chan);
2051 out2:
2052         CLOSE_MAILBOX;
2053         ast_stopstream(chan);
2054         if (cfg)
2055                 ast_destroy(cfg);
2056         if (useadsi)
2057                 adsi_unload_session(chan);
2058         if (valid) {
2059                 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
2060         }
2061         LOCAL_USER_REMOVE(u);
2062         return res;
2063
2064 vm_options:
2065         d = play_and_wait(chan,"vm-options");
2066         if (!d)
2067                 d = ast_waitfordigit(chan,6000);
2068         if (d < 0)
2069                 goto out;
2070         switch (d) {
2071                 
2072                 case '1':
2073                         snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username);
2074                         play_and_record(chan,"vm-rec-unv",prefile, maxgreet);
2075                         break;
2076                 case '2': 
2077                         snprintf(prefile,sizeof(prefile),"vm/%s/busy",username);
2078                         play_and_record(chan,"vm-rec-busy",prefile, maxgreet);
2079                         break;
2080                 case '3': 
2081                         snprintf(prefile,sizeof(prefile),"vm/%s/greet",username);
2082                         play_and_record(chan,"vm-rec-name",prefile, maxgreet);
2083                         break;
2084                 case '4':
2085                         newpassword[1] = '\0';
2086                         newpassword[0] = play_and_wait(chan,"vm-newpassword");
2087                         if (ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#") < 0) {
2088                                 play_and_wait(chan, "vm-sorry");
2089                                 ast_log(LOG_NOTICE,"Unable to read new password\n");
2090                                 goto vm_options;
2091             }
2092                         newpassword2[1] = '\0';
2093                         newpassword2[0] = play_and_wait(chan,"vm-reenterpassword");
2094
2095                         if (ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#") < 0) {
2096                                 play_and_wait(chan, "vm-sorry");
2097                                 ast_log(LOG_NOTICE,"Unable to read re-entered password\n");
2098                                 goto vm_options;
2099             }
2100                         if (strcmp(newpassword, newpassword2)) {
2101                                 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", username, newpassword, newpassword2);
2102                                 play_and_wait(chan, "vm-mismatch");
2103                                 goto vm_options;
2104                         }
2105                         if (vm_change_password(username,password,newpassword) < 0)
2106                         {
2107                                 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",username);
2108                         } else
2109                 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",username,newpassword,strlen(newpassword));
2110                         play_and_wait(chan,"vm-passchanged");
2111                         break;
2112                 case '*': 
2113                         goto instructions;
2114
2115                 default: 
2116                         goto vm_options;
2117                  }
2118         goto vm_options;
2119 }
2120
2121 static int vm_exec(struct ast_channel *chan, void *data)
2122 {
2123         int res=0, silent=0, busy=0, unavail=0;
2124         struct localuser *u;
2125         char tmp[256], *ext;
2126         
2127         LOCAL_USER_ADD(u);
2128         if (chan->_state != AST_STATE_UP)
2129                 ast_answer(chan);
2130         if (data)
2131                 strncpy(tmp, data, sizeof(tmp) - 1);
2132         else {
2133                 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2134                 if (res < 0)
2135                         return res;
2136                 if (!strlen(tmp))
2137                         return 0;
2138         }
2139         ext = tmp;
2140         if (*ext == 's') {
2141                 silent++;
2142                 ext++;
2143         } else if (*ext == 'b') {
2144                 busy++;
2145                 ext++;
2146         } else if (*ext == 'u') {
2147                 unavail++;
2148                 ext++;
2149         }
2150         res = leave_voicemail(chan, ext, silent, busy, unavail);
2151         LOCAL_USER_REMOVE(u);
2152         return res;
2153 }
2154
2155 int unload_module(void)
2156 {
2157         int res;
2158         STANDARD_HANGUP_LOCALUSERS;
2159         res = ast_unregister_application(app);
2160         res |= ast_unregister_application(app2);
2161         return res;
2162 }
2163
2164 int load_module(void)
2165 {
2166         int res;
2167         res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2168         if (!res)
2169                 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2170         return res;
2171 }
2172
2173 char *description(void)
2174 {
2175         return tdesc;
2176 }
2177
2178 int usecount(void)
2179 {
2180         int res;
2181         STANDARD_USECOUNT(res);
2182         return res;
2183 }
2184
2185 char *key()
2186 {
2187         return ASTERISK_GPL_KEY;
2188 }