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