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>
37 #include "../asterisk.h"
38 #include "../astconf.h"
40 #define COMMAND_TIMEOUT 5000
42 #define VOICEMAIL_CONFIG "voicemail.conf"
43 #define ASTERISK_USERNAME "asterisk"
45 #define SENDMAIL "/usr/sbin/sendmail -t"
47 #define INTRO "vm-intro"
51 #define MAX_OTHER_FORMATS 10
53 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
55 #define BASEMAXINLINE 256
57 #define BASELINELEN 72
63 #define BASEMAXINLINE 256
64 #define BASELINELEN 72
69 static int linelength;
71 static unsigned char iobuf[BASEMAXINLINE];
73 static char *tdesc = "Comedian Mail (Voicemail System)";
75 static char *adapp = "CoMa";
77 static char *adsec = "_AST";
79 static char *addesc = "Comedian Mail";
83 static char *synopsis_vm =
84 "Leave a voicemail message";
86 static char *descrip_vm =
87 " VoiceMail([s|u|b]extension): Leaves voicemail for a given extension (must\n"
88 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
89 "then instructions for leaving the message will be skipped. If the extension\n"
90 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
91 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
92 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
93 "busy instead of unavail). At most one of 's', 'u', or 'b' may be specified.\n"
94 "Returns -1 on error or mailbox not found, or if the user hangs up. \n"
95 "Otherwise, it returns 0. \n";
97 static char *synopsis_vmain =
98 "Enter voicemail system";
100 static char *descrip_vmain =
101 " VoiceMailMain(): Enters the main voicemail system for the checking of\n"
102 "voicemail. The mailbox can be passed as the option, which will stop the\n"
103 "voicemail system from prompting the user for the mailbox. If the mailbox\n"
104 "is preceded by 's' then the password check will be skipped. Returns -1 if\n"
105 "the user hangs up or 0 otherwise.\n";
107 /* Leave a message */
108 static char *app = "VoiceMail";
110 /* Check mail, control, etc */
111 static char *app2 = "VoiceMailMain";
117 static int make_dir(char *dest, int len, char *ext, char *mailbox)
119 return snprintf(dest, len, "%s/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", ext, mailbox);
122 static int make_file(char *dest, int len, char *dir, int num)
124 return snprintf(dest, len, "%s/msg%04d", dir, num);
127 static int vm_change_password(char *username, char *password, char *newpassword)
129 /* There's probably a better way of doing this. */
130 /* That's why I've put the password change in a separate function. */
136 char tmpin[AST_CONFIG_MAX_PATH];
137 char tmpout[AST_CONFIG_MAX_PATH];
138 char *user, *pass, *rest, *trim;
139 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
140 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
141 configin = fopen((char *)tmpin,"r");
142 configout = fopen((char *)tmpout,"w+");
144 while (!feof(configin)) {
145 /* Read in the line */
146 fgets(inbuf, sizeof(inbuf), configin);
147 if (!feof(configin)) {
148 /* Make a backup of it */
149 memcpy(orig, inbuf, sizeof(orig));
150 /* Strip trailing \n and comment */
151 inbuf[strlen(inbuf) - 1] = '\0';
152 user = strchr(inbuf, ';');
158 pass = strchr(user, '=');
161 while(*trim && *trim < 33) {
171 while(*pass && *pass < 33)
175 rest = strchr(pass,',');
182 if (user && pass && *user && *pass && !strcmp(user, username) && !strcmp(pass, password)) {
183 /* This is the line */
185 fprintf(configout, "%s => %s,%s\n", username,newpassword,rest);
187 fprintf(configout, "%s => %s\n", username,newpassword);
190 /* Put it back like it was */
191 fprintf(configout, orig);
198 unlink((char *)tmpin);
199 rename((char *)tmpout,(char *)tmpin);
211 if ( (l = fread(iobuf,1,BASEMAXINLINE,fi)) <= 0) {
232 return iobuf[iocp++];
236 ochar(int c, FILE *so)
238 if(linelength>=BASELINELEN) {
239 if(fputs(eol,so)==EOF)
245 if(putc(((unsigned char)c),so)==EOF)
253 static int base_encode(char *filename, FILE *so)
255 unsigned char dtable[BASEMAXINLINE];
260 iocp = BASEMAXINLINE;
264 if ( !(fi = fopen(filename, "rb"))) {
265 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
273 dtable[26+i+9]= 'j'+i;
277 dtable[26+i+18]= 's'+i;
286 unsigned char igroup[3],ogroup[4];
289 igroup[0]= igroup[1]= igroup[2]= 0;
292 if ( (c = inchar(fi)) == EOF) {
297 igroup[n]= (unsigned char)c;
301 ogroup[0]= dtable[igroup[0]>>2];
302 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
303 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
304 ogroup[3]= dtable[igroup[2]&0x3F];
314 ochar(ogroup[i], so);
318 if(fputs(eol,so)==EOF)
326 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
338 struct ast_config *cfg;
339 p = popen(SENDMAIL, "w");
340 cfg = ast_load(VOICEMAIL_CONFIG);
341 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
344 gethostname(host, sizeof(host));
345 if (strchr(srcemail, '@'))
346 strncpy(who, srcemail, sizeof(who)-1);
348 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
350 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
353 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
354 fprintf(p, "Date: %s\n", date);
355 fprintf(p, "From: Asterisk PBX <%s>\n", who);
356 fprintf(p, "To: %s <%s>\n", name, email);
357 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
358 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
359 fprintf(p, "MIME-Version: 1.0\n");
360 if (ast_true(astattach)) {
362 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
364 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
366 fprintf(p, "--%s\n", bound);
368 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
369 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
370 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
372 "in mailbox %s from %s, on %s so you might\n"
373 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
374 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
375 if (ast_true(astattach)) {
376 fprintf(p, "--%s\n", bound);
377 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
378 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
379 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
380 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
382 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
383 base_encode(fname, p);
384 fprintf(p, "\n\n--%s--\n.\n", bound);
388 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
394 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration)
403 struct ast_config *cfg;
404 p = popen(SENDMAIL, "w");
405 cfg = ast_load(VOICEMAIL_CONFIG);
408 gethostname(host, sizeof(host));
409 if (strchr(srcemail, '@'))
410 strncpy(who, srcemail, sizeof(who)-1);
412 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
414 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
417 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
418 fprintf(p, "Date: %s\n", date);
419 fprintf(p, "From: Asterisk PBX <%s>\n", who);
420 fprintf(p, "To: %s\n", pager);
421 fprintf(p, "Subject: New voicemail\n\n");
422 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
423 fprintf(p, "New %s long message in mailbox %s\n"
424 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
427 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
433 static int get_date(char *s, int len)
439 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
442 static int invent_message(struct ast_channel *chan, char *ext, int busy, char *ecodes)
446 snprintf(fn, sizeof(fn), "vm/%s/greet", ext);
447 if (ast_fileexists(fn, NULL, NULL) > 0) {
448 res = ast_streamfile(chan, fn, chan->language);
451 res = ast_waitstream(chan, ecodes);
455 res = ast_streamfile(chan, "vm-theperson", chan->language);
458 res = ast_waitstream(chan, ecodes);
461 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
466 res = ast_streamfile(chan, "vm-isonphone", chan->language);
468 res = ast_streamfile(chan, "vm-isunavail", chan->language);
471 res = ast_waitstream(chan, ecodes);
475 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
477 struct ast_config *cfg;
478 char *copy, *name, *passwd, *email, *pager, *fmt, *fmts;
480 struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS];
481 char *sfmt[MAX_OTHER_FORMATS];
484 int res = -1, fmtcnt=0, x;
493 char prefile[256]="";
500 cfg = ast_load(VOICEMAIL_CONFIG);
502 ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG);
505 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
506 astemail = ASTERISK_USERNAME;
507 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
508 if (sscanf(s, "%d", &x) == 1) {
511 ast_log(LOG_WARNING, "Invalid max message time length\n");
514 if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
516 /* Setup pre-file if appropriate */
518 snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
520 snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
521 /* Make sure they have an entry in the config */
524 passwd = strsep(&stringp, ",");
525 name = strsep(&stringp, ",");
526 email = strsep(&stringp, ",");
527 pager = strsep(&stringp, ",");
528 make_dir(dir, sizeof(dir), ext, "");
529 /* It's easier just to try to make it than to check for its existence */
530 if (mkdir(dir, 0700) && (errno != EEXIST))
531 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
532 make_dir(dir, sizeof(dir), ext, "INBOX");
533 if (mkdir(dir, 0700) && (errno != EEXIST))
534 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
535 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
537 /* Play the beginning intro if desired */
538 if (strlen(prefile)) {
539 if (ast_fileexists(prefile, NULL, NULL) > 0) {
540 if (ast_streamfile(chan, prefile, chan->language) > -1)
541 silent = ast_waitstream(chan, "#0");
543 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
544 silent = invent_message(chan, ext, busy, ecodes);
547 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
552 /* If they hit "#" we should still play the beep sound */
554 if (!ast_streamfile(chan, "beep", chan->language) < 0)
556 if (ast_waitstream(chan, "") <0) {
557 ast_log(LOG_DEBUG, "Hangup during beep\n");
561 } else if (silent == '0') {
562 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
563 if (strlen(chan->macrocontext))
564 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
569 /* Stream an info message */
570 if (silent || !ast_streamfile(chan, INTRO, chan->language)) {
571 /* Wait for the message to finish */
572 if (silent || !ast_waitstream(chan, "")) {
573 if (!ast_streamfile(chan, "beep", chan->language) < 0)
575 if (ast_waitstream(chan, "") <0) {
576 ast_log(LOG_DEBUG, "Hangup during beep\n");
580 fmt = ast_variable_retrieve(cfg, "general", "format");
585 fmt = strsep(&stringp, "|");
588 make_file(fn, sizeof(fn), dir, msgnum);
589 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
590 (chan->callerid ? chan->callerid : "Unknown"),
591 name, ext, chan->name);
592 if (ast_fileexists(fn, NULL, chan->language) > 0) {
596 writer = ast_writefile(fn, fmt, comment, O_EXCL, 1 /* check for other formats */, 0700);
600 } while(!writer && (msgnum < MAXMSG));
603 /* Store information */
604 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
605 txt = fopen(txtfile, "w+");
607 get_date(date, sizeof(date));
611 "; Message Information file\n"
627 chan->callerid ? chan->callerid : "Unknown",
631 ast_log(LOG_WARNING, "Error opening text file for output\n");
633 /* We need to reset these values */
635 fmt = ast_variable_retrieve(cfg, "general", "format");
638 strsep(&stringp, "|");
639 while((fmt = strsep(&stringp, "|"))) {
640 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
641 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
644 sfmt[fmtcnt++] = strdup(fmt);
646 for (x=0;x<fmtcnt;x++) {
647 others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
649 /* Ick, the other format didn't work, but be sure not
650 to leak memory here */
652 for(y=x+1;y < fmtcnt;y++)
656 if(!strcasecmp(sfmt[x], "wav"))
661 /* Loop forever, writing the packets we read to the writer(s), until
662 we read a # or get a hangup */
663 if (option_verbose > 2)
664 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
667 res = ast_waitfor(chan, 2000);
669 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
670 /* Try one more time in case of masq */
671 res = ast_waitfor(chan, 2000);
673 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
686 if (f->frametype == AST_FRAME_VOICE) {
687 /* Write the primary format */
688 res = ast_writestream(writer, f);
690 ast_log(LOG_WARNING, "Error writing primary frame\n");
693 /* And each of the others */
694 for (x=0;x<fmtcnt;x++) {
695 res |= ast_writestream(others[x], f);
697 /* Exit on any error */
699 ast_log(LOG_WARNING, "Error writing frame\n");
703 } else if (f->frametype == AST_FRAME_DTMF) {
704 if (f->subclass == '#') {
705 if (option_verbose > 2)
706 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
715 if (maxmessage && (end - start > maxmessage)) {
716 if (option_verbose > 2)
717 ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n");
724 if (option_verbose > 2)
725 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
730 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]);
734 ast_closestream(writer);
735 for (x=0;x<fmtcnt;x++) {
738 ast_closestream(others[x]);
742 /* Let them know it worked */
743 ast_streamfile(chan, "vm-msgsaved", chan->language);
744 ast_waitstream(chan, "");
746 txt = fopen(txtfile, "a");
749 fprintf(txt, "duration=%ld\n", end-start);
752 /* Send e-mail if applicable */
754 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start);
756 sendpage(astemail, pager, msgnum, ext, chan->callerid, end - start);
760 ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
762 ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
766 ast_log(LOG_WARNING, "No format to save messages in \n");
769 ast_log(LOG_WARNING, "Unable to playback instructions\n");
773 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
775 /* Leave voicemail for someone */
776 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
780 static char *mbox(int id)
808 static int count_messages(char *dir)
812 for (x=0;x<MAXMSG;x++) {
813 make_file(fn, sizeof(fn), dir, x);
814 if (ast_fileexists(fn, NULL, NULL) < 1)
820 static int play_and_wait(struct ast_channel *chan, char *fn)
823 d = ast_streamfile(chan, fn, chan->language);
826 d = ast_waitstream(chan, AST_DIGIT_ANY);
830 static int say_and_wait(struct ast_channel *chan, int num)
833 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
837 static int copy(char *infile, char *outfile)
844 if ((ifd = open(infile, O_RDONLY)) < 0) {
845 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
848 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
849 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
854 len = read(ifd, buf, sizeof(buf));
856 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
862 res = write(ofd, buf, len);
864 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
876 static int save_to_folder(char *dir, int msg, char *username, int box)
883 char *dbox = mbox(box);
885 make_file(sfn, sizeof(sfn), dir, msg);
886 make_dir(ddir, sizeof(ddir), username, dbox);
888 for (x=0;x<MAXMSG;x++) {
889 make_file(dfn, sizeof(dfn), ddir, x);
890 if (ast_fileexists(dfn, NULL, NULL) < 0)
895 ast_filecopy(sfn, dfn, NULL);
896 if (strcmp(sfn, dfn)) {
897 snprintf(txt, sizeof(txt), "%s.txt", sfn);
898 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
904 static int adsi_logo(unsigned char *buf)
907 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
908 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
912 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
920 bytes += adsi_data_mode(buf + bytes);
921 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
924 bytes += adsi_logo(buf);
925 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
927 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
929 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
930 bytes += adsi_data_mode(buf + bytes);
931 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
933 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
935 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
936 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
937 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
938 bytes += adsi_voice_mode(buf + bytes, 0);
939 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
946 bytes += adsi_logo(buf);
947 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
948 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
949 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
950 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
953 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
954 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
955 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
956 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
957 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
958 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
959 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
962 /* Add another dot */
964 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
965 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
966 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
970 /* These buttons we load but don't use yet */
971 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
972 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
973 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
974 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
975 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
976 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
977 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
980 /* Add another dot */
982 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
983 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
984 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
989 snprintf(num, sizeof(num), "%d", x);
990 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
992 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
993 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
996 /* Add another dot */
998 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
999 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1000 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1003 if (adsi_end_download(chan)) {
1005 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1006 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1007 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1008 bytes += adsi_voice_mode(buf + bytes, 0);
1009 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1013 bytes += adsi_download_disconnect(buf + bytes);
1014 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1016 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1021 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1022 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1024 ast_log(LOG_DEBUG, "Restarting session...\n");
1027 /* Load the session now */
1028 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1030 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1032 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1034 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1038 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1041 if (!adsi_available(chan))
1043 x = adsi_load_session(chan, adapp, adver, 1);
1047 if (adsi_load_vmail(chan, useadsi)) {
1048 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1055 static void adsi_login(struct ast_channel *chan)
1059 unsigned char keys[8];
1061 if (!adsi_available(chan))
1066 /* Set one key for next */
1067 keys[3] = ADSI_KEY_APPS + 3;
1069 bytes += adsi_logo(buf + bytes);
1070 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1071 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1072 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1073 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1074 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1075 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1076 bytes += adsi_set_keys(buf + bytes, keys);
1077 bytes += adsi_voice_mode(buf + bytes, 0);
1078 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1081 static void adsi_password(struct ast_channel *chan)
1085 unsigned char keys[8];
1087 if (!adsi_available(chan))
1092 /* Set one key for next */
1093 keys[3] = ADSI_KEY_APPS + 3;
1095 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1096 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1097 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1098 bytes += adsi_set_keys(buf + bytes, keys);
1099 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1102 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1106 unsigned char keys[8];
1109 if (!adsi_available(chan))
1113 y = ADSI_KEY_APPS + 12 + start + x;
1114 if (y > ADSI_KEY_APPS + 12 + 4)
1116 keys[x] = ADSI_KEY_SKT | y;
1118 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1122 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1123 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1124 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1125 bytes += adsi_set_keys(buf + bytes, keys);
1126 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1129 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1132 char buf[256], buf1[256], buf2[256];
1137 char datetime[21]="";
1140 unsigned char keys[8];
1144 if (!adsi_available(chan))
1147 /* Retrieve important info */
1148 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1149 f = fopen(fn2, "r");
1152 fgets(buf, sizeof(buf), f);
1156 strsep(&stringp, "=");
1157 val = strsep(&stringp, "=");
1158 if (val && strlen(val)) {
1159 if (!strcmp(buf, "callerid"))
1160 strncpy(cid, val, sizeof(cid) - 1);
1161 if (!strcmp(buf, "origdate"))
1162 strncpy(datetime, val, sizeof(datetime) - 1);
1168 /* New meaning for keys */
1170 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1175 /* No prev key, provide "Folder" instead */
1176 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1179 /* If last message ... */
1181 /* but not only message, provide "Folder" instead */
1182 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1184 /* Otherwise if only message, leave blank */
1190 ast_callerid_parse(cid, &name, &num);
1194 name = "Unknown Caller";
1196 /* If deleted, show "undeleted" */
1198 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1201 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1202 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1203 strcasecmp(folder, "INBOX") ? " Messages" : "");
1204 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1206 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1207 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1208 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1209 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1210 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1211 bytes += adsi_set_keys(buf + bytes, keys);
1212 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1215 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1219 unsigned char keys[8];
1223 if (!adsi_available(chan))
1226 /* New meaning for keys */
1228 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1234 /* No prev key, provide "Folder" instead */
1235 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1238 /* If last message ... */
1240 /* but not only message, provide "Folder" instead */
1241 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1243 /* Otherwise if only message, leave blank */
1248 /* If deleted, show "undeleted" */
1250 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1253 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1254 bytes += adsi_set_keys(buf + bytes, keys);
1255 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1258 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1260 char buf[256], buf1[256], buf2[256];
1262 unsigned char keys[8];
1265 char *newm = (new == 1) ? "message" : "messages";
1266 char *oldm = (old == 1) ? "message" : "messages";
1267 if (!adsi_available(chan))
1270 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1272 strcat(buf1, " and");
1273 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1275 snprintf(buf2, sizeof(buf2), "%s.", newm);
1278 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1279 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1281 strcpy(buf1, "You have no messages.");
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_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1289 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1293 /* Don't let them listen if there are none */
1296 bytes += adsi_set_keys(buf + bytes, keys);
1298 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1301 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1303 char buf[256], buf1[256], buf2[256];
1305 unsigned char keys[8];
1308 char *mess = (messages == 1) ? "message" : "messages";
1310 if (!adsi_available(chan))
1313 /* Original command keys */
1315 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1323 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1324 strcasecmp(folder, "INBOX") ? " folder" : "");
1327 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1329 strcpy(buf2, "no messages.");
1330 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1331 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1332 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1333 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1334 bytes += adsi_set_keys(buf + bytes, keys);
1336 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1340 static void adsi_clear(struct ast_channel *chan)
1344 if (!adsi_available(chan))
1346 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1347 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1350 static void adsi_goodbye(struct ast_channel *chan)
1355 if (!adsi_available(chan))
1357 bytes += adsi_logo(buf + bytes);
1358 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1359 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1360 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1361 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1364 static int get_folder(struct ast_channel *chan, int start)
1369 d = play_and_wait(chan, "vm-press");
1372 for (x = start; x< 5; x++) {
1373 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1375 d = play_and_wait(chan, "vm-for");
1378 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1379 d = play_and_wait(chan, fn);
1382 d = play_and_wait(chan, "vm-messages");
1385 d = ast_waitfordigit(chan, 500);
1389 d = play_and_wait(chan, "vm-tocancel");
1392 d = ast_waitfordigit(chan, 4000);
1397 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg, char* myusername)
1404 struct ast_config *mif;
1406 char *copy, *name, *passwd, *email, *pager;
1407 char *mycopy, *myname, *mypasswd, *myemail, *mypager;
1413 ast_streamfile(chan, "vm-extension", chan->language);
1415 if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)
1417 if (ast_variable_retrieve(cfg, NULL, username)) {
1418 printf("Got %d\n", atoi(username));
1419 /* if (play_and_wait(chan, "vm-savedto"))
1423 snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1424 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1428 todircount = count_messages(todir);
1430 snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1434 /* TODO: use config to determine what other formats to copy the message in */
1435 snprintf(sys, sizeof(sys), "cp %s/msg%04d.wav %s/msg%04d.wav\n", dir, curmsg, todir, todircount);
1439 /* copy the message information file too */
1440 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
1444 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1446 /* load the information on the source message so we can send an e-mail like a new message */
1447 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1448 if ((mif=ast_load(miffile))) {
1450 /* send an e-mail like it was a new message if appropriate */
1451 if ((copy = ast_variable_retrieve(cfg, NULL, username))) {
1453 /* Make sure they have an entry in the config */
1454 copy = strdup(copy);
1456 passwd = strsep(&stringp, ",");
1457 name = strsep(&stringp, ",");
1458 email = strsep(&stringp, ",");
1459 pager = strsep(&stringp, ",");
1462 if ((mycopy = ast_variable_retrieve(cfg, NULL, myusername))) {
1463 char *mystringp=NULL;
1464 /* Make sure they have an entry in the config */
1465 mycopy = strdup(mycopy);
1467 mypasswd = strsep(&mystringp, ",");
1468 myname = strsep(&mystringp, ",");
1469 myemail = strsep(&mystringp, ",");
1470 mypager = strsep(&mystringp, ",");
1473 /* set the outbound email from address */
1474 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
1475 astemail = ASTERISK_USERNAME;
1477 /* set callerid and duration variables */
1478 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", myname, ast_variable_retrieve(mif, NULL, "callerid"));
1479 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1482 sendmail(astemail, email, name, todircount, username, callerid, fn, "wav", atol(ast_variable_retrieve(mif, NULL, "duration")));
1485 sendpage(astemail, pager, todircount, username, callerid, duration);
1487 free(copy); /* no leaks here */
1488 free(mycopy); /* or here */
1489 ast_destroy(mif); /* or here */
1492 /* give confirmatopm that the message was saved */
1493 if (play_and_wait(chan, "vm-message")) break;
1494 if (play_and_wait(chan, "vm-saved")) break;
1498 if ( play_and_wait(chan, "pbx-invalid"))
1505 #define WAITCMD(a) do { \
1513 #define WAITFILE2(file) do { \
1514 if (ast_streamfile(chan, file, chan->language)) \
1515 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1516 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1522 #define WAITFILE(file) do { \
1523 if (ast_streamfile(chan, file, chan->language)) \
1524 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1525 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) { \
1526 if (sscanf(s, "%d", &x) == 1) \
1529 d = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",ms); \
1532 goto instructions; \
1533 } else if (d < 0) { \
1538 #define PLAYMSG(a) do { \
1540 make_file(fn, sizeof(fn), curdir, a); \
1541 adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1543 WAITFILE2("vm-first"); \
1544 else if (a == lastmsg) \
1545 WAITFILE2("vm-last"); \
1546 WAITFILE2("vm-message"); \
1547 if (a && (a != lastmsg)) { \
1548 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1549 if (d < 0) goto out; \
1552 make_file(fn, sizeof(fn), curdir, a); \
1557 #define CLOSE_MAILBOX do { \
1558 if (lastmsg > -1) { \
1559 /* Get the deleted messages fixed */ \
1561 for (x=0;x<=lastmsg;x++) { \
1562 if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1563 /* Save this message. It's not in INBOX or hasn't been heard */ \
1565 make_file(fn, sizeof(fn), curdir, x); \
1566 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1567 if (strcmp(fn, fn2)) { \
1568 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1569 snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1570 ast_filerename(fn, fn2, NULL); \
1571 rename(txt, ntxt); \
1573 } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1574 /* Move to old folder before deleting */ \
1575 save_to_folder(curdir, x, username, 1); \
1578 for (x = curmsg + 1; x<=lastmsg; x++) { \
1579 make_file(fn, sizeof(fn), curdir, x); \
1580 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1581 ast_filedelete(fn, NULL); \
1585 memset(deleted, 0, sizeof(deleted)); \
1586 memset(heard, 0, sizeof(heard)); \
1589 #define OPEN_MAILBOX(a) do { \
1590 strcpy(curbox, mbox(a)); \
1591 make_dir(curdir, sizeof(curdir), username, curbox); \
1592 lastmsg = count_messages(curdir) - 1; \
1593 snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1596 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime)
1598 char d, *fmt, *fmts;
1600 int x, fmtcnt=1, res=-1,outmsg=0, wavother=0;
1601 struct ast_frame *f;
1602 struct ast_config *cfg;
1603 struct ast_filestream *others[MAX_OTHER_FORMATS];
1604 char *sfmt[MAX_OTHER_FORMATS];
1609 ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile);
1610 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name);
1612 d = play_and_wait(chan, playfile);
1615 ast_streamfile(chan, "beep",chan->language);
1616 ast_waitstream(chan,"");
1617 cfg = ast_load(VOICEMAIL_CONFIG);
1619 fmt = ast_variable_retrieve(cfg, "general", "format");
1620 ast_log(LOG_DEBUG,"Recording Formats: fmt=%s\n", fmt);
1627 strsep(&stringp, "|");
1628 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1629 sfmt[0] = strdup(fmts);
1631 while((fmt = strsep(&stringp, "|"))) {
1632 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1633 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1636 sfmt[fmtcnt++] = strdup(fmt);
1641 for (x=0;x<fmtcnt;x++) {
1642 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
1643 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s\n", x, recordfile, sfmt[x]);
1646 /* Ick, the other format didn't work, but be sure not
1647 to leak memory here */
1649 for(y=x+1;y < fmtcnt;y++)
1653 if(!strcasecmp(sfmt[x], "wav"))
1658 /* Loop forever, writing the packets we read to the writer(s), until
1659 we read a # or get a hangup */
1662 res = ast_waitfor(chan, 2000);
1664 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1665 /* Try one more time in case of masq */
1666 res = ast_waitfor(chan, 2000);
1668 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1681 if (f->frametype == AST_FRAME_VOICE) {
1682 /* write each format */
1683 for (x=0;x<fmtcnt;x++) {
1684 res = ast_writestream(others[x], f);
1686 /* Exit on any error */
1688 ast_log(LOG_WARNING, "Error writing frame\n");
1692 } else if (f->frametype == AST_FRAME_DTMF) {
1693 if (f->subclass == '#') {
1694 if (option_verbose > 2)
1695 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1702 if (maxtime < (end - start)) {
1703 if (option_verbose > 2)
1704 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1712 if (option_verbose > 2)
1713 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1718 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1722 for (x=0;x<fmtcnt;x++) {
1725 ast_closestream(others[x]);
1729 /* Let them know it worked */
1730 ast_streamfile(chan, "vm-msgsaved", chan->language);
1731 ast_waitstream(chan, "");
1742 static int vm_execmain(struct ast_channel *chan, void *data)
1744 /* XXX This is, admittedly, some pretty horrendus code. For some
1745 reason it just seemed a lot easier to do with GOTO's. I feel
1746 like I'm back in my GWBASIC days. XXX */
1751 struct localuser *u;
1752 char username[80] ="";
1753 char prefixstr[80] ="";
1754 char empty[80] = "";
1755 char password[80] = "", *copy;
1756 char newpassword[80] = "";
1757 char newpassword2[80] = "";
1758 char curbox[80] = "";
1759 char curdir[256] = "";
1760 char vmbox[256] = "";
1763 char prefile[256]="";
1765 char ntxt[256] = "";
1767 int deleted[MAXMSG] = { 0, };
1768 int heard[MAXMSG] = { 0, };
1781 char tmp[256], *ext;
1782 struct ast_config *cfg;
1785 cfg = ast_load(VOICEMAIL_CONFIG);
1787 ast_log(LOG_WARNING, "No voicemail configuration\n");
1790 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1791 if (sscanf(s, "%d", &x) == 1) {
1794 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1797 if (chan->_state != AST_STATE_UP)
1801 strncpy(tmp, data, sizeof(tmp) - 1);
1806 /* We should skip the user's password */
1811 /* We should prefix the mailbox with the supplied data */
1819 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1821 strncpy(username, ext, sizeof(username) - 1);
1822 /* make sure username passed as an option is valid */
1823 if (ast_variable_retrieve(cfg, NULL, username))
1830 /* If ADSI is supported, setup login screen */
1831 adsi_begin(chan, &useadsi);
1832 if (!skipuser && useadsi)
1834 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1835 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1839 /* Authenticate them and get their mailbox/password */
1842 /* Prompt for, and read in the username */
1843 if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) {
1844 ast_log(LOG_WARNING, "Couldn't read username\n");
1847 if (!strlen(username)) {
1848 if (option_verbose > 2)
1849 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1854 adsi_password(chan);
1855 if (ast_streamfile(chan, "vm-password", chan->language)) {
1856 ast_log(LOG_WARNING, "Unable to stream password file\n");
1859 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1860 ast_log(LOG_WARNING, "Unable to read password\n");
1864 char fullusername[80] = "";
1865 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1866 strncat(fullusername, username, sizeof(fullusername) - 1);
1867 strncpy(username, fullusername, sizeof(username) - 1);
1869 copy = ast_variable_retrieve(cfg, NULL, username);
1872 copy = strdup(copy);
1874 strsep(&stringp, ",");
1875 if (!strcmp(password,copy))
1878 if (option_verbose > 2)
1879 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1881 strncpy(username, empty, sizeof(username) -1);
1886 if (option_verbose > 2)
1887 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1892 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1895 if (ast_waitstream(chan, ""))
1902 snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1903 mkdir(curdir, 0700);
1905 oldmessages = lastmsg + 1;
1906 /* Start in INBOX */
1908 newmessages = lastmsg + 1;
1911 /* Select proper mailbox FIRST!! */
1912 if (!newmessages && oldmessages) {
1913 /* If we only have old messages start here */
1918 adsi_status(chan, newmessages, oldmessages, lastmsg);
1920 WAITCMD(play_and_wait(chan, "vm-youhave"));
1922 WAITCMD(say_and_wait(chan, newmessages));
1923 WAITCMD(play_and_wait(chan, "vm-INBOX"));
1926 WAITCMD(play_and_wait(chan, "vm-and"));
1928 if (newmessages == 1)
1929 WAITCMD(play_and_wait(chan, "vm-message"));
1931 WAITCMD(play_and_wait(chan, "vm-messages"));
1936 WAITCMD(say_and_wait(chan, oldmessages));
1937 WAITCMD(play_and_wait(chan, "vm-Old"));
1938 if (oldmessages == 1)
1939 WAITCMD(play_and_wait(chan, "vm-message"));
1941 WAITCMD(play_and_wait(chan, "vm-messages"));
1943 if (!oldmessages && !newmessages) {
1944 WAITCMD(play_and_wait(chan, "vm-no"));
1945 WAITCMD(play_and_wait(chan, "vm-messages"));
1952 WAITCMD(play_and_wait(chan, "vm-onefor"));
1953 WAITCMD(play_and_wait(chan, vmbox));
1954 WAITCMD(play_and_wait(chan, "vm-messages"));
1956 WAITCMD(play_and_wait(chan, "vm-opts"));
1959 WAITCMD(play_and_wait(chan, "vm-prev"));
1960 WAITCMD(play_and_wait(chan, "vm-repeat"));
1961 if (curmsg != lastmsg)
1962 WAITCMD(play_and_wait(chan, "vm-next"));
1963 if (!deleted[curmsg])
1964 WAITCMD(play_and_wait(chan, "vm-delete"));
1966 WAITCMD(play_and_wait(chan, "vm-undelete"));
1967 WAITCMD(play_and_wait(chan, "vm-toforward"));
1968 WAITCMD(play_and_wait(chan, "vm-savemessage"));
1970 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1971 d = ast_waitfordigit(chan, 6000);
1977 play_and_wait(chan, "vm-goodbye");
1986 adsi_folders(chan, 0, "Change to folder...");
1987 box = play_and_wait(chan, "vm-changeto");
1990 while((box < '0') || (box > '9')) {
1991 box = get_folder(chan, 0);
2001 adsi_status2(chan, curbox, lastmsg + 1);
2002 WAITCMD(play_and_wait(chan, vmbox));
2003 WAITCMD(play_and_wait(chan, "vm-messages"));
2011 WAITCMD(play_and_wait(chan, "vm-nomore"));
2021 WAITCMD(play_and_wait(chan, "vm-youhave"));
2022 WAITCMD(play_and_wait(chan, "vm-no"));
2023 snprintf(fn, sizeof(fn), "vm-%s", curbox);
2024 WAITCMD(play_and_wait(chan, fn));
2025 WAITCMD(play_and_wait(chan, "vm-messages"));
2029 if (curmsg < lastmsg) {
2033 WAITCMD(play_and_wait(chan, "vm-nomore"));
2037 deleted[curmsg] = !deleted[curmsg];
2039 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
2040 if (deleted[curmsg])
2041 WAITCMD(play_and_wait(chan, "vm-deleted"));
2043 WAITCMD(play_and_wait(chan, "vm-undeleted"));
2047 if(forward_message(chan, cfg, curdir, curmsg, username) < 0)
2052 adsi_folders(chan, 1, "Save to folder...");
2053 box = play_and_wait(chan, "vm-savefolder");
2056 while((box < '1') || (box > '9')) {
2057 box = get_folder(chan, 1);
2065 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
2066 if (save_to_folder(curdir, curmsg, username, box))
2069 make_file(fn, sizeof(fn), curdir, curmsg);
2071 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
2072 WAITCMD(play_and_wait(chan, "vm-message"));
2073 WAITCMD(say_and_wait(chan, curmsg + 1) );
2074 WAITCMD(play_and_wait(chan, "vm-savedto"));
2075 snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
2076 WAITCMD(play_and_wait(chan, fn));
2077 WAITCMD(play_and_wait(chan, "vm-messages"));
2081 WAITCMD(play_and_wait(chan, "vm-onefor"));
2082 WAITCMD(play_and_wait(chan, vmbox));
2083 WAITCMD(play_and_wait(chan, "vm-messages"));
2084 WAITCMD(play_and_wait(chan, "vm-opts"));
2088 ast_stopstream(chan);
2090 play_and_wait(chan, "vm-goodbye");
2105 ast_stopstream(chan);
2109 adsi_unload_session(chan);
2111 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
2113 LOCAL_USER_REMOVE(u);
2117 d = play_and_wait(chan,"vm-options");
2119 d = ast_waitfordigit(chan,6000);
2125 snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username);
2126 play_and_record(chan,"vm-rec-unv",prefile, maxgreet);
2129 snprintf(prefile,sizeof(prefile),"vm/%s/busy",username);
2130 play_and_record(chan,"vm-rec-busy",prefile, maxgreet);
2133 snprintf(prefile,sizeof(prefile),"vm/%s/greet",username);
2134 play_and_record(chan,"vm-rec-name",prefile, maxgreet);
2137 newpassword[1] = '\0';
2138 newpassword[0] = play_and_wait(chan,"vm-newpassword");
2139 if (ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#") < 0) {
2140 play_and_wait(chan, "vm-sorry");
2141 ast_log(LOG_NOTICE,"Unable to read new password\n");
2144 newpassword2[1] = '\0';
2145 newpassword2[0] = play_and_wait(chan,"vm-reenterpassword");
2147 if (ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#") < 0) {
2148 play_and_wait(chan, "vm-sorry");
2149 ast_log(LOG_NOTICE,"Unable to read re-entered password\n");
2152 if (strcmp(newpassword, newpassword2)) {
2153 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", username, newpassword, newpassword2);
2154 play_and_wait(chan, "vm-mismatch");
2157 if (vm_change_password(username,password,newpassword) < 0)
2159 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",username);
2161 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",username,newpassword,strlen(newpassword));
2162 play_and_wait(chan,"vm-passchanged");
2173 static int vm_exec(struct ast_channel *chan, void *data)
2175 int res=0, silent=0, busy=0, unavail=0;
2176 struct localuser *u;
2177 char tmp[256], *ext;
2180 if (chan->_state != AST_STATE_UP)
2183 strncpy(tmp, data, sizeof(tmp) - 1);
2185 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2195 } else if (*ext == 'b') {
2198 } else if (*ext == 'u') {
2202 res = leave_voicemail(chan, ext, silent, busy, unavail);
2203 LOCAL_USER_REMOVE(u);
2207 int unload_module(void)
2210 STANDARD_HANGUP_LOCALUSERS;
2211 res = ast_unregister_application(app);
2212 res |= ast_unregister_application(app2);
2216 int load_module(void)
2219 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2221 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2225 char *description(void)
2233 STANDARD_USECOUNT(res);
2239 return ASTERISK_GPL_KEY;