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