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