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