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