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