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