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>
38 #include <sys/types.h>
42 /* we define USESQLVM when we have MySQL or POSTGRES */
44 #include <mysql/mysql.h>
50 * PostgreSQL routines written by Otmar Lendl <lendl@nic.at>
52 #include <postgresql/libpq-fe.h>
57 static inline int sql_init(void) { return 0; }
58 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 DIGITS_DIR AST_SOUNDS "/digits/"
93 unsigned char iobuf[BASEMAXINLINE];
96 /* Structure for linked list of users */
104 char serveremail[80];
105 char mailcmd[160]; /* Configurable mail command */
109 struct ast_vm_user *next;
115 char msg_format[512];
116 struct vm_zone *next;
136 static char *tdesc = "Comedian Mail (Voicemail System)";
138 static char *adapp = "CoMa";
140 static char *adsec = "_AST";
142 static char *addesc = "Comedian Mail";
144 static int adver = 1;
146 static char *synopsis_vm =
147 "Leave a voicemail message";
149 static char *descrip_vm =
150 " VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given\n"
151 "extension (must be configured in voicemail.conf). If the extension is\n"
152 "preceded by an 's' then instructions for leaving the message will be\n"
153 "skipped. If the extension is preceeded by 'u' then the \"unavailable\"\n"
154 "message will be played (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it\n"
155 "exists. If the extension is preceeded by a 'b' then the the busy message\n"
156 "will be played (that is, busy instead of unavail).\n"
157 "If the requested mailbox does not exist, and there exists a priority\n"
158 "n + 101, then that priority will be taken next.\n"
159 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
160 "Otherwise, it returns 0.\n";
162 static char *synopsis_vmain =
163 "Enter voicemail system";
165 static char *descrip_vmain =
166 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
167 "for the checking of voicemail. The mailbox can be passed as the option,\n"
168 "which will stop the voicemail system from prompting the user for the mailbox.\n"
169 "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
170 "a context is specified, logins are considered in that context only.\n"
171 "Returns -1 if the user hangs up or 0 otherwise.\n";
173 /* Leave a message */
174 static char *capp = "VoiceMail2";
175 static char *app = "VoiceMail";
177 /* Check mail, control, etc */
178 static char *capp2 = "VoiceMailMain2";
179 static char *app2 = "VoiceMailMain";
181 static ast_mutex_t vmlock = AST_MUTEX_INITIALIZER;
182 struct ast_vm_user *users;
183 struct ast_vm_user *usersl;
184 struct vm_zone *zones = NULL;
185 struct vm_zone *zonesl = NULL;
186 static int attach_voicemail;
187 static int maxsilence;
188 static int silencethreshold = 128;
189 static char serveremail[80];
190 static char mailcmd[160]; /* Configurable mail cmd */
192 static char vmfmts[80];
193 static int vmmaxmessage;
196 static int maxlogins;
198 static char *emailbody = NULL;
199 static int pbxskip = 0;
200 static char fromstring[100];
201 static char emailtitle[100];
208 static void apply_options(struct ast_vm_user *vmu, char *options)
210 /* Destructively Parse options and apply */
211 char *stringp = ast_strdupa(options);
214 while((s = strsep(&stringp, "|"))) {
216 if ((var = strsep(&value, "=")) && value) {
217 if (!strcasecmp(var, "attach")) {
222 } else if (!strcasecmp(var, "serveremail")) {
223 strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
224 } else if (!strcasecmp(var, "tz")) {
225 strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
233 #include "mysql-vm-routines.h"
240 ast_mutex_t postgreslock;
242 static int sql_init(void)
244 ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption);
245 /* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */
247 dbhandler=PQconnectdb(dboption);
248 if (PQstatus(dbhandler) == CONNECTION_BAD) {
249 ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler));
252 ast_mutex_init(&postgreslock);
254 /* fprintf(stderr,"postgres login OK\n"); */
258 static void sql_close(void)
264 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
272 char options[160] = "";
273 struct ast_vm_user *retval;
275 retval=malloc(sizeof(struct ast_vm_user));
277 /* fprintf(stderr,"postgres find_user:\n"); */
280 *retval->mailbox='\0';
281 *retval->context='\0';
282 strcpy(retval->password, "NULL");
283 *retval->fullname='\0';
286 *retval->serveremail='\0';
291 strcpy(retval->mailbox, mailbox);
294 strcpy(retval->context, context);
298 strcpy(retval->context, "default");
300 sprintf(query, "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", retval->context, mailbox);
302 /* fprintf(stderr,"postgres find_user: query = %s\n",query); */
303 ast_mutex_lock(&postgreslock);
304 PGSQLres=PQexec(dbhandler,query);
305 if (PGSQLres!=NULL) {
306 if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
307 PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
308 PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
310 ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres));
313 ast_mutex_unlock(&postgreslock);
317 numFields = PQnfields(PGSQLres);
318 /* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */
319 if (PQntuples(PGSQLres) != 1) {
320 ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox);
322 ast_mutex_unlock(&postgreslock);
326 for (i=0; i<numFields; i++) {
327 fname = PQfname(PGSQLres,i);
328 if (!strcmp(fname, "password") && !PQgetisnull (PGSQLres,0,i)) {
329 strncpy(retval->password, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1);
330 } else if (!strcmp(fname, "fullname")) {
331 strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1);
332 } else if (!strcmp(fname, "email")) {
333 strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1);
334 } else if (!strcmp(fname, "pager")) {
335 strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1);
336 } else if (!strcmp(fname, "options")) {
337 strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1);
338 apply_options(retval, options);
343 ast_mutex_unlock(&postgreslock);
347 ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler));
348 ast_mutex_unlock(&postgreslock);
353 } /* malloc() retval */
358 static void vm_change_password(struct ast_vm_user *vmu, char *password)
363 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);
365 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password);
367 /* fprintf(stderr,"postgres change_password: query = %s\n",query); */
368 ast_mutex_lock(&postgreslock);
369 PQexec(dbhandler, query);
370 strcpy(vmu->password, password);
371 ast_mutex_unlock(&postgreslock);
374 static void reset_user_pw(char *context, char *mailbox, char *password)
379 sprintf(query, "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox);
381 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox);
383 ast_mutex_lock(&postgreslock);
384 /* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */
385 PQexec(dbhandler, query);
386 ast_mutex_unlock(&postgreslock);
389 #endif /* Postgres */
393 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
395 /* This function could be made to generate one from a database, too */
396 struct ast_vm_user *vmu=NULL, *cur;
397 ast_mutex_lock(&vmlock);
400 if ((!context || !strcasecmp(context, cur->context)) &&
401 (!strcasecmp(mailbox, cur->mailbox)))
409 /* Make a copy, so that on a reload, we have no race */
410 vmu = malloc(sizeof(struct ast_vm_user));
412 memcpy(vmu, cur, sizeof(struct ast_vm_user));
420 ast_mutex_unlock(&vmlock);
424 static int reset_user_pw(char *context, char *mailbox, char *newpass)
426 /* This function could be made to generate one from a database, too */
427 struct ast_vm_user *cur;
429 ast_mutex_lock(&vmlock);
432 if ((!context || !strcasecmp(context, cur->context)) &&
433 (!strcasecmp(mailbox, cur->mailbox)))
438 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
441 ast_mutex_unlock(&vmlock);
445 static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
447 /* There's probably a better way of doing this. */
448 /* That's why I've put the password change in a separate function. */
449 /* This could also be done with a database function */
456 char currcontext[256] ="";
457 char tmpin[AST_CONFIG_MAX_PATH];
458 char tmpout[AST_CONFIG_MAX_PATH];
459 char *user, *pass, *rest, *trim, *tempcontext;
461 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
462 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
463 configin = fopen((char *)tmpin,"r");
465 configout = fopen((char *)tmpout,"w+");
468 if(!configin || !configout) {
472 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
476 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
480 while (!feof(configin)) {
481 /* Read in the line */
482 fgets(inbuf, sizeof(inbuf), configin);
484 if (!feof(configin)) {
485 /* Make a backup of it */
486 memcpy(orig, inbuf, sizeof(orig));
487 /* Strip trailing \n and comment */
488 inbuf[strlen(inbuf) - 1] = '\0';
489 user = strchr(inbuf, ';');
495 /* check for '[' (opening of context name ) */
496 tempcontext = strchr(user, '[');
498 strncpy(currcontext, tempcontext +1,
499 sizeof(currcontext) - 1);
500 /* now check for ']' */
501 tempcontext = strchr(currcontext, ']');
505 currcontext[0] = '\0';
507 pass = strchr(user, '=');
510 while(*trim && *trim < 33) {
520 while(*pass && *pass < 33)
524 rest = strchr(pass,',');
532 /* Compare user, pass AND context */
533 if (user && *user && !strcmp(user, vmu->mailbox) &&
534 pass && *pass && !strcmp(pass, vmu->password) &&
535 currcontext && *currcontext && !strcmp(currcontext, vmu->context)) {
536 /* This is the line */
538 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
540 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
543 /* Put it back like it was */
544 fprintf(configout, orig);
551 unlink((char *)tmpin);
552 rename((char *)tmpout,(char *)tmpin);
553 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
554 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
558 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
560 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
563 static int make_file(char *dest, int len, char *dir, int num)
565 return snprintf(dest, len, "%s/msg%04d", dir, num);
569 inbuf(struct baseio *bio, FILE *fi)
576 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
591 inchar(struct baseio *bio, FILE *fi)
593 if(bio->iocp>=bio->iolen)
597 return bio->iobuf[bio->iocp++];
601 ochar(struct baseio *bio, int c, FILE *so)
603 if(bio->linelength>=BASELINELEN) {
604 if(fputs(eol,so)==EOF)
610 if(putc(((unsigned char)c),so)==EOF)
618 static int base_encode(char *filename, FILE *so)
620 unsigned char dtable[BASEMAXINLINE];
625 memset(&bio, 0, sizeof(bio));
626 bio.iocp = BASEMAXINLINE;
628 if ( !(fi = fopen(filename, "rb"))) {
629 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
637 dtable[26+i+9]= 'j'+i;
641 dtable[26+i+18]= 's'+i;
650 unsigned char igroup[3],ogroup[4];
653 igroup[0]= igroup[1]= igroup[2]= 0;
656 if ( (c = inchar(&bio, fi)) == EOF) {
661 igroup[n]= (unsigned char)c;
665 ogroup[0]= dtable[igroup[0]>>2];
666 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
667 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
668 ogroup[3]= dtable[igroup[2]&0x3F];
678 ochar(&bio, ogroup[i], so);
682 if(fputs(eol,so)==EOF)
690 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration, int attach_user_voicemail)
701 struct vm_zone *the_zone = NULL;
703 if (!strcmp(format, "wav49"))
705 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, attach_voicemail);
706 p = popen(mailcmd, "w");
708 gethostname(host, sizeof(host));
709 if (strchr(srcemail, '@'))
710 strncpy(who, srcemail, sizeof(who)-1);
712 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
714 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
717 /* Does this user have a timezone specified? */
718 if (strlen(vmu->zonetag)) {
719 /* Find the zone in the list */
723 if (!strcmp(z->name, vmu->zonetag)) {
732 ast_localtime(&t,&tm,the_zone->timezone);
734 ast_localtime(&t,&tm,NULL);
735 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
736 fprintf(p, "Date: %s\n", date);
739 fprintf(p, "From: %s <%s>\n", fromstring, who);
741 fprintf(p, "From: Asterisk PBX <%s>\n", who);
742 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
746 fprintf(p, emailtitle, msgnum, mailbox) ;
751 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
753 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
754 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
755 fprintf(p, "MIME-Version: 1.0\n");
756 if (attach_user_voicemail) {
758 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
760 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
762 fprintf(p, "--%s\n", bound);
764 fprintf(p, "Content-Type: text/plain; charset=ISO-8859-1\nContent-Transfer-Encoding: 8bit\n");
765 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
767 struct ast_channel *ast = ast_channel_alloc(0);
770 int vmlen = strlen(emailbody)*3 + 200;
771 if ((passdata = alloca(vmlen))) {
772 memset(passdata, 0, vmlen);
773 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
774 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
775 sprintf(passdata,"%d",msgnum);
776 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
777 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
778 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (callerid ? callerid : "an unknown caller"));
779 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
780 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
781 fprintf(p, "%s\n",passdata);
782 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
783 ast_channel_free(ast);
784 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
786 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
788 "in mailbox %s from %s, on %s so you might\n"
789 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
790 dur, msgnum + 1, mailbox, (callerid ? callerid : "an unknown caller"), date);
792 if (attach_user_voicemail) {
793 fprintf(p, "--%s\n", bound);
794 fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
795 fprintf(p, "Content-Transfer-Encoding: base64\n");
796 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
797 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
799 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
800 base_encode(fname, p);
801 fprintf(p, "\n\n--%s--\n.\n", bound);
804 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
806 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
812 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration, struct ast_vm_user *vmu)
821 struct vm_zone *the_zone = NULL;
822 p = popen(mailcmd, "w");
825 gethostname(host, sizeof(host));
826 if (strchr(srcemail, '@'))
827 strncpy(who, srcemail, sizeof(who)-1);
829 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
831 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
834 /* Does this user have a timezone specified? */
835 if (strlen(vmu->zonetag)) {
836 /* Find the zone in the list */
840 if (!strcmp(z->name, vmu->zonetag)) {
849 ast_localtime(&t,&tm,the_zone->timezone);
851 ast_localtime(&t,&tm,NULL);
853 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
854 fprintf(p, "Date: %s\n", date);
855 fprintf(p, "From: Asterisk PBX <%s>\n", who);
856 fprintf(p, "To: %s\n", pager);
857 fprintf(p, "Subject: New VM\n\n");
858 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
859 fprintf(p, "New %s long msg in box %s\n"
860 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
862 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
864 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
870 static int get_date(char *s, int len)
876 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
879 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
883 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
884 if (ast_fileexists(fn, NULL, NULL) > 0) {
885 res = ast_streamfile(chan, fn, chan->language);
888 res = ast_waitstream(chan, ecodes);
892 res = ast_streamfile(chan, "vm-theperson", chan->language);
895 res = ast_waitstream(chan, ecodes);
898 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
903 res = ast_streamfile(chan, "vm-isonphone", chan->language);
905 res = ast_streamfile(chan, "vm-isunavail", chan->language);
908 res = ast_waitstream(chan, ecodes);
912 static int play_and_wait(struct ast_channel *chan, char *fn)
915 d = ast_streamfile(chan, fn, chan->language);
918 d = ast_waitstream(chan, AST_DIGIT_ANY);
919 ast_stopstream(chan);
923 static int play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int beep)
927 int x, fmtcnt=1, res=-1,outmsg=0;
929 struct ast_filestream *others[MAX_OTHER_FORMATS];
930 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
931 char *sfmt[MAX_OTHER_FORMATS];
934 struct ast_dsp *sildet; /* silence detector dsp */
935 int totalsilence = 0;
937 int gotsilence = 0; /* did we timeout for silence? */
939 char prependfile[80];
941 ast_log(LOG_DEBUG,"play_and_preped: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
942 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
944 if (playfile || beep) {
946 d = play_and_wait(chan, playfile);
948 d = ast_streamfile(chan, "beep",chan->language);
950 d = ast_waitstream(chan,"");
954 strncpy(prependfile, recordfile, sizeof(prependfile) -1);
955 strcat(prependfile, "-prepend");
957 fmts = ast_strdupa(fmt);
960 strsep(&stringp, "|");
961 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
962 sfmt[0] = ast_strdupa(fmts);
964 while((fmt = strsep(&stringp, "|"))) {
965 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
966 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
969 sfmt[fmtcnt++] = ast_strdupa(fmt);
974 for (x=0;x<fmtcnt;x++) {
975 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
976 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
982 sildet = ast_dsp_new(); //Create the silence detector
984 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
987 ast_dsp_set_threshold(sildet, silencethreshold);
989 if (maxsilence > 0) {
990 rfmt = chan->readformat;
991 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
993 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
999 /* Loop forever, writing the packets we read to the writer(s), until
1000 we read a # or get a hangup */
1003 res = ast_waitfor(chan, 2000);
1005 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1006 /* Try one more time in case of masq */
1007 res = ast_waitfor(chan, 2000);
1009 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1021 if (f->frametype == AST_FRAME_VOICE) {
1022 /* write each format */
1023 for (x=0;x<fmtcnt;x++) {
1026 res = ast_writestream(others[x], f);
1029 /* Silence Detection */
1030 if (maxsilence > 0) {
1032 ast_dsp_silence(sildet, f, &dspsilence);
1034 totalsilence = dspsilence;
1038 if (totalsilence > maxsilence) {
1039 /* Ended happily with silence */
1046 /* Exit on any error */
1048 ast_log(LOG_WARNING, "Error writing frame\n");
1052 } else if (f->frametype == AST_FRAME_VIDEO) {
1053 /* Write only once */
1054 ast_writestream(others[0], f);
1055 } else if (f->frametype == AST_FRAME_DTMF) {
1056 /* stop recording with any digit */
1057 if (option_verbose > 2)
1058 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1066 if (maxtime < (end - start)) {
1067 if (option_verbose > 2)
1068 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1077 if (option_verbose > 2)
1078 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1082 /* delete all the prepend files */
1083 for (x=0;x<fmtcnt;x++) {
1086 ast_closestream(others[x]);
1087 ast_filedelete(prependfile, sfmt[x]);
1092 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
1099 struct ast_frame *fr;
1100 for (x=0;x<fmtcnt;x++) {
1101 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
1102 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
1103 if (!others[x] || !realfiles[x])
1106 ast_stream_rewind(others[x], totalsilence-200);
1108 ast_stream_rewind(others[x], 200);
1109 ast_truncstream(others[x]);
1110 /* add the original file too */
1111 while ((fr = ast_readframe(realfiles[x]))) {
1112 ast_writestream(others[x],fr);
1114 ast_closestream(others[x]);
1115 ast_closestream(realfiles[x]);
1116 ast_filerename(prependfile, recordfile, sfmt[x]);
1118 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
1120 ast_filedelete(prependfile, sfmt[x]);
1124 if (ast_set_read_format(chan, rfmt)) {
1125 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1130 /* Let them know it worked */
1131 ast_streamfile(chan, "vm-msgsaved", chan->language);
1132 ast_waitstream(chan, "");
1138 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
1142 int x, fmtcnt=1, res=-1,outmsg=0;
1143 struct ast_frame *f;
1144 struct ast_filestream *others[MAX_OTHER_FORMATS];
1145 char *sfmt[MAX_OTHER_FORMATS];
1148 struct ast_dsp *sildet; /* silence detector dsp */
1149 int totalsilence = 0;
1151 int gotsilence = 0; /* did we timeout for silence? */
1154 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
1155 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
1158 d = play_and_wait(chan, playfile);
1160 d = ast_streamfile(chan, "beep",chan->language);
1162 d = ast_waitstream(chan,"");
1167 fmts = ast_strdupa(fmt);
1170 strsep(&stringp, "|");
1171 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1172 sfmt[0] = ast_strdupa(fmts);
1174 while((fmt = strsep(&stringp, "|"))) {
1175 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1176 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1179 sfmt[fmtcnt++] = ast_strdupa(fmt);
1184 for (x=0;x<fmtcnt;x++) {
1185 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1186 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
1193 sildet = ast_dsp_new(); //Create the silence detector
1195 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1198 ast_dsp_set_threshold(sildet, silencethreshold);
1200 if (maxsilence > 0) {
1201 rfmt = chan->readformat;
1202 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1204 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1210 /* Loop forever, writing the packets we read to the writer(s), until
1211 we read a # or get a hangup */
1214 res = ast_waitfor(chan, 2000);
1216 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1217 /* Try one more time in case of masq */
1218 res = ast_waitfor(chan, 2000);
1220 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1232 if (f->frametype == AST_FRAME_VOICE) {
1233 /* write each format */
1234 for (x=0;x<fmtcnt;x++) {
1235 res = ast_writestream(others[x], f);
1238 /* Silence Detection */
1239 if (maxsilence > 0) {
1241 ast_dsp_silence(sildet, f, &dspsilence);
1243 totalsilence = dspsilence;
1247 if (totalsilence > maxsilence) {
1248 /* Ended happily with silence */
1255 /* Exit on any error */
1257 ast_log(LOG_WARNING, "Error writing frame\n");
1261 } else if (f->frametype == AST_FRAME_VIDEO) {
1262 /* Write only once */
1263 ast_writestream(others[0], f);
1264 } else if (f->frametype == AST_FRAME_DTMF) {
1265 if (f->subclass == '#') {
1266 if (option_verbose > 2)
1267 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1276 if (maxtime < (end - start)) {
1277 if (option_verbose > 2)
1278 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1287 if (option_verbose > 2)
1288 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1293 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1296 for (x=0;x<fmtcnt;x++) {
1300 ast_stream_rewind(others[x], totalsilence-200);
1302 ast_stream_rewind(others[x], 200);
1303 ast_truncstream(others[x]);
1304 ast_closestream(others[x]);
1307 if (ast_set_read_format(chan, rfmt)) {
1308 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1313 /* Let them know it worked */
1314 ast_streamfile(chan, "vm-msgsaved", chan->language);
1315 ast_waitstream(chan, "");
1323 static void free_user(struct ast_vm_user *vmu)
1329 static void free_zone(struct vm_zone *z)
1334 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
1344 char prefile[256]="";
1352 struct ast_vm_user *vmu;
1353 struct ast_vm_user svm;
1355 strncpy(tmp, ext, sizeof(tmp) - 1);
1357 context = strchr(tmp, '@');
1363 if ((vmu = find_user(&svm, context, ext))) {
1364 /* Setup pre-file if appropriate */
1366 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
1368 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
1369 make_dir(dir, sizeof(dir), vmu->context, "", "");
1370 /* It's easier just to try to make it than to check for its existence */
1371 if (mkdir(dir, 0700) && (errno != EEXIST))
1372 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1373 make_dir(dir, sizeof(dir), vmu->context, ext, "");
1374 /* It's easier just to try to make it than to check for its existence */
1375 if (mkdir(dir, 0700) && (errno != EEXIST))
1376 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1377 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
1378 if (mkdir(dir, 0700) && (errno != EEXIST))
1379 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1380 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
1382 /* Play the beginning intro if desired */
1383 if (strlen(prefile)) {
1384 if (ast_fileexists(prefile, NULL, NULL) > 0) {
1385 if (ast_streamfile(chan, prefile, chan->language) > -1)
1386 res = ast_waitstream(chan, "#0");
1388 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
1389 res = invent_message(chan, vmu->context, ext, busy, ecodes);
1392 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
1398 /* On a '#' we skip the instructions */
1402 if (!res && !silent) {
1403 res = ast_streamfile(chan, INTRO, chan->language);
1405 res = ast_waitstream(chan, ecodes);
1411 /* Check for a '0' here */
1413 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
1414 if (strlen(chan->macrocontext))
1415 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1421 /* Unless we're *really* silent, try to send the beep */
1422 res = ast_streamfile(chan, "beep", chan->language);
1424 res = ast_waitstream(chan, "");
1430 /* The meat of recording the message... All the announcements and beeps have been played*/
1431 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
1435 make_file(fn, sizeof(fn), dir, msgnum);
1436 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
1437 (chan->callerid ? chan->callerid : "Unknown"),
1438 vmu->fullname, ext, chan->name);
1439 if (ast_fileexists(fn, NULL, chan->language) <= 0)
1442 } while(msgnum < MAXMSG);
1443 if (msgnum < MAXMSG) {
1444 /* Store information */
1445 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
1446 txt = fopen(txtfile, "w+");
1448 get_date(date, sizeof(date));
1452 "; Message Information file\n"
1468 chan->callerid ? chan->callerid : "Unknown",
1469 date, (long)time(NULL));
1472 ast_log(LOG_WARNING, "Error opening text file for output\n");
1473 res = play_and_record(chan, NULL, fn, vmmaxmessage, fmt);
1476 txt = fopen(txtfile, "a");
1479 fprintf(txt, "duration=%ld\n", (long)(end-start));
1483 strsep(&stringp, "|");
1484 /* Send e-mail if applicable */
1485 if (strlen(vmu->email)) {
1486 int attach_user_voicemail = attach_voicemail;
1487 char *myserveremail = serveremail;
1488 if (vmu->attach > -1)
1489 attach_user_voicemail = vmu->attach;
1490 if (strlen(vmu->serveremail))
1491 myserveremail = vmu->serveremail;
1492 sendmail(myserveremail, vmu, msgnum, ext, chan->callerid, fn, fmt, end - start, attach_user_voicemail);
1494 if (strlen(vmu->pager)) {
1495 char *myserveremail = serveremail;
1496 if (strlen(vmu->serveremail))
1497 myserveremail = vmu->serveremail;
1498 sendpage(myserveremail, vmu->pager, msgnum, ext, chan->callerid, end - start, vmu);
1501 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
1503 res = ast_waitstream(chan, "");
1504 ast_log(LOG_WARNING, "No more messages possible\n");
1507 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
1510 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
1511 /*Send the call to n+101 priority, where n is the current priority*/
1512 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
1513 chan->priority+=100;
1515 /* Leave voicemail for someone */
1516 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
1520 static char *mbox(int id)
1548 static int count_messages(char *dir)
1552 for (x=0;x<MAXMSG;x++) {
1553 make_file(fn, sizeof(fn), dir, x);
1554 if (ast_fileexists(fn, NULL, NULL) < 1)
1560 static int say_and_wait(struct ast_channel *chan, int num)
1563 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
1567 static int copy(char *infile, char *outfile)
1574 if ((ifd = open(infile, O_RDONLY)) < 0) {
1575 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1578 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1579 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1584 len = read(ifd, buf, sizeof(buf));
1586 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1592 res = write(ofd, buf, len);
1594 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1606 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
1613 char *dbox = mbox(box);
1615 make_file(sfn, sizeof(sfn), dir, msg);
1616 make_dir(ddir, sizeof(ddir), context, username, dbox);
1618 for (x=0;x<MAXMSG;x++) {
1619 make_file(dfn, sizeof(dfn), ddir, x);
1620 if (ast_fileexists(dfn, NULL, NULL) < 0)
1625 ast_filecopy(sfn, dfn, NULL);
1626 if (strcmp(sfn, dfn)) {
1627 snprintf(txt, sizeof(txt), "%s.txt", sfn);
1628 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
1634 static int adsi_logo(unsigned char *buf)
1637 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
1638 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
1642 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
1650 bytes += adsi_data_mode(buf + bytes);
1651 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1654 bytes += adsi_logo(buf);
1655 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1657 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1659 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1660 bytes += adsi_data_mode(buf + bytes);
1661 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1663 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1665 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1666 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1667 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1668 bytes += adsi_voice_mode(buf + bytes, 0);
1669 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1676 bytes += adsi_logo(buf);
1677 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1678 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1679 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1680 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1683 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1684 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1685 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1686 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
1687 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1688 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1689 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1692 /* Add another dot */
1694 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1695 bytes += adsi_voice_mode(buf + bytes, 0);
1697 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1698 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1702 /* These buttons we load but don't use yet */
1703 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1704 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1705 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1706 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1707 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1708 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1709 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1712 /* Add another dot */
1714 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1715 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1716 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1721 snprintf(num, sizeof(num), "%d", x);
1722 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1724 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1725 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1728 /* Add another dot */
1730 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1731 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1732 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1735 if (adsi_end_download(chan)) {
1737 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1738 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1739 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1740 bytes += adsi_voice_mode(buf + bytes, 0);
1741 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1745 bytes += adsi_download_disconnect(buf + bytes);
1746 bytes += adsi_voice_mode(buf + bytes, 0);
1747 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1749 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1754 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1755 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1757 ast_log(LOG_DEBUG, "Restarting session...\n");
1760 /* Load the session now */
1761 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1763 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1765 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1767 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1771 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1774 if (!adsi_available(chan))
1776 x = adsi_load_session(chan, adapp, adver, 1);
1780 if (adsi_load_vmail(chan, useadsi)) {
1781 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1788 static void adsi_login(struct ast_channel *chan)
1792 unsigned char keys[8];
1794 if (!adsi_available(chan))
1799 /* Set one key for next */
1800 keys[3] = ADSI_KEY_APPS + 3;
1802 bytes += adsi_logo(buf + bytes);
1803 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1804 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1805 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1806 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1807 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1808 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1809 bytes += adsi_set_keys(buf + bytes, keys);
1810 bytes += adsi_voice_mode(buf + bytes, 0);
1811 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1814 static void adsi_password(struct ast_channel *chan)
1818 unsigned char keys[8];
1820 if (!adsi_available(chan))
1825 /* Set one key for next */
1826 keys[3] = ADSI_KEY_APPS + 3;
1828 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1829 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1830 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1831 bytes += adsi_set_keys(buf + bytes, keys);
1832 bytes += adsi_voice_mode(buf + bytes, 0);
1833 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1836 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1840 unsigned char keys[8];
1843 if (!adsi_available(chan))
1847 y = ADSI_KEY_APPS + 12 + start + x;
1848 if (y > ADSI_KEY_APPS + 12 + 4)
1850 keys[x] = ADSI_KEY_SKT | y;
1852 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1856 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1857 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1858 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1859 bytes += adsi_set_keys(buf + bytes, keys);
1860 bytes += adsi_voice_mode(buf + bytes, 0);
1862 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1865 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1868 char buf[256], buf1[256], buf2[256];
1874 char datetime[21]="";
1877 unsigned char keys[8];
1881 if (!adsi_available(chan))
1884 /* Retrieve important info */
1885 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1886 f = fopen(fn2, "r");
1889 fgets(buf, sizeof(buf), f);
1893 strsep(&stringp, "=");
1894 val = strsep(&stringp, "=");
1895 if (val && strlen(val)) {
1896 if (!strcmp(buf, "callerid"))
1897 strncpy(cid, val, sizeof(cid) - 1);
1898 if (!strcmp(buf, "origdate"))
1899 strncpy(datetime, val, sizeof(datetime) - 1);
1905 /* New meaning for keys */
1907 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1912 /* No prev key, provide "Folder" instead */
1913 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1916 /* If last message ... */
1918 /* but not only message, provide "Folder" instead */
1919 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1920 bytes += adsi_voice_mode(buf + bytes, 0);
1923 /* Otherwise if only message, leave blank */
1929 ast_callerid_parse(cid, &name, &num);
1933 name = "Unknown Caller";
1935 /* If deleted, show "undeleted" */
1938 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1941 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1942 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1943 strcasecmp(folder, "INBOX") ? " Messages" : "");
1944 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1946 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1947 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1948 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1949 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1950 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1951 bytes += adsi_set_keys(buf + bytes, keys);
1952 bytes += adsi_voice_mode(buf + bytes, 0);
1954 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1957 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1961 unsigned char keys[8];
1965 if (!adsi_available(chan))
1968 /* New meaning for keys */
1970 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1976 /* No prev key, provide "Folder" instead */
1977 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1980 /* If last message ... */
1982 /* but not only message, provide "Folder" instead */
1983 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1985 /* Otherwise if only message, leave blank */
1990 /* If deleted, show "undeleted" */
1992 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1995 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1996 bytes += adsi_set_keys(buf + bytes, keys);
1997 bytes += adsi_voice_mode(buf + bytes, 0);
1999 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2002 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
2004 char buf[256], buf1[256], buf2[256];
2006 unsigned char keys[8];
2009 char *newm = (new == 1) ? "message" : "messages";
2010 char *oldm = (old == 1) ? "message" : "messages";
2011 if (!adsi_available(chan))
2014 snprintf(buf1, sizeof(buf1), "You have %d new", new);
2016 strcat(buf1, " and");
2017 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
2019 snprintf(buf2, sizeof(buf2), "%s.", newm);
2022 snprintf(buf1, sizeof(buf1), "You have %d old", old);
2023 snprintf(buf2, sizeof(buf2), "%s.", oldm);
2025 strcpy(buf1, "You have no messages.");
2028 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2029 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2030 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2033 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2037 /* Don't let them listen if there are none */
2040 bytes += adsi_set_keys(buf + bytes, keys);
2042 bytes += adsi_voice_mode(buf + bytes, 0);
2044 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2047 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
2049 char buf[256], buf1[256], buf2[256];
2051 unsigned char keys[8];
2054 char *mess = (messages == 1) ? "message" : "messages";
2056 if (!adsi_available(chan))
2059 /* Original command keys */
2061 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2069 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
2070 strcasecmp(folder, "INBOX") ? " folder" : "");
2073 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
2075 strcpy(buf2, "no messages.");
2076 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2077 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2078 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
2079 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2080 bytes += adsi_set_keys(buf + bytes, keys);
2082 bytes += adsi_voice_mode(buf + bytes, 0);
2084 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2089 static void adsi_clear(struct ast_channel *chan)
2093 if (!adsi_available(chan))
2095 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2096 bytes += adsi_voice_mode(buf + bytes, 0);
2098 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2102 static void adsi_goodbye(struct ast_channel *chan)
2107 if (!adsi_available(chan))
2109 bytes += adsi_logo(buf + bytes);
2110 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
2111 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
2112 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2113 bytes += adsi_voice_mode(buf + bytes, 0);
2115 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2118 static int get_folder(struct ast_channel *chan, int start)
2123 d = play_and_wait(chan, "vm-press");
2126 for (x = start; x< 5; x++) {
2127 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
2129 d = play_and_wait(chan, "vm-for");
2132 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
2133 d = play_and_wait(chan, fn);
2136 d = play_and_wait(chan, "vm-messages");
2139 d = ast_waitfordigit(chan, 500);
2143 d = play_and_wait(chan, "vm-tocancel");
2146 d = ast_waitfordigit(chan, 4000);
2150 static int get_folder2(struct ast_channel *chan, char *fn, int start)
2153 res = play_and_wait(chan, fn);
2154 while (((res < '0') || (res > '9')) &&
2155 (res != '#') && (res >= 0)) {
2156 res = get_folder(chan, 0);
2161 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context)
2166 while((cmd >= 0) && (cmd != 't') && (cmd != '#')) {
2171 /* prepend a message to the current message and return */
2174 snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
2175 cmd = play_and_prepend(chan, NULL, file, 0, vmfmts, 1);
2185 cmd = play_and_wait(chan,"vm-forwardoptions");
2187 cmd = ast_waitfordigit(chan,6000);
2199 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
2206 struct ast_config *mif;
2210 int res = 0, cmd = 0;
2211 struct ast_vm_user *receiver, *extensions = NULL, *vmtmp = NULL, *vmfree;
2214 int saved_messages = 0, found = 0;
2215 int valid_extensions = 0;
2216 while (!res && !valid_extensions) {
2217 res = ast_streamfile(chan, "vm-extension", chan->language);
2220 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
2222 /* start all over if no username */
2223 if (!strlen(username))
2226 s = strsep(&stringp, "*");
2227 /* start optimistic */
2228 valid_extensions = 1;
2230 /* find_user is going to malloc since we have a NULL as first argument */
2231 if ((receiver = find_user(NULL, context, s))) {
2233 vmtmp = extensions = receiver;
2235 vmtmp->next = receiver;
2240 valid_extensions = 0;
2243 s = strsep(&stringp, "*");
2245 /* break from the loop of reading the extensions */
2246 if (valid_extensions)
2248 /* invalid extension, try again */
2249 res = play_and_wait(chan, "pbx-invalid");
2251 /* check if we're clear to proceed */
2252 if (!extensions || !valid_extensions)
2255 cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context);
2257 while(!res && vmtmp) {
2258 /* if (play_and_wait(chan, "vm-savedto"))
2261 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
2262 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
2263 ast_log(LOG_DEBUG, sys);
2266 todircount = count_messages(todir);
2267 strncpy(tmp, fmt, sizeof(tmp));
2269 while((s = strsep(&stringp, "|"))) {
2270 /* XXX This is a hack -- we should use build_filename or similar XXX */
2271 if (!strcasecmp(s, "wav49"))
2273 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
2274 ast_log(LOG_DEBUG, sys);
2277 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
2278 ast_log(LOG_DEBUG, sys);
2280 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
2282 /* load the information on the source message so we can send an e-mail like a new message */
2283 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
2284 if ((mif=ast_load(miffile))) {
2286 /* set callerid and duration variables */
2287 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
2288 s = ast_variable_retrieve(mif, NULL, "duration");
2293 if (strlen(vmtmp->email)) {
2294 int attach_user_voicemail = attach_voicemail;
2295 char *myserveremail = serveremail;
2296 if (vmtmp->attach > -1)
2297 attach_user_voicemail = vmtmp->attach;
2298 if (strlen(vmtmp->serveremail))
2299 myserveremail = vmtmp->serveremail;
2300 sendmail(myserveremail, vmtmp, todircount, vmtmp->mailbox, callerid, fn, tmp, duration, attach_user_voicemail);
2303 if (strlen(vmtmp->pager)) {
2304 char *myserveremail = serveremail;
2305 if (strlen(vmtmp->serveremail))
2306 myserveremail = vmtmp->serveremail;
2307 sendpage(myserveremail, vmtmp->pager, todircount, vmtmp->mailbox, callerid, duration, vmtmp);
2310 ast_destroy(mif); /* or here */
2312 /* Leave voicemail for someone */
2313 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vmtmp->mailbox, ast_app_has_voicemail(vmtmp->mailbox));
2317 vmtmp = vmtmp->next;
2320 if (saved_messages > 0) {
2321 /* give confirmatopm that the message was saved */
2322 if (saved_messages == 1)
2323 res = play_and_wait(chan, "vm-message");
2325 res = play_and_wait(chan, "vm-messages");
2327 res = play_and_wait(chan, "vm-saved");
2329 return res ? res : cmd;
2333 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
2336 if ((res = ast_streamfile(chan, file, chan->language)))
2337 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2339 res = ast_waitstream(chan, AST_DIGIT_ANY);
2343 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
2346 if ((res = ast_streamfile(chan, file, chan->language)))
2347 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2349 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
2353 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
2356 char filename[256], *origtime;
2357 struct vm_zone *the_zone = NULL;
2358 struct ast_config *msg_cfg;
2362 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2363 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
2364 msg_cfg = ast_load(filename);
2366 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
2370 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
2372 if (sscanf(origtime,"%ld",&tin) < 1) {
2373 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
2377 ast_destroy(msg_cfg);
2379 /* Does this user have a timezone specified? */
2380 if (strlen(vmu->zonetag)) {
2381 /* Find the zone in the list */
2385 if (!strcmp(z->name, vmu->zonetag)) {
2393 /* No internal variable parsing for now, so we'll comment it out for the time being */
2395 /* Set the DIFF_* variables */
2396 localtime_r(&t, &time_now);
2397 gettimeofday(&tv_now,NULL);
2398 tnow = tv_now.tv_sec;
2399 localtime_r(&tnow,&time_then);
2401 /* Day difference */
2402 if (time_now.tm_year == time_then.tm_year)
2403 sprintf(temp,"%d",time_now.tm_yday);
2405 sprintf(temp,"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
2406 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
2408 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
2411 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
2413 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
2415 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
2420 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg)
2424 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2425 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
2427 res = wait_file2(chan, vms, "vm-first");
2428 else if (msg == vms->lastmsg)
2429 res = wait_file2(chan, vms, "vm-last");
2431 res = wait_file2(chan, vms, "vm-message");
2432 if (msg && (msg != vms->lastmsg)) {
2434 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
2439 res = play_message_datetime(chan,vmu,vms);
2442 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2443 vms->heard[msg] = 1;
2444 res = wait_file(chan, vms, vms->fn);
2449 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
2451 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
2452 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2453 vms->lastmsg = count_messages(vms->curdir) - 1;
2454 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
2457 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
2460 char ntxt[256] = "";
2462 if (vms->lastmsg > -1) {
2463 /* Get the deleted messages fixed */
2465 for (x=0;x < MAXMSG;x++) {
2466 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
2467 /* Save this message. It's not in INBOX or hasn't been heard */
2468 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2469 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2472 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2473 if (strcmp(vms->fn, vms->fn2)) {
2474 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2475 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
2476 ast_filerename(vms->fn, vms->fn2, NULL);
2479 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
2480 /* Move to old folder before deleting */
2481 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
2484 for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
2485 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2486 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2488 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2489 ast_filedelete(vms->fn, NULL);
2493 memset(vms->deleted, 0, sizeof(vms->deleted));
2494 memset(vms->heard, 0, sizeof(vms->heard));
2497 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
2499 /* Introduce messages they have */
2501 res = play_and_wait(chan, "vm-youhave");
2503 if (vms->newmessages) {
2504 res = say_and_wait(chan, vms->newmessages);
2506 res = play_and_wait(chan, "vm-INBOX");
2507 if (vms->oldmessages && !res)
2508 res = play_and_wait(chan, "vm-and");
2510 if ((vms->newmessages == 1))
2511 res = play_and_wait(chan, "vm-message");
2513 res = play_and_wait(chan, "vm-messages");
2517 if (!res && vms->oldmessages) {
2518 res = say_and_wait(chan, vms->oldmessages);
2520 res = play_and_wait(chan, "vm-Old");
2522 if (vms->oldmessages == 1)
2523 res = play_and_wait(chan, "vm-message");
2525 res = play_and_wait(chan, "vm-messages");
2529 if (!vms->oldmessages && !vms->newmessages) {
2530 res = play_and_wait(chan, "vm-no");
2532 res = play_and_wait(chan, "vm-messages");
2539 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
2542 /* Play instructions and wait for new command */
2544 if (vms->starting) {
2545 if (vms->lastmsg > -1) {
2546 res = play_and_wait(chan, "vm-onefor");
2548 res = play_and_wait(chan, vms->vmbox);
2550 res = play_and_wait(chan, "vm-messages");
2553 res = play_and_wait(chan, "vm-opts");
2556 res = play_and_wait(chan, "vm-prev");
2558 res = play_and_wait(chan, "vm-repeat");
2559 if (!res && (vms->curmsg != vms->lastmsg))
2560 res = play_and_wait(chan, "vm-next");
2562 if (!vms->deleted[vms->curmsg])
2563 res = play_and_wait(chan, "vm-delete");
2565 res = play_and_wait(chan, "vm-undelete");
2567 res = play_and_wait(chan, "vm-toforward");
2569 res = play_and_wait(chan, "vm-savemessage");
2573 res = play_and_wait(chan, "vm-helpexit");
2575 res = ast_waitfordigit(chan, 6000);
2578 if (vms->repeats > 2) {
2579 res = play_and_wait(chan, "vm-goodbye");
2588 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
2592 char newpassword[80] = "";
2593 char newpassword2[80] = "";
2594 char prefile[256]="";
2598 if (adsi_available(chan))
2600 bytes += adsi_logo(buf + bytes);
2601 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
2602 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
2603 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2604 bytes += adsi_voice_mode(buf + bytes, 0);
2605 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2607 while((cmd >= 0) && (cmd != 't')) {
2612 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
2613 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
2616 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
2617 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
2620 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
2621 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
2624 newpassword[1] = '\0';
2625 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
2628 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
2631 newpassword2[1] = '\0';
2632 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
2636 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
2639 if (strcmp(newpassword, newpassword2)) {
2640 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
2641 cmd = play_and_wait(chan, "vm-mismatch");
2644 vm_change_password(vmu,newpassword);
2645 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
2646 cmd = play_and_wait(chan,"vm-passchanged");
2652 cmd = play_and_wait(chan,"vm-options");
2654 cmd = ast_waitfordigit(chan,6000);
2666 static int vm_execmain(struct ast_channel *chan, void *data)
2668 /* XXX This is, admittedly, some pretty horrendus code. For some
2669 reason it just seemed a lot easier to do with GOTO's. I feel
2670 like I'm back in my GWBASIC days. XXX */
2675 struct localuser *u;
2676 char prefixstr[80] ="";
2677 char empty[80] = "";
2681 char tmp[256], *ext;
2682 char fmtc[256] = "";
2684 struct vm_state vms;
2686 struct ast_vm_user *vmu = NULL, vmus;
2690 memset(&vms, 0, sizeof(vms));
2691 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
2692 if (chan->_state != AST_STATE_UP)
2695 if (data && strlen(data)) {
2696 strncpy(tmp, data, sizeof(tmp) - 1);
2701 /* We should skip the user's password */
2706 /* We should prefix the mailbox with the supplied data */
2712 context = strchr(ext, '@');
2719 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
2721 strncpy(vms.username, ext, sizeof(vms.username) - 1);
2722 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
2729 /* If ADSI is supported, setup login screen */
2730 adsi_begin(chan, &useadsi);
2731 if (!skipuser && useadsi)
2733 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
2734 ast_log(LOG_WARNING, "Couldn't stream login file\n");
2738 /* Authenticate them and get their mailbox/password */
2740 while (!valid && (logretries < maxlogins)) {
2741 /* Prompt for, and read in the username */
2742 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
2743 ast_log(LOG_WARNING, "Couldn't read username\n");
2746 if (!strlen(vms.username)) {
2747 if (option_verbose > 2)
2748 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
2753 adsi_password(chan);
2754 if (ast_streamfile(chan, "vm-password", chan->language)) {
2755 ast_log(LOG_WARNING, "Unable to stream password file\n");
2758 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
2759 ast_log(LOG_WARNING, "Unable to read password\n");
2763 char fullusername[80] = "";
2764 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
2765 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
2766 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
2769 vmu = find_user(&vmus, context, vms.username);
2770 if (vmu && !strcmp(vmu->password, password))
2773 if (option_verbose > 2)
2774 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
2776 strncpy(vms.username, empty, sizeof(vms.username) -1);
2781 if (ast_streamfile(chan, "vm-incorrect", chan->language))
2786 if (!valid && (logretries >= maxlogins)) {
2787 ast_stopstream(chan);
2788 res = play_and_wait(chan, "vm-goodbye");
2794 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
2795 mkdir(vms.curdir, 0700);
2796 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
2797 mkdir(vms.curdir, 0700);
2798 /* Retrieve old and new message counts */
2799 open_mailbox(&vms, vmu, 1);
2800 vms.oldmessages = vms.lastmsg + 1;
2801 /* Start in INBOX */
2802 open_mailbox(&vms, vmu, 0);
2803 vms.newmessages = vms.lastmsg + 1;
2806 /* Select proper mailbox FIRST!! */
2807 if (!vms.newmessages && vms.oldmessages) {
2808 /* If we only have old messages start here */
2809 open_mailbox(&vms, vmu, 1);
2813 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2815 cmd = vm_intro(chan, &vms);
2818 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2825 if (vms.lastmsg > -1) {
2826 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2828 cmd = play_and_wait(chan, "vm-youhave");
2830 cmd = play_and_wait(chan, "vm-no");
2832 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2833 cmd = play_and_wait(chan, vms.fn);
2836 cmd = play_and_wait(chan, "vm-messages");
2839 case '2': /* Change folders */
2841 adsi_folders(chan, 0, "Change to folder...");
2842 cmd = get_folder2(chan, "vm-changeto", 0);
2845 } else if (cmd > 0) {
2847 close_mailbox(&vms, vmu);
2848 open_mailbox(&vms, vmu, cmd);
2852 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2854 cmd = play_and_wait(chan, vms.vmbox);
2856 cmd = play_and_wait(chan, "vm-messages");
2862 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2864 cmd = play_and_wait(chan, "vm-nomore");
2868 if (vms.curmsg < vms.lastmsg) {
2870 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2872 cmd = play_and_wait(chan, "vm-nomore");
2876 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2878 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2879 if (vms.deleted[vms.curmsg])
2880 cmd = play_and_wait(chan, "vm-deleted");
2882 cmd = play_and_wait(chan, "vm-undeleted");
2885 if(vms.lastmsg > -1)
2886 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2888 cmd = play_and_wait(chan, "vm-nomore");
2892 adsi_folders(chan, 1, "Save to folder...");
2893 cmd = get_folder2(chan, "vm-savefolder", 1);
2894 box = 0; /* Shut up compiler */
2898 } else if (cmd > 0) {
2899 box = cmd = cmd - '0';
2900 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2901 vms.deleted[vms.curmsg]=1;
2903 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2905 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2907 cmd = play_and_wait(chan, "vm-message");
2909 cmd = say_and_wait(chan, vms.curmsg + 1);
2911 cmd = play_and_wait(chan, "vm-savedto");
2913 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2914 cmd = play_and_wait(chan, vms.fn);
2917 cmd = play_and_wait(chan, "vm-messages");
2920 if (!vms.starting) {
2921 cmd = play_and_wait(chan, "vm-onefor");
2923 cmd = play_and_wait(chan, vms.vmbox);
2925 cmd = play_and_wait(chan, "vm-messages");
2927 cmd = play_and_wait(chan, "vm-opts");
2932 cmd = vm_options(chan, vmu, &vms, vmfmts);
2934 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);