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