Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 186053) +++ apps/app_voicemail.c (working copy) @@ -399,7 +399,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain); static int vm_play_folder_name(struct ast_channel *chan, char *mbox); static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname); -static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap); +static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *folder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap); #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE)) static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit); #endif @@ -1307,7 +1307,7 @@ *(vmu->email) = '\0'; return -1; } else { - make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1); + make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, vms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1); /* read mail file to memory */ len = ftell(p); rewind(p); @@ -2988,9 +2988,15 @@ return 1; } -static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category) +static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category) { char callerid[256]; + char fromdir[256], fromfile[256]; + struct ast_config *msg_cfg; + const char *origcallerid, *origtime; + char origcidname[80], origcidnum[80], origdate[80]; + int inttime; + /* Prepare variables for substition in email body and subject */ pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname); pbx_builtin_setvar_helper(ast, "VM_DUR", dur); @@ -3004,6 +3010,35 @@ pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller")); pbx_builtin_setvar_helper(ast, "VM_DATE", date); pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category"); + + /* Retrieve info from VM attribute file */ + make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder); + make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1); + if (strlen(fromfile) < sizeof(fromfile) - 5) { + strcat(fromfile, ".txt"); + } + if (!(msg_cfg = ast_config_load(fromfile))) { + if (option_debug > 0) { + ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile); + } + return; + } + + if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) { + pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid); + ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum)); + pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname); + pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum); + } + + if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%d", &inttime) == 1) { + time_t ttime = inttime; + struct tm tm; + ast_localtime(&ttime, &tm, NULL); + strftime(origdate, sizeof(origdate), emaildateformat, &tm); + pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate); + } + ast_config_destroy(msg_cfg); } static char *quote(const char *from, char *to, size_t len) @@ -3109,7 +3144,7 @@ return end; } -static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap) +static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap) { char date[256]; char host[MAXHOSTNAMELEN] = ""; @@ -3166,7 +3201,7 @@ if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) { char *ptr; memset(passdata2, 0, len_passdata2); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category); pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2); len_passdata = strlen(passdata2) * 3 + 300; passdata = alloca(len_passdata); @@ -3214,7 +3249,7 @@ } memset(passdata, 0, len_passdata); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, len_passdata, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category); pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata); if (check_mime(passdata)) { int first_line = 1; @@ -3288,7 +3323,7 @@ int vmlen = strlen(emailbody)*3 + 200; if ((passdata = alloca(vmlen))) { memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category); pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen); fprintf(p, "%s" ENDL, passdata); } else @@ -3297,11 +3332,49 @@ } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); } else { - fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL + if (strcmp(vmu->mailbox, mailbox)) { + /* Forwarded type */ + struct ast_config *msg_cfg; + const char *v; + int inttime; + char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = ""; + /* Retrieve info from VM attribute file */ + make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder); + make_file(fromfile, sizeof(fromfile), fromdir, msgnum); + if (strlen(fromfile) < sizeof(fromfile) - 5) { + strcat(fromfile, ".txt"); + } + if ((msg_cfg = ast_config_load(fromfile))) { + if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) { + ast_copy_string(origcallerid, v, sizeof(origcallerid)); + } - "in mailbox %s from %s, on %s so you might" ENDL - "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, - dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date); + /* You might be tempted to do origdate, except that a) it's in the wrong + * format, and b) it's missing for IMAP recordings. */ + if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%d", &inttime) == 1) { + time_t ttime = inttime; + struct tm tm; + ast_localtime(&ttime, &tm, NULL); + strftime(origdate, sizeof(origdate), emaildateformat, &tm); + } + fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded" + " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL + "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a" + " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur, + msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), + date, origcallerid, origdate); + ast_config_destroy(msg_cfg); + } else { + goto plain_message; + } + } else { +plain_message: + fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a " + "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL + "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" + ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox, + (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date); + } } if (attach_user_voicemail) { /* Eww. We want formats to tell us their own MIME type */ @@ -3347,7 +3420,7 @@ } #undef ENDL } -static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category) +static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category) { FILE *p=NULL; char tmp[80] = "/tmp/astmail-XXXXXX"; @@ -3367,7 +3440,7 @@ ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd); return -1; } else { - make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0); + make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0); fclose(p); snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); ast_safe_system(tmp2); @@ -3377,7 +3450,7 @@ return 0; } -static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category) +static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category) { char date[256]; char host[MAXHOSTNAMELEN] = ""; @@ -3409,7 +3482,7 @@ int vmlen = strlen(fromstring)*3 + 200; if ((passdata = alloca(vmlen))) { memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category); pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen); fprintf(p, "From: %s <%s>\n", passdata, who); } else @@ -3426,7 +3499,7 @@ int vmlen = strlen(pagersubject) * 3 + 200; if ((passdata = alloca(vmlen))) { memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category); pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen); fprintf(p, "Subject: %s\n\n", passdata); } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); @@ -3442,7 +3515,7 @@ int vmlen = strlen(pagerbody)*3 + 200; if ((passdata = alloca(vmlen))) { memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category); pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen); fprintf(p, "%s\n", passdata); } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); @@ -5030,7 +5103,7 @@ RETRIEVE(todir, msgnum, vmu); /*XXX possible imap issue, should category be NULL XXX*/ - sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category); + sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category); if (attach_user_voicemail) DISPOSE(todir, msgnum); @@ -5040,7 +5113,7 @@ char *myserveremail = serveremail; if (!ast_strlen_zero(vmu->serveremail)) myserveremail = vmu->serveremail; - sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category); + sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category); } if (ast_test_flag(vmu, VM_DELETE)) { @@ -5172,6 +5245,7 @@ AST_LIST_INSERT_HEAD(&extensions, receiver, list); found++; } else { + ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s); valid_extensions = 0; break; } @@ -5243,7 +5317,7 @@ myserveremail = vmtmp->serveremail; attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH); /* NULL category for IMAP storage */ - sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL); + sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL); #else copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir); #endif Index: configs/voicemail.conf.sample =================================================================== --- configs/voicemail.conf.sample (revision 186053) +++ configs/voicemail.conf.sample (working copy) @@ -95,6 +95,10 @@ ; Change the from, body and/or subject, variables: ; VM_NAME, VM_DUR, VM_MSGNUM, VM_MAILBOX, VM_CALLERID, VM_CIDNUM, ; VM_CIDNAME, VM_DATE +; Additionally, on forwarded messages, you have the variables: +; ORIG_VM_CALLERID, ORIG_VM_CIDNUM, ORIG_VM_CIDNAME, ORIG_VM_DATE +; You can select between two variables by using dialplan functions, e.g. +; ${IF(${ISNULL(${ORIG_VM_DATE})}?${VM_DATE}:${ORIG_VM_DATE})} ; ; Note: The emailbody config row can only be up to 512 characters due to a ; limitation in the Asterisk configuration subsystem. @@ -102,7 +106,8 @@ ; The following definition is very close to the default, but the default shows ; just the CIDNAME, if it is not null, otherwise just the CIDNUM, or "an unknown ; caller", if they are both null. -;emailbody=Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just left a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE}, so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n +;emailbody=Dear ${VM_NAME}:\n\n\tWanted to let you know you were left a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE}, so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n +;emailbody=Dear ${VM_NAME}:\n\n\tWanted to let you know you were ${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?left:forwarded)} a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE},\n${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?:(originally sent by ${ORIG_VM_CALLERID} on ${ORIG_VM_DATE})\n)}\nso you might want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n ; ; You can also change the Pager From: string, the pager body and/or subject. ; The above defined variables also can be used here