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