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