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