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