2 * Asterisk -- A telephony toolkit for Linux.
4 * Voicemail System (did you ever think it could be so easy?)
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/config.h>
21 #include <asterisk/say.h>
22 #include <asterisk/module.h>
23 #include <asterisk/adsi.h>
24 #include <asterisk/app.h>
25 #include <asterisk/manager.h>
26 #include <asterisk/dsp.h>
38 #include "../asterisk.h"
39 #include "../astconf.h"
41 #define COMMAND_TIMEOUT 5000
43 #define VOICEMAIL_CONFIG "voicemail.conf"
44 #define ASTERISK_USERNAME "asterisk"
46 #define SENDMAIL "/usr/sbin/sendmail -t"
48 #define INTRO "vm-intro"
52 #define MAX_OTHER_FORMATS 10
54 #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
56 #define BASEMAXINLINE 256
58 #define BASELINELEN 72
64 #define BASEMAXINLINE 256
65 #define BASELINELEN 72
73 unsigned char iobuf[BASEMAXINLINE];
84 struct ast_vm_user *next;
87 static char *tdesc = "Comedian Mail (Voicemail System)";
89 static char *adapp = "CoMa";
91 static char *adsec = "_AST";
93 static char *addesc = "Comedian Mail";
97 static char *synopsis_vm =
98 "Leave a voicemail message";
100 static char *descrip_vm =
101 " VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given extension (must\n"
102 "be configured in voicemail.conf). If the extension is preceeded by an 's'"
103 "then instructions for leaving the message will be skipped. If the extension\n"
104 "is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
105 "/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
106 "is preceeded by a 'b' then the the busy message will be played (that is,\n"
107 "busy instead of unavail). At most one of 's', 'u', or 'b' may be specified.\n"
108 "Returns -1 on error or mailbox not found, or if the user hangs up. \n"
109 "Otherwise, it returns 0. \n";
111 static char *synopsis_vmain =
112 "Enter voicemail system";
114 static char *descrip_vmain =
115 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system for the checking of\n"
116 "voicemail. The mailbox can be passed as the option, which will stop the\n"
117 "voicemail system from prompting the user for the mailbox. If the mailbox\n"
118 "is preceded by 's' then the password check will be skipped. If a context is\n"
119 "specified, logins are considered in that context only. Returns -1 if\n"
120 "the user hangs up or 0 otherwise.\n";
122 /* Leave a message */
123 static char *app = "VoiceMail2";
125 /* Check mail, control, etc */
126 static char *app2 = "VoiceMailMain2";
128 static pthread_mutex_t vmlock = AST_MUTEX_INITIALIZER;
129 struct ast_vm_user *users;
130 struct ast_vm_user *usersl;
131 static int attach_voicemail;
132 static int maxsilence;
133 static int silencethreshold;
134 static char serveremail[80];
135 static char vmfmts[80];
136 static int vmmaxmessage;
139 static int maxlogins;
145 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
147 return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
150 static int make_file(char *dest, int len, char *dir, int num)
152 return snprintf(dest, len, "%s/msg%04d", dir, num);
155 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
157 /* This function could be made to generate one from a database, too */
158 struct ast_vm_user *vmu=NULL, *cur;
159 ast_pthread_mutex_lock(&vmlock);
162 if ((!context || !strcasecmp(context, cur->context)) &&
163 (!strcasecmp(mailbox, cur->mailbox)))
171 /* Make a copy, so that on a reload, we have no race */
172 vmu = malloc(sizeof(struct ast_vm_user));
174 memcpy(vmu, cur, sizeof(struct ast_vm_user));
182 ast_pthread_mutex_unlock(&vmlock);
186 static int reset_user_pw(char *context, char *mailbox, char *newpass)
188 /* This function could be made to generate one from a database, too */
189 struct ast_vm_user *cur;
191 ast_pthread_mutex_lock(&vmlock);
194 if ((!context || !strcasecmp(context, cur->context)) &&
195 (!strcasecmp(mailbox, cur->mailbox)))
200 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
203 ast_pthread_mutex_unlock(&vmlock);
207 static int vm_change_password(struct ast_vm_user *vmu, char *newpassword)
209 /* There's probably a better way of doing this. */
210 /* That's why I've put the password change in a separate function. */
211 /* This could also be done with a database function */
217 char tmpin[AST_CONFIG_MAX_PATH];
218 char tmpout[AST_CONFIG_MAX_PATH];
219 char *user, *pass, *rest, *trim;
220 snprintf((char *)tmpin, sizeof(tmpin)-1, "%s/voicemail.conf",(char *)ast_config_AST_CONFIG_DIR);
221 snprintf((char *)tmpout, sizeof(tmpout)-1, "%s/voicemail.conf.new",(char *)ast_config_AST_CONFIG_DIR);
222 configin = fopen((char *)tmpin,"r");
223 configout = fopen((char *)tmpout,"w+");
225 while (!feof(configin)) {
226 /* Read in the line */
227 fgets(inbuf, sizeof(inbuf), configin);
228 if (!feof(configin)) {
229 /* Make a backup of it */
230 memcpy(orig, inbuf, sizeof(orig));
231 /* Strip trailing \n and comment */
232 inbuf[strlen(inbuf) - 1] = '\0';
233 user = strchr(inbuf, ';');
239 pass = strchr(user, '=');
242 while(*trim && *trim < 33) {
252 while(*pass && *pass < 33)
256 rest = strchr(pass,',');
263 if (user && pass && *user && *pass && !strcmp(user, vmu->mailbox) && !strcmp(pass, vmu->password)) {
264 /* This is the line */
266 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
268 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
271 /* Put it back like it was */
272 fprintf(configout, orig);
279 unlink((char *)tmpin);
280 rename((char *)tmpout,(char *)tmpin);
281 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
282 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
287 inbuf(struct baseio *bio, FILE *fi)
294 if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
309 inchar(struct baseio *bio, FILE *fi)
311 if(bio->iocp>=bio->iolen)
315 return bio->iobuf[bio->iocp++];
319 ochar(struct baseio *bio, int c, FILE *so)
321 if(bio->linelength>=BASELINELEN) {
322 if(fputs(eol,so)==EOF)
328 if(putc(((unsigned char)c),so)==EOF)
336 static int base_encode(char *filename, FILE *so)
338 unsigned char dtable[BASEMAXINLINE];
343 memset(&bio, 0, sizeof(bio));
344 bio.iocp = BASEMAXINLINE;
346 if ( !(fi = fopen(filename, "rb"))) {
347 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
355 dtable[26+i+9]= 'j'+i;
359 dtable[26+i+18]= 's'+i;
368 unsigned char igroup[3],ogroup[4];
371 igroup[0]= igroup[1]= igroup[2]= 0;
374 if ( (c = inchar(&bio, fi)) == EOF) {
379 igroup[n]= (unsigned char)c;
383 ogroup[0]= dtable[igroup[0]>>2];
384 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
385 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
386 ogroup[3]= dtable[igroup[2]&0x3F];
396 ochar(&bio, ogroup[i], so);
400 if(fputs(eol,so)==EOF)
408 static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid, char *attach, char *format, long duration)
419 if (!strcmp(format, "wav49"))
421 p = popen(SENDMAIL, "w");
423 gethostname(host, sizeof(host));
424 if (strchr(srcemail, '@'))
425 strncpy(who, srcemail, sizeof(who)-1);
427 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
429 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
432 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
433 fprintf(p, "Date: %s\n", date);
434 fprintf(p, "From: Asterisk PBX <%s>\n", who);
435 fprintf(p, "To: %s <%s>\n", name, email);
436 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum, mailbox);
437 fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host);
438 fprintf(p, "MIME-Version: 1.0\n");
439 if (attach_voicemail) {
441 snprintf(bound, sizeof(bound), "Boundary=%d%s%d", msgnum, mailbox, getpid());
443 fprintf(p, "Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n\n\n", bound);
445 fprintf(p, "--%s\n", bound);
447 fprintf(p, "Content-Type: TEXT/PLAIN; charset=US-ASCII\n\n");
448 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
449 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
451 "in mailbox %s from %s, on %s so you might\n"
452 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", name,
453 dur, msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date);
454 if (attach_voicemail) {
455 fprintf(p, "--%s\n", bound);
456 fprintf(p, "Content-Type: audio/x-wav; name=\"msg%04d.%s\"\n", msgnum, format);
457 fprintf(p, "Content-Transfer-Encoding: BASE64\n");
458 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
459 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
461 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
462 base_encode(fname, p);
463 fprintf(p, "\n\n--%s--\n.\n", bound);
467 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
473 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, long duration)
482 p = popen(SENDMAIL, "w");
485 gethostname(host, sizeof(host));
486 if (strchr(srcemail, '@'))
487 strncpy(who, srcemail, sizeof(who)-1);
489 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
491 snprintf(dur, sizeof(dur), "%ld:%02ld", duration / 60, duration % 60);
494 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
495 fprintf(p, "Date: %s\n", date);
496 fprintf(p, "From: Asterisk PBX <%s>\n", who);
497 fprintf(p, "To: %s\n", pager);
498 fprintf(p, "Subject: New VM\n\n");
499 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
500 fprintf(p, "New %s long msg in box %s\n"
501 "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
504 ast_log(LOG_WARNING, "Unable to launch '%s'\n", SENDMAIL);
510 static int get_date(char *s, int len)
516 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
519 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
523 snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
524 if (ast_fileexists(fn, NULL, NULL) > 0) {
525 res = ast_streamfile(chan, fn, chan->language);
528 res = ast_waitstream(chan, ecodes);
532 res = ast_streamfile(chan, "vm-theperson", chan->language);
535 res = ast_waitstream(chan, ecodes);
538 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
543 res = ast_streamfile(chan, "vm-isonphone", chan->language);
545 res = ast_streamfile(chan, "vm-isunavail", chan->language);
548 res = ast_waitstream(chan, ecodes);
552 static int play_and_wait(struct ast_channel *chan, char *fn)
555 d = ast_streamfile(chan, fn, chan->language);
558 d = ast_waitstream(chan, AST_DIGIT_ANY);
562 static int play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt)
566 int x, fmtcnt=1, res=-1,outmsg=0;
568 struct ast_filestream *others[MAX_OTHER_FORMATS];
569 char *sfmt[MAX_OTHER_FORMATS];
574 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
575 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
578 d = play_and_wait(chan, playfile);
580 d = ast_streamfile(chan, "beep",chan->language);
582 d = ast_waitstream(chan,"");
590 strsep(&stringp, "|");
591 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
592 sfmt[0] = strdupa(fmts);
594 while((fmt = strsep(&stringp, "|"))) {
595 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
596 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
599 sfmt[fmtcnt++] = strdupa(fmt);
604 for (x=0;x<fmtcnt;x++) {
605 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
606 ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
613 /* Loop forever, writing the packets we read to the writer(s), until
614 we read a # or get a hangup */
617 res = ast_waitfor(chan, 2000);
619 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
620 /* Try one more time in case of masq */
621 res = ast_waitfor(chan, 2000);
623 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
635 if (f->frametype == AST_FRAME_VOICE) {
636 /* write each format */
637 for (x=0;x<fmtcnt;x++) {
638 res = ast_writestream(others[x], f);
640 /* Exit on any error */
642 ast_log(LOG_WARNING, "Error writing frame\n");
646 } else if (f->frametype == AST_FRAME_DTMF) {
647 if (f->subclass == '#') {
648 if (option_verbose > 2)
649 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
658 if (maxtime < (end - start)) {
659 if (option_verbose > 2)
660 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
669 if (option_verbose > 2)
670 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
675 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
678 for (x=0;x<fmtcnt;x++) {
681 ast_stream_rewind(others[x], 1000);
682 ast_truncstream(others[x]);
683 ast_closestream(others[x]);
687 /* Let them know it worked */
688 ast_streamfile(chan, "vm-msgsaved", chan->language);
689 ast_waitstream(chan, "");
697 static void free_user(struct ast_vm_user *vmu)
703 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
713 char prefile[256]="";
721 /* XXX Need to be moved to play_and_record */
722 struct ast_dsp *sildet; /* silence detector dsp */
723 int totalsilence = 0;
725 int gotsilence = 0; /* did we timeout for silence? */
729 struct ast_vm_user *vmu;
730 struct ast_vm_user svm;
732 strncpy(tmp, ext, sizeof(tmp) - 1);
734 context = strchr(tmp, '@');
740 if ((vmu = find_user(&svm, context, ext))) {
741 /* Setup pre-file if appropriate */
743 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
745 snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
746 make_dir(dir, sizeof(dir), vmu->context, "", "");
747 /* It's easier just to try to make it than to check for its existence */
748 if (mkdir(dir, 0700) && (errno != EEXIST))
749 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
750 make_dir(dir, sizeof(dir), vmu->context, ext, "");
751 /* It's easier just to try to make it than to check for its existence */
752 if (mkdir(dir, 0700) && (errno != EEXIST))
753 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
754 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
755 if (mkdir(dir, 0700) && (errno != EEXIST))
756 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
757 if (ast_exists_extension(chan, strlen(chan->macrocontext) ? chan->macrocontext : chan->context, "o", 1, chan->callerid))
759 /* Play the beginning intro if desired */
760 if (strlen(prefile)) {
761 if (ast_fileexists(prefile, NULL, NULL) > 0) {
762 if (ast_streamfile(chan, prefile, chan->language) > -1)
763 res = ast_waitstream(chan, "#0");
765 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
766 res = invent_message(chan, vmu->context, ext, busy, ecodes);
769 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
775 /* On a '#' we skip the instructions */
779 if (!res && !silent) {
780 res = ast_streamfile(chan, INTRO, chan->language);
782 res = ast_waitstream(chan, ecodes);
788 /* Check for a '0' here */
790 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
791 if (strlen(chan->macrocontext))
792 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
798 /* Unless we're *really* silent, try to send the beep */
799 res = ast_streamfile(chan, "beep", chan->language);
801 res = ast_waitstream(chan, "");
807 /* The meat of recording the message... All the announcements and beeps have been played*/
808 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
812 make_file(fn, sizeof(fn), dir, msgnum);
813 snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
814 (chan->callerid ? chan->callerid : "Unknown"),
815 vmu->fullname, ext, chan->name);
816 if (ast_fileexists(fn, NULL, chan->language) <= 0)
819 } while(msgnum < MAXMSG);
820 if (msgnum < MAXMSG) {
821 /* Store information */
822 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
823 txt = fopen(txtfile, "w+");
825 get_date(date, sizeof(date));
829 "; Message Information file\n"
845 chan->callerid ? chan->callerid : "Unknown",
849 ast_log(LOG_WARNING, "Error opening text file for output\n");
850 res = play_and_record(chan, NULL, fn, vmmaxmessage, fmt);
853 txt = fopen(txtfile, "a");
856 fprintf(txt, "duration=%ld\n", end-start);
860 strsep(&stringp, "|");
861 /* Send e-mail if applicable */
862 if (strlen(vmu->email))
863 sendmail(serveremail, vmu->email, vmu->fullname, msgnum, ext, chan->callerid, fn, fmt, end - start);
864 if (strlen(vmu->pager))
865 sendpage(serveremail, vmu->pager, msgnum, ext, chan->callerid, end - start);
867 ast_log(LOG_WARNING, "No more messages possible\n");
869 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
872 sildet = ast_dsp_new(); //Create the silence detector
874 rfmt = chan->readformat;
875 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
877 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
881 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
884 ast_dsp_set_threshold(sildet, 50);
889 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
890 /* Leave voicemail for someone */
891 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext, ast_app_has_voicemail(ext));
895 static char *mbox(int id)
923 static int count_messages(char *dir)
927 for (x=0;x<MAXMSG;x++) {
928 make_file(fn, sizeof(fn), dir, x);
929 if (ast_fileexists(fn, NULL, NULL) < 1)
935 static int say_and_wait(struct ast_channel *chan, int num)
938 d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
942 static int copy(char *infile, char *outfile)
949 if ((ifd = open(infile, O_RDONLY)) < 0) {
950 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
953 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
954 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
959 len = read(ifd, buf, sizeof(buf));
961 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
967 res = write(ofd, buf, len);
969 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
981 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
988 char *dbox = mbox(box);
990 make_file(sfn, sizeof(sfn), dir, msg);
991 make_dir(ddir, sizeof(ddir), context, username, dbox);
993 for (x=0;x<MAXMSG;x++) {
994 make_file(dfn, sizeof(dfn), ddir, x);
995 if (ast_fileexists(dfn, NULL, NULL) < 0)
1000 ast_filecopy(sfn, dfn, NULL);
1001 if (strcmp(sfn, dfn)) {
1002 snprintf(txt, sizeof(txt), "%s.txt", sfn);
1003 snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
1009 static int adsi_logo(unsigned char *buf)
1012 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
1013 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
1017 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
1025 bytes += adsi_data_mode(buf + bytes);
1026 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1029 bytes += adsi_logo(buf);
1030 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1032 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
1034 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1035 bytes += adsi_data_mode(buf + bytes);
1036 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1038 if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
1040 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
1041 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1042 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1043 bytes += adsi_voice_mode(buf + bytes, 0);
1044 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1051 bytes += adsi_logo(buf);
1052 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
1053 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
1054 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1055 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1058 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
1059 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
1060 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
1061 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
1062 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
1063 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
1064 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1067 /* Add another dot */
1069 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
1070 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1071 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1075 /* These buttons we load but don't use yet */
1076 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
1077 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
1078 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
1079 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
1080 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
1081 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
1082 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1085 /* Add another dot */
1087 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
1088 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1089 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1094 snprintf(num, sizeof(num), "%d", x);
1095 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
1097 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
1098 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1101 /* Add another dot */
1103 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
1104 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1105 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1108 if (adsi_end_download(chan)) {
1110 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
1111 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
1112 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1113 bytes += adsi_voice_mode(buf + bytes, 0);
1114 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1118 bytes += adsi_download_disconnect(buf + bytes);
1119 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
1121 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
1126 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
1127 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1129 ast_log(LOG_DEBUG, "Restarting session...\n");
1132 /* Load the session now */
1133 if (adsi_load_session(chan, adapp, adver, 1) == 1) {
1135 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
1137 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
1139 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1143 static void adsi_begin(struct ast_channel *chan, int *useadsi)
1146 if (!adsi_available(chan))
1148 x = adsi_load_session(chan, adapp, adver, 1);
1152 if (adsi_load_vmail(chan, useadsi)) {
1153 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
1160 static void adsi_login(struct ast_channel *chan)
1164 unsigned char keys[8];
1166 if (!adsi_available(chan))
1171 /* Set one key for next */
1172 keys[3] = ADSI_KEY_APPS + 3;
1174 bytes += adsi_logo(buf + bytes);
1175 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
1176 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
1177 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1178 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
1179 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
1180 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
1181 bytes += adsi_set_keys(buf + bytes, keys);
1182 bytes += adsi_voice_mode(buf + bytes, 0);
1183 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1186 static void adsi_password(struct ast_channel *chan)
1190 unsigned char keys[8];
1192 if (!adsi_available(chan))
1197 /* Set one key for next */
1198 keys[3] = ADSI_KEY_APPS + 3;
1200 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1201 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
1202 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
1203 bytes += adsi_set_keys(buf + bytes, keys);
1204 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1207 static void adsi_folders(struct ast_channel *chan, int start, char *label)
1211 unsigned char keys[8];
1214 if (!adsi_available(chan))
1218 y = ADSI_KEY_APPS + 12 + start + x;
1219 if (y > ADSI_KEY_APPS + 12 + 4)
1221 keys[x] = ADSI_KEY_SKT | y;
1223 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
1227 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
1228 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
1229 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1230 bytes += adsi_set_keys(buf + bytes, keys);
1231 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1234 static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
1237 char buf[256], buf1[256], buf2[256];
1242 char datetime[21]="";
1245 unsigned char keys[8];
1249 if (!adsi_available(chan))
1252 /* Retrieve important info */
1253 snprintf(fn2, sizeof(fn2), "%s.txt", fn);
1254 f = fopen(fn2, "r");
1257 fgets(buf, sizeof(buf), f);
1261 strsep(&stringp, "=");
1262 val = strsep(&stringp, "=");
1263 if (val && strlen(val)) {
1264 if (!strcmp(buf, "callerid"))
1265 strncpy(cid, val, sizeof(cid) - 1);
1266 if (!strcmp(buf, "origdate"))
1267 strncpy(datetime, val, sizeof(datetime) - 1);
1273 /* New meaning for keys */
1275 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1280 /* No prev key, provide "Folder" instead */
1281 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1284 /* If last message ... */
1286 /* but not only message, provide "Folder" instead */
1287 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1289 /* Otherwise if only message, leave blank */
1295 ast_callerid_parse(cid, &name, &num);
1299 name = "Unknown Caller";
1301 /* If deleted, show "undeleted" */
1303 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1306 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1307 snprintf(buf1, sizeof(buf1), "%s%s", folder,
1308 strcasecmp(folder, "INBOX") ? " Messages" : "");
1309 snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
1311 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1312 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1313 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
1314 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
1315 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1316 bytes += adsi_set_keys(buf + bytes, keys);
1317 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1320 static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
1324 unsigned char keys[8];
1328 if (!adsi_available(chan))
1331 /* New meaning for keys */
1333 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
1339 /* No prev key, provide "Folder" instead */
1340 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1343 /* If last message ... */
1345 /* but not only message, provide "Folder" instead */
1346 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
1348 /* Otherwise if only message, leave blank */
1353 /* If deleted, show "undeleted" */
1355 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
1358 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
1359 bytes += adsi_set_keys(buf + bytes, keys);
1360 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1363 static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
1365 char buf[256], buf1[256], buf2[256];
1367 unsigned char keys[8];
1370 char *newm = (new == 1) ? "message" : "messages";
1371 char *oldm = (old == 1) ? "message" : "messages";
1372 if (!adsi_available(chan))
1375 snprintf(buf1, sizeof(buf1), "You have %d new", new);
1377 strcat(buf1, " and");
1378 snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
1380 snprintf(buf2, sizeof(buf2), "%s.", newm);
1383 snprintf(buf1, sizeof(buf1), "You have %d old", old);
1384 snprintf(buf2, sizeof(buf2), "%s.", oldm);
1386 strcpy(buf1, "You have no messages.");
1389 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1390 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1391 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1394 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1398 /* Don't let them listen if there are none */
1401 bytes += adsi_set_keys(buf + bytes, keys);
1403 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1406 static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
1408 char buf[256], buf1[256], buf2[256];
1410 unsigned char keys[8];
1413 char *mess = (messages == 1) ? "message" : "messages";
1415 if (!adsi_available(chan))
1418 /* Original command keys */
1420 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
1428 snprintf(buf1, sizeof(buf1), "%s%s has", folder,
1429 strcasecmp(folder, "INBOX") ? " folder" : "");
1432 snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
1434 strcpy(buf2, "no messages.");
1435 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
1436 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
1437 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
1438 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1439 bytes += adsi_set_keys(buf + bytes, keys);
1441 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1445 static void adsi_clear(struct ast_channel *chan)
1449 if (!adsi_available(chan))
1451 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1452 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1455 static void adsi_goodbye(struct ast_channel *chan)
1460 if (!adsi_available(chan))
1462 bytes += adsi_logo(buf + bytes);
1463 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
1464 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
1465 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
1466 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
1469 static int get_folder(struct ast_channel *chan, int start)
1474 d = play_and_wait(chan, "vm-press");
1477 for (x = start; x< 5; x++) {
1478 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
1480 d = play_and_wait(chan, "vm-for");
1483 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
1484 d = play_and_wait(chan, fn);
1487 d = play_and_wait(chan, "vm-messages");
1490 d = ast_waitfordigit(chan, 500);
1494 d = play_and_wait(chan, "vm-tocancel");
1497 d = ast_waitfordigit(chan, 4000);
1501 static int get_folder2(struct ast_channel *chan, char *fn, int start)
1504 res = play_and_wait(chan, fn);
1505 while (((res < '0') || (res > '9')) &&
1506 (res != '#') && (res >= 0)) {
1507 res = get_folder(chan, 0);
1513 forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
1520 struct ast_config *mif;
1525 struct ast_vm_user *receiver, srec;
1530 res = ast_streamfile(chan, "vm-extension", chan->language);
1533 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
1535 if ((receiver = find_user(&srec, context, username))) {
1536 printf("Got %d\n", atoi(username));
1537 /* if (play_and_wait(chan, "vm-savedto"))
1541 snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, receiver->context, username);
1542 snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
1543 ast_log(LOG_DEBUG, sys);
1546 todircount = count_messages(todir);
1547 strncpy(tmp, fmt, sizeof(tmp));
1549 while((s = strsep(&stringp, "|"))) {
1550 snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
1551 ast_log(LOG_DEBUG, sys);
1554 snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
1556 /* load the information on the source message so we can send an e-mail like a new message */
1557 snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
1558 if ((mif=ast_load(miffile))) {
1560 /* set callerid and duration variables */
1561 snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
1562 duration = atol(ast_variable_retrieve(mif, NULL, "duration"));
1564 if (strlen(receiver->email))
1565 sendmail(serveremail, receiver->email, receiver->fullname, todircount, username, callerid, fn, tmp, atol(ast_variable_retrieve(mif, NULL, "duration")));
1567 if (strlen(receiver->pager))
1568 sendpage(serveremail, receiver->pager, todircount, username, callerid, duration);
1570 ast_destroy(mif); /* or here */
1573 /* give confirmatopm that the message was saved */
1574 res = play_and_wait(chan, "vm-message");
1576 res = play_and_wait(chan, "vm-saved");
1577 free_user(receiver);
1580 res = play_and_wait(chan, "pbx-invalid");
1593 int deleted[MAXMSG];
1604 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
1607 if ((res = ast_streamfile(chan, file, chan->language)))
1608 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1610 res = ast_waitstream(chan, AST_DIGIT_ANY);
1614 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
1617 if ((res = ast_streamfile(chan, file, chan->language)))
1618 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
1620 res = ast_waitstream_fr(chan, AST_DIGIT_ANY, "#", "*",skipms);
1624 static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg)
1628 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1629 adsi_message(chan, vms->curbox, msg, vms->lastmsg, vms->deleted[msg], vms->fn);
1631 res = wait_file2(chan, vms, "vm-first");
1632 else if (msg == vms->lastmsg)
1633 res = wait_file2(chan, vms, "vm-last");
1635 res = wait_file2(chan, vms, "vm-message");
1636 if (msg && (msg != vms->lastmsg)) {
1638 res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language);
1643 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
1644 vms->heard[msg] = 1;
1645 res = wait_file(chan, vms, vms->fn);
1650 static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
1652 strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
1653 make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
1654 vms->lastmsg = count_messages(vms->curdir) - 1;
1655 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
1658 static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
1661 char ntxt[256] = "";
1663 if (vms->lastmsg > -1) {
1664 /* Get the deleted messages fixed */
1666 for (x=0;x<=vms->lastmsg;x++) {
1667 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
1668 /* Save this message. It's not in INBOX or hasn't been heard */
1670 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1671 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
1672 if (strcmp(vms->fn, vms->fn2)) {
1673 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1674 snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
1675 ast_filerename(vms->fn, vms->fn2, NULL);
1678 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
1679 /* Move to old folder before deleting */
1680 save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
1683 for (x = vms->curmsg + 1; x<=vms->lastmsg; x++) {
1684 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
1685 snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
1686 ast_filedelete(vms->fn, NULL);
1690 memset(vms->deleted, 0, sizeof(vms->deleted));
1691 memset(vms->heard, 0, sizeof(vms->heard));
1694 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
1696 /* Introduce messages they have */
1698 res = play_and_wait(chan, "vm-youhave");
1700 if (vms->newmessages) {
1701 res = say_and_wait(chan, vms->newmessages);
1703 res = play_and_wait(chan, "vm-INBOX");
1704 if (vms->oldmessages && !res)
1705 res = play_and_wait(chan, "vm-and");
1707 if ((vms->newmessages == 1))
1708 res = play_and_wait(chan, "vm-message");
1710 res = play_and_wait(chan, "vm-messages");
1714 if (!res && vms->oldmessages) {
1715 res = say_and_wait(chan, vms->oldmessages);
1717 res = play_and_wait(chan, "vm-Old");
1719 if (vms->oldmessages == 1)
1720 res = play_and_wait(chan, "vm-message");
1722 res = play_and_wait(chan, "vm-messages");
1726 if (!vms->oldmessages && !vms->newmessages) {
1727 res = play_and_wait(chan, "vm-no");
1729 res = play_and_wait(chan, "vm-messages");
1736 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms)
1739 /* Play instructions and wait for new command */
1741 if (vms->starting) {
1742 if (vms->lastmsg > -1) {
1743 res = play_and_wait(chan, "vm-onefor");
1745 res = play_and_wait(chan, vms->vmbox);
1747 res = play_and_wait(chan, "vm-messages");
1750 res = play_and_wait(chan, "vm-opts");
1753 res = play_and_wait(chan, "vm-prev");
1755 res = play_and_wait(chan, "vm-repeat");
1756 if (!res && (vms->curmsg != vms->lastmsg))
1757 res = play_and_wait(chan, "vm-next");
1759 if (!vms->deleted[vms->curmsg])
1760 res = play_and_wait(chan, "vm-delete");
1762 res = play_and_wait(chan, "vm-undelete");
1764 res = play_and_wait(chan, "vm-toforward");
1766 res = play_and_wait(chan, "vm-savemessage");
1770 res = play_and_wait(chan, "vm-helpexit");
1772 res = ast_waitfordigit(chan, 6000);
1775 if (vms->repeats > 2) {
1776 res = play_and_wait(chan, "vm-goodbye");
1785 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
1789 char newpassword[80] = "";
1790 char newpassword2[80] = "";
1791 char prefile[256]="";
1792 while((cmd >= 0) && (cmd != 't')) {
1797 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
1798 cmd = play_and_record(chan,"vm-rec-unv",prefile, maxgreet, fmtc);
1801 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
1802 cmd = play_and_record(chan,"vm-rec-busy",prefile, maxgreet, fmtc);
1805 snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
1806 cmd = play_and_record(chan,"vm-rec-name",prefile, maxgreet, fmtc);
1809 newpassword[1] = '\0';
1810 newpassword[0] = cmd = play_and_wait(chan,"vm-newpassword");
1813 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
1816 newpassword2[1] = '\0';
1817 newpassword2[0] = cmd = play_and_wait(chan,"vm-reenterpassword");
1821 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
1824 if (strcmp(newpassword, newpassword2)) {
1825 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
1826 cmd = play_and_wait(chan, "vm-mismatch");
1829 if (vm_change_password(vmu,newpassword) < 0)
1831 ast_log(LOG_DEBUG,"Failed to set new password of user %s\n",vms->username);
1833 ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,strlen(newpassword));
1834 cmd = play_and_wait(chan,"vm-passchanged");
1840 cmd = play_and_wait(chan,"vm-options");
1842 cmd = ast_waitfordigit(chan,6000);
1854 static int vm_execmain(struct ast_channel *chan, void *data)
1856 /* XXX This is, admittedly, some pretty horrendus code. For some
1857 reason it just seemed a lot easier to do with GOTO's. I feel
1858 like I'm back in my GWBASIC days. XXX */
1863 struct localuser *u;
1864 char prefixstr[80] ="";
1865 char empty[80] = "";
1869 char tmp[256], *ext;
1870 char fmtc[256] = "";
1872 struct vm_state vms;
1874 struct ast_vm_user *vmu = NULL, vmus;
1878 memset(&vms, 0, sizeof(vms));
1879 strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
1880 if (chan->_state != AST_STATE_UP)
1883 if (data && strlen(data)) {
1884 strncpy(tmp, data, sizeof(tmp) - 1);
1889 /* We should skip the user's password */
1894 /* We should prefix the mailbox with the supplied data */
1900 context = strchr(ext, '@');
1907 strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
1909 strncpy(vms.username, ext, sizeof(vms.username) - 1);
1910 if (strlen(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
1917 /* If ADSI is supported, setup login screen */
1918 adsi_begin(chan, &useadsi);
1919 if (!skipuser && useadsi)
1921 if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
1922 ast_log(LOG_WARNING, "Couldn't stream login file\n");
1926 /* Authenticate them and get their mailbox/password */
1928 while (!valid && (logretries < maxlogins)) {
1929 /* Prompt for, and read in the username */
1930 if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
1931 ast_log(LOG_WARNING, "Couldn't read username\n");
1934 if (!strlen(vms.username)) {
1935 if (option_verbose > 2)
1936 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
1941 adsi_password(chan);
1942 if (ast_streamfile(chan, "vm-password", chan->language)) {
1943 ast_log(LOG_WARNING, "Unable to stream password file\n");
1946 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
1947 ast_log(LOG_WARNING, "Unable to read password\n");
1951 char fullusername[80] = "";
1952 strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
1953 strncat(fullusername, vms.username, sizeof(fullusername) - 1);
1954 strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
1957 vmu = find_user(&vmus, context, vms.username);
1958 if (vmu && !strcmp(vmu->password, password))
1961 if (option_verbose > 2)
1962 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
1964 strncpy(vms.username, empty, sizeof(vms.username) -1);
1969 if (ast_streamfile(chan, "vm-incorrect", chan->language))
1974 if (!valid && (logretries >= maxlogins)) {
1975 ast_stopstream(chan);
1976 res = play_and_wait(chan, "vm-goodbye");
1982 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
1983 mkdir(vms.curdir, 0700);
1984 snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
1985 mkdir(vms.curdir, 0700);
1986 /* Retrieve old and new message counts */
1987 open_mailbox(&vms, vmu, 1);
1988 vms.oldmessages = vms.lastmsg + 1;
1989 /* Start in INBOX */
1990 open_mailbox(&vms, vmu, 0);
1991 vms.newmessages = vms.lastmsg + 1;
1994 /* Select proper mailbox FIRST!! */
1995 if (!vms.newmessages && vms.oldmessages) {
1996 /* If we only have old messages start here */
1997 open_mailbox(&vms, vmu, 1);
2001 adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
2003 cmd = vm_intro(chan, &vms);
2006 while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
2013 if (vms.lastmsg > -1) {
2014 cmd = play_message(chan, &vms, vms.curmsg);
2016 cmd = play_and_wait(chan, "vm-youhave");
2018 cmd = play_and_wait(chan, "vm-no");
2020 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", vms.curbox);
2021 cmd = play_and_wait(chan, vms.fn);
2024 cmd = play_and_wait(chan, "vm-messages");
2027 case '2': /* Change folders */
2029 adsi_folders(chan, 0, "Change to folder...");
2030 cmd = get_folder2(chan, "vm-changeto", 0);
2033 } else if (cmd > 0) {
2035 close_mailbox(&vms, vmu);
2036 open_mailbox(&vms, vmu, cmd);
2040 adsi_status2(chan, vms.curbox, vms.lastmsg + 1);
2042 cmd = play_and_wait(chan, vms.vmbox);
2044 cmd = play_and_wait(chan, "vm-messages");
2050 cmd = play_message(chan, &vms, vms.curmsg);
2052 cmd = play_and_wait(chan, "vm-nomore");
2056 if (vms.curmsg < vms.lastmsg) {
2058 cmd = play_message(chan, &vms, vms.curmsg);
2060 cmd = play_and_wait(chan, "vm-nomore");
2064 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
2066 adsi_delete(chan, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg]);
2067 if (vms.deleted[vms.curmsg])
2068 cmd = play_and_wait(chan, "vm-deleted");
2070 cmd = play_and_wait(chan, "vm-undeleted");
2073 if(vms.lastmsg > -1)
2074 cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts);
2078 adsi_folders(chan, 1, "Save to folder...");
2079 cmd = get_folder2(chan, "vm-savefolder", 1);
2080 box = 0; /* Shut up compiler */
2084 } else if (cmd > 0) {
2085 box = cmd = cmd - '0';
2086 cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
2087 vms.deleted[vms.curmsg]=1;
2089 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
2091 adsi_message(chan, vms.curbox, vms.curmsg, vms.lastmsg, vms.deleted[vms.curmsg], vms.fn);
2093 cmd = play_and_wait(chan, "vm-message");
2095 cmd = say_and_wait(chan, vms.curmsg + 1);
2097 cmd = play_and_wait(chan, "vm-savedto");
2099 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
2100 cmd = play_and_wait(chan, vms.fn);
2103 cmd = play_and_wait(chan, "vm-messages");
2106 if (!vms.starting) {
2107 cmd = play_and_wait(chan, "vm-onefor");
2109 cmd = play_and_wait(chan, vms.vmbox);
2111 cmd = play_and_wait(chan, "vm-messages");
2113 cmd = play_and_wait(chan, "vm-opts");
2118 cmd = vm_options(chan, vmu, &vms, vmfmts);
2121 ast_stopstream(chan);
2123 cmd = play_and_wait(chan, "vm-goodbye");
2127 default: /* Nothing */
2128 cmd = vm_instructions(chan, &vms);
2132 if ((cmd == 't') || (cmd == '#')) {
2142 ast_stopstream(chan);
2145 adsi_unload_session(chan);
2148 close_mailbox(&vms, vmu);
2152 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vms.username, ast_app_has_voicemail(vms.username));
2154 LOCAL_USER_REMOVE(u);
2159 static int vm_exec(struct ast_channel *chan, void *data)
2161 int res=0, silent=0, busy=0, unavail=0;
2162 struct localuser *u;
2163 char tmp[256], *ext;
2166 if (chan->_state != AST_STATE_UP)
2169 strncpy(tmp, data, sizeof(tmp) - 1);
2171 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
2182 } else if (*ext == 'b') {
2185 } else if (*ext == 'u') {
2191 res = leave_voicemail(chan, ext, silent, busy, unavail);
2192 LOCAL_USER_REMOVE(u);
2196 static int append_mailbox(char *context, char *mbox, char *data)
2198 /* Assumes lock is already held */
2202 struct ast_vm_user *vmu;
2203 strncpy(tmp, data, sizeof(tmp));
2204 vmu = malloc(sizeof(struct ast_vm_user));
2206 memset(vmu, 0, sizeof(struct ast_vm_user));
2207 strncpy(vmu->context, context, sizeof(vmu->context));
2208 strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox));
2210 if ((s = strsep(&stringp, ",")))
2211 strncpy(vmu->password, s, sizeof(vmu->password));
2212 if ((s = strsep(&stringp, ",")))
2213 strncpy(vmu->fullname, s, sizeof(vmu->fullname));
2214 if ((s = strsep(&stringp, ",")))
2215 strncpy(vmu->email, s, sizeof(vmu->email));
2216 if ((s = strsep(&stringp, ",")))
2217 strncpy(vmu->pager, s, sizeof(vmu->pager));
2228 static int load_users(void)
2230 struct ast_vm_user *cur, *l;
2231 struct ast_config *cfg;
2233 struct ast_variable *var;
2241 cfg = ast_load(VOICEMAIL_CONFIG);
2242 ast_pthread_mutex_lock(&vmlock);
2252 /* General settings */
2253 attach_voicemail = 1;
2254 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
2256 attach_voicemail = ast_true(astattach);
2258 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
2259 maxsilence = atoi(silencestr);
2264 silencethreshold = 256;
2265 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
2266 silencethreshold = atoi(thresholdstr);
2268 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
2269 astemail = ASTERISK_USERNAME;
2270 strncpy(serveremail, astemail, sizeof(serveremail) - 1);
2273 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
2274 if (sscanf(s, "%d", &x) == 1) {
2277 ast_log(LOG_WARNING, "Invalid max message time length\n");
2280 fmt = ast_variable_retrieve(cfg, "general", "format");
2283 strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
2286 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
2287 if (sscanf(s, "%d", &x) == 1) {
2290 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
2294 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
2295 if (sscanf(s, "%d", &x) == 1) {
2298 ast_log(LOG_WARNING, "Invalid skipms value\n");
2303 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
2304 if (sscanf(s, "%d", &x) == 1) {
2307 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
2311 cat = ast_category_browse(cfg, NULL);
2313 if (strcasecmp(cat, "general")) {
2314 /* Process mailboxes in this context */
2315 var = ast_variable_browse(cfg, cat);
2317 append_mailbox(cat, var->name, var->value);
2321 cat = ast_category_browse(cfg, cat);
2325 ast_pthread_mutex_unlock(&vmlock);
2335 int unload_module(void)
2338 STANDARD_HANGUP_LOCALUSERS;
2339 res = ast_unregister_application(app);
2340 res |= ast_unregister_application(app2);
2344 int load_module(void)
2348 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
2350 res = ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
2354 char *description(void)
2362 STANDARD_USECOUNT(res);
2368 return ASTERISK_GPL_KEY;