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