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>
39 /* we define USESQLVM when we have MySQL or POSTGRES */
41 #include <mysql/mysql.h>
47 * PostgreSQL routines written by Otmar Lendl <lendl@nic.at>
49 #include <postgresql/libpq-fe.h>
54 static inline int sql_init(void) { return 0; }
55 static inline void sql_close(void) { }
59 #include "../asterisk.h"
60 #include "../astconf.h"
62 #define COMMAND_TIMEOUT 5000
64 #define VOICEMAIL_CONFIG "voicemail.conf"
65 #define ASTERISK_USERNAME "asterisk"
67 #define SENDMAIL "/usr/sbin/sendmail -t"
69 #define INTRO "vm-intro"
72 #define MAX_OTHER_FORMATS 10
74 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
76 #define BASEMAXINLINE 256
77 #define BASELINELEN 72
78 #define BASEMAXINLINE 256
81 #define MAX_DATETIME_FORMAT 512
82 #define DIGITS_DIR AST_SOUNDS "/digits/"
88 unsigned char iobuf[BASEMAXINLINE];
102 struct ast_vm_user *next;
108 char msg_format[512];
109 struct vm_zone *next;
112 static char *tdesc = "Comedian Mail (Voicemail System)";
114 static char *adapp = "CoMa";
116 static char *adsec = "_AST";
118 static char *addesc = "Comedian Mail";
120 static int adver = 1;
122 static char *synopsis_vm =
123 "Leave a voicemail message";
125 static char *descrip_vm =
126 " VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given\n"
127 "extension (must be configured in voicemail.conf). If the extension is\n"
128 "preceded by an 's' then instructions for leaving the message will be\n"
129 "skipped. If the extension is preceeded by 'u' then the \"unavailable\"\n"
130 "message will be played (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it\n"
131 "exists. If the extension is preceeded by a 'b' then the the busy message\n"
132 "will be played (that is, busy instead of unavail).\n"
133 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
134 "Otherwise, it returns 0.\n";
136 static char *synopsis_vmain =
137 "Enter voicemail system";
139 static char *descrip_vmain =
140 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
141 "for the checking of voicemail. The mailbox can be passed as the option,\n"
142 "which will stop the voicemail system from prompting the user for the mailbox.\n"
143 "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
144 "a context is specified, logins are considered in that context only.\n"
145 "Returns -1 if the user hangs up or 0 otherwise.\n";
147 /* Leave a message */
148 static char *capp = "VoiceMail2";
149 static char *app = "VoiceMail";
151 /* Check mail, control, etc */
152 static char *capp2 = "VoiceMailMain2";
153 static char *app2 = "VoiceMailMain";
155 static ast_mutex_t vmlock = AST_MUTEX_INITIALIZER;
156 struct ast_vm_user *users;
157 struct ast_vm_user *usersl;
158 struct vm_zone *zones = NULL;
159 struct vm_zone *zonesl = NULL;
160 static int attach_voicemail;
161 static int maxsilence;
162 static int silencethreshold = 128;
163 static char serveremail[80];
164 static char vmfmts[80];
165 static int vmmaxmessage;
168 static int maxlogins;
170 static char *emailbody = NULL;
171 static int pbxskip = 0;
172 static char fromstring[100];
173 static char emailtitle[100];
179 static void apply_options(struct ast_vm_user *vmu, char *options)
181 /* Destructively Parse options and apply */
182 char *stringp = ast_strdupa(options);
185 while((s = strsep(&stringp, "|"))) {
187 if ((var = strsep(&value, "=")) && value) {
188 if (!strcasecmp(var, "attach")) {
193 } else if (!strcasecmp(var, "serveremail")) {
194 strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
195 } else if (!strcasecmp(var, "tz")) {
196 strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
204 #include "mysql-vm-routines.h"
211 ast_mutex_t postgreslock;
213 static int sql_init(void)
215 ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption);
216 /* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */
218 dbhandler=PQconnectdb(dboption);
219 if (PQstatus(dbhandler) == CONNECTION_BAD) {
220 ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler));
223 ast_mutex_init(&postgreslock);
225 /* fprintf(stderr,"postgres login OK\n"); */
229 static void sql_close(void)
235 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
243 char options[160] = "";
244 struct ast_vm_user *retval;
246 retval=malloc(sizeof(struct ast_vm_user));
248 /* fprintf(stderr,"postgres find_user:\n"); */
251 *retval->mailbox='\0';
252 *retval->context='\0';
253 *retval->password='\0';
254 *retval->fullname='\0';
257 *retval->serveremail='\0';
262 strcpy(retval->mailbox, mailbox);
265 strcpy(retval->context, context);
268 if (*retval->context) {
269 sprintf(query, "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", context, mailbox);
271 sprintf(query, "SELECT password,fullname,email,pager,options FROM voicemail WHERE mailbox='%s'", mailbox);
273 /* fprintf(stderr,"postgres find_user: query = %s\n",query); */
274 ast_mutex_lock(&postgreslock);
275 PGSQLres=PQexec(dbhandler,query);
276 if (PGSQLres!=NULL) {
277 if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
278 PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
279 PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
281 ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres));
284 ast_mutex_unlock(&postgreslock);
288 numFields = PQnfields(PGSQLres);
289 /* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */
290 if (PQntuples(PGSQLres) != 1) {
291 ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox);
293 ast_mutex_unlock(&postgreslock);
297 for (i=0; i<numFields; i++) {
298 fname = PQfname(PGSQLres,i);
299 if (!strcmp(fname, "password")) {
300 strncpy(retval->password, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1);
301 } else if (!strcmp(fname, "fullname")) {
302 strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1);
303 } else if (!strcmp(fname, "email")) {
304 strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1);
305 } else if (!strcmp(fname, "pager")) {
306 strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1);
307 } else if (!strcmp(fname, "options")) {
308 strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1);
309 apply_options(retval, options);
314 ast_mutex_unlock(&postgreslock);
318 ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler));
319 ast_mutex_unlock(&postgreslock);
324 } /* malloc() retval */
329 static void vm_change_password(struct ast_vm_user *vmu, char *password)
334 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);
336 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password);
338 /* fprintf(stderr,"postgres change_password: query = %s\n",query); */
339 ast_mutex_lock(&postgreslock);
340 PQexec(dbhandler, query);
341 strcpy(vmu->password, password);
342 ast_mutex_unlock(&postgreslock);
345 static void reset_user_pw(char *context, char *mailbox, char *password)
350 sprintf(query, "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox);
352 sprintf(query, "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox);
354 ast_mutex_lock(&postgreslock);
355 /* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */
356 PQexec(dbhandler, query);
357 ast_mutex_unlock(&postgreslock);
360 #endif /* Postgres */
363 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
365 /* This function could be made to generate one from a database, too */
366 struct ast_vm_user *vmu=NULL, *cur;
367 ast_mutex_lock(&vmlock);
370 if ((!context || !strcasecmp(context, cur->context)) &&
371 (!strcasecmp(mailbox, cur->mailbox)))
379 /* Make a copy, so that on a reload, we have no race */
380 vmu = malloc(sizeof(struct ast_vm_user));
382 memcpy(vmu, cur, sizeof(struct ast_vm_user));
390 ast_mutex_unlock(&vmlock);
394 static int reset_user_pw(char *context, char *mailbox, char *newpass)
396 /* This function could be made to generate one from a database, too */
397 struct ast_vm_user *cur;
399 ast_mutex_lock(&vmlock);
402 if ((!context || !strcasecmp(context, cur->context)) &&
403 (!strcasecmp(mailbox, cur->mailbox)))
408 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
411 ast_mutex_unlock(&vmlock);
415 static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
417 /* There's probably a better way of doing this. */
418 /* That's why I've put the password change in a separate function. */
419 /* This could also be done with a database function */
425 char tmpin[AST_CONFIG_MAX_PATH];
426 char tmpout[AST_CONFIG_MAX_PATH];
427 char *user, *pass, *rest, *trim;
428 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
429 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
430 configin = fopen((char *)tmpin,"r");
432 configout = fopen((char *)tmpout,"w+");
435 if(!configin || !configout) {
439 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
443 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
447 while (!feof(configin)) {
448 /* Read in the line */
449 fgets(inbuf, sizeof(inbuf), configin);
450 if (!feof(configin)) {
451 /* Make a backup of it */
452 memcpy(orig, inbuf, sizeof(orig));
453 /* Strip trailing \n and comment */
454 inbuf[strlen(inbuf) - 1] = '\0';
455 user = strchr(inbuf, ';');
461 pass = strchr(user, '=');
464 while(*trim && *trim < 33) {
474 while(*pass && *pass < 33)
478 rest = strchr(pass,',');
485 if (user && pass && *user && *pass && !strcmp(user, vmu->mailbox) && !strcmp(pass, vmu->password)) {
486 /* This is the line */
488 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
490 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
493 /* Put it back like it was */
494 fprintf(configout, orig);
501 unlink((char *)tmpin);
502 rename((char *)tmpout,(char *)tmpin);
503 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
504 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
508 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
510 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
513 static int make_file(char *dest, int len, char *dir, int num)
515 return snprintf(dest, len, "%s/msg%04d", dir, num);
519 inbuf(struct baseio *bio, FILE *fi)
526 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
541 inchar(struct baseio *bio, FILE *fi)
543 if(bio->iocp>=bio->iolen)
547 return bio->iobuf[bio->iocp++];
551 ochar(struct baseio *bio, int c, FILE *so)
553 if(bio->linelength>=BASELINELEN) {
554 if(fputs(eol,so)==EOF)
560 if(putc(((unsigned char)c),so)==EOF)
568 static int base_encode(char *filename, FILE *so)
570 unsigned char dtable[BASEMAXINLINE];
575 memset(&bio, 0, sizeof(bio));
576 bio.iocp = BASEMAXINLINE;
578 if ( !(fi = fopen(filename, "rb"))) {
579 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
587 dtable[26+i+9]= 'j'+i;
591 dtable[26+i+18]= 's'+i;
600 unsigned char igroup[3],ogroup[4];
603 igroup[0]= igroup[1]= igroup[2]= 0;
606 if ( (c = inchar(&bio, fi)) == EOF) {
611 igroup[n]= (unsigned char)c;
615 ogroup[0]= dtable[igroup[0]>>2];
616 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
617 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
618 ogroup[3]= dtable[igroup[2]&0x3F];
628 ochar(&bio, ogroup[i], so);
632 if(fputs(eol,so)==EOF)
640 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)
651 struct vm_zone *the_zone = NULL;
653 if (!strcmp(format, "wav49"))
655 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, attach_voicemail);
656 p = popen(SENDMAIL, "w");
658 gethostname(host, sizeof(host));
659 if (strchr(srcemail, '@'))
660 strncpy(who, srcemail, sizeof(who)-1);
662 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
664 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
667 /* Does this user have a timezone specified? */
668 if (strlen(vmu->zonetag)) {
669 /* Find the zone in the list */
673 if (!strcmp(z->name, vmu->zonetag)) {
682 ast_localtime(&t,&tm,the_zone->timezone);
684 ast_localtime(&t,&tm,NULL);
685 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
686 fprintf(p, "Date: %s\n", date);
689 fprintf(p, "From: %s <%s>\n", fromstring, who);
691 fprintf(p, "From: Asterisk PBX <%s>\n", who);
692 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
696 fprintf(p, emailtitle, msgnum, mailbox) ;
701 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
703 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
704 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
705 fprintf(p, "MIME-Version: 1.0\n");
706 if (attach_user_voicemail) {
708 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
710 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
712 fprintf(p, "--%s\n", bound);
714 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
715 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
717 struct ast_channel *ast = ast_channel_alloc(0);
720 int vmlen = strlen(emailbody)*3 + 200;
721 if ((passdata = alloca(vmlen))) {
722 memset(passdata, 0, vmlen);
723 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
724 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
725 sprintf(passdata,"%d",msgnum);
726 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
727 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
728 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (callerid ? callerid : "an unknown caller"));
729 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
730 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
731 fprintf(p, "%s\n",passdata);
732 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
733 ast_channel_free(ast);
734 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
736 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
738 "in mailbox %s from %s, on %s so you might\n"
739 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
740 dur, msgnum + 1, mailbox, (callerid ? callerid : "an unknown caller"), date);
742 if (attach_user_voicemail) {
743 fprintf(p, "--%s\n", bound);
744 fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
745 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
746 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
747 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
749 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
750 base_encode(fname, p);
751 fprintf(p, "\n\n--%s--\n.\n", bound);
755 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
761 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration, struct ast_vm_user *vmu)
770 struct vm_zone *the_zone = NULL;
771 p = popen(SENDMAIL, "w");
774 gethostname(host, sizeof(host));
775 if (strchr(srcemail, '@'))
776 strncpy(who, srcemail, sizeof(who)-1);
778 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
780 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
783 /* Does this user have a timezone specified? */
784 if (strlen(vmu->zonetag)) {
785 /* Find the zone in the list */
789 if (!strcmp(z->name, vmu->zonetag)) {
798 ast_localtime(&t,&tm,the_zone->timezone);
800 ast_localtime(&t,&tm,NULL);
802 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
803 fprintf(p, "Date: %s\n", date);
804 fprintf(p, "From: Asterisk PBX <%s>\n", who);
805 fprintf(p, "To: %s\n", pager);
806 fprintf(p, "Subject: New VM\n\n");
807 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
808 fprintf(p, "New %s long msg in box %s\n"
809 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
812 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
818 static int get_date(char *s, int len)
824 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
827 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
831 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
832 if (ast_fileexists(fn, NULL, NULL) > 0) {
833 res = ast_streamfile(chan, fn, chan->language);
836 res = ast_waitstream(chan, ecodes);
840 res = ast_streamfile(chan, "vm-theperson", chan->language);
843 res = ast_waitstream(chan, ecodes);
846 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
851 res = ast_streamfile(chan, "vm-isonphone", chan->language);
853 res = ast_streamfile(chan, "vm-isunavail", chan->language);
856 res = ast_waitstream(chan, ecodes);
860 static int play_and_wait(struct ast_channel *chan, char *fn)
863 d = ast_streamfile(chan, fn, chan->language);
866 d = ast_waitstream(chan, AST_DIGIT_ANY);
867 ast_stopstream(chan);
871 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
875 int x, fmtcnt=1, res=-1,outmsg=0;
877 struct ast_filestream *others[MAX_OTHER_FORMATS];
878 char *sfmt[MAX_OTHER_FORMATS];
881 struct ast_dsp *sildet; /* silence detector dsp */
882 int totalsilence = 0;
884 int gotsilence = 0; /* did we timeout for silence? */
887 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
888 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
891 d = play_and_wait(chan, playfile);
893 d = ast_streamfile(chan, "beep",chan->language);
895 d = ast_waitstream(chan,"");
900 fmts = ast_strdupa(fmt);
903 strsep(&stringp, "|");
904 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
905 sfmt[0] = ast_strdupa(fmts);
907 while((fmt = strsep(&stringp, "|"))) {
908 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
909 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
912 sfmt[fmtcnt++] = ast_strdupa(fmt);
917 for (x=0;x<fmtcnt;x++) {
918 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
919 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
926 sildet = ast_dsp_new(); //Create the silence detector
928 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
931 ast_dsp_set_threshold(sildet, silencethreshold);
933 if (maxsilence > 0) {
934 rfmt = chan->readformat;
935 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
937 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
943 /* Loop forever, writing the packets we read to the writer(s), until
944 we read a # or get a hangup */
947 res = ast_waitfor(chan, 2000);
949 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
950 /* Try one more time in case of masq */
951 res = ast_waitfor(chan, 2000);
953 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
965 if (f->frametype == AST_FRAME_VOICE) {
966 /* write each format */
967 for (x=0;x<fmtcnt;x++) {
968 res = ast_writestream(others[x], f);
971 /* Silence Detection */
972 if (maxsilence > 0) {
974 ast_dsp_silence(sildet, f, &dspsilence);
976 totalsilence = dspsilence;
980 if (totalsilence > maxsilence) {
981 /* Ended happily with silence */
988 /* Exit on any error */
990 ast_log(LOG_WARNING, "Error writing frame\n");
994 } else if (f->frametype == AST_FRAME_VIDEO) {
995 /* Write only once */
996 ast_writestream(others[0], f);
997 } else if (f->frametype == AST_FRAME_DTMF) {
998 if (f->subclass == '#') {
999 if (option_verbose > 2)
1000 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1009 if (maxtime < (end - start)) {
1010 if (option_verbose > 2)
1011 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1020 if (option_verbose > 2)
1021 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1026 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1029 for (x=0;x<fmtcnt;x++) {
1033 ast_stream_rewind(others[x], totalsilence-200);
1035 ast_stream_rewind(others[x], 200);
1036 ast_truncstream(others[x]);
1037 ast_closestream(others[x]);
1040 if (ast_set_read_format(chan, rfmt)) {
1041 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
1046 /* Let them know it worked */
1047 ast_streamfile(chan, "vm-msgsaved", chan->language);
1048 ast_waitstream(chan, "");
1056 static void free_user(struct ast_vm_user *vmu)
1062 static void free_zone(struct vm_zone *z)
1067 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
1077 char prefile[256]="";
1085 struct ast_vm_user *vmu;
1086 struct ast_vm_user svm;
1088 strncpy(tmp, ext, sizeof(tmp) - 1);
1090 context = strchr(tmp, '@');
1096 if ((vmu = find_user(&svm, context, ext))) {
1097 /* Setup pre-file if appropriate */
1099 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
1101 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
1102 make_dir(dir, sizeof(dir), vmu->context, "", "");
1103 /* It's easier just to try to make it than to check for its existence */
1104 if (mkdir(dir, 0700) && (errno != EEXIST))
1105 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1106 make_dir(dir, sizeof(dir), vmu->context, ext, "");
1107 /* It's easier just to try to make it than to check for its existence */
1108 if (mkdir(dir, 0700) && (errno != EEXIST))
1109 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1110 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
1111 if (mkdir(dir, 0700) && (errno != EEXIST))
1112 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
1113 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
1115 /* Play the beginning intro if desired */
1116 if (strlen(prefile)) {
1117 if (ast_fileexists(prefile, NULL, NULL) > 0) {
1118 if (ast_streamfile(chan, prefile, chan->language) > -1)
1119 res = ast_waitstream(chan, "#0");
1121 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
1122 res = invent_message(chan, vmu->context, ext, busy, ecodes);
1125 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
1131 /* On a '#' we skip the instructions */
1135 if (!res && !silent) {
1136 res = ast_streamfile(chan, INTRO, chan->language);
1138 res = ast_waitstream(chan, ecodes);
1144 /* Check for a '0' here */
1146 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
1147 if (strlen(chan->macrocontext))
1148 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
1154 /* Unless we're *really* silent, try to send the beep */
1155 res = ast_streamfile(chan, "beep", chan->language);
1157 res = ast_waitstream(chan, "");
1163 /* The meat of recording the message... All the announcements and beeps have been played*/
1164 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
1168 make_file(fn, sizeof(fn), dir, msgnum);
1169 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
1170 (chan->callerid ? chan->callerid : "Unknown"),
1171 vmu->fullname, ext, chan->name);
1172 if (ast_fileexists(fn, NULL, chan->language) <= 0)
1175 } while(msgnum < MAXMSG);
1176 if (msgnum < MAXMSG) {
1177 /* Store information */
1178 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
1179 txt = fopen(txtfile, "w+");
1181 get_date(date, sizeof(date));
1185 "; Message Information file\n"
1201 chan->callerid ? chan->callerid : "Unknown",
1202 date, (long)time(NULL));
1205 ast_log(LOG_WARNING, "Error opening text file for output\n");
1206 res = play_and_record(chan, NULL, fn, vmmaxmessage, fmt);
1209 txt = fopen(txtfile, "a");
1212 fprintf(txt, "duration=%ld\n", (long)(end-start));
1216 strsep(&stringp, "|");
1217 /* Send e-mail if applicable */
1218 if (strlen(vmu->email)) {
1219 int attach_user_voicemail = attach_voicemail;
1220 char *myserveremail = serveremail;
1221 if (vmu->attach > -1)
1222 attach_user_voicemail = vmu->attach;
1223 if (strlen(vmu->serveremail))
1224 myserveremail = vmu->serveremail;
1225 sendmail(myserveremail, vmu, msgnum, ext, chan->callerid, fn, fmt, end - start, attach_user_voicemail);
1227 if (strlen(vmu->pager)) {
1228 char *myserveremail = serveremail;
1229 if (strlen(vmu->serveremail))
1230 myserveremail = vmu->serveremail;
1231 sendpage(myserveremail, vmu->pager, msgnum, ext, chan->callerid, end - start, vmu);
1234 ast_log(LOG_WARNING, "No more messages possible\n");
1236 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
1239 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
1240 /*Send the call to n+101 priority, where n is the current priority*/
1241 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
1242 chan->priority+=100;
1244 /* Leave voicemail for someone */
1245 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
1249 static char *mbox(int id)
1277 static int count_messages(char *dir)
1281 for (x=0;x<MAXMSG;x++) {
1282 make_file(fn, sizeof(fn), dir, x);
1283 if (ast_fileexists(fn, NULL, NULL) < 1)
1289 static int say_and_wait(struct ast_channel *chan, int num)
1292 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
1296 static int copy(char *infile, char *outfile)
1303 if ((ifd = open(infile, O_RDONLY)) < 0) {
1304 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1307 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1308 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1313 len = read(ifd, buf, sizeof(buf));
1315 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1321 res = write(ofd, buf, len);
1323 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1335 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
1342 char *dbox = mbox(box);
1344 make_file(sfn, sizeof(sfn), dir, msg);
1345 make_dir(ddir, sizeof(ddir), context, username, dbox);
1347 for (x=0;x<MAXMSG;x++) {
1348 make_file(dfn, sizeof(dfn), ddir, x);
1349 if (ast_fileexists(dfn, NULL, NULL) < 0)
1354 ast_filecopy(sfn, dfn, NULL);
1355 if (strcmp(sfn, dfn)) {
1356 snprintf(txt, sizeof(txt), "%s.txt", sfn);
1357 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
1363 static int adsi_logo(unsigned char *buf)
1366 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
1367 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
1371 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
1379 bytes += adsi_data_mode(buf + bytes);
1380 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1383 bytes += adsi_logo(buf);
1384 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1386 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1388 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1389 bytes += adsi_data_mode(buf + bytes);
1390 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1392 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1394 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1395 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1396 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1397 bytes += adsi_voice_mode(buf + bytes, 0);
1398 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1405 bytes += adsi_logo(buf);
1406 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1407 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1408 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1409 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1412 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1413 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1414 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1415 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
1416 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1417 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1418 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1421 /* Add another dot */
1423 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1424 bytes += adsi_voice_mode(buf + bytes, 0);
1426 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1427 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1431 /* These buttons we load but don't use yet */
1432 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1433 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1434 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1435 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1436 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1437 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1438 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1441 /* Add another dot */
1443 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1444 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1445 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1450 snprintf(num, sizeof(num), "%d", x);
1451 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1453 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1454 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1457 /* Add another dot */
1459 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1460 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1461 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1464 if (adsi_end_download(chan)) {
1466 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1467 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1468 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1469 bytes += adsi_voice_mode(buf + bytes, 0);
1470 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1474 bytes += adsi_download_disconnect(buf + bytes);
1475 bytes += adsi_voice_mode(buf + bytes, 0);
1476 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1478 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1483 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1484 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1486 ast_log(LOG_DEBUG, "Restarting session...\n");
1489 /* Load the session now */
1490 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1492 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1494 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1496 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1500 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1503 if (!adsi_available(chan))
1505 x = adsi_load_session(chan, adapp, adver, 1);
1509 if (adsi_load_vmail(chan, useadsi)) {
1510 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1517 static void adsi_login(struct ast_channel *chan)
1521 unsigned char keys[8];
1523 if (!adsi_available(chan))
1528 /* Set one key for next */
1529 keys[3] = ADSI_KEY_APPS + 3;
1531 bytes += adsi_logo(buf + bytes);
1532 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1533 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1534 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1535 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1536 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1537 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1538 bytes += adsi_set_keys(buf + bytes, keys);
1539 bytes += adsi_voice_mode(buf + bytes, 0);
1540 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1543 static void adsi_password(struct ast_channel *chan)
1547 unsigned char keys[8];
1549 if (!adsi_available(chan))
1554 /* Set one key for next */
1555 keys[3] = ADSI_KEY_APPS + 3;
1557 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1558 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1559 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1560 bytes += adsi_set_keys(buf + bytes, keys);
1561 bytes += adsi_voice_mode(buf + bytes, 0);
1562 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1565 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1569 unsigned char keys[8];
1572 if (!adsi_available(chan))
1576 y = ADSI_KEY_APPS + 12 + start + x;
1577 if (y > ADSI_KEY_APPS + 12 + 4)
1579 keys[x] = ADSI_KEY_SKT | y;
1581 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1585 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1586 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1587 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1588 bytes += adsi_set_keys(buf + bytes, keys);
1589 bytes += adsi_voice_mode(buf + bytes, 0);
1591 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1594 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1597 char buf[256], buf1[256], buf2[256];
1603 char datetime[21]="";
1606 unsigned char keys[8];
1610 if (!adsi_available(chan))
1613 /* Retrieve important info */
1614 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1615 f = fopen(fn2, "r");
1618 fgets(buf, sizeof(buf), f);
1622 strsep(&stringp, "=");
1623 val = strsep(&stringp, "=");
1624 if (val && strlen(val)) {
1625 if (!strcmp(buf, "callerid"))
1626 strncpy(cid, val, sizeof(cid) - 1);
1627 if (!strcmp(buf, "origdate"))
1628 strncpy(datetime, val, sizeof(datetime) - 1);
1634 /* New meaning for keys */
1636 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1641 /* No prev key, provide "Folder" instead */
1642 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1645 /* If last message ... */
1647 /* but not only message, provide "Folder" instead */
1648 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1649 bytes += adsi_voice_mode(buf + bytes, 0);
1652 /* Otherwise if only message, leave blank */
1658 ast_callerid_parse(cid, &name, &num);
1662 name = "Unknown Caller";
1664 /* If deleted, show "undeleted" */
1667 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1670 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1671 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1672 strcasecmp(folder, "INBOX") ? " Messages" : "");
1673 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1675 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1676 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1677 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1678 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1679 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1680 bytes += adsi_set_keys(buf + bytes, keys);
1681 bytes += adsi_voice_mode(buf + bytes, 0);
1683 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1686 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1690 unsigned char keys[8];
1694 if (!adsi_available(chan))
1697 /* New meaning for keys */
1699 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1705 /* No prev key, provide "Folder" instead */
1706 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1709 /* If last message ... */
1711 /* but not only message, provide "Folder" instead */
1712 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1714 /* Otherwise if only message, leave blank */
1719 /* If deleted, show "undeleted" */
1721 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1724 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1725 bytes += adsi_set_keys(buf + bytes, keys);
1726 bytes += adsi_voice_mode(buf + bytes, 0);
1728 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1731 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1733 char buf[256], buf1[256], buf2[256];
1735 unsigned char keys[8];
1738 char *newm = (new == 1) ? "message" : "messages";
1739 char *oldm = (old == 1) ? "message" : "messages";
1740 if (!adsi_available(chan))
1743 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1745 strcat(buf1, " and");
1746 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1748 snprintf(buf2, sizeof(buf2), "%s.", newm);
1751 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1752 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1754 strcpy(buf1, "You have no messages.");
1757 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1758 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1759 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1762 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1766 /* Don't let them listen if there are none */
1769 bytes += adsi_set_keys(buf + bytes, keys);
1771 bytes += adsi_voice_mode(buf + bytes, 0);
1773 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1776 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1778 char buf[256], buf1[256], buf2[256];
1780 unsigned char keys[8];
1783 char *mess = (messages == 1) ? "message" : "messages";
1785 if (!adsi_available(chan))
1788 /* Original command keys */
1790 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1798 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1799 strcasecmp(folder, "INBOX") ? " folder" : "");
1802 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1804 strcpy(buf2, "no messages.");
1805 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1806 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1807 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1808 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1809 bytes += adsi_set_keys(buf + bytes, keys);
1811 bytes += adsi_voice_mode(buf + bytes, 0);
1813 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1817 static void adsi_clear(struct ast_channel *chan)
1821 if (!adsi_available(chan))
1823 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1824 bytes += adsi_voice_mode(buf + bytes, 0);
1826 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1829 static void adsi_goodbye(struct ast_channel *chan)
1834 if (!adsi_available(chan))
1836 bytes += adsi_logo(buf + bytes);
1837 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1838 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1839 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1840 bytes += adsi_voice_mode(buf + bytes, 0);
1842 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1845 static int get_folder(struct ast_channel *chan, int start)
1850 d = play_and_wait(chan, "vm-press");
1853 for (x = start; x< 5; x++) {
1854 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1856 d = play_and_wait(chan, "vm-for");
1859 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1860 d = play_and_wait(chan, fn);
1863 d = play_and_wait(chan, "vm-messages");
1866 d = ast_waitfordigit(chan, 500);
1870 d = play_and_wait(chan, "vm-tocancel");
1873 d = ast_waitfordigit(chan, 4000);
1877 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1880 res = play_and_wait(chan, fn);
1881 while (((res < '0') || (res > '9')) &&
1882 (res != '#') && (res >= 0)) {
1883 res = get_folder(chan, 0);
1889 forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
1896 struct ast_config *mif;
1901 struct ast_vm_user *receiver, srec;
1906 res = ast_streamfile(chan, "vm-extension", chan->language);
1909 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1911 if ((receiver = find_user(&srec, context, username))) {
1912 /* if (play_and_wait(chan, "vm-savedto"))
1916 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, receiver->context, username);
1917 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1918 ast_log(LOG_DEBUG, sys);
1921 todircount = count_messages(todir);
1922 strncpy(tmp, fmt, sizeof(tmp));
1924 while((s = strsep(&stringp, "|"))) {
1925 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
1926 ast_log(LOG_DEBUG, sys);
1929 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
1930 ast_log(LOG_DEBUG, sys);
1932 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1934 /* load the information on the source message so we can send an e-mail like a new message */
1935 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1936 if ((mif=ast_load(miffile))) {
1938 /* set callerid and duration variables */
1939 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
1940 s = ast_variable_retrieve(mif, NULL, "duration");
1945 if (strlen(receiver->email)) {
1946 int attach_user_voicemail = attach_voicemail;
1947 char *myserveremail = serveremail;
1948 if (receiver->attach > -1)
1949 attach_user_voicemail = receiver->attach;
1950 if (strlen(receiver->serveremail))
1951 myserveremail = receiver->serveremail;
1952 sendmail(myserveremail, receiver, todircount, username, callerid, fn, tmp, duration), attach_user_voicemail);
1955 if (strlen(receiver->pager)) {
1956 char *myserveremail = serveremail;
1957 if (strlen(receiver->serveremail))
1958 myserveremail = receiver->serveremail;
1959 sendpage(myserveremail, receiver->pager, todircount, username, callerid, duration, receiver);
1962 ast_destroy(mif); /* or here */
1964 /* Leave voicemail for someone */
1965 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
1967 /* give confirmatopm that the message was saved */
1968 res = play_and_wait(chan, "vm-message");
1970 res = play_and_wait(chan, "vm-saved");
1971 free_user(receiver);
1974 res = play_and_wait(chan, "pbx-invalid");
1987 int deleted[MAXMSG];
1998 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
2001 if ((res = ast_streamfile(chan, file, chan->language)))
2002 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2004 res = ast_waitstream(chan, AST_DIGIT_ANY);
2008 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
2011 if ((res = ast_streamfile(chan, file, chan->language)))
2012 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2014 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
2018 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
2021 char filename[256], *origtime;
2022 struct vm_zone *the_zone = NULL;
2023 struct ast_config *msg_cfg;
2027 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2028 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
2029 msg_cfg = ast_load(filename);
2031 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
2035 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
2037 if (sscanf(origtime,"%ld",&tin) < 1) {
2038 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
2042 ast_destroy(msg_cfg);
2044 /* Does this user have a timezone specified? */
2045 if (strlen(vmu->zonetag)) {
2046 /* Find the zone in the list */
2050 if (!strcmp(z->name, vmu->zonetag)) {
2058 /* No internal variable parsing for now, so we'll comment it out for the time being */
2060 /* Set the DIFF_* variables */
2061 localtime_r(&t, &time_now);
2062 gettimeofday(&tv_now,NULL);
2063 tnow = tv_now.tv_sec;
2064 localtime_r(&tnow,&time_then);
2066 /* Day difference */
2067 if (time_now.tm_year == time_then.tm_year)
2068 sprintf(temp,"%d",time_now.tm_yday);
2070 sprintf(temp,"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
2071 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
2073 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
2076 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
2078 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
2080 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
2085 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg)
2089 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2090 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
2092 res = wait_file2(chan, vms, "vm-first");
2093 else if (msg == vms->lastmsg)
2094 res = wait_file2(chan, vms, "vm-last");
2096 res = wait_file2(chan, vms, "vm-message");
2097 if (msg && (msg != vms->lastmsg)) {
2099 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
2104 res = play_message_datetime(chan,vmu,vms);
2107 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2108 vms->heard[msg] = 1;
2109 res = wait_file(chan, vms, vms->fn);
2114 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
2116 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
2117 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2118 vms->lastmsg = count_messages(vms->curdir) - 1;
2119 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
2122 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
2125 char ntxt[256] = "";
2127 if (vms->lastmsg > -1) {
2128 /* Get the deleted messages fixed */
2130 for (x=0;x < MAXMSG;x++) {
2131 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
2132 /* Save this message. It's not in INBOX or hasn't been heard */
2133 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2134 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2137 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2138 if (strcmp(vms->fn, vms->fn2)) {
2139 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2140 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
2141 ast_filerename(vms->fn, vms->fn2, NULL);
2144 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
2145 /* Move to old folder before deleting */
2146 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
2149 for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
2150 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2151 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2153 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2154 ast_filedelete(vms->fn, NULL);
2158 memset(vms->deleted, 0, sizeof(vms->deleted));
2159 memset(vms->heard, 0, sizeof(vms->heard));
2162 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
2164 /* Introduce messages they have */
2166 res = play_and_wait(chan, "vm-youhave");
2168 if (vms->newmessages) {
2169 res = say_and_wait(chan, vms->newmessages);
2171 res = play_and_wait(chan, "vm-INBOX");
2172 if (vms->oldmessages && !res)
2173 res = play_and_wait(chan, "vm-and");
2175 if ((vms->newmessages == 1))
2176 res = play_and_wait(chan, "vm-message");
2178 res = play_and_wait(chan, "vm-messages");
2182 if (!res && vms->oldmessages) {
2183 res = say_and_wait(chan, vms->oldmessages);
2185 res = play_and_wait(chan, "vm-Old");
2187 if (vms->oldmessages == 1)
2188 res = play_and_wait(chan, "vm-message");
2190 res = play_and_wait(chan, "vm-messages");
2194 if (!vms->oldmessages && !vms->newmessages) {
2195 res = play_and_wait(chan, "vm-no");
2197 res = play_and_wait(chan, "vm-messages");
2204 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
2207 /* Play instructions and wait for new command */
2209 if (vms->starting) {
2210 if (vms->lastmsg > -1) {
2211 res = play_and_wait(chan, "vm-onefor");
2213 res = play_and_wait(chan, vms->vmbox);
2215 res = play_and_wait(chan, "vm-messages");
2218 res = play_and_wait(chan, "vm-opts");
2221 res = play_and_wait(chan, "vm-prev");
2223 res = play_and_wait(chan, "vm-repeat");
2224 if (!res && (vms->curmsg != vms->lastmsg))
2225 res = play_and_wait(chan, "vm-next");
2227 if (!vms->deleted[vms->curmsg])
2228 res = play_and_wait(chan, "vm-delete");
2230 res = play_and_wait(chan, "vm-undelete");
2232 res = play_and_wait(chan, "vm-toforward");
2234 res = play_and_wait(chan, "vm-savemessage");
2238 res = play_and_wait(chan, "vm-helpexit");
2240 res = ast_waitfordigit(chan, 6000);
2243 if (vms->repeats > 2) {
2244 res = play_and_wait(chan, "vm-goodbye");
2253 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
2257 char newpassword[80] = "";
2258 char newpassword2[80] = "";
2259 char prefile[256]="";
2263 if (adsi_available(chan))
2265 bytes += adsi_logo(buf + bytes);
2266 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
2267 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
2268 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2269 bytes += adsi_voice_mode(buf + bytes, 0);
2270 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2272 while((cmd >= 0) && (cmd != 't')) {
2277 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
2278 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
2281 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
2282 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
2285 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
2286 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
2289 newpassword[1] = '\0';
2290 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
2293 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
2296 newpassword2[1] = '\0';
2297 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
2301 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
2304 if (strcmp(newpassword, newpassword2)) {
2305 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
2306 cmd = play_and_wait(chan, "vm-mismatch");
2309 vm_change_password(vmu,newpassword);
2310 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
2311 cmd = play_and_wait(chan,"vm-passchanged");
2317 cmd = play_and_wait(chan,"vm-options");
2319 cmd = ast_waitfordigit(chan,6000);
2331 static int vm_execmain(struct ast_channel *chan, void *data)
2333 /* XXX This is, admittedly, some pretty horrendus code. For some
2334 reason it just seemed a lot easier to do with GOTO's. I feel
2335 like I'm back in my GWBASIC days. XXX */
2340 struct localuser *u;
2341 char prefixstr[80] ="";
2342 char empty[80] = "";
2346 char tmp[256], *ext;
2347 char fmtc[256] = "";
2349 struct vm_state vms;
2351 struct ast_vm_user *vmu = NULL, vmus;
2355 memset(&vms, 0, sizeof(vms));
2356 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
2357 if (chan->_state != AST_STATE_UP)
2360 if (data && strlen(data)) {
2361 strncpy(tmp, data, sizeof(tmp) - 1);
2366 /* We should skip the user's password */
2371 /* We should prefix the mailbox with the supplied data */
2377 context = strchr(ext, '@');
2384 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
2386 strncpy(vms.username, ext, sizeof(vms.username) - 1);
2387 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
2394 /* If ADSI is supported, setup login screen */
2395 adsi_begin(chan, &useadsi);
2396 if (!skipuser && useadsi)
2398 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
2399 ast_log(LOG_WARNING, "Couldn't stream login file\n");
2403 /* Authenticate them and get their mailbox/password */
2405 while (!valid && (logretries < maxlogins)) {
2406 /* Prompt for, and read in the username */
2407 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
2408 ast_log(LOG_WARNING, "Couldn't read username\n");
2411 if (!strlen(vms.username)) {
2412 if (option_verbose > 2)
2413 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
2418 adsi_password(chan);
2419 if (ast_streamfile(chan, "vm-password", chan->language)) {
2420 ast_log(LOG_WARNING, "Unable to stream password file\n");
2423 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
2424 ast_log(LOG_WARNING, "Unable to read password\n");
2428 char fullusername[80] = "";
2429 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
2430 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
2431 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
2434 vmu = find_user(&vmus, context, vms.username);
2435 if (vmu && !strcmp(vmu->password, password))
2438 if (option_verbose > 2)
2439 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
2441 strncpy(vms.username, empty, sizeof(vms.username) -1);
2446 if (ast_streamfile(chan, "vm-incorrect", chan->language))
2451 if (!valid && (logretries >= maxlogins)) {
2452 ast_stopstream(chan);
2453 res = play_and_wait(chan, "vm-goodbye");
2459 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
2460 mkdir(vms.curdir, 0700);
2461 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
2462 mkdir(vms.curdir, 0700);
2463 /* Retrieve old and new message counts */
2464 open_mailbox(&vms, vmu, 1);
2465 vms.oldmessages = vms.lastmsg + 1;
2466 /* Start in INBOX */
2467 open_mailbox(&vms, vmu, 0);
2468 vms.newmessages = vms.lastmsg + 1;
2471 /* Select proper mailbox FIRST!! */
2472 if (!vms.newmessages && vms.oldmessages) {
2473 /* If we only have old messages start here */
2474 open_mailbox(&vms, vmu, 1);
2478 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2480 cmd = vm_intro(chan, &vms);
2483 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2490 if (vms.lastmsg > -1) {
2491 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2493 cmd = play_and_wait(chan, "vm-youhave");
2495 cmd = play_and_wait(chan, "vm-no");
2497 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2498 cmd = play_and_wait(chan, vms.fn);
2501 cmd = play_and_wait(chan, "vm-messages");
2504 case '2': /* Change folders */
2506 adsi_folders(chan, 0, "Change to folder...");
2507 cmd = get_folder2(chan, "vm-changeto", 0);
2510 } else if (cmd > 0) {
2512 close_mailbox(&vms, vmu);
2513 open_mailbox(&vms, vmu, cmd);
2517 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2519 cmd = play_and_wait(chan, vms.vmbox);
2521 cmd = play_and_wait(chan, "vm-messages");
2527 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2529 cmd = play_and_wait(chan, "vm-nomore");
2533 if (vms.curmsg < vms.lastmsg) {
2535 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2537 cmd = play_and_wait(chan, "vm-nomore");
2541 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2543 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2544 if (vms.deleted[vms.curmsg])
2545 cmd = play_and_wait(chan, "vm-deleted");
2547 cmd = play_and_wait(chan, "vm-undeleted");
2550 if(vms.lastmsg > -1)
2551 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2553 cmd = play_and_wait(chan, "vm-nomore");
2557 adsi_folders(chan, 1, "Save to folder...");
2558 cmd = get_folder2(chan, "vm-savefolder", 1);
2559 box = 0; /* Shut up compiler */
2563 } else if (cmd > 0) {
2564 box = cmd = cmd - '0';
2565 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2566 vms.deleted[vms.curmsg]=1;
2568 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2570 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2572 cmd = play_and_wait(chan, "vm-message");
2574 cmd = say_and_wait(chan, vms.curmsg + 1);
2576 cmd = play_and_wait(chan, "vm-savedto");
2578 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2579 cmd = play_and_wait(chan, vms.fn);
2582 cmd = play_and_wait(chan, "vm-messages");
2585 if (!vms.starting) {
2586 cmd = play_and_wait(chan, "vm-onefor");
2588 cmd = play_and_wait(chan, vms.vmbox);
2590 cmd = play_and_wait(chan, "vm-messages");
2592 cmd = play_and_wait(chan, "vm-opts");
2597 cmd = vm_options(chan, vmu, &vms, vmfmts);
2599 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2601 default: /* Nothing */
2602 cmd = vm_instructions(chan, &vms);
2606 if ((cmd == 't') || (cmd == '#')) {
2616 ast_stopstream(chan);
2619 res = play_and_wait(chan, "vm-goodbye");
2624 adsi_unload_session(chan);
2627 close_mailbox(&vms, vmu);
2631 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2633 LOCAL_USER_REMOVE(u);
2638 static int vm_exec(struct ast_channel *chan, void *data)
2640 int res=0, silent=0, busy=0, unavail=0;
2641 struct localuser *u;
2642 char tmp[256], *ext;
2645 if (chan->_state != AST_STATE_UP)
2647 if (data && strlen(data))
2648 strncpy(tmp, data, sizeof(tmp) - 1);
2650 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2661 } else if (*ext == 'b') {
2664 } else if (*ext == 'u') {
2670 res = leave_voicemail(chan, ext, silent, busy, unavail);
2671 LOCAL_USER_REMOVE(u);
2675 static int append_mailbox(char *context, char *mbox, char *data)
2677 /* Assumes lock is already held */
2681 struct ast_vm_user *vmu;
2682 strncpy(tmp, data, sizeof(tmp));
2683 vmu = malloc(sizeof(struct ast_vm_user));
2685 memset(vmu, 0, sizeof(struct ast_vm_user));
2686 strncpy(vmu->context, context, sizeof(vmu->context));
2687 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2690 if ((s = strsep(&stringp, ",")))
2691 strncpy(vmu->password, s, sizeof(vmu->password));
2692 if (stringp && (s = strsep(&stringp, ",")))
2693 strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2694 if (stringp && (s = strsep(&stringp, ",")))
2695 strncpy(vmu->email, s, sizeof(vmu->email));
2696 if (stringp && (s = strsep(&stringp, ",")))
2697 strncpy(vmu->pager, s, sizeof(vmu->pager));
2698 if (stringp && (s = strsep(&stringp, ",")))
2699 apply_options(vmu, s);
2710 static int load_config(void)
2712 struct ast_vm_user *cur, *l;
2713 struct vm_zone *zcur, *zl;
2714 struct ast_config *cfg;
2716 struct ast_variable *var;
2725 cfg = ast_load(VOICEMAIL_CONFIG);
2726 ast_mutex_lock(&vmlock);
2744 /* General settings */
2745 attach_voicemail = 1;
2746 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
2748 attach_voicemail = ast_true(astattach);
2750 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2751 maxsilence = atoi(silencestr);
2756 silencethreshold = 256;
2757 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2758 silencethreshold = atoi(thresholdstr);
2760 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
2761 astemail = ASTERISK_USERNAME;
2762 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2765 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2766 if (sscanf(s, "%d", &x) == 1) {
2769 ast_log(LOG_WARNING, "Invalid max message time length\n");
2772 fmt = ast_variable_retrieve(cfg, "general", "format");
2775 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2778 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2779 if (sscanf(s, "%d", &x) == 1) {
2782 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2786 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2787 if (sscanf(s, "%d", &x) == 1) {
2790 ast_log(LOG_WARNING, "Invalid skipms value\n");
2795 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
2796 if (sscanf(s, "%d", &x) == 1) {
2799 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
2804 if (!(s=ast_variable_retrieve(cfg, "general", "dbuser"))) {
2805 strcpy(dbuser, "test");
2809 if (!(s=ast_variable_retrieve(cfg, "general", "dbpass"))) {
2810 strcpy(dbpass, "test");
2814 if (!(s=ast_variable_retrieve(cfg, "general", "dbhost"))) {
2819 if (!(s=ast_variable_retrieve(cfg, "general", "dbname"))) {
2820 strcpy(dbname, "vmdb");
2826 #ifdef USEPOSTGRESVM
2827 if (!(s=ast_variable_retrieve(cfg, "general", "dboption"))) {
2828 strcpy(dboption, "dboption not-specified in voicemail.conf");
2830 strcpy(dboption, s);
2833 cat = ast_category_browse(cfg, NULL);
2835 if (strcasecmp(cat, "general")) {
2836 var = ast_variable_browse(cfg, cat);
2837 if (strcasecmp(cat, "zonemessages")) {
2839 /* Process mailboxes in this context */
2841 append_mailbox(cat, var->name, var->value);
2846 /* Timezones in this context */
2849 z = malloc(sizeof(struct vm_zone));
2851 char *msg_format, *timezone;
2852 msg_format = ast_strdupa(var->value);
2853 if (msg_format != NULL) {
2854 timezone = strsep(&msg_format, "|");
2855 strncpy(z->name, var->name, sizeof(z->name) - 1);
2856 strncpy(z->timezone, timezone, sizeof(z->timezone) - 1);
2857 strncpy(z->msg_format, msg_format, sizeof(z->msg_format) - 1);
2867 ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
2872 ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
2879 cat = ast_category_browse(cfg, cat);
2881 memset(fromstring,0,sizeof(fromstring));
2882 memset(emailtitle,0,sizeof(emailtitle));
2887 if ((s=ast_variable_retrieve(cfg, "general", "pbxskip")))
2888 pbxskip = ast_true(s);
2889 if ((s=ast_variable_retrieve(cfg, "general", "fromstring")))
2890 strncpy(fromstring,s,sizeof(fromstring)-1);
2891 if ((s=ast_variable_retrieve(cfg, "general", "emailtitle")))
2892 strncpy(emailtitle,s,sizeof(emailtitle)-1);
2893 if ((s=ast_variable_retrieve(cfg, "general", "emailbody"))) {
2894 char *tmpread, *tmpwrite;
2895 emailbody = strdup(s);
2897 /* substitute strings \t and \n into the apropriate characters */
2898 tmpread = tmpwrite = emailbody;
2899 while ((tmpwrite = strchr(tmpread,'\\'))) {
2900 int len = strlen("\n");
2901 switch (tmpwrite[1]) {
2903 strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
2904 strncpy(tmpwrite,"\n",len);
2907 strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
2908 strncpy(tmpwrite,"\t",len);
2911 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n",tmpwrite[1]);
2913 tmpread = tmpwrite+len;
2917 ast_mutex_unlock(&vmlock);
2920 ast_mutex_unlock(&vmlock);
2921 ast_log(LOG_WARNING, "Error reading voicemail config\n");
2928 return(load_config());
2931 int unload_module(void)
2934 STANDARD_HANGUP_LOCALUSERS;
2935 res = ast_unregister_application(app);
2936 res |= ast_unregister_application(capp);
2937 res |= ast_unregister_application(app2);
2938 res |= ast_unregister_application(capp2);
2943 int load_module(void)
2946 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2947 res |= ast_register_application(capp, vm_exec, synopsis_vm, descrip_vm);
2948 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2949 res |= ast_register_application(capp2, vm_execmain, synopsis_vmain, descrip_vmain);
2953 if ((res=load_config())) {
2957 if ((res = sql_init())) {
2958 ast_log(LOG_WARNING, "SQL init\n");
2964 char *description(void)
2972 STANDARD_USECOUNT(res);
2978 return ASTERISK_GPL_KEY;