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