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