diff options
Diffstat (limited to '')
-rw-r--r-- | src/LYMail.c | 1774 |
1 files changed, 1774 insertions, 0 deletions
diff --git a/src/LYMail.c b/src/LYMail.c new file mode 100644 index 0000000..1443f24 --- /dev/null +++ b/src/LYMail.c @@ -0,0 +1,1774 @@ +/* + * $LynxId: LYMail.c,v 1.100 2020/01/21 21:33:27 tom Exp $ + */ +#include <HTUtils.h> +#include <HTParse.h> +#include <LYGlobalDefs.h> +#include <HTAlert.h> +#include <LYCurses.h> +#include <LYSignal.h> +#include <LYUtils.h> +#include <LYClean.h> +#include <LYStrings.h> +#include <GridText.h> +#include <LYMail.h> +#include <LYEdit.h> +#include <LYCharSets.h> /* to get current charset for mail header */ + +#include <LYLeaks.h> + +#define MAX_SUBJECT 70 + +BOOLEAN term_letter; /* Global variable for async i/o. */ + +static void terminate_letter(int sig GCC_UNUSED) +{ + term_letter = TRUE; + /* Reassert the AST */ + signal(SIGINT, terminate_letter); +#if USE_VMS_MAILER || defined(PDCURSES) + /* + * Refresh the screen to get rid of the "interrupt" message. + */ + if (!dump_output_immediately) { + lynx_force_repaint(); + LYrefresh(); + } +#endif /* VMS */ +} + +/* HTUnEscape with control-code nuking */ +static void SafeHTUnEscape(char *string) +{ + int i; + int flg = FALSE; + + HTUnEscape(string); + for (i = 0; string[i] != '\0'; i++) { + /* FIXME: this is no longer explicitly 7-bit ASCII, + but are there portability problems? */ + if ((!LYIsASCII(string[i])) || !isprint(UCH(string[i]))) { + string[i] = '?'; + flg = TRUE; + } + } + if (flg) + HTAlert(MAILTO_SQUASH_CTL); +} + +static void remove_tildes(char *string) +{ + /* + * Change the first character to a space if it is a '~'. + */ + if (*string == '~') + *string = ' '; +} + +static void comma_append(char **dst, + char *src) +{ + if (*src) { + while (*src == ',' || isspace(UCH(*src))) + src++; + if (*src) { + if (isEmpty(*dst)) { + StrAllocCopy(*dst, src); + } else { + StrAllocCat(*dst, ","); + StrAllocCat(*dst, src); + } + } + } +} + +static void extract_field(char **dst, + char *src, + const char *keyword) +{ + int len = (int) strlen(keyword); + char *cp, *cp1; + + cp = (src + 1); + while (*cp != '\0') { + if ((*(cp - 1) == '?' || *(cp - 1) == '&') && + !strncasecomp(cp, keyword, len)) { + cp += len; + if ((cp1 = StrChr(cp, '&')) != NULL) { + *cp1 = '\0'; + } + comma_append(dst, cp); + if (cp1) { + *cp1 = '&'; + cp = cp1; + cp1 = NULL; + } else { + break; + } + } + cp++; + } + CTRACE((tfp, "extract_field(%s) = '%s'\n", keyword, *dst)); +} + +/* + * Seek and handle a subject=foo. - FM + */ +static void extract_subject(char *dst, + char *src) +{ + const char *keyword = "subject="; + int len = (int) strlen(keyword); + char *cp, *cp1; + + cp = (src + 1); + while (*cp != '\0') { + if ((*(cp - 1) == '?' || *(cp - 1) == '&') && + !strncasecomp(cp, keyword, len)) + break; + cp++; + } + if (*cp) { + cp += len; + if ((cp1 = StrChr(cp, '&')) != NULL) { + *cp1 = '\0'; + } + if (*cp) { + LYStrNCpy(dst, cp, MAX_SUBJECT); + SafeHTUnEscape(dst); + } + if (cp1) { + *cp1 = '&'; + cp1 = NULL; + } + } + CTRACE((tfp, "extract_subject(%s) = '%s'\n", keyword, NONNULL(dst))); +} + +/* + * Seek and handle body=foo fields. - FM + */ +static void extract_body(char **dst, + char *src) +{ + const char *keyword = "body="; + int len = (int) strlen(keyword); + int i; + char *cp, *cp0, *cp1, *temp = 0; + + cp = (src + 1); + while (*cp != '\0') { + if ((*(cp - 1) == '?' || *(cp - 1) == '&') && + !strncasecomp(cp, keyword, len)) { + cp += len; + if ((cp1 = StrChr(cp, '&')) != NULL) { + *cp1 = '\0'; + } + if (*cp) { + /* + * Break up the value into lines with a maximum length of 78. + * - FM + */ + StrAllocCopy(temp, cp); + HTUnEscape(temp); + cp0 = temp; + while ((cp = StrChr(cp0, '\n')) != NULL) { + *cp = '\0'; + if (cp > cp0) { + if (*(cp - 1) == '\r') { + *(cp - 1) = '\0'; + } + } + i = 0; + len = (int) strlen(cp0); + while (len > 78) { + HTSprintf(dst, "%.78s\n", &cp0[i]); + i += 78; + len = (int) strlen(&cp0[i]); + } + HTSprintf(dst, "%s\n", &cp0[i]); + cp0 = (cp + 1); + } + i = 0; + len = (int) strlen(cp0); + while (len > 78) { + HTSprintf(dst, "%.78s\n", &cp0[i]); + i += 78; + len = (int) strlen(&cp0[i]); + } + if (len) { + HTSprintf(dst, "%s\n", &cp0[i]); + } + FREE(temp); + } + if (cp1) { + *cp1 = '&'; + cp = cp1; + cp1 = NULL; + } else { + break; + } + } + cp++; + } + CTRACE((tfp, "extract_body(%s) = '%s'\n", keyword, NONNULL(*dst))); +} + +/* + * Convert any Explorer semi-colon Internet address separators to commas - FM + */ +static BOOLEAN trim_comma(char *address) +{ + if (address[(strlen(address) - 1)] == ',') + address[(strlen(address) - 1)] = '\0'; + return (BOOL) (*address == '\0'); +} + +/* + * Convert any Explorer semi-colon Internet address separators to commas - FM + */ +static BOOLEAN convert_explorer(char *address) +{ + char *cp = address; + char *cp0; + char *cp1; + + while ((cp1 = StrChr(cp, '@')) != NULL) { + cp1++; + if ((cp0 = StrChr(cp1, ';')) != NULL) { + *cp0 = ','; + cp1 = cp0 + 1; + } + cp = cp1; + } + return trim_comma(address); +} + +/* + * reply_by_mail() prompts line-by-line for header information, allowing + * scrolling of the screen. + */ +static int header_prompt(const char *label, + char **result, + unsigned limit) +{ + char buffer[LINESIZE]; + int ok; + + if (*result != 0) { + LYaddstr(CTRL_U_TO_ERASE); + LYStrNCpy(buffer, *result, sizeof(buffer) - 1); + } else + *buffer = 0; + + if (limit > sizeof(buffer)) + limit = sizeof(buffer); + + LYaddstr(gettext(label)); + LYaddstr(": "); + ok = (LYGetStr(buffer, FALSE, limit, NORECALL) >= 0 + && !term_letter); + LYaddstr("\n"); + + if (ok) { + remove_tildes(buffer); + StrAllocCopy(*result, buffer); + } + term_letter = FALSE; + return ok; +} + +static void show_addresses(char *addresses) +{ + char *cp = addresses; + char *cp1; + + while ((cp1 = StrChr(cp, ',')) != NULL) { + *cp1 = '\0'; + while (*cp == ' ') + cp++; + if (*cp) { + LYaddstr(cp); + LYaddstr(",\n "); + } + *cp1 = ','; + cp = (cp1 + 1); + } + if (*cp) { + LYaddstr(cp); + } +} + +#if USE_BLAT_MAILER + +/* + * blat's options-file parser (see makeargv.cpp) treats backslash and double + * quote characters specially. lynx doesn't. Do a conversion as we write the + * option. + * + * Other quirks (reading blat 3.06): + * + Whitespace not in quotes terminates a line. + * + Blat allows a comment-character to terminate a line. By default, that + * is a semicolon. + * + * Given that, the simplest thing to do is to always quote the string, using + * escaping to handle special cases. + */ +static void blat_option(FILE *fp, const char *option, const char *value) +{ + if (non_empty(value)) { + char *result = malloc(strlen(option) + 4 + 4 * strlen(value)); + char *working = result; + + CTRACE((tfp, "blat_option(opt=\"%s\", value=\"%s\")\n", option, value)); + sprintf(working, "%s \"", option); + working += strlen(working); + + while (*value != '\0') { + unsigned ch = UCH(*value); + + switch (ch) { + case '\\': + *working++ = '\\'; + *working++ = '\\'; + break; + case '"': + *working++ = '\\'; + *working++ = '"'; + break; + default: + if (ch < ' ' || ch > '~') { + sprintf(working, "\\%03o", ch); + } else { + *working++ = ch; + } + break; + } + ++value; + } + *working++ = '"'; + *working++ = '\n'; + *working = 0; + + CTRACE((tfp, "->%s", result)); + fputs(result, fp); + FREE(result); + } +} + +/* +syntax for blat 2.6.2: +Blat <filename> -t <recipient> [optional switches (see below)] + +-bodyF <filename> : file with the message body +-t <recipient> : recipient list (comma separated) +-s <subj> : subject line +-f <sender> : overrides the default sender address (must be known to server) +-i <addr> : a 'From:' address, not necessarily known to the SMTP server. +-c <recipient> : carbon copy recipient list (comma separated) +-b <recipient> : blind carbon copy recipient list (comma separated) +-help : displays the help message. +-mime : MIME Quoted-Printable Content-Transfer-Encoding. +-q : suppresses *all* output. +-server <addr> : overrides the default SMTP server to be used. + +*/ + +static char *blat_cmd(char *filename, + char *address, + char *subject, + char *ccaddr, + char *mail_addr) +{ + char *b_cmd = NULL; + + if (mail_is_altblat) { + const char *format = "%s %s -t %s -s %s %s%s%s"; + + HTAddParam(&b_cmd, format, 1, ALTBLAT_MAIL); + HTAddParam(&b_cmd, format, 2, filename); + HTAddParam(&b_cmd, format, 3, address); + HTAddParam(&b_cmd, format, 4, subject); + HTAddToCmd(&b_cmd, format, 5, ALTBLAT_MAIL_FLAGS); + if (non_empty(ccaddr)) { + HTAddToCmd(&b_cmd, format, 6, " -c "); + HTAddParam(&b_cmd, format, 7, NonNull(ccaddr)); + } + HTEndParam(&b_cmd, format, 8); + + } else { + + const char *format = "%s -of %s"; + char bl_cmd_file[LY_MAXPATH]; + FILE *fp; + +#ifdef __CYGWIN__ + char dosname[LY_MAXPATH]; + +#else + char *dosname; +#endif + + bl_cmd_file[0] = '\0'; + if ((fp = LYOpenTemp(bl_cmd_file, ".blt", "w")) == NULL) { + HTAlert(FORM_MAILTO_FAILED); + return NULL; + } + + HTAddParam(&b_cmd, format, 1, BLAT_MAIL); + + ConvertToWin32Path(filename, dosname); + blat_option(fp, "-bodyF", dosname); + blat_option(fp, "-t", address); + blat_option(fp, "-s", subject); + blat_option(fp, "-f", mail_addr); + blat_option(fp, "-c", ccaddr); + LYCloseOutput(fp); + + ConvertToWin32Path(bl_cmd_file, dosname); + + HTAddParam(&b_cmd, format, 2, dosname); + HTEndParam(&b_cmd, format, 3); + + } + + return b_cmd; +} + +#endif /* USE_BLAT_MAILER */ + +#if USE_VMS_MAILER +BOOLEAN LYMailPMDF(void) +{ + return (system_mail != 0) + ? !strncasecomp(system_mail, "PMDF SEND", 9) + : FALSE; +} + +/* + * Add all of the people in the address field to the command + */ +static void vms_append_addrs(char **cmd, char *address, char *option) +{ + BOOLEAN first = TRUE; + char *cp; + char *address_ptr1; + char *address_ptr2; + + address_ptr1 = address; + do { + if ((cp = StrChr(address_ptr1, ',')) != NULL) { + address_ptr2 = (cp + 1); + *cp = '\0'; + } else { + address_ptr2 = NULL; + } + + /* + * 4 letters is arbitrarily the smallest possible mail address, at + * least for lynx. That way extra spaces won't confuse the mailer and + * give a blank address. + */ + if (strlen(address_ptr1) > 3) { + if (!first) { + StrAllocCat(*cmd, ","); + } + HTSprintf(cmd, mail_adrs, address_ptr1); + if (*option && LYMailPMDF()) + StrAllocCat(*cmd, option); + first = FALSE; + } + address_ptr1 = address_ptr2; + } while (address_ptr1 != NULL); +} + +static void remove_quotes(char *string) +{ + while (*string != 0) { + if (StrChr("\"&|", *string) != 0) + *string = ' '; + string++; + } +} +#else +#if CAN_PIPE_TO_MAILER + +/* + * Open a pipe to the mailer + */ +FILE *LYPipeToMailer(void) +{ + char *buffer = NULL; + FILE *fp = NULL; + + if (LYSystemMail()) { + HTSprintf0(&buffer, "%s %s", system_mail, system_mail_flags); + fp = popen(buffer, "w"); + CTRACE((tfp, "popen(%s) %s\n", buffer, fp != 0 ? "OK" : "FAIL")); + FREE(buffer); + } + return fp; +} +#else /* DOS, Win32, etc. */ + +int LYSendMailFile(char *the_address, + char *the_filename, + char *the_subject GCC_UNUSED, + char *the_ccaddr GCC_UNUSED, + char *message) +{ + char *cmd = NULL; + int code; + + if (!LYSystemMail()) + return 0; + +#if USE_BLAT_MAILER + if (mail_is_blat) { + cmd = blat_cmd(the_filename, + the_address, + the_subject, + the_ccaddr, + personal_mail_address); + } else +#endif +#ifdef __DJGPP__ + if (LYGetEnv("SHELL")) { + extern char *shell; + const char *c_option; + const char *format = "%s %s %s -t %s -F %s"; + + if (dj_is_bash) { + c_option = "-c"; + } else { + c_option = "/c"; + } + HTAddParam(&cmd, format, 1, shell); + HTAddParam(&cmd, format, 2, c_option); + HTAddParam(&cmd, format, 3, system_mail); + HTAddParam(&cmd, format, 4, the_address); + HTAddParam(&cmd, format, 5, the_filename); + HTEndParam(&cmd, format, 6); + } else +#endif /* __DJGPP__ */ + { + const char *format = "%s -t %s -F %s"; + + HTAddParam(&cmd, format, 1, system_mail); + HTAddParam(&cmd, format, 2, the_address); + HTAddParam(&cmd, format, 3, the_filename); + HTEndParam(&cmd, format, 4); + } + + stop_curses(); + SetOutputMode(O_TEXT); + printf("%s\n\n$ %s\n\n%s", + *message ? message : gettext("Sending"), + cmd, PLEASE_WAIT); + code = LYSystem(cmd); + LYSleepMsg(); + start_curses(); + SetOutputMode(O_BINARY); + + FREE(cmd); + + return code; +} +#endif /* CAN_PIPE_TO_FILE */ +#endif /* USE_VMS_MAILER */ + +/* + * mailform() sends form content to the mailto address(es). - FM + */ +void mailform(const char *mailto_address, + const char *mailto_subject, + const char *mailto_content, + const char *mailto_type) +{ + FILE *fd; + char *address = NULL; + char *ccaddr = NULL; + char *keywords = NULL; + char *cp = NULL; + char self[MAX_SUBJECT + 10]; + char subject[MAX_SUBJECT + 10]; + char *searchpart = NULL; + char buf[512]; + int len, i; + +#if USE_VMS_MAILER + static char *cmd; + char *command = NULL; + BOOLEAN isPMDF = LYMailPMDF(); + char hdrfile[LY_MAXPATH]; +#endif +#if !CAN_PIPE_TO_MAILER + char my_tmpfile[LY_MAXPATH]; +#endif + + CTRACE((tfp, "mailto_address: \"%s\"\n", NONNULL(mailto_address))); + CTRACE((tfp, "mailto_subject: \"%s\"\n", NONNULL(mailto_subject))); + CTRACE((tfp, "mailto_content: \"%s\"\n", NONNULL(mailto_content))); + CTRACE((tfp, "mailto_type: \"%s\"\n", NONNULL(mailto_type))); + + if (!LYSystemMail()) + return; + + if (!mailto_address || !mailto_content) { + HTAlert(BAD_FORM_MAILTO); + return; + } + subject[0] = '\0'; + self[0] = '\0'; + + if ((cp = StrChr(mailto_address, '\n')) != NULL) + *cp = '\0'; + StrAllocCopy(address, mailto_address); + + /* + * Check for a ?searchpart. - FM + */ + if ((cp = StrChr(address, '?')) != NULL) { + StrAllocCopy(searchpart, cp); + *cp = '\0'; + cp = (searchpart + 1); + if (*cp != '\0') { + /* + * Seek and handle a subject=foo. - FM + */ + extract_subject(subject, searchpart); + + /* + * Seek and handle to=address(es) fields. Appends to address. - + * FM + */ + extract_field(&address, searchpart, "to="); + + /* + * Seek and handle cc=address(es) fields. Excludes Bcc=address(es) + * as unsafe. We may append our own cc (below) as a list for the + * actual mailing. - FM + */ + extract_field(&ccaddr, searchpart, "cc="); + + /* + * Seek and handle keywords=term(s) fields. - FM + */ + extract_field(&keywords, searchpart, "keywords="); + + if (keywords != NULL) { + if (*keywords != '\0') { + SafeHTUnEscape(keywords); + } else { + FREE(keywords); + } + } + + FREE(searchpart); + } + } + + if (convert_explorer(address)) { + HTAlert(BAD_FORM_MAILTO); + goto cleanup; + } + if (ccaddr != NULL) { + if (convert_explorer(ccaddr)) { + FREE(ccaddr); + } + } + + /* + * Unescape the address and ccaddr fields. - FM + */ + SafeHTUnEscape(address); + if (ccaddr != NULL) { + SafeHTUnEscape(ccaddr); + } + + /* + * Allow user to edit the default Subject - FM + */ + if (subject[0] == '\0') { + if (non_empty(mailto_subject)) { + LYStrNCpy(subject, mailto_subject, MAX_SUBJECT); + } else { + sprintf(subject, "mailto:%.63s", address); + } + } + _statusline(SUBJECT_PROMPT); + if (LYGetStr(subject, FALSE, MAX_SUBJECT, NORECALL) < 0) { + /* + * User cancelled via ^G. - FM + */ + HTInfoMsg(FORM_MAILTO_CANCELLED); + goto cleanup; + } + + /* + * Allow user to specify a self copy via a CC: entry, if permitted. - FM + */ + if (!LYNoCc) { + sprintf(self, "%.*s", MAX_SUBJECT, + isEmpty(personal_mail_address) ? "" : personal_mail_address); + _statusline("Cc: "); + if (LYGetStr(self, FALSE, MAX_SUBJECT, NORECALL) < 0) { + /* + * User cancelled via ^G. - FM + */ + HTInfoMsg(FORM_MAILTO_CANCELLED); + goto cleanup; + } + remove_tildes(self); + if (ccaddr == NULL) { + StrAllocCopy(ccaddr, self); + } else { + StrAllocCat(ccaddr, ","); + StrAllocCat(ccaddr, self); + } + } +#if CAN_PIPE_TO_MAILER + if ((fd = LYPipeToMailer()) == 0) { + HTAlert(FORM_MAILTO_FAILED); + goto cleanup; + } + + if (non_empty(mailto_type)) { + fprintf(fd, "Mime-Version: 1.0\n"); + fprintf(fd, "Content-Type: %s\n", mailto_type); + } + fprintf(fd, "To: %s\n", address); + if (non_empty(personal_mail_address)) + fprintf(fd, "From: %s\n", personal_mail_address); + if (non_empty(ccaddr)) + fprintf(fd, "Cc: %s\n", ccaddr); + fprintf(fd, "Subject: %s\n\n", subject); + if (non_empty(keywords)) + fprintf(fd, "Keywords: %s\n", keywords); + _statusline(SENDING_FORM_CONTENT); +#else /* e.g., VMS, DOS */ + if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) { + HTAlert(FORM_MAILTO_FAILED); + goto cleanup; + } +#if USE_VMS_MAILER + if (isPMDF) { + FILE *hfd; + + if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) { + HTAlert(FORM_MAILTO_FAILED); + LYCloseTempFP(fd); + goto cleanup; + } + if (non_empty(mailto_type)) { + fprintf(hfd, "Mime-Version: 1.0\n"); + fprintf(hfd, "Content-Type: %s\n", mailto_type); + if (non_empty(personal_mail_address)) + fprintf(hfd, "From: %s\n", personal_mail_address); + } + /* + * For PMDF, put any keywords and the subject in the header file and + * close it. - FM + */ + if (non_empty(keywords)) { + fprintf(hfd, "Keywords: %s\n", keywords); + } + fprintf(hfd, "Subject: %s\n\n", subject); + LYCloseTempFP(hfd); + } else if (mailto_type && + !strncasecomp(mailto_type, "multipart/form-data", 19)) { + /* + * Ugh! There's no good way to include headers while we're still using + * "generic" VMS MAIL, so we'll put this in the body of the message. - + * FM + */ + fprintf(fd, "X-Content-Type: %s\n\n", mailto_type); + } +#else /* !VMS (DOS) */ +#if USE_BLAT_MAILER + if (mail_is_blat) { + if (strlen(subject) > MAX_SUBJECT) + subject[MAX_SUBJECT] = '\0'; + } else +#endif + { + if (non_empty(mailto_type)) { + fprintf(fd, "Mime-Version: 1.0\n"); + fprintf(fd, "Content-Type: %s\n", mailto_type); + } + fprintf(fd, "To: %s\n", address); + if (non_empty(personal_mail_address)) + fprintf(fd, "From: %s\n", personal_mail_address); + fprintf(fd, "Subject: %.70s\n\n", subject); + } +#endif /* VMS */ +#endif /* CAN_PIPE_TO_MAILER */ + + /* + * Break up the content into lines with a maximum length of 78. If the + * ENCTYPE was text/plain, we have physical newlines and should take them + * into account. Otherwise, the actual newline characters in the content + * are hex escaped. - FM + */ + while ((cp = StrChr(mailto_content, '\n')) != NULL) { + *cp = '\0'; + i = 0; + len = (int) strlen(mailto_content); + while (len > 78) { + LYStrNCpy(buf, &mailto_content[i], 78); + fprintf(fd, "%s\n", buf); + i += 78; + len = (int) strlen(&mailto_content[i]); + } + fprintf(fd, "%s\n", &mailto_content[i]); + mailto_content = (cp + 1); + } + i = 0; + len = (int) strlen(mailto_content); + while (len > 78) { + LYStrNCpy(buf, &mailto_content[i], 78); + fprintf(fd, "%s\n", buf); + i += 78; + len = (int) strlen(&mailto_content[i]); + } + if (len) + fprintf(fd, "%s\n", &mailto_content[i]); + +#if CAN_PIPE_TO_MAILER + pclose(fd); + LYSleepMsg(); +#else + LYCloseTempFP(fd); +#if USE_VMS_MAILER + /* + * Set the mail command. - FM + */ + if (isPMDF) { + /* + * Now set up the command. - FM + */ + HTSprintf0(&cmd, + "%s %s %s,%s ", + system_mail, + system_mail_flags, + hdrfile, + my_tmpfile); + } else { + /* + * For "generic" VMS MAIL, include the subject in the command, and + * ignore any keywords to minimize risk of them making the line too + * long or having problem characters. - FM + */ + HTSprintf0(&cmd, + "%s %s%s/subject=\"%s\" %s ", + system_mail, + system_mail_flags, + (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"), + subject, + my_tmpfile); + } + StrAllocCopy(command, cmd); + + vms_append_addrs(&command, address, ""); + if (non_empty(ccaddr)) { + vms_append_addrs(&command, ccaddr, "/CC"); + } + + stop_curses(); + printf("%s\n\n$ %s\n\n%s", SENDING_FORM_CONTENT, command, PLEASE_WAIT); + LYSystem(command); /* Mail (VMS) */ + FREE(command); + LYSleepAlert(); + start_curses(); + (void) LYRemoveTemp(my_tmpfile); + if (isPMDF) + (void) LYRemoveTemp(hdrfile); +#else /* DOS */ + LYSendMailFile(address, + my_tmpfile, + subject, + ccaddr, + SENDING_FORM_CONTENT); + (void) LYRemoveTemp(my_tmpfile); +#endif /* USE_VMS_MAILER */ +#endif /* CAN_PIPE_TO_MAILER */ + + cleanup: + FREE(address); + FREE(ccaddr); + FREE(keywords); + return; +} + +/* + * mailmsg() sends a message to the owner of the file, if one is defined, + * telling of errors (i.e., link not available). + */ +void mailmsg(int cur, + char *owner_address, + char *filename, + char *linkname) +{ + FILE *fd, *fp; + char *address = NULL; + char *searchpart = NULL; + char *cmd = NULL, *cp; + +#ifdef ALERTMAIL + BOOLEAN skip_parsing = FALSE; +#endif +#if !CAN_PIPE_TO_MAILER + char *ccaddr; + char subject[128]; + char my_tmpfile[LY_MAXPATH]; +#endif +#if USE_VMS_MAILER + BOOLEAN isPMDF = LYMailPMDF(); + char hdrfile[LY_MAXPATH]; + char *command = NULL; + + CTRACE((tfp, "mailmsg(%d, \"%s\", \"%s\", \"%s\")\n", cur, + NONNULL(owner_address), + NONNULL(filename), + NONNULL(linkname))); + +#endif /* VMS */ + + if (!LYSystemMail()) + return; + +#ifdef ALERTMAIL + if (owner_address == NULL) { + owner_address = ALERTMAIL; + skip_parsing = TRUE; + } +#endif + + if (isEmpty(owner_address)) + return; + if ((cp = StrChr(owner_address, '\n')) != NULL) { +#ifdef ALERTMAIL + if (skip_parsing) + return; /* invalidly defined - ignore - kw */ +#else + *cp = '\0'; +#endif + } + if (!strncasecomp(owner_address, "lynx-dev@", 9)) { + /* + * Silently refuse sending bad link messages to lynx-dev. + */ + return; + } + StrAllocCopy(address, owner_address); + +#ifdef ALERTMAIL + /* + * If we are using a fixed address given by ALERTMAIL, it is supposed to + * already be in usable form, without URL-isms like ?-searchpart and + * URL-escaping. So skip some code. - kw + */ + if (!skip_parsing) +#endif + { + /* + * Check for a ?searchpart. - FM + */ + if ((cp = StrChr(address, '?')) != NULL) { + StrAllocCopy(searchpart, cp); + *cp = '\0'; + cp = (searchpart + 1); + if (*cp != '\0') { + /* + * Seek and handle to=address(es) fields. + * Appends to address. We ignore any other + * headers in the ?searchpart. - FM + */ + extract_field(&address, searchpart, "to="); + } + } + + (void) convert_explorer(address); + + /* + * Unescape the address field. - FM + */ + SafeHTUnEscape(address); + } + + if (trim_comma(address)) { + FREE(address); + CTRACE((tfp, "mailmsg: No address in '%s'.\n", owner_address)); + return; + } +#if CAN_PIPE_TO_MAILER + if ((fd = LYPipeToMailer()) == 0) { + FREE(address); + CTRACE((tfp, "mailmsg: '%s' failed.\n", cmd)); + return; + } + + fprintf(fd, "To: %s\n", address); + fprintf(fd, "Subject: Lynx Error in %s\n", filename); + if (non_empty(personal_mail_address)) { + fprintf(fd, "Cc: %s\n", personal_mail_address); + } + fprintf(fd, "X-URL: %s\n", filename); + fprintf(fd, "X-Mailer: %s, Version %s\n\n", LYNX_NAME, LYNX_VERSION); +#else + if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) { + CTRACE((tfp, "mailmsg: Could not fopen '%s'.\n", my_tmpfile)); + FREE(address); + return; + } + sprintf(subject, "Lynx Error in %.56s", filename); + ccaddr = personal_mail_address; +#if USE_VMS_MAILER + if (isPMDF) { + FILE *hfd; + + if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) { + CTRACE((tfp, "mailmsg: Could not fopen '%s'.\n", hdrfile)); + FREE(address); + return; + } + + if (non_empty(personal_mail_address)) { + fprintf(fd, "Cc: %s\n", personal_mail_address); + } + fprintf(fd, "X-URL: %s\n", filename); + fprintf(fd, "X-Mailer: %s, Version %s\n\n", LYNX_NAME, LYNX_VERSION); + /* + * For PMDF, put the subject in the header file and close it. - FM + */ + fprintf(hfd, "Subject: Lynx Error in %.56s\n\n", filename); + LYCloseTempFP(hfd); + } +#endif /* USE_VMS_MAILER */ +#endif /* CAN_PIPE_TO_MAILER */ + + fprintf(fd, gettext("The link %s :?: %s \n"), + links[cur].lname, links[cur].target); + fprintf(fd, gettext("called \"%s\"\n"), LYGetHiliteStr(cur, 0)); + fprintf(fd, gettext("in the file \"%s\" called \"%s\"\n"), filename, linkname); + fprintf(fd, "%s\n\n", gettext("was requested but was not available.")); + fprintf(fd, "%s\n\n", gettext("Thought you might want to know.")); + + fprintf(fd, "%s\n", gettext("This message was automatically generated by")); + fprintf(fd, "%s %s", LYNX_NAME, LYNX_VERSION); + if ((LynxSigFile != NULL) && + (fp = fopen(LynxSigFile, TXT_R)) != NULL) { + fputs("-- \n", fd); + while (LYSafeGets(&cmd, fp) != NULL) + fputs(cmd, fd); + LYCloseInput(fp); + } +#if CAN_PIPE_TO_MAILER + pclose(fd); +#else + LYCloseTempFP(fd); +#if USE_VMS_MAILER + if (isPMDF) { + /* + * Now set up the command. - FM + */ + HTSprintf0(&command, + "%s %s %s,%s ", + system_mail, + system_mail_flags, + hdrfile, + my_tmpfile); + } else { + /* + * For "generic" VMS MAIL, include the subject in the command. - FM + */ + HTSprintf0(&command, + "%s %s/self/subject=\"Lynx Error in %.56s\" %s ", + system_mail, + system_mail_flags, + filename, + my_tmpfile); + } + vms_append_addrs(&command, address, ""); + + LYSystem(command); /* VMS */ + FREE(command); + FREE(cmd); + (void) LYRemoveTemp(my_tmpfile); + if (isPMDF) { + (void) LYRemoveTemp(hdrfile); + } +#else /* DOS */ + LYSendMailFile(address, + my_tmpfile, + subject, + ccaddr, + ""); + (void) LYRemoveTemp(my_tmpfile); +#endif /* USE_VMS_MAILER */ +#endif /* CAN_PIPE_TO_MAILER */ + + if (traversal) { + FILE *ofp; + + if ((ofp = LYAppendToTxtFile(TRAVERSE_ERRORS)) == NULL) { + if ((ofp = LYNewTxtFile(TRAVERSE_ERRORS)) == NULL) { + perror(NOOPEN_TRAV_ERR_FILE); + exit_immediately(EXIT_FAILURE); + } + } + + fprintf(ofp, "%s\t%s \tin %s\n", + links[cur].lname, links[cur].target, filename); + LYCloseOutput(ofp); + } + + FREE(address); + return; +} + +/* + * reply_by_mail() invokes sendmail on Unix or mail on VMS to send + * a comment from the users to the owner + */ +void reply_by_mail(char *mail_address, + char *filename, + const char *title, + const char *refid) +{ + char user_input[LINESIZE]; + FILE *fd, *fp; + const char *label = NULL; + char *from_address = NULL; + char *cc_address = NULL; + char *to_address = NULL; + char *the_subject = NULL; + char *ccaddr = NULL; + char *keywords = NULL; + char *searchpart = NULL; + char *body = NULL; + char *cp = NULL, *cp1 = NULL; + int i; + int c = 0; /* user input */ + char my_tmpfile[LY_MAXPATH]; + char default_subject[MAX_SUBJECT + 10]; + +#if USE_VMS_MAILER + char *command = NULL; + BOOLEAN isPMDF = LYMailPMDF(); + char hdrfile[LY_MAXPATH]; + FILE *hfd = 0; + +#else +#if !CAN_PIPE_TO_MAILER + char tmpfile2[LY_MAXPATH]; +#endif + char buf[4096]; /* 512 */ + char *header = NULL; + size_t nbytes; +#endif /* USE_VMS_MAILER */ + + CTRACE((tfp, "reply_by_mail(\"%s\", \"%s\", \"%s\", \"%s\")\n", + NONNULL(mail_address), + NONNULL(filename), + NONNULL(title), + NONNULL(refid))); + + term_letter = FALSE; + + if (!LYSystemMail()) + return; + + if (isEmpty(mail_address)) { + HTAlert(NO_ADDRESS_IN_MAILTO_URL); + return; + } + StrAllocCopy(to_address, mail_address); + + if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) { + HTAlert(MAILTO_URL_TEMPOPEN_FAILED); + return; + } +#if USE_VMS_MAILER + if (isPMDF) { + if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) { + HTAlert(MAILTO_URL_TEMPOPEN_FAILED); + return; + } + } +#endif /* VMS */ + default_subject[0] = '\0'; + + /* + * Check for a ?searchpart. - FM + */ + if ((cp = StrChr(to_address, '?')) != NULL) { + StrAllocCopy(searchpart, cp); + *cp = '\0'; + cp = (searchpart + 1); + if (*cp != '\0') { + /* + * Seek and handle a subject=foo. - FM + */ + extract_subject(default_subject, searchpart); + + /* + * Seek and handle to=address(es) fields. Appends to address. - + * FM + */ + extract_field(&to_address, searchpart, "to="); + + /* + * Seek and handle cc=address(es) fields. Excludes Bcc=address(es) + * as unsafe. We may append our own cc (below) as a list for the + * actual mailing. - FM + */ + extract_field(&ccaddr, searchpart, "cc="); + + /* + * Seek and handle keywords=term(s) fields. - FM + */ + extract_field(&keywords, searchpart, "keywords="); + + if (keywords != NULL) { + if (*keywords != '\0') { + SafeHTUnEscape(keywords); + } else { + FREE(keywords); + } + } + + /* + * Seek and handle body=foo fields. - FM + */ + extract_body(&body, searchpart); + + FREE(searchpart); + } + } + + if (convert_explorer(to_address)) { + HTAlert(NO_ADDRESS_IN_MAILTO_URL); + goto cancelled; + } + if (ccaddr != NULL) { + if (convert_explorer(ccaddr)) { + FREE(ccaddr); + } + } + + /* + * Unescape the address and ccaddr fields. - FM + */ + SafeHTUnEscape(to_address); + if (ccaddr != NULL) { + SafeHTUnEscape(ccaddr); + } + + /* + * Set the default subject. - FM + */ + if ((default_subject[0] == '\0') && non_empty(title)) { + LYStrNCpy(default_subject, title, MAX_SUBJECT); + } + + /* + * Use ^G to cancel mailing of comment and don't let SIGINTs exit lynx. + */ + signal(SIGINT, terminate_letter); + +#if USE_VMS_MAILER + if (isPMDF || !body) { + /* + * Put the X-URL and X-Mailer lines in the hdrfile for PMDF or + * my_tmpfile for VMS MAIL. - FM + */ + fprintf((isPMDF ? hfd : fd), + "X-URL: %s%s\n", + isEmpty(filename) ? STR_MAILTO_URL : filename, + isEmpty(filename) ? to_address : ""); + fprintf((isPMDF ? hfd : fd), + "X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION); +#ifdef NO_ANONYMOUS_EMAIL + if (!isPMDF) { + fprintf(fd, "\n"); + } +#endif /* NO_ANONYMOUS_EMAIL */ + } +#else /* Unix/DOS/Windows */ + /* + * Put the To: line in the header. + */ +#ifndef DOSPATH + HTSprintf(&header, "To: %s\n", to_address); +#endif + + /* + * Put the Mime-Version, Content-Type and Content-Transfer-Encoding in the + * header. This assumes that the same character set is used for composing + * the mail which is currently selected as display character set... Don't + * send a charset if we have a CJK character set selected, since it may not + * be appropriate for mail... Also don't use an unofficial "x-" charset. + * Also if the charset would be "us-ascii" (7-bit replacements selected, + * don't send any MIME headers. - kw + */ + if (strncasecomp(LYCharSet_UC[current_char_set].MIMEname, + "us-ascii", 8) != 0) { + StrAllocCat(header, "Mime-Version: 1.0\n"); + if (!LYHaveCJKCharacterSet && + strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2) + != 0) { + HTSprintf(&header, "Content-Type: " STR_PLAINTEXT "; charset=%s\n", + LYCharSet_UC[current_char_set].MIMEname); + } + StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n"); + } + /* + * Put the X-URL and X-Mailer lines in the header. + */ + if (non_empty(filename)) { + HTSprintf(&header, "X-URL: %s\n", filename); + } else { + HTSprintf(&header, "X-URL: mailto:%s\n", to_address); + } + HTSprintf(&header, "X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION); + + if (non_empty(refid)) { + HTSprintf(&header, "In-Reply-To: <%s>\n", refid); + } +#endif /* VMS */ + + /* + * Clear the screen and inform the user. + */ + LYclear(); + LYmove(2, 0); + scrollok(LYwin, TRUE); /* Enable scrolling. */ + if (body) + LYaddstr(SENDING_MESSAGE_WITH_BODY_TO); + else + LYaddstr(SENDING_COMMENT_TO); + show_addresses(to_address); + if ( +#if USE_VMS_MAILER + (isPMDF == TRUE) && +#endif /* VMS */ + (cp = ccaddr) != NULL) { + if (StrChr(cp, ',') != NULL) { + LYaddstr(WITH_COPIES_TO); + } else { + LYaddstr(WITH_COPY_TO); + } + show_addresses(ccaddr); + } + LYaddstr(CTRL_G_TO_CANCEL_SEND); + +#if USE_VMS_MAILER + if (isPMDF || !body) { +#endif /* USE_VMS_MAILER */ +#ifndef NO_ANONYMOUS_EMAIL + /* + * Get the user's personal name. + */ + LYaddstr(ENTER_NAME_OR_BLANK); +#if USE_VMS_MAILER + if (isPMDF) { + label = "Personal_name"; + } else { + label = "X-Personal_name"; + } +#else + label = "X-Personal_Name"; +#endif /* USE_VMS_MAILER */ + if (!header_prompt(label, &personal_mail_name, LINESIZE)) { + goto cancelled; + } + if (*personal_mail_name) { +#if USE_VMS_MAILER + fprintf((isPMDF ? hfd : fd), "%s: %s\n", label, personal_mail_name); +#else + HTSprintf(&header, "%s: %s\n", label, personal_mail_name); +#endif /* VMS */ + } + + /* + * Get the user's return address. + */ + LYaddstr(ENTER_MAIL_ADDRESS_OR_OTHER); + LYaddstr(MEANS_TO_CONTACT_FOR_RESPONSE); +#if USE_VMS_MAILER + if (isPMDF) { + label = "From"; + } else { + label = "X-From"; + } +#else + label = "From"; +#endif /* VMS */ + /* Add the personal mail address if there is one. */ + if (non_empty(personal_mail_address)) + StrAllocCopy(from_address, personal_mail_address); + if (!header_prompt(label, &from_address, LINESIZE)) { + goto cancelled; + } +#if USE_VMS_MAILER + if (*from_address) { + fprintf(isPMDF ? hfd : fd, "%s: %s\n", label, from_address); + } + if (!isPMDF) { + fprintf(fd, "\n"); + } +#else + HTSprintf(&header, "%s: %s\n", label, from_address); +#endif /* USE_VMS_MAILER */ +#endif /* !NO_ANONYMOUS_EMAIL */ +#if USE_VMS_MAILER + } +#endif /* USE_VMS_MAILER */ + + /* + * Get the subject line. + */ + LYaddstr(ENTER_SUBJECT_LINE); + label = "Subject"; + if (*default_subject) { + StrAllocCopy(the_subject, default_subject); + } else if (non_empty(filename)) { + HTSprintf(&the_subject, "%s", filename); + } else { + HTSprintf(&the_subject, "mailto:%s", to_address); + } + if (!header_prompt(label, &the_subject, MAX_SUBJECT)) { + goto cancelled; + } + + /* + * Offer a CC line, if permitted. - FM + */ + if (!LYNoCc) { + LYaddstr(ENTER_ADDRESS_FOR_CC); + LYaddstr(BLANK_FOR_NO_COPY); + if (non_empty(personal_mail_address)) + StrAllocCopy(cc_address, personal_mail_address); + if (!header_prompt("Cc", &cc_address, LINESIZE)) { + goto cancelled; + } + comma_append(&ccaddr, cc_address); + } +#if !USE_VMS_MAILER + HTSprintf(&header, "%s: %s\n", label, the_subject); +#if !CAN_PIPE_TO_MAILER + if (*to_address) { + HTSprintf(&header, "To: %s\n", to_address); + } +#endif + + /* + * Add the Cc: header. - FM + */ + if (non_empty(ccaddr)) { + HTSprintf(&header, "Cc: %s\n", ccaddr); + } + + /* + * Add the Keywords: header. - FM + */ + if (non_empty(keywords)) { + HTSprintf(&header, "Keywords: %s\n", keywords); + } + + /* + * Terminate the header. + */ + StrAllocCat(header, "\n"); + CTRACE((tfp, "**header==\n%s", header)); +#endif /* !VMS */ + + if (!no_editor && non_empty(editor)) { + + if (body) { + cp1 = body; + while ((cp = StrChr(cp1, '\n')) != NULL) { + *cp++ = '\0'; + fprintf(fd, "%s\n", cp1); + cp1 = cp; + } + } else if (strcmp(HTLoadedDocumentURL(), "")) { + /* + * Ask if the user wants to include the original message. + */ + BOOLEAN is_preparsed = (BOOL) (LYPreparsedSource && + HTisDocumentSource()); + + if (HTConfirm(is_preparsed + ? INC_PREPARSED_MSG_PROMPT + : INC_ORIG_MSG_PROMPT) == YES) { + print_wwwfile_to_fd(fd, TRUE, (BOOL) !is_preparsed); + } + } + LYCloseTempFP(fd); /* Close the tmpfile. */ + scrollok(LYwin, FALSE); /* Stop scrolling. */ + + if (term_letter || LYCharIsINTERRUPT(c)) + goto cleanup; + + /* + * Spawn the users editor on the mail file + */ + edit_temporary_file(my_tmpfile, "", SPAWNING_EDITOR_FOR_MAIL); + + } else if (body) { + /* + * Let user review the body. - FM + */ + LYclear(); + LYmove(0, 0); + LYaddstr(REVIEW_MESSAGE_BODY); + LYrefresh(); + cp1 = body; + i = (LYlines - 5); + while ((cp = StrChr(cp1, '\n')) != NULL) { + if (i <= 0) { + LYaddstr(RETURN_TO_CONTINUE); + LYrefresh(); + c = LYgetch(); + LYaddstr("\n"); + if (term_letter || LYCharIsINTERRUPT(c)) { + goto cancelled; + } + i = (LYlines - 2); + } + *cp++ = '\0'; + fprintf(fd, "%s\n", cp1); + LYaddstr(cp1); + LYaddstr("\n"); + cp1 = cp; + i--; + } + while (i >= 0) { + LYaddstr("\n"); + i--; + } + LYrefresh(); + LYCloseTempFP(fd); /* Close the tmpfile. */ + scrollok(LYwin, FALSE); /* Stop scrolling. */ + + } else { + /* + * Use the internal line editor for the message. + */ + LYaddstr(ENTER_MESSAGE_BELOW); + LYaddstr(ENTER_PERIOD_WHEN_DONE_A); + LYaddstr(ENTER_PERIOD_WHEN_DONE_B); + LYaddstr(CTRL_G_TO_CANCEL_SEND); + LYaddstr("\n\n"); + LYrefresh(); + *user_input = '\0'; + if (LYGetStr(user_input, FALSE, sizeof(user_input), NORECALL) < 0 || + term_letter || STREQ(user_input, ".")) { + goto cancelled; + } + + while (!STREQ(user_input, ".") && !term_letter) { + LYaddstr("\n"); + remove_tildes(user_input); + fprintf(fd, "%s\n", user_input); + *user_input = '\0'; + if (LYGetStr(user_input, FALSE, + sizeof(user_input), NORECALL) < 0) { + goto cancelled; + } + } + + fprintf(fd, "\n"); /* Terminate the message. */ + LYCloseTempFP(fd); /* Close the tmpfile. */ + scrollok(LYwin, FALSE); /* Stop scrolling. */ + } + +#if !USE_VMS_MAILER + /* + * Ignore CTRL-C on this last question. + */ + signal(SIGINT, SIG_IGN); +#endif /* !VMS */ + LYStatusLine = (LYlines - 1); + c = HTConfirm(body ? SEND_MESSAGE_PROMPT : SEND_COMMENT_PROMPT); + LYStatusLine = -1; + if (c != YES) { + LYclear(); /* clear the screen */ + goto cleanup; + } + if ((body == NULL && non_empty(LynxSigFile)) && + (fp = fopen(LynxSigFile, TXT_R)) != NULL) { + LYStatusLine = (LYlines - 1); + if (term_letter) { + _user_message(APPEND_SIG_FILE, LynxSigFile); + c = 0; + } else { + char *msg = NULL; + + HTSprintf0(&msg, APPEND_SIG_FILE, LynxSigFile); + c = HTConfirm(msg); + FREE(msg); + } + LYStatusLine = -1; + if (c == YES) { + if ((fd = fopen(my_tmpfile, TXT_A)) != NULL) { + char *buffer = NULL; + + fputs("-- \n", fd); + while (LYSafeGets(&buffer, fp) != NULL) { + fputs(buffer, fd); + } + LYCloseOutput(fd); + FREE(buffer); + } + } + LYCloseInput(fp); + } + LYclear(); /* Clear the screen. */ + + /* + * Send the message. + */ +#if USE_VMS_MAILER + /* + * Set the mail command. - FM + */ + if (isPMDF) { + /* + * For PMDF, put any keywords and the subject in the header file and + * close it. - FM + */ + if (non_empty(keywords)) { + fprintf(hfd, "Keywords: %s\n", keywords); + } + fprintf(hfd, "Subject: %s\n\n", the_subject); + LYCloseTempFP(hfd); + /* + * Now set up the command. - FM + */ + HTSprintf0(&command, "%s %s %s,%s ", + system_mail, + system_mail_flags, + hdrfile, + my_tmpfile); + } else { + /* + * For "generic" VMS MAIL, include the subject in the command, and + * ignore any keywords to minimize risk of them making the line too + * long or having problem characters. - FM + */ + HTSprintf0(&command, "%s %s%s/subject=\"%s\" %s ", + system_mail, + system_mail_flags, + (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"), + the_subject, + my_tmpfile); + } + + vms_append_addrs(&command, to_address, ""); + if (non_empty(ccaddr)) { + vms_append_addrs(&command, ccaddr, "/CC"); + } + + stop_curses(); + printf("%s\n\n$ %s\n\n%s", SENDING_COMMENT, command, PLEASE_WAIT); + LYSystem(command); /* SENDING COMMENT (VMS) */ + FREE(command); + LYSleepAlert(); + start_curses(); +#else /* Unix/DOS/Windows */ + /* + * Send the tmpfile into sendmail. + */ + _statusline(SENDING_YOUR_MSG); +#if CAN_PIPE_TO_MAILER + signal(SIGINT, SIG_IGN); + if ((fp = LYPipeToMailer()) == 0) { + HTInfoMsg(CANCELLED); + } +#else + if ((fp = LYOpenTemp(tmpfile2, ".txt", "w")) == NULL) { + HTAlert(MAILTO_URL_TEMPOPEN_FAILED); + } +#endif /* CAN_PIPE_TO_MAILER */ + if (fp != 0) { + fd = fopen(my_tmpfile, TXT_R); + if (fd == NULL) { + HTInfoMsg(CANCELLED); +#if CAN_PIPE_TO_MAILER + pclose(fp); +#else + LYCloseTempFP(fp); +#endif /* CAN_PIPE_TO_MAILER */ + } else { +#if USE_BLAT_MAILER + if (!mail_is_blat) + fputs(header, fp); +#else + fputs(header, fp); +#endif + while ((nbytes = fread(buf, (size_t) 1, sizeof(buf), fd)) != 0) { + if (fwrite(buf, (size_t) 1, (size_t) nbytes, fp) < nbytes) + break; + } +#if CAN_PIPE_TO_MAILER + pclose(fp); +#else + LYCloseTempFP(fp); /* Close the tmpfile. */ + LYSendMailFile(to_address, + tmpfile2, + the_subject, + ccaddr, + SENDING_COMMENT); + (void) LYRemoveTemp(tmpfile2); /* Delete the tmpfile. */ +#endif /* CAN_PIPE_TO_MAILER */ + LYCloseInput(fd); /* Close the tmpfile. */ + } + } +#endif /* USE_VMS_MAILER */ + goto cleanup; + + /* + * Come here to cleanup and exit. + */ + cancelled: + HTInfoMsg(CANCELLED); + LYCloseTempFP(fd); /* Close the tmpfile. */ + scrollok(LYwin, FALSE); /* Stop scrolling. */ + cleanup: + signal(SIGINT, cleanup_sig); + term_letter = FALSE; + +#if USE_VMS_MAILER + while (LYRemoveTemp(my_tmpfile) == 0) ; /* Delete the tmpfile(s). */ + if (isPMDF) { + (void) LYRemoveTemp(hdrfile); /* Delete the hdrfile. */ + } +#else + FREE(header); + (void) LYRemoveTemp(my_tmpfile); /* Delete the tmpfile. */ +#endif /* VMS */ + + FREE(from_address); + FREE(the_subject); + FREE(cc_address); + FREE(to_address); + FREE(ccaddr); + FREE(keywords); + FREE(body); + return; +} + +/* + * Check that we have configured values for system mailer. + */ +BOOLEAN LYSystemMail(void) +{ + if (isEmpty(system_mail) || !strcmp(system_mail, "unknown")) { + HTAlert(gettext("No system mailer configured")); + return FALSE; + } + return TRUE; +} |