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