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