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