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