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
71 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 voicemail. The mailbox\n"
102 "can be passed as the option, which will stop the voicemail system from prompting the user\n"
103 "for the mailbox. If the mailbox is preceeded by 's' then the passsword check will be skipped.\n"
104 "Returns -1 if the user hangs up or 0 otherwise.\n";
106 /* Leave a message */
107 static char *app = "VoiceMail";
109 /* Check mail, control, etc */
110 static char *app2 = "VoiceMailMain";
116 static int make_dir(char *dest, int len, char *ext, char *mailbox)
118 return snprintf(dest, len, "%s/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", ext, mailbox);
121 static int make_file(char *dest, int len, char *dir, int num)
123 return snprintf(dest, len, "%s/msg%04d", dir, num);
126 static int vm_change_password(char *username, char *password, char *newpassword)
128 /* There's probably a better way of doing this. */
129 /* That's why I've put the password change in a separate function. */
135 char tmpin[AST_CONFIG_MAX_PATH];
136 char tmpout[AST_CONFIG_MAX_PATH];
137 char *user, *pass, *rest, *trim;
138 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
139 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
140 configin = fopen((char *)tmpin,"r");
141 configout = fopen((char *)tmpout,"w+");
143 while (!feof(configin)) {
144 /* Read in the line */
145 fgets(inbuf, sizeof(inbuf), configin);
146 if (!feof(configin)) {
147 /* Make a backup of it */
148 memcpy(orig, inbuf, sizeof(orig));
149 /* Strip trailing \n and comment */
150 inbuf[strlen(inbuf) - 1] = '\0';
151 user = strchr(inbuf, ';');
157 pass = strchr(user, '=');
160 while(*trim && *trim < 33) {
170 while(*pass && *pass < 33)
174 rest = strchr(pass,',');
181 if (user && pass && *user && *pass && !strcmp(user, username) && !strcmp(pass, password)) {
182 /* This is the line */
184 fprintf(configout, "%s => %s,%s\n", username,newpassword,rest);
186 fprintf(configout, "%s => %s\n", username,newpassword);
189 /* Put it back like it was */
190 fprintf(configout, orig);
197 unlink((char *)tmpin);
198 rename((char *)tmpout,(char *)tmpin);
210 if ( (l = fread(iobuf,1,BASEMAXINLINE,fi)) <= 0) {
231 return iobuf[iocp++];
235 ochar(int c, FILE *so)
237 if(linelength>=BASELINELEN) {
238 if(fputs(eol,so)==EOF)
244 if(putc(((unsigned char)c),so)==EOF)
252 static int base_encode(char *filename, FILE *so)
254 unsigned char dtable[BASEMAXINLINE];
259 iocp = BASEMAXINLINE;
263 if ( !(fi = fopen(filename, "rb"))) {
264 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
272 dtable[26+i+9]= 'j'+i;
276 dtable[26+i+18]= 's'+i;
285 unsigned char igroup[3],ogroup[4];
288 igroup[0]= igroup[1]= igroup[2]= 0;
291 if ( (c = inchar(fi)) == EOF) {
296 igroup[n]= (unsigned char)c;
300 ogroup[0]= dtable[igroup[0]>>2];
301 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
302 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
303 ogroup[3]= dtable[igroup[2]&0x3F];
313 ochar(ogroup[i], so);
317 if(fputs(eol,so)==EOF)
325 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
337 struct ast_config *cfg;
338 p = popen(SENDMAIL, "w");
339 cfg = ast_load(VOICEMAIL_CONFIG);
340 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
343 gethostname(host, sizeof(host));
344 if (strchr(srcemail, '@'))
345 strncpy(who, srcemail, sizeof(who)-1);
347 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
349 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
352 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", tm);
353 fprintf(p, "Date: %s\n", date);
354 fprintf(p, "From: Asterisk PBX <%s>\n", who);
355 fprintf(p, "To: %s <%s>\n", name, email);
356 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
357 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
358 fprintf(p, "MIME-Version: 1.0\n");
359 if (ast_true(astattach)) {
361 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
363 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
365 fprintf(p, "--%s\n", bound);
367 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
368 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm);
369 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
371 "in mailbox %s from %s, on %s so you might\n"
372 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
373 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
374 if (ast_true(astattach)) {
375 fprintf(p, "--%s\n", bound);
376 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
377 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
378 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
379 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
381 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
382 base_encode(fname, p);
383 fprintf(p, "\n\n--%s--\n.\n", bound);
387 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
393 static int get_date(char *s, int len)
399 return strftime(s, len, "%a %b %e %r %Z %Y", tm);
402 static int invent_message(struct ast_channel *chan, char *ext, int busy, char *ecodes)
406 snprintf(fn, sizeof(fn), "vm/%s/greet", ext);
407 if (ast_fileexists(fn, NULL, NULL) > 0) {
408 res = ast_streamfile(chan, fn, chan->language);
411 res = ast_waitstream(chan, ecodes);
415 res = ast_streamfile(chan, "vm-theperson", chan->language);
418 res = ast_waitstream(chan, ecodes);
421 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
426 res = ast_streamfile(chan, "vm-isonphone", chan->language);
428 res = ast_streamfile(chan, "vm-isunavail", chan->language);
431 res = ast_waitstream(chan, ecodes);
435 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
437 struct ast_config *cfg;
438 char *copy, *name, *passwd, *email, *fmt, *fmts;
440 struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS];
441 char *sfmt[MAX_OTHER_FORMATS];
444 int res = -1, fmtcnt=0, x;
453 char prefile[256]="";
460 cfg = ast_load(VOICEMAIL_CONFIG);
462 ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG);
465 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
466 astemail = ASTERISK_USERNAME;
467 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
468 if (sscanf(s, "%d", &x) == 1) {
471 ast_log(LOG_WARNING, "Invalid max message time length\n");
474 if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
476 /* Setup pre-file if appropriate */
478 snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
480 snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
481 /* Make sure they have an entry in the config */
484 passwd = strsep(&stringp, ",");
485 name = strsep(&stringp, ",");
486 email = strsep(&stringp, ",");
487 make_dir(dir, sizeof(dir), ext, "");
488 /* It's easier just to try to make it than to check for its existence */
489 if (mkdir(dir, 0700) && (errno != EEXIST))
490 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
491 make_dir(dir, sizeof(dir), ext, "INBOX");
492 if (mkdir(dir, 0700) && (errno != EEXIST))
493 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
494 if (ast_exists_extension(chan, chan->context, "o", 1, chan->callerid))
496 /* Play the beginning intro if desired */
497 if (strlen(prefile)) {
498 if (ast_fileexists(prefile, NULL, NULL) > 0) {
499 if (ast_streamfile(chan, prefile, chan->language) > -1)
500 silent = ast_waitstream(chan, "#0");
502 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
503 silent = invent_message(chan, ext, busy, ecodes);
506 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
511 /* If they hit "#" we should still play the beep sound */
513 if (!ast_streamfile(chan, "beep", chan->language) < 0)
515 if (ast_waitstream(chan, "") <0) {
516 ast_log(LOG_DEBUG, "Hangup during beep\n");
520 } else if (silent == '0') {
521 strncpy(chan->exten, "0", sizeof(chan->exten) - 1);
526 /* Stream an info message */
527 if (silent || !ast_streamfile(chan, INTRO, chan->language)) {
528 /* Wait for the message to finish */
529 if (silent || !ast_waitstream(chan, "")) {
530 if (!ast_streamfile(chan, "beep", chan->language) < 0)
532 if (ast_waitstream(chan, "") <0) {
533 ast_log(LOG_DEBUG, "Hangup during beep\n");
537 fmt = ast_variable_retrieve(cfg, "general", "format");
542 fmt = strsep(&stringp, "|");
545 make_file(fn, sizeof(fn), dir, msgnum);
546 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
547 (chan->callerid ? chan->callerid : "Unknown"),
548 name, ext, chan->name);
549 if (ast_fileexists(fn, NULL, chan->language) > 0) {
553 writer = ast_writefile(fn, fmt, comment, O_EXCL, 1 /* check for other formats */, 0700);
557 } while(!writer && (msgnum < MAXMSG));
560 /* Store information */
561 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
562 txt = fopen(txtfile, "w+");
564 get_date(date, sizeof(date));
568 "; Message Information file\n"
584 chan->callerid ? chan->callerid : "Unknown",
588 ast_log(LOG_WARNING, "Error opening text file for output\n");
590 /* We need to reset these values */
592 fmt = ast_variable_retrieve(cfg, "general", "format");
595 strsep(&stringp, "|");
596 while((fmt = strsep(&stringp, "|"))) {
597 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
598 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
601 sfmt[fmtcnt++] = strdup(fmt);
603 for (x=0;x<fmtcnt;x++) {
604 others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
606 /* Ick, the other format didn't work, but be sure not
607 to leak memory here */
609 for(y=x+1;y < fmtcnt;y++)
613 if(!strcasecmp(sfmt[x], "wav"))
618 /* Loop forever, writing the packets we read to the writer(s), until
619 we read a # or get a hangup */
620 if (option_verbose > 2)
621 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
624 res = ast_waitfor(chan, 2000);
626 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
627 /* Try one more time in case of masq */
628 res = ast_waitfor(chan, 2000);
630 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
643 if (f->frametype == AST_FRAME_VOICE) {
644 /* Write the primary format */
645 res = ast_writestream(writer, f);
647 ast_log(LOG_WARNING, "Error writing primary frame\n");
650 /* And each of the others */
651 for (x=0;x<fmtcnt;x++) {
652 res |= ast_writestream(others[x], f);
654 /* Exit on any error */
656 ast_log(LOG_WARNING, "Error writing frame\n");
660 } else if (f->frametype == AST_FRAME_DTMF) {
661 if (f->subclass == '#') {
662 if (option_verbose > 2)
663 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
672 if (maxmessage && (end - start > maxmessage)) {
673 if (option_verbose > 2)
674 ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n");
681 if (option_verbose > 2)
682 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
687 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]);
691 ast_closestream(writer);
692 for (x=0;x<fmtcnt;x++) {
695 ast_closestream(others[x]);
699 /* Let them know it worked */
700 ast_streamfile(chan, "vm-msgsaved", chan->language);
701 ast_waitstream(chan, "");
703 txt = fopen(txtfile, "a");
706 fprintf(txt, "duration=%ld\n", end-start);
709 /* Send e-mail if applicable */
711 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start);
715 ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
717 ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
721 ast_log(LOG_WARNING, "No format to save messages in \n");
724 ast_log(LOG_WARNING, "Unable to playback instructions\n");
728 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
730 /* Leave voicemail for someone */
731 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
735 static char *mbox(int id)
763 static int count_messages(char *dir)
767 for (x=0;x<MAXMSG;x++) {
768 make_file(fn, sizeof(fn), dir, x);
769 if (ast_fileexists(fn, NULL, NULL) < 1)
775 static int play_and_wait(struct ast_channel *chan, char *fn)
778 d = ast_streamfile(chan, fn, chan->language);
781 d = ast_waitstream(chan, AST_DIGIT_ANY);
785 static int say_and_wait(struct ast_channel *chan, int num)
788 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
792 static int copy(char *infile, char *outfile)
799 if ((ifd = open(infile, O_RDONLY)) < 0) {
800 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
803 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
804 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
809 len = read(ifd, buf, sizeof(buf));
811 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
817 res = write(ofd, buf, len);
819 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
831 static int save_to_folder(char *dir, int msg, char *username, int box)
838 char *dbox = mbox(box);
840 make_file(sfn, sizeof(sfn), dir, msg);
841 make_dir(ddir, sizeof(ddir), username, dbox);
843 for (x=0;x<MAXMSG;x++) {
844 make_file(dfn, sizeof(dfn), ddir, x);
845 if (ast_fileexists(dfn, NULL, NULL) < 0)
850 ast_filecopy(sfn, dfn, NULL);
851 if (strcmp(sfn, dfn)) {
852 snprintf(txt, sizeof(txt), "%s.txt", sfn);
853 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
859 static int adsi_logo(unsigned char *buf)
862 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
863 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
867 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
875 bytes += adsi_data_mode(buf + bytes);
876 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
879 bytes += adsi_logo(buf);
880 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
882 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
884 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
885 bytes += adsi_data_mode(buf + bytes);
886 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
888 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
890 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
891 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
892 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
893 bytes += adsi_voice_mode(buf + bytes, 0);
894 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
901 bytes += adsi_logo(buf);
902 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
903 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
904 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
905 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
908 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
909 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
910 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
911 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
912 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
913 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
914 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
917 /* Add another dot */
919 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
920 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
921 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
925 /* These buttons we load but don't use yet */
926 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
927 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
928 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
929 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
930 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
931 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
932 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
935 /* Add another dot */
937 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
938 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
939 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
944 snprintf(num, sizeof(num), "%d", x);
945 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
947 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
948 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
951 /* Add another dot */
953 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
954 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
955 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
958 if (adsi_end_download(chan)) {
960 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
961 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
962 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
963 bytes += adsi_voice_mode(buf + bytes, 0);
964 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
968 bytes += adsi_download_disconnect(buf + bytes);
969 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
971 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
976 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
977 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
979 ast_log(LOG_DEBUG, "Restarting session...\n");
982 /* Load the session now */
983 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
985 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
987 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
989 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
993 static void adsi_begin(struct ast_channel *chan, int *useadsi)
996 if(!strcasecmp(chan->type, "sip")){
1001 x = adsi_load_session(chan, adapp, adver, 1);
1005 if (adsi_load_vmail(chan, useadsi)) {
1006 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1013 static void adsi_login(struct ast_channel *chan)
1017 unsigned char keys[8];
1019 if (!adsi_available(chan))
1024 /* Set one key for next */
1025 keys[3] = ADSI_KEY_APPS + 3;
1027 bytes += adsi_logo(buf + bytes);
1028 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1029 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1030 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1031 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1032 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1033 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1034 bytes += adsi_set_keys(buf + bytes, keys);
1035 bytes += adsi_voice_mode(buf + bytes, 0);
1036 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1039 static void adsi_password(struct ast_channel *chan)
1043 unsigned char keys[8];
1045 if (!adsi_available(chan))
1050 /* Set one key for next */
1051 keys[3] = ADSI_KEY_APPS + 3;
1053 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1054 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1055 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1056 bytes += adsi_set_keys(buf + bytes, keys);
1057 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1060 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1064 unsigned char keys[8];
1067 if (!adsi_available(chan))
1071 y = ADSI_KEY_APPS + 12 + start + x;
1072 if (y > ADSI_KEY_APPS + 12 + 4)
1074 keys[x] = ADSI_KEY_SKT | y;
1076 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1080 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1081 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1082 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1083 bytes += adsi_set_keys(buf + bytes, keys);
1084 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1087 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1090 char buf[256], buf1[256], buf2[256];
1095 char datetime[21]="";
1098 unsigned char keys[8];
1102 if (!adsi_available(chan))
1105 /* Retrieve important info */
1106 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1107 f = fopen(fn2, "r");
1110 fgets(buf, sizeof(buf), f);
1114 strsep(&stringp, "=");
1115 val = strsep(&stringp, "=");
1116 if (val && strlen(val)) {
1117 if (!strcmp(buf, "callerid"))
1118 strncpy(cid, val, sizeof(cid) - 1);
1119 if (!strcmp(buf, "origdate"))
1120 strncpy(datetime, val, sizeof(datetime) - 1);
1126 /* New meaning for keys */
1128 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1133 /* No prev key, provide "Folder" instead */
1134 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1137 /* If last message ... */
1139 /* but not only message, provide "Folder" instead */
1140 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1142 /* Otherwise if only message, leave blank */
1148 ast_callerid_parse(cid, &name, &num);
1152 name = "Unknown Caller";
1154 /* If deleted, show "undeleted" */
1156 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1159 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1160 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1161 strcasecmp(folder, "INBOX") ? " Messages" : "");
1162 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1164 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1165 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1166 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1167 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1168 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1169 bytes += adsi_set_keys(buf + bytes, keys);
1170 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1173 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1177 unsigned char keys[8];
1181 if (!adsi_available(chan))
1184 /* New meaning for keys */
1186 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1192 /* No prev key, provide "Folder" instead */
1193 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1196 /* If last message ... */
1198 /* but not only message, provide "Folder" instead */
1199 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1201 /* Otherwise if only message, leave blank */
1206 /* If deleted, show "undeleted" */
1208 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1211 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1212 bytes += adsi_set_keys(buf + bytes, keys);
1213 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1216 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1218 char buf[256], buf1[256], buf2[256];
1220 unsigned char keys[8];
1223 char *newm = (new == 1) ? "message" : "messages";
1224 char *oldm = (old == 1) ? "message" : "messages";
1225 if (!adsi_available(chan))
1228 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1230 strcat(buf1, " and");
1231 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1233 snprintf(buf2, sizeof(buf2), "%s.", newm);
1236 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1237 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1239 strcpy(buf1, "You have no messages.");
1242 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1243 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1244 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1247 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1251 /* Don't let them listen if there are none */
1254 bytes += adsi_set_keys(buf + bytes, keys);
1256 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1259 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1261 char buf[256], buf1[256], buf2[256];
1263 unsigned char keys[8];
1266 char *mess = (messages == 1) ? "message" : "messages";
1268 if (!adsi_available(chan))
1271 /* Original command keys */
1273 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1281 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1282 strcasecmp(folder, "INBOX") ? " folder" : "");
1285 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1287 strcpy(buf2, "no messages.");
1288 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1289 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1290 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1291 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1292 bytes += adsi_set_keys(buf + bytes, keys);
1294 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1298 static void adsi_clear(struct ast_channel *chan)
1302 if (!adsi_available(chan))
1304 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1305 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1308 static void adsi_goodbye(struct ast_channel *chan)
1312 if(!strcasecmp(chan->type, "sip")){
1315 if (!adsi_available(chan))
1317 bytes += adsi_logo(buf + bytes);
1318 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1319 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1320 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1321 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1324 static int get_folder(struct ast_channel *chan, int start)
1329 d = play_and_wait(chan, "vm-press");
1332 for (x = start; x< 5; x++) {
1333 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1335 d = play_and_wait(chan, "vm-for");
1338 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1339 d = play_and_wait(chan, fn);
1342 d = play_and_wait(chan, "vm-messages");
1345 d = ast_waitfordigit(chan, 500);
1349 d = play_and_wait(chan, "vm-tocancel");
1352 d = ast_waitfordigit(chan, 4000);
1357 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg, char* myusername)
1363 struct ast_config *mif;
1365 char *copy, *name, *passwd, *email;
1366 char *mycopy, *myname, *mypasswd, *myemail;
1371 ast_streamfile(chan, "vm-extension", chan->language);
1373 if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)
1375 if (ast_variable_retrieve(cfg, NULL, username)) {
1376 printf("Got %d\n", atoi(username));
1377 /* if (play_and_wait(chan, "vm-savedto"))
1381 snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1382 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1386 todircount = count_messages(todir);
1388 snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1392 /* TODO: use config to determine what other formats to copy the message in */
1393 snprintf(sys, sizeof(sys), "cp %s/msg%04d.wav %s/msg%04d.wav\n", dir, curmsg, todir, todircount);
1397 /* copy the message information file too */
1398 snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
1402 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1404 /* load the information on the source message so we can send an e-mail like a new message */
1405 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1406 if ((mif=ast_load(miffile))) {
1408 /* send an e-mail like it was a new message if appropriate */
1409 if ((copy = ast_variable_retrieve(cfg, NULL, username))) {
1411 /* Make sure they have an entry in the config */
1412 copy = strdup(copy);
1414 passwd = strsep(&stringp, ",");
1415 name = strsep(&stringp, ",");
1416 email = strsep(&stringp, ",");
1419 if ((mycopy = ast_variable_retrieve(cfg, NULL, myusername))) {
1420 char *mystringp=NULL;
1421 /* Make sure they have an entry in the config */
1422 mycopy = strdup(mycopy);
1424 mypasswd = strsep(&mystringp, ",");
1425 myname = strsep(&mystringp, ",");
1426 myemail = strsep(&mystringp, ",");
1430 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", myname, ast_variable_retrieve(mif, NULL, "callerid"));
1431 sendmail(ast_variable_retrieve(cfg, "general", "serveremail"),
1432 email, name, todircount, username,
1436 atol(ast_variable_retrieve(mif, NULL, "duration"))
1440 free(copy); /* no leaks here */
1441 free(mycopy); /* or here */
1442 ast_destroy(mif); /* or here */
1445 /* give confirmatopm that the message was saved */
1446 if (play_and_wait(chan, "vm-message")) break;
1447 if (play_and_wait(chan, "vm-saved")) break;
1451 if ( play_and_wait(chan, "pbx-invalid"))
1458 #define WAITCMD(a) do { \
1466 #define WAITFILE2(file) do { \
1467 if (ast_streamfile(chan, file, chan->language)) \
1468 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1469 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1475 #define WAITFILE(file) do { \
1476 if (ast_streamfile(chan, file, chan->language)) \
1477 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1478 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1481 goto instructions; \
1482 } else if (d < 0) { \
1487 #define PLAYMSG(a) do { \
1489 make_file(fn, sizeof(fn), curdir, a); \
1490 adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1492 WAITFILE2("vm-first"); \
1493 else if (a == lastmsg) \
1494 WAITFILE2("vm-last"); \
1495 WAITFILE2("vm-message"); \
1496 if (a && (a != lastmsg)) { \
1497 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1498 if (d < 0) goto out; \
1501 make_file(fn, sizeof(fn), curdir, a); \
1506 #define CLOSE_MAILBOX do { \
1507 if (lastmsg > -1) { \
1508 /* Get the deleted messages fixed */ \
1510 for (x=0;x<=lastmsg;x++) { \
1511 if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1512 /* Save this message. It's not in INBOX or hasn't been heard */ \
1514 make_file(fn, sizeof(fn), curdir, x); \
1515 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1516 if (strcmp(fn, fn2)) { \
1517 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1518 snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1519 ast_filerename(fn, fn2, NULL); \
1520 rename(txt, ntxt); \
1522 } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1523 /* Move to old folder before deleting */ \
1524 save_to_folder(curdir, x, username, 1); \
1527 for (x = curmsg + 1; x<=lastmsg; x++) { \
1528 make_file(fn, sizeof(fn), curdir, x); \
1529 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1530 ast_filedelete(fn, NULL); \
1534 memset(deleted, 0, sizeof(deleted)); \
1535 memset(heard, 0, sizeof(heard)); \
1538 #define OPEN_MAILBOX(a) do { \
1539 strcpy(curbox, mbox(a)); \
1540 make_dir(curdir, sizeof(curdir), username, curbox); \
1541 lastmsg = count_messages(curdir) - 1; \
1542 snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1545 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime)
1547 char d, *fmt, *fmts;
1549 int x, fmtcnt=1, res=-1,outmsg=0, wavother=0;
1550 struct ast_frame *f;
1551 struct ast_config *cfg;
1552 struct ast_filestream *others[MAX_OTHER_FORMATS];
1553 char *sfmt[MAX_OTHER_FORMATS];
1558 ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile);
1559 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name);
1561 d = play_and_wait(chan, playfile);
1564 ast_streamfile(chan, "beep",chan->language);
1565 ast_waitstream(chan,"");
1566 cfg = ast_load(VOICEMAIL_CONFIG);
1568 fmt = ast_variable_retrieve(cfg, "general", "format");
1569 ast_log(LOG_DEBUG,"Recording Formats: fmt=%s\n", fmt);
1576 strsep(&stringp, "|");
1577 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1578 sfmt[0] = strdup(fmts);
1580 while((fmt = strsep(&stringp, "|"))) {
1581 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1582 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1585 sfmt[fmtcnt++] = strdup(fmt);
1590 for (x=0;x<fmtcnt;x++) {
1591 others[x] = ast_writefile(recordfile, sfmt[x], comment, 0, 0, 0700);
1592 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s\n", x, recordfile, sfmt[x]);
1595 /* Ick, the other format didn't work, but be sure not
1596 to leak memory here */
1598 for(y=x+1;y < fmtcnt;y++)
1602 if(!strcasecmp(sfmt[x], "wav"))
1607 /* Loop forever, writing the packets we read to the writer(s), until
1608 we read a # or get a hangup */
1611 res = ast_waitfor(chan, 2000);
1613 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1614 /* Try one more time in case of masq */
1615 res = ast_waitfor(chan, 2000);
1617 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1630 if (f->frametype == AST_FRAME_VOICE) {
1631 /* write each format */
1632 for (x=0;x<fmtcnt;x++) {
1633 res = ast_writestream(others[x], f);
1635 /* Exit on any error */
1637 ast_log(LOG_WARNING, "Error writing frame\n");
1641 } else if (f->frametype == AST_FRAME_DTMF) {
1642 if (f->subclass == '#') {
1643 if (option_verbose > 2)
1644 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1651 if (maxtime < (end - start)) {
1652 if (option_verbose > 2)
1653 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1661 if (option_verbose > 2)
1662 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1667 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1671 for (x=0;x<fmtcnt;x++) {
1674 ast_closestream(others[x]);
1678 /* Let them know it worked */
1679 ast_streamfile(chan, "vm-msgsaved", chan->language);
1680 ast_waitstream(chan, "");
1691 static int vm_execmain(struct ast_channel *chan, void *data)
1693 /* XXX This is, admittedly, some pretty horrendus code. For some
1694 reason it just seemed a lot easier to do with GOTO's. I feel
1695 like I'm back in my GWBASIC days. XXX */
1700 struct localuser *u;
1701 char username[80] ="";
1702 char prefixstr[80] ="";
1703 char empty[80] = "";
1704 char password[80] = "", *copy;
1705 char newpassword[80] = "";
1706 char newpassword2[80] = "";
1707 char curbox[80] = "";
1708 char curdir[256] = "";
1709 char vmbox[256] = "";
1712 char prefile[256]="";
1714 char ntxt[256] = "";
1716 int deleted[MAXMSG] = { 0, };
1717 int heard[MAXMSG] = { 0, };
1729 char tmp[256], *ext;
1730 struct ast_config *cfg;
1733 cfg = ast_load(VOICEMAIL_CONFIG);
1735 ast_log(LOG_WARNING, "No voicemail configuration\n");
1738 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1739 if (sscanf(s, "%d", &x) == 1) {
1742 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1745 if (chan->_state != AST_STATE_UP)
1749 strncpy(tmp, data, sizeof(tmp) - 1);
1754 /* We should skip the user's password */
1759 /* We should prefix the mailbox with the supplied data */
1767 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1769 strncpy(username, ext, sizeof(username) - 1);
1770 /* make sure username passed as an option is valid */
1771 if (ast_variable_retrieve(cfg, NULL, username))
1778 /* If ADSI is supported, setup login screen */
1779 adsi_begin(chan, &useadsi);
1780 if (!skipuser && useadsi)
1782 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1783 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1787 /* Authenticate them and get their mailbox/password */
1790 /* Prompt for, and read in the username */
1791 if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) {
1792 ast_log(LOG_WARNING, "Couldn't read username\n");
1795 if (!strlen(username)) {
1796 if (option_verbose > 2)
1797 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1802 adsi_password(chan);
1803 if (ast_streamfile(chan, "vm-password", chan->language)) {
1804 ast_log(LOG_WARNING, "Unable to stream password file\n");
1807 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1808 ast_log(LOG_WARNING, "Unable to read password\n");
1812 char fullusername[80] = "";
1813 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1814 strncat(fullusername, username, sizeof(fullusername) - 1);
1815 strncpy(username, fullusername, sizeof(username) - 1);
1817 copy = ast_variable_retrieve(cfg, NULL, username);
1820 copy = strdup(copy);
1822 strsep(&stringp, ",");
1823 if (!strcmp(password,copy))
1826 if (option_verbose > 2)
1827 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1829 strncpy(username, empty, sizeof(username) -1);
1834 if (option_verbose > 2)
1835 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1840 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1843 if (ast_waitstream(chan, ""))
1850 snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1851 mkdir(curdir, 0700);
1853 oldmessages = lastmsg + 1;
1854 /* Start in INBOX */
1856 newmessages = lastmsg + 1;
1859 /* Select proper mailbox FIRST!! */
1860 if (!newmessages && oldmessages) {
1861 /* If we only have old messages start here */
1866 adsi_status(chan, newmessages, oldmessages, lastmsg);
1868 WAITCMD(play_and_wait(chan, "vm-youhave"));
1870 WAITCMD(say_and_wait(chan, newmessages));
1871 WAITCMD(play_and_wait(chan, "vm-INBOX"));
1874 WAITCMD(play_and_wait(chan, "vm-and"));
1876 if (newmessages == 1)
1877 WAITCMD(play_and_wait(chan, "vm-message"));
1879 WAITCMD(play_and_wait(chan, "vm-messages"));
1884 WAITCMD(say_and_wait(chan, oldmessages));
1885 WAITCMD(play_and_wait(chan, "vm-Old"));
1886 if (oldmessages == 1)
1887 WAITCMD(play_and_wait(chan, "vm-message"));
1889 WAITCMD(play_and_wait(chan, "vm-messages"));
1891 if (!oldmessages && !newmessages) {
1892 WAITCMD(play_and_wait(chan, "vm-no"));
1893 WAITCMD(play_and_wait(chan, "vm-messages"));
1900 WAITCMD(play_and_wait(chan, "vm-onefor"));
1901 WAITCMD(play_and_wait(chan, vmbox));
1902 WAITCMD(play_and_wait(chan, "vm-messages"));
1904 WAITCMD(play_and_wait(chan, "vm-opts"));
1907 WAITCMD(play_and_wait(chan, "vm-prev"));
1908 WAITCMD(play_and_wait(chan, "vm-repeat"));
1909 if (curmsg != lastmsg)
1910 WAITCMD(play_and_wait(chan, "vm-next"));
1911 if (!deleted[curmsg])
1912 WAITCMD(play_and_wait(chan, "vm-delete"));
1914 WAITCMD(play_and_wait(chan, "vm-undelete"));
1915 WAITCMD(play_and_wait(chan, "vm-toforward"));
1916 WAITCMD(play_and_wait(chan, "vm-savemessage"));
1918 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1919 d = ast_waitfordigit(chan, 6000);
1925 play_and_wait(chan, "vm-goodbye");
1934 adsi_folders(chan, 0, "Change to folder...");
1935 box = play_and_wait(chan, "vm-changeto");
1938 while((box < '0') || (box > '9')) {
1939 box = get_folder(chan, 0);
1949 adsi_status2(chan, curbox, lastmsg + 1);
1950 WAITCMD(play_and_wait(chan, vmbox));
1951 WAITCMD(play_and_wait(chan, "vm-messages"));
1959 WAITCMD(play_and_wait(chan, "vm-nomore"));
1969 WAITCMD(play_and_wait(chan, "vm-youhave"));
1970 WAITCMD(play_and_wait(chan, "vm-no"));
1971 snprintf(fn, sizeof(fn), "vm-%s", curbox);
1972 WAITCMD(play_and_wait(chan, fn));
1973 WAITCMD(play_and_wait(chan, "vm-messages"));
1977 if (curmsg < lastmsg) {
1981 WAITCMD(play_and_wait(chan, "vm-nomore"));
1985 deleted[curmsg] = !deleted[curmsg];
1987 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
1988 if (deleted[curmsg])
1989 WAITCMD(play_and_wait(chan, "vm-deleted"));
1991 WAITCMD(play_and_wait(chan, "vm-undeleted"));
1995 if(forward_message(chan, cfg, curdir, curmsg, username) < 0)
2000 adsi_folders(chan, 1, "Save to folder...");
2001 box = play_and_wait(chan, "vm-savefolder");
2004 while((box < '1') || (box > '9')) {
2005 box = get_folder(chan, 1);
2013 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
2014 if (save_to_folder(curdir, curmsg, username, box))
2017 make_file(fn, sizeof(fn), curdir, curmsg);
2019 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
2020 WAITCMD(play_and_wait(chan, "vm-message"));
2021 WAITCMD(say_and_wait(chan, curmsg + 1) );
2022 WAITCMD(play_and_wait(chan, "vm-savedto"));
2023 snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
2024 WAITCMD(play_and_wait(chan, fn));
2025 WAITCMD(play_and_wait(chan, "vm-messages"));
2029 WAITCMD(play_and_wait(chan, "vm-onefor"));
2030 WAITCMD(play_and_wait(chan, vmbox));
2031 WAITCMD(play_and_wait(chan, "vm-messages"));
2032 WAITCMD(play_and_wait(chan, "vm-opts"));
2036 ast_stopstream(chan);
2038 play_and_wait(chan, "vm-goodbye");
2053 ast_stopstream(chan);
2057 adsi_unload_session(chan);
2059 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
2061 LOCAL_USER_REMOVE(u);
2065 d = play_and_wait(chan,"vm-options");
2067 d = ast_waitfordigit(chan,6000);
2073 snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username);
2074 play_and_record(chan,"vm-rec-unv",prefile, maxgreet);
2077 snprintf(prefile,sizeof(prefile),"vm/%s/busy",username);
2078 play_and_record(chan,"vm-rec-busy",prefile, maxgreet);
2081 snprintf(prefile,sizeof(prefile),"vm/%s/greet",username);
2082 play_and_record(chan,"vm-rec-name",prefile, maxgreet);
2085 newpassword[1] = '\0';
2086 newpassword[0] = play_and_wait(chan,"vm-newpassword");
2087 if (ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#") < 0) {
2088 play_and_wait(chan, "vm-sorry");
2089 ast_log(LOG_NOTICE,"Unable to read new password\n");
2092 newpassword2[1] = '\0';
2093 newpassword2[0] = play_and_wait(chan,"vm-reenterpassword");
2095 if (ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#") < 0) {
2096 play_and_wait(chan, "vm-sorry");
2097 ast_log(LOG_NOTICE,"Unable to read re-entered password\n");
2100 if (strcmp(newpassword, newpassword2)) {
2101 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", username, newpassword, newpassword2);
2102 play_and_wait(chan, "vm-mismatch");
2105 if (vm_change_password(username,password,newpassword) < 0)
2107 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",username);
2109 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",username,newpassword,strlen(newpassword));
2110 play_and_wait(chan,"vm-passchanged");
2121 static int vm_exec(struct ast_channel *chan, void *data)
2123 int res=0, silent=0, busy=0, unavail=0;
2124 struct localuser *u;
2125 char tmp[256], *ext;
2128 if (chan->_state != AST_STATE_UP)
2131 strncpy(tmp, data, sizeof(tmp) - 1);
2133 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2143 } else if (*ext == 'b') {
2146 } else if (*ext == 'u') {
2150 res = leave_voicemail(chan, ext, silent, busy, unavail);
2151 LOCAL_USER_REMOVE(u);
2155 int unload_module(void)
2158 STANDARD_HANGUP_LOCALUSERS;
2159 res = ast_unregister_application(app);
2160 res |= ast_unregister_application(app2);
2164 int load_module(void)
2167 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2169 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2173 char *description(void)
2181 STANDARD_USECOUNT(res);
2187 return ASTERISK_GPL_KEY;