Change in-memory password when changing password
[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_closestream(others[x]);
682         }
683         if (outmsg) {
684                 if (outmsg > 1) {
685                 /* Let them know it worked */
686                         ast_streamfile(chan, "vm-msgsaved", chan->language);
687                         ast_waitstream(chan, "");
688                 }
689         }       
690
691         
692         return res;
693 }
694
695 static void free_user(struct ast_vm_user *vmu)
696 {
697         if (vmu->alloced)
698                 free(vmu);
699 }
700
701 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
702 {
703         char comment[256];
704         char txtfile[256];
705         FILE *txt;
706         int res = 0;
707         int msgnum;
708         int maxmessage=0;
709         char date[256];
710         char dir[256];
711         char fn[256];
712         char prefile[256]="";
713         char fmt[80];
714         char *context;
715         char *ecodes = "#";
716         char *stringp;
717         time_t start;
718         time_t end;
719 #if 0
720         /* XXX Need to be moved to play_and_record */
721         struct ast_dsp *sildet;         /* silence detector dsp */
722         int totalsilence = 0;
723         int dspsilence = 0;
724         int gotsilence = 0;             /* did we timeout for silence? */
725 #endif  
726
727         char tmp[256] = "";
728         struct ast_vm_user *vmu;
729         struct ast_vm_user svm;
730         
731         strncpy(tmp, ext, sizeof(tmp) - 1);
732         ext = tmp;
733         context = strchr(tmp, '@');
734         if (context) {
735                 *context = '\0';
736                 context++;
737         }
738
739         if ((vmu = find_user(&svm, context, ext))) {
740                 /* Setup pre-file if appropriate */
741                 if (busy)
742                         snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
743                 else if (unavail)
744                         snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
745                 make_dir(dir, sizeof(dir), vmu->context, "", "");
746                 /* It's easier just to try to make it than to check for its existence */
747                 if (mkdir(dir, 0700) && (errno != EEXIST))
748                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
749                 make_dir(dir, sizeof(dir), vmu->context, ext, "");
750                 /* It's easier just to try to make it than to check for its existence */
751                 if (mkdir(dir, 0700) && (errno != EEXIST))
752                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
753                 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
754                 if (mkdir(dir, 0700) && (errno != EEXIST))
755                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
756                 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
757                         ecodes = "#0";
758                 /* Play the beginning intro if desired */
759                 if (strlen(prefile)) {
760                         if (ast_fileexists(prefile, NULL, NULL) > 0) {
761                                 if (ast_streamfile(chan, prefile, chan->language) > -1) 
762                                     res = ast_waitstream(chan, "#0");
763                         } else {
764                                 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
765                                 res = invent_message(chan, vmu->context, ext, busy, ecodes);
766                         }
767                         if (res < 0) {
768                                 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
769                                 free_user(vmu);
770                                 return -1;
771                         }
772                 }
773                 if (res == '#') {
774                         /* On a '#' we skip the instructions */
775                         silent = 1;
776                         res = 0;
777                 }
778                 if (!res && !silent) {
779                         res = ast_streamfile(chan, INTRO, chan->language);
780                         if (!res)
781                                 res = ast_waitstream(chan, ecodes);
782                         if (res == '#') {
783                                 silent = 1;
784                                 res = 0;
785                         }
786                 }
787                 /* Check for a '0' here */
788                 if (res == '0') {
789                         strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
790                         if (strlen(chan->macrocontext))
791                                 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
792                         chan->priority = 0;
793                         free_user(vmu);
794                         return 0;
795                 }
796                 if (res >= 0) {
797                         /* Unless we're *really* silent, try to send the beep */
798                         res = ast_streamfile(chan, "beep", chan->language);
799                         if (!res)
800                                 res = ast_waitstream(chan, "");
801                 }
802                 if (res < 0) {
803                         free_user(vmu);
804                         return -1;
805                 }
806                 /* The meat of recording the message...  All the announcements and beeps have been played*/
807                 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
808                 if (strlen(fmt)) {
809                         msgnum = 0;
810                         do {
811                                 make_file(fn, sizeof(fn), dir, msgnum);
812                                 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
813                                                                         (chan->callerid ? chan->callerid : "Unknown"), 
814                                                                         vmu->fullname, ext, chan->name);
815                                 if (ast_fileexists(fn, NULL, chan->language) <= 0) 
816                                         break;
817                                 msgnum++;
818                         } while(msgnum < MAXMSG);
819                         if (msgnum < MAXMSG) {
820                                 /* Store information */
821                                 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
822                                 txt = fopen(txtfile, "w+");
823                                 if (txt) {
824                                         get_date(date, sizeof(date));
825                                         time(&start);
826                                         fprintf(txt, 
827 ";\n"
828 "; Message Information file\n"
829 ";\n"
830 "[message]\n"
831 "origmailbox=%s\n"
832 "context=%s\n"
833 "exten=%s\n"
834 "priority=%d\n"
835 "callerchan=%s\n"
836 "callerid=%s\n"
837 "origdate=%s\n"
838 "origtime=%ld\n",
839         ext,
840         chan->context,
841         chan->exten,
842         chan->priority,
843         chan->name,
844         chan->callerid ? chan->callerid : "Unknown",
845         date, time(NULL));
846                                         fclose(txt);
847                                 } else
848                                         ast_log(LOG_WARNING, "Error opening text file for output\n");
849                                 res = play_and_record(chan, NULL, fn, maxmessage, fmt);
850                                 if (res > 0)
851                                         res = 0;
852                                 txt = fopen(txtfile, "a");
853                                 if (txt) {
854                                         time(&end);
855                                         fprintf(txt, "duration=%ld\n", end-start);
856                                         fclose(txt);
857                                 }
858                                 stringp = fmt;
859                                 strsep(&stringp, "|");
860                                 /* Send e-mail if applicable */
861                                 if (strlen(vmu->email))
862                                         sendmail(serveremail, vmu->email, vmu->fullname, msgnum, ext, chan->callerid, fn, fmt, end - start);
863                                 if (strlen(vmu->pager))
864                                         sendpage(serveremail, vmu->pager, msgnum, ext, chan->callerid, end - start);
865                         } else
866                                 ast_log(LOG_WARNING, "No more messages possible\n");
867                 } else
868                         ast_log(LOG_WARNING, "No format for saving voicemail?\n");
869         
870 #if 0
871                                                 sildet = ast_dsp_new(); //Create the silence detector
872                                                 if (silence > 0) {
873                                                         rfmt = chan->readformat;
874                                                         res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
875                                                         if (res < 0) {
876                                                                 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
877                                                                 return -1;
878                                                         }
879                                                         if (!sildet) {
880                                                                 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
881                                                                 return -1;
882                                                         }
883                                                         ast_dsp_set_threshold(sildet, 50);
884                                                 }
885 #endif                                          
886                 free_user(vmu);
887         } else
888                 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
889         /* Leave voicemail for someone */
890         manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
891         return res;
892 }
893
894 static char *mbox(int id)
895 {
896         switch(id) {
897         case 0:
898                 return "INBOX";
899         case 1:
900                 return "Old";
901         case 2:
902                 return "Work";
903         case 3:
904                 return "Family";
905         case 4:
906                 return "Friends";
907         case 5:
908                 return "Cust1";
909         case 6:
910                 return "Cust2";
911         case 7:
912                 return "Cust3";
913         case 8:
914                 return "Cust4";
915         case 9:
916                 return "Cust5";
917         default:
918                 return "Unknown";
919         }
920 }
921
922 static int count_messages(char *dir)
923 {
924         int x;
925         char fn[256];
926         for (x=0;x<MAXMSG;x++) {
927                 make_file(fn, sizeof(fn), dir, x);
928                 if (ast_fileexists(fn, NULL, NULL) < 1)
929                         break;
930         }
931         return x;
932 }
933
934 static int say_and_wait(struct ast_channel *chan, int num)
935 {
936         int d;
937         d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
938         return d;
939 }
940
941 static int copy(char *infile, char *outfile)
942 {
943         int ifd;
944         int ofd;
945         int res;
946         int len;
947         char buf[4096];
948         if ((ifd = open(infile, O_RDONLY)) < 0) {
949                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
950                 return -1;
951         }
952         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
953                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
954                 close(ifd);
955                 return -1;
956         }
957         do {
958                 len = read(ifd, buf, sizeof(buf));
959                 if (len < 0) {
960                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
961                         close(ifd);
962                         close(ofd);
963                         unlink(outfile);
964                 }
965                 if (len) {
966                         res = write(ofd, buf, len);
967                         if (res != len) {
968                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
969                                 close(ifd);
970                                 close(ofd);
971                                 unlink(outfile);
972                         }
973                 }
974         } while(len);
975         close(ifd);
976         close(ofd);
977         return 0;
978 }
979
980 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
981 {
982         char sfn[256];
983         char dfn[256];
984         char ddir[256];
985         char txt[256];
986         char ntxt[256];
987         char *dbox = mbox(box);
988         int x;
989         make_file(sfn, sizeof(sfn), dir, msg);
990         make_dir(ddir, sizeof(ddir), context, username, dbox);
991         mkdir(ddir, 0700);
992         for (x=0;x<MAXMSG;x++) {
993                 make_file(dfn, sizeof(dfn), ddir, x);
994                 if (ast_fileexists(dfn, NULL, NULL) < 0)
995                         break;
996         }
997         if (x >= MAXMSG)
998                 return -1;
999         ast_filecopy(sfn, dfn, NULL);
1000         if (strcmp(sfn, dfn)) {
1001                 snprintf(txt, sizeof(txt), "%s.txt", sfn);
1002                 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
1003                 copy(txt, ntxt);
1004         }
1005         return 0;
1006 }
1007
1008 static int adsi_logo(unsigned char *buf)
1009 {
1010         int bytes = 0;
1011         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
1012         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
1013         return bytes;
1014 }
1015
1016 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
1017 {
1018         char buf[256];
1019         int bytes=0;
1020         int x;
1021         char num[5];
1022
1023         *useadsi = 0;
1024         bytes += adsi_data_mode(buf + bytes);
1025         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1026
1027         bytes = 0;
1028         bytes += adsi_logo(buf);
1029         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1030 #ifdef DISPLAY
1031         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
1032 #endif
1033         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1034         bytes += adsi_data_mode(buf + bytes);
1035         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1036
1037         if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1038                 bytes = 0;
1039                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1040                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1041                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1042                 bytes += adsi_voice_mode(buf + bytes, 0);
1043                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1044                 return 0;
1045         }
1046
1047 #ifdef DISPLAY
1048         /* Add a dot */
1049         bytes = 0;
1050         bytes += adsi_logo(buf);
1051         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1052         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
1053         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1054         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1055 #endif
1056         bytes = 0;
1057         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1058         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1059         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1060         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
1061         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1062         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1063         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1064
1065 #ifdef DISPLAY
1066         /* Add another dot */
1067         bytes = 0;
1068         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
1069         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1070         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1071 #endif
1072
1073         bytes = 0;
1074         /* These buttons we load but don't use yet */
1075         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1076         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1077         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1078         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1079         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1080         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1081         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1082
1083 #ifdef DISPLAY
1084         /* Add another dot */
1085         bytes = 0;
1086         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
1087         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1088         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1089 #endif
1090
1091         bytes = 0;
1092         for (x=0;x<5;x++) {
1093                 snprintf(num, sizeof(num), "%d", x);
1094                 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1095         }
1096         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1097         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1098
1099 #ifdef DISPLAY
1100         /* Add another dot */
1101         bytes = 0;
1102         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
1103         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1104         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1105 #endif
1106
1107         if (adsi_end_download(chan)) {
1108                 bytes = 0;
1109                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1110                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1111                 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1112                 bytes += adsi_voice_mode(buf + bytes, 0);
1113                 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1114                 return 0;
1115         }
1116         bytes = 0;
1117         bytes += adsi_download_disconnect(buf + bytes);
1118         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1119
1120         ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1121
1122 #ifdef DISPLAY
1123         /* Add last dot */
1124         bytes = 0;
1125         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
1126         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1127 #endif
1128         ast_log(LOG_DEBUG, "Restarting session...\n");
1129
1130         bytes = 0;
1131         /* Load the session now */
1132         if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1133                 *useadsi = 1;
1134                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1135         } else
1136                 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1137
1138         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1139         return 0;
1140 }
1141
1142 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1143 {
1144         int x;
1145         if (!adsi_available(chan))
1146           return;
1147         x = adsi_load_session(chan, adapp, adver, 1);
1148         if (x < 0)
1149                 return;
1150         if (!x) {
1151                 if (adsi_load_vmail(chan, useadsi)) {
1152                         ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1153                         return;
1154                 }
1155         } else
1156                 *useadsi = 1;
1157 }
1158
1159 static void adsi_login(struct ast_channel *chan)
1160 {
1161         char buf[256];
1162         int bytes=0;
1163         unsigned char keys[8];
1164         int x;
1165         if (!adsi_available(chan))
1166                 return;
1167
1168         for (x=0;x<8;x++)
1169                 keys[x] = 0;
1170         /* Set one key for next */
1171         keys[3] = ADSI_KEY_APPS + 3;
1172
1173         bytes += adsi_logo(buf + bytes);
1174         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1175         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1176         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1177         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1178         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1179         bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1180         bytes += adsi_set_keys(buf + bytes, keys);
1181         bytes += adsi_voice_mode(buf + bytes, 0);
1182         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1183 }
1184
1185 static void adsi_password(struct ast_channel *chan)
1186 {
1187         char buf[256];
1188         int bytes=0;
1189         unsigned char keys[8];
1190         int x;
1191         if (!adsi_available(chan))
1192                 return;
1193
1194         for (x=0;x<8;x++)
1195                 keys[x] = 0;
1196         /* Set one key for next */
1197         keys[3] = ADSI_KEY_APPS + 3;
1198
1199         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1200         bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1201         bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1202         bytes += adsi_set_keys(buf + bytes, keys);
1203         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1204 }
1205
1206 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1207 {
1208         char buf[256];
1209         int bytes=0;
1210         unsigned char keys[8];
1211         int x,y;
1212
1213         if (!adsi_available(chan))
1214                 return;
1215
1216         for (x=0;x<5;x++) {
1217                 y = ADSI_KEY_APPS + 12 + start + x;
1218                 if (y > ADSI_KEY_APPS + 12 + 4)
1219                         y = 0;
1220                 keys[x] = ADSI_KEY_SKT | y;
1221         }
1222         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1223         keys[6] = 0;
1224         keys[7] = 0;
1225
1226         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1227         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1228         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1229         bytes += adsi_set_keys(buf + bytes, keys);
1230         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1231 }
1232
1233 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1234 {
1235         int bytes=0;
1236         char buf[256], buf1[256], buf2[256];
1237         char fn2[256];
1238         char cid[256]="";
1239         char *val;
1240         char *name, *num;
1241         char datetime[21]="";
1242         FILE *f;
1243
1244         unsigned char keys[8];
1245
1246         int x;
1247
1248         if (!adsi_available(chan))
1249                 return;
1250
1251         /* Retrieve important info */
1252         snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1253         f = fopen(fn2, "r");
1254         if (f) {
1255                 while(!feof(f)) {       
1256                         fgets(buf, sizeof(buf), f);
1257                         if (!feof(f)) {
1258                                 char *stringp=NULL;
1259                                 stringp=buf;
1260                                 strsep(&stringp, "=");
1261                                 val = strsep(&stringp, "=");
1262                                 if (val && strlen(val)) {
1263                                         if (!strcmp(buf, "callerid"))
1264                                                 strncpy(cid, val, sizeof(cid) - 1);
1265                                         if (!strcmp(buf, "origdate"))
1266                                                 strncpy(datetime, val, sizeof(datetime) - 1);
1267                                 }
1268                         }
1269                 }
1270                 fclose(f);
1271         }
1272         /* New meaning for keys */
1273         for (x=0;x<5;x++)
1274                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1275         keys[6] = 0x0;
1276         keys[7] = 0x0;
1277
1278         if (!msg) {
1279                 /* No prev key, provide "Folder" instead */
1280                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1281         }
1282         if (msg >= last) {
1283                 /* If last message ... */
1284                 if (msg) {
1285                         /* but not only message, provide "Folder" instead */
1286                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1287                 } else {
1288                         /* Otherwise if only message, leave blank */
1289                         keys[3] = 1;
1290                 }
1291         }
1292
1293         if (strlen(cid)) {
1294                 ast_callerid_parse(cid, &name, &num);
1295                 if (!name)
1296                         name = num;
1297         } else
1298                 name = "Unknown Caller";
1299
1300         /* If deleted, show "undeleted" */
1301         if (deleted)
1302                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1303
1304         /* Except "Exit" */
1305         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1306         snprintf(buf1, sizeof(buf1), "%s%s", folder,
1307                  strcasecmp(folder, "INBOX") ? " Messages" : "");
1308         snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1309
1310         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1311         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1312         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1313         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1314         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1315         bytes += adsi_set_keys(buf + bytes, keys);
1316         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1317 }
1318
1319 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1320 {
1321         int bytes=0;
1322         char buf[256];
1323         unsigned char keys[8];
1324
1325         int x;
1326
1327         if (!adsi_available(chan))
1328                 return;
1329
1330         /* New meaning for keys */
1331         for (x=0;x<5;x++)
1332                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1333
1334         keys[6] = 0x0;
1335         keys[7] = 0x0;
1336
1337         if (!msg) {
1338                 /* No prev key, provide "Folder" instead */
1339                 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1340         }
1341         if (msg >= last) {
1342                 /* If last message ... */
1343                 if (msg) {
1344                         /* but not only message, provide "Folder" instead */
1345                         keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1346                 } else {
1347                         /* Otherwise if only message, leave blank */
1348                         keys[3] = 1;
1349                 }
1350         }
1351
1352         /* If deleted, show "undeleted" */
1353         if (deleted) 
1354                 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1355
1356         /* Except "Exit" */
1357         keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1358         bytes += adsi_set_keys(buf + bytes, keys);
1359         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1360 }
1361
1362 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1363 {
1364         char buf[256], buf1[256], buf2[256];
1365         int bytes=0;
1366         unsigned char keys[8];
1367         int x;
1368
1369         char *newm = (new == 1) ? "message" : "messages";
1370         char *oldm = (old == 1) ? "message" : "messages";
1371         if (!adsi_available(chan))
1372                 return;
1373         if (new) {
1374                 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1375                 if (old) {
1376                         strcat(buf1, " and");
1377                         snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1378                 } else {
1379                         snprintf(buf2, sizeof(buf2), "%s.", newm);
1380                 }
1381         } else if (old) {
1382                 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1383                 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1384         } else {
1385                 strcpy(buf1, "You have no messages.");
1386                 strcpy(buf2, " ");
1387         }
1388         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1389         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1390         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1391
1392         for (x=0;x<6;x++)
1393                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1394         keys[6] = 0;
1395         keys[7] = 0;
1396
1397         /* Don't let them listen if there are none */
1398         if (lastmsg < 0)
1399                 keys[0] = 1;
1400         bytes += adsi_set_keys(buf + bytes, keys);
1401
1402         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1403 }
1404
1405 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1406 {
1407         char buf[256], buf1[256], buf2[256];
1408         int bytes=0;
1409         unsigned char keys[8];
1410         int x;
1411
1412         char *mess = (messages == 1) ? "message" : "messages";
1413
1414         if (!adsi_available(chan))
1415                 return;
1416
1417         /* Original command keys */
1418         for (x=0;x<6;x++)
1419                 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1420
1421         keys[6] = 0;
1422         keys[7] = 0;
1423
1424         if (messages < 1)
1425                 keys[0] = 0;
1426
1427         snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1428                         strcasecmp(folder, "INBOX") ? " folder" : "");
1429
1430         if (messages)
1431                 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1432         else
1433                 strcpy(buf2, "no messages.");
1434         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1435         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1436         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1437         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1438         bytes += adsi_set_keys(buf + bytes, keys);
1439
1440         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1441         
1442 }
1443
1444 static void adsi_clear(struct ast_channel *chan)
1445 {
1446         char buf[256];
1447         int bytes=0;
1448         if (!adsi_available(chan))
1449                 return;
1450         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1451         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1452 }
1453
1454 static void adsi_goodbye(struct ast_channel *chan)
1455 {
1456         char buf[256];
1457         int bytes=0;
1458
1459         if (!adsi_available(chan))
1460                 return;
1461         bytes += adsi_logo(buf + bytes);
1462         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1463         bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1464         bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1465         adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1466 }
1467
1468 static int get_folder(struct ast_channel *chan, int start)
1469 {
1470         int x;
1471         int d;
1472         char fn[256];
1473         d = play_and_wait(chan, "vm-press");
1474         if (d)
1475                 return d;
1476         for (x = start; x< 5; x++) {
1477                 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1478                         return d;
1479                 d = play_and_wait(chan, "vm-for");
1480                 if (d)
1481                         return d;
1482                 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1483                 d = play_and_wait(chan, fn);
1484                 if (d)
1485                         return d;
1486                 d = play_and_wait(chan, "vm-messages");
1487                 if (d)
1488                         return d;
1489                 d = ast_waitfordigit(chan, 500);
1490                 if (d)
1491                         return d;
1492         }
1493         d = play_and_wait(chan, "vm-tocancel");
1494         if (d)
1495                 return d;
1496         d = ast_waitfordigit(chan, 4000);
1497         return d;
1498 }
1499
1500 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1501 {
1502         int res = 0;
1503         res = play_and_wait(chan, fn);
1504         while (((res < '0') || (res > '9')) &&
1505                         (res != '#') && (res >= 0)) {
1506                 res = get_folder(chan, 0);
1507         }
1508         return res;
1509 }
1510
1511 static int
1512 forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
1513 {
1514         char username[70];
1515         char sys[256];
1516         char todir[256];
1517         int todircount=0;
1518         long duration;
1519         struct ast_config *mif;
1520         char miffile[256];
1521         char fn[256];
1522         char callerid[512];
1523         int res = 0;
1524         struct ast_vm_user *receiver, srec;
1525         char tmp[256];
1526         char *stringp, *s;
1527         
1528         while(!res) {
1529                 res = ast_streamfile(chan, "vm-extension", chan->language);
1530                 if (res)
1531                         break;
1532                 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1533                         break;
1534                 if ((receiver = find_user(&srec, context, username))) {
1535                         printf("Got %d\n", atoi(username));
1536                         /* if (play_and_wait(chan, "vm-savedto"))
1537                                 break;
1538                         */
1539
1540                         snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX",  (char *)ast_config_AST_SPOOL_DIR, receiver->context, username);
1541                         snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1542                         ast_log(LOG_DEBUG, sys);
1543                         system(sys);
1544
1545                         todircount = count_messages(todir);
1546                         strncpy(tmp, fmt, sizeof(tmp));
1547                         stringp = tmp;
1548                         while((s = strsep(&stringp, "|"))) {
1549                                 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
1550                                 ast_log(LOG_DEBUG, sys);
1551                                 system(sys);
1552                         }
1553                         snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1554
1555                         /* load the information on the source message so we can send an e-mail like a new message */
1556                         snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1557                         if ((mif=ast_load(miffile))) {
1558
1559               /* set callerid and duration variables */
1560               snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
1561               duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1562                         
1563                           if (strlen(receiver->email))
1564                             sendmail(serveremail, receiver->email, receiver->fullname, todircount, username, callerid, fn, tmp, atol(ast_variable_retrieve(mif, NULL, "duration")));
1565                                      
1566                           if (strlen(receiver->pager))
1567                                 sendpage(serveremail, receiver->pager, todircount, username, callerid, duration);
1568                           
1569                           ast_destroy(mif); /* or here */
1570                         }
1571
1572                         /* give confirmatopm that the message was saved */
1573                         res = play_and_wait(chan, "vm-message");
1574                         if (!res)
1575                                 res = play_and_wait(chan, "vm-saved");
1576                         free_user(receiver);
1577                         break;
1578                 } else {
1579                         res = play_and_wait(chan, "pbx-invalid");
1580                 }
1581         }
1582         return res;
1583 }
1584
1585 struct vm_state {
1586         char curbox[80];
1587         char username[80];
1588         char curdir[256];
1589         char vmbox[256];
1590         char fn[256];
1591         char fn2[256];
1592         int deleted[MAXMSG];
1593         int heard[MAXMSG];
1594         int curmsg;
1595         int lastmsg;
1596         int newmessages;
1597         int oldmessages;
1598         int starting;
1599         int repeats;
1600 };
1601
1602
1603 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1604 {
1605         int res;
1606         if ((res = ast_streamfile(chan, file, chan->language))) 
1607                 ast_log(LOG_WARNING, "Unable to play message %s\n", file); 
1608         if (!res)
1609                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1610         return res;
1611 }
1612
1613 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) 
1614 {
1615         int res;
1616         if ((res = ast_streamfile(chan, file, chan->language)))
1617                 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1618         if (!res)
1619                 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
1620         return res;
1621 }
1622
1623 static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg)
1624 {
1625         int res = 0;
1626         vms->starting = 0; 
1627         make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1628         adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
1629         if (!msg)
1630                 res = wait_file2(chan, vms, "vm-first");
1631         else if (msg == vms->lastmsg)
1632                 res = wait_file2(chan, vms, "vm-last");
1633         if (!res) {
1634                 res = wait_file2(chan, vms, "vm-message");
1635                 if (msg && (msg != vms->lastmsg)) {
1636                         if (!res)
1637                                 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
1638                 }
1639         }
1640         
1641         if (!res) {
1642                 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1643                 vms->heard[msg] = 1;
1644                 res = wait_file(chan, vms, vms->fn);
1645         }
1646         return res;
1647 }
1648
1649 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
1650 {
1651         strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
1652         make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
1653         vms->lastmsg = count_messages(vms->curdir) - 1;
1654         snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
1655 }
1656
1657 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
1658 {
1659         int x;
1660         char ntxt[256] = "";
1661         char txt[256] = "";
1662         if (vms->lastmsg > -1) { 
1663                 /* Get the deleted messages fixed */ 
1664                 vms->curmsg = -1; 
1665                 for (x=0;x<=vms->lastmsg;x++) { 
1666                         if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) { 
1667                                 /* Save this message.  It's not in INBOX or hasn't been heard */ 
1668                                 vms->curmsg++; 
1669                                 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); 
1670                                 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg); 
1671                                 if (strcmp(vms->fn, vms->fn2)) { 
1672                                         snprintf(txt, sizeof(txt), "%s.txt", vms->fn); 
1673                                         snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2); 
1674                                         ast_filerename(vms->fn, vms->fn2, NULL); 
1675                                         rename(txt, ntxt); 
1676                                 } 
1677                         } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) { 
1678                                 /* Move to old folder before deleting */ 
1679                                 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1); 
1680                         } 
1681                 } 
1682                 for (x = vms->curmsg + 1; x<=vms->lastmsg; x++) { 
1683                         make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); 
1684                         snprintf(txt, sizeof(txt), "%s.txt", vms->fn); 
1685                         ast_filedelete(vms->fn, NULL); 
1686                         unlink(txt); 
1687                 } 
1688         } 
1689         memset(vms->deleted, 0, sizeof(vms->deleted)); 
1690         memset(vms->heard, 0, sizeof(vms->heard)); 
1691 }
1692
1693 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
1694 {
1695         /* Introduce messages they have */
1696         int res;
1697         res = play_and_wait(chan, "vm-youhave");
1698         if (!res) {
1699                 if (vms->newmessages) {
1700                         res = say_and_wait(chan, vms->newmessages);
1701                         if (!res)
1702                                 res = play_and_wait(chan, "vm-INBOX");
1703                         if (vms->oldmessages && !res)
1704                                 res = play_and_wait(chan, "vm-and");
1705                         else if (!res) {
1706                                 if ((vms->newmessages == 1))
1707                                         res = play_and_wait(chan, "vm-message");
1708                                 else
1709                                         res = play_and_wait(chan, "vm-messages");
1710                         }
1711                                 
1712                 }
1713                 if (!res && vms->oldmessages) {
1714                         res = say_and_wait(chan, vms->oldmessages);
1715                         if (!res)
1716                                 res = play_and_wait(chan, "vm-Old");
1717                         if (!res) {
1718                                 if (vms->oldmessages == 1)
1719                                         res = play_and_wait(chan, "vm-message");
1720                                 else
1721                                         res = play_and_wait(chan, "vm-messages");
1722                         }
1723                 }
1724                 if (!res) {
1725                         if (!vms->oldmessages && !vms->newmessages) {
1726                                 res = play_and_wait(chan, "vm-no");
1727                                 if (!res)
1728                                         res = play_and_wait(chan, "vm-messages");
1729                         }
1730                 }
1731         }
1732         return res;
1733 }
1734
1735 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
1736 {
1737         int res = 0;
1738         /* Play instructions and wait for new command */
1739         while(!res) {
1740                 if (vms->starting) {
1741                         if (vms->lastmsg > -1) {
1742                                 res = play_and_wait(chan, "vm-onefor");
1743                                 if (!res)
1744                                         res = play_and_wait(chan, vms->vmbox);
1745                                 if (!res)
1746                                         res = play_and_wait(chan, "vm-messages");
1747                         }
1748                         if (!res)
1749                                 res = play_and_wait(chan, "vm-opts");
1750                 } else {
1751                         if (vms->curmsg)
1752                                 res = play_and_wait(chan, "vm-prev");
1753                         if (!res)
1754                                 res = play_and_wait(chan, "vm-repeat");
1755                         if (!res && (vms->curmsg != vms->lastmsg))
1756                                 res = play_and_wait(chan, "vm-next");
1757                         if (!res) {
1758                                 if (!vms->deleted[vms->curmsg])
1759                                         res = play_and_wait(chan, "vm-delete");
1760                                 else
1761                                         res = play_and_wait(chan, "vm-undelete");
1762                                 if (!res)
1763                                         res = play_and_wait(chan, "vm-toforward");
1764                                 if (!res)
1765                                         res = play_and_wait(chan, "vm-savemessage");
1766                         }
1767                 }
1768                 if (!res)
1769                         res = play_and_wait(chan, "vm-helpexit");
1770                 if (!res)
1771                         res = ast_waitfordigit(chan, 6000);
1772                 if (!res) {
1773                         vms->repeats++;
1774                         if (vms->repeats > 2) {
1775                                 res = play_and_wait(chan, "vm-goodbye");
1776                                 if (!res)
1777                                         res = 't';
1778                         }
1779                 }
1780         }
1781         return res;
1782 }
1783
1784 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
1785 {
1786         int cmd = 0;
1787         int retries = 0;
1788         char newpassword[80] = "";
1789         char newpassword2[80] = "";
1790         char prefile[256]="";
1791         while((cmd >= 0) && (cmd != 't')) {
1792                 if (cmd)
1793                         retries = 0;
1794                 switch (cmd) {
1795                 case '1':
1796                         snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
1797                         cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
1798                         break;
1799                 case '2': 
1800                         snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
1801                         cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
1802                         break;
1803                 case '3': 
1804                         snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
1805                         cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
1806                         break;
1807                 case '4':
1808                         newpassword[1] = '\0';
1809                         newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
1810                         if (cmd < 0)
1811                                 break;
1812                         if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
1813                                 break;
1814             }
1815                         newpassword2[1] = '\0';
1816                         newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
1817                         if (cmd < 0)
1818                                 break;
1819
1820                         if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
1821                                 break;
1822             }
1823                         if (strcmp(newpassword, newpassword2)) {
1824                                 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
1825                                 cmd = play_and_wait(chan, "vm-mismatch");
1826                                 break;
1827                         }
1828                         if (vm_change_password(vmu,newpassword) < 0)
1829                         {
1830                                 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",vms->username);
1831                         } else
1832                 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
1833                         cmd = play_and_wait(chan,"vm-passchanged");
1834                         break;
1835                 case '*': 
1836                         cmd = 't';
1837                         break;
1838                 default: 
1839                         cmd = play_and_wait(chan,"vm-options");
1840                         if (!cmd)
1841                                 cmd = ast_waitfordigit(chan,6000);
1842                         if (!cmd)
1843                                 retries++;
1844                         if (retries > 3)
1845                                 cmd = 't';
1846                  }
1847         }
1848         if (cmd == 't')
1849                 cmd = 0;
1850         return cmd;
1851 }
1852
1853 static int vm_execmain(struct ast_channel *chan, void *data)
1854 {
1855         /* XXX This is, admittedly, some pretty horrendus code.  For some
1856            reason it just seemed a lot easier to do with GOTO's.  I feel
1857            like I'm back in my GWBASIC days. XXX */
1858         int res=-1;
1859         int valid = 0;
1860         int prefix = 0;
1861         int cmd=0;
1862         struct localuser *u;
1863         char prefixstr[80] ="";
1864         char empty[80] = "";
1865         int box;
1866         int useadsi = 0;
1867         int skipuser = 0;
1868         char tmp[256], *ext;
1869         char fmtc[256] = "";
1870         char password[80];
1871         struct vm_state vms;
1872         int logretries = 0;
1873         struct ast_vm_user *vmu = NULL, vmus;
1874         char *context=NULL;
1875
1876         LOCAL_USER_ADD(u);
1877         memset(&vms, 0, sizeof(vms));
1878         strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
1879         if (chan->_state != AST_STATE_UP)
1880                 ast_answer(chan);
1881
1882         if (data && strlen(data)) {
1883                 strncpy(tmp, data, sizeof(tmp) - 1);
1884                 ext = tmp;
1885
1886                 switch (*ext) {
1887                         case 's':
1888                  /* We should skip the user's password */
1889                                 valid++;
1890                                 ext++;
1891                                 break;
1892                         case 'p':
1893                  /* We should prefix the mailbox with the supplied data */
1894                                 prefix++;
1895                                 ext++;
1896                                 break;
1897                 }
1898
1899                 context = strchr(ext, '@');
1900                 if (context) {
1901                         *context = '\0';
1902                         context++;
1903                 }
1904
1905                 if (prefix)
1906                         strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1907                 else
1908                         strncpy(vms.username, ext, sizeof(vms.username) - 1);
1909                 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
1910                         skipuser++;
1911                 else
1912                         valid = 0;
1913
1914         }
1915
1916         /* If ADSI is supported, setup login screen */
1917         adsi_begin(chan, &useadsi);
1918         if (!skipuser && useadsi)
1919                 adsi_login(chan);
1920         if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1921                 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1922                 goto out;
1923         }
1924         
1925         /* Authenticate them and get their mailbox/password */
1926         
1927         while (!valid && (logretries < maxlogins)) {
1928                 /* Prompt for, and read in the username */
1929                 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
1930                         ast_log(LOG_WARNING, "Couldn't read username\n");
1931                         goto out;
1932                 }
1933                 if (!strlen(vms.username)) {
1934                         if (option_verbose > 2)
1935                                 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1936                         res = 0;
1937                         goto out;
1938                 }
1939                 if (useadsi)
1940                         adsi_password(chan);
1941                 if (ast_streamfile(chan, "vm-password", chan->language)) {
1942                         ast_log(LOG_WARNING, "Unable to stream password file\n");
1943                         goto out;
1944                 }
1945                 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1946                         ast_log(LOG_WARNING, "Unable to read password\n");
1947                         goto out;
1948                 }
1949                 if (prefix) {
1950                         char fullusername[80] = "";
1951                         strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1952                         strncat(fullusername, vms.username, sizeof(fullusername) - 1);
1953                         strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
1954                 }
1955                 if (!skipuser) 
1956                         vmu = find_user(&vmus, context, vms.username);
1957                 if (vmu && !strcmp(vmu->password, password)) 
1958                         valid++;
1959                 else {
1960                         if (option_verbose > 2)
1961                                 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
1962                         if (prefix)
1963                                 strncpy(vms.username, empty, sizeof(vms.username) -1);
1964                 }
1965                 if (!valid) {
1966                         if (useadsi)
1967                                 adsi_login(chan);
1968                         if (ast_streamfile(chan, "vm-incorrect", chan->language))
1969                                 break;
1970                 }
1971                 logretries++;
1972         }
1973         if (!valid && (logretries >= maxlogins)) {
1974                 ast_stopstream(chan);
1975                 res = play_and_wait(chan, "vm-goodbye");
1976                 if (res > 0)
1977                         res = 0;
1978         }
1979
1980         if (valid) {
1981                 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
1982                 mkdir(vms.curdir, 0700);
1983                 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
1984                 mkdir(vms.curdir, 0700);
1985                 /* Retrieve old and new message counts */
1986                 open_mailbox(&vms, vmu, 1);
1987                 vms.oldmessages = vms.lastmsg + 1;
1988                 /* Start in INBOX */
1989                 open_mailbox(&vms, vmu, 0);
1990                 vms.newmessages = vms.lastmsg + 1;
1991                 
1992
1993                 /* Select proper mailbox FIRST!! */
1994                 if (!vms.newmessages && vms.oldmessages) {
1995                         /* If we only have old messages start here */
1996                         open_mailbox(&vms, vmu, 1);
1997                 }
1998
1999                 if (useadsi)
2000                         adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2001                 res = 0;
2002                 cmd = vm_intro(chan, &vms);
2003                 vms.repeats = 0;
2004                 vms.starting = 1;
2005                 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2006                         /* Run main menu */
2007                         switch(cmd) {
2008                         case '1':
2009                                 vms.curmsg = 0;
2010                                 /* Fall through */
2011                         case '5':
2012                                 if (vms.lastmsg > -1) {
2013                                         cmd = play_message(chan, &vms, vms.curmsg);
2014                                 } else {
2015                                         cmd = play_and_wait(chan, "vm-youhave");
2016                                         if (!cmd) 
2017                                                 cmd = play_and_wait(chan, "vm-no");
2018                                         if (!cmd) {
2019                                                 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2020                                                 cmd = play_and_wait(chan, vms.fn);
2021                                         }
2022                                         if (!cmd)
2023                                                 cmd = play_and_wait(chan, "vm-messages");
2024                                 }
2025                                 break;
2026                         case '2': /* Change folders */
2027                                 if (useadsi)
2028                                         adsi_folders(chan, 0, "Change to folder...");
2029                                 cmd = get_folder2(chan, "vm-changeto", 0);
2030                                 if (cmd == '#') {
2031                                         cmd = 0;
2032                                 } else if (cmd > 0) {
2033                                         cmd = cmd - '0';
2034                                         close_mailbox(&vms, vmu);
2035                                         open_mailbox(&vms, vmu, cmd);
2036                                         cmd = 0;
2037                                 }
2038                                 if (useadsi)
2039                                         adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2040                                 if (!cmd)
2041                                         cmd = play_and_wait(chan, vms.vmbox);
2042                                 if (!cmd)
2043                                         cmd = play_and_wait(chan, "vm-messages");
2044                                 vms.starting = 1;
2045                                 break;
2046                         case '4':
2047                                 if (vms.curmsg) {
2048                                         vms.curmsg--;
2049                                         cmd = play_message(chan, &vms, vms.curmsg);
2050                                 } else {
2051                                         cmd = play_and_wait(chan, "vm-nomore");
2052                                 }
2053                                 break;
2054                         case '6':
2055                                 if (vms.curmsg < vms.lastmsg) {
2056                                         vms.curmsg++;
2057                                         cmd = play_message(chan, &vms, vms.curmsg);
2058                                 } else {
2059                                         cmd = play_and_wait(chan, "vm-nomore");
2060                                 }
2061                                 break;
2062                         case '7':
2063                                 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2064                                 if (useadsi)
2065                                         adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2066                                 if (vms.deleted[vms.curmsg]) 
2067                                         cmd = play_and_wait(chan, "vm-deleted");
2068                                 else
2069                                         cmd = play_and_wait(chan, "vm-undeleted");
2070                                 break;
2071                         case '8':
2072                                 if(vms.lastmsg > -1)
2073                                         cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2074                                 break;
2075                         case '9':
2076                                 if (useadsi)
2077                                         adsi_folders(chan, 1, "Save to folder...");
2078                                 cmd = get_folder2(chan, "vm-savefolder", 1);
2079                                 box = 0;        /* Shut up compiler */
2080                                 if (cmd == '#') {
2081                                         cmd = 0;
2082                                         break;
2083                                 } else if (cmd > 0) {
2084                                         box = cmd = cmd - '0';
2085                                         cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2086                                         vms.deleted[vms.curmsg]=1;
2087                                 }
2088                                 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2089                                 if (useadsi)
2090                                         adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2091                                 if (!cmd)
2092                                         cmd = play_and_wait(chan, "vm-message");
2093                                 if (!cmd)
2094                                         cmd = say_and_wait(chan, vms.curmsg + 1);
2095                                 if (!cmd)
2096                                         cmd = play_and_wait(chan, "vm-savedto");
2097                                 if (!cmd) {
2098                                         snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2099                                         cmd = play_and_wait(chan, vms.fn);
2100                                 }
2101                                 if (!cmd)
2102                                         cmd = play_and_wait(chan, "vm-messages");
2103                                 break;
2104                         case '*':
2105                                 if (!vms.starting) {
2106                                         cmd = play_and_wait(chan, "vm-onefor");
2107                                         if (!cmd)
2108                                                 cmd = play_and_wait(chan, vms.vmbox);
2109                                         if (!cmd)
2110                                                 cmd = play_and_wait(chan, "vm-messages");
2111                                         if (!cmd)
2112                                                 cmd = play_and_wait(chan, "vm-opts");
2113                                 } else
2114                                         cmd = 0;
2115                                 break;
2116                         case '0':
2117                                 cmd = vm_options(chan, vmu, &vms, vmfmts);
2118                                 break;
2119                         case '#':
2120                                 ast_stopstream(chan);
2121                                 adsi_goodbye(chan);
2122                                 cmd = play_and_wait(chan, "vm-goodbye");
2123                                 if (cmd > 0)
2124                                         cmd = '#';
2125                                 break;
2126                         default:        /* Nothing */
2127                                 cmd = vm_instructions(chan, &vms);
2128                                 break;
2129                         }
2130                 }
2131                 if ((cmd == 't') || (cmd == '#')) {
2132                         /* Timeout */
2133                         res = 0;
2134                 } else {
2135                         /* Hangup */
2136                         res = -1;
2137                 }
2138         }
2139 out:
2140         if (res > -1) {
2141                 ast_stopstream(chan);
2142                 adsi_goodbye(chan);
2143                 if (useadsi)
2144                         adsi_unload_session(chan);
2145         }
2146         if (vmu)
2147                 close_mailbox(&vms, vmu);
2148         if (vmu)
2149                 free_user(vmu);
2150         if (valid) {
2151                 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2152         }
2153         LOCAL_USER_REMOVE(u);
2154         return res;
2155
2156 }
2157
2158 static int vm_exec(struct ast_channel *chan, void *data)
2159 {
2160         int res=0, silent=0, busy=0, unavail=0;
2161         struct localuser *u;
2162         char tmp[256], *ext;
2163         
2164         LOCAL_USER_ADD(u);
2165         if (chan->_state != AST_STATE_UP)
2166                 ast_answer(chan);
2167         if (data)
2168                 strncpy(tmp, data, sizeof(tmp) - 1);
2169         else {
2170                 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2171                 if (res < 0)
2172                         return res;
2173                 if (!strlen(tmp))
2174                         return 0;
2175         }
2176         ext = tmp;
2177         while(*ext) {
2178                 if (*ext == 's') {
2179                         silent = 2;
2180                         ext++;
2181                 } else if (*ext == 'b') {
2182                         busy=1;
2183                         ext++;
2184                 } else if (*ext == 'u') {
2185                         unavail=1;
2186                         ext++;
2187                 } else 
2188                         break;
2189         }
2190         res = leave_voicemail(chan, ext, silent, busy, unavail);
2191         LOCAL_USER_REMOVE(u);
2192         return res;
2193 }
2194
2195 static int append_mailbox(char *context, char *mbox, char *data)
2196 {
2197         /* Assumes lock is already held */
2198         char tmp[256] = "";
2199         char *stringp;
2200         char *s;
2201         struct ast_vm_user *vmu;
2202         strncpy(tmp, data, sizeof(tmp));
2203         vmu = malloc(sizeof(struct ast_vm_user));
2204         if (vmu) {
2205                 memset(vmu, 0, sizeof(struct ast_vm_user));
2206                 strncpy(vmu->context, context, sizeof(vmu->context));
2207                 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2208                 stringp = tmp;
2209                 if ((s = strsep(&stringp, ","))) 
2210                         strncpy(vmu->password, s, sizeof(vmu->password));
2211                 if ((s = strsep(&stringp, ","))) 
2212                         strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2213                 if ((s = strsep(&stringp, ","))) 
2214                         strncpy(vmu->email, s, sizeof(vmu->email));
2215                 if ((s = strsep(&stringp, ","))) 
2216                         strncpy(vmu->pager, s, sizeof(vmu->pager));
2217                 vmu->next = NULL;
2218                 if (usersl)
2219                         usersl->next = vmu;
2220                 else
2221                         users = vmu;
2222                 usersl = vmu;
2223         }
2224         return 0;
2225 }
2226
2227 static int load_users(void)
2228 {
2229         struct ast_vm_user *cur, *l;
2230         struct ast_config *cfg;
2231         char *cat;
2232         struct ast_variable *var;
2233         char *astattach;
2234         char *silencestr;
2235         char *thresholdstr;
2236         char *fmt;
2237         char *astemail;
2238         char *s;
2239         int x;
2240         cfg = ast_load(VOICEMAIL_CONFIG);
2241         ast_pthread_mutex_lock(&vmlock);
2242         cur = users;
2243         while(cur) {
2244                 l = cur;
2245                 cur = cur->next;
2246                 free_user(l);
2247         }
2248         users = NULL;
2249         usersl = NULL;
2250         if (cfg) {
2251                 /* General settings */
2252                 attach_voicemail = 1;
2253                 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach"))) 
2254                         astattach = "yes";
2255                 attach_voicemail = ast_true(astattach);
2256                 maxsilence = 0;
2257                 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2258                         maxsilence = atoi(silencestr);
2259                         if (maxsilence > 0)
2260                                 maxsilence *= 1000;
2261                 }
2262                 
2263                 silencethreshold = 256;
2264                 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2265                         silencethreshold = atoi(thresholdstr);
2266                 
2267                 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) 
2268                         astemail = ASTERISK_USERNAME;
2269                 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2270                 
2271                 vmmaxmessage = 0;
2272                 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2273                         if (sscanf(s, "%d", &x) == 1) {
2274                                 vmmaxmessage = x;
2275                         } else {
2276                                 ast_log(LOG_WARNING, "Invalid max message time length\n");
2277                         }
2278                 }
2279                 fmt = ast_variable_retrieve(cfg, "general", "format");
2280                 if (!fmt)
2281                         fmt = "wav";    
2282                 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2283
2284                 skipms = 3000;
2285                 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2286                         if (sscanf(s, "%d", &x) == 1) {
2287                                 maxgreet = x;
2288                         } else {
2289                                 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2290                         }
2291                 }
2292
2293                 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2294                         if (sscanf(s, "%d", &x) == 1) {
2295                                 skipms = x;
2296                         } else {
2297                                 ast_log(LOG_WARNING, "Invalid skipms value\n");
2298                         }
2299                 }
2300
2301                 maxlogins = 3;
2302                 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
2303                         if (sscanf(s, "%d", &x) == 1) {
2304                                 maxlogins = x;
2305                         } else {
2306                                 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
2307                         }
2308                 }
2309
2310                 cat = ast_category_browse(cfg, NULL);
2311                 while(cat) {
2312                         if (strcasecmp(cat, "general")) {
2313                                 /* Process mailboxes in this context */
2314                                 var = ast_variable_browse(cfg, cat);
2315                                 while(var) {
2316                                         append_mailbox(cat, var->name, var->value);
2317                                         var = var->next;
2318                                 }
2319                         }
2320                         cat = ast_category_browse(cfg, cat);
2321                 }
2322                 ast_destroy(cfg);
2323         }
2324         ast_pthread_mutex_unlock(&vmlock);
2325         return 0;
2326 }
2327
2328 int reload(void)
2329 {
2330         load_users();
2331         return 0;
2332 }
2333
2334 int unload_module(void)
2335 {
2336         int res;
2337         STANDARD_HANGUP_LOCALUSERS;
2338         res = ast_unregister_application(app);
2339         res |= ast_unregister_application(app2);
2340         return res;
2341 }
2342
2343 int load_module(void)
2344 {
2345         int res;
2346         load_users();
2347         res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2348         if (!res)
2349                 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2350         return res;
2351 }
2352
2353 char *description(void)
2354 {
2355         return tdesc;
2356 }
2357
2358 int usecount(void)
2359 {
2360         int res;
2361         STANDARD_USECOUNT(res);
2362         return res;
2363 }
2364
2365 char *key()
2366 {
2367         return ASTERISK_GPL_KEY;
2368 }