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