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];
76 static char *tdesc = "Comedian Mail (Voicemail System)";
78 static char *adapp = "CoMa";
80 static char *adsec = "_AST";
82 static char *addesc = "Comedian Mail";
86 static char *synopsis_vm =
87 "Leave a voicemail message";
89 static char *descrip_vm =
90 " VoiceMail([s|u|b]extension): Leaves voicemail for a given extension (must\n"
91 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
92 "then instructions for leaving the message will be skipped. If the extension\n"
93 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
94 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
95 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
96 "busy instead of unavail). At most one of 's', 'u', or 'b' may be specified.\n"
97 "Returns -1 on error or mailbox not found, or if the user hangs up. \n"
98 "Otherwise, it returns 0. \n";
100 static char *synopsis_vmain =
101 "Enter voicemail system";
103 static char *descrip_vmain =
104 " VoiceMailMain(): Enters the main voicemail system for the checking of\n"
105 "voicemail. The mailbox can be passed as the option, which will stop the\n"
106 "voicemail system from prompting the user for the mailbox. If the mailbox\n"
107 "is preceded by 's' then the password check will be skipped. Returns -1 if\n"
108 "the user hangs up or 0 otherwise.\n";
110 /* Leave a message */
111 static char *app = "VoiceMail2";
113 /* Check mail, control, etc */
114 static char *app2 = "VoiceMailMain2";
120 static int make_dir(char *dest, int len, char *ext, char *mailbox)
122 return snprintf(dest, len, "%s/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", ext, mailbox);
125 static int make_file(char *dest, int len, char *dir, int num)
127 return snprintf(dest, len, "%s/msg%04d", dir, num);
130 static int vm_change_password(char *username, char *password, char *newpassword)
132 /* There's probably a better way of doing this. */
133 /* That's why I've put the password change in a separate function. */
139 char tmpin[AST_CONFIG_MAX_PATH];
140 char tmpout[AST_CONFIG_MAX_PATH];
141 char *user, *pass, *rest, *trim;
142 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
143 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
144 configin = fopen((char *)tmpin,"r");
145 configout = fopen((char *)tmpout,"w+");
147 while (!feof(configin)) {
148 /* Read in the line */
149 fgets(inbuf, sizeof(inbuf), configin);
150 if (!feof(configin)) {
151 /* Make a backup of it */
152 memcpy(orig, inbuf, sizeof(orig));
153 /* Strip trailing \n and comment */
154 inbuf[strlen(inbuf) - 1] = '\0';
155 user = strchr(inbuf, ';');
161 pass = strchr(user, '=');
164 while(*trim && *trim < 33) {
174 while(*pass && *pass < 33)
178 rest = strchr(pass,',');
185 if (user && pass && *user && *pass && !strcmp(user, username) && !strcmp(pass, password)) {
186 /* This is the line */
188 fprintf(configout, "%s => %s,%s\n", username,newpassword,rest);
190 fprintf(configout, "%s => %s\n", username,newpassword);
193 /* Put it back like it was */
194 fprintf(configout, orig);
201 unlink((char *)tmpin);
202 rename((char *)tmpout,(char *)tmpin);
207 inbuf(struct baseio *bio, FILE *fi)
214 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
229 inchar(struct baseio *bio, FILE *fi)
231 if(bio->iocp>=bio->iolen)
235 return bio->iobuf[bio->iocp++];
239 ochar(struct baseio *bio, int c, FILE *so)
241 if(bio->linelength>=BASELINELEN) {
242 if(fputs(eol,so)==EOF)
248 if(putc(((unsigned char)c),so)==EOF)
256 static int base_encode(char *filename, FILE *so)
258 unsigned char dtable[BASEMAXINLINE];
263 memset(&bio, 0, sizeof(bio));
264 bio.iocp = BASEMAXINLINE;
266 if ( !(fi = fopen(filename, "rb"))) {
267 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
275 dtable[26+i+9]= 'j'+i;
279 dtable[26+i+18]= 's'+i;
288 unsigned char igroup[3],ogroup[4];
291 igroup[0]= igroup[1]= igroup[2]= 0;
294 if ( (c = inchar(&bio, fi)) == EOF) {
299 igroup[n]= (unsigned char)c;
303 ogroup[0]= dtable[igroup[0]>>2];
304 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
305 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
306 ogroup[3]= dtable[igroup[2]&0x3F];
316 ochar(&bio, ogroup[i], so);
320 if(fputs(eol,so)==EOF)
328 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
340 struct ast_config *cfg;
341 p = popen(SENDMAIL, "w");
342 cfg = ast_load(VOICEMAIL_CONFIG);
343 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
346 gethostname(host, sizeof(host));
347 if (strchr(srcemail, '@'))
348 strncpy(who, srcemail, sizeof(who)-1);
350 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
352 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
355 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
356 fprintf(p, "Date: %s\n", date);
357 fprintf(p, "From: Asterisk PBX <%s>\n", who);
358 fprintf(p, "To: %s <%s>\n", name, email);
359 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
360 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
361 fprintf(p, "MIME-Version: 1.0\n");
362 if (ast_true(astattach)) {
364 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
366 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
368 fprintf(p, "--%s\n", bound);
370 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
371 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
372 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
374 "in mailbox %s from %s, on %s so you might\n"
375 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
376 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
377 if (ast_true(astattach)) {
378 fprintf(p, "--%s\n", bound);
379 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
380 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
381 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
382 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
384 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
385 base_encode(fname, p);
386 fprintf(p, "\n\n--%s--\n.\n", bound);
390 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
396 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration)
405 struct ast_config *cfg;
406 p = popen(SENDMAIL, "w");
407 cfg = ast_load(VOICEMAIL_CONFIG);
410 gethostname(host, sizeof(host));
411 if (strchr(srcemail, '@'))
412 strncpy(who, srcemail, sizeof(who)-1);
414 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
416 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
419 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
420 fprintf(p, "Date: %s\n", date);
421 fprintf(p, "From: Asterisk PBX <%s>\n", who);
422 fprintf(p, "To: %s\n", pager);
423 fprintf(p, "Subject: New VM\n\n");
424 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
425 fprintf(p, "New %s long msg in box %s\n"
426 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
429 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
435 static int get_date(char *s, int len)
441 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
444 static int invent_message(struct ast_channel *chan, char *ext, int busy, char *ecodes)
448 snprintf(fn, sizeof(fn), "vm/%s/greet", ext);
449 if (ast_fileexists(fn, NULL, NULL) > 0) {
450 res = ast_streamfile(chan, fn, chan->language);
453 res = ast_waitstream(chan, ecodes);
457 res = ast_streamfile(chan, "vm-theperson", chan->language);
460 res = ast_waitstream(chan, ecodes);
463 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
468 res = ast_streamfile(chan, "vm-isonphone", chan->language);
470 res = ast_streamfile(chan, "vm-isunavail", chan->language);
473 res = ast_waitstream(chan, ecodes);
477 static int play_and_wait(struct ast_channel *chan, char *fn)
480 d = ast_streamfile(chan, fn, chan->language);
483 d = ast_waitstream(chan, AST_DIGIT_ANY);
487 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
491 int x, fmtcnt=1, res=-1,outmsg=0;
493 struct ast_filestream *others[MAX_OTHER_FORMATS];
494 char *sfmt[MAX_OTHER_FORMATS];
499 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
500 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
503 d = play_and_wait(chan, playfile);
505 d = ast_streamfile(chan, "beep",chan->language);
507 d = ast_waitstream(chan,"");
515 strsep(&stringp, "|");
516 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
517 sfmt[0] = strdupa(fmts);
519 while((fmt = strsep(&stringp, "|"))) {
520 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
521 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
524 sfmt[fmtcnt++] = strdupa(fmt);
529 for (x=0;x<fmtcnt;x++) {
530 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
531 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s\n", x, recordfile, sfmt[x]);
538 /* Loop forever, writing the packets we read to the writer(s), until
539 we read a # or get a hangup */
542 res = ast_waitfor(chan, 2000);
544 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
545 /* Try one more time in case of masq */
546 res = ast_waitfor(chan, 2000);
548 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
560 if (f->frametype == AST_FRAME_VOICE) {
561 /* write each format */
562 for (x=0;x<fmtcnt;x++) {
563 res = ast_writestream(others[x], f);
565 /* Exit on any error */
567 ast_log(LOG_WARNING, "Error writing frame\n");
571 } else if (f->frametype == AST_FRAME_DTMF) {
572 if (f->subclass == '#') {
573 if (option_verbose > 2)
574 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
583 if (maxtime < (end - start)) {
584 if (option_verbose > 2)
585 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
594 if (option_verbose > 2)
595 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
600 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
603 for (x=0;x<fmtcnt;x++) {
606 ast_closestream(others[x]);
610 /* Let them know it worked */
611 ast_streamfile(chan, "vm-msgsaved", chan->language);
612 ast_waitstream(chan, "");
620 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
622 struct ast_config *cfg;
623 char *copy, *name=NULL, *passwd=NULL, *email=NULL, *pager=NULL, *fmt;
633 char prefile[256]="";
639 int silence = 0; /* amount of silence to allow */
641 /* XXX Need to be moved to play_and_record */
642 struct ast_dsp *sildet; /* silence detector dsp */
643 int totalsilence = 0;
645 int gotsilence = 0; /* did we timeout for silence? */
651 cfg = ast_load(VOICEMAIL_CONFIG);
653 ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG);
656 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
657 silence = atoi(silencestr);
661 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
662 threshold = atoi(thresholdstr);
664 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
665 astemail = ASTERISK_USERNAME;
666 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
667 if (sscanf(s, "%d", &x) == 1) {
670 ast_log(LOG_WARNING, "Invalid max message time length\n");
673 if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
675 /* Setup pre-file if appropriate */
677 snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
679 snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
680 /* Make sure they have an entry in the config */
681 copy = strdupa(copy);
683 passwd = strsep(&stringp, ",");
685 name = strsep(&stringp, ",");
687 email = strsep(&stringp, ",");
689 pager = strsep(&stringp, ",");
690 make_dir(dir, sizeof(dir), ext, "");
691 /* It's easier just to try to make it than to check for its existence */
692 if (mkdir(dir, 0700) && (errno != EEXIST))
693 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
694 make_dir(dir, sizeof(dir), ext, "INBOX");
695 if (mkdir(dir, 0700) && (errno != EEXIST))
696 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
697 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
699 /* Play the beginning intro if desired */
700 if (strlen(prefile)) {
701 if (ast_fileexists(prefile, NULL, NULL) > 0) {
702 if (ast_streamfile(chan, prefile, chan->language) > -1)
703 res = ast_waitstream(chan, "#0");
705 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
706 res = invent_message(chan, ext, busy, ecodes);
709 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
714 /* On a '#' we skip the instructions */
718 if (!res && !silent) {
719 res = ast_streamfile(chan, INTRO, chan->language);
721 res = ast_waitstream(chan, ecodes);
727 /* Check for a '0' here */
729 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
730 if (strlen(chan->macrocontext))
731 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
735 if (!res && (silent < 2)) {
736 /* Unless we're *really* silent, try to send the beep */
737 res = ast_streamfile(chan, "beep", chan->language);
739 res = ast_waitstream(chan, "");
743 /* The meat of recording the message... All the announcements and beeps have been played*/
744 fmt = ast_variable_retrieve(cfg, "general", "format");
748 make_file(fn, sizeof(fn), dir, msgnum);
749 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
750 (chan->callerid ? chan->callerid : "Unknown"),
751 name, ext, chan->name);
752 if (ast_fileexists(fn, NULL, chan->language) <= 0)
755 } while(msgnum < MAXMSG);
756 if (msgnum < MAXMSG) {
757 /* Store information */
758 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
759 txt = fopen(txtfile, "w+");
761 get_date(date, sizeof(date));
765 "; Message Information file\n"
781 chan->callerid ? chan->callerid : "Unknown",
785 ast_log(LOG_WARNING, "Error opening text file for output\n");
786 res = play_and_record(chan, NULL, fn, maxmessage, fmt);
787 txt = fopen(txtfile, "a");
790 fprintf(txt, "duration=%ld\n", end-start);
794 strsep(&stringp, "|");
795 /* Send e-mail if applicable */
797 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, fmt, end - start);
799 sendpage(astemail, pager, msgnum, ext, chan->callerid, end - start);
801 ast_log(LOG_WARNING, "No more messages possible\n");
803 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
806 sildet = ast_dsp_new(); //Create the silence detector
808 rfmt = chan->readformat;
809 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
811 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
815 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
818 ast_dsp_set_threshold(sildet, 50);
822 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
824 /* Leave voicemail for someone */
825 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
829 static char *mbox(int id)
857 static int count_messages(char *dir)
861 for (x=0;x<MAXMSG;x++) {
862 make_file(fn, sizeof(fn), dir, x);
863 if (ast_fileexists(fn, NULL, NULL) < 1)
869 static int say_and_wait(struct ast_channel *chan, int num)
872 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
876 static int copy(char *infile, char *outfile)
883 if ((ifd = open(infile, O_RDONLY)) < 0) {
884 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
887 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
888 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
893 len = read(ifd, buf, sizeof(buf));
895 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
901 res = write(ofd, buf, len);
903 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
915 static int save_to_folder(char *dir, int msg, char *username, int box)
922 char *dbox = mbox(box);
924 make_file(sfn, sizeof(sfn), dir, msg);
925 make_dir(ddir, sizeof(ddir), username, dbox);
927 for (x=0;x<MAXMSG;x++) {
928 make_file(dfn, sizeof(dfn), ddir, x);
929 if (ast_fileexists(dfn, NULL, NULL) < 0)
934 ast_filecopy(sfn, dfn, NULL);
935 if (strcmp(sfn, dfn)) {
936 snprintf(txt, sizeof(txt), "%s.txt", sfn);
937 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
943 static int adsi_logo(unsigned char *buf)
946 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
947 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
951 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
959 bytes += adsi_data_mode(buf + bytes);
960 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
963 bytes += adsi_logo(buf);
964 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
966 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
968 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
969 bytes += adsi_data_mode(buf + bytes);
970 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
972 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
974 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
975 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
976 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
977 bytes += adsi_voice_mode(buf + bytes, 0);
978 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
985 bytes += adsi_logo(buf);
986 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
987 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
988 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
989 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
992 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
993 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
994 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
995 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
996 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
997 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
998 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1001 /* Add another dot */
1003 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1004 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1005 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1009 /* These buttons we load but don't use yet */
1010 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1011 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1012 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1013 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1014 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1015 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1016 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1019 /* Add another dot */
1021 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1022 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1023 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1028 snprintf(num, sizeof(num), "%d", x);
1029 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1031 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1032 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1035 /* Add another dot */
1037 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1038 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1039 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1042 if (adsi_end_download(chan)) {
1044 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1045 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1046 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1047 bytes += adsi_voice_mode(buf + bytes, 0);
1048 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1052 bytes += adsi_download_disconnect(buf + bytes);
1053 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1055 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1060 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1061 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1063 ast_log(LOG_DEBUG, "Restarting session...\n");
1066 /* Load the session now */
1067 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1069 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1071 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1073 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1077 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1080 if (!adsi_available(chan))
1082 x = adsi_load_session(chan, adapp, adver, 1);
1086 if (adsi_load_vmail(chan, useadsi)) {
1087 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1094 static void adsi_login(struct ast_channel *chan)
1098 unsigned char keys[8];
1100 if (!adsi_available(chan))
1105 /* Set one key for next */
1106 keys[3] = ADSI_KEY_APPS + 3;
1108 bytes += adsi_logo(buf + bytes);
1109 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1110 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1111 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1112 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1113 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1114 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1115 bytes += adsi_set_keys(buf + bytes, keys);
1116 bytes += adsi_voice_mode(buf + bytes, 0);
1117 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1120 static void adsi_password(struct ast_channel *chan)
1124 unsigned char keys[8];
1126 if (!adsi_available(chan))
1131 /* Set one key for next */
1132 keys[3] = ADSI_KEY_APPS + 3;
1134 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1135 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1136 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1137 bytes += adsi_set_keys(buf + bytes, keys);
1138 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1141 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1145 unsigned char keys[8];
1148 if (!adsi_available(chan))
1152 y = ADSI_KEY_APPS + 12 + start + x;
1153 if (y > ADSI_KEY_APPS + 12 + 4)
1155 keys[x] = ADSI_KEY_SKT | y;
1157 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1161 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1162 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1163 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1164 bytes += adsi_set_keys(buf + bytes, keys);
1165 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1168 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1171 char buf[256], buf1[256], buf2[256];
1176 char datetime[21]="";
1179 unsigned char keys[8];
1183 if (!adsi_available(chan))
1186 /* Retrieve important info */
1187 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1188 f = fopen(fn2, "r");
1191 fgets(buf, sizeof(buf), f);
1195 strsep(&stringp, "=");
1196 val = strsep(&stringp, "=");
1197 if (val && strlen(val)) {
1198 if (!strcmp(buf, "callerid"))
1199 strncpy(cid, val, sizeof(cid) - 1);
1200 if (!strcmp(buf, "origdate"))
1201 strncpy(datetime, val, sizeof(datetime) - 1);
1207 /* New meaning for keys */
1209 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1214 /* No prev key, provide "Folder" instead */
1215 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1218 /* If last message ... */
1220 /* but not only message, provide "Folder" instead */
1221 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1223 /* Otherwise if only message, leave blank */
1229 ast_callerid_parse(cid, &name, &num);
1233 name = "Unknown Caller";
1235 /* If deleted, show "undeleted" */
1237 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1240 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1241 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1242 strcasecmp(folder, "INBOX") ? " Messages" : "");
1243 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1245 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1246 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1247 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1248 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1249 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1250 bytes += adsi_set_keys(buf + bytes, keys);
1251 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1254 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1258 unsigned char keys[8];
1262 if (!adsi_available(chan))
1265 /* New meaning for keys */
1267 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1273 /* No prev key, provide "Folder" instead */
1274 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1277 /* If last message ... */
1279 /* but not only message, provide "Folder" instead */
1280 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1282 /* Otherwise if only message, leave blank */
1287 /* If deleted, show "undeleted" */
1289 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1292 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1293 bytes += adsi_set_keys(buf + bytes, keys);
1294 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1297 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1299 char buf[256], buf1[256], buf2[256];
1301 unsigned char keys[8];
1304 char *newm = (new == 1) ? "message" : "messages";
1305 char *oldm = (old == 1) ? "message" : "messages";
1306 if (!adsi_available(chan))
1309 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1311 strcat(buf1, " and");
1312 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1314 snprintf(buf2, sizeof(buf2), "%s.", newm);
1317 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1318 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1320 strcpy(buf1, "You have no messages.");
1323 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1324 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1325 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1328 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1332 /* Don't let them listen if there are none */
1335 bytes += adsi_set_keys(buf + bytes, keys);
1337 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1340 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1342 char buf[256], buf1[256], buf2[256];
1344 unsigned char keys[8];
1347 char *mess = (messages == 1) ? "message" : "messages";
1349 if (!adsi_available(chan))
1352 /* Original command keys */
1354 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1362 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1363 strcasecmp(folder, "INBOX") ? " folder" : "");
1366 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1368 strcpy(buf2, "no messages.");
1369 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1370 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1371 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1372 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1373 bytes += adsi_set_keys(buf + bytes, keys);
1375 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1379 static void adsi_clear(struct ast_channel *chan)
1383 if (!adsi_available(chan))
1385 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1386 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1389 static void adsi_goodbye(struct ast_channel *chan)
1394 if (!adsi_available(chan))
1396 bytes += adsi_logo(buf + bytes);
1397 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1398 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1399 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1400 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1403 static int get_folder(struct ast_channel *chan, int start)
1408 d = play_and_wait(chan, "vm-press");
1411 for (x = start; x< 5; x++) {
1412 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1414 d = play_and_wait(chan, "vm-for");
1417 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1418 d = play_and_wait(chan, fn);
1421 d = play_and_wait(chan, "vm-messages");
1424 d = ast_waitfordigit(chan, 500);
1428 d = play_and_wait(chan, "vm-tocancel");
1431 d = ast_waitfordigit(chan, 4000);
1435 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1438 res = play_and_wait(chan, fn);
1439 while (((res < '0') || (res > '9')) &&
1440 (res != '#') && (res > 0)) {
1441 res = get_folder(chan, 0);
1447 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg, char* myusername)
1454 struct ast_config *mif;
1456 char *copy, *name, *passwd, *email, *pager;
1457 char *mycopy, *myname, *mypasswd, *myemail, *mypager;
1464 res = ast_streamfile(chan, "vm-extension", chan->language);
1467 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1469 if (ast_variable_retrieve(cfg, NULL, username)) {
1470 printf("Got %d\n", atoi(username));
1471 /* if (play_and_wait(chan, "vm-savedto"))
1475 snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1476 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1480 todircount = count_messages(todir);
1482 snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1486 /* TODO: use config to determine what other formats to copy the message in */
1487 snprintf(sys, sizeof(sys), "cp %s/msg%04d.wav %s/msg%04d.wav\n", dir, curmsg, todir, todircount);
1491 /* copy the message information file too */
1492 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
1496 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1498 /* load the information on the source message so we can send an e-mail like a new message */
1499 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1500 if ((mif=ast_load(miffile))) {
1502 /* send an e-mail like it was a new message if appropriate */
1503 if ((copy = ast_variable_retrieve(cfg, NULL, username))) {
1505 /* Make sure they have an entry in the config */
1506 copy = strdup(copy);
1508 passwd = strsep(&stringp, ",");
1509 name = strsep(&stringp, ",");
1510 email = strsep(&stringp, ",");
1511 pager = strsep(&stringp, ",");
1514 if ((mycopy = ast_variable_retrieve(cfg, NULL, myusername))) {
1515 char *mystringp=NULL;
1516 /* Make sure they have an entry in the config */
1517 mycopy = strdup(mycopy);
1519 mypasswd = strsep(&mystringp, ",");
1520 myname = strsep(&mystringp, ",");
1521 myemail = strsep(&mystringp, ",");
1522 mypager = strsep(&mystringp, ",");
1525 /* set the outbound email from address */
1526 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
1527 astemail = ASTERISK_USERNAME;
1529 /* set callerid and duration variables */
1530 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", myname, ast_variable_retrieve(mif, NULL, "callerid"));
1531 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1534 sendmail(astemail, email, name, todircount, username, callerid, fn, "wav", atol(ast_variable_retrieve(mif, NULL, "duration")));
1537 sendpage(astemail, pager, todircount, username, callerid, duration);
1539 free(copy); /* no leaks here */
1540 free(mycopy); /* or here */
1541 ast_destroy(mif); /* or here */
1544 /* give confirmatopm that the message was saved */
1545 res = play_and_wait(chan, "vm-message");
1547 res = play_and_wait(chan, "vm-saved");
1550 res = play_and_wait(chan, "pbx-invalid");
1564 int deleted[MAXMSG];
1576 #define WAITCMD(a) do { \
1584 #define WAITFILE2(file) do { \
1585 if (ast_streamfile(chan, file, chan->language)) \
1586 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1587 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1593 #define WAITFILE(file) do { \
1594 if (ast_streamfile(chan, file, chan->language)) \
1595 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1596 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) { \
1597 if (sscanf(s, "%d", &x) == 1) \
1600 d = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",ms); \
1603 goto instructions; \
1604 } else if (d < 0) { \
1609 #define PLAYMSG(a) do { \
1611 make_file(fn, sizeof(fn), curdir, a); \
1612 adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1614 WAITFILE2("vm-first"); \
1615 else if (a == lastmsg) \
1616 WAITFILE2("vm-last"); \
1617 WAITFILE2("vm-message"); \
1618 if (a && (a != lastmsg)) { \
1619 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1620 if (d < 0) goto out; \
1623 make_file(fn, sizeof(fn), curdir, a); \
1628 #define CLOSE_MAILBOX do { \
1629 if (lastmsg > -1) { \
1630 /* Get the deleted messages fixed */ \
1632 for (x=0;x<=lastmsg;x++) { \
1633 if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1634 /* Save this message. It's not in INBOX or hasn't been heard */ \
1636 make_file(fn, sizeof(fn), curdir, x); \
1637 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1638 if (strcmp(fn, fn2)) { \
1639 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1640 snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1641 ast_filerename(fn, fn2, NULL); \
1642 rename(txt, ntxt); \
1644 } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1645 /* Move to old folder before deleting */ \
1646 save_to_folder(curdir, x, username, 1); \
1649 for (x = curmsg + 1; x<=lastmsg; x++) { \
1650 make_file(fn, sizeof(fn), curdir, x); \
1651 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1652 ast_filedelete(fn, NULL); \
1656 memset(deleted, 0, sizeof(deleted)); \
1657 memset(heard, 0, sizeof(heard)); \
1660 #define OPEN_MAILBOX(a) do { \
1661 strcpy(curbox, mbox(a)); \
1662 make_dir(curdir, sizeof(curdir), username, curbox); \
1663 lastmsg = count_messages(curdir) - 1; \
1664 snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1668 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1671 if ((res = ast_streamfile(chan, file, chan->language)))
1672 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1674 res = ast_waitstream(chan, AST_DIGIT_ANY);
1678 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
1681 if ((res = ast_streamfile(chan, file, chan->language)))
1682 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1684 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",vms->skipms);
1688 static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg)
1691 vms->starting = 0; \
1692 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1693 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
1695 res = wait_file2(chan, vms, "vm-first");
1696 else if (msg == vms->lastmsg)
1697 res = wait_file2(chan, vms, "vm-last");
1699 res = wait_file2(chan, vms, "vm-message");
1700 if (msg && (msg != vms->lastmsg)) {
1702 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
1707 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1708 vms->heard[msg] = 1;
1709 res = wait_file(chan, vms, vms->fn);
1714 static void open_mailbox(struct vm_state *vms, int box)
1716 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
1717 make_dir(vms->curdir, sizeof(vms->curdir), vms->username, vms->curbox);
1718 vms->lastmsg = count_messages(vms->curdir) - 1;
1719 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
1722 static void close_mailbox(struct vm_state *vms)
1725 char ntxt[256] = "";
1727 if (vms->lastmsg > -1) {
1728 /* Get the deleted messages fixed */
1730 for (x=0;x<=vms->lastmsg;x++) {
1731 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
1732 /* Save this message. It's not in INBOX or hasn't been heard */
1734 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1735 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
1736 if (strcmp(vms->fn, vms->fn2)) {
1737 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1738 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
1739 ast_filerename(vms->fn, vms->fn2, NULL);
1742 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
1743 /* Move to old folder before deleting */
1744 save_to_folder(vms->curdir, x, vms->username, 1);
1747 for (x = vms->curmsg + 1; x<=vms->lastmsg; x++) {
1748 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1749 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1750 ast_filedelete(vms->fn, NULL);
1754 memset(vms->deleted, 0, sizeof(vms->deleted));
1755 memset(vms->heard, 0, sizeof(vms->heard));
1758 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
1760 /* Introduce messages they have */
1762 res = play_and_wait(chan, "vm-youhave");
1764 if (vms->newmessages) {
1765 res = say_and_wait(chan, vms->newmessages);
1767 res = play_and_wait(chan, "vm-INBOX");
1768 if (vms->oldmessages && !res)
1769 res = play_and_wait(chan, "vm-and");
1771 if ((vms->newmessages == 1))
1772 res = play_and_wait(chan, "vm-message");
1774 res = play_and_wait(chan, "vm-messages");
1778 if (!res && vms->oldmessages) {
1779 res = say_and_wait(chan, vms->oldmessages);
1781 res = play_and_wait(chan, "vm-Old");
1783 if (vms->oldmessages == 1)
1784 res = play_and_wait(chan, "vm-message");
1786 res = play_and_wait(chan, "vm-messages");
1790 if (!vms->oldmessages && !vms->newmessages) {
1791 res = play_and_wait(chan, "vm-no");
1793 res = play_and_wait(chan, "vm-messages");
1800 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
1803 /* Play instructions and wait for new command */
1805 if (vms->starting) {
1806 if (vms->lastmsg > -1) {
1807 res = play_and_wait(chan, "vm-onefor");
1809 res = play_and_wait(chan, vms->vmbox);
1811 res = play_and_wait(chan, "vm-messages");
1814 res = play_and_wait(chan, "vm-opts");
1817 res = play_and_wait(chan, "vm-prev");
1819 res = play_and_wait(chan, "vm-repeat");
1820 if (!res && (vms->curmsg != vms->lastmsg))
1821 res = play_and_wait(chan, "vm-next");
1823 if (!vms->deleted[vms->curmsg])
1824 res = play_and_wait(chan, "vm-delete");
1826 res = play_and_wait(chan, "vm-undelete");
1828 res = play_and_wait(chan, "vm-toforward");
1830 res = play_and_wait(chan, "vm-savemessage");
1834 res = play_and_wait(chan, "vm-helpexit");
1836 res = ast_waitfordigit(chan, 6000);
1839 if (vms->repeats > 2) {
1840 res = play_and_wait(chan, "vm-goodbye");
1849 static int vm_options(struct ast_channel *chan, struct vm_state *vms, char *fmtc)
1853 char newpassword[80] = "";
1854 char newpassword2[80] = "";
1855 char prefile[256]="";
1856 while((cmd >= 0) && (cmd != 't')) {
1861 snprintf(prefile,sizeof(prefile),"vm/%s/unavail",vms->username);
1862 cmd = play_and_record(chan,"vm-rec-unv",prefile, vms->maxgreet, fmtc);
1868 snprintf(prefile,sizeof(prefile),"vm/%s/busy",vms->username);
1869 cmd = play_and_record(chan,"vm-rec-busy",prefile, vms->maxgreet, fmtc);
1875 snprintf(prefile,sizeof(prefile),"vm/%s/greet",vms->username);
1876 cmd = play_and_record(chan,"vm-rec-name",prefile, vms->maxgreet, fmtc);
1882 newpassword[1] = '\0';
1883 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
1886 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
1889 newpassword2[1] = '\0';
1890 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
1894 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
1897 if (strcmp(newpassword, newpassword2)) {
1898 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
1899 cmd = play_and_wait(chan, "vm-mismatch");
1902 if (vm_change_password(vms->username,vms->password,newpassword) < 0)
1904 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",vms->username);
1906 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
1907 cmd = play_and_wait(chan,"vm-passchanged");
1913 cmd = play_and_wait(chan,"vm-options");
1915 cmd = ast_waitfordigit(chan,6000);
1927 static int vm_execmain(struct ast_channel *chan, void *data)
1929 /* XXX This is, admittedly, some pretty horrendus code. For some
1930 reason it just seemed a lot easier to do with GOTO's. I feel
1931 like I'm back in my GWBASIC days. XXX */
1936 struct localuser *u;
1937 char prefixstr[80] ="";
1938 char empty[80] = "";
1945 char tmp[256], *ext;
1946 char fmtc[256] = "";
1947 struct ast_config *cfg;
1948 struct vm_state vms;
1951 memset(&vms, 0, sizeof(vms));
1953 cfg = ast_load(VOICEMAIL_CONFIG);
1955 ast_log(LOG_WARNING, "No voicemail configuration\n");
1958 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1959 if (sscanf(s, "%d", &x) == 1) {
1962 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1965 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
1966 if (sscanf(s, "%d", &x) == 1) {
1969 ast_log(LOG_WARNING, "Invalid skipms value\n");
1972 if ((s = ast_variable_retrieve(cfg, "general", "format"))) {
1973 strncpy(fmtc, s, sizeof(fmtc) - 1);
1975 if (chan->_state != AST_STATE_UP)
1979 strncpy(tmp, data, sizeof(tmp) - 1);
1984 /* We should skip the user's password */
1989 /* We should prefix the mailbox with the supplied data */
1997 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1999 strncpy(vms.username, ext, sizeof(vms.username) - 1);
2000 /* make sure username passed as an option is valid */
2001 if (ast_variable_retrieve(cfg, NULL, vms.username))
2008 /* If ADSI is supported, setup login screen */
2009 adsi_begin(chan, &useadsi);
2010 if (!skipuser && useadsi)
2012 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
2013 ast_log(LOG_WARNING, "Couldn't stream login file\n");
2017 /* Authenticate them and get their mailbox/password */
2020 /* Prompt for, and read in the username */
2021 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
2022 ast_log(LOG_WARNING, "Couldn't read username\n");
2025 if (!strlen(vms.username)) {
2026 if (option_verbose > 2)
2027 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
2032 adsi_password(chan);
2033 if (ast_streamfile(chan, "vm-password", chan->language)) {
2034 ast_log(LOG_WARNING, "Unable to stream password file\n");
2037 if (ast_readstring(chan, vms.password, sizeof(vms.password) - 1, 2000, 10000, "#") < 0) {
2038 ast_log(LOG_WARNING, "Unable to read password\n");
2042 char fullusername[80] = "";
2043 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
2044 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
2045 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
2047 copy = ast_variable_retrieve(cfg, NULL, vms.username);
2050 copy = strdup(copy);
2052 strsep(&stringp, ",");
2053 if (!strcmp(vms.password,copy))
2056 if (option_verbose > 2)
2057 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", vms.password, vms.username);
2059 strncpy(vms.username, empty, sizeof(vms.username) -1);
2064 if (option_verbose > 2)
2065 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", vms.username);
2070 if (ast_streamfile(chan, "vm-incorrect", chan->language))
2073 if (ast_waitstream(chan, ""))
2080 snprintf(vms.curdir, sizeof(vms.curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", vms.username);
2081 mkdir(vms.curdir, 0700);
2082 /* Retrieve old and new message counts */
2083 open_mailbox(&vms, 1);
2084 vms.oldmessages = vms.lastmsg + 1;
2085 /* Start in INBOX */
2086 open_mailbox(&vms, 0);
2087 vms.newmessages = vms.lastmsg + 1;
2090 /* Select proper mailbox FIRST!! */
2091 if (!vms.newmessages && vms.oldmessages) {
2092 /* If we only have old messages start here */
2093 open_mailbox(&vms, 1);
2097 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2099 cmd = vm_intro(chan, &vms);
2102 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2109 if (vms.lastmsg > -1) {
2110 cmd = play_message(chan, &vms, vms.curmsg);
2112 cmd = play_and_wait(chan, "vm-youhave");
2114 cmd = play_and_wait(chan, "vm-no");
2116 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2117 cmd = play_and_wait(chan, vms.fn);
2120 cmd = play_and_wait(chan, "vm-messages");
2123 case '2': /* Change folders */
2125 adsi_folders(chan, 0, "Change to folder...");
2128 } else if (cmd > 0) {
2130 close_mailbox(&vms);
2131 open_mailbox(&vms, cmd);
2135 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2137 cmd = play_and_wait(chan, vms.vmbox);
2139 cmd = play_and_wait(chan, "vm-messages");
2145 cmd = play_message(chan, &vms, vms.curmsg);
2147 cmd = play_and_wait(chan, "vm-nomore");
2151 if (vms.curmsg < vms.lastmsg) {
2153 cmd = play_message(chan, &vms, vms.curmsg);
2155 cmd = play_and_wait(chan, "vm-nomore");
2159 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2161 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2162 if (vms.deleted[vms.curmsg])
2163 cmd = play_and_wait(chan, "vm-deleted");
2165 cmd = play_and_wait(chan, "vm-undeleted");
2168 if(vms.lastmsg > -1)
2169 cmd = forward_message(chan, cfg, vms.curdir, vms.curmsg, vms.username);
2173 adsi_folders(chan, 1, "Save to folder...");
2174 cmd = get_folder2(chan, "vm-savefolder", 1);
2175 box = 0; /* Shut up compiler */
2179 } else if (cmd > 0) {
2180 box = cmd = cmd - '0';
2181 cmd = save_to_folder(vms.curdir, vms.curmsg, vms.username, cmd);
2182 vms.deleted[vms.curmsg]=1;
2184 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2186 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2188 cmd = play_and_wait(chan, "vm-message");
2190 cmd = say_and_wait(chan, vms.curmsg + 1);
2192 cmd = play_and_wait(chan, "vm-savedto");
2194 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2195 cmd = play_and_wait(chan, vms.fn);
2198 cmd = play_and_wait(chan, "vm-messages");
2201 if (!vms.starting) {
2202 cmd = play_and_wait(chan, "vm-onefor");
2204 cmd = play_and_wait(chan, vms.vmbox);
2206 cmd = play_and_wait(chan, "vm-messages");
2208 cmd = play_and_wait(chan, "vm-opts");
2213 cmd = vm_options(chan, &vms, fmtc);
2216 ast_stopstream(chan);
2218 cmd = play_and_wait(chan, "vm-goodbye");
2222 default: /* Nothing */
2223 cmd = vm_instructions(chan, &vms);
2236 if ((res > -1) && (cmd != '#')) {
2237 ast_stopstream(chan);
2240 adsi_unload_session(chan);
2242 close_mailbox(&vms);
2246 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2248 LOCAL_USER_REMOVE(u);
2253 static int vm_exec(struct ast_channel *chan, void *data)
2255 int res=0, silent=0, busy=0, unavail=0;
2256 struct localuser *u;
2257 char tmp[256], *ext;
2260 if (chan->_state != AST_STATE_UP)
2263 strncpy(tmp, data, sizeof(tmp) - 1);
2265 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2276 } else if (*ext == 'b') {
2279 } else if (*ext == 'u') {
2285 res = leave_voicemail(chan, ext, silent, busy, unavail);
2286 LOCAL_USER_REMOVE(u);
2290 int unload_module(void)
2293 STANDARD_HANGUP_LOCALUSERS;
2294 res = ast_unregister_application(app);
2295 res |= ast_unregister_application(app2);
2299 int load_module(void)
2302 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2304 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2308 char *description(void)
2316 STANDARD_USECOUNT(res);
2322 return ASTERISK_GPL_KEY;