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"
583 chan->callerid ? chan->callerid : "Unknown",
587 ast_log(LOG_WARNING, "Error opening text file for output\n");
589 /* We need to reset these values */
591 fmt = ast_variable_retrieve(cfg, "general", "format");
594 strsep(&stringp, "|");
595 while((fmt = strsep(&stringp, "|"))) {
596 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
597 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
600 sfmt[fmtcnt++] = strdup(fmt);
602 for (x=0;x<fmtcnt;x++) {
603 others[x] = ast_writefile(fn, sfmt[x], comment, 0, 0, 0700);
605 /* Ick, the other format didn't work, but be sure not
606 to leak memory here */
608 for(y=x+1;y < fmtcnt;y++)
612 if(!strcasecmp(sfmt[x], "wav"))
617 /* Loop forever, writing the packets we read to the writer(s), until
618 we read a # or get a hangup */
619 if (option_verbose > 2)
620 ast_verbose( VERBOSE_PREFIX_3 "Recording to %s\n", fn);
623 res = ast_waitfor(chan, 2000);
625 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
626 /* Try one more time in case of masq */
627 res = ast_waitfor(chan, 2000);
629 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
642 if (f->frametype == AST_FRAME_VOICE) {
643 /* Write the primary format */
644 res = ast_writestream(writer, f);
646 ast_log(LOG_WARNING, "Error writing primary frame\n");
649 /* And each of the others */
650 for (x=0;x<fmtcnt;x++) {
651 res |= ast_writestream(others[x], f);
653 /* Exit on any error */
655 ast_log(LOG_WARNING, "Error writing frame\n");
659 } else if (f->frametype == AST_FRAME_DTMF) {
660 if (f->subclass == '#') {
661 if (option_verbose > 2)
662 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
671 if (maxmessage && (end - start > maxmessage)) {
672 if (option_verbose > 2)
673 ast_verbose( VERBOSE_PREFIX_3 "Message is too long, ending it now...\n");
680 if (option_verbose > 2)
681 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
686 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", fn, sfmt[x]);
690 ast_closestream(writer);
691 for (x=0;x<fmtcnt;x++) {
694 ast_closestream(others[x]);
698 /* Let them know it worked */
699 ast_streamfile(chan, "vm-msgsaved", chan->language);
700 ast_waitstream(chan, "");
702 txt = fopen(txtfile, "a");
705 fprintf(txt, "duration=%ld\n", end-start);
708 /* Send e-mail if applicable */
710 sendmail(astemail, email, name, msgnum, ext, chan->callerid, fn, wavother ? "wav" : fmts, end - start);
714 ast_log(LOG_WARNING, "Error writing to mailbox %s\n", ext);
716 ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext);
720 ast_log(LOG_WARNING, "No format to save messages in \n");
723 ast_log(LOG_WARNING, "Unable to playback instructions\n");
727 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
729 /* Leave voicemail for someone */
730 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
734 static char *mbox(int id)
762 static int count_messages(char *dir)
766 for (x=0;x<MAXMSG;x++) {
767 make_file(fn, sizeof(fn), dir, x);
768 if (ast_fileexists(fn, NULL, NULL) < 1)
774 static int play_and_wait(struct ast_channel *chan, char *fn)
777 d = ast_streamfile(chan, fn, chan->language);
780 d = ast_waitstream(chan, AST_DIGIT_ANY);
784 static int say_and_wait(struct ast_channel *chan, int num)
787 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
791 static int copy(char *infile, char *outfile)
798 if ((ifd = open(infile, O_RDONLY)) < 0) {
799 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
802 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
803 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
808 len = read(ifd, buf, sizeof(buf));
810 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
816 res = write(ofd, buf, len);
818 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
830 static int save_to_folder(char *dir, int msg, char *username, int box)
837 char *dbox = mbox(box);
839 make_file(sfn, sizeof(sfn), dir, msg);
840 make_dir(ddir, sizeof(ddir), username, dbox);
842 for (x=0;x<MAXMSG;x++) {
843 make_file(dfn, sizeof(dfn), ddir, x);
844 if (ast_fileexists(dfn, NULL, NULL) < 0)
849 ast_filecopy(sfn, dfn, NULL);
850 if (strcmp(sfn, dfn)) {
851 snprintf(txt, sizeof(txt), "%s.txt", sfn);
852 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
858 static int adsi_logo(unsigned char *buf)
861 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
862 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
866 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
874 bytes += adsi_data_mode(buf + bytes);
875 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
878 bytes += adsi_logo(buf);
879 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
881 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
883 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
884 bytes += adsi_data_mode(buf + bytes);
885 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
887 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
889 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
890 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
891 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
892 bytes += adsi_voice_mode(buf + bytes, 0);
893 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
900 bytes += adsi_logo(buf);
901 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
902 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
903 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
904 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
907 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
908 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
909 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
910 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
911 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
912 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
913 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
916 /* Add another dot */
918 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
919 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
920 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
924 /* These buttons we load but don't use yet */
925 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
926 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
927 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
928 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
929 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
930 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
931 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
934 /* Add another dot */
936 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
937 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
938 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
943 snprintf(num, sizeof(num), "%d", x);
944 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
946 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
947 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
950 /* Add another dot */
952 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
953 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
954 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
957 if (adsi_end_download(chan)) {
959 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
960 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
961 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
962 bytes += adsi_voice_mode(buf + bytes, 0);
963 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
967 bytes += adsi_download_disconnect(buf + bytes);
968 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
970 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
975 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
976 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
978 ast_log(LOG_DEBUG, "Restarting session...\n");
981 /* Load the session now */
982 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
984 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
986 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
988 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
992 static void adsi_begin(struct ast_channel *chan, int *useadsi)
995 x = adsi_load_session(chan, adapp, adver, 1);
999 if (adsi_load_vmail(chan, useadsi)) {
1000 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1007 static void adsi_login(struct ast_channel *chan)
1011 unsigned char keys[8];
1013 if (!adsi_available(chan))
1018 /* Set one key for next */
1019 keys[3] = ADSI_KEY_APPS + 3;
1021 bytes += adsi_logo(buf + bytes);
1022 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1023 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1024 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1025 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1026 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1027 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1028 bytes += adsi_set_keys(buf + bytes, keys);
1029 bytes += adsi_voice_mode(buf + bytes, 0);
1030 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1033 static void adsi_password(struct ast_channel *chan)
1037 unsigned char keys[8];
1039 if (!adsi_available(chan))
1044 /* Set one key for next */
1045 keys[3] = ADSI_KEY_APPS + 3;
1047 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1048 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1049 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1050 bytes += adsi_set_keys(buf + bytes, keys);
1051 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1054 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1058 unsigned char keys[8];
1061 if (!adsi_available(chan))
1065 y = ADSI_KEY_APPS + 12 + start + x;
1066 if (y > ADSI_KEY_APPS + 12 + 4)
1068 keys[x] = ADSI_KEY_SKT | y;
1070 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1074 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1075 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1076 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1077 bytes += adsi_set_keys(buf + bytes, keys);
1078 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1081 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1084 char buf[256], buf1[256], buf2[256];
1089 char datetime[21]="";
1092 unsigned char keys[8];
1096 if (!adsi_available(chan))
1099 /* Retrieve important info */
1100 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1101 f = fopen(fn2, "r");
1104 fgets(buf, sizeof(buf), f);
1108 strsep(&stringp, "=");
1109 val = strsep(&stringp, "=");
1110 if (val && strlen(val)) {
1111 if (!strcmp(buf, "callerid"))
1112 strncpy(cid, val, sizeof(cid) - 1);
1113 if (!strcmp(buf, "origdate"))
1114 strncpy(datetime, val, sizeof(datetime) - 1);
1120 /* New meaning for keys */
1122 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1127 /* No prev key, provide "Folder" instead */
1128 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1131 /* If last message ... */
1133 /* but not only message, provide "Folder" instead */
1134 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1136 /* Otherwise if only message, leave blank */
1142 ast_callerid_parse(cid, &name, &num);
1146 name = "Unknown Caller";
1148 /* If deleted, show "undeleted" */
1150 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1153 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1154 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1155 strcasecmp(folder, "INBOX") ? " Messages" : "");
1156 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1158 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1159 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1160 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1161 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1162 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1163 bytes += adsi_set_keys(buf + bytes, keys);
1164 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1167 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1171 unsigned char keys[8];
1175 if (!adsi_available(chan))
1178 /* New meaning for keys */
1180 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1186 /* No prev key, provide "Folder" instead */
1187 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1190 /* If last message ... */
1192 /* but not only message, provide "Folder" instead */
1193 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1195 /* Otherwise if only message, leave blank */
1200 /* If deleted, show "undeleted" */
1202 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1205 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1206 bytes += adsi_set_keys(buf + bytes, keys);
1207 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1210 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1212 char buf[256], buf1[256], buf2[256];
1214 unsigned char keys[8];
1217 char *newm = (new == 1) ? "message" : "messages";
1218 char *oldm = (old == 1) ? "message" : "messages";
1219 if (!adsi_available(chan))
1222 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1224 strcat(buf1, " and");
1225 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1227 snprintf(buf2, sizeof(buf2), "%s.", newm);
1230 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1231 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1233 strcpy(buf1, "You have no messages.");
1236 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1237 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1238 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1241 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1245 /* Don't let them listen if there are none */
1248 bytes += adsi_set_keys(buf + bytes, keys);
1250 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1253 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1255 char buf[256], buf1[256], buf2[256];
1257 unsigned char keys[8];
1260 char *mess = (messages == 1) ? "message" : "messages";
1262 if (!adsi_available(chan))
1265 /* Original command keys */
1267 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1275 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1276 strcasecmp(folder, "INBOX") ? " folder" : "");
1279 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1281 strcpy(buf2, "no messages.");
1282 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1283 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1284 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1285 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1286 bytes += adsi_set_keys(buf + bytes, keys);
1288 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1292 static void adsi_clear(struct ast_channel *chan)
1296 if (!adsi_available(chan))
1298 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1299 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1302 static void adsi_goodbye(struct ast_channel *chan)
1306 if (!adsi_available(chan))
1308 bytes += adsi_logo(buf + bytes);
1309 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1310 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1311 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1312 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1315 static int get_folder(struct ast_channel *chan, int start)
1320 d = play_and_wait(chan, "vm-press");
1323 for (x = start; x< 5; x++) {
1324 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1326 d = play_and_wait(chan, "vm-for");
1329 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1330 d = play_and_wait(chan, fn);
1333 d = play_and_wait(chan, "vm-messages");
1336 d = ast_waitfordigit(chan, 500);
1340 d = play_and_wait(chan, "vm-tocancel");
1343 d = ast_waitfordigit(chan, 4000);
1348 forward_message(struct ast_channel *chan, struct ast_config *cfg, char *dir, int curmsg)
1356 ast_streamfile(chan, "vm-extension", chan->language);
1358 if (ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)
1360 if (ast_variable_retrieve(cfg, NULL, username)) {
1361 printf("Got %d\n", atoi(username));
1362 if (play_and_wait(chan, "vm-savedto"))
1365 snprintf(todir, sizeof(todir), "%s/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1366 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1370 todircount = count_messages(todir);
1372 snprintf(sys, sizeof(sys), "cp %s/msg%04d.gsm %s/msg%04d.gsm\n", dir, curmsg, todir, todircount);
1378 if ( play_and_wait(chan, "pbx-invalid"))
1386 #define WAITCMD(a) do { \
1394 #define WAITFILE2(file) do { \
1395 if (ast_streamfile(chan, file, chan->language)) \
1396 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1397 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1403 #define WAITFILE(file) do { \
1404 if (ast_streamfile(chan, file, chan->language)) \
1405 ast_log(LOG_WARNING, "Unable to play message %s\n", file); \
1406 d = ast_waitstream(chan, AST_DIGIT_ANY); \
1409 goto instructions; \
1410 } else if (d < 0) { \
1415 #define PLAYMSG(a) do { \
1417 make_file(fn, sizeof(fn), curdir, a); \
1418 adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
1420 WAITFILE2("vm-first"); \
1421 else if (a == lastmsg) \
1422 WAITFILE2("vm-last"); \
1423 WAITFILE2("vm-message"); \
1424 if (a && (a != lastmsg)) { \
1425 d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
1426 if (d < 0) goto out; \
1429 make_file(fn, sizeof(fn), curdir, a); \
1434 #define CLOSE_MAILBOX do { \
1435 if (lastmsg > -1) { \
1436 /* Get the deleted messages fixed */ \
1438 for (x=0;x<=lastmsg;x++) { \
1439 if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \
1440 /* Save this message. It's not in INBOX or hasn't been heard */ \
1442 make_file(fn, sizeof(fn), curdir, x); \
1443 make_file(fn2, sizeof(fn2), curdir, curmsg); \
1444 if (strcmp(fn, fn2)) { \
1445 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1446 snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \
1447 ast_filerename(fn, fn2, NULL); \
1448 rename(txt, ntxt); \
1450 } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \
1451 /* Move to old folder before deleting */ \
1452 save_to_folder(curdir, x, username, 1); \
1455 for (x = curmsg + 1; x<=lastmsg; x++) { \
1456 make_file(fn, sizeof(fn), curdir, x); \
1457 snprintf(txt, sizeof(txt), "%s.txt", fn); \
1458 ast_filedelete(fn, NULL); \
1462 memset(deleted, 0, sizeof(deleted)); \
1463 memset(heard, 0, sizeof(heard)); \
1466 #define OPEN_MAILBOX(a) do { \
1467 strcpy(curbox, mbox(a)); \
1468 make_dir(curdir, sizeof(curdir), username, curbox); \
1469 lastmsg = count_messages(curdir) - 1; \
1470 snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
1473 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime)
1475 char d, *fmt, *fmts;
1477 int x, fmtcnt=1, res=-1,outmsg=0, wavother=0;
1478 struct ast_frame *f;
1479 struct ast_config *cfg;
1480 struct ast_filestream *others[MAX_OTHER_FORMATS];
1481 char *sfmt[MAX_OTHER_FORMATS];
1486 ast_log(LOG_DEBUG,"play_and_record: %s, %s\n", playfile, recordfile);
1487 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile, recordfile, chan->name);
1489 d = play_and_wait(chan, playfile);
1492 ast_streamfile(chan, "beep",chan->language);
1493 ast_waitstream(chan,"");
1494 cfg = ast_load(VOICEMAIL_CONFIG);
1496 fmt = ast_variable_retrieve(cfg, "general", "format");
1497 ast_log(LOG_DEBUG,"Recording Formats: fmt=%s\n", fmt);
1504 strsep(&stringp, "|");
1505 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
1506 sfmt[0] = strdup(fmts);
1508 while((fmt = strsep(&stringp, "|"))) {
1509 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
1510 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
1513 sfmt[fmtcnt++] = strdup(fmt);
1518 for (x=0;x<fmtcnt;x++) {
1519 others[x] = ast_writefile(recordfile, sfmt[x], comment, 0, 0, 0700);
1520 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s\n", x, recordfile, sfmt[x]);
1523 /* Ick, the other format didn't work, but be sure not
1524 to leak memory here */
1526 for(y=x+1;y < fmtcnt;y++)
1530 if(!strcasecmp(sfmt[x], "wav"))
1535 /* Loop forever, writing the packets we read to the writer(s), until
1536 we read a # or get a hangup */
1539 res = ast_waitfor(chan, 2000);
1541 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
1542 /* Try one more time in case of masq */
1543 res = ast_waitfor(chan, 2000);
1545 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
1558 if (f->frametype == AST_FRAME_VOICE) {
1559 /* write each format */
1560 for (x=0;x<fmtcnt;x++) {
1561 res = ast_writestream(others[x], f);
1563 /* Exit on any error */
1565 ast_log(LOG_WARNING, "Error writing frame\n");
1569 } else if (f->frametype == AST_FRAME_DTMF) {
1570 if (f->subclass == '#') {
1571 if (option_verbose > 2)
1572 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
1579 if (maxtime < (end - start)) {
1580 if (option_verbose > 2)
1581 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
1589 if (option_verbose > 2)
1590 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
1595 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
1599 for (x=0;x<fmtcnt;x++) {
1602 ast_closestream(others[x]);
1606 /* Let them know it worked */
1607 ast_streamfile(chan, "vm-msgsaved", chan->language);
1608 ast_waitstream(chan, "");
1619 static int vm_execmain(struct ast_channel *chan, void *data)
1621 /* XXX This is, admittedly, some pretty horrendus code. For some
1622 reason it just seemed a lot easier to do with GOTO's. I feel
1623 like I'm back in my GWBASIC days. XXX */
1628 struct localuser *u;
1629 char username[80] ="";
1630 char prefixstr[80] ="";
1631 char empty[80] = "";
1632 char password[80] = "", *copy;
1633 char newpassword[80] = "";
1634 char newpassword2[80] = "";
1635 char curbox[80] = "";
1636 char curdir[256] = "";
1637 char vmbox[256] = "";
1640 char prefile[256]="";
1642 char ntxt[256] = "";
1644 int deleted[MAXMSG] = { 0, };
1645 int heard[MAXMSG] = { 0, };
1657 char tmp[256], *ext;
1658 struct ast_config *cfg;
1661 cfg = ast_load(VOICEMAIL_CONFIG);
1663 ast_log(LOG_WARNING, "No voicemail configuration\n");
1666 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
1667 if (sscanf(s, "%d", &x) == 1) {
1670 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
1673 if (chan->_state != AST_STATE_UP)
1677 strncpy(tmp, data, sizeof(tmp) - 1);
1682 /* We should skip the user's password */
1687 /* We should prefix the mailbox with the supplied data */
1695 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1697 strncpy(username, ext, sizeof(username) - 1);
1698 /* make sure username passed as an option is valid */
1699 if (ast_variable_retrieve(cfg, NULL, username))
1706 /* If ADSI is supported, setup login screen */
1707 adsi_begin(chan, &useadsi);
1708 if (!skipuser && useadsi)
1710 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1711 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1715 /* Authenticate them and get their mailbox/password */
1718 /* Prompt for, and read in the username */
1719 if (!skipuser && ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0) {
1720 ast_log(LOG_WARNING, "Couldn't read username\n");
1723 if (!strlen(username)) {
1724 if (option_verbose > 2)
1725 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1730 adsi_password(chan);
1731 if (ast_streamfile(chan, "vm-password", chan->language)) {
1732 ast_log(LOG_WARNING, "Unable to stream password file\n");
1735 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1736 ast_log(LOG_WARNING, "Unable to read password\n");
1740 char fullusername[80] = "";
1741 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1742 strncat(fullusername, username, sizeof(fullusername) - 1);
1743 strncpy(username, fullusername, sizeof(username) - 1);
1745 copy = ast_variable_retrieve(cfg, NULL, username);
1748 copy = strdup(copy);
1750 strsep(&stringp, ",");
1751 if (!strcmp(password,copy))
1754 if (option_verbose > 2)
1755 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s'\n", password, username);
1757 strncpy(username, empty, sizeof(username) -1);
1762 if (option_verbose > 2)
1763 ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
1768 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1771 if (ast_waitstream(chan, ""))
1778 snprintf(curdir, sizeof(curdir), "%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,"vm", username);
1779 mkdir(curdir, 0700);
1781 oldmessages = lastmsg + 1;
1782 /* Start in INBOX */
1784 newmessages = lastmsg + 1;
1787 /* Select proper mailbox FIRST!! */
1788 if (!newmessages && oldmessages) {
1789 /* If we only have old messages start here */
1794 adsi_status(chan, newmessages, oldmessages, lastmsg);
1796 WAITCMD(play_and_wait(chan, "vm-youhave"));
1798 WAITCMD(say_and_wait(chan, newmessages));
1799 WAITCMD(play_and_wait(chan, "vm-INBOX"));
1802 WAITCMD(play_and_wait(chan, "vm-and"));
1804 if (newmessages == 1)
1805 WAITCMD(play_and_wait(chan, "vm-message"));
1807 WAITCMD(play_and_wait(chan, "vm-messages"));
1812 WAITCMD(say_and_wait(chan, oldmessages));
1813 WAITCMD(play_and_wait(chan, "vm-Old"));
1814 if (oldmessages == 1)
1815 WAITCMD(play_and_wait(chan, "vm-message"));
1817 WAITCMD(play_and_wait(chan, "vm-messages"));
1819 if (!oldmessages && !newmessages) {
1820 WAITCMD(play_and_wait(chan, "vm-no"));
1821 WAITCMD(play_and_wait(chan, "vm-messages"));
1828 WAITCMD(play_and_wait(chan, "vm-onefor"));
1829 WAITCMD(play_and_wait(chan, vmbox));
1830 WAITCMD(play_and_wait(chan, "vm-messages"));
1832 WAITCMD(play_and_wait(chan, "vm-opts"));
1835 WAITCMD(play_and_wait(chan, "vm-prev"));
1836 WAITCMD(play_and_wait(chan, "vm-repeat"));
1837 if (curmsg != lastmsg)
1838 WAITCMD(play_and_wait(chan, "vm-next"));
1839 if (!deleted[curmsg])
1840 WAITCMD(play_and_wait(chan, "vm-delete"));
1842 WAITCMD(play_and_wait(chan, "vm-undelete"));
1843 WAITCMD(play_and_wait(chan, "vm-toforward"));
1844 WAITCMD(play_and_wait(chan, "vm-savemessage"));
1846 WAITCMD(play_and_wait(chan, "vm-helpexit"));
1847 d = ast_waitfordigit(chan, 6000);
1853 play_and_wait(chan, "vm-goodbye");
1862 adsi_folders(chan, 0, "Change to folder...");
1863 box = play_and_wait(chan, "vm-changeto");
1866 while((box < '0') || (box > '9')) {
1867 box = get_folder(chan, 0);
1877 adsi_status2(chan, curbox, lastmsg + 1);
1878 WAITCMD(play_and_wait(chan, vmbox));
1879 WAITCMD(play_and_wait(chan, "vm-messages"));
1887 WAITCMD(play_and_wait(chan, "vm-nomore"));
1897 WAITCMD(play_and_wait(chan, "vm-youhave"));
1898 WAITCMD(play_and_wait(chan, "vm-no"));
1899 snprintf(fn, sizeof(fn), "vm-%s", curbox);
1900 WAITCMD(play_and_wait(chan, fn));
1901 WAITCMD(play_and_wait(chan, "vm-messages"));
1905 if (curmsg < lastmsg) {
1909 WAITCMD(play_and_wait(chan, "vm-nomore"));
1913 deleted[curmsg] = !deleted[curmsg];
1915 adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
1916 if (deleted[curmsg])
1917 WAITCMD(play_and_wait(chan, "vm-deleted"));
1919 WAITCMD(play_and_wait(chan, "vm-undeleted"));
1923 if(forward_message(chan, cfg, curdir, curmsg) < 0)
1928 adsi_folders(chan, 1, "Save to folder...");
1929 box = play_and_wait(chan, "vm-savefolder");
1932 while((box < '1') || (box > '9')) {
1933 box = get_folder(chan, 1);
1941 ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
1942 if (save_to_folder(curdir, curmsg, username, box))
1945 make_file(fn, sizeof(fn), curdir, curmsg);
1947 adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
1948 WAITCMD(play_and_wait(chan, "vm-message"));
1949 WAITCMD(say_and_wait(chan, curmsg + 1) );
1950 WAITCMD(play_and_wait(chan, "vm-savedto"));
1951 snprintf(fn, sizeof(fn), "vm-%s", mbox(box));
1952 WAITCMD(play_and_wait(chan, fn));
1953 WAITCMD(play_and_wait(chan, "vm-messages"));
1957 WAITCMD(play_and_wait(chan, "vm-onefor"));
1958 WAITCMD(play_and_wait(chan, vmbox));
1959 WAITCMD(play_and_wait(chan, "vm-messages"));
1960 WAITCMD(play_and_wait(chan, "vm-opts"));
1964 ast_stopstream(chan);
1966 play_and_wait(chan, "vm-goodbye");
1981 ast_stopstream(chan);
1985 adsi_unload_session(chan);
1987 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", username, ast_app_has_voicemail(username));
1989 LOCAL_USER_REMOVE(u);
1993 d = play_and_wait(chan,"vm-options");
1995 d = ast_waitfordigit(chan,6000);
2001 snprintf(prefile,sizeof(prefile),"vm/%s/unavail",username);
2002 play_and_record(chan,"vm-rec-unv",prefile, maxgreet);
2005 snprintf(prefile,sizeof(prefile),"vm/%s/busy",username);
2006 play_and_record(chan,"vm-rec-busy",prefile, maxgreet);
2009 snprintf(prefile,sizeof(prefile),"vm/%s/greet",username);
2010 play_and_record(chan,"vm-rec-name",prefile, maxgreet);
2013 newpassword[1] = '\0';
2014 newpassword[0] = play_and_wait(chan,"vm-newpassword");
2015 if (ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#") < 0) {
2016 play_and_wait(chan, "vm-sorry");
2017 ast_log(LOG_NOTICE,"Unable to read new password\n");
2020 newpassword2[1] = '\0';
2021 newpassword2[0] = play_and_wait(chan,"vm-reenterpassword");
2023 if (ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#") < 0) {
2024 play_and_wait(chan, "vm-sorry");
2025 ast_log(LOG_NOTICE,"Unable to read re-entered password\n");
2028 if (strcmp(newpassword, newpassword2)) {
2029 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", username, newpassword, newpassword2);
2030 play_and_wait(chan, "vm-mismatch");
2033 if (vm_change_password(username,password,newpassword) < 0)
2035 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",username);
2037 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",username,newpassword,strlen(newpassword));
2038 play_and_wait(chan,"vm-passchanged");
2049 static int vm_exec(struct ast_channel *chan, void *data)
2051 int res=0, silent=0, busy=0, unavail=0;
2052 struct localuser *u;
2053 char tmp[256], *ext;
2056 if (chan->_state != AST_STATE_UP)
2059 strncpy(tmp, data, sizeof(tmp) - 1);
2061 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2071 } else if (*ext == 'b') {
2074 } else if (*ext == 'u') {
2078 res = leave_voicemail(chan, ext, silent, busy, unavail);
2079 LOCAL_USER_REMOVE(u);
2083 int unload_module(void)
2086 STANDARD_HANGUP_LOCALUSERS;
2087 res = ast_unregister_application(app);
2088 res |= ast_unregister_application(app2);
2092 int load_module(void)
2095 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2097 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2101 char *description(void)
2109 STANDARD_USECOUNT(res);
2115 return ASTERISK_GPL_KEY;