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 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1942 if (strlen(receiver->email)) {
1943 int attach_user_voicemail = attach_voicemail;
1944 char *myserveremail = serveremail;
1945 if (receiver->attach > -1)
1946 attach_user_voicemail = receiver->attach;
1947 if (strlen(receiver->serveremail))
1948 myserveremail = receiver->serveremail;
1949 sendmail(myserveremail, receiver, todircount, username, callerid, fn, tmp, atol(ast_variable_retrieve(mif, NULL, "duration")), attach_user_voicemail);
1952 if (strlen(receiver->pager)) {
1953 char *myserveremail = serveremail;
1954 if (strlen(receiver->serveremail))
1955 myserveremail = receiver->serveremail;
1956 sendpage(myserveremail, receiver->pager, todircount, username, callerid, duration, receiver);
1959 ast_destroy(mif); /* or here */
1961 /* Leave voicemail for someone */
1962 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
1964 /* give confirmatopm that the message was saved */
1965 res = play_and_wait(chan, "vm-message");
1967 res = play_and_wait(chan, "vm-saved");
1968 free_user(receiver);
1971 res = play_and_wait(chan, "pbx-invalid");
1984 int deleted[MAXMSG];
1995 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1998 if ((res = ast_streamfile(chan, file, chan->language)))
1999 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2001 res = ast_waitstream(chan, AST_DIGIT_ANY);
2005 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
2008 if ((res = ast_streamfile(chan, file, chan->language)))
2009 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
2011 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
2015 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
2018 char filename[256], *origtime;
2019 struct vm_zone *the_zone = NULL;
2020 struct ast_config *msg_cfg;
2024 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2025 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
2026 msg_cfg = ast_load(filename);
2028 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
2032 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
2034 if (sscanf(origtime,"%ld",&tin) < 1) {
2035 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
2039 ast_destroy(msg_cfg);
2041 /* Does this user have a timezone specified? */
2042 if (strlen(vmu->zonetag)) {
2043 /* Find the zone in the list */
2047 if (!strcmp(z->name, vmu->zonetag)) {
2055 /* No internal variable parsing for now, so we'll comment it out for the time being */
2057 /* Set the DIFF_* variables */
2058 localtime_r(&t, &time_now);
2059 gettimeofday(&tv_now,NULL);
2060 tnow = tv_now.tv_sec;
2061 localtime_r(&tnow,&time_then);
2063 /* Day difference */
2064 if (time_now.tm_year == time_then.tm_year)
2065 sprintf(temp,"%d",time_now.tm_yday);
2067 sprintf(temp,"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
2068 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
2070 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
2073 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
2075 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
2077 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
2082 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg)
2086 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2087 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
2089 res = wait_file2(chan, vms, "vm-first");
2090 else if (msg == vms->lastmsg)
2091 res = wait_file2(chan, vms, "vm-last");
2093 res = wait_file2(chan, vms, "vm-message");
2094 if (msg && (msg != vms->lastmsg)) {
2096 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
2101 res = play_message_datetime(chan,vmu,vms);
2104 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
2105 vms->heard[msg] = 1;
2106 res = wait_file(chan, vms, vms->fn);
2111 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
2113 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
2114 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2115 vms->lastmsg = count_messages(vms->curdir) - 1;
2116 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
2119 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
2122 char ntxt[256] = "";
2124 if (vms->lastmsg > -1) {
2125 /* Get the deleted messages fixed */
2127 for (x=0;x < MAXMSG;x++) {
2128 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
2129 /* Save this message. It's not in INBOX or hasn't been heard */
2130 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2131 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2134 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
2135 if (strcmp(vms->fn, vms->fn2)) {
2136 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2137 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
2138 ast_filerename(vms->fn, vms->fn2, NULL);
2141 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
2142 /* Move to old folder before deleting */
2143 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
2146 for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
2147 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
2148 if (ast_fileexists(vms->fn, NULL, NULL) < 1)
2150 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
2151 ast_filedelete(vms->fn, NULL);
2155 memset(vms->deleted, 0, sizeof(vms->deleted));
2156 memset(vms->heard, 0, sizeof(vms->heard));
2159 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
2161 /* Introduce messages they have */
2163 res = play_and_wait(chan, "vm-youhave");
2165 if (vms->newmessages) {
2166 res = say_and_wait(chan, vms->newmessages);
2168 res = play_and_wait(chan, "vm-INBOX");
2169 if (vms->oldmessages && !res)
2170 res = play_and_wait(chan, "vm-and");
2172 if ((vms->newmessages == 1))
2173 res = play_and_wait(chan, "vm-message");
2175 res = play_and_wait(chan, "vm-messages");
2179 if (!res && vms->oldmessages) {
2180 res = say_and_wait(chan, vms->oldmessages);
2182 res = play_and_wait(chan, "vm-Old");
2184 if (vms->oldmessages == 1)
2185 res = play_and_wait(chan, "vm-message");
2187 res = play_and_wait(chan, "vm-messages");
2191 if (!vms->oldmessages && !vms->newmessages) {
2192 res = play_and_wait(chan, "vm-no");
2194 res = play_and_wait(chan, "vm-messages");
2201 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
2204 /* Play instructions and wait for new command */
2206 if (vms->starting) {
2207 if (vms->lastmsg > -1) {
2208 res = play_and_wait(chan, "vm-onefor");
2210 res = play_and_wait(chan, vms->vmbox);
2212 res = play_and_wait(chan, "vm-messages");
2215 res = play_and_wait(chan, "vm-opts");
2218 res = play_and_wait(chan, "vm-prev");
2220 res = play_and_wait(chan, "vm-repeat");
2221 if (!res && (vms->curmsg != vms->lastmsg))
2222 res = play_and_wait(chan, "vm-next");
2224 if (!vms->deleted[vms->curmsg])
2225 res = play_and_wait(chan, "vm-delete");
2227 res = play_and_wait(chan, "vm-undelete");
2229 res = play_and_wait(chan, "vm-toforward");
2231 res = play_and_wait(chan, "vm-savemessage");
2235 res = play_and_wait(chan, "vm-helpexit");
2237 res = ast_waitfordigit(chan, 6000);
2240 if (vms->repeats > 2) {
2241 res = play_and_wait(chan, "vm-goodbye");
2250 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
2254 char newpassword[80] = "";
2255 char newpassword2[80] = "";
2256 char prefile[256]="";
2260 if (adsi_available(chan))
2262 bytes += adsi_logo(buf + bytes);
2263 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
2264 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
2265 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2266 bytes += adsi_voice_mode(buf + bytes, 0);
2267 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2269 while((cmd >= 0) && (cmd != 't')) {
2274 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
2275 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
2278 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
2279 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
2282 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
2283 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
2286 newpassword[1] = '\0';
2287 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
2290 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
2293 newpassword2[1] = '\0';
2294 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
2298 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
2301 if (strcmp(newpassword, newpassword2)) {
2302 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
2303 cmd = play_and_wait(chan, "vm-mismatch");
2306 vm_change_password(vmu,newpassword);
2307 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
2308 cmd = play_and_wait(chan,"vm-passchanged");
2314 cmd = play_and_wait(chan,"vm-options");
2316 cmd = ast_waitfordigit(chan,6000);
2328 static int vm_execmain(struct ast_channel *chan, void *data)
2330 /* XXX This is, admittedly, some pretty horrendus code. For some
2331 reason it just seemed a lot easier to do with GOTO's. I feel
2332 like I'm back in my GWBASIC days. XXX */
2337 struct localuser *u;
2338 char prefixstr[80] ="";
2339 char empty[80] = "";
2343 char tmp[256], *ext;
2344 char fmtc[256] = "";
2346 struct vm_state vms;
2348 struct ast_vm_user *vmu = NULL, vmus;
2352 memset(&vms, 0, sizeof(vms));
2353 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
2354 if (chan->_state != AST_STATE_UP)
2357 if (data && strlen(data)) {
2358 strncpy(tmp, data, sizeof(tmp) - 1);
2363 /* We should skip the user's password */
2368 /* We should prefix the mailbox with the supplied data */
2374 context = strchr(ext, '@');
2381 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
2383 strncpy(vms.username, ext, sizeof(vms.username) - 1);
2384 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
2391 /* If ADSI is supported, setup login screen */
2392 adsi_begin(chan, &useadsi);
2393 if (!skipuser && useadsi)
2395 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
2396 ast_log(LOG_WARNING, "Couldn't stream login file\n");
2400 /* Authenticate them and get their mailbox/password */
2402 while (!valid && (logretries < maxlogins)) {
2403 /* Prompt for, and read in the username */
2404 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
2405 ast_log(LOG_WARNING, "Couldn't read username\n");
2408 if (!strlen(vms.username)) {
2409 if (option_verbose > 2)
2410 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
2415 adsi_password(chan);
2416 if (ast_streamfile(chan, "vm-password", chan->language)) {
2417 ast_log(LOG_WARNING, "Unable to stream password file\n");
2420 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
2421 ast_log(LOG_WARNING, "Unable to read password\n");
2425 char fullusername[80] = "";
2426 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
2427 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
2428 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
2431 vmu = find_user(&vmus, context, vms.username);
2432 if (vmu && !strcmp(vmu->password, password))
2435 if (option_verbose > 2)
2436 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
2438 strncpy(vms.username, empty, sizeof(vms.username) -1);
2443 if (ast_streamfile(chan, "vm-incorrect", chan->language))
2448 if (!valid && (logretries >= maxlogins)) {
2449 ast_stopstream(chan);
2450 res = play_and_wait(chan, "vm-goodbye");
2456 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
2457 mkdir(vms.curdir, 0700);
2458 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
2459 mkdir(vms.curdir, 0700);
2460 /* Retrieve old and new message counts */
2461 open_mailbox(&vms, vmu, 1);
2462 vms.oldmessages = vms.lastmsg + 1;
2463 /* Start in INBOX */
2464 open_mailbox(&vms, vmu, 0);
2465 vms.newmessages = vms.lastmsg + 1;
2468 /* Select proper mailbox FIRST!! */
2469 if (!vms.newmessages && vms.oldmessages) {
2470 /* If we only have old messages start here */
2471 open_mailbox(&vms, vmu, 1);
2475 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2477 cmd = vm_intro(chan, &vms);
2480 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2487 if (vms.lastmsg > -1) {
2488 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2490 cmd = play_and_wait(chan, "vm-youhave");
2492 cmd = play_and_wait(chan, "vm-no");
2494 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2495 cmd = play_and_wait(chan, vms.fn);
2498 cmd = play_and_wait(chan, "vm-messages");
2501 case '2': /* Change folders */
2503 adsi_folders(chan, 0, "Change to folder...");
2504 cmd = get_folder2(chan, "vm-changeto", 0);
2507 } else if (cmd > 0) {
2509 close_mailbox(&vms, vmu);
2510 open_mailbox(&vms, vmu, cmd);
2514 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2516 cmd = play_and_wait(chan, vms.vmbox);
2518 cmd = play_and_wait(chan, "vm-messages");
2524 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2526 cmd = play_and_wait(chan, "vm-nomore");
2530 if (vms.curmsg < vms.lastmsg) {
2532 cmd = play_message(chan, vmu, &vms, vms.curmsg);
2534 cmd = play_and_wait(chan, "vm-nomore");
2538 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2540 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2541 if (vms.deleted[vms.curmsg])
2542 cmd = play_and_wait(chan, "vm-deleted");
2544 cmd = play_and_wait(chan, "vm-undeleted");
2547 if(vms.lastmsg > -1)
2548 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2550 cmd = play_and_wait(chan, "vm-nomore");
2554 adsi_folders(chan, 1, "Save to folder...");
2555 cmd = get_folder2(chan, "vm-savefolder", 1);
2556 box = 0; /* Shut up compiler */
2560 } else if (cmd > 0) {
2561 box = cmd = cmd - '0';
2562 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2563 vms.deleted[vms.curmsg]=1;
2565 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2567 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2569 cmd = play_and_wait(chan, "vm-message");
2571 cmd = say_and_wait(chan, vms.curmsg + 1);
2573 cmd = play_and_wait(chan, "vm-savedto");
2575 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2576 cmd = play_and_wait(chan, vms.fn);
2579 cmd = play_and_wait(chan, "vm-messages");
2582 if (!vms.starting) {
2583 cmd = play_and_wait(chan, "vm-onefor");
2585 cmd = play_and_wait(chan, vms.vmbox);
2587 cmd = play_and_wait(chan, "vm-messages");
2589 cmd = play_and_wait(chan, "vm-opts");
2594 cmd = vm_options(chan, vmu, &vms, vmfmts);
2596 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2598 default: /* Nothing */
2599 cmd = vm_instructions(chan, &vms);
2603 if ((cmd == 't') || (cmd == '#')) {
2613 ast_stopstream(chan);
2616 res = play_and_wait(chan, "vm-goodbye");
2621 adsi_unload_session(chan);
2624 close_mailbox(&vms, vmu);
2628 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2630 LOCAL_USER_REMOVE(u);
2635 static int vm_exec(struct ast_channel *chan, void *data)
2637 int res=0, silent=0, busy=0, unavail=0;
2638 struct localuser *u;
2639 char tmp[256], *ext;
2642 if (chan->_state != AST_STATE_UP)
2645 strncpy(tmp, data, sizeof(tmp) - 1);
2647 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2658 } else if (*ext == 'b') {
2661 } else if (*ext == 'u') {
2667 res = leave_voicemail(chan, ext, silent, busy, unavail);
2668 LOCAL_USER_REMOVE(u);
2672 static int append_mailbox(char *context, char *mbox, char *data)
2674 /* Assumes lock is already held */
2678 struct ast_vm_user *vmu;
2679 strncpy(tmp, data, sizeof(tmp));
2680 vmu = malloc(sizeof(struct ast_vm_user));
2682 memset(vmu, 0, sizeof(struct ast_vm_user));
2683 strncpy(vmu->context, context, sizeof(vmu->context));
2684 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2687 if ((s = strsep(&stringp, ",")))
2688 strncpy(vmu->password, s, sizeof(vmu->password));
2689 if (stringp && (s = strsep(&stringp, ",")))
2690 strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2691 if (stringp && (s = strsep(&stringp, ",")))
2692 strncpy(vmu->email, s, sizeof(vmu->email));
2693 if (stringp && (s = strsep(&stringp, ",")))
2694 strncpy(vmu->pager, s, sizeof(vmu->pager));
2695 if (stringp && (s = strsep(&stringp, ",")))
2696 apply_options(vmu, s);
2707 static int load_config(void)
2709 struct ast_vm_user *cur, *l;
2710 struct vm_zone *zcur, *zl;
2711 struct ast_config *cfg;
2713 struct ast_variable *var;
2722 cfg = ast_load(VOICEMAIL_CONFIG);
2723 ast_mutex_lock(&vmlock);
2741 /* General settings */
2742 attach_voicemail = 1;
2743 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
2745 attach_voicemail = ast_true(astattach);
2747 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2748 maxsilence = atoi(silencestr);
2753 silencethreshold = 256;
2754 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2755 silencethreshold = atoi(thresholdstr);
2757 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
2758 astemail = ASTERISK_USERNAME;
2759 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2762 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2763 if (sscanf(s, "%d", &x) == 1) {
2766 ast_log(LOG_WARNING, "Invalid max message time length\n");
2769 fmt = ast_variable_retrieve(cfg, "general", "format");
2772 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2775 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2776 if (sscanf(s, "%d", &x) == 1) {
2779 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2783 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2784 if (sscanf(s, "%d", &x) == 1) {
2787 ast_log(LOG_WARNING, "Invalid skipms value\n");
2792 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
2793 if (sscanf(s, "%d", &x) == 1) {
2796 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
2801 if (!(s=ast_variable_retrieve(cfg, "general", "dbuser"))) {
2802 strcpy(dbuser, "test");
2806 if (!(s=ast_variable_retrieve(cfg, "general", "dbpass"))) {
2807 strcpy(dbpass, "test");
2811 if (!(s=ast_variable_retrieve(cfg, "general", "dbhost"))) {
2816 if (!(s=ast_variable_retrieve(cfg, "general", "dbname"))) {
2817 strcpy(dbname, "vmdb");
2823 #ifdef USEPOSTGRESVM
2824 if (!(s=ast_variable_retrieve(cfg, "general", "dboption"))) {
2825 strcpy(dboption, "dboption not-specified in voicemail.conf");
2827 strcpy(dboption, s);
2830 cat = ast_category_browse(cfg, NULL);
2832 if (strcasecmp(cat, "general")) {
2833 var = ast_variable_browse(cfg, cat);
2834 if (strcasecmp(cat, "zonemessages")) {
2836 /* Process mailboxes in this context */
2838 append_mailbox(cat, var->name, var->value);
2843 /* Timezones in this context */
2846 z = malloc(sizeof(struct vm_zone));
2848 char *msg_format, *timezone;
2849 msg_format = ast_strdupa(var->value);
2850 if (msg_format != NULL) {
2851 timezone = strsep(&msg_format, "|");
2852 strncpy(z->name, var->name, sizeof(z->name) - 1);
2853 strncpy(z->timezone, timezone, sizeof(z->timezone) - 1);
2854 strncpy(z->msg_format, msg_format, sizeof(z->msg_format) - 1);
2864 ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
2869 ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
2876 cat = ast_category_browse(cfg, cat);
2878 memset(fromstring,0,sizeof(fromstring));
2879 memset(emailtitle,0,sizeof(emailtitle));
2884 if ((s=ast_variable_retrieve(cfg, "general", "pbxskip")))
2885 pbxskip = ast_true(s);
2886 if ((s=ast_variable_retrieve(cfg, "general", "fromstring")))
2887 strncpy(fromstring,s,sizeof(fromstring)-1);
2888 if ((s=ast_variable_retrieve(cfg, "general", "emailtitle")))
2889 strncpy(emailtitle,s,sizeof(emailtitle)-1);
2890 if ((s=ast_variable_retrieve(cfg, "general", "emailbody"))) {
2891 char *tmpread, *tmpwrite;
2892 emailbody = strdup(s);
2894 /* substitute strings \t and \n into the apropriate characters */
2895 tmpread = tmpwrite = emailbody;
2896 while ((tmpwrite = strchr(tmpread,'\\'))) {
2897 int len = strlen("\n");
2898 switch (tmpwrite[1]) {
2900 strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
2901 strncpy(tmpwrite,"\n",len);
2904 strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
2905 strncpy(tmpwrite,"\t",len);
2908 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n",tmpwrite[1]);
2910 tmpread = tmpwrite+len;
2914 ast_mutex_unlock(&vmlock);
2917 ast_mutex_unlock(&vmlock);
2918 ast_log(LOG_WARNING, "Error reading voicemail config\n");
2925 return(load_config());
2928 int unload_module(void)
2931 STANDARD_HANGUP_LOCALUSERS;
2932 res = ast_unregister_application(app);
2933 res |= ast_unregister_application(capp);
2934 res |= ast_unregister_application(app2);
2935 res |= ast_unregister_application(capp2);
2940 int load_module(void)
2943 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2944 res |= ast_register_application(capp, vm_exec, synopsis_vm, descrip_vm);
2945 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2946 res |= ast_register_application(capp2, vm_execmain, synopsis_vmain, descrip_vmain);
2950 if ((res=load_config())) {
2954 if ((res = sql_init())) {
2955 ast_log(LOG_WARNING, "SQL init\n");
2961 char *description(void)
2969 STANDARD_USECOUNT(res);
2975 return ASTERISK_GPL_KEY;