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