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