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 static int load_config(void);
91 /* Syntaxes supported, not really language codes.
99 German requires the following additional soundfile:
102 Spanish requires the following additional soundfile:
105 Dutch, Portuguese & Spanish require the following additional soundfiles:
106 vm-INBOXs singular of 'new'
107 vm-Olds singular of 'old/heard/read'
126 unsigned char iobuf[BASEMAXINLINE];
129 /* Structure for linked list of users */
131 char context[80]; /* Voicemail context */
132 char mailbox[80]; /* Mailbox id, unique within vm context */
133 char password[80]; /* Secret pin code, numbers only */
134 char fullname[80]; /* Full name, for directory app */
135 char email[80]; /* E-mail address */
136 char pager[80]; /* E-mail address to pager (no attachment) */
137 char serveremail[80]; /* From: Mail address */
138 char mailcmd[160]; /* Configurable mail command */
139 char language[MAX_LANGUAGE]; /* Config: Language setting */
140 char zonetag[80]; /* Time zone */
152 struct ast_vm_user *next;
158 char msg_format[512];
159 struct vm_zone *next;
178 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
179 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
180 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);
181 static int vm_delete(char *file);
183 static char ext_pass_cmd[128];
185 static char *tdesc = "Comedian Mail (Voicemail System)";
187 static char *adapp = "\x00\x00\x00\x0F";
189 static char *adsec = "\x9B\xDB\xF7\xAC";
191 static char *addesc = "Comedian Mail";
193 static int adver = 1;
195 static char *synopsis_vm =
196 "Leave a voicemail message";
198 static char *descrip_vm =
199 " VoiceMail([s|u|b]extension[@context][&extension[@context]][...]): Leaves"
200 "voicemail for a given extension (must be configured in voicemail.conf).\n"
201 " If the extension is preceded by \n"
202 "* 's' then instructions for leaving the message will be skipped.\n"
203 "* 'u' then the \"unavailable\" message will be played.\n"
204 " (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.\n"
205 "* 'b' then the the busy message will be played (that is, busy instead of unavail).\n"
206 "If the caller presses '0' (zero) during the prompt, the call jumps to\n"
207 "extension 'o' in the current context.\n"
208 "If the caller presses '*' during the prompt, the call jumps to\n"
209 "extension 'a' in the current context.\n"
210 "If the requested mailbox does not exist, and there exists a priority\n"
211 "n + 101, then that priority will be taken next.\n"
212 "When multiple mailboxes are specified, the unavailable or busy message\n"
213 "will be taken from the first mailbox specified.\n"
214 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
215 "Otherwise, it returns 0.\n";
217 static char *synopsis_vmain =
218 "Enter voicemail system";
220 static char *descrip_vmain =
221 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
222 "for the checking of voicemail. The mailbox can be passed as the option,\n"
223 "which will stop the voicemail system from prompting the user for the mailbox.\n"
224 "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
225 "a context is specified, logins are considered in that voicemail context only.\n"
226 "Returns -1 if the user hangs up or 0 otherwise.\n";
228 static char *synopsis_vm_box_exists =
229 "Check if vmbox exists";
231 static char *descrip_vm_box_exists =
232 " MailboxExists(mailbox[@context]): Conditionally branches to priority n+101\n"
233 "if the specified voice mailbox exists.\n";
236 /* Leave a message */
237 static char *capp = "VoiceMail2";
238 static char *app = "VoiceMail";
240 /* Check mail, control, etc */
241 static char *capp2 = "VoiceMailMain2";
242 static char *app2 = "VoiceMailMain";
244 static char *app3 = "MailboxExists";
246 AST_MUTEX_DEFINE_STATIC(vmlock);
247 struct ast_vm_user *users;
248 struct ast_vm_user *usersl;
249 struct vm_zone *zones = NULL;
250 struct vm_zone *zonesl = NULL;
251 static int attach_voicemail;
252 static int maxsilence;
253 static int silencethreshold = 128;
254 static char serveremail[80];
255 static char mailcmd[160]; /* Configurable mail cmd */
256 static char externnotify[160];
258 static char vmfmts[80];
259 static int vmminmessage;
260 static int vmmaxmessage;
263 static int maxlogins;
267 static int saycidinfo;
268 static int svmailinfo;
270 static int skipaftercmd;
271 static char dialcontext[80];
272 static char callcontext[80];
273 static char exitcontext[80];
275 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
278 static char *emailbody = NULL;
279 static int pbxskip = 0;
280 static char *emailsubject = NULL;
281 static char fromstring[100];
282 static char pagerfromstring[100];
283 static char emailtitle[100];
284 static char charset[32] = "ISO-8859-1";
291 static void populate_defaults(struct ast_vm_user *vmu)
305 strncpy(vmu->callback, callcontext, sizeof(vmu->callback) -1);
307 strncpy(vmu->dialout, dialcontext, sizeof(vmu->dialout) -1);
309 strncpy(vmu->exit, exitcontext, sizeof(vmu->exit) -1);
312 static void apply_options(struct ast_vm_user *vmu, char *options)
314 /* Destructively Parse options and apply */
315 char *stringp = ast_strdupa(options);
319 while((s = strsep(&stringp, "|"))) {
321 if ((var = strsep(&value, "=")) && value) {
322 if (!strcasecmp(var, "attach")) {
327 } else if (!strcasecmp(var, "serveremail")) {
328 strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
329 } else if (!strcasecmp(var, "language")) {
330 strncpy(vmu->language, value, sizeof(vmu->language) - 1);
331 } else if (!strcasecmp(var, "tz")) {
332 strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
333 } else if (!strcasecmp(var, "delete")) {
334 vmu->delete = ast_true(value);
335 } else if (!strcasecmp(var, "saycid")){
340 } else if (!strcasecmp(var,"sendvoicemail")){
345 } else if (!strcasecmp(var, "review")){
350 } else if (!strcasecmp(var, "operator")){
355 } else if (!strcasecmp(var, "envelope")){
360 } else if (!strcasecmp(var, "callback")) {
361 strncpy(vmu->callback, value, sizeof(vmu->callback) -1);
362 } else if (!strcasecmp(var, "dialout")) {
363 strncpy(vmu->dialout, value, sizeof(vmu->dialout) -1);
364 } else if (!strcasecmp(var, "exitcontext")) {
365 strncpy(vmu->exit, value, sizeof(vmu->exit) -1);
374 #include "mysql-vm-routines.h"
380 char dboption[256] = "";
381 AST_MUTEX_DEFINE_STATIC(postgreslock);
383 static int sql_init(void)
385 ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption);
386 /* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */
388 dbhandler=PQconnectdb(dboption);
389 if (PQstatus(dbhandler) == CONNECTION_BAD) {
390 ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler));
393 /* fprintf(stderr,"postgres login OK\n"); */
397 static void sql_close(void)
403 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
411 char options[160] = "";
412 struct ast_vm_user *retval;
414 retval=malloc(sizeof(struct ast_vm_user));
416 /* fprintf(stderr,"postgres find_user:\n"); */
419 memset(retval, 0, sizeof(struct ast_vm_user));
422 strncpy(retval->mailbox, mailbox, sizeof(retval->mailbox) - 1);
425 strncpy(retval->context, context, sizeof(retval->context) - 1);
429 strncpy(retval->context, "default", sizeof(retval->context) - 1);
431 populate_defaults(retval);
432 snprintf(query, sizeof(query), "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", retval->context, mailbox);
434 /* fprintf(stderr,"postgres find_user: query = %s\n",query); */
435 ast_mutex_lock(&postgreslock);
436 PGSQLres=PQexec(dbhandler,query);
437 if (PGSQLres!=NULL) {
438 if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
439 PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
440 PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
442 ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres));
445 ast_mutex_unlock(&postgreslock);
449 numFields = PQnfields(PGSQLres);
450 /* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */
451 if (PQntuples(PGSQLres) != 1) {
452 ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox);
454 ast_mutex_unlock(&postgreslock);
458 for (i=0; i<numFields; i++) {
459 fname = PQfname(PGSQLres,i);
460 if (!strcmp(fname, "password") && !PQgetisnull (PGSQLres,0,i)) {
461 strncpy(retval->password, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1);
462 } else if (!strcmp(fname, "fullname")) {
463 strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1);
464 } else if (!strcmp(fname, "email")) {
465 strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1);
466 } else if (!strcmp(fname, "pager")) {
467 strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1);
468 } else if (!strcmp(fname, "options")) {
469 strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1);
470 apply_options(retval, options);
475 ast_mutex_unlock(&postgreslock);
479 ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler));
480 ast_mutex_unlock(&postgreslock);
485 } /* malloc() retval */
490 static void vm_change_password(struct ast_vm_user *vmu, char *password)
495 snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->context, vmu->mailbox, vmu->password);
497 snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password);
499 /* fprintf(stderr,"postgres change_password: query = %s\n",query); */
500 ast_mutex_lock(&postgreslock);
501 PQexec(dbhandler, query);
502 strncpy(vmu->password, password, sizeof(vmu->password) - 1);
503 ast_mutex_unlock(&postgreslock);
506 static void reset_user_pw(char *context, char *mailbox, char *password)
511 snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox);
513 snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox);
515 ast_mutex_lock(&postgreslock);
516 /* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */
517 PQexec(dbhandler, query);
518 ast_mutex_unlock(&postgreslock);
521 #endif /* Postgres */
525 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
527 /* This function could be made to generate one from a database, too */
528 struct ast_vm_user *vmu=NULL, *cur;
529 ast_mutex_lock(&vmlock);
532 if ((!context || !strcasecmp(context, cur->context)) &&
533 (!strcasecmp(mailbox, cur->mailbox)))
541 /* Make a copy, so that on a reload, we have no race */
542 vmu = malloc(sizeof(struct ast_vm_user));
544 memcpy(vmu, cur, sizeof(struct ast_vm_user));
552 ast_mutex_unlock(&vmlock);
556 static int reset_user_pw(char *context, char *mailbox, char *newpass)
558 /* This function could be made to generate one from a database, too */
559 struct ast_vm_user *cur;
561 ast_mutex_lock(&vmlock);
564 if ((!context || !strcasecmp(context, cur->context)) &&
565 (!strcasecmp(mailbox, cur->mailbox)))
570 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
573 ast_mutex_unlock(&vmlock);
577 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
580 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
581 ast_safe_system(buf);
584 static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
586 /* There's probably a better way of doing this. */
587 /* That's why I've put the password change in a separate function. */
588 /* This could also be done with a database function */
595 char currcontext[256] ="";
596 char tmpin[AST_CONFIG_MAX_PATH];
597 char tmpout[AST_CONFIG_MAX_PATH];
598 char *user, *pass, *rest, *trim, *tempcontext;
600 snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR);
601 snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR);
602 configin = fopen(tmpin,"r");
604 configout = fopen(tmpout,"w+");
607 if(!configin || !configout) {
611 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
615 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
619 while (!feof(configin)) {
620 /* Read in the line */
621 fgets(inbuf, sizeof(inbuf), configin);
623 if (!feof(configin)) {
624 /* Make a backup of it */
625 memcpy(orig, inbuf, sizeof(orig));
626 /* Strip trailing \n and comment */
627 inbuf[strlen(inbuf) - 1] = '\0';
628 user = strchr(inbuf, ';');
634 /* check for '[' (opening of context name ) */
635 tempcontext = strchr(user, '[');
637 strncpy(currcontext, tempcontext +1,
638 sizeof(currcontext) - 1);
639 /* now check for ']' */
640 tempcontext = strchr(currcontext, ']');
644 currcontext[0] = '\0';
646 pass = strchr(user, '=');
649 while(*trim && *trim < 33) {
659 while(*pass && *pass < 33)
663 rest = strchr(pass,',');
671 /* Compare user, pass AND context */
672 if (user && *user && !strcmp(user, vmu->mailbox) &&
673 pass && *pass && !strcmp(pass, vmu->password) &&
674 currcontext && *currcontext && !strcmp(currcontext, vmu->context)) {
675 /* This is the line */
677 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
679 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
682 /* Put it back like it was */
683 fprintf(configout, orig);
690 unlink((char *)tmpin);
691 rename((char *)tmpout,(char *)tmpin);
692 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
693 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
697 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
699 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
702 static int make_file(char *dest, int len, char *dir, int num)
704 return snprintf(dest, len, "%s/msg%04d", dir, num);
708 inbuf(struct baseio *bio, FILE *fi)
715 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
730 inchar(struct baseio *bio, FILE *fi)
732 if(bio->iocp>=bio->iolen)
736 return bio->iobuf[bio->iocp++];
740 ochar(struct baseio *bio, int c, FILE *so)
742 if(bio->linelength>=BASELINELEN) {
743 if(fputs(eol,so)==EOF)
749 if(putc(((unsigned char)c),so)==EOF)
757 static int base_encode(char *filename, FILE *so)
759 unsigned char dtable[BASEMAXINLINE];
764 memset(&bio, 0, sizeof(bio));
765 bio.iocp = BASEMAXINLINE;
767 if ( !(fi = fopen(filename, "rb"))) {
768 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
776 dtable[26+i+9]= 'j'+i;
780 dtable[26+i+18]= 's'+i;
789 unsigned char igroup[3],ogroup[4];
792 igroup[0]= igroup[1]= igroup[2]= 0;
795 if ( (c = inchar(&bio, fi)) == EOF) {
800 igroup[n]= (unsigned char)c;
804 ogroup[0]= dtable[igroup[0]>>2];
805 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
806 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
807 ogroup[3]= dtable[igroup[2]&0x3F];
817 ochar(&bio, ogroup[i], so);
821 if(fputs(eol,so)==EOF)
829 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *dur, char *date, char *passdata, size_t passdatasize)
831 /* Prepare variables for substition in email body and subject */
832 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
833 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
834 snprintf(passdata, passdatasize, "%d", msgnum);
835 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
836 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
837 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (callerid ? callerid : "an unknown caller"));
838 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
841 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)
851 char tmp[80] = "/tmp/astmail-XXXXXX";
855 struct vm_zone *the_zone = NULL;
856 if (vmu && ast_strlen_zero(vmu->email)) {
857 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
860 if (!strcmp(format, "wav49"))
862 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, attach_voicemail);
863 /* Make a temporary file instead of piping directly to sendmail, in case the mail
867 p = fdopen(pfd, "w");
874 gethostname(host, sizeof(host));
875 if (strchr(srcemail, '@'))
876 strncpy(who, srcemail, sizeof(who)-1);
878 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
880 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
883 /* Does this user have a timezone specified? */
884 if (!ast_strlen_zero(vmu->zonetag)) {
885 /* Find the zone in the list */
889 if (!strcmp(z->name, vmu->zonetag)) {
898 ast_localtime(&t,&tm,the_zone->timezone);
900 ast_localtime(&t,&tm,NULL);
901 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
902 fprintf(p, "Date: %s\n", date);
905 struct ast_channel *ast = ast_channel_alloc(0);
908 int vmlen = strlen(fromstring)*3 + 200;
909 if ((passdata = alloca(vmlen))) {
910 memset(passdata, 0, vmlen);
911 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
912 pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen);
913 fprintf(p, "From: %s <%s>\n",passdata,who);
914 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
915 ast_channel_free(ast);
916 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
918 fprintf(p, "From: Asterisk PBX <%s>\n", who);
919 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
922 struct ast_channel *ast = ast_channel_alloc(0);
925 int vmlen = strlen(emailsubject)*3 + 200;
926 if ((passdata = alloca(vmlen))) {
927 memset(passdata, 0, vmlen);
928 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
929 pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen);
930 fprintf(p, "Subject: %s\n",passdata);
931 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
932 ast_channel_free(ast);
933 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
937 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
942 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
944 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
945 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)rand(), mailbox, getpid(), host);
946 fprintf(p, "MIME-Version: 1.0\n");
947 if (attach_user_voicemail) {
948 /* Something unique. */
949 snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand());
951 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
953 fprintf(p, "--%s\n", bound);
955 fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
956 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
958 struct ast_channel *ast = ast_channel_alloc(0);
961 int vmlen = strlen(emailbody)*3 + 200;
962 if ((passdata = alloca(vmlen))) {
963 memset(passdata, 0, vmlen);
964 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
965 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
966 fprintf(p, "%s\n",passdata);
967 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
968 ast_channel_free(ast);
969 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
971 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
973 "in mailbox %s from %s, on %s so you might\n"
974 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
975 dur, msgnum + 1, mailbox, (callerid ? callerid : "an unknown caller"), date);
977 if (attach_user_voicemail) {
978 fprintf(p, "--%s\n", bound);
979 fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
980 fprintf(p, "Content-Transfer-Encoding: base64\n");
981 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
982 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
984 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
985 base_encode(fname, p);
986 fprintf(p, "\n\n--%s--\n.\n", bound);
989 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
990 ast_safe_system(tmp2);
991 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
993 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
999 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, int duration, struct ast_vm_user *vmu)
1007 char tmp[80] = "/tmp/astmail-XXXXXX";
1011 struct vm_zone *the_zone = NULL;
1015 p = fdopen(pfd, "w");
1023 gethostname(host, sizeof(host));
1024 if (strchr(srcemail, '@'))
1025 strncpy(who, srcemail, sizeof(who)-1);
1027 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1029 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1032 /* Does this user have a timezone specified? */
1033 if (!ast_strlen_zero(vmu->zonetag)) {
1034 /* Find the zone in the list */
1038 if (!strcmp(z->name, vmu->zonetag)) {
1047 ast_localtime(&t,&tm,the_zone->timezone);
1049 ast_localtime(&t,&tm,NULL);
1051 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1052 fprintf(p, "Date: %s\n", date);
1054 if (*pagerfromstring) {
1055 struct ast_channel *ast = ast_channel_alloc(0);
1058 int vmlen = strlen(fromstring)*3 + 200;
1059 if ((passdata = alloca(vmlen))) {
1060 memset(passdata, 0, vmlen);
1061 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
1062 pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen);
1063 fprintf(p, "From: %s <%s>\n",passdata,who);
1065 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1066 ast_channel_free(ast);
1067 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1069 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1070 fprintf(p, "To: %s\n", pager);
1071 fprintf(p, "Subject: New VM\n\n");
1072 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
1073 fprintf(p, "New %s long msg in box %s\n"
1074 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
1076 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1077 ast_safe_system(tmp2);
1078 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
1080 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1086 static int get_date(char *s, int len)
1091 localtime_r(&t,&tm);
1092 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
1095 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
1099 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
1100 if (ast_fileexists(fn, NULL, NULL) > 0) {
1101 res = ast_streamfile(chan, fn, chan->language);
1104 res = ast_waitstream(chan, ecodes);
1108 res = ast_streamfile(chan, "vm-theperson", chan->language);
1111 res = ast_waitstream(chan, ecodes);
1114 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
1119 res = ast_streamfile(chan, "vm-isonphone", chan->language);
1121 res = ast_streamfile(chan, "vm-isunavail", chan->language);
1124 res = ast_waitstream(chan, ecodes);
1128 static int play_and_wait(struct ast_channel *chan, char *fn)
1131 d = ast_streamfile(chan, fn, chan->language);
1134 d = ast_waitstream(chan, AST_DIGIT_ANY);
1135 ast_stopstream(chan);
1139 static int play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep)
1143 int x, fmtcnt=1, res=-1,outmsg=0;
1144 struct ast_frame *f;
1145 struct ast_filestream *others[MAX_OTHER_FORMATS];
1146 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
1147 char *sfmt[MAX_OTHER_FORMATS];
1150 struct ast_dsp *sildet; /* silence detector dsp */
1151 int totalsilence = 0;
1153 int gotsilence = 0; /* did we timeout for silence? */
1155 char prependfile[80];
1157 /* barf if no pointer passed to store duration in */
1158 if (duration == NULL) {
1159 ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
1163 ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1164 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
1166 if (playfile || beep) {
1168 d = play_and_wait(chan, playfile);
1170 d = ast_streamfile(chan, "beep",chan->language);
1172 d = ast_waitstream(chan,"");
1176 strncpy(prependfile, recordfile, sizeof(prependfile) -1);
1177 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
1179 fmts = ast_strdupa(fmt);
1182 strsep(&stringp, "|");
1183 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1184 sfmt[0] = ast_strdupa(fmts);
1186 while((fmt = strsep(&stringp, "|"))) {
1187 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1188 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1191 sfmt[fmtcnt++] = ast_strdupa(fmt);
1195 end=start; /* pre-initialize end to be same as start in case we never get into loop */
1196 for (x=0;x<fmtcnt;x++) {
1197 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1198 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
1204 sildet = ast_dsp_new(); /* Create the silence detector */
1206 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1209 ast_dsp_set_threshold(sildet, silencethreshold);
1211 if (maxsilence > 0) {
1212 rfmt = chan->readformat;
1213 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1215 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1221 /* Loop forever, writing the packets we read to the writer(s), until
1222 we read a # or get a hangup */
1225 res = ast_waitfor(chan, 2000);
1227 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1228 /* Try one more time in case of masq */
1229 res = ast_waitfor(chan, 2000);
1231 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1243 if (f->frametype == AST_FRAME_VOICE) {
1244 /* write each format */
1245 for (x=0;x<fmtcnt;x++) {
1248 res = ast_writestream(others[x], f);
1251 /* Silence Detection */
1252 if (maxsilence > 0) {
1254 ast_dsp_silence(sildet, f, &dspsilence);
1256 totalsilence = dspsilence;
1260 if (totalsilence > maxsilence) {
1261 /* Ended happily with silence */
1262 if (option_verbose > 2)
1263 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
1270 /* Exit on any error */
1272 ast_log(LOG_WARNING, "Error writing frame\n");
1276 } else if (f->frametype == AST_FRAME_VIDEO) {
1277 /* Write only once */
1278 ast_writestream(others[0], f);
1279 } else if (f->frametype == AST_FRAME_DTMF) {
1280 /* stop recording with any digit */
1281 if (option_verbose > 2)
1282 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1290 if (maxtime < (end - start)) {
1291 if (option_verbose > 2)
1292 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1301 if (end == start) time(&end);
1303 if (option_verbose > 2)
1304 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1308 /* delete all the prepend files */
1309 for (x=0;x<fmtcnt;x++) {
1312 ast_closestream(others[x]);
1313 ast_filedelete(prependfile, sfmt[x]);
1318 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
1320 *duration = end - start;
1326 struct ast_frame *fr;
1327 for (x=0;x<fmtcnt;x++) {
1328 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
1329 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
1330 if (!others[x] || !realfiles[x])
1333 ast_stream_rewind(others[x], totalsilence-200);
1335 ast_stream_rewind(others[x], 200);
1336 ast_truncstream(others[x]);
1337 /* add the original file too */
1338 while ((fr = ast_readframe(realfiles[x]))) {
1339 ast_writestream(others[x],fr);
1341 ast_closestream(others[x]);
1342 ast_closestream(realfiles[x]);
1343 ast_filerename(prependfile, recordfile, sfmt[x]);
1345 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
1347 ast_filedelete(prependfile, sfmt[x]);
1351 if (ast_set_read_format(chan, rfmt)) {
1352 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1357 /* Let them know it worked */
1358 ast_streamfile(chan, "auth-thankyou", chan->language);
1359 ast_waitstream(chan, "");
1365 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration)
1369 int x, fmtcnt=1, res=-1,outmsg=0;
1370 struct ast_frame *f;
1371 struct ast_filestream *others[MAX_OTHER_FORMATS];
1372 char *sfmt[MAX_OTHER_FORMATS];
1375 struct ast_dsp *sildet; /* silence detector dsp */
1376 int totalsilence = 0;
1378 int gotsilence = 0; /* did we timeout for silence? */
1381 /* barf if no pointer passed to store duration in */
1382 if (duration == NULL) {
1383 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
1387 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1388 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
1391 d = play_and_wait(chan, playfile);
1393 d = ast_streamfile(chan, "beep",chan->language);
1395 d = ast_waitstream(chan,"");
1400 fmts = ast_strdupa(fmt);
1403 strsep(&stringp, "|");
1404 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1405 sfmt[0] = ast_strdupa(fmts);
1407 while((fmt = strsep(&stringp, "|"))) {
1408 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1409 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1412 sfmt[fmtcnt++] = ast_strdupa(fmt);
1416 end=start; /* pre-initialize end to be same as start in case we never get into loop */
1417 for (x=0;x<fmtcnt;x++) {
1418 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1419 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
1426 sildet = ast_dsp_new(); /* Create the silence detector */
1428 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1431 ast_dsp_set_threshold(sildet, silencethreshold);
1433 if (maxsilence > 0) {
1434 rfmt = chan->readformat;
1435 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1437 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1443 /* Loop forever, writing the packets we read to the writer(s), until
1444 we read a # or get a hangup */
1447 res = ast_waitfor(chan, 2000);
1449 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1450 /* Try one more time in case of masq */
1451 res = ast_waitfor(chan, 2000);
1453 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1465 if (f->frametype == AST_FRAME_VOICE) {
1466 /* write each format */
1467 for (x=0;x<fmtcnt;x++) {
1468 res = ast_writestream(others[x], f);
1471 /* Silence Detection */
1472 if (maxsilence > 0) {
1474 ast_dsp_silence(sildet, f, &dspsilence);
1476 totalsilence = dspsilence;
1480 if (totalsilence > maxsilence) {
1481 /* Ended happily with silence */
1482 if (option_verbose > 2)
1483 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
1490 /* Exit on any error */
1492 ast_log(LOG_WARNING, "Error writing frame\n");
1496 } else if (f->frametype == AST_FRAME_VIDEO) {
1497 /* Write only once */
1498 ast_writestream(others[0], f);
1499 } else if (f->frametype == AST_FRAME_DTMF) {
1500 if (f->subclass == '#') {
1501 if (option_verbose > 2)
1502 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1509 if (f->subclass == '0') {
1510 /* Check for a '0' during message recording also, in case caller wants operator */
1511 if (option_verbose > 2)
1512 ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
1520 if (maxtime < (end - start)) {
1521 if (option_verbose > 2)
1522 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1531 if (end == start) time(&end);
1533 if (option_verbose > 2)
1534 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1539 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1542 *duration = end - start;
1544 for (x=0;x<fmtcnt;x++) {
1548 ast_stream_rewind(others[x], totalsilence-200);
1550 ast_stream_rewind(others[x], 200);
1551 ast_truncstream(others[x]);
1552 ast_closestream(others[x]);
1555 if (ast_set_read_format(chan, rfmt)) {
1556 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1561 /* Let them know recording is stopped */
1562 ast_streamfile(chan, "auth-thankyou", chan->language);
1563 ast_waitstream(chan, "");
1570 static void free_user(struct ast_vm_user *vmu)
1576 static void free_zone(struct vm_zone *z)
1581 static char *mbox(int id)
1609 static int copy(char *infile, char *outfile)
1617 #ifdef HARDLINK_WHEN_POSSIBLE
1618 /* Hard link if possible; saves disk space & is faster */
1619 if (link(infile, outfile)) {
1621 if ((ifd = open(infile, O_RDONLY)) < 0) {
1622 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1625 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1626 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1631 len = read(ifd, buf, sizeof(buf));
1633 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1639 res = write(ofd, buf, len);
1641 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1651 #ifdef HARDLINK_WHEN_POSSIBLE
1653 /* Hard link succeeded */
1659 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid);
1661 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)
1663 char fromdir[256], todir[256], frompath[256], topath[256];
1664 char *frombox = mbox(imbox);
1667 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
1669 make_dir(todir, sizeof(todir), recip->context, "", "");
1670 /* It's easier just to try to make it than to check for its existence */
1671 if (mkdir(todir, 0700) && (errno != EEXIST))
1672 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1673 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
1674 /* It's easier just to try to make it than to check for its existence */
1675 if (mkdir(todir, 0700) && (errno != EEXIST))
1676 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1677 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
1678 if (mkdir(todir, 0700) && (errno != EEXIST))
1679 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1681 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
1682 make_file(frompath, sizeof(frompath), fromdir, msgnum);
1685 make_file(topath, sizeof(topath), todir, recipmsgnum);
1686 if (ast_fileexists(topath, NULL, chan->language) <= 0)
1689 } while(recipmsgnum < MAXMSG);
1690 if (recipmsgnum < MAXMSG) {
1691 char frompath2[256],topath2[256];
1692 ast_filecopy(frompath, topath, NULL);
1693 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
1694 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
1695 copy(frompath2, topath2);
1697 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
1700 notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
1703 static void run_externnotify(char *context, char *extension)
1705 char arguments[255];
1706 int newvoicemails = 0, oldvoicemails = 0;
1708 if(!ast_strlen_zero(externnotify)) {
1709 if (ast_app_messagecount(extension, &newvoicemails, &oldvoicemails)) {
1710 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
1712 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
1713 ast_log(LOG_DEBUG,"Executing %s\n", arguments);
1714 ast_safe_system(arguments);
1720 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
1733 char prefile[256]="";
1734 char ext_context[256] = "";
1737 char ecodes[16] = "#";
1738 char tmp[256] = "", *tmpptr;
1739 struct ast_vm_user *vmu;
1740 struct ast_vm_user svm;
1742 strncpy(tmp, ext, sizeof(tmp) - 1);
1744 context = strchr(tmp, '@');
1748 tmpptr = strchr(context, '&');
1750 tmpptr = strchr(ext, '&');
1758 if ((vmu = find_user(&svm, context, ext))) {
1759 /* Setup pre-file if appropriate */
1760 if (strcmp(vmu->context, "default"))
1761 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
1763 strncpy(ext_context, vmu->context, sizeof(ext_context) - 1);
1765 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
1767 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
1768 make_dir(dir, sizeof(dir), vmu->context, "", "");
1769 /* It's easier just to try to make it than to check for its existence */
1770 if (mkdir(dir, 0700) && (errno != EEXIST))
1771 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1772 make_dir(dir, sizeof(dir), vmu->context, ext, "");
1773 /* It's easier just to try to make it than to check for its existence */
1774 if (mkdir(dir, 0700) && (errno != EEXIST))
1775 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1776 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
1777 if (mkdir(dir, 0700) && (errno != EEXIST))
1778 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1780 /* Check current or macro-calling context for special extensions */
1781 if (!ast_strlen_zero(vmu->exit)) {
1782 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->callerid))
1783 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
1784 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->callerid))
1785 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
1786 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->callerid)) {
1787 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
1791 if (!ast_strlen_zero(vmu->exit)) {
1792 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->callerid))
1793 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
1794 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->callerid))
1795 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
1796 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->callerid)) {
1797 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
1801 /* Play the beginning intro if desired */
1802 if (!ast_strlen_zero(prefile)) {
1803 if (ast_fileexists(prefile, NULL, NULL) > 0) {
1804 if (ast_streamfile(chan, prefile, chan->language) > -1)
1805 res = ast_waitstream(chan, ecodes);
1807 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
1808 res = invent_message(chan, vmu->context, ext, busy, ecodes);
1811 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
1817 /* On a '#' we skip the instructions */
1821 if (!res && !silent) {
1822 res = ast_streamfile(chan, INTRO, chan->language);
1824 res = ast_waitstream(chan, ecodes);
1831 ast_stopstream(chan);
1832 /* Check for a '*' here in case the caller wants to escape from voicemail to something
1833 other than the operator -- an automated attendant or mailbox login for example */
1835 strncpy(chan->exten, "a", sizeof(chan->exten) - 1);
1836 if (!ast_strlen_zero(vmu->exit)) {
1837 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
1838 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
1839 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1845 /* Check for a '0' here */
1848 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
1849 if (!ast_strlen_zero(vmu->exit)) {
1850 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
1851 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
1852 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1859 /* Unless we're *really* silent, try to send the beep */
1860 res = ast_streamfile(chan, "beep", chan->language);
1862 res = ast_waitstream(chan, "");
1868 /* The meat of recording the message... All the announcements and beeps have been played*/
1869 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
1870 if (!ast_strlen_zero(fmt)) {
1873 make_file(fn, sizeof(fn), dir, msgnum);
1874 if (ast_fileexists(fn, NULL, chan->language) <= 0)
1877 } while(msgnum < MAXMSG);
1878 if (msgnum < MAXMSG) {
1879 /* Store information */
1880 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
1881 txt = fopen(txtfile, "w+");
1883 get_date(date, sizeof(date));
1886 "; Message Information file\n"
1904 chan->callerid ? chan->callerid : "Unknown",
1905 date, (long)time(NULL));
1908 ast_log(LOG_WARNING, "Error opening text file for output\n");
1909 res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration);
1914 fd = open(txtfile, O_APPEND | O_WRONLY);
1916 txt = fdopen(fd, "a");
1918 fprintf(txt, "duration=%d\n", duration);
1923 if (duration < vmminmessage) {
1924 if (option_verbose > 2)
1925 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
1927 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
1930 /* Are there to be more recipients of this message? */
1932 struct ast_vm_user recipu, *recip;
1933 char *exten, *context;
1935 exten = strsep(&tmpptr, "&");
1936 context = strchr(exten, '@');
1941 if ((recip = find_user(&recipu, context, exten))) {
1942 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
1946 notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
1948 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
1950 res = ast_waitstream(chan, "");
1951 ast_log(LOG_WARNING, "No more messages possible\n");
1954 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
1958 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
1959 /*Send the call to n+101 priority, where n is the current priority*/
1960 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
1961 chan->priority+=100;
1967 static int count_messages(char *dir)
1971 for (x=0;x<MAXMSG;x++) {
1972 make_file(fn, sizeof(fn), dir, x);
1973 if (ast_fileexists(fn, NULL, NULL) < 1)
1979 static int say_and_wait(struct ast_channel *chan, int num, char *language)
1982 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
1986 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
1993 char *dbox = mbox(box);
1995 make_file(sfn, sizeof(sfn), dir, msg);
1996 make_dir(ddir, sizeof(ddir), context, username, dbox);
1998 for (x=0;x<MAXMSG;x++) {
1999 make_file(dfn, sizeof(dfn), ddir, x);
2000 if (ast_fileexists(dfn, NULL, NULL) < 0)
2005 ast_filecopy(sfn, dfn, NULL);
2006 if (strcmp(sfn, dfn)) {
2007 snprintf(txt, sizeof(txt), "%s.txt", sfn);
2008 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
2014 static int adsi_logo(unsigned char *buf)
2017 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
2018 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
2022 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
2030 bytes += adsi_data_mode(buf + bytes);
2031 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2034 bytes += adsi_logo(buf);
2035 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2037 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
2039 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2040 bytes += adsi_data_mode(buf + bytes);
2041 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2043 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
2045 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
2046 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2047 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2048 bytes += adsi_voice_mode(buf + bytes, 0);
2049 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2056 bytes += adsi_logo(buf);
2057 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2058 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
2059 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2060 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2063 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
2064 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
2065 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
2066 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
2067 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
2068 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
2069 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2072 /* Add another dot */
2074 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
2075 bytes += adsi_voice_mode(buf + bytes, 0);
2077 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2078 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2082 /* These buttons we load but don't use yet */
2083 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
2084 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
2085 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
2086 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
2087 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
2088 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
2089 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2092 /* Add another dot */
2094 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
2095 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2096 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2101 snprintf(num, sizeof(num), "%d", x);
2102 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
2104 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
2105 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2108 /* Add another dot */
2110 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
2111 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2112 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2115 if (adsi_end_download(chan)) {
2117 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
2118 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2119 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2120 bytes += adsi_voice_mode(buf + bytes, 0);
2121 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2125 bytes += adsi_download_disconnect(buf + bytes);
2126 bytes += adsi_voice_mode(buf + bytes, 0);
2127 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2129 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
2134 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
2135 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2137 ast_log(LOG_DEBUG, "Restarting session...\n");
2140 /* Load the session now */
2141 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
2143 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
2145 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
2147 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2151 static void adsi_begin(struct ast_channel *chan, int *useadsi)
2154 if (!adsi_available(chan))
2156 x = adsi_load_session(chan, adapp, adver, 1);
2160 if (adsi_load_vmail(chan, useadsi)) {
2161 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
2168 static void adsi_login(struct ast_channel *chan)
2172 unsigned char keys[8];
2174 if (!adsi_available(chan))
2179 /* Set one key for next */
2180 keys[3] = ADSI_KEY_APPS + 3;
2182 bytes += adsi_logo(buf + bytes);
2183 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
2184 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
2185 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2186 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
2187 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
2188 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
2189 bytes += adsi_set_keys(buf + bytes, keys);
2190 bytes += adsi_voice_mode(buf + bytes, 0);
2191 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2194 static void adsi_password(struct ast_channel *chan)
2198 unsigned char keys[8];
2200 if (!adsi_available(chan))
2205 /* Set one key for next */
2206 keys[3] = ADSI_KEY_APPS + 3;
2208 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2209 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
2210 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
2211 bytes += adsi_set_keys(buf + bytes, keys);
2212 bytes += adsi_voice_mode(buf + bytes, 0);
2213 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2216 static void adsi_folders(struct ast_channel *chan, int start, char *label)
2220 unsigned char keys[8];
2223 if (!adsi_available(chan))
2227 y = ADSI_KEY_APPS + 12 + start + x;
2228 if (y > ADSI_KEY_APPS + 12 + 4)
2230 keys[x] = ADSI_KEY_SKT | y;
2232 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
2236 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
2237 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
2238 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2239 bytes += adsi_set_keys(buf + bytes, keys);
2240 bytes += adsi_voice_mode(buf + bytes, 0);
2242 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2245 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
2248 char buf[256], buf1[256], buf2[256];
2254 char datetime[21]="";
2257 unsigned char keys[8];
2261 if (!adsi_available(chan))
2264 /* Retrieve important info */
2265 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
2266 f = fopen(fn2, "r");
2269 fgets(buf, sizeof(buf), f);
2273 strsep(&stringp, "=");
2274 val = strsep(&stringp, "=");
2275 if (val && !ast_strlen_zero(val)) {
2276 if (!strcmp(buf, "callerid"))
2277 strncpy(cid, val, sizeof(cid) - 1);
2278 if (!strcmp(buf, "origdate"))
2279 strncpy(datetime, val, sizeof(datetime) - 1);
2285 /* New meaning for keys */
2287 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2292 /* No prev key, provide "Folder" instead */
2293 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2295 if (vms->curmsg >= vms->lastmsg) {
2296 /* If last message ... */
2298 /* but not only message, provide "Folder" instead */
2299 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2300 bytes += adsi_voice_mode(buf + bytes, 0);
2303 /* Otherwise if only message, leave blank */
2308 if (!ast_strlen_zero(cid)) {
2309 ast_callerid_parse(cid, &name, &num);
2313 name = "Unknown Caller";
2315 /* If deleted, show "undeleted" */
2317 if (vms->deleted[vms->curmsg])
2318 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2321 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2322 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
2323 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
2324 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
2326 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2327 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2328 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
2329 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
2330 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2331 bytes += adsi_set_keys(buf + bytes, keys);
2332 bytes += adsi_voice_mode(buf + bytes, 0);
2334 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2337 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
2341 unsigned char keys[8];
2345 if (!adsi_available(chan))
2348 /* New meaning for keys */
2350 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2356 /* No prev key, provide "Folder" instead */
2357 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2359 if (vms->curmsg >= vms->lastmsg) {
2360 /* If last message ... */
2362 /* but not only message, provide "Folder" instead */
2363 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2365 /* Otherwise if only message, leave blank */
2370 /* If deleted, show "undeleted" */
2371 if (vms->deleted[vms->curmsg])
2372 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2375 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2376 bytes += adsi_set_keys(buf + bytes, keys);
2377 bytes += adsi_voice_mode(buf + bytes, 0);
2379 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2382 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
2384 char buf[256] = "", buf1[256] = "", buf2[256] = "";
2386 unsigned char keys[8];
2389 char *newm = (vms->newmessages == 1) ? "message" : "messages";
2390 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
2391 if (!adsi_available(chan))
2393 if (vms->newmessages) {
2394 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
2395 if (vms->oldmessages) {
2396 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
2397 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
2399 snprintf(buf2, sizeof(buf2), "%s.", newm);
2401 } else if (vms->oldmessages) {
2402 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
2403 snprintf(buf2, sizeof(buf2), "%s.", oldm);
2405 strncpy(buf1, "You have no messages.", sizeof(buf1) - 1);
2409 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2410 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2411 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2414 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2418 /* Don't let them listen if there are none */
2419 if (vms->lastmsg < 0)
2421 bytes += adsi_set_keys(buf + bytes, keys);
2423 bytes += adsi_voice_mode(buf + bytes, 0);
2425 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2428 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
2430 char buf[256] = "", buf1[256] = "", buf2[256] = "";
2432 unsigned char keys[8];
2435 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
2437 if (!adsi_available(chan))
2440 /* Original command keys */
2442 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2447 if ((vms->lastmsg + 1) < 1)
2450 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
2451 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
2453 if (vms->lastmsg + 1)
2454 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
2456 strncpy(buf2, "no messages.", sizeof(buf2) - 1);
2457 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2458 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2459 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
2460 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2461 bytes += adsi_set_keys(buf + bytes, keys);
2463 bytes += adsi_voice_mode(buf + bytes, 0);
2465 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2470 static void adsi_clear(struct ast_channel *chan)
2474 if (!adsi_available(chan))
2476 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2477 bytes += adsi_voice_mode(buf + bytes, 0);
2479 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2483 static void adsi_goodbye(struct ast_channel *chan)
2488 if (!adsi_available(chan))
2490 bytes += adsi_logo(buf + bytes);
2491 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
2492 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
2493 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2494 bytes += adsi_voice_mode(buf + bytes, 0);
2496 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2499 /*--- get_folder: Folder menu ---*/
2500 /* Plays "press 1 for INBOX messages" etc
2501 Should possibly be internationalized
2503 static int get_folder(struct ast_channel *chan, int start)
2508 d = play_and_wait(chan, "vm-press"); /* "Press" */
2511 for (x = start; x< 5; x++) { /* For all folders */
2512 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
2514 d = play_and_wait(chan, "vm-for"); /* "for" */
2517 if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Spanish, French or Portuguese syntax */
2518 d = play_and_wait(chan, "vm-messages"); /* "messages */
2521 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
2522 d = play_and_wait(chan, fn);
2525 } else { /* Default English */
2526 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
2527 d = play_and_wait(chan, fn);
2530 d = play_and_wait(chan, "vm-messages"); /* "messages */
2534 d = ast_waitfordigit(chan, 500);
2538 d = play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
2541 d = ast_waitfordigit(chan, 4000);
2545 static int get_folder2(struct ast_channel *chan, char *fn, int start)
2548 res = play_and_wait(chan, fn); /* Folder name */
2549 while (((res < '0') || (res > '9')) &&
2550 (res != '#') && (res >= 0)) {
2551 res = get_folder(chan, 0);
2556 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context)
2562 while((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
2567 /* prepend a message to the current message and return */
2570 snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
2571 cmd = play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1);
2581 cmd = play_and_wait(chan,"vm-forwardoptions");
2582 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
2584 cmd = play_and_wait(chan,"vm-starmain");
2585 /* "press star to return to the main menu" */
2587 cmd = ast_waitfordigit(chan,6000);
2599 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid)
2601 char todir[256], fn[256], ext_context[256], *stringp;
2603 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
2604 make_file(fn, sizeof(fn), todir, msgnum);
2605 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
2607 /* Attach only the first format */
2608 fmt = ast_strdupa(fmt);
2611 strsep(&stringp, "|");
2613 if (!ast_strlen_zero(vmu->email)) {
2614 int attach_user_voicemail = attach_voicemail;
2615 char *myserveremail = serveremail;
2616 if (vmu->attach > -1)
2617 attach_user_voicemail = vmu->attach;
2618 if (!ast_strlen_zero(vmu->serveremail))
2619 myserveremail = vmu->serveremail;
2620 sendmail(myserveremail, vmu, msgnum, vmu->mailbox, callerid, fn, fmt, duration, attach_user_voicemail);
2623 if (!ast_strlen_zero(vmu->pager)) {
2624 char *myserveremail = serveremail;
2625 if (!ast_strlen_zero(vmu->serveremail))
2626 myserveremail = vmu->serveremail;
2627 sendpage(myserveremail, vmu->pager, msgnum, vmu->mailbox, callerid, duration, vmu);
2630 ast_log(LOG_ERROR, "Out of memory\n");
2637 /* Leave voicemail for someone */
2638 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context));
2639 run_externnotify(chan->context, ext_context);
2643 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt,int flag)
2650 struct ast_config *mif;
2654 char ext_context[256]="";
2655 int res = 0, cmd = 0;
2656 struct ast_vm_user *receiver, *extensions = NULL, *vmtmp = NULL, *vmfree;
2659 int saved_messages = 0, found = 0;
2660 int valid_extensions = 0;
2661 while (!res && !valid_extensions) {
2662 res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */
2665 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
2667 /* start all over if no username */
2668 if (ast_strlen_zero(username))
2671 s = strsep(&stringp, "*");
2672 /* start optimistic */
2673 valid_extensions = 1;
2675 /* find_user is going to malloc since we have a NULL as first argument */
2676 if ((receiver = find_user(NULL, context, s))) {
2678 vmtmp = extensions = receiver;
2680 vmtmp->next = receiver;
2685 valid_extensions = 0;
2688 s = strsep(&stringp, "*");
2690 /* break from the loop of reading the extensions */
2691 if (valid_extensions)
2693 /* "I am sorry, that's not a valid extension. Please try again." */
2694 res = play_and_wait(chan, "pbx-invalid");
2696 /* check if we're clear to proceed */
2697 if (!extensions || !valid_extensions)
2700 if(flag==1)/*Send VoiceMail*/
2702 cmd=leave_voicemail(chan,username,0,0,0);
2705 else /*Forward VoiceMail*/
2707 cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context);
2709 while(!res && vmtmp) {
2710 /* if (play_and_wait(chan, "vm-savedto"))
2713 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
2714 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
2715 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmtmp->mailbox, vmtmp->context);
2716 ast_log(LOG_DEBUG, sys);
2717 ast_safe_system(sys);
2719 todircount = count_messages(todir);
2720 strncpy(tmp, fmt, sizeof(tmp) - 1);
2722 while((s = strsep(&stringp, "|"))) {
2723 /* XXX This is a hack -- we should use build_filename or similar XXX */
2724 if (!strcasecmp(s, "wav49"))
2726 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
2727 ast_log(LOG_DEBUG, sys);
2728 ast_safe_system(sys);
2730 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
2731 ast_log(LOG_DEBUG, sys);
2732 ast_safe_system(sys);
2733 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
2735 /* load the information on the source message so we can send an e-mail like a new message */
2736 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
2737 if ((mif=ast_load(miffile))) {
2739 /* set callerid and duration variables */
2740 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
2741 s = ast_variable_retrieve(mif, NULL, "duration");
2746 if (!ast_strlen_zero(vmtmp->email)) {
2747 int attach_user_voicemail = attach_voicemail;
2748 char *myserveremail = serveremail;
2749 if (vmtmp->attach > -1)
2750 attach_user_voicemail = vmtmp->attach;
2751 if (!ast_strlen_zero(vmtmp->serveremail))
2752 myserveremail = vmtmp->serveremail;
2753 sendmail(myserveremail, vmtmp, todircount, vmtmp->mailbox, callerid, fn, tmp, duration, attach_user_voicemail);
2756 if (!ast_strlen_zero(vmtmp->pager)) {
2757 char *myserveremail = serveremail;
2758 if (!ast_strlen_zero(vmtmp->serveremail))
2759 myserveremail = vmtmp->serveremail;
2760 sendpage(myserveremail, vmtmp->pager, todircount, vmtmp->mailbox, callerid, duration, vmtmp);
2763 ast_destroy(mif); /* or here */
2765 /* Leave voicemail for someone */
2766 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
2767 run_externnotify(chan->context, ext_context);
2771 vmtmp = vmtmp->next;
2774 if (saved_messages > 0) {
2775 /* give confirmation that the message was saved */
2776 /* commented out since we can't forward batches yet
2777 if (saved_messages == 1)
2778 res = play_and_wait(chan, "vm-message");
2780 res = play_and_wait(chan, "vm-messages");
2782 res = play_and_wait(chan, "vm-saved"); */
2784 res = play_and_wait(chan, "vm-msgsaved");
2788 return res ? res : cmd;
2791 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
2794 if ((res = ast_streamfile(chan, file, chan->language)))
2795 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2797 res = ast_waitstream(chan, AST_DIGIT_ANY);
2801 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
2803 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", skipms);
2806 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, char *origtime, char *filename)
2809 struct vm_zone *the_zone = NULL;
2813 if (sscanf(origtime,"%ld",&tin) < 1) {
2814 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
2819 /* Does this user have a timezone specified? */
2820 if (!ast_strlen_zero(vmu->zonetag)) {
2821 /* Find the zone in the list */
2825 if (!strcmp(z->name, vmu->zonetag)) {
2833 /* No internal variable parsing for now, so we'll comment it out for the time being */
2835 /* Set the DIFF_* variables */
2836 localtime_r(&t, &time_now);
2837 gettimeofday(&tv_now,NULL);
2838 tnow = tv_now.tv_sec;
2839 localtime_r(&tnow,&time_then);
2841 /* Day difference */
2842 if (time_now.tm_year == time_then.tm_year)
2843 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
2845 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
2846 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
2848 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
2851 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
2852 else if (!strcasecmp(chan->language,"nl")) /* DUTCH syntax */
2853 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
2855 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
2857 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
2864 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, char *context, int callback)
2868 char *callerid, *name;
2869 char prefile[256]="";
2872 /* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
2873 /* 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 */
2874 if((cid == NULL)||(context == NULL))
2877 /* Strip off caller ID number from name */
2878 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
2879 ast_callerid_parse(cid, &name, &callerid);
2880 if((callerid != NULL)&&(!res)&&(!ast_strlen_zero(callerid))){
2881 /* Check for internal contexts and only */
2882 /* say extension when the call didn't come from an internal context in the list */
2883 for(i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
2884 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
2885 if((strcmp(cidinternalcontexts[i], context) == 0))
2888 if(i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
2890 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/greet", context, callerid);
2891 if (!ast_strlen_zero(prefile)) {
2892 /* See if we can find a recorded name for this person instead of their extension number */
2893 if (ast_fileexists(prefile, NULL, NULL) > 0) {
2894 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
2896 res = wait_file2(chan, vms, "vm-from");
2897 res = ast_streamfile(chan, prefile, chan->language) > -1;
2898 res = ast_waitstream(chan, "");
2900 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
2901 /* BB: Say "from extension" as one saying to sound smoother */
2903 res = wait_file2(chan, vms, "vm-from-extension");
2904 res = ast_say_digit_str(chan, callerid, "", chan->language);
2911 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
2912 /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
2914 res = wait_file2(chan, vms, "vm-from-phonenumber");
2915 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
2919 /* Number unknown */
2920 ast_log(LOG_DEBUG, "VM-CID: From an unknown number");
2922 /* BB: Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
2923 res = wait_file2(chan, vms, "vm-unknown-caller");
2928 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
2931 char filename[256],*origtime, *cid, *context;
2932 struct ast_config *msg_cfg;
2935 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
2936 adsi_message(chan, vms);
2938 res = wait_file2(chan, vms, "vm-first"); /* "First" */
2939 else if (vms->curmsg == vms->lastmsg)
2940 res = wait_file2(chan, vms, "vm-last"); /* "last" */
2942 res = wait_file2(chan, vms, "vm-message"); /* "message" */
2943 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
2945 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
2949 /* Retrieve info from VM attribute file */
2950 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2951 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
2952 msg_cfg = ast_load(filename);
2954 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
2958 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
2961 cid = ast_variable_retrieve(msg_cfg, "message", "callerid");
2963 context = ast_variable_retrieve(msg_cfg, "message", "context");
2964 if(!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */
2965 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
2967 if ((!res)&&(vmu->envelope))
2968 res = play_message_datetime(chan, vmu, origtime, filename);
2969 if ((!res)&&(vmu->saycid))
2970 res = play_message_callerid(chan, vms, cid, context, 0);
2971 /* Allow pressing '1' to skip envelope / callerid */
2974 ast_destroy(msg_cfg);
2977 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
2978 vms->heard[vms->curmsg] = 1;
2979 res = wait_file(chan, vms, vms->fn);
2984 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
2986 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
2987 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2988 vms->lastmsg = count_messages(vms->curdir) - 1;
2989 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
2992 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
2995 char ntxt[256] = "";
2997 if (vms->lastmsg > -1) {
2998 /* Get the deleted messages fixed */
3000 for (x=0;x < MAXMSG;x++) {
3001 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
3002 /* Save this message. It's not in INBOX or hasn't been heard */
3003 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
3004 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
3007 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
3008 if (strcmp(vms->fn, vms->fn2)) {
3009 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
3010 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
3011 ast_filerename(vms->fn, vms->fn2, NULL);
3014 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
3015 /* Move to old folder before deleting */
3016 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
3019 for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
3020 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
3021 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
3026 memset(vms->deleted, 0, sizeof(vms->deleted));
3027 memset(vms->heard, 0, sizeof(vms->heard));
3030 /* Default English syntax */
3031 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
3033 /* Introduce messages they have */
3035 res = play_and_wait(chan, "vm-youhave");
3037 if (vms->newmessages) {
3038 res = say_and_wait(chan, vms->newmessages, chan->language);
3040 res = play_and_wait(chan, "vm-INBOX");
3041 if (vms->oldmessages && !res)
3042 res = play_and_wait(chan, "vm-and");
3044 if ((vms->newmessages == 1))
3045 res = play_and_wait(chan, "vm-message");
3047 res = play_and_wait(chan, "vm-messages");
3051 if (!res && vms->oldmessages) {
3052 res = say_and_wait(chan, vms->oldmessages, chan->language);
3054 res = play_and_wait(chan, "vm-Old");
3056 if (vms->oldmessages == 1)
3057 res = play_and_wait(chan, "vm-message");
3059 res = play_and_wait(chan, "vm-messages");
3063 if (!vms->oldmessages && !vms->newmessages) {
3064 res = play_and_wait(chan, "vm-no");
3066 res = play_and_wait(chan, "vm-messages");
3074 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
3076 /* Introduce messages they have */
3078 res = play_and_wait(chan, "vm-youhave");
3080 if (vms->newmessages) {
3081 if ((vms->newmessages == 1))
3082 res = play_and_wait(chan, "digits/1F");
3084 res = say_and_wait(chan, vms->newmessages, chan->language);
3086 res = play_and_wait(chan, "vm-INBOX");
3087 if (vms->oldmessages && !res)
3088 res = play_and_wait(chan, "vm-and");
3090 if ((vms->newmessages == 1))
3091 res = play_and_wait(chan, "vm-message");
3093 res = play_and_wait(chan, "vm-messages");
3097 if (!res && vms->oldmessages) {
3098 if (vms->oldmessages == 1)
3099 res = play_and_wait(chan, "digits/1F");
3101 res = say_and_wait(chan, vms->oldmessages, chan->language);
3103 res = play_and_wait(chan, "vm-Old");
3105 if (vms->oldmessages == 1)
3106 res = play_and_wait(chan, "vm-message");
3108 res = play_and_wait(chan, "vm-messages");
3112 if (!vms->oldmessages && !vms->newmessages) {
3113 res = play_and_wait(chan, "vm-no");
3115 res = play_and_wait(chan, "vm-messages");
3122 /* SPANISH syntax */
3123 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
3125 /* Introduce messages they have */
3127 if (!vms->oldmessages && !vms->newmessages) {
3128 res = play_and_wait(chan, "vm-youhaveno");
3130 res = play_and_wait(chan, "vm-messages");
3132 res = play_and_wait(chan, "vm-youhave");
3135 if (vms->newmessages) {
3137 if ((vms->newmessages == 1)) {
3138 res = play_and_wait(chan, "digits/1M");
3140 res = play_and_wait(chan, "vm-message");
3142 res = play_and_wait(chan, "vm-INBOXs");
3144 res = say_and_wait(chan, vms->newmessages, chan->language);
3146 res = play_and_wait(chan, "vm-messages");
3148 res = play_and_wait(chan, "vm-INBOX");
3151 if (vms->oldmessages && !res)
3152 res = play_and_wait(chan, "vm-and");
3154 if (vms->oldmessages) {
3156 if (vms->oldmessages == 1) {
3157 res = play_and_wait(chan, "digits/1M");
3159 res = play_and_wait(chan, "vm-message");
3161 res = play_and_wait(chan, "vm-Olds");
3163 res = say_and_wait(chan, vms->oldmessages, chan->language);
3165 res = play_and_wait(chan, "vm-messages");
3167 res = play_and_wait(chan, "vm-Old");
3176 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
3178 /* Introduce messages they have */
3180 res = play_and_wait(chan, "vm-youhave");
3182 if (vms->newmessages) {
3183 res = say_and_wait(chan, vms->newmessages, chan->language);
3185 res = play_and_wait(chan, "vm-INBOX");
3186 if (vms->oldmessages && !res)
3187 res = play_and_wait(chan, "vm-and");
3189 if ((vms->newmessages == 1))
3190 res = play_and_wait(chan, "vm-message");
3192 res = play_and_wait(chan, "vm-messages");
3196 if (!res && vms->oldmessages) {
3197 res = say_and_wait(chan, vms->oldmessages, chan->language);
3199 if (vms->oldmessages == 1)
3200 res = play_and_wait(chan, "vm-message");
3202 res = play_and_wait(chan, "vm-messages");
3205 res = play_and_wait(chan, "vm-Old");
3208 if (!vms->oldmessages && !vms->newmessages) {
3209 res = play_and_wait(chan, "vm-no");
3211 res = play_and_wait(chan, "vm-messages");
3219 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
3221 /* Introduce messages they have */
3223 res = play_and_wait(chan, "vm-youhave");
3225 if (vms->newmessages) {
3226 res = say_and_wait(chan, vms->newmessages, chan->language);
3228 if (vms->oldmessages == 1)
3229 res = play_and_wait(chan, "vm-INBOXs");
3231 res = play_and_wait(chan, "vm-INBOX");
3233 if (vms->oldmessages && !res)
3234 res = play_and_wait(chan, "vm-and");
3236 if ((vms->newmessages == 1))
3237 res = play_and_wait(chan, "vm-message");
3239 res = play_and_wait(chan, "vm-messages");
3243 if (!res && vms->oldmessages) {
3244 res = say_and_wait(chan, vms->oldmessages, chan->language);
3246 if (vms->oldmessages == 1)
3247 res = play_and_wait(chan, "vm-Olds");
3249 res = play_and_wait(chan, "vm-Old");
3252 if (vms->oldmessages == 1)
3253 res = play_and_wait(chan, "vm-message");
3255 res = play_and_wait(chan, "vm-messages");
3259 if (!vms->oldmessages && !vms->newmessages) {
3260 res = play_and_wait(chan, "vm-no");
3262 res = play_and_wait(chan, "vm-messages");
3269 /* PORTUGUESE syntax */
3270 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
3272 /* Introduce messages they have */
3274 res = play_and_wait(chan, "vm-youhave");
3276 if (vms->newmessages) {
3277 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
3279 if ((vms->newmessages == 1)) {
3280 res = play_and_wait(chan, "vm-message");
3282 res = play_and_wait(chan, "vm-INBOXs");
3284 res = play_and_wait(chan, "vm-messages");
3286 res = play_and_wait(chan, "vm-INBOX");
3289 if (vms->oldmessages && !res)
3290 res = play_and_wait(chan, "vm-and");
3292 if (!res && vms->oldmessages) {
3293 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
3295 if (vms->oldmessages == 1) {
3296 res = play_and_wait(chan, "vm-message");
3298 res = play_and_wait(chan, "vm-Olds");
3300 res = play_and_wait(chan, "vm-messages");
3302 res = play_and_wait(chan, "vm-Old");
3307 if (!vms->oldmessages && !vms->newmessages) {
3308 res = play_and_wait(chan, "vm-no");
3310 res = play_and_wait(chan, "vm-messages");
3317 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)