diff --git a/apps/app_directory.c b/apps/app_directory.c index 551f61faef..bea790293f 100755 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -30,11 +30,12 @@ static char *app = "Directory"; static char *synopsis = "Provide directory of voicemail extensions"; static char *descrip = -" Directory(context): Presents the user with a directory of extensions from which\n" -" they may select by name. The list of names and extensions is discovered from\n" -" voicemail.conf. The context argument is required, and specifies the context\n" -" in which to interpret the extensions\n. Returns 0 unless the user hangs up. It\n" -" also sets up the channel on exit to enter the extension the user selected.\n"; +" Directory(context): Presents the user with a directory of extensions from\n" +"which they may select by name. The list of names and extensions is\n" +"discovered from voicemail.conf. The context argument is required, and\n" +"specifies the context in which to interpret the extensions\n. Returns 0\n" +"unless the user hangs up. It also sets up the channel on exit to enter the\n" +"extension the user selected.\n"; /* For simplicity, I'm keeping the format compatible with the voicemail config, but i'm open to suggestions for isolating it */ @@ -129,7 +130,8 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char * char fn[256]; memset(ext, 0, sizeof(ext)); ext[0] = digit; - res = ast_readstring(chan, ext + 1, NUMDIGITS, 3000, 3000, "#"); + res = 0; + if (ast_readstring(chan, ext + 1, NUMDIGITS, 3000, 3000, "#") < 0) res = -1; if (!res) { /* Search for all names which start with those digits */ v = ast_variable_browse(cfg, context); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 356e1015d3..5321466406 100755 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -37,10 +37,6 @@ #define VOICEMAIL_CONFIG "voicemail.conf" #define ASTERISK_USERNAME "asterisk" -/* -#define HOSTNAME_OVERRIDE "linux-support.net" -*/ - #define SENDMAIL "/usr/sbin/sendmail -t" #define INTRO "vm-intro" @@ -58,10 +54,10 @@ static char *synopsis_vm = "Leave a voicemail message"; static char *descrip_vm = -" VoiceMail([s]extension): Leaves voicemail for a given extension (must be configured in\n" -" voicemail.conf). If the extension is preceeded by an 's' then instructions for leaving\n" -" the message will be skipped. Returns -1 on error or mailbox not found, or if the user\n" -" hangs up. Otherwise, it returns 0. \n"; +" VoiceMail([s]extension): Leaves voicemail for a given extension (must be\n" +"configured in voicemail.conf). If the extension is preceeded by an 's' then\n" +"instructions for leaving the message will be skipped. Returns -1 on error\n" +"or mailbox not found, or if the user hangs up. Otherwise, it returns 0. \n"; static char *synopsis_vmain = "Enter voicemail system"; @@ -80,19 +76,18 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; -static char *get_dir(char *ext, char *mailbox) +static int make_dir(char *dest, int len, char *ext, char *mailbox) { - char *tmp = malloc(strlen(ext) + strlen(VM_SPOOL_DIR) + 3 + strlen(mailbox)); - sprintf(tmp, "%s/%s/%s", VM_SPOOL_DIR, ext, mailbox); - return tmp; + return snprintf(dest, len, "%s/%s/%s", VM_SPOOL_DIR, ext, mailbox); } -static char *get_fn(char *dir, int num) + +static int make_file(char *dest, int len, char *dir, int num) { - char *tmp = malloc(strlen(dir) + 10); - sprintf(tmp, "%s/msg%04d", dir, num); - return tmp; + return snprintf(dest, len, "%s/msg%04d", dir, num); } +#if 0 + static int announce_message(struct ast_channel *chan, char *dir, int msgcnt) { char *fn; @@ -115,34 +110,37 @@ static int announce_message(struct ast_channel *chan, char *dir, int msgcnt) ast_log(LOG_WARNING, "Unable to announce message\n"); return res; } -static int sendmail(char *email, char *name, int msgnum, char *mailbox) +#endif + +static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *mailbox, char *callerid) { FILE *p; char date[256]; char host[256]; + char who[256]; time_t t; struct tm *tm; p = popen(SENDMAIL, "w"); if (p) { - gethostname(host, sizeof(host)); + if (strchr(srcemail, '@')) + strncpy(who, srcemail, sizeof(who)); + else { + gethostname(host, sizeof(host)); + snprintf(who, sizeof(who), "%s@%s", srcemail, host); + } time(&t); tm = localtime(&t); strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", tm); fprintf(p, "Date: %s\n", date); fprintf(p, "Message-ID: <Asterisk-%d-%s-%d@%s>\n", msgnum, mailbox, getpid(), host); - fprintf(p, "From: Asterisk PBX <%s@%s>\n", ASTERISK_USERNAME, -#ifdef HOSTNAME_OVERRIDE - HOSTNAME_OVERRIDE -#else - host -#endif - ); + fprintf(p, "From: Asterisk PBX <%s>\n", who); fprintf(p, "To: %s <%s>\n", name, email); fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n\n", msgnum, mailbox); strftime(date, sizeof(date), "%A, %B %d, %Y at %r", tm); fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a message (number %d)\n" - "in mailbox %s, on %s so you might\n" - "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n", name, msgnum, mailbox, date); + "in mailbox %s from %s, on %s so you might\n" + "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n", name, + msgnum, mailbox, (callerid ? callerid : "an unknown caller"), date); fprintf(p, ".\n"); pclose(p); } else { @@ -164,7 +162,7 @@ static int get_date(char *s, int len) static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) { struct ast_config *cfg; - char *copy, *name, *passwd, *email, *dir, *fmt, *fmts, *fn=NULL; + char *copy, *name, *passwd, *email, *fmt, *fmts; char comment[256]; struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; @@ -175,23 +173,28 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) int outmsg=0; struct ast_frame *f; char date[256]; + char dir[256]; + char fn[256]; + char *astemail; cfg = ast_load(VOICEMAIL_CONFIG); if (!cfg) { ast_log(LOG_WARNING, "No such configuration file %s\n", VOICEMAIL_CONFIG); return -1; } + if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) + astemail = ASTERISK_USERNAME; if ((copy = ast_variable_retrieve(cfg, NULL, ext))) { /* Make sure they have an entry in the config */ copy = strdup(copy); passwd = strtok(copy, ","); name = strtok(NULL, ","); email = strtok(NULL, ","); - dir = get_dir(ext, ""); + make_dir(dir, sizeof(dir), ext, ""); /* It's easier just to try to make it than to check for its existence */ if (mkdir(dir, 0700) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - dir = get_dir(ext, "INBOX"); + make_dir(dir, sizeof(dir), ext, "INBOX"); if (mkdir(dir, 0700) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); /* Stream an info message */ @@ -204,9 +207,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) fmt = strtok(fmts, "|"); msgnum = 0; do { - if (fn) - free(fn); - fn = get_fn(dir, msgnum); + make_file(fn, sizeof(fn), dir, msgnum); snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n", (chan->callerid ? chan->callerid : "Unknown"), name, ext, chan->name); @@ -328,7 +329,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) } /* Send e-mail if applicable */ if (email) - sendmail(email, name, msgnum, ext); + sendmail(astemail, email, name, msgnum, ext, chan->callerid); } } else { if (msgnum < MAXMSG) @@ -336,8 +337,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) else ast_log(LOG_WARNING, "Too many messages in mailbox %s\n", ext); } - if (fn) - free(fn); free(fmts); } else ast_log(LOG_WARNING, "No format to save messages in \n"); @@ -345,7 +344,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) } else ast_log(LOG_WARNING, "Unable to playback instructions\n"); - free(dir); free(copy); } else ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); @@ -354,25 +352,276 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent) return res; } +static char *mbox(int id) +{ + switch(id) { + case 0: + return "INBOX"; + case 1: + return "Old"; + case 2: + return "Work"; + case 3: + return "Family"; + case 4: + return "Friends"; + case 5: + return "Cust1"; + case 6: + return "Cust2"; + case 7: + return "Cust3"; + case 8: + return "Cust4"; + case 9: + return "Cust5"; + default: + return "Unknown"; + } +} + +static int count_messages(char *dir) +{ + int x; + char fn[256]; + for (x=0;x<MAXMSG;x++) { + make_file(fn, sizeof(fn), dir, x); + if (ast_fileexists(fn, NULL, NULL) < 1) + break; + } + return x; +} + +static int play_and_wait(struct ast_channel *chan, char *fn) +{ + int d; + d = ast_streamfile(chan, fn, chan->language); + if (d) + return d; + d = ast_waitstream(chan, AST_DIGIT_ANY); + return d; +} + +static int say_and_wait(struct ast_channel *chan, int num) +{ + int d; + d = ast_say_number(chan, num, chan->language); + return d; +} + +static int copy(char *infile, char *outfile) +{ + int ifd; + int ofd; + int res; + int len; + char buf[4096]; + if ((ifd = open(infile, O_RDONLY)) < 0) { + ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile); + return -1; + } + if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { + ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile); + close(ifd); + return -1; + } + do { + len = read(ifd, buf, sizeof(buf)); + if (len < 0) { + ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno)); + close(ifd); + close(ofd); + unlink(outfile); + } + if (len) { + res = write(ofd, buf, len); + if (res != len) { + ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno)); + close(ifd); + close(ofd); + unlink(outfile); + } + } + } while(len); + close(ifd); + close(ofd); + return 0; +} + +static int save_to_folder(char *dir, int msg, char *username, int box) +{ + char sfn[256]; + char dfn[256]; + char ddir[256]; + char txt[256]; + char ntxt[256]; + char *dbox = mbox(box); + int x; + make_file(sfn, sizeof(sfn), dir, msg); + make_dir(ddir, sizeof(ddir), username, dbox); + mkdir(ddir, 0700); + for (x=0;x<MAXMSG;x++) { + make_file(dfn, sizeof(dfn), ddir, x); + if (ast_fileexists(dfn, NULL, NULL) < 0) + break; + } + if (x >= MAXMSG) + return -1; + ast_filecopy(sfn, dfn, NULL); + if (strcmp(sfn, dfn)) { + snprintf(txt, sizeof(txt), "%s.txt", sfn); + snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn); + copy(txt, ntxt); + } + return 0; +} + +static int get_folder(struct ast_channel *chan, int start) +{ + int x; + int d; + char fn[256]; + d = play_and_wait(chan, "vm-press"); + if (d) + return d; + for (x = start; x< 5; x++) { + if ((d = ast_say_number(chan, x, chan->language))) + return d; + d = play_and_wait(chan, "vm-for"); + if (d) + return d; + snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); + d = play_and_wait(chan, fn); + if (d) + return d; + d = play_and_wait(chan, "vm-messages"); + if (d) + return d; + d = ast_waitfordigit(chan, 500); + if (d) + return d; + } + d = play_and_wait(chan, "vm-tocancel"); + if (d) + return d; + d = ast_waitfordigit(chan, 4000); + return d; +} + +#define WAITCMD(a) do { \ + d = (a); \ + if (d < 0) \ + goto out; \ + if (d) \ + goto cmd; \ +} while(0) + +#define WAITFILE2(file) do { \ + if (ast_streamfile(chan, file, chan->language)) \ + ast_log(LOG_WARNING, "Unable to play message %s\n", file); \ + d = ast_waitstream(chan, AST_DIGIT_ANY); \ + if (d < 0) { \ + goto out; \ + }\ +} while(0) + +#define WAITFILE(file) do { \ + if (ast_streamfile(chan, file, chan->language)) \ + ast_log(LOG_WARNING, "Unable to play message %s\n", file); \ + d = ast_waitstream(chan, AST_DIGIT_ANY); \ + if (!d) { \ + repeats = 0; \ + goto instructions; \ + } else if (d < 0) { \ + goto out; \ + } else goto cmd;\ +} while(0) + +#define PLAYMSG(a) do { \ + starting = 0; \ + if (!a) \ + WAITFILE2("vm-first"); \ + else if (a == lastmsg) \ + WAITFILE2("vm-last"); \ + WAITFILE2("vm-message"); \ + if (a && (a != lastmsg)) { \ + d = ast_say_number(chan, a + 1, chan->language); \ + if (d < 0) goto out; \ + if (d) goto cmd; \ + } \ + make_file(fn, sizeof(fn), curdir, a); \ + heard[a] = 1; \ + WAITFILE(fn); \ +} while(0) + +#define CLOSE_MAILBOX do { \ + if (lastmsg > -1) { \ + /* Get the deleted messages fixed */ \ + curmsg = -1; \ + for (x=0;x<=lastmsg;x++) { \ + if (!deleted[x] && (strcasecmp(curbox, "INBOX") || !heard[x])) { \ + /* Save this message. It's not in INBOX or hasn't been heard */ \ + curmsg++; \ + make_file(fn, sizeof(fn), curdir, x); \ + make_file(fn2, sizeof(fn2), curdir, curmsg); \ + if (strcmp(fn, fn2)) { \ + snprintf(txt, sizeof(txt), "%s.txt", fn); \ + snprintf(ntxt, sizeof(ntxt), "%s.txt", fn2); \ + ast_filerename(fn, fn2, NULL); \ + rename(txt, ntxt); \ + } \ + } else if (!strcasecmp(curbox, "INBOX") && heard[x] && !deleted[x]) { \ + /* Move to old folder before deleting */ \ + save_to_folder(curdir, x, username, 1); \ + } \ + } \ + for (x = curmsg + 1; x<=lastmsg; x++) { \ + make_file(fn, sizeof(fn), curdir, x); \ + snprintf(txt, sizeof(txt), "%s.txt", fn); \ + ast_filedelete(fn, NULL); \ + unlink(txt); \ + } \ + } \ + memset(deleted, 0, sizeof(deleted)); \ + memset(heard, 0, sizeof(heard)); \ +} while(0) + +#define OPEN_MAILBOX(a) do { \ + strcpy(curbox, mbox(a)); \ + make_dir(curdir, sizeof(curdir), username, curbox); \ + lastmsg = count_messages(curdir) - 1; \ + snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \ +} while (0) + static int vm_execmain(struct ast_channel *chan, void *data) { - /* XXX This is, admittedly, some pretty horrendus code XXX */ + /* XXX This is, admittedly, some pretty horrendus code. For some + reason it just seemed a lot easier to do with GOTO's. I feel + like I'm back in my GWBASIC days. XXX */ int res=-1; int valid = 0; - int curmsg = 0; - int maxmsg = 0; - int x; - char *fn, *nfn; char d; struct localuser *u; char username[80]; char password[80], *copy; - int deleted[MAXMSG]; + char curbox[80]; + char curdir[256]; + char vmbox[256]; + char fn[256]; + char fn2[256]; + int x; char ntxt[256]; char txt[256]; + int deleted[MAXMSG] = { 0, }; + int heard[MAXMSG] = { 0, }; + int newmessages; + int oldmessages; + int repeats = 0; + int curmsg = 0; + int lastmsg = 0; + int starting = 1; + int box; struct ast_config *cfg; - int state; - char *dir=NULL; LOCAL_USER_ADD(u); cfg = ast_load(VOICEMAIL_CONFIG); @@ -386,9 +635,12 @@ static int vm_execmain(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Couldn't stream login file\n"); goto out; } + + /* Authenticate them and get their mailbox/password */ + do { /* Prompt for, and read in the username */ - if (ast_readstring(chan, username, sizeof(username), 2000, 10000, "#")) { + if (ast_readstring(chan, username, sizeof(username), 2000, 10000, "#") < 0) { ast_log(LOG_WARNING, "Couldn't read username\n"); goto out; } @@ -402,7 +654,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Unable to stream password file\n"); goto out; } - if (ast_readstring(chan, password, sizeof(password), 2000, 10000, "#")) { + if (ast_readstring(chan, password, sizeof(password), 2000, 10000, "#") < 0) { ast_log(LOG_WARNING, "Unable to read password\n"); goto out; } @@ -424,208 +676,175 @@ static int vm_execmain(struct ast_channel *chan, void *data) break; } } while (!valid); - if (valid) { - dir = get_dir(username, "INBOX"); - if (!dir) - goto out; - deleted[0] = 0; - /* Find out how many messages are there, mark all as - not deleted. */ - do { - fn = get_fn(dir, maxmsg); - if ((res = ast_fileexists(fn, NULL, chan->language))>0) { - maxmsg++; - deleted[maxmsg] = 0; + if (valid) { + OPEN_MAILBOX(1); + oldmessages = lastmsg + 1; + /* Start in INBOX */ + OPEN_MAILBOX(0); + newmessages = lastmsg + 1; + + WAITCMD(play_and_wait(chan, "vm-youhave")); + if (newmessages) { + WAITCMD(say_and_wait(chan, newmessages)); + WAITCMD(play_and_wait(chan, "vm-INBOX")); + if (newmessages == 1) + WAITCMD(play_and_wait(chan, "vm-message")); + else + WAITCMD(play_and_wait(chan, "vm-messages")); + + if (oldmessages) + WAITCMD(play_and_wait(chan, "vm-and")); + } + if (oldmessages) { + WAITCMD(say_and_wait(chan, oldmessages)); + WAITCMD(play_and_wait(chan, "vm-Old")); + if (oldmessages == 1) + WAITCMD(play_and_wait(chan, "vm-message")); + else + WAITCMD(play_and_wait(chan, "vm-messages")); + } + if (!oldmessages && !newmessages) { + WAITCMD(play_and_wait(chan, "vm-no")); + WAITCMD(play_and_wait(chan, "vm-messages")); + } + if (!newmessages && oldmessages) { + /* If we only have old messages start here */ + OPEN_MAILBOX(1); + } + repeats = 0; + starting = 1; +instructions: + if (starting) { + if (lastmsg > -1) { + WAITCMD(play_and_wait(chan, "vm-onefor")); + WAITCMD(play_and_wait(chan, vmbox)); + WAITCMD(play_and_wait(chan, "vm-messages")); } - free(fn); - } while(res > 0); - if (ast_streamfile(chan, "vm-youhave", chan->language)) - goto out; - if ((d=ast_waitstream(chan, AST_DIGIT_ANY)) < 0) + WAITCMD(play_and_wait(chan, "vm-opts")); + } else { + if (curmsg) + WAITCMD(play_and_wait(chan, "vm-prev")); + WAITCMD(play_and_wait(chan, "vm-repeat")); + if (curmsg != lastmsg) + WAITCMD(play_and_wait(chan, "vm-next")); + if (!deleted[curmsg]) + WAITCMD(play_and_wait(chan, "vm-delete")); + else + WAITCMD(play_and_wait(chan, "vm-undelete")); + WAITCMD(play_and_wait(chan, "vm-toforward")); + WAITCMD(play_and_wait(chan, "vm-savemessage")); + } + WAITCMD(play_and_wait(chan, "vm-helpexit")); + d = ast_waitfordigit(chan, 6000); + if (d < 0) goto out; - ast_stopstream(chan); if (!d) { - /* If they haven't interrupted us, play the message count */ - if (maxmsg > 0) { - if ((d = ast_say_number(chan, maxmsg, chan->language)) < 0) + repeats++; + if (repeats > 2) { + play_and_wait(chan, "vm-goodbye"); + goto out; + } + goto instructions; + } +cmd: + switch(d) { + case '2': + box = play_and_wait(chan, "vm-changeto"); + if (box < 0) + goto out; + while((box < '0') || (box > '9')) { + box = get_folder(chan, 0); + if (box < 0) goto out; + if (box == '#') + goto instructions; + } + box = box - '0'; + CLOSE_MAILBOX; + OPEN_MAILBOX(box); + WAITCMD(play_and_wait(chan, vmbox)); + WAITCMD(play_and_wait(chan, "vm-messages")); + starting = 1; + goto instructions; + case '4': + if (curmsg) { + curmsg--; + PLAYMSG(curmsg); } else { - if (ast_streamfile(chan, "vm-no", chan->language)) - goto out; - if ((d=ast_waitstream(chan, AST_DIGIT_ANY)) < 0) - goto out; - ast_stopstream(chan); + WAITCMD(play_and_wait(chan, "vm-nomore")); + goto instructions; } - if (!d) { - /* And if they still haven't, give them the last word */ - if (ast_streamfile(chan, ((maxmsg == 1) ? "vm-message" : "vm-messages"), chan->language)) - goto out; - if (ast_waitstream(chan, AST_DIGIT_ANY) < 0) - goto out; - ast_stopstream(chan); + case '1': + curmsg = 0; + /* Fall through */ + case '5': + if (lastmsg > -1) { + PLAYMSG(curmsg); + } else { + WAITCMD(play_and_wait(chan, "vm-youhave")); + WAITCMD(play_and_wait(chan, "vm-no")); + snprintf(fn, sizeof(fn), "vm-%s", curbox); + WAITCMD(play_and_wait(chan, fn)); + WAITCMD(play_and_wait(chan, "vm-messages")); + goto instructions; } - } - res = -1; - -#define STATE_STARTING 1 -#define STATE_MESSAGE 2 -#define STATE_MESSAGE_PLAYING 3 - state = STATE_STARTING; - ast_log(LOG_EVENT, "User '%s' logged in on channel '%s' with %d message(s).\n", username, chan->name, maxmsg); - if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "User '%s' logged in on channel %s with %d messages\n", username, chan->name, maxmsg); - if (!ast_streamfile(chan, "vm-instructions", chan->language)) { - for(;;) { - if (chan->stream) { - d = ast_waitstream(chan, AST_DIGIT_ANY); - ast_stopstream(chan); - if (!d && (state == STATE_MESSAGE_PLAYING)) { - state = STATE_MESSAGE; - /* If it runs out playing a message, then give directions */ - if (!(d = ast_streamfile(chan, "vm-msginstruct", chan->language))) - d = ast_waitstream(chan, AST_DIGIT_ANY); - ast_stopstream(chan); - } - if (!d) - d = ast_waitfordigit(chan, COMMAND_TIMEOUT); - } else - d = ast_waitfordigit(chan, COMMAND_TIMEOUT); - if (d < 0) + case '6': + if (curmsg < lastmsg) { + curmsg++; + PLAYMSG(curmsg); + } else { + WAITCMD(play_and_wait(chan, "vm-nomore")); + goto instructions; + } + case '7': + deleted[curmsg] = !deleted[curmsg]; + if (deleted[curmsg]) + WAITCMD(play_and_wait(chan, "vm-deleted")); + else + WAITCMD(play_and_wait(chan, "vm-undeleted")); + goto instructions; + case '9': + box = play_and_wait(chan, "vm-savefolder"); + if (box < 0) + goto out; + while((box < '1') || (box > '9')) { + box = get_folder(chan, 1); + if (box < 0) goto out; -restart: - if (!d || (d == '*')) { - /* If they don't say anything, play back a message. We'll decide which one is - best based up on where they are. Ditto if they press the '*' key. */ - switch(state) { - case STATE_STARTING: - if (ast_streamfile(chan, "vm-instructions", chan->language)) - goto out; - break; - case STATE_MESSAGE: - case STATE_MESSAGE_PLAYING: - if (ast_streamfile(chan, "vm-msginstruct", chan->language)) - goto out; - break; - default: - ast_log(LOG_WARNING, "What do I do when they timeout/* in state %d?\n", state); - } - } else { - /* XXX Should we be command-compatible with Meridian mail? Their system seems - very confusing, but also widely used XXX */ - /* They've entered (or started to enter) a command */ - switch(d) { - case '0': - if (curmsg < maxmsg) { - deleted[curmsg] = !deleted[curmsg]; - if (deleted[curmsg]) { - if (ast_streamfile(chan, "vm-deleted", chan->language)) - goto out; - } else { - if (ast_streamfile(chan, "vm-undeleted", chan->language)) - goto out; - } - } else { - if (ast_streamfile(chan, "vm-nomore", chan->language)) - goto out; - } - break; - case '1': - curmsg = 0; - if (maxmsg > 0) { - /* Yuck */ - if ((d = announce_message(chan, dir, curmsg)) > 0) - goto restart; - else if (d < 0) - goto out; - } else { - if (ast_streamfile(chan, "vm-nomore", chan->language)) - goto out; - } - state = STATE_MESSAGE_PLAYING; - break; - case '4': - if (curmsg > 0) - curmsg--; - /* Yuck */ - if ((d = announce_message(chan, dir, curmsg)) > 0) - goto restart; - else if (d < 0) - goto out; - state = STATE_MESSAGE_PLAYING; - break; - case '5': - if ((d = announce_message(chan, dir, curmsg)) > 0) - goto restart; - else if (d < 0) - goto out; - state = STATE_MESSAGE_PLAYING; - break; - case '6': - if (curmsg < maxmsg - 1) { - curmsg++; - if ((d = announce_message(chan, dir, curmsg)) > 0) - goto restart; - else if (d < 0) - goto out; - } else { - if (ast_streamfile(chan, "vm-nomore", chan->language)) - goto out; - } - state = STATE_MESSAGE_PLAYING; - break; - /* XXX Message compose? It's easy! Just read their # and, assuming it's in the config, - call the routine as if it were called from the PBX proper XXX */ - case '#': - if (ast_streamfile(chan, "vm-goodbye", chan->language)) - goto out; - if (ast_waitstream(chan, "")) - goto out; - res = 0; - goto out; - break; - default: - /* Double yuck */ - d = '*'; - goto restart; - } - } + if (box == '#') + goto instructions; + } + box = box - '0'; + ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box); + if (save_to_folder(curdir, curmsg, username, box)) + goto out; + deleted[curmsg]=1; + WAITCMD(play_and_wait(chan, "vm-message")); + WAITCMD(say_and_wait(chan, curmsg + 1) ); + WAITCMD(play_and_wait(chan, "vm-savedto")); + snprintf(fn, sizeof(fn), "vm-%s", mbox(box)); + WAITCMD(play_and_wait(chan, fn)); + WAITCMD(play_and_wait(chan, "vm-messages")); + goto instructions; + case '*': + if (!starting) { + WAITCMD(play_and_wait(chan, "vm-onefor")); + WAITCMD(play_and_wait(chan, vmbox)); + WAITCMD(play_and_wait(chan, "vm-messages")); + WAITCMD(play_and_wait(chan, "vm-opts")); } + goto instructions; + case '#': + play_and_wait(chan, "vm-goodbye"); + goto out; + default: + goto instructions; } } - out: + CLOSE_MAILBOX; ast_stopstream(chan); - if (maxmsg) { - /* Get the deleted messages fixed */ - curmsg = -1; - for (x=0;x<maxmsg;x++) { - if (!deleted[x]) { - curmsg++; - fn = get_fn(dir, x); - nfn = get_fn(dir, curmsg); - if (strcmp(fn, nfn)) { - snprintf(txt, sizeof(txt), "%s.txt", fn); - snprintf(ntxt, sizeof(ntxt), "%s.txt", nfn); - ast_filerename(fn, nfn, NULL); - rename(txt, ntxt); - } - free(fn); - free(nfn); - } - } - for (x = curmsg + 1; x<maxmsg; x++) { - fn = get_fn(dir, x); - if (fn) { - snprintf(txt, sizeof(txt), "%s.txt", fn); - ast_filedelete(fn, NULL); - unlink(txt); - free(fn); - } - } - } - if (dir) - free(dir); if (cfg) ast_destroy(cfg); LOCAL_USER_REMOVE(u); @@ -647,6 +866,8 @@ static int vm_exec(struct ast_channel *chan, void *data) silent++; ext++; } + if (chan->state != AST_STATE_UP) + ast_answer(chan); res = leave_voicemail(chan, ext, silent); LOCAL_USER_REMOVE(u); return res; diff --git a/include/asterisk/app.h b/include/asterisk/app.h new file mode 100755 index 0000000000..ecb1ab1018 --- /dev/null +++ b/include/asterisk/app.h @@ -0,0 +1,27 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * Application convenience functions, designed to give consistent + * look and feel to asterisk apps. + * + * Copyright (C) 1999, Mark Spencer + * + * Mark Spencer <markster@linux-support.net> + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#ifndef _ASTERISK_APP_H +#define _ASTERISK_APP_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif +extern int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif