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;
144 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
146 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
149 static int make_file(char *dest, int len, char *dir, int num)
151 return snprintf(dest, len, "%s/msg%04d", dir, num);
154 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
156 /* This function could be made to generate one from a database, too */
157 struct ast_vm_user *vmu=NULL, *cur;
158 ast_pthread_mutex_lock(&vmlock);
161 if ((!context || !strcasecmp(context, cur->context)) &&
162 (!strcasecmp(mailbox, cur->mailbox)))
170 /* Make a copy, so that on a reload, we have no race */
171 vmu = malloc(sizeof(struct ast_vm_user));
173 memcpy(vmu, cur, sizeof(struct ast_vm_user));
181 ast_pthread_mutex_unlock(&vmlock);
185 static int vm_change_password(struct ast_vm_user *vmu, char *newpassword)
187 /* There's probably a better way of doing this. */
188 /* That's why I've put the password change in a separate function. */
189 /* This could also be done with a database function */
195 char tmpin[AST_CONFIG_MAX_PATH];
196 char tmpout[AST_CONFIG_MAX_PATH];
197 char *user, *pass, *rest, *trim;
198 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
199 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
200 configin = fopen((char *)tmpin,"r");
201 configout = fopen((char *)tmpout,"w+");
203 while (!feof(configin)) {
204 /* Read in the line */
205 fgets(inbuf, sizeof(inbuf), configin);
206 if (!feof(configin)) {
207 /* Make a backup of it */
208 memcpy(orig, inbuf, sizeof(orig));
209 /* Strip trailing \n and comment */
210 inbuf[strlen(inbuf) - 1] = '\0';
211 user = strchr(inbuf, ';');
217 pass = strchr(user, '=');
220 while(*trim && *trim < 33) {
230 while(*pass && *pass < 33)
234 rest = strchr(pass,',');
241 if (user && pass && *user && *pass && !strcmp(user, vmu->mailbox) && !strcmp(pass, vmu->password)) {
242 /* This is the line */
244 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
246 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
249 /* Put it back like it was */
250 fprintf(configout, orig);
257 unlink((char *)tmpin);
258 rename((char *)tmpout,(char *)tmpin);
263 inbuf(struct baseio *bio, FILE *fi)
270 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
285 inchar(struct baseio *bio, FILE *fi)
287 if(bio->iocp>=bio->iolen)
291 return bio->iobuf[bio->iocp++];
295 ochar(struct baseio *bio, int c, FILE *so)
297 if(bio->linelength>=BASELINELEN) {
298 if(fputs(eol,so)==EOF)
304 if(putc(((unsigned char)c),so)==EOF)
312 static int base_encode(char *filename, FILE *so)
314 unsigned char dtable[BASEMAXINLINE];
319 memset(&bio, 0, sizeof(bio));
320 bio.iocp = BASEMAXINLINE;
322 if ( !(fi = fopen(filename, "rb"))) {
323 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
331 dtable[26+i+9]= 'j'+i;
335 dtable[26+i+18]= 's'+i;
344 unsigned char igroup[3],ogroup[4];
347 igroup[0]= igroup[1]= igroup[2]= 0;
350 if ( (c = inchar(&bio, fi)) == EOF) {
355 igroup[n]= (unsigned char)c;
359 ogroup[0]= dtable[igroup[0]>>2];
360 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
361 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
362 ogroup[3]= dtable[igroup[2]&0x3F];
372 ochar(&bio, ogroup[i], so);
376 if(fputs(eol,so)==EOF)
384 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
395 if (!strcmp(format, "wav49"))
397 p = popen(SENDMAIL, "w");
399 gethostname(host, sizeof(host));
400 if (strchr(srcemail, '@'))
401 strncpy(who, srcemail, sizeof(who)-1);
403 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
405 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
408 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
409 fprintf(p, "Date: %s\n", date);
410 fprintf(p, "From: Asterisk PBX <%s>\n", who);
411 fprintf(p, "To: %s <%s>\n", name, email);
412 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
413 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
414 fprintf(p, "MIME-Version: 1.0\n");
415 if (attach_voicemail) {
417 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
419 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
421 fprintf(p, "--%s\n", bound);
423 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
424 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
425 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
427 "in mailbox %s from %s, on %s so you might\n"
428 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
429 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
430 if (attach_voicemail) {
431 fprintf(p, "--%s\n", bound);
432 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
433 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
434 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
435 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
437 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
438 base_encode(fname, p);
439 fprintf(p, "\n\n--%s--\n.\n", bound);
443 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
449 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration)
458 p = popen(SENDMAIL, "w");
461 gethostname(host, sizeof(host));
462 if (strchr(srcemail, '@'))
463 strncpy(who, srcemail, sizeof(who)-1);
465 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
467 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
470 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
471 fprintf(p, "Date: %s\n", date);
472 fprintf(p, "From: Asterisk PBX <%s>\n", who);
473 fprintf(p, "To: %s\n", pager);
474 fprintf(p, "Subject: New VM\n\n");
475 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
476 fprintf(p, "New %s long msg in box %s\n"
477 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
480 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
486 static int get_date(char *s, int len)
492 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
495 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
499 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
500 if (ast_fileexists(fn, NULL, NULL) > 0) {
501 res = ast_streamfile(chan, fn, chan->language);
504 res = ast_waitstream(chan, ecodes);
508 res = ast_streamfile(chan, "vm-theperson", chan->language);
511 res = ast_waitstream(chan, ecodes);
514 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
519 res = ast_streamfile(chan, "vm-isonphone", chan->language);
521 res = ast_streamfile(chan, "vm-isunavail", chan->language);
524 res = ast_waitstream(chan, ecodes);
528 static int play_and_wait(struct ast_channel *chan, char *fn)
531 d = ast_streamfile(chan, fn, chan->language);
534 d = ast_waitstream(chan, AST_DIGIT_ANY);
538 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
542 int x, fmtcnt=1, res=-1,outmsg=0;
544 struct ast_filestream *others[MAX_OTHER_FORMATS];
545 char *sfmt[MAX_OTHER_FORMATS];
550 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
551 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
554 d = play_and_wait(chan, playfile);
556 d = ast_streamfile(chan, "beep",chan->language);
558 d = ast_waitstream(chan,"");
566 strsep(&stringp, "|");
567 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
568 sfmt[0] = strdupa(fmts);
570 while((fmt = strsep(&stringp, "|"))) {
571 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
572 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
575 sfmt[fmtcnt++] = strdupa(fmt);
580 for (x=0;x<fmtcnt;x++) {
581 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
582 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
589 /* Loop forever, writing the packets we read to the writer(s), until
590 we read a # or get a hangup */
593 res = ast_waitfor(chan, 2000);
595 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
596 /* Try one more time in case of masq */
597 res = ast_waitfor(chan, 2000);
599 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
611 if (f->frametype == AST_FRAME_VOICE) {
612 /* write each format */
613 for (x=0;x<fmtcnt;x++) {
614 res = ast_writestream(others[x], f);
616 /* Exit on any error */
618 ast_log(LOG_WARNING, "Error writing frame\n");
622 } else if (f->frametype == AST_FRAME_DTMF) {
623 if (f->subclass == '#') {
624 if (option_verbose > 2)
625 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
634 if (maxtime < (end - start)) {
635 if (option_verbose > 2)
636 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
645 if (option_verbose > 2)
646 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
651 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
654 for (x=0;x<fmtcnt;x++) {
657 ast_closestream(others[x]);
661 /* Let them know it worked */
662 ast_streamfile(chan, "vm-msgsaved", chan->language);
663 ast_waitstream(chan, "");
671 static void free_user(struct ast_vm_user *vmu)
677 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
688 char prefile[256]="";
696 /* XXX Need to be moved to play_and_record */
697 struct ast_dsp *sildet; /* silence detector dsp */
698 int totalsilence = 0;
700 int gotsilence = 0; /* did we timeout for silence? */
704 struct ast_vm_user *vmu;
705 struct ast_vm_user svm;
707 strncpy(tmp, ext, sizeof(tmp) - 1);
709 context = strchr(tmp, '@');
715 if ((vmu = find_user(&svm, context, ext))) {
716 /* Setup pre-file if appropriate */
718 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
720 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
721 make_dir(dir, sizeof(dir), vmu->context, "", "");
722 /* It's easier just to try to make it than to check for its existence */
723 if (mkdir(dir, 0700) && (errno != EEXIST))
724 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
725 make_dir(dir, sizeof(dir), vmu->context, ext, "");
726 /* It's easier just to try to make it than to check for its existence */
727 if (mkdir(dir, 0700) && (errno != EEXIST))
728 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
729 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
730 if (mkdir(dir, 0700) && (errno != EEXIST))
731 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
732 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
734 /* Play the beginning intro if desired */
735 if (strlen(prefile)) {
736 if (ast_fileexists(prefile, NULL, NULL) > 0) {
737 if (ast_streamfile(chan, prefile, chan->language) > -1)
738 res = ast_waitstream(chan, "#0");
740 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
741 res = invent_message(chan, vmu->context, ext, busy, ecodes);
744 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
750 /* On a '#' we skip the instructions */
754 if (!res && !silent) {
755 res = ast_streamfile(chan, INTRO, chan->language);
757 res = ast_waitstream(chan, ecodes);
763 /* Check for a '0' here */
765 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
766 if (strlen(chan->macrocontext))
767 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
772 if (!res && (silent < 2)) {
773 /* Unless we're *really* silent, try to send the beep */
774 res = ast_streamfile(chan, "beep", chan->language);
776 res = ast_waitstream(chan, "");
782 /* The meat of recording the message... All the announcements and beeps have been played*/
783 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
787 make_file(fn, sizeof(fn), dir, msgnum);
788 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
789 (chan->callerid ? chan->callerid : "Unknown"),
790 vmu->fullname, ext, chan->name);
791 if (ast_fileexists(fn, NULL, chan->language) <= 0)
794 } while(msgnum < MAXMSG);
795 if (msgnum < MAXMSG) {
796 /* Store information */
797 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
798 txt = fopen(txtfile, "w+");
800 get_date(date, sizeof(date));
804 "; Message Information file\n"
820 chan->callerid ? chan->callerid : "Unknown",
824 ast_log(LOG_WARNING, "Error opening text file for output\n");
825 res = play_and_record(chan, NULL, fn, maxmessage, fmt);
826 txt = fopen(txtfile, "a");
829 fprintf(txt, "duration=%ld\n", end-start);
833 strsep(&stringp, "|");
834 /* Send e-mail if applicable */
835 if (strlen(vmu->email))
836 sendmail(serveremail, vmu->email, vmu->fullname, msgnum, ext, chan->callerid, fn, fmt, end - start);
837 if (strlen(vmu->pager))
838 sendpage(serveremail, vmu->pager, msgnum, ext, chan->callerid, end - start);
840 ast_log(LOG_WARNING, "No more messages possible\n");
842 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
845 sildet = ast_dsp_new(); //Create the silence detector
847 rfmt = chan->readformat;
848 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
850 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
854 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
857 ast_dsp_set_threshold(sildet, 50);
862 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
863 /* Leave voicemail for someone */
864 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
868 static char *mbox(int id)
896 static int count_messages(char *dir)
900 for (x=0;x<MAXMSG;x++) {
901 make_file(fn, sizeof(fn), dir, x);
902 if (ast_fileexists(fn, NULL, NULL) < 1)
908 static int say_and_wait(struct ast_channel *chan, int num)
911 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
915 static int copy(char *infile, char *outfile)
922 if ((ifd = open(infile, O_RDONLY)) < 0) {
923 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
926 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
927 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
932 len = read(ifd, buf, sizeof(buf));
934 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
940 res = write(ofd, buf, len);
942 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
954 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
961 char *dbox = mbox(box);
963 make_file(sfn, sizeof(sfn), dir, msg);
964 make_dir(ddir, sizeof(ddir), context, username, dbox);
966 for (x=0;x<MAXMSG;x++) {
967 make_file(dfn, sizeof(dfn), ddir, x);
968 if (ast_fileexists(dfn, NULL, NULL) < 0)
973 ast_filecopy(sfn, dfn, NULL);
974 if (strcmp(sfn, dfn)) {
975 snprintf(txt, sizeof(txt), "%s.txt", sfn);
976 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
982 static int adsi_logo(unsigned char *buf)
985 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
986 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
990 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
998 bytes += adsi_data_mode(buf + bytes);
999 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1002 bytes += adsi_logo(buf);
1003 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1005 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1007 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1008 bytes += adsi_data_mode(buf + bytes);
1009 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1011 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1013 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1014 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1015 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1016 bytes += adsi_voice_mode(buf + bytes, 0);
1017 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1024 bytes += adsi_logo(buf);
1025 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1026 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1027 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1028 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1031 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1032 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1033 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1034 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
1035 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1036 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1037 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1040 /* Add another dot */
1042 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1043 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1044 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1048 /* These buttons we load but don't use yet */
1049 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1050 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1051 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1052 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1053 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1054 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1055 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1058 /* Add another dot */
1060 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1061 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1062 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1067 snprintf(num, sizeof(num), "%d", x);
1068 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1070 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1071 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1074 /* Add another dot */
1076 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1077 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1078 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1081 if (adsi_end_download(chan)) {
1083 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1084 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1085 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1086 bytes += adsi_voice_mode(buf + bytes, 0);
1087 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1091 bytes += adsi_download_disconnect(buf + bytes);
1092 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1094 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1099 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1100 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1102 ast_log(LOG_DEBUG, "Restarting session...\n");
1105 /* Load the session now */
1106 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1108 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1110 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1112 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1116 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1119 if (!adsi_available(chan))
1121 x = adsi_load_session(chan, adapp, adver, 1);
1125 if (adsi_load_vmail(chan, useadsi)) {
1126 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1133 static void adsi_login(struct ast_channel *chan)
1137 unsigned char keys[8];
1139 if (!adsi_available(chan))
1144 /* Set one key for next */
1145 keys[3] = ADSI_KEY_APPS + 3;
1147 bytes += adsi_logo(buf + bytes);
1148 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1149 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1150 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1151 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1152 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1153 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1154 bytes += adsi_set_keys(buf + bytes, keys);
1155 bytes += adsi_voice_mode(buf + bytes, 0);
1156 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1159 static void adsi_password(struct ast_channel *chan)
1163 unsigned char keys[8];
1165 if (!adsi_available(chan))
1170 /* Set one key for next */
1171 keys[3] = ADSI_KEY_APPS + 3;
1173 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1174 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1175 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1176 bytes += adsi_set_keys(buf + bytes, keys);
1177 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1180 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1184 unsigned char keys[8];
1187 if (!adsi_available(chan))
1191 y = ADSI_KEY_APPS + 12 + start + x;
1192 if (y > ADSI_KEY_APPS + 12 + 4)
1194 keys[x] = ADSI_KEY_SKT | y;
1196 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1200 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1201 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1202 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1203 bytes += adsi_set_keys(buf + bytes, keys);
1204 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1207 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1210 char buf[256], buf1[256], buf2[256];
1215 char datetime[21]="";
1218 unsigned char keys[8];
1222 if (!adsi_available(chan))
1225 /* Retrieve important info */
1226 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1227 f = fopen(fn2, "r");
1230 fgets(buf, sizeof(buf), f);
1234 strsep(&stringp, "=");
1235 val = strsep(&stringp, "=");
1236 if (val && strlen(val)) {
1237 if (!strcmp(buf, "callerid"))
1238 strncpy(cid, val, sizeof(cid) - 1);
1239 if (!strcmp(buf, "origdate"))
1240 strncpy(datetime, val, sizeof(datetime) - 1);
1246 /* New meaning for keys */
1248 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1253 /* No prev key, provide "Folder" instead */
1254 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1257 /* If last message ... */
1259 /* but not only message, provide "Folder" instead */
1260 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1262 /* Otherwise if only message, leave blank */
1268 ast_callerid_parse(cid, &name, &num);
1272 name = "Unknown Caller";
1274 /* If deleted, show "undeleted" */
1276 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1279 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1280 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1281 strcasecmp(folder, "INBOX") ? " Messages" : "");
1282 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1284 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1285 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1286 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1287 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1288 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1289 bytes += adsi_set_keys(buf + bytes, keys);
1290 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1293 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1297 unsigned char keys[8];
1301 if (!adsi_available(chan))
1304 /* New meaning for keys */
1306 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1312 /* No prev key, provide "Folder" instead */
1313 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1316 /* If last message ... */
1318 /* but not only message, provide "Folder" instead */
1319 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1321 /* Otherwise if only message, leave blank */
1326 /* If deleted, show "undeleted" */
1328 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1331 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1332 bytes += adsi_set_keys(buf + bytes, keys);
1333 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1336 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1338 char buf[256], buf1[256], buf2[256];
1340 unsigned char keys[8];
1343 char *newm = (new == 1) ? "message" : "messages";
1344 char *oldm = (old == 1) ? "message" : "messages";
1345 if (!adsi_available(chan))
1348 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1350 strcat(buf1, " and");
1351 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1353 snprintf(buf2, sizeof(buf2), "%s.", newm);
1356 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1357 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1359 strcpy(buf1, "You have no messages.");
1362 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1363 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1364 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1367 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1371 /* Don't let them listen if there are none */
1374 bytes += adsi_set_keys(buf + bytes, keys);
1376 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1379 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1381 char buf[256], buf1[256], buf2[256];
1383 unsigned char keys[8];
1386 char *mess = (messages == 1) ? "message" : "messages";
1388 if (!adsi_available(chan))
1391 /* Original command keys */
1393 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1401 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1402 strcasecmp(folder, "INBOX") ? " folder" : "");
1405 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1407 strcpy(buf2, "no messages.");
1408 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1409 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1410 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1411 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1412 bytes += adsi_set_keys(buf + bytes, keys);
1414 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1418 static void adsi_clear(struct ast_channel *chan)
1422 if (!adsi_available(chan))
1424 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1425 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1428 static void adsi_goodbye(struct ast_channel *chan)
1433 if (!adsi_available(chan))
1435 bytes += adsi_logo(buf + bytes);
1436 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1437 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1438 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1439 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1442 static int get_folder(struct ast_channel *chan, int start)
1447 d = play_and_wait(chan, "vm-press");
1450 for (x = start; x< 5; x++) {
1451 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1453 d = play_and_wait(chan, "vm-for");
1456 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1457 d = play_and_wait(chan, fn);
1460 d = play_and_wait(chan, "vm-messages");
1463 d = ast_waitfordigit(chan, 500);
1467 d = play_and_wait(chan, "vm-tocancel");
1470 d = ast_waitfordigit(chan, 4000);
1474 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1477 res = play_and_wait(chan, fn);
1478 while (((res < '0') || (res > '9')) &&
1479 (res != '#') && (res > 0)) {
1480 res = get_folder(chan, 0);
1486 forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
1493 struct ast_config *mif;
1498 struct ast_vm_user *receiver, srec;
1503 res = ast_streamfile(chan, "vm-extension", chan->language);
1506 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1508 if ((receiver = find_user(&srec, context, username))) {
1509 printf("Got %d\n", atoi(username));
1510 /* if (play_and_wait(chan, "vm-savedto"))
1514 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, receiver->context, username);
1515 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1516 ast_log(LOG_DEBUG, sys);
1519 todircount = count_messages(todir);
1520 strncpy(tmp, fmt, sizeof(tmp));
1522 while((s = strsep(&stringp, "|"))) {
1523 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
1524 ast_log(LOG_DEBUG, sys);
1527 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1529 /* load the information on the source message so we can send an e-mail like a new message */
1530 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1531 if ((mif=ast_load(miffile))) {
1533 /* set callerid and duration variables */
1534 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
1535 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1537 if (strlen(receiver->email))
1538 sendmail(serveremail, receiver->email, receiver->fullname, todircount, username, callerid, fn, tmp, atol(ast_variable_retrieve(mif, NULL, "duration")));
1540 if (strlen(receiver->pager))
1541 sendpage(serveremail, receiver->pager, todircount, username, callerid, duration);
1543 ast_destroy(mif); /* or here */
1546 /* give confirmatopm that the message was saved */
1547 res = play_and_wait(chan, "vm-message");
1549 res = play_and_wait(chan, "vm-saved");
1550 free_user(receiver);
1553 res = play_and_wait(chan, "pbx-invalid");
1566 int deleted[MAXMSG];
1577 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1580 if ((res = ast_streamfile(chan, file, chan->language)))
1581 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1583 res = ast_waitstream(chan, AST_DIGIT_ANY);
1587 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
1590 if ((res = ast_streamfile(chan, file, chan->language)))
1591 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1593 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
1597 static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg)
1601 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1602 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
1604 res = wait_file2(chan, vms, "vm-first");
1605 else if (msg == vms->lastmsg)
1606 res = wait_file2(chan, vms, "vm-last");
1608 res = wait_file2(chan, vms, "vm-message");
1609 if (msg && (msg != vms->lastmsg)) {
1611 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
1616 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1617 vms->heard[msg] = 1;
1618 res = wait_file(chan, vms, vms->fn);
1623 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
1625 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
1626 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
1627 vms->lastmsg = count_messages(vms->curdir) - 1;
1628 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
1631 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
1634 char ntxt[256] = "";
1636 if (vms->lastmsg > -1) {
1637 /* Get the deleted messages fixed */
1639 for (x=0;x<=vms->lastmsg;x++) {
1640 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
1641 /* Save this message. It's not in INBOX or hasn't been heard */
1643 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1644 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
1645 if (strcmp(vms->fn, vms->fn2)) {
1646 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1647 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
1648 ast_filerename(vms->fn, vms->fn2, NULL);
1651 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
1652 /* Move to old folder before deleting */
1653 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
1656 for (x = vms->curmsg + 1; x<=vms->lastmsg; x++) {
1657 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1658 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1659 ast_filedelete(vms->fn, NULL);
1663 memset(vms->deleted, 0, sizeof(vms->deleted));
1664 memset(vms->heard, 0, sizeof(vms->heard));
1667 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
1669 /* Introduce messages they have */
1671 res = play_and_wait(chan, "vm-youhave");
1673 if (vms->newmessages) {
1674 res = say_and_wait(chan, vms->newmessages);
1676 res = play_and_wait(chan, "vm-INBOX");
1677 if (vms->oldmessages && !res)
1678 res = play_and_wait(chan, "vm-and");
1680 if ((vms->newmessages == 1))
1681 res = play_and_wait(chan, "vm-message");
1683 res = play_and_wait(chan, "vm-messages");
1687 if (!res && vms->oldmessages) {
1688 res = say_and_wait(chan, vms->oldmessages);
1690 res = play_and_wait(chan, "vm-Old");
1692 if (vms->oldmessages == 1)
1693 res = play_and_wait(chan, "vm-message");
1695 res = play_and_wait(chan, "vm-messages");
1699 if (!vms->oldmessages && !vms->newmessages) {
1700 res = play_and_wait(chan, "vm-no");
1702 res = play_and_wait(chan, "vm-messages");
1709 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
1712 /* Play instructions and wait for new command */
1714 if (vms->starting) {
1715 if (vms->lastmsg > -1) {
1716 res = play_and_wait(chan, "vm-onefor");
1718 res = play_and_wait(chan, vms->vmbox);
1720 res = play_and_wait(chan, "vm-messages");
1723 res = play_and_wait(chan, "vm-opts");
1726 res = play_and_wait(chan, "vm-prev");
1728 res = play_and_wait(chan, "vm-repeat");
1729 if (!res && (vms->curmsg != vms->lastmsg))
1730 res = play_and_wait(chan, "vm-next");
1732 if (!vms->deleted[vms->curmsg])
1733 res = play_and_wait(chan, "vm-delete");
1735 res = play_and_wait(chan, "vm-undelete");
1737 res = play_and_wait(chan, "vm-toforward");
1739 res = play_and_wait(chan, "vm-savemessage");
1743 res = play_and_wait(chan, "vm-helpexit");
1745 res = ast_waitfordigit(chan, 6000);
1748 if (vms->repeats > 2) {
1749 res = play_and_wait(chan, "vm-goodbye");
1758 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
1762 char newpassword[80] = "";
1763 char newpassword2[80] = "";
1764 char prefile[256]="";
1765 while((cmd >= 0) && (cmd != 't')) {
1770 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
1771 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
1774 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
1775 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
1778 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
1779 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
1782 newpassword[1] = '\0';
1783 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
1786 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
1789 newpassword2[1] = '\0';
1790 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
1794 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
1797 if (strcmp(newpassword, newpassword2)) {
1798 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
1799 cmd = play_and_wait(chan, "vm-mismatch");
1802 if (vm_change_password(vmu,newpassword) < 0)
1804 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",vms->username);
1806 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
1807 cmd = play_and_wait(chan,"vm-passchanged");
1813 cmd = play_and_wait(chan,"vm-options");
1815 cmd = ast_waitfordigit(chan,6000);
1827 static int vm_execmain(struct ast_channel *chan, void *data)
1829 /* XXX This is, admittedly, some pretty horrendus code. For some
1830 reason it just seemed a lot easier to do with GOTO's. I feel
1831 like I'm back in my GWBASIC days. XXX */
1836 struct localuser *u;
1837 char prefixstr[80] ="";
1838 char empty[80] = "";
1842 char tmp[256], *ext;
1843 char fmtc[256] = "";
1845 struct vm_state vms;
1846 struct ast_vm_user *vmu = NULL, vmus;
1850 memset(&vms, 0, sizeof(vms));
1851 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
1852 if (chan->_state != AST_STATE_UP)
1855 if (data && strlen(data)) {
1856 strncpy(tmp, data, sizeof(tmp) - 1);
1861 /* We should skip the user's password */
1866 /* We should prefix the mailbox with the supplied data */
1872 context = strchr(ext, '@');
1879 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1881 strncpy(vms.username, ext, sizeof(vms.username) - 1);
1882 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
1889 /* If ADSI is supported, setup login screen */
1890 adsi_begin(chan, &useadsi);
1891 if (!skipuser && useadsi)
1893 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1894 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1898 /* Authenticate them and get their mailbox/password */
1901 /* Prompt for, and read in the username */
1902 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
1903 ast_log(LOG_WARNING, "Couldn't read username\n");
1906 if (!strlen(vms.username)) {
1907 if (option_verbose > 2)
1908 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1913 adsi_password(chan);
1914 if (ast_streamfile(chan, "vm-password", chan->language)) {
1915 ast_log(LOG_WARNING, "Unable to stream password file\n");
1918 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1919 ast_log(LOG_WARNING, "Unable to read password\n");
1923 char fullusername[80] = "";
1924 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1925 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
1926 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
1929 vmu = find_user(&vmus, context, vms.username);
1930 if (vmu && !strcmp(vmu->password, password))
1933 if (option_verbose > 2)
1934 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
1936 strncpy(vms.username, empty, sizeof(vms.username) -1);
1941 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1947 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
1948 mkdir(vms.curdir, 0700);
1949 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
1950 mkdir(vms.curdir, 0700);
1951 /* Retrieve old and new message counts */
1952 open_mailbox(&vms, vmu, 1);
1953 vms.oldmessages = vms.lastmsg + 1;
1954 /* Start in INBOX */
1955 open_mailbox(&vms, vmu, 0);
1956 vms.newmessages = vms.lastmsg + 1;
1959 /* Select proper mailbox FIRST!! */
1960 if (!vms.newmessages && vms.oldmessages) {
1961 /* If we only have old messages start here */
1962 open_mailbox(&vms, vmu, 1);
1966 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
1968 cmd = vm_intro(chan, &vms);
1971 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
1978 if (vms.lastmsg > -1) {
1979 cmd = play_message(chan, &vms, vms.curmsg);
1981 cmd = play_and_wait(chan, "vm-youhave");
1983 cmd = play_and_wait(chan, "vm-no");
1985 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
1986 cmd = play_and_wait(chan, vms.fn);
1989 cmd = play_and_wait(chan, "vm-messages");
1992 case '2': /* Change folders */
1994 adsi_folders(chan, 0, "Change to folder...");
1995 cmd = get_folder2(chan, "vm-changeto", 0);
1998 } else if (cmd > 0) {
2000 close_mailbox(&vms, vmu);
2001 open_mailbox(&vms, vmu, cmd);
2005 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2007 cmd = play_and_wait(chan, vms.vmbox);
2009 cmd = play_and_wait(chan, "vm-messages");
2015 cmd = play_message(chan, &vms, vms.curmsg);
2017 cmd = play_and_wait(chan, "vm-nomore");
2021 if (vms.curmsg < vms.lastmsg) {
2023 cmd = play_message(chan, &vms, vms.curmsg);
2025 cmd = play_and_wait(chan, "vm-nomore");
2029 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2031 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2032 if (vms.deleted[vms.curmsg])
2033 cmd = play_and_wait(chan, "vm-deleted");
2035 cmd = play_and_wait(chan, "vm-undeleted");
2038 if(vms.lastmsg > -1)
2039 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2043 adsi_folders(chan, 1, "Save to folder...");
2044 cmd = get_folder2(chan, "vm-savefolder", 1);
2045 box = 0; /* Shut up compiler */
2049 } else if (cmd > 0) {
2050 box = cmd = cmd - '0';
2051 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2052 vms.deleted[vms.curmsg]=1;
2054 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2056 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2058 cmd = play_and_wait(chan, "vm-message");
2060 cmd = say_and_wait(chan, vms.curmsg + 1);
2062 cmd = play_and_wait(chan, "vm-savedto");
2064 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2065 cmd = play_and_wait(chan, vms.fn);
2068 cmd = play_and_wait(chan, "vm-messages");
2071 if (!vms.starting) {
2072 cmd = play_and_wait(chan, "vm-onefor");
2074 cmd = play_and_wait(chan, vms.vmbox);
2076 cmd = play_and_wait(chan, "vm-messages");
2078 cmd = play_and_wait(chan, "vm-opts");
2083 cmd = vm_options(chan, vmu, &vms, vmfmts);
2086 ast_stopstream(chan);
2088 cmd = play_and_wait(chan, "vm-goodbye");
2092 default: /* Nothing */
2093 cmd = vm_instructions(chan, &vms);
2106 if ((res > -1) && (cmd != '#')) {
2107 ast_stopstream(chan);
2110 adsi_unload_session(chan);
2113 close_mailbox(&vms, vmu);
2117 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2119 LOCAL_USER_REMOVE(u);
2124 static int vm_exec(struct ast_channel *chan, void *data)
2126 int res=0, silent=0, busy=0, unavail=0;
2127 struct localuser *u;
2128 char tmp[256], *ext;
2131 if (chan->_state != AST_STATE_UP)
2134 strncpy(tmp, data, sizeof(tmp) - 1);
2136 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2147 } else if (*ext == 'b') {
2150 } else if (*ext == 'u') {
2156 res = leave_voicemail(chan, ext, silent, busy, unavail);
2157 LOCAL_USER_REMOVE(u);
2161 static int append_mailbox(char *context, char *mbox, char *data)
2163 /* Assumes lock is already held */
2167 struct ast_vm_user *vmu;
2168 strncpy(tmp, data, sizeof(tmp));
2169 vmu = malloc(sizeof(struct ast_vm_user));
2171 memset(vmu, 0, sizeof(struct ast_vm_user));
2172 strncpy(vmu->context, context, sizeof(vmu->context));
2173 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2175 if ((s = strsep(&stringp, ",")))
2176 strncpy(vmu->password, s, sizeof(vmu->password));
2177 if ((s = strsep(&stringp, ",")))
2178 strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2179 if ((s = strsep(&stringp, ",")))
2180 strncpy(vmu->email, s, sizeof(vmu->email));
2181 if ((s = strsep(&stringp, ",")))
2182 strncpy(vmu->pager, s, sizeof(vmu->pager));
2193 static int load_users(void)
2195 struct ast_vm_user *cur, *l;
2196 struct ast_config *cfg;
2198 struct ast_variable *var;
2206 cfg = ast_load(VOICEMAIL_CONFIG);
2207 ast_pthread_mutex_lock(&vmlock);
2217 /* General settings */
2218 attach_voicemail = 1;
2219 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
2221 attach_voicemail = ast_true(astattach);
2223 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2224 maxsilence = atoi(silencestr);
2229 silencethreshold = 256;
2230 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2231 silencethreshold = atoi(thresholdstr);
2233 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
2234 astemail = ASTERISK_USERNAME;
2235 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2238 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2239 if (sscanf(s, "%d", &x) == 1) {
2242 ast_log(LOG_WARNING, "Invalid max message time length\n");
2245 fmt = ast_variable_retrieve(cfg, "general", "format");
2248 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2251 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2252 if (sscanf(s, "%d", &x) == 1) {
2255 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2259 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2260 if (sscanf(s, "%d", &x) == 1) {
2263 ast_log(LOG_WARNING, "Invalid skipms value\n");
2267 cat = ast_category_browse(cfg, NULL);
2269 if (strcasecmp(cat, "general")) {
2270 /* Process mailboxes in this context */
2271 var = ast_variable_browse(cfg, cat);
2273 append_mailbox(cat, var->name, var->value);
2277 cat = ast_category_browse(cfg, cat);
2281 ast_pthread_mutex_unlock(&vmlock);
2291 int unload_module(void)
2294 STANDARD_HANGUP_LOCALUSERS;
2295 res = ast_unregister_application(app);
2296 res |= ast_unregister_application(app2);
2300 int load_module(void)
2304 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2306 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2310 char *description(void)
2318 STANDARD_USECOUNT(res);
2324 return ASTERISK_GPL_KEY;