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