2 * Asterisk -- A telephony toolkit for Linux.
4 * Voicemail System (did you ever think it could be so easy?)
6 * Copyright (C) 2003, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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>
39 #include <sys/types.h>
43 /* we define USESQLVM when we have MySQL or POSTGRES */
45 #include <mysql/mysql.h>
51 * PostgreSQL routines written by Otmar Lendl <lendl@nic.at>
53 #include <postgresql/libpq-fe.h>
58 static inline int sql_init(void) { return 0; }
59 static inline void sql_close(void) { }
62 #include "../asterisk.h"
63 #include "../astconf.h"
65 #define COMMAND_TIMEOUT 5000
67 #define VOICEMAIL_CONFIG "voicemail.conf"
68 #define ASTERISK_USERNAME "asterisk"
70 /* Default mail command to mail voicemail. Change it with the
71 mailcmd= command in voicemail.conf */
72 #define SENDMAIL "/usr/sbin/sendmail -t"
74 #define INTRO "vm-intro"
77 #define MAX_OTHER_FORMATS 10
79 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
81 #define BASEMAXINLINE 256
82 #define BASELINELEN 72
83 #define BASEMAXINLINE 256
86 #define MAX_DATETIME_FORMAT 512
87 #define MAX_NUM_CID_CONTEXTS 10
89 /* Syntaxes supported, not really language codes.
97 German requires the following additional soundfile:
100 Spanish requires the following additional soundfile:
103 Dutch, Portuguese & Spanish require the following additional soundfiles:
104 vm-INBOXs singular of 'new'
105 vm-Olds singular of 'old/heard/read'
124 unsigned char iobuf[BASEMAXINLINE];
127 /* Structure for linked list of users */
129 char context[80]; /* Voicemail context */
130 char mailbox[80]; /* Mailbox id, unique within vm context */
131 char password[80]; /* Secret pin code, numbers only */
132 char fullname[80]; /* Full name, for directory app */
133 char email[80]; /* E-mail address */
134 char pager[80]; /* E-mail address to pager (no attachment) */
135 char serveremail[80]; /* From: Mail address */
136 char mailcmd[160]; /* Configurable mail command */
137 char language[MAX_LANGUAGE]; /* Config: Language setting */
138 char zonetag[80]; /* Time zone */
149 struct ast_vm_user *next;
155 char msg_format[512];
156 struct vm_zone *next;
175 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
176 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
177 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);
178 static int vm_delete(char *file);
182 static char *tdesc = "Comedian Mail (Voicemail System)";
184 static char *adapp = "\x00\x00\x00\x0F";
186 static char *adsec = "\x9B\xDB\xF7\xAC";
188 static char *addesc = "Comedian Mail";
190 static int adver = 1;
192 static char *synopsis_vm =
193 "Leave a voicemail message";
195 static char *descrip_vm =
196 " VoiceMail([s|u|b]extension[@context][&extension[@context]][...]): Leaves"
197 "voicemail for a given extension (must be configured in voicemail.conf).\n"
198 " If the extension is preceded by \n"
199 "* 's' then instructions for leaving the message will be skipped.\n"
200 "* 'u' then the \"unavailable\" message will be played.\n"
201 " (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.\n"
202 "* 'b' then the the busy message will be played (that is, busy instead of unavail).\n"
203 "If the caller presses '0' (zero) during the prompt, the call jumps to\n"
204 "extension 'o' in the current context.\n"
205 "If the caller presses '*' during the prompt, the call jumps to\n"
206 "extension 'a' in the current context.\n"
207 "If the requested mailbox does not exist, and there exists a priority\n"
208 "n + 101, then that priority will be taken next.\n"
209 "When multiple mailboxes are specified, the unavailable or busy message\n"
210 "will be taken from the first mailbox specified.\n"
211 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
212 "Otherwise, it returns 0.\n";
214 static char *synopsis_vmain =
215 "Enter voicemail system";
217 static char *descrip_vmain =
218 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
219 "for the checking of voicemail. The mailbox can be passed as the option,\n"
220 "which will stop the voicemail system from prompting the user for the mailbox.\n"
221 "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
222 "a context is specified, logins are considered in that voicemail context only.\n"
223 "Returns -1 if the user hangs up or 0 otherwise.\n";
225 static char *synopsis_vm_box_exists =
226 "Check if vmbox exists";
228 static char *descrip_vm_box_exists =
229 " MailboxExists(mailbox[@context]): Conditionally branches to priority n+101\n"
230 "if the specified voice mailbox exists.\n";
233 /* Leave a message */
234 static char *capp = "VoiceMail2";
235 static char *app = "VoiceMail";
237 /* Check mail, control, etc */
238 static char *capp2 = "VoiceMailMain2";
239 static char *app2 = "VoiceMailMain";
241 static char *app3 = "MailboxExists";
243 AST_MUTEX_DEFINE_STATIC(vmlock);
244 struct ast_vm_user *users;
245 struct ast_vm_user *usersl;
246 struct vm_zone *zones = NULL;
247 struct vm_zone *zonesl = NULL;
248 static int attach_voicemail;
249 static int maxsilence;
250 static int silencethreshold = 128;
251 static char serveremail[80];
252 static char mailcmd[160]; /* Configurable mail cmd */
253 static char externnotify[160];
255 static char vmfmts[80];
256 static int vmminmessage;
257 static int vmmaxmessage;
260 static int maxlogins;
264 static int saycidinfo;
266 static char dialcontext[80];
267 static char callcontext[80];
268 static char exitcontext[80];
270 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
273 static char *emailbody = NULL;
274 static int pbxskip = 0;
275 static char *emailsubject = NULL;
276 static char fromstring[100];
277 static char emailtitle[100];
278 static char charset[32] = "ISO-8859-1";
285 static void populate_defaults(struct ast_vm_user *vmu)
297 strncpy(vmu->callback, callcontext, sizeof(vmu->callback) -1);
299 strncpy(vmu->dialout, dialcontext, sizeof(vmu->dialout) -1);
301 strncpy(vmu->exit, exitcontext, sizeof(vmu->exit) -1);
304 static void apply_options(struct ast_vm_user *vmu, char *options)
306 /* Destructively Parse options and apply */
307 char *stringp = ast_strdupa(options);
311 while((s = strsep(&stringp, "|"))) {
313 if ((var = strsep(&value, "=")) && value) {
314 if (!strcasecmp(var, "attach")) {
319 } else if (!strcasecmp(var, "serveremail")) {
320 strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
321 } else if (!strcasecmp(var, "language")) {
322 strncpy(vmu->language, value, sizeof(vmu->language) - 1);
323 } else if (!strcasecmp(var, "tz")) {
324 strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
325 } else if (!strcasecmp(var, "delete")) {
326 vmu->delete = ast_true(value);
327 } else if (!strcasecmp(var, "saycid")){
332 } else if (!strcasecmp(var, "review")){
337 } else if (!strcasecmp(var, "operator")){
342 } else if (!strcasecmp(var, "envelope")){
347 } else if (!strcasecmp(var, "callback")) {
348 strncpy(vmu->callback, value, sizeof(vmu->callback) -1);
349 } else if (!strcasecmp(var, "dialout")) {
350 strncpy(vmu->dialout, value, sizeof(vmu->dialout) -1);
351 } else if (!strcasecmp(var, "exitcontext")) {
352 strncpy(vmu->exit, value, sizeof(vmu->exit) -1);
361 #include "mysql-vm-routines.h"
368 AST_MUTEX_DEFINE_STATIC(postgreslock);
370 static int sql_init(void)
372 ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption);
373 /* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */
375 dbhandler=PQconnectdb(dboption);
376 if (PQstatus(dbhandler) == CONNECTION_BAD) {
377 ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler));
380 /* fprintf(stderr,"postgres login OK\n"); */
384 static void sql_close(void)
390 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
398 char options[160] = "";
399 struct ast_vm_user *retval;
401 retval=malloc(sizeof(struct ast_vm_user));
403 /* fprintf(stderr,"postgres find_user:\n"); */
406 memset(retval, 0, sizeof(struct ast_vm_user));
409 strcpy(retval->mailbox, mailbox);
412 strcpy(retval->context, context);
416 strcpy(retval->context, "default");
418 populate_defaults(retval);
419 sprintf(query, "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", retval->context, mailbox);
421 /* fprintf(stderr,"postgres find_user: query = %s\n",query); */
422 ast_mutex_lock(&postgreslock);
423 PGSQLres=PQexec(dbhandler,query);
424 if (PGSQLres!=NULL) {
425 if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
426 PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
427 PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
429 ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres));
432 ast_mutex_unlock(&postgreslock);
436 numFields = PQnfields(PGSQLres);
437 /* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */
438 if (PQntuples(PGSQLres) != 1) {
439 ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox);
441 ast_mutex_unlock(&postgreslock);
445 for (i=0; i<numFields; i++) {
446 fname = PQfname(PGSQLres,i);
447 if (!strcmp(fname, "password") && !PQgetisnull (PGSQLres,0,i)) {
448 strncpy(retval->password, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1);
449 } else if (!strcmp(fname, "fullname")) {
450 strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1);
451 } else if (!strcmp(fname, "email")) {
452 strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1);
453 } else if (!strcmp(fname, "pager")) {
454 strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1);
455 } else if (!strcmp(fname, "options")) {
456 strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1);
457 apply_options(retval, options);
462 ast_mutex_unlock(&postgreslock);
466 ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler));
467 ast_mutex_unlock(&postgreslock);
472 } /* malloc() retval */
477 static void vm_change_password(struct ast_vm_user *vmu, char *password)
482 sprintf(query, "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->context, vmu->mailbox, vmu->password);
484 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password);
486 /* fprintf(stderr,"postgres change_password: query = %s\n",query); */
487 ast_mutex_lock(&postgreslock);
488 PQexec(dbhandler, query);
489 strcpy(vmu->password, password);
490 ast_mutex_unlock(&postgreslock);
493 static void reset_user_pw(char *context, char *mailbox, char *password)
498 sprintf(query, "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox);
500 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox);
502 ast_mutex_lock(&postgreslock);
503 /* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */
504 PQexec(dbhandler, query);
505 ast_mutex_unlock(&postgreslock);
508 #endif /* Postgres */
512 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
514 /* This function could be made to generate one from a database, too */
515 struct ast_vm_user *vmu=NULL, *cur;
516 ast_mutex_lock(&vmlock);
519 if ((!context || !strcasecmp(context, cur->context)) &&
520 (!strcasecmp(mailbox, cur->mailbox)))
528 /* Make a copy, so that on a reload, we have no race */
529 vmu = malloc(sizeof(struct ast_vm_user));
531 memcpy(vmu, cur, sizeof(struct ast_vm_user));
539 ast_mutex_unlock(&vmlock);
543 static int reset_user_pw(char *context, char *mailbox, char *newpass)
545 /* This function could be made to generate one from a database, too */
546 struct ast_vm_user *cur;
548 ast_mutex_lock(&vmlock);
551 if ((!context || !strcasecmp(context, cur->context)) &&
552 (!strcasecmp(mailbox, cur->mailbox)))
557 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
560 ast_mutex_unlock(&vmlock);
564 static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
566 /* There's probably a better way of doing this. */
567 /* That's why I've put the password change in a separate function. */
568 /* This could also be done with a database function */
575 char currcontext[256] ="";
576 char tmpin[AST_CONFIG_MAX_PATH];
577 char tmpout[AST_CONFIG_MAX_PATH];
578 char *user, *pass, *rest, *trim, *tempcontext;
580 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
581 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
582 configin = fopen((char *)tmpin,"r");
584 configout = fopen((char *)tmpout,"w+");
587 if(!configin || !configout) {
591 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
595 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
599 while (!feof(configin)) {
600 /* Read in the line */
601 fgets(inbuf, sizeof(inbuf), configin);
603 if (!feof(configin)) {
604 /* Make a backup of it */
605 memcpy(orig, inbuf, sizeof(orig));
606 /* Strip trailing \n and comment */
607 inbuf[strlen(inbuf) - 1] = '\0';
608 user = strchr(inbuf, ';');
614 /* check for '[' (opening of context name ) */
615 tempcontext = strchr(user, '[');
617 strncpy(currcontext, tempcontext +1,
618 sizeof(currcontext) - 1);
619 /* now check for ']' */
620 tempcontext = strchr(currcontext, ']');
624 currcontext[0] = '\0';
626 pass = strchr(user, '=');
629 while(*trim && *trim < 33) {
639 while(*pass && *pass < 33)
643 rest = strchr(pass,',');
651 /* Compare user, pass AND context */
652 if (user && *user && !strcmp(user, vmu->mailbox) &&
653 pass && *pass && !strcmp(pass, vmu->password) &&
654 currcontext && *currcontext && !strcmp(currcontext, vmu->context)) {
655 /* This is the line */
657 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
659 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
662 /* Put it back like it was */
663 fprintf(configout, orig);
670 unlink((char *)tmpin);
671 rename((char *)tmpout,(char *)tmpin);
672 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
673 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
677 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
679 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
682 static int make_file(char *dest, int len, char *dir, int num)
684 return snprintf(dest, len, "%s/msg%04d", dir, num);
688 inbuf(struct baseio *bio, FILE *fi)
695 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
710 inchar(struct baseio *bio, FILE *fi)
712 if(bio->iocp>=bio->iolen)
716 return bio->iobuf[bio->iocp++];
720 ochar(struct baseio *bio, int c, FILE *so)
722 if(bio->linelength>=BASELINELEN) {
723 if(fputs(eol,so)==EOF)
729 if(putc(((unsigned char)c),so)==EOF)
737 static int base_encode(char *filename, FILE *so)
739 unsigned char dtable[BASEMAXINLINE];
744 memset(&bio, 0, sizeof(bio));
745 bio.iocp = BASEMAXINLINE;
747 if ( !(fi = fopen(filename, "rb"))) {
748 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
756 dtable[26+i+9]= 'j'+i;
760 dtable[26+i+18]= 's'+i;
769 unsigned char igroup[3],ogroup[4];
772 igroup[0]= igroup[1]= igroup[2]= 0;
775 if ( (c = inchar(&bio, fi)) == EOF) {
780 igroup[n]= (unsigned char)c;
784 ogroup[0]= dtable[igroup[0]>>2];
785 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
786 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
787 ogroup[3]= dtable[igroup[2]&0x3F];
797 ochar(&bio, ogroup[i], so);
801 if(fputs(eol,so)==EOF)
809 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *dur, char *date, char *passdata)
811 /* Prepare variables for substition in email body and subject */
812 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
813 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
814 sprintf(passdata,"%d",msgnum);
815 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
816 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
817 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (callerid ? callerid : "an unknown caller"));
818 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
821 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *attach, char *format, int duration, int attach_user_voicemail)
831 char tmp[80] = "/tmp/astmail-XXXXXX";
835 struct vm_zone *the_zone = NULL;
837 if (!strcmp(format, "wav49"))
839 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, attach_voicemail);
840 /* Make a temporary file instead of piping directly to sendmail, in case the mail
844 p = fdopen(pfd, "w");
851 gethostname(host, sizeof(host));
852 if (strchr(srcemail, '@'))
853 strncpy(who, srcemail, sizeof(who)-1);
855 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
857 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
860 /* Does this user have a timezone specified? */
861 if (!ast_strlen_zero(vmu->zonetag)) {
862 /* Find the zone in the list */
866 if (!strcmp(z->name, vmu->zonetag)) {
875 ast_localtime(&t,&tm,the_zone->timezone);
877 ast_localtime(&t,&tm,NULL);
878 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
879 fprintf(p, "Date: %s\n", date);
882 struct ast_channel *ast = ast_channel_alloc(0);
885 int vmlen = strlen(fromstring)*3 + 200;
886 if ((passdata = alloca(vmlen))) {
887 memset(passdata, 0, vmlen);
888 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata);
889 pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen);
890 fprintf(p, "From: %s <%s>\n",passdata,who);
891 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
892 ast_channel_free(ast);
893 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
895 fprintf(p, "From: Asterisk PBX <%s>\n", who);
896 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
899 struct ast_channel *ast = ast_channel_alloc(0);
902 int vmlen = strlen(emailsubject)*3 + 200;
903 if ((passdata = alloca(vmlen))) {
904 memset(passdata, 0, vmlen);
905 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata);
906 pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen);
907 fprintf(p, "Subject: %s\n",passdata);
908 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
909 ast_channel_free(ast);
910 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
914 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
919 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
921 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
922 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
923 fprintf(p, "MIME-Version: 1.0\n");
924 if (attach_user_voicemail) {
925 /* Something unique. */
926 snprintf(bound, sizeof(bound), "voicemail_%d%s%d", msgnum, mailbox, getpid());
928 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
930 fprintf(p, "--%s\n", bound);
932 fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
933 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
935 struct ast_channel *ast = ast_channel_alloc(0);
938 int vmlen = strlen(emailbody)*3 + 200;
939 if ((passdata = alloca(vmlen))) {
940 memset(passdata, 0, vmlen);
941 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata);
942 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
943 fprintf(p, "%s\n",passdata);
944 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
945 ast_channel_free(ast);
946 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
948 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
950 "in mailbox %s from %s, on %s so you might\n"
951 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
952 dur, msgnum + 1, mailbox, (callerid ? callerid : "an unknown caller"), date);
954 if (attach_user_voicemail) {
955 fprintf(p, "--%s\n", bound);
956 fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
957 fprintf(p, "Content-Transfer-Encoding: base64\n");
958 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
959 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
961 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
962 base_encode(fname, p);
963 fprintf(p, "\n\n--%s--\n.\n", bound);
966 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
967 ast_safe_system(tmp2);
968 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
970 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
976 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, int duration, struct ast_vm_user *vmu)
984 char tmp[80] = "/tmp/astmail-XXXXXX";
988 struct vm_zone *the_zone = NULL;
992 p = fdopen(pfd, "w");
1000 gethostname(host, sizeof(host));
1001 if (strchr(srcemail, '@'))
1002 strncpy(who, srcemail, sizeof(who)-1);
1004 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1006 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1009 /* Does this user have a timezone specified? */
1010 if (!ast_strlen_zero(vmu->zonetag)) {
1011 /* Find the zone in the list */
1015 if (!strcmp(z->name, vmu->zonetag)) {
1024 ast_localtime(&t,&tm,the_zone->timezone);
1026 ast_localtime(&t,&tm,NULL);
1028 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1029 fprintf(p, "Date: %s\n", date);
1030 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1031 fprintf(p, "To: %s\n", pager);
1032 fprintf(p, "Subject: New VM\n\n");
1033 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
1034 fprintf(p, "New %s long msg in box %s\n"
1035 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
1037 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1038 ast_safe_system(tmp2);
1039 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
1041 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1047 static int get_date(char *s, int len)
1052 localtime_r(&t,&tm);
1053 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
1056 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
1060 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
1061 if (ast_fileexists(fn, NULL, NULL) > 0) {
1062 res = ast_streamfile(chan, fn, chan->language);
1065 res = ast_waitstream(chan, ecodes);
1069 res = ast_streamfile(chan, "vm-theperson", chan->language);
1072 res = ast_waitstream(chan, ecodes);
1075 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
1080 res = ast_streamfile(chan, "vm-isonphone", chan->language);
1082 res = ast_streamfile(chan, "vm-isunavail", chan->language);
1085 res = ast_waitstream(chan, ecodes);
1089 static int play_and_wait(struct ast_channel *chan, char *fn)
1092 d = ast_streamfile(chan, fn, chan->language);
1095 d = ast_waitstream(chan, AST_DIGIT_ANY);
1096 ast_stopstream(chan);
1100 static int play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep)
1104 int x, fmtcnt=1, res=-1,outmsg=0;
1105 struct ast_frame *f;
1106 struct ast_filestream *others[MAX_OTHER_FORMATS];
1107 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
1108 char *sfmt[MAX_OTHER_FORMATS];
1111 struct ast_dsp *sildet; /* silence detector dsp */
1112 int totalsilence = 0;
1114 int gotsilence = 0; /* did we timeout for silence? */
1116 char prependfile[80];
1118 /* barf if no pointer passed to store duration in */
1119 if (duration == NULL) {
1120 ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
1124 ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1125 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
1127 if (playfile || beep) {
1129 d = play_and_wait(chan, playfile);
1131 d = ast_streamfile(chan, "beep",chan->language);
1133 d = ast_waitstream(chan,"");
1137 strncpy(prependfile, recordfile, sizeof(prependfile) -1);
1138 strcat(prependfile, "-prepend");
1140 fmts = ast_strdupa(fmt);
1143 strsep(&stringp, "|");
1144 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1145 sfmt[0] = ast_strdupa(fmts);
1147 while((fmt = strsep(&stringp, "|"))) {
1148 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1149 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1152 sfmt[fmtcnt++] = ast_strdupa(fmt);
1156 end=start; /* pre-initialize end to be same as start in case we never get into loop */
1157 for (x=0;x<fmtcnt;x++) {
1158 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1159 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
1165 sildet = ast_dsp_new(); /* Create the silence detector */
1167 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1170 ast_dsp_set_threshold(sildet, silencethreshold);
1172 if (maxsilence > 0) {
1173 rfmt = chan->readformat;
1174 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1176 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1182 /* Loop forever, writing the packets we read to the writer(s), until
1183 we read a # or get a hangup */
1186 res = ast_waitfor(chan, 2000);
1188 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1189 /* Try one more time in case of masq */
1190 res = ast_waitfor(chan, 2000);
1192 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1204 if (f->frametype == AST_FRAME_VOICE) {
1205 /* write each format */
1206 for (x=0;x<fmtcnt;x++) {
1209 res = ast_writestream(others[x], f);
1212 /* Silence Detection */
1213 if (maxsilence > 0) {
1215 ast_dsp_silence(sildet, f, &dspsilence);
1217 totalsilence = dspsilence;
1221 if (totalsilence > maxsilence) {
1222 /* Ended happily with silence */
1229 /* Exit on any error */
1231 ast_log(LOG_WARNING, "Error writing frame\n");
1235 } else if (f->frametype == AST_FRAME_VIDEO) {
1236 /* Write only once */
1237 ast_writestream(others[0], f);
1238 } else if (f->frametype == AST_FRAME_DTMF) {
1239 /* stop recording with any digit */
1240 if (option_verbose > 2)
1241 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1249 if (maxtime < (end - start)) {
1250 if (option_verbose > 2)
1251 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1260 if (end == start) time(&end);
1262 if (option_verbose > 2)
1263 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1267 /* delete all the prepend files */
1268 for (x=0;x<fmtcnt;x++) {
1271 ast_closestream(others[x]);
1272 ast_filedelete(prependfile, sfmt[x]);
1277 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
1279 *duration = end - start;
1285 struct ast_frame *fr;
1286 for (x=0;x<fmtcnt;x++) {
1287 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
1288 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
1289 if (!others[x] || !realfiles[x])
1292 ast_stream_rewind(others[x], totalsilence-200);
1294 ast_stream_rewind(others[x], 200);
1295 ast_truncstream(others[x]);
1296 /* add the original file too */
1297 while ((fr = ast_readframe(realfiles[x]))) {
1298 ast_writestream(others[x],fr);
1300 ast_closestream(others[x]);
1301 ast_closestream(realfiles[x]);
1302 ast_filerename(prependfile, recordfile, sfmt[x]);
1304 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
1306 ast_filedelete(prependfile, sfmt[x]);
1310 if (ast_set_read_format(chan, rfmt)) {
1311 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1316 /* Let them know it worked */
1317 ast_streamfile(chan, "auth-thankyou", chan->language);
1318 ast_waitstream(chan, "");
1324 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration)
1328 int x, fmtcnt=1, res=-1,outmsg=0;
1329 struct ast_frame *f;
1330 struct ast_filestream *others[MAX_OTHER_FORMATS];
1331 char *sfmt[MAX_OTHER_FORMATS];
1334 struct ast_dsp *sildet; /* silence detector dsp */
1335 int totalsilence = 0;
1337 int gotsilence = 0; /* did we timeout for silence? */
1340 /* barf if no pointer passed to store duration in */
1341 if (duration == NULL) {
1342 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
1346 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1347 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
1350 d = play_and_wait(chan, playfile);
1352 d = ast_streamfile(chan, "beep",chan->language);
1354 d = ast_waitstream(chan,"");
1359 fmts = ast_strdupa(fmt);
1362 strsep(&stringp, "|");
1363 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1364 sfmt[0] = ast_strdupa(fmts);
1366 while((fmt = strsep(&stringp, "|"))) {
1367 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1368 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1371 sfmt[fmtcnt++] = ast_strdupa(fmt);
1375 end=start; /* pre-initialize end to be same as start in case we never get into loop */
1376 for (x=0;x<fmtcnt;x++) {
1377 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1378 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
1385 sildet = ast_dsp_new(); /* Create the silence detector */
1387 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1390 ast_dsp_set_threshold(sildet, silencethreshold);
1392 if (maxsilence > 0) {
1393 rfmt = chan->readformat;
1394 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1396 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1402 /* Loop forever, writing the packets we read to the writer(s), until
1403 we read a # or get a hangup */
1406 res = ast_waitfor(chan, 2000);
1408 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1409 /* Try one more time in case of masq */
1410 res = ast_waitfor(chan, 2000);
1412 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1424 if (f->frametype == AST_FRAME_VOICE) {
1425 /* write each format */
1426 for (x=0;x<fmtcnt;x++) {
1427 res = ast_writestream(others[x], f);
1430 /* Silence Detection */
1431 if (maxsilence > 0) {
1433 ast_dsp_silence(sildet, f, &dspsilence);
1435 totalsilence = dspsilence;
1439 if (totalsilence > maxsilence) {
1440 /* Ended happily with silence */
1447 /* Exit on any error */
1449 ast_log(LOG_WARNING, "Error writing frame\n");
1453 } else if (f->frametype == AST_FRAME_VIDEO) {
1454 /* Write only once */
1455 ast_writestream(others[0], f);
1456 } else if (f->frametype == AST_FRAME_DTMF) {
1457 if (f->subclass == '#') {
1458 if (option_verbose > 2)
1459 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1466 if (f->subclass == '0') {
1467 /* Check for a '0' during message recording also, in case caller wants operator */
1468 if (option_verbose > 2)
1469 ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
1477 if (maxtime < (end - start)) {
1478 if (option_verbose > 2)
1479 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1488 if (end == start) time(&end);
1490 if (option_verbose > 2)
1491 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1496 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1499 *duration = end - start;
1501 for (x=0;x<fmtcnt;x++) {
1505 ast_stream_rewind(others[x], totalsilence-200);
1507 ast_stream_rewind(others[x], 200);
1508 ast_truncstream(others[x]);
1509 ast_closestream(others[x]);
1512 if (ast_set_read_format(chan, rfmt)) {
1513 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1518 /* Let them know recording is stopped */
1519 ast_streamfile(chan, "auth-thankyou", chan->language);
1520 ast_waitstream(chan, "");
1527 static void free_user(struct ast_vm_user *vmu)
1533 static void free_zone(struct vm_zone *z)
1538 static char *mbox(int id)
1566 static int copy(char *infile, char *outfile)
1574 #ifdef HARDLINK_WHEN_POSSIBLE
1575 /* Hard link if possible; saves disk space & is faster */
1576 if (link(infile, outfile)) {
1578 if ((ifd = open(infile, O_RDONLY)) < 0) {
1579 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1582 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1583 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1588 len = read(ifd, buf, sizeof(buf));
1590 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1596 res = write(ofd, buf, len);
1598 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1608 #ifdef HARDLINK_WHEN_POSSIBLE
1610 /* Hard link succeeded */
1616 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid);
1618 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)
1620 char fromdir[256], todir[256], frompath[256], topath[256];
1621 char *frombox = mbox(imbox);
1624 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
1626 make_dir(todir, sizeof(todir), recip->context, "", "");
1627 /* It's easier just to try to make it than to check for its existence */
1628 if (mkdir(todir, 0700) && (errno != EEXIST))
1629 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1630 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
1631 /* It's easier just to try to make it than to check for its existence */
1632 if (mkdir(todir, 0700) && (errno != EEXIST))
1633 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1634 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
1635 if (mkdir(todir, 0700) && (errno != EEXIST))
1636 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1638 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
1639 make_file(frompath, sizeof(frompath), fromdir, msgnum);
1642 make_file(topath, sizeof(topath), todir, recipmsgnum);
1643 if (ast_fileexists(topath, NULL, chan->language) <= 0)
1646 } while(recipmsgnum < MAXMSG);
1647 if (recipmsgnum < MAXMSG) {
1648 char frompath2[256],topath2[256];
1649 ast_filecopy(frompath, topath, NULL);
1650 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
1651 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
1652 copy(frompath2, topath2);
1654 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
1657 notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
1660 static void run_externnotify(char *context, char *extension, int numvoicemails)
1662 char arguments[255];
1664 if(externnotify[0]) {
1665 strncpy(arguments, externnotify, sizeof(arguments));
1666 snprintf(arguments, sizeof(arguments)-1, "%s %s %s %d&", externnotify, context, extension, numvoicemails);
1667 ast_log(LOG_DEBUG,"Executing %s\n", arguments);
1668 ast_safe_system(arguments);
1673 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
1684 char prefile[256]="";
1685 char ext_context[256] = "";
1688 char ecodes[16] = "#";
1689 char tmp[256] = "", *tmpptr;
1690 struct ast_vm_user *vmu;
1691 struct ast_vm_user svm;
1693 strncpy(tmp, ext, sizeof(tmp) - 1);
1695 context = strchr(tmp, '@');
1699 tmpptr = strchr(context, '&');
1701 tmpptr = strchr(ext, '&');
1709 if ((vmu = find_user(&svm, context, ext))) {
1710 /* Setup pre-file if appropriate */
1711 if (strcmp(vmu->context, "default"))
1712 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
1714 strncpy(ext_context, vmu->context, sizeof(ext_context) - 1);
1716 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
1718 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
1719 make_dir(dir, sizeof(dir), vmu->context, "", "");
1720 /* It's easier just to try to make it than to check for its existence */
1721 if (mkdir(dir, 0700) && (errno != EEXIST))
1722 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1723 make_dir(dir, sizeof(dir), vmu->context, ext, "");
1724 /* It's easier just to try to make it than to check for its existence */
1725 if (mkdir(dir, 0700) && (errno != EEXIST))
1726 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1727 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
1728 if (mkdir(dir, 0700) && (errno != EEXIST))
1729 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1730 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
1731 strcat(ecodes, "0");
1732 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "a", 1, chan->callerid))
1733 strcat(ecodes, "*");
1734 /* Play the beginning intro if desired */
1735 if (!ast_strlen_zero(prefile)) {
1736 if (ast_fileexists(prefile, NULL, NULL) > 0) {
1737 if (ast_streamfile(chan, prefile, chan->language) > -1)
1738 res = ast_waitstream(chan, ecodes);
1740 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
1741 res = invent_message(chan, vmu->context, ext, busy, ecodes);
1744 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
1750 /* On a '#' we skip the instructions */
1754 if (!res && !silent) {
1755 res = ast_streamfile(chan, INTRO, chan->language);
1757 res = ast_waitstream(chan, ecodes);
1764 ast_stopstream(chan);
1765 /* Check for a '*' here in case the caller wants to escape from voicemail to something
1766 other than the operator -- an automated attendant or mailbox login for example */
1768 strncpy(chan->exten, "a", sizeof(chan->exten) - 1);
1769 if (!ast_strlen_zero(vmu->exit)) {
1770 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
1771 } else if (!ast_strlen_zero(chan->macrocontext)) {
1772 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1778 /* Check for a '0' here */
1781 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
1782 if (!ast_strlen_zero(vmu->exit)) {
1783 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
1784 } else if (!ast_strlen_zero(chan->macrocontext)) {
1785 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1792 /* Unless we're *really* silent, try to send the beep */
1793 res = ast_streamfile(chan, "beep", chan->language);
1795 res = ast_waitstream(chan, "");
1801 /* The meat of recording the message... All the announcements and beeps have been played*/
1802 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
1803 if (!ast_strlen_zero(fmt)) {
1806 make_file(fn, sizeof(fn), dir, msgnum);
1807 if (ast_fileexists(fn, NULL, chan->language) <= 0)
1810 } while(msgnum < MAXMSG);
1811 if (msgnum < MAXMSG) {
1812 /* Store information */
1813 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
1814 txt = fopen(txtfile, "w+");
1816 get_date(date, sizeof(date));
1819 "; Message Information file\n"
1837 chan->callerid ? chan->callerid : "Unknown",
1838 date, (long)time(NULL));
1841 ast_log(LOG_WARNING, "Error opening text file for output\n");
1842 res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration);
1847 fd = open(txtfile, O_APPEND | O_WRONLY);
1849 txt = fdopen(fd, "a");
1851 fprintf(txt, "duration=%d\n", duration);
1856 if (duration < vmminmessage) {
1860 /* Are there to be more recipients of this message? */
1862 struct ast_vm_user recipu, *recip;
1863 char *exten, *context;
1865 exten = strsep(&tmpptr, "&");
1866 context = strchr(exten, '@');
1871 if ((recip = find_user(&recipu, context, exten))) {
1872 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
1876 notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
1878 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
1880 res = ast_waitstream(chan, "");
1881 ast_log(LOG_WARNING, "No more messages possible\n");
1884 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
1888 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
1889 /*Send the call to n+101 priority, where n is the current priority*/
1890 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
1891 chan->priority+=100;
1897 static int count_messages(char *dir)
1901 for (x=0;x<MAXMSG;x++) {
1902 make_file(fn, sizeof(fn), dir, x);
1903 if (ast_fileexists(fn, NULL, NULL) < 1)
1909 static int say_and_wait(struct ast_channel *chan, int num, char *language)
1912 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
1916 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
1923 char *dbox = mbox(box);
1925 make_file(sfn, sizeof(sfn), dir, msg);
1926 make_dir(ddir, sizeof(ddir), context, username, dbox);
1928 for (x=0;x<MAXMSG;x++) {
1929 make_file(dfn, sizeof(dfn), ddir, x);
1930 if (ast_fileexists(dfn, NULL, NULL) < 0)
1935 ast_filecopy(sfn, dfn, NULL);
1936 if (strcmp(sfn, dfn)) {
1937 snprintf(txt, sizeof(txt), "%s.txt", sfn);
1938 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
1944 static int adsi_logo(unsigned char *buf)
1947 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
1948 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
1952 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
1960 bytes += adsi_data_mode(buf + bytes);
1961 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1964 bytes += adsi_logo(buf);
1965 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1967 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1969 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1970 bytes += adsi_data_mode(buf + bytes);
1971 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1973 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1975 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1976 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1977 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1978 bytes += adsi_voice_mode(buf + bytes, 0);
1979 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1986 bytes += adsi_logo(buf);
1987 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1988 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1989 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1990 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1993 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1994 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1995 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1996 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
1997 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1998 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1999 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2002 /* Add another dot */
2004 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
2005 bytes += adsi_voice_mode(buf + bytes, 0);
2007 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2008 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2012 /* These buttons we load but don't use yet */
2013 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
2014 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
2015 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
2016 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
2017 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
2018 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
2019 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2022 /* Add another dot */
2024 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
2025 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2026 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2031 snprintf(num, sizeof(num), "%d", x);
2032 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
2034 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
2035 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2038 /* Add another dot */
2040 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
2041 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2042 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2045 if (adsi_end_download(chan)) {
2047 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
2048 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2049 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2050 bytes += adsi_voice_mode(buf + bytes, 0);
2051 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2055 bytes += adsi_download_disconnect(buf + bytes);
2056 bytes += adsi_voice_mode(buf + bytes, 0);
2057 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2059 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
2064 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
2065 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2067 ast_log(LOG_DEBUG, "Restarting session...\n");
2070 /* Load the session now */
2071 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
2073 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
2075 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
2077 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2081 static void adsi_begin(struct ast_channel *chan, int *useadsi)
2084 if (!adsi_available(chan))
2086 x = adsi_load_session(chan, adapp, adver, 1);
2090 if (adsi_load_vmail(chan, useadsi)) {
2091 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
2098 static void adsi_login(struct ast_channel *chan)
2102 unsigned char keys[8];
2104 if (!adsi_available(chan))
2109 /* Set one key for next */
2110 keys[3] = ADSI_KEY_APPS + 3;
2112 bytes += adsi_logo(buf + bytes);
2113 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
2114 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
2115 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2116 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
2117 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
2118 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
2119 bytes += adsi_set_keys(buf + bytes, keys);
2120 bytes += adsi_voice_mode(buf + bytes, 0);
2121 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2124 static void adsi_password(struct ast_channel *chan)
2128 unsigned char keys[8];
2130 if (!adsi_available(chan))
2135 /* Set one key for next */
2136 keys[3] = ADSI_KEY_APPS + 3;
2138 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2139 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
2140 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
2141 bytes += adsi_set_keys(buf + bytes, keys);
2142 bytes += adsi_voice_mode(buf + bytes, 0);
2143 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2146 static void adsi_folders(struct ast_channel *chan, int start, char *label)
2150 unsigned char keys[8];
2153 if (!adsi_available(chan))
2157 y = ADSI_KEY_APPS + 12 + start + x;
2158 if (y > ADSI_KEY_APPS + 12 + 4)
2160 keys[x] = ADSI_KEY_SKT | y;
2162 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
2166 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
2167 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
2168 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2169 bytes += adsi_set_keys(buf + bytes, keys);
2170 bytes += adsi_voice_mode(buf + bytes, 0);
2172 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2175 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
2178 char buf[256], buf1[256], buf2[256];
2184 char datetime[21]="";
2187 unsigned char keys[8];
2191 if (!adsi_available(chan))
2194 /* Retrieve important info */
2195 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
2196 f = fopen(fn2, "r");
2199 fgets(buf, sizeof(buf), f);
2203 strsep(&stringp, "=");
2204 val = strsep(&stringp, "=");
2205 if (val && !ast_strlen_zero(val)) {
2206 if (!strcmp(buf, "callerid"))
2207 strncpy(cid, val, sizeof(cid) - 1);
2208 if (!strcmp(buf, "origdate"))
2209 strncpy(datetime, val, sizeof(datetime) - 1);
2215 /* New meaning for keys */
2217 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2222 /* No prev key, provide "Folder" instead */
2223 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2226 /* If last message ... */
2228 /* but not only message, provide "Folder" instead */
2229 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2230 bytes += adsi_voice_mode(buf + bytes, 0);
2233 /* Otherwise if only message, leave blank */
2238 if (!ast_strlen_zero(cid)) {
2239 ast_callerid_parse(cid, &name, &num);
2243 name = "Unknown Caller";
2245 /* If deleted, show "undeleted" */
2248 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2251 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2252 snprintf(buf1, sizeof(buf1), "%s%s", folder,
2253 strcasecmp(folder, "INBOX") ? " Messages" : "");
2254 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
2256 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2257 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2258 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
2259 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
2260 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2261 bytes += adsi_set_keys(buf + bytes, keys);
2262 bytes += adsi_voice_mode(buf + bytes, 0);
2264 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2267 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
2271 unsigned char keys[8];
2275 if (!adsi_available(chan))
2278 /* New meaning for keys */
2280 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2286 /* No prev key, provide "Folder" instead */
2287 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2290 /* If last message ... */
2292 /* but not only message, provide "Folder" instead */
2293 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2295 /* Otherwise if only message, leave blank */
2300 /* If deleted, show "undeleted" */
2302 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2305 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2306 bytes += adsi_set_keys(buf + bytes, keys);
2307 bytes += adsi_voice_mode(buf + bytes, 0);
2309 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2312 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
2314 char buf[256], buf1[256], buf2[256];
2316 unsigned char keys[8];
2319 char *newm = (new == 1) ? "message" : "messages";
2320 char *oldm = (old == 1) ? "message" : "messages";
2321 if (!adsi_available(chan))
2324 snprintf(buf1, sizeof(buf1), "You have %d new", new);
2326 strcat(buf1, " and");
2327 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
2329 snprintf(buf2, sizeof(buf2), "%s.", newm);
2332 snprintf(buf1, sizeof(buf1), "You have %d old", old);
2333 snprintf(buf2, sizeof(buf2), "%s.", oldm);
2335 strcpy(buf1, "You have no messages.");
2338 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2339 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2340 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2343 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2347 /* Don't let them listen if there are none */
2350 bytes += adsi_set_keys(buf + bytes, keys);
2352 bytes += adsi_voice_mode(buf + bytes, 0);
2354 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2357 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
2359 char buf[256], buf1[256], buf2[256];
2361 unsigned char keys[8];
2364 char *mess = (messages == 1) ? "message" : "messages";
2366 if (!adsi_available(chan))
2369 /* Original command keys */
2371 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2379 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
2380 strcasecmp(folder, "INBOX") ? " folder" : "");
2383 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
2385 strcpy(buf2, "no messages.");
2386 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2387 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2388 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
2389 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2390 bytes += adsi_set_keys(buf + bytes, keys);
2392 bytes += adsi_voice_mode(buf + bytes, 0);
2394 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2399 static void adsi_clear(struct ast_channel *chan)
2403 if (!adsi_available(chan))
2405 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2406 bytes += adsi_voice_mode(buf + bytes, 0);
2408 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2412 static void adsi_goodbye(struct ast_channel *chan)
2417 if (!adsi_available(chan))
2419 bytes += adsi_logo(buf + bytes);
2420 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
2421 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
2422 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2423 bytes += adsi_voice_mode(buf + bytes, 0);
2425 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2428 /*--- get_folder: Folder menu ---*/
2429 /* Plays "press 1 for INBOX messages" etc
2430 Should possibly be internationalized
2432 static int get_folder(struct ast_channel *chan, int start)
2437 d = play_and_wait(chan, "vm-press"); /* "Press" */
2440 for (x = start; x< 5; x++) { /* For all folders */
2441 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
2443 d = play_and_wait(chan, "vm-for"); /* "for" */
2446 if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Spanish, French or Portuguese syntax */
2447 d = play_and_wait(chan, "vm-messages"); /* "messages */
2450 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
2451 d = play_and_wait(chan, fn);
2454 } else { /* Default English */
2455 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
2456 d = play_and_wait(chan, fn);
2459 d = play_and_wait(chan, "vm-messages"); /* "messages */
2463 d = ast_waitfordigit(chan, 500);
2467 d = play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
2470 d = ast_waitfordigit(chan, 4000);
2474 static int get_folder2(struct ast_channel *chan, char *fn, int start)
2477 res = play_and_wait(chan, fn); /* Folder name */
2478 while (((res < '0') || (res > '9')) &&
2479 (res != '#') && (res >= 0)) {
2480 res = get_folder(chan, 0);
2485 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context)
2491 while((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
2496 /* prepend a message to the current message and return */
2499 snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
2500 cmd = play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1);
2510 cmd = play_and_wait(chan,"vm-forwardoptions");
2511 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
2513 cmd = play_and_wait(chan,"vm-starmain");
2514 /* "press star to return to the main menu" */
2516 cmd = ast_waitfordigit(chan,6000);
2528 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid)
2530 char todir[256], fn[256], *stringp;
2532 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
2533 make_file(fn, sizeof(fn), todir, msgnum);
2535 /* Attach only the first format */
2536 fmt = ast_strdupa(fmt);
2539 strsep(&stringp, "|");
2541 if (!ast_strlen_zero(vmu->email)) {
2542 int attach_user_voicemail = attach_voicemail;
2543 char *myserveremail = serveremail;
2544 if (vmu->attach > -1)
2545 attach_user_voicemail = vmu->attach;
2546 if (!ast_strlen_zero(vmu->serveremail))
2547 myserveremail = vmu->serveremail;
2548 sendmail(myserveremail, vmu, msgnum, vmu->mailbox, callerid, fn, fmt, duration, attach_user_voicemail);
2551 if (!ast_strlen_zero(vmu->pager)) {
2552 char *myserveremail = serveremail;
2553 if (!ast_strlen_zero(vmu->serveremail))
2554 myserveremail = vmu->serveremail;
2555 sendpage(myserveremail, vmu->pager, msgnum, vmu->mailbox, callerid, duration, vmu);
2558 ast_log(LOG_ERROR, "Out of memory\n");
2565 /* Leave voicemail for someone */
2566 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vmu->mailbox, ast_app_has_voicemail(vmu->mailbox));
2567 run_externnotify(chan->context, vmu->mailbox, ast_app_has_voicemail(vmu->mailbox));
2571 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
2578 struct ast_config *mif;
2582 char ext_context[256]="";
2583 int res = 0, cmd = 0;
2584 struct ast_vm_user *receiver, *extensions = NULL, *vmtmp = NULL, *vmfree;
2587 int saved_messages = 0, found = 0;
2588 int valid_extensions = 0;
2589 while (!res && !valid_extensions) {
2590 res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */
2593 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
2595 /* start all over if no username */
2596 if (ast_strlen_zero(username))
2599 s = strsep(&stringp, "*");
2600 /* start optimistic */
2601 valid_extensions = 1;
2603 /* find_user is going to malloc since we have a NULL as first argument */
2604 if ((receiver = find_user(NULL, context, s))) {
2606 vmtmp = extensions = receiver;
2608 vmtmp->next = receiver;
2613 valid_extensions = 0;
2616 s = strsep(&stringp, "*");
2618 /* break from the loop of reading the extensions */
2619 if (valid_extensions)
2621 /* "I am sorry, that's not a valid extension. Please try again." */
2622 res = play_and_wait(chan, "pbx-invalid");
2624 /* check if we're clear to proceed */
2625 if (!extensions || !valid_extensions)
2628 cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context);
2630 while(!res && vmtmp) {
2631 /* if (play_and_wait(chan, "vm-savedto"))
2634 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
2635 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
2636 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmtmp->mailbox, vmtmp->context);
2637 ast_log(LOG_DEBUG, sys);
2638 ast_safe_system(sys);
2640 todircount = count_messages(todir);
2641 strncpy(tmp, fmt, sizeof(tmp) - 1);
2643 while((s = strsep(&stringp, "|"))) {
2644 /* XXX This is a hack -- we should use build_filename or similar XXX */
2645 if (!strcasecmp(s, "wav49"))
2647 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
2648 ast_log(LOG_DEBUG, sys);
2649 ast_safe_system(sys);
2651 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
2652 ast_log(LOG_DEBUG, sys);
2653 ast_safe_system(sys);
2654 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
2656 /* load the information on the source message so we can send an e-mail like a new message */
2657 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
2658 if ((mif=ast_load(miffile))) {
2660 /* set callerid and duration variables */
2661 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
2662 s = ast_variable_retrieve(mif, NULL, "duration");
2667 if (!ast_strlen_zero(vmtmp->email)) {
2668 int attach_user_voicemail = attach_voicemail;
2669 char *myserveremail = serveremail;
2670 if (vmtmp->attach > -1)
2671 attach_user_voicemail = vmtmp->attach;
2672 if (!ast_strlen_zero(vmtmp->serveremail))
2673 myserveremail = vmtmp->serveremail;
2674 sendmail(myserveremail, vmtmp, todircount, vmtmp->mailbox, callerid, fn, tmp, duration, attach_user_voicemail);
2677 if (!ast_strlen_zero(vmtmp->pager)) {
2678 char *myserveremail = serveremail;
2679 if (!ast_strlen_zero(vmtmp->serveremail))
2680 myserveremail = vmtmp->serveremail;
2681 sendpage(myserveremail, vmtmp->pager, todircount, vmtmp->mailbox, callerid, duration, vmtmp);
2684 ast_destroy(mif); /* or here */
2686 /* Leave voicemail for someone */
2687 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
2688 run_externnotify(chan->context, ext_context, ast_app_has_voicemail(ext_context));
2692 vmtmp = vmtmp->next;
2695 if (saved_messages > 0) {
2696 /* give confirmation that the message was saved */
2697 /* commented out since we can't forward batches yet
2698 if (saved_messages == 1)
2699 res = play_and_wait(chan, "vm-message");
2701 res = play_and_wait(chan, "vm-messages");
2703 res = play_and_wait(chan, "vm-saved"); */
2705 res = play_and_wait(chan, "vm-msgsaved");
2708 return res ? res : cmd;
2712 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
2715 if ((res = ast_streamfile(chan, file, chan->language)))
2716 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2718 res = ast_waitstream(chan, AST_DIGIT_ANY);
2722 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
2724 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", skipms);
2727 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, char *origtime, char *filename)
2730 struct vm_zone *the_zone = NULL;
2734 if (sscanf(origtime,"%ld",&tin) < 1) {
2735 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
2740 /* Does this user have a timezone specified? */
2741 if (!ast_strlen_zero(vmu->zonetag)) {
2742 /* Find the zone in the list */
2746 if (!strcmp(z->name, vmu->zonetag)) {
2754 /* No internal variable parsing for now, so we'll comment it out for the time being */
2756 /* Set the DIFF_* variables */
2757 localtime_r(&t, &time_now);
2758 gettimeofday(&tv_now,NULL);
2759 tnow = tv_now.tv_sec;
2760 localtime_r(&tnow,&time_then);
2762 /* Day difference */
2763 if (time_now.tm_year == time_then.tm_year)
2764 sprintf(temp,"%d",time_now.tm_yday);
2766 sprintf(temp,"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
2767 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
2769 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
2772 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
2773 else if (!strcasecmp(chan->language,"nl")) /* DUTCH syntax */
2774 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
2776 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
2778 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
2785 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, char *context, int callback)
2789 char *callerid, *name;
2790 char prefile[256]="";
2793 /* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
2794 /* 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 */
2795 if((cid == NULL)||(context == NULL))
2798 /* Strip off caller ID number from name */
2799 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
2800 ast_callerid_parse(cid, &name, &callerid);
2801 if((callerid != NULL)&&(!res)&&(!ast_strlen_zero(callerid))){
2802 /* Check for internal contexts and only */
2803 /* say extension when the call didn't come from an internal context in the list */
2804 for(i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
2805 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
2806 if((strcmp(cidinternalcontexts[i], context) == 0))
2809 if(i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
2811 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/greet", context, callerid);
2812 if (!ast_strlen_zero(prefile)) {
2813 /* See if we can find a recorded name for this person instead of their extension number */
2814 if (ast_fileexists(prefile, NULL, NULL) > 0) {
2815 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
2817 res = wait_file2(chan, vms, "vm-from");
2818 res = ast_streamfile(chan, prefile, chan->language) > -1;
2819 res = ast_waitstream(chan, "");
2821 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
2822 /* BB: Say "from extension" as one saying to sound smoother */
2824 res = wait_file2(chan, vms, "vm-from-extension");
2825 res = ast_say_digit_str(chan, callerid, "", chan->language);
2832 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
2833 /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
2835 res = wait_file2(chan, vms, "vm-from-phonenumber");
2836 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
2840 /* Number unknown */
2841 ast_log(LOG_DEBUG, "VM-CID: From an unknown number");
2843 /* BB: Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
2844 res = wait_file2(chan, vms, "vm-unknown-caller");
2849 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg)
2852 char filename[256],*origtime, *cid, *context;
2853 struct ast_config *msg_cfg;
2856 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2857 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
2859 res = wait_file2(chan, vms, "vm-first"); /* "First" */
2860 else if (msg == vms->lastmsg)
2861 res = wait_file2(chan, vms, "vm-last"); /* "last" */
2863 res = wait_file2(chan, vms, "vm-message"); /* "message" */
2864 if (msg && (msg != vms->lastmsg)) {
2866 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
2870 /* Retrieve info from VM attribute file */
2871 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2872 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
2873 msg_cfg = ast_load(filename);
2875 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
2879 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
2882 cid = ast_variable_retrieve(msg_cfg, "message", "callerid");
2884 context = ast_variable_retrieve(msg_cfg, "message", "context");
2885 if(!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */
2886 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
2888 if ((!res)&&(vmu->envelope))
2889 res = play_message_datetime(chan, vmu, origtime, filename);
2890 if ((!res)&&(vmu->saycid))
2891 res = play_message_callerid(chan, vms, cid, context, 0);
2892 /* Allow pressing '1' to skip envelope / callerid */
2895 ast_destroy(msg_cfg);
2898 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2899 vms->heard[msg] = 1;
2900 res = wait_file(chan, vms, vms->fn);
2905 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
2907 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
2908 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2909 vms->lastmsg = count_messages(vms->curdir) - 1;
2910 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
2913 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
2916 char ntxt[256] = "";
2918 if (vms->lastmsg > -1) {
2919 /* Get the deleted messages fixed */
2921 for (x=0;x < MAXMSG;x++) {
2922 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
2923 /* Save this message. It's not in INBOX or hasn't been heard */
2924 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2925 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2928 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2929 if (strcmp(vms->fn, vms->fn2)) {
2930 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2931 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
2932 ast_filerename(vms->fn, vms->fn2, NULL);
2935 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
2936 /* Move to old folder before deleting */
2937 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
2940 for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
2941 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2942 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2947 memset(vms->deleted, 0, sizeof(vms->deleted));
2948 memset(vms->heard, 0, sizeof(vms->heard));
2951 /* Default English syntax */
2952 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
2954 /* Introduce messages they have */
2956 res = play_and_wait(chan, "vm-youhave");
2958 if (vms->newmessages) {
2959 res = say_and_wait(chan, vms->newmessages, chan->language);
2961 res = play_and_wait(chan, "vm-INBOX");
2962 if (vms->oldmessages && !res)
2963 res = play_and_wait(chan, "vm-and");
2965 if ((vms->newmessages == 1))
2966 res = play_and_wait(chan, "vm-message");
2968 res = play_and_wait(chan, "vm-messages");
2972 if (!res && vms->oldmessages) {
2973 res = say_and_wait(chan, vms->oldmessages, chan->language);
2975 res = play_and_wait(chan, "vm-Old");
2977 if (vms->oldmessages == 1)
2978 res = play_and_wait(chan, "vm-message");
2980 res = play_and_wait(chan, "vm-messages");
2984 if (!vms->oldmessages && !vms->newmessages) {
2985 res = play_and_wait(chan, "vm-no");
2987 res = play_and_wait(chan, "vm-messages");
2995 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
2997 /* Introduce messages they have */
2999 res = play_and_wait(chan, "vm-youhave");
3001 if (vms->newmessages) {
3002 if ((vms->newmessages == 1))
3003 res = play_and_wait(chan, "digits/1F");
3005 res = say_and_wait(chan, vms->newmessages, chan->language);
3007 res = play_and_wait(chan, "vm-INBOX");
3008 if (vms->oldmessages && !res)
3009 res = play_and_wait(chan, "vm-and");
3011 if ((vms->newmessages == 1))
3012 res = play_and_wait(chan, "vm-message");
3014 res = play_and_wait(chan, "vm-messages");
3018 if (!res && vms->oldmessages) {
3019 if (vms->oldmessages == 1)
3020 res = play_and_wait(chan, "digits/1F");
3022 res = say_and_wait(chan, vms->oldmessages, chan->language);
3024 res = play_and_wait(chan, "vm-Old");
3026 if (vms->oldmessages == 1)
3027 res = play_and_wait(chan, "vm-message");
3029 res = play_and_wait(chan, "vm-messages");
3033 if (!vms->oldmessages && !vms->newmessages) {
3034 res = play_and_wait(chan, "vm-no");
3036 res = play_and_wait(chan, "vm-messages");
3043 /* SPANISH syntax */
3044 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
3046 /* Introduce messages they have */
3048 if (!vms->oldmessages && !vms->newmessages) {
3049 res = play_and_wait(chan, "vm-youhaveno");
3051 res = play_and_wait(chan, "vm-messages");
3053 res = play_and_wait(chan, "vm-youhave");
3056 if (vms->newmessages) {
3058 if ((vms->newmessages == 1)) {
3059 res = play_and_wait(chan, "digits/1M");
3061 res = play_and_wait(chan, "vm-message");
3063 res = play_and_wait(chan, "vm-INBOXs");
3065 res = say_and_wait(chan, vms->newmessages, chan->language);
3067 res = play_and_wait(chan, "vm-messages");
3069 res = play_and_wait(chan, "vm-INBOX");
3072 if (vms->oldmessages && !res)
3073 res = play_and_wait(chan, "vm-and");
3075 if (vms->oldmessages) {
3077 if (vms->oldmessages == 1) {
3078 res = play_and_wait(chan, "digits/1M");
3080 res = play_and_wait(chan, "vm-message");
3082 res = play_and_wait(chan, "vm-Olds");
3084 res = say_and_wait(chan, vms->oldmessages, chan->language);
3086 res = play_and_wait(chan, "vm-messages");
3088 res = play_and_wait(chan, "vm-Old");
3097 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
3099 /* Introduce messages they have */
3101 res = play_and_wait(chan, "vm-youhave");
3103 if (vms->newmessages) {
3104 res = say_and_wait(chan, vms->newmessages, chan->language);
3106 res = play_and_wait(chan, "vm-INBOX");
3107 if (vms->oldmessages && !res)
3108 res = play_and_wait(chan, "vm-and");
3110 if ((vms->newmessages == 1))
3111 res = play_and_wait(chan, "vm-message");
3113 res = play_and_wait(chan, "vm-messages");
3117 if (!res && vms->oldmessages) {
3118 res = say_and_wait(chan, vms->oldmessages, chan->language);
3120 if (vms->oldmessages == 1)
3121 res = play_and_wait(chan, "vm-message");
3123 res = play_and_wait(chan, "vm-messages");
3126 res = play_and_wait(chan, "vm-Old");
3129 if (!vms->oldmessages && !vms->newmessages) {
3130 res = play_and_wait(chan, "vm-no");
3132 res = play_and_wait(chan, "vm-messages");
3140 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
3142 /* Introduce messages they have */
3144 res = play_and_wait(chan, "vm-youhave");
3146 if (vms->newmessages) {
3147 res = say_and_wait(chan, vms->newmessages, chan->language);
3149 if (vms->oldmessages == 1)
3150 res = play_and_wait(chan, "vm-INBOXs");
3152 res = play_and_wait(chan, "vm-INBOX");
3154 if (vms->oldmessages && !res)
3155 res = play_and_wait(chan, "vm-and");
3157 if ((vms->newmessages == 1))
3158 res = play_and_wait(chan, "vm-message");
3160 res = play_and_wait(chan, "vm-messages");
3164 if (!res && vms->oldmessages) {
3165 res = say_and_wait(chan, vms->oldmessages, chan->language);
3167 if (vms->oldmessages == 1)
3168 res = play_and_wait(chan, "vm-Olds");
3170 res = play_and_wait(chan, "vm-Old");
3173 if (vms->oldmessages == 1)
3174 res = play_and_wait(chan, "vm-message");
3176 res = play_and_wait(chan, "vm-messages");
3180 if (!vms->oldmessages && !vms->newmessages) {
3181 res = play_and_wait(chan, "vm-no");
3183 res = play_and_wait(chan, "vm-messages");
3190 /* PORTUGUESE syntax */
3191 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
3193 /* Introduce messages they have */
3195 res = play_and_wait(chan, "vm-youhave");
3197 if (vms->newmessages) {
3198 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
3200 if ((vms->newmessages == 1)) {
3201 res = play_and_wait(chan, "vm-message");
3203 res = play_and_wait(chan, "vm-INBOXs");
3205 res = play_and_wait(chan, "vm-messages");
3207 res = play_and_wait(chan, "vm-INBOX");
3210 if (vms->oldmessages && !res)
3211 res = play_and_wait(chan, "vm-and");
3213 if (!res && vms->oldmessages) {
3214 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
3216 if (vms->oldmessages == 1) {
3217 res = play_and_wait(chan, "vm-message");
3219 res = play_and_wait(chan, "vm-Olds");
3221 res = play_and_wait(chan, "vm-messages");
3223 res = play_and_wait(chan, "vm-Old");
3228 if (!vms->oldmessages && !vms->newmessages) {
3229 res = play_and_wait(chan, "vm-no");
3231 res = play_and_wait(chan, "vm-messages");
3238 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
3241 /* Play instructions and wait for new command */
3243 if (vms->starting) {
3244 if (vms->lastmsg > -1) {
3245 res = play_and_wait(chan, "vm-onefor");
3246 if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Spanish, French & Portuguese Syntax */
3248 res = play_and_wait(chan, "vm-messages");
3250 res = play_and_wait(chan, vms->vmbox);
3251 } else { /* Default English syntax */
3253 res = play_and_wait(chan, vms->vmbox);
3255 res = play_and_wait(chan, "vm-messages");
3259 res = play_and_wait(chan, "vm-opts");
3262 res = play_and_wait(chan, "vm-prev");
3263 if (!res && !skipadvanced)
3264 res = play_and_wait(chan, "vm-advopts");
3266 res = play_and_wait(chan, "vm-repeat");
3267 if (!res && (vms->curmsg != vms->lastmsg))
3268 res = play_and_wait(chan, "vm-next");
3270 if (!vms->deleted[vms->curmsg])
3271 res = play_and_wait(chan, "vm-delete");
3273 res = play_and_wait(chan, "vm-undelete");
3275 res = play_and_wait(chan, "vm-toforward");
3277 res = play_and_wait(chan, "vm-savemessage");
3281 res = play_and_wait(chan, "vm-helpexit");
3283 res = ast_waitfordigit(chan, 6000);
3286 if (vms->repeats > 2) {
3294 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
3299 char newpassword[80] = "";
3300 char newpassword2[80] = "";
3301 char prefile[256]="";
3305 if (adsi_available(chan))
3307 bytes += adsi_logo(buf + bytes);
3308 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
3309 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
3310 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3311 bytes += adsi_voice_mode(buf + bytes, 0);
3312 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3314 while((cmd >= 0) && (cmd != 't')) {
3319 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
3320 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration);
3323 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
3324 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration);
3327 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
3328 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration);