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