2 * Asterisk -- A telephony toolkit for Linux.
4 * Voicemail System (did you ever think it could be so easy?)
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
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/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/config.h>
21 #include <asterisk/say.h>
22 #include <asterisk/module.h>
23 #include <asterisk/adsi.h>
24 #include <asterisk/app.h>
25 #include <asterisk/manager.h>
26 #include <asterisk/dsp.h>
38 #include "../asterisk.h"
39 #include "../astconf.h"
41 #define COMMAND_TIMEOUT 5000
43 #define VOICEMAIL_CONFIG "voicemail.conf"
44 #define ASTERISK_USERNAME "asterisk"
46 #define SENDMAIL "/usr/sbin/sendmail -t"
48 #define INTRO "vm-intro"
52 #define MAX_OTHER_FORMATS 10
54 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
56 #define BASEMAXINLINE 256
58 #define BASELINELEN 72
64 #define BASEMAXINLINE 256
65 #define BASELINELEN 72
73 unsigned char iobuf[BASEMAXINLINE];
84 struct ast_vm_user *next;
87 static char *tdesc = "Comedian Mail (Voicemail System)";
89 static char *adapp = "CoMa";
91 static char *adsec = "_AST";
93 static char *addesc = "Comedian Mail";
97 static char *synopsis_vm =
98 "Leave a voicemail message";
100 static char *descrip_vm =
101 " VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given extension (must\n"
102 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
103 "then instructions for leaving the message will be skipped. If the extension\n"
104 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
105 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
106 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
107 "busy instead of unavail). At most one of 's', 'u', or 'b' may be specified.\n"
108 "Returns -1 on error or mailbox not found, or if the user hangs up. \n"
109 "Otherwise, it returns 0. \n";
111 static char *synopsis_vmain =
112 "Enter voicemail system";
114 static char *descrip_vmain =
115 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system for the checking of\n"
116 "voicemail. The mailbox can be passed as the option, which will stop the\n"
117 "voicemail system from prompting the user for the mailbox. If the mailbox\n"
118 "is preceded by 's' then the password check will be skipped. If a context is\n"
119 "specified, logins are considered in that context only. Returns -1 if\n"
120 "the user hangs up or 0 otherwise.\n";
122 /* Leave a message */
123 static char *app = "VoiceMail2";
125 /* Check mail, control, etc */
126 static char *app2 = "VoiceMailMain2";
128 static pthread_mutex_t vmlock = AST_MUTEX_INITIALIZER;
129 struct ast_vm_user *users;
130 struct ast_vm_user *usersl;
131 static int attach_voicemail;
132 static int maxsilence;
133 static int silencethreshold;
134 static char serveremail[80];
135 static char vmfmts[80];
136 static int vmmaxmessage;
139 static int maxlogins;
145 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
147 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
150 static int make_file(char *dest, int len, char *dir, int num)
152 return snprintf(dest, len, "%s/msg%04d", dir, num);
155 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
157 /* This function could be made to generate one from a database, too */
158 struct ast_vm_user *vmu=NULL, *cur;
159 ast_pthread_mutex_lock(&vmlock);
162 if ((!context || !strcasecmp(context, cur->context)) &&
163 (!strcasecmp(mailbox, cur->mailbox)))
171 /* Make a copy, so that on a reload, we have no race */
172 vmu = malloc(sizeof(struct ast_vm_user));
174 memcpy(vmu, cur, sizeof(struct ast_vm_user));
182 ast_pthread_mutex_unlock(&vmlock);
186 static int vm_change_password(struct ast_vm_user *vmu, char *newpassword)
188 /* There's probably a better way of doing this. */
189 /* That's why I've put the password change in a separate function. */
190 /* This could also be done with a database function */
196 char tmpin[AST_CONFIG_MAX_PATH];
197 char tmpout[AST_CONFIG_MAX_PATH];
198 char *user, *pass, *rest, *trim;
199 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
200 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
201 configin = fopen((char *)tmpin,"r");
202 configout = fopen((char *)tmpout,"w+");
204 while (!feof(configin)) {
205 /* Read in the line */
206 fgets(inbuf, sizeof(inbuf), configin);
207 if (!feof(configin)) {
208 /* Make a backup of it */
209 memcpy(orig, inbuf, sizeof(orig));
210 /* Strip trailing \n and comment */
211 inbuf[strlen(inbuf) - 1] = '\0';
212 user = strchr(inbuf, ';');
218 pass = strchr(user, '=');
221 while(*trim && *trim < 33) {
231 while(*pass && *pass < 33)
235 rest = strchr(pass,',');
242 if (user && pass && *user && *pass && !strcmp(user, vmu->mailbox) && !strcmp(pass, vmu->password)) {
243 /* This is the line */
245 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
247 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
250 /* Put it back like it was */
251 fprintf(configout, orig);
258 unlink((char *)tmpin);
259 rename((char *)tmpout,(char *)tmpin);
264 inbuf(struct baseio *bio, FILE *fi)
271 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
286 inchar(struct baseio *bio, FILE *fi)
288 if(bio->iocp>=bio->iolen)
292 return bio->iobuf[bio->iocp++];
296 ochar(struct baseio *bio, int c, FILE *so)
298 if(bio->linelength>=BASELINELEN) {
299 if(fputs(eol,so)==EOF)
305 if(putc(((unsigned char)c),so)==EOF)
313 static int base_encode(char *filename, FILE *so)
315 unsigned char dtable[BASEMAXINLINE];
320 memset(&bio, 0, sizeof(bio));
321 bio.iocp = BASEMAXINLINE;
323 if ( !(fi = fopen(filename, "rb"))) {
324 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
332 dtable[26+i+9]= 'j'+i;
336 dtable[26+i+18]= 's'+i;
345 unsigned char igroup[3],ogroup[4];
348 igroup[0]= igroup[1]= igroup[2]= 0;
351 if ( (c = inchar(&bio, fi)) == EOF) {
356 igroup[n]= (unsigned char)c;
360 ogroup[0]= dtable[igroup[0]>>2];
361 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
362 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
363 ogroup[3]= dtable[igroup[2]&0x3F];
373 ochar(&bio, ogroup[i], so);
377 if(fputs(eol,so)==EOF)
385 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
396 if (!strcmp(format, "wav49"))
398 p = popen(SENDMAIL, "w");
400 gethostname(host, sizeof(host));
401 if (strchr(srcemail, '@'))
402 strncpy(who, srcemail, sizeof(who)-1);
404 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
406 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
409 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
410 fprintf(p, "Date: %s\n", date);
411 fprintf(p, "From: Asterisk PBX <%s>\n", who);
412 fprintf(p, "To: %s <%s>\n", name, email);
413 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
414 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
415 fprintf(p, "MIME-Version: 1.0\n");
416 if (attach_voicemail) {
418 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
420 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
422 fprintf(p, "--%s\n", bound);
424 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
425 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
426 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
428 "in mailbox %s from %s, on %s so you might\n"
429 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
430 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
431 if (attach_voicemail) {
432 fprintf(p, "--%s\n", bound);
433 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
434 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
435 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
436 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
438 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
439 base_encode(fname, p);
440 fprintf(p, "\n\n--%s--\n.\n", bound);
444 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
450 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration)
459 p = popen(SENDMAIL, "w");
462 gethostname(host, sizeof(host));
463 if (strchr(srcemail, '@'))
464 strncpy(who, srcemail, sizeof(who)-1);
466 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
468 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
471 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
472 fprintf(p, "Date: %s\n", date);
473 fprintf(p, "From: Asterisk PBX <%s>\n", who);
474 fprintf(p, "To: %s\n", pager);
475 fprintf(p, "Subject: New VM\n\n");
476 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
477 fprintf(p, "New %s long msg in box %s\n"
478 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
481 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
487 static int get_date(char *s, int len)
493 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
496 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
500 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
501 if (ast_fileexists(fn, NULL, NULL) > 0) {
502 res = ast_streamfile(chan, fn, chan->language);
505 res = ast_waitstream(chan, ecodes);
509 res = ast_streamfile(chan, "vm-theperson", chan->language);
512 res = ast_waitstream(chan, ecodes);
515 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
520 res = ast_streamfile(chan, "vm-isonphone", chan->language);
522 res = ast_streamfile(chan, "vm-isunavail", chan->language);
525 res = ast_waitstream(chan, ecodes);
529 static int play_and_wait(struct ast_channel *chan, char *fn)
532 d = ast_streamfile(chan, fn, chan->language);
535 d = ast_waitstream(chan, AST_DIGIT_ANY);
539 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
543 int x, fmtcnt=1, res=-1,outmsg=0;
545 struct ast_filestream *others[MAX_OTHER_FORMATS];
546 char *sfmt[MAX_OTHER_FORMATS];
551 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
552 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
555 d = play_and_wait(chan, playfile);
557 d = ast_streamfile(chan, "beep",chan->language);
559 d = ast_waitstream(chan,"");
567 strsep(&stringp, "|");
568 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
569 sfmt[0] = strdupa(fmts);
571 while((fmt = strsep(&stringp, "|"))) {
572 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
573 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
576 sfmt[fmtcnt++] = strdupa(fmt);
581 for (x=0;x<fmtcnt;x++) {
582 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
583 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
590 /* Loop forever, writing the packets we read to the writer(s), until
591 we read a # or get a hangup */
594 res = ast_waitfor(chan, 2000);
596 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
597 /* Try one more time in case of masq */
598 res = ast_waitfor(chan, 2000);
600 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
612 if (f->frametype == AST_FRAME_VOICE) {
613 /* write each format */
614 for (x=0;x<fmtcnt;x++) {
615 res = ast_writestream(others[x], f);
617 /* Exit on any error */
619 ast_log(LOG_WARNING, "Error writing frame\n");
623 } else if (f->frametype == AST_FRAME_DTMF) {
624 if (f->subclass == '#') {
625 if (option_verbose > 2)
626 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
635 if (maxtime < (end - start)) {
636 if (option_verbose > 2)
637 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
646 if (option_verbose > 2)
647 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
652 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
655 for (x=0;x<fmtcnt;x++) {
658 ast_closestream(others[x]);
662 /* Let them know it worked */
663 ast_streamfile(chan, "vm-msgsaved", chan->language);
664 ast_waitstream(chan, "");
672 static void free_user(struct ast_vm_user *vmu)
678 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
689 char prefile[256]="";
697 /* XXX Need to be moved to play_and_record */
698 struct ast_dsp *sildet; /* silence detector dsp */
699 int totalsilence = 0;
701 int gotsilence = 0; /* did we timeout for silence? */
705 struct ast_vm_user *vmu;
706 struct ast_vm_user svm;
708 strncpy(tmp, ext, sizeof(tmp) - 1);
710 context = strchr(tmp, '@');
716 if ((vmu = find_user(&svm, context, ext))) {
717 /* Setup pre-file if appropriate */
719 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
721 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
722 make_dir(dir, sizeof(dir), vmu->context, "", "");
723 /* It's easier just to try to make it than to check for its existence */
724 if (mkdir(dir, 0700) && (errno != EEXIST))
725 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
726 make_dir(dir, sizeof(dir), vmu->context, ext, "");
727 /* It's easier just to try to make it than to check for its existence */
728 if (mkdir(dir, 0700) && (errno != EEXIST))
729 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
730 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
731 if (mkdir(dir, 0700) && (errno != EEXIST))
732 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
733 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
735 /* Play the beginning intro if desired */
736 if (strlen(prefile)) {
737 if (ast_fileexists(prefile, NULL, NULL) > 0) {
738 if (ast_streamfile(chan, prefile, chan->language) > -1)
739 res = ast_waitstream(chan, "#0");
741 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
742 res = invent_message(chan, vmu->context, ext, busy, ecodes);
745 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
751 /* On a '#' we skip the instructions */
755 if (!res && !silent) {
756 res = ast_streamfile(chan, INTRO, chan->language);
758 res = ast_waitstream(chan, ecodes);
764 /* Check for a '0' here */
766 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
767 if (strlen(chan->macrocontext))
768 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
774 /* Unless we're *really* silent, try to send the beep */
775 res = ast_streamfile(chan, "beep", chan->language);
777 res = ast_waitstream(chan, "");
783 /* The meat of recording the message... All the announcements and beeps have been played*/
784 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
788 make_file(fn, sizeof(fn), dir, msgnum);
789 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
790 (chan->callerid ? chan->callerid : "Unknown"),
791 vmu->fullname, ext, chan->name);
792 if (ast_fileexists(fn, NULL, chan->language) <= 0)
795 } while(msgnum < MAXMSG);
796 if (msgnum < MAXMSG) {
797 /* Store information */
798 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
799 txt = fopen(txtfile, "w+");
801 get_date(date, sizeof(date));
805 "; Message Information file\n"
821 chan->callerid ? chan->callerid : "Unknown",
825 ast_log(LOG_WARNING, "Error opening text file for output\n");
826 res = play_and_record(chan, NULL, fn, maxmessage, fmt);
827 txt = fopen(txtfile, "a");
830 fprintf(txt, "duration=%ld\n", end-start);
834 strsep(&stringp, "|");
835 /* Send e-mail if applicable */
836 if (strlen(vmu->email))
837 sendmail(serveremail, vmu->email, vmu->fullname, msgnum, ext, chan->callerid, fn, fmt, end - start);
838 if (strlen(vmu->pager))
839 sendpage(serveremail, vmu->pager, msgnum, ext, chan->callerid, end - start);
841 ast_log(LOG_WARNING, "No more messages possible\n");
843 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
846 sildet = ast_dsp_new(); //Create the silence detector
848 rfmt = chan->readformat;
849 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
851 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
855 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
858 ast_dsp_set_threshold(sildet, 50);
863 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
864 /* Leave voicemail for someone */
865 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
869 static char *mbox(int id)
897 static int count_messages(char *dir)
901 for (x=0;x<MAXMSG;x++) {
902 make_file(fn, sizeof(fn), dir, x);
903 if (ast_fileexists(fn, NULL, NULL) < 1)
909 static int say_and_wait(struct ast_channel *chan, int num)
912 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
916 static int copy(char *infile, char *outfile)
923 if ((ifd = open(infile, O_RDONLY)) < 0) {
924 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
927 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
928 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
933 len = read(ifd, buf, sizeof(buf));
935 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
941 res = write(ofd, buf, len);
943 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
955 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
962 char *dbox = mbox(box);
964 make_file(sfn, sizeof(sfn), dir, msg);
965 make_dir(ddir, sizeof(ddir), context, username, dbox);
967 for (x=0;x<MAXMSG;x++) {
968 make_file(dfn, sizeof(dfn), ddir, x);
969 if (ast_fileexists(dfn, NULL, NULL) < 0)
974 ast_filecopy(sfn, dfn, NULL);
975 if (strcmp(sfn, dfn)) {
976 snprintf(txt, sizeof(txt), "%s.txt", sfn);
977 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
983 static int adsi_logo(unsigned char *buf)
986 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
987 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
991 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
999 bytes += adsi_data_mode(buf + bytes);
1000 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1003 bytes += adsi_logo(buf);
1004 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1006 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1008 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1009 bytes += adsi_data_mode(buf + bytes);
1010 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1012 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1014 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1015 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1016 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1017 bytes += adsi_voice_mode(buf + bytes, 0);
1018 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1025 bytes += adsi_logo(buf);
1026 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1027 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1028 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1029 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1032 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1033 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1034 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1035 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
1036 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1037 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1038 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1041 /* Add another dot */
1043 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1044 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1045 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1049 /* These buttons we load but don't use yet */
1050 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1051 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1052 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1053 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1054 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1055 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1056 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1059 /* Add another dot */
1061 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1062 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1063 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1068 snprintf(num, sizeof(num), "%d", x);
1069 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1071 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1072 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1075 /* Add another dot */
1077 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1078 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1079 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1082 if (adsi_end_download(chan)) {
1084 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1085 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1086 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1087 bytes += adsi_voice_mode(buf + bytes, 0);
1088 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1092 bytes += adsi_download_disconnect(buf + bytes);
1093 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1095 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1100 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1101 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1103 ast_log(LOG_DEBUG, "Restarting session...\n");
1106 /* Load the session now */
1107 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1109 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1111 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1113 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1117 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1120 if (!adsi_available(chan))
1122 x = adsi_load_session(chan, adapp, adver, 1);
1126 if (adsi_load_vmail(chan, useadsi)) {
1127 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1134 static void adsi_login(struct ast_channel *chan)
1138 unsigned char keys[8];
1140 if (!adsi_available(chan))
1145 /* Set one key for next */
1146 keys[3] = ADSI_KEY_APPS + 3;
1148 bytes += adsi_logo(buf + bytes);
1149 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1150 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1151 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1152 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1153 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1154 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1155 bytes += adsi_set_keys(buf + bytes, keys);
1156 bytes += adsi_voice_mode(buf + bytes, 0);
1157 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1160 static void adsi_password(struct ast_channel *chan)
1164 unsigned char keys[8];
1166 if (!adsi_available(chan))
1171 /* Set one key for next */
1172 keys[3] = ADSI_KEY_APPS + 3;
1174 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1175 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1176 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1177 bytes += adsi_set_keys(buf + bytes, keys);
1178 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1181 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1185 unsigned char keys[8];
1188 if (!adsi_available(chan))
1192 y = ADSI_KEY_APPS + 12 + start + x;
1193 if (y > ADSI_KEY_APPS + 12 + 4)
1195 keys[x] = ADSI_KEY_SKT | y;
1197 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1201 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1202 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1203 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1204 bytes += adsi_set_keys(buf + bytes, keys);
1205 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1208 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1211 char buf[256], buf1[256], buf2[256];
1216 char datetime[21]="";
1219 unsigned char keys[8];
1223 if (!adsi_available(chan))
1226 /* Retrieve important info */
1227 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1228 f = fopen(fn2, "r");
1231 fgets(buf, sizeof(buf), f);
1235 strsep(&stringp, "=");
1236 val = strsep(&stringp, "=");
1237 if (val && strlen(val)) {
1238 if (!strcmp(buf, "callerid"))
1239 strncpy(cid, val, sizeof(cid) - 1);
1240 if (!strcmp(buf, "origdate"))
1241 strncpy(datetime, val, sizeof(datetime) - 1);
1247 /* New meaning for keys */
1249 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1254 /* No prev key, provide "Folder" instead */
1255 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1258 /* If last message ... */
1260 /* but not only message, provide "Folder" instead */
1261 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1263 /* Otherwise if only message, leave blank */
1269 ast_callerid_parse(cid, &name, &num);
1273 name = "Unknown Caller";
1275 /* If deleted, show "undeleted" */
1277 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1280 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1281 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1282 strcasecmp(folder, "INBOX") ? " Messages" : "");
1283 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1285 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1286 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1287 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1288 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1289 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1290 bytes += adsi_set_keys(buf + bytes, keys);
1291 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1294 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1298 unsigned char keys[8];
1302 if (!adsi_available(chan))
1305 /* New meaning for keys */
1307 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1313 /* No prev key, provide "Folder" instead */
1314 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1317 /* If last message ... */
1319 /* but not only message, provide "Folder" instead */
1320 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1322 /* Otherwise if only message, leave blank */
1327 /* If deleted, show "undeleted" */
1329 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1332 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1333 bytes += adsi_set_keys(buf + bytes, keys);
1334 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1337 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1339 char buf[256], buf1[256], buf2[256];
1341 unsigned char keys[8];
1344 char *newm = (new == 1) ? "message" : "messages";
1345 char *oldm = (old == 1) ? "message" : "messages";
1346 if (!adsi_available(chan))
1349 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1351 strcat(buf1, " and");
1352 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1354 snprintf(buf2, sizeof(buf2), "%s.", newm);
1357 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1358 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1360 strcpy(buf1, "You have no messages.");
1363 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1364 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1365 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1368 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1372 /* Don't let them listen if there are none */
1375 bytes += adsi_set_keys(buf + bytes, keys);
1377 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1380 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1382 char buf[256], buf1[256], buf2[256];
1384 unsigned char keys[8];
1387 char *mess = (messages == 1) ? "message" : "messages";
1389 if (!adsi_available(chan))
1392 /* Original command keys */
1394 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1402 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1403 strcasecmp(folder, "INBOX") ? " folder" : "");
1406 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1408 strcpy(buf2, "no messages.");
1409 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1410 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1411 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1412 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1413 bytes += adsi_set_keys(buf + bytes, keys);
1415 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1419 static void adsi_clear(struct ast_channel *chan)
1423 if (!adsi_available(chan))
1425 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1426 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1429 static void adsi_goodbye(struct ast_channel *chan)
1434 if (!adsi_available(chan))
1436 bytes += adsi_logo(buf + bytes);
1437 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1438 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1439 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1440 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1443 static int get_folder(struct ast_channel *chan, int start)
1448 d = play_and_wait(chan, "vm-press");
1451 for (x = start; x< 5; x++) {
1452 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1454 d = play_and_wait(chan, "vm-for");
1457 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1458 d = play_and_wait(chan, fn);
1461 d = play_and_wait(chan, "vm-messages");
1464 d = ast_waitfordigit(chan, 500);
1468 d = play_and_wait(chan, "vm-tocancel");
1471 d = ast_waitfordigit(chan, 4000);
1475 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1478 res = play_and_wait(chan, fn);
1479 while (((res < '0') || (res > '9')) &&
1480 (res != '#') && (res >= 0)) {
1481 res = get_folder(chan, 0);
1487 forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
1494 struct ast_config *mif;
1499 struct ast_vm_user *receiver, srec;
1504 res = ast_streamfile(chan, "vm-extension", chan->language);
1507 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1509 if ((receiver = find_user(&srec, context, username))) {
1510 printf("Got %d\n", atoi(username));
1511 /* if (play_and_wait(chan, "vm-savedto"))
1515 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, receiver->context, username);
1516 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1517 ast_log(LOG_DEBUG, sys);
1520 todircount = count_messages(todir);
1521 strncpy(tmp, fmt, sizeof(tmp));
1523 while((s = strsep(&stringp, "|"))) {
1524 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
1525 ast_log(LOG_DEBUG, sys);
1528 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1530 /* load the information on the source message so we can send an e-mail like a new message */
1531 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1532 if ((mif=ast_load(miffile))) {
1534 /* set callerid and duration variables */
1535 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
1536 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1538 if (strlen(receiver->email))
1539 sendmail(serveremail, receiver->email, receiver->fullname, todircount, username, callerid, fn, tmp, atol(ast_variable_retrieve(mif, NULL, "duration")));
1541 if (strlen(receiver->pager))
1542 sendpage(serveremail, receiver->pager, todircount, username, callerid, duration);
1544 ast_destroy(mif); /* or here */
1547 /* give confirmatopm that the message was saved */
1548 res = play_and_wait(chan, "vm-message");
1550 res = play_and_wait(chan, "vm-saved");
1551 free_user(receiver);
1554 res = play_and_wait(chan, "pbx-invalid");
1567 int deleted[MAXMSG];
1578 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1581 if ((res = ast_streamfile(chan, file, chan->language)))
1582 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1584 res = ast_waitstream(chan, AST_DIGIT_ANY);
1588 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
1591 if ((res = ast_streamfile(chan, file, chan->language)))
1592 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1594 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
1598 static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg)
1602 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1603 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
1605 res = wait_file2(chan, vms, "vm-first");
1606 else if (msg == vms->lastmsg)
1607 res = wait_file2(chan, vms, "vm-last");
1609 res = wait_file2(chan, vms, "vm-message");
1610 if (msg && (msg != vms->lastmsg)) {
1612 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
1617 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1618 vms->heard[msg] = 1;
1619 res = wait_file(chan, vms, vms->fn);
1624 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
1626 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
1627 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
1628 vms->lastmsg = count_messages(vms->curdir) - 1;
1629 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
1632 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
1635 char ntxt[256] = "";
1637 if (vms->lastmsg > -1) {
1638 /* Get the deleted messages fixed */
1640 for (x=0;x<=vms->lastmsg;x++) {
1641 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
1642 /* Save this message. It's not in INBOX or hasn't been heard */
1644 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1645 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
1646 if (strcmp(vms->fn, vms->fn2)) {
1647 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1648 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
1649 ast_filerename(vms->fn, vms->fn2, NULL);
1652 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
1653 /* Move to old folder before deleting */
1654 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
1657 for (x = vms->curmsg + 1; x<=vms->lastmsg; x++) {
1658 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1659 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1660 ast_filedelete(vms->fn, NULL);
1664 memset(vms->deleted, 0, sizeof(vms->deleted));
1665 memset(vms->heard, 0, sizeof(vms->heard));
1668 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
1670 /* Introduce messages they have */
1672 res = play_and_wait(chan, "vm-youhave");
1674 if (vms->newmessages) {
1675 res = say_and_wait(chan, vms->newmessages);
1677 res = play_and_wait(chan, "vm-INBOX");
1678 if (vms->oldmessages && !res)
1679 res = play_and_wait(chan, "vm-and");
1681 if ((vms->newmessages == 1))
1682 res = play_and_wait(chan, "vm-message");
1684 res = play_and_wait(chan, "vm-messages");
1688 if (!res && vms->oldmessages) {
1689 res = say_and_wait(chan, vms->oldmessages);
1691 res = play_and_wait(chan, "vm-Old");
1693 if (vms->oldmessages == 1)
1694 res = play_and_wait(chan, "vm-message");
1696 res = play_and_wait(chan, "vm-messages");
1700 if (!vms->oldmessages && !vms->newmessages) {
1701 res = play_and_wait(chan, "vm-no");
1703 res = play_and_wait(chan, "vm-messages");
1710 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
1713 /* Play instructions and wait for new command */
1715 if (vms->starting) {
1716 if (vms->lastmsg > -1) {
1717 res = play_and_wait(chan, "vm-onefor");
1719 res = play_and_wait(chan, vms->vmbox);
1721 res = play_and_wait(chan, "vm-messages");
1724 res = play_and_wait(chan, "vm-opts");
1727 res = play_and_wait(chan, "vm-prev");
1729 res = play_and_wait(chan, "vm-repeat");
1730 if (!res && (vms->curmsg != vms->lastmsg))
1731 res = play_and_wait(chan, "vm-next");
1733 if (!vms->deleted[vms->curmsg])
1734 res = play_and_wait(chan, "vm-delete");
1736 res = play_and_wait(chan, "vm-undelete");
1738 res = play_and_wait(chan, "vm-toforward");
1740 res = play_and_wait(chan, "vm-savemessage");
1744 res = play_and_wait(chan, "vm-helpexit");
1746 res = ast_waitfordigit(chan, 6000);
1749 if (vms->repeats > 2) {
1750 res = play_and_wait(chan, "vm-goodbye");
1759 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
1763 char newpassword[80] = "";
1764 char newpassword2[80] = "";
1765 char prefile[256]="";
1766 while((cmd >= 0) && (cmd != 't')) {
1771 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
1772 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
1775 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
1776 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
1779 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
1780 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
1783 newpassword[1] = '\0';
1784 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
1787 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
1790 newpassword2[1] = '\0';
1791 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
1795 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
1798 if (strcmp(newpassword, newpassword2)) {
1799 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
1800 cmd = play_and_wait(chan, "vm-mismatch");
1803 if (vm_change_password(vmu,newpassword) < 0)
1805 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",vms->username);
1807 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
1808 cmd = play_and_wait(chan,"vm-passchanged");
1814 cmd = play_and_wait(chan,"vm-options");
1816 cmd = ast_waitfordigit(chan,6000);
1828 static int vm_execmain(struct ast_channel *chan, void *data)
1830 /* XXX This is, admittedly, some pretty horrendus code. For some
1831 reason it just seemed a lot easier to do with GOTO's. I feel
1832 like I'm back in my GWBASIC days. XXX */
1837 struct localuser *u;
1838 char prefixstr[80] ="";
1839 char empty[80] = "";
1843 char tmp[256], *ext;
1844 char fmtc[256] = "";
1846 struct vm_state vms;
1848 struct ast_vm_user *vmu = NULL, vmus;
1852 memset(&vms, 0, sizeof(vms));
1853 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
1854 if (chan->_state != AST_STATE_UP)
1857 if (data && strlen(data)) {
1858 strncpy(tmp, data, sizeof(tmp) - 1);
1863 /* We should skip the user's password */
1868 /* We should prefix the mailbox with the supplied data */
1874 context = strchr(ext, '@');
1881 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1883 strncpy(vms.username, ext, sizeof(vms.username) - 1);
1884 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
1891 /* If ADSI is supported, setup login screen */
1892 adsi_begin(chan, &useadsi);
1893 if (!skipuser && useadsi)
1895 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1896 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1900 /* Authenticate them and get their mailbox/password */
1902 while (!valid && (logretries < maxlogins)) {
1903 /* Prompt for, and read in the username */
1904 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
1905 ast_log(LOG_WARNING, "Couldn't read username\n");
1908 if (!strlen(vms.username)) {
1909 if (option_verbose > 2)
1910 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1915 adsi_password(chan);
1916 if (ast_streamfile(chan, "vm-password", chan->language)) {
1917 ast_log(LOG_WARNING, "Unable to stream password file\n");
1920 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1921 ast_log(LOG_WARNING, "Unable to read password\n");
1925 char fullusername[80] = "";
1926 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1927 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
1928 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
1931 vmu = find_user(&vmus, context, vms.username);
1932 if (vmu && !strcmp(vmu->password, password))
1935 if (option_verbose > 2)
1936 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
1938 strncpy(vms.username, empty, sizeof(vms.username) -1);
1943 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1948 if (logretries >= maxlogins) {
1949 ast_stopstream(chan);
1950 res = play_and_wait(chan, "vm-goodbye");
1956 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
1957 mkdir(vms.curdir, 0700);
1958 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
1959 mkdir(vms.curdir, 0700);
1960 /* Retrieve old and new message counts */
1961 open_mailbox(&vms, vmu, 1);
1962 vms.oldmessages = vms.lastmsg + 1;
1963 /* Start in INBOX */
1964 open_mailbox(&vms, vmu, 0);
1965 vms.newmessages = vms.lastmsg + 1;
1968 /* Select proper mailbox FIRST!! */
1969 if (!vms.newmessages && vms.oldmessages) {
1970 /* If we only have old messages start here */
1971 open_mailbox(&vms, vmu, 1);
1975 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
1977 cmd = vm_intro(chan, &vms);
1980 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
1987 if (vms.lastmsg > -1) {
1988 cmd = play_message(chan, &vms, vms.curmsg);
1990 cmd = play_and_wait(chan, "vm-youhave");
1992 cmd = play_and_wait(chan, "vm-no");
1994 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
1995 cmd = play_and_wait(chan, vms.fn);
1998 cmd = play_and_wait(chan, "vm-messages");
2001 case '2': /* Change folders */
2003 adsi_folders(chan, 0, "Change to folder...");
2004 cmd = get_folder2(chan, "vm-changeto", 0);
2007 } else if (cmd > 0) {
2009 close_mailbox(&vms, vmu);
2010 open_mailbox(&vms, vmu, cmd);
2014 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2016 cmd = play_and_wait(chan, vms.vmbox);
2018 cmd = play_and_wait(chan, "vm-messages");
2024 cmd = play_message(chan, &vms, vms.curmsg);
2026 cmd = play_and_wait(chan, "vm-nomore");
2030 if (vms.curmsg < vms.lastmsg) {
2032 cmd = play_message(chan, &vms, vms.curmsg);
2034 cmd = play_and_wait(chan, "vm-nomore");
2038 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2040 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2041 if (vms.deleted[vms.curmsg])
2042 cmd = play_and_wait(chan, "vm-deleted");
2044 cmd = play_and_wait(chan, "vm-undeleted");
2047 if(vms.lastmsg > -1)
2048 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2052 adsi_folders(chan, 1, "Save to folder...");
2053 cmd = get_folder2(chan, "vm-savefolder", 1);
2054 box = 0; /* Shut up compiler */
2058 } else if (cmd > 0) {
2059 box = cmd = cmd - '0';
2060 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2061 vms.deleted[vms.curmsg]=1;
2063 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2065 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2067 cmd = play_and_wait(chan, "vm-message");
2069 cmd = say_and_wait(chan, vms.curmsg + 1);
2071 cmd = play_and_wait(chan, "vm-savedto");
2073 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2074 cmd = play_and_wait(chan, vms.fn);
2077 cmd = play_and_wait(chan, "vm-messages");
2080 if (!vms.starting) {
2081 cmd = play_and_wait(chan, "vm-onefor");
2083 cmd = play_and_wait(chan, vms.vmbox);
2085 cmd = play_and_wait(chan, "vm-messages");
2087 cmd = play_and_wait(chan, "vm-opts");
2092 cmd = vm_options(chan, vmu, &vms, vmfmts);
2095 ast_stopstream(chan);
2097 cmd = play_and_wait(chan, "vm-goodbye");
2101 default: /* Nothing */
2102 cmd = vm_instructions(chan, &vms);
2106 if ((cmd == 't') || (cmd == '#')) {
2116 ast_stopstream(chan);
2119 adsi_unload_session(chan);
2122 close_mailbox(&vms, vmu);
2126 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2128 LOCAL_USER_REMOVE(u);
2133 static int vm_exec(struct ast_channel *chan, void *data)
2135 int res=0, silent=0, busy=0, unavail=0;
2136 struct localuser *u;
2137 char tmp[256], *ext;
2140 if (chan->_state != AST_STATE_UP)
2143 strncpy(tmp, data, sizeof(tmp) - 1);
2145 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2156 } else if (*ext == 'b') {
2159 } else if (*ext == 'u') {
2165 res = leave_voicemail(chan, ext, silent, busy, unavail);
2166 LOCAL_USER_REMOVE(u);
2170 static int append_mailbox(char *context, char *mbox, char *data)
2172 /* Assumes lock is already held */
2176 struct ast_vm_user *vmu;
2177 strncpy(tmp, data, sizeof(tmp));
2178 vmu = malloc(sizeof(struct ast_vm_user));
2180 memset(vmu, 0, sizeof(struct ast_vm_user));
2181 strncpy(vmu->context, context, sizeof(vmu->context));
2182 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2184 if ((s = strsep(&stringp, ",")))
2185 strncpy(vmu->password, s, sizeof(vmu->password));
2186 if ((s = strsep(&stringp, ",")))
2187 strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2188 if ((s = strsep(&stringp, ",")))
2189 strncpy(vmu->email, s, sizeof(vmu->email));
2190 if ((s = strsep(&stringp, ",")))
2191 strncpy(vmu->pager, s, sizeof(vmu->pager));
2202 static int load_users(void)
2204 struct ast_vm_user *cur, *l;
2205 struct ast_config *cfg;
2207 struct ast_variable *var;
2215 cfg = ast_load(VOICEMAIL_CONFIG);
2216 ast_pthread_mutex_lock(&vmlock);
2226 /* General settings */
2227 attach_voicemail = 1;
2228 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
2230 attach_voicemail = ast_true(astattach);
2232 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2233 maxsilence = atoi(silencestr);
2238 silencethreshold = 256;
2239 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2240 silencethreshold = atoi(thresholdstr);
2242 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
2243 astemail = ASTERISK_USERNAME;
2244 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2247 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2248 if (sscanf(s, "%d", &x) == 1) {
2251 ast_log(LOG_WARNING, "Invalid max message time length\n");
2254 fmt = ast_variable_retrieve(cfg, "general", "format");
2257 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2260 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2261 if (sscanf(s, "%d", &x) == 1) {
2264 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2268 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2269 if (sscanf(s, "%d", &x) == 1) {
2272 ast_log(LOG_WARNING, "Invalid skipms value\n");
2277 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
2278 if (sscanf(s, "%d", &x) == 1) {
2281 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
2285 cat = ast_category_browse(cfg, NULL);
2287 if (strcasecmp(cat, "general")) {
2288 /* Process mailboxes in this context */
2289 var = ast_variable_browse(cfg, cat);
2291 append_mailbox(cat, var->name, var->value);
2295 cat = ast_category_browse(cfg, cat);
2299 ast_pthread_mutex_unlock(&vmlock);
2309 int unload_module(void)
2312 STANDARD_HANGUP_LOCALUSERS;
2313 res = ast_unregister_application(app);
2314 res |= ast_unregister_application(app2);
2318 int load_module(void)
2322 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2324 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2328 char *description(void)
2336 STANDARD_USECOUNT(res);
2342 return ASTERISK_GPL_KEY;